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);
1245 int anim_frames = graphic_info[graphic].anim_frames;
1246 /* !!! THIS ONLY REALLY WORKS WITH anim_frames == 7 (MOVEMENT FRAMES) !!! */
1247 /* !!! (ELSE sync_frame DOES NOT START WITH 0 AND MOVEMENT LOOK WRONG !!! */
1248 /* !!! (AND anim_frames == 15 FOR SLOW MOVEMENT AND SO ON) !!! */
1250 /* (we also need anim_delay here for movement animations with less frames) */
1251 int anim_delay = graphic_info[graphic].anim_delay;
1252 int anim_pos = (dx ? ABS(dx) : ABS(dy));
1253 int sync_frame = anim_pos * anim_frames * anim_delay / TILESIZE;
1255 int sync_frame = (dx ? ABS(dx) : ABS(dy)) * anim_frames / TILESIZE;
1257 boolean draw_start_tile = (cut_mode != CUT_ABOVE); /* only for falling! */
1258 boolean draw_end_tile = (cut_mode != CUT_BELOW); /* only for falling! */
1260 /* re-calculate animation frame for two-tile movement animation */
1261 frame = getGraphicAnimationFrame(graphic, sync_frame);
1264 printf("::: %d [%d, %d]\n", frame, sync_frame, dy);
1267 /* check if movement start graphic inside screen area and should be drawn */
1268 if (draw_start_tile && IN_SCR_FIELD(x1, y1))
1270 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, TRUE);
1272 dst_x = FX + x1 * TILEX;
1273 dst_y = FY + y1 * TILEY;
1275 if (mask_mode == USE_MASKING)
1277 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1278 dst_x - src_x, dst_y - src_y);
1279 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1283 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1286 MarkTileDirty(x1, y1);
1289 /* check if movement end graphic inside screen area and should be drawn */
1290 if (draw_end_tile && IN_SCR_FIELD(x2, y2))
1292 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
1294 dst_x = FX + x2 * TILEX;
1295 dst_y = FY + y2 * TILEY;
1297 if (mask_mode == USE_MASKING)
1299 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1300 dst_x - src_x, dst_y - src_y);
1301 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1305 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1308 MarkTileDirty(x2, y2);
1312 static void DrawGraphicShifted(int x, int y, int dx, int dy,
1313 int graphic, int frame,
1314 int cut_mode, int mask_mode)
1318 DrawGraphic(x, y, graphic, frame);
1323 if (graphic_info[graphic].double_movement) /* EM style movement images */
1324 DrawGraphicShiftedDouble(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1326 DrawGraphicShiftedNormal(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1329 void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
1330 int frame, int cut_mode)
1332 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, USE_MASKING);
1335 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
1336 int cut_mode, int mask_mode)
1338 int lx = LEVELX(x), ly = LEVELY(y);
1342 if (IN_LEV_FIELD(lx, ly))
1344 SetRandomAnimationValue(lx, ly);
1346 graphic = el_act_dir2img(element, GfxAction[lx][ly], GfxDir[lx][ly]);
1347 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1349 /* do not use double (EM style) movement graphic when not moving */
1350 if (graphic_info[graphic].double_movement && !dx && !dy)
1352 graphic = el_act_dir2img(element, ACTION_DEFAULT, GfxDir[lx][ly]);
1353 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1356 else /* border element */
1358 graphic = el2img(element);
1359 frame = getGraphicAnimationFrame(graphic, -1);
1362 if (element == EL_EXPANDABLE_WALL)
1364 boolean left_stopped = FALSE, right_stopped = FALSE;
1366 if (!IN_LEV_FIELD(lx - 1, ly) || IS_WALL(Feld[lx - 1][ly]))
1367 left_stopped = TRUE;
1368 if (!IN_LEV_FIELD(lx + 1, ly) || IS_WALL(Feld[lx + 1][ly]))
1369 right_stopped = TRUE;
1371 if (left_stopped && right_stopped)
1373 else if (left_stopped)
1375 graphic = IMG_EXPANDABLE_WALL_GROWING_RIGHT;
1376 frame = graphic_info[graphic].anim_frames - 1;
1378 else if (right_stopped)
1380 graphic = IMG_EXPANDABLE_WALL_GROWING_LEFT;
1381 frame = graphic_info[graphic].anim_frames - 1;
1386 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
1387 else if (mask_mode == USE_MASKING)
1388 DrawGraphicThruMask(x, y, graphic, frame);
1390 DrawGraphic(x, y, graphic, frame);
1393 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
1394 int cut_mode, int mask_mode)
1396 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1397 DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
1398 cut_mode, mask_mode);
1401 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
1404 DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1407 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
1410 DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1413 void DrawLevelElementThruMask(int x, int y, int element)
1415 DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1418 void DrawLevelFieldThruMask(int x, int y)
1420 DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
1423 /* !!! implementation of quicksand is totally broken !!! */
1424 #define IS_CRUMBLED_TILE(x, y, e) \
1425 (GFX_CRUMBLED(e) && (!IN_LEV_FIELD(x, y) || \
1426 !IS_MOVING(x, y) || \
1427 (e) == EL_QUICKSAND_EMPTYING || \
1428 (e) == EL_QUICKSAND_FAST_EMPTYING))
1430 static void DrawLevelFieldCrumbledSandExt(int x, int y, int graphic, int frame)
1434 int sx = SCREENX(x), sy = SCREENY(y);
1436 int width, height, cx, cy, i;
1437 int crumbled_border_size = graphic_info[graphic].border_size;
1438 static int xy[4][2] =
1446 if (!IN_LEV_FIELD(x, y))
1449 element = TILE_GFX_ELEMENT(x, y);
1451 /* crumble field itself */
1453 if (IS_CRUMBLED_TILE(x, y, element))
1455 if (GFX_CRUMBLED(element) && !IS_MOVING(x, y))
1458 if (!IN_SCR_FIELD(sx, sy))
1461 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1463 for (i = 0; i < 4; i++)
1465 int xx = x + xy[i][0];
1466 int yy = y + xy[i][1];
1468 element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1471 /* check if neighbour field is of same type */
1473 if (IS_CRUMBLED_TILE(xx, yy, element))
1476 if (GFX_CRUMBLED(element) && !IS_MOVING(xx, yy))
1480 if (i == 1 || i == 2)
1482 width = crumbled_border_size;
1484 cx = (i == 2 ? TILEX - crumbled_border_size : 0);
1490 height = crumbled_border_size;
1492 cy = (i == 3 ? TILEY - crumbled_border_size : 0);
1495 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1496 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
1499 MarkTileDirty(sx, sy);
1501 else /* crumble neighbour fields */
1503 for (i = 0; i < 4; i++)
1505 int xx = x + xy[i][0];
1506 int yy = y + xy[i][1];
1507 int sxx = sx + xy[i][0];
1508 int syy = sy + xy[i][1];
1511 if (!IN_LEV_FIELD(xx, yy) ||
1512 !IN_SCR_FIELD(sxx, syy))
1515 if (!IN_LEV_FIELD(xx, yy) ||
1516 !IN_SCR_FIELD(sxx, syy) ||
1521 if (Feld[xx][yy] == EL_ELEMENT_SNAPPING)
1524 element = TILE_GFX_ELEMENT(xx, yy);
1527 if (!IS_CRUMBLED_TILE(xx, yy, element))
1530 if (!GFX_CRUMBLED(element))
1534 graphic = el_act2crm(element, ACTION_DEFAULT);
1535 crumbled_border_size = graphic_info[graphic].border_size;
1537 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1539 if (i == 1 || i == 2)
1541 width = crumbled_border_size;
1543 cx = (i == 1 ? TILEX - crumbled_border_size : 0);
1549 height = crumbled_border_size;
1551 cy = (i == 0 ? TILEY - crumbled_border_size : 0);
1554 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1555 width, height, FX + sxx * TILEX + cx, FY + syy * TILEY + cy);
1557 MarkTileDirty(sxx, syy);
1562 void DrawLevelFieldCrumbledSand(int x, int y)
1566 if (!IN_LEV_FIELD(x, y))
1570 /* !!! CHECK THIS !!! */
1573 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
1574 GFX_CRUMBLED(GfxElement[x][y]))
1577 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
1578 GfxElement[x][y] != EL_UNDEFINED &&
1579 GFX_CRUMBLED(GfxElement[x][y]))
1581 DrawLevelFieldCrumbledSandDigging(x, y, GfxDir[x][y], GfxFrame[x][y]);
1588 graphic = el_act2crm(TILE_GFX_ELEMENT(x, y), ACTION_DEFAULT);
1590 graphic = el_act2crm(Feld[x][y], ACTION_DEFAULT);
1593 DrawLevelFieldCrumbledSandExt(x, y, graphic, 0);
1596 void DrawLevelFieldCrumbledSandDigging(int x, int y, int direction,
1599 int graphic1 = el_act_dir2img(GfxElement[x][y], ACTION_DIGGING, direction);
1600 int graphic2 = el_act_dir2crm(GfxElement[x][y], ACTION_DIGGING, direction);
1601 int frame1 = getGraphicAnimationFrame(graphic1, step_frame);
1602 int frame2 = getGraphicAnimationFrame(graphic2, step_frame);
1603 int sx = SCREENX(x), sy = SCREENY(y);
1605 DrawGraphic(sx, sy, graphic1, frame1);
1606 DrawLevelFieldCrumbledSandExt(x, y, graphic2, frame2);
1609 void DrawLevelFieldCrumbledSandNeighbours(int x, int y)
1611 int sx = SCREENX(x), sy = SCREENY(y);
1612 static int xy[4][2] =
1621 for (i = 0; i < 4; i++)
1623 int xx = x + xy[i][0];
1624 int yy = y + xy[i][1];
1625 int sxx = sx + xy[i][0];
1626 int syy = sy + xy[i][1];
1628 if (!IN_LEV_FIELD(xx, yy) ||
1629 !IN_SCR_FIELD(sxx, syy) ||
1630 !GFX_CRUMBLED(Feld[xx][yy]) ||
1634 DrawLevelField(xx, yy);
1638 static int getBorderElement(int x, int y)
1642 { EL_STEELWALL_TOPLEFT, EL_INVISIBLE_STEELWALL_TOPLEFT },
1643 { EL_STEELWALL_TOPRIGHT, EL_INVISIBLE_STEELWALL_TOPRIGHT },
1644 { EL_STEELWALL_BOTTOMLEFT, EL_INVISIBLE_STEELWALL_BOTTOMLEFT },
1645 { EL_STEELWALL_BOTTOMRIGHT, EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
1646 { EL_STEELWALL_VERTICAL, EL_INVISIBLE_STEELWALL_VERTICAL },
1647 { EL_STEELWALL_HORIZONTAL, EL_INVISIBLE_STEELWALL_HORIZONTAL },
1648 { EL_STEELWALL, EL_INVISIBLE_STEELWALL }
1650 int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
1651 int steel_position = (x == -1 && y == -1 ? 0 :
1652 x == lev_fieldx && y == -1 ? 1 :
1653 x == -1 && y == lev_fieldy ? 2 :
1654 x == lev_fieldx && y == lev_fieldy ? 3 :
1655 x == -1 || x == lev_fieldx ? 4 :
1656 y == -1 || y == lev_fieldy ? 5 : 6);
1658 return border[steel_position][steel_type];
1661 void DrawScreenElement(int x, int y, int element)
1663 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
1664 DrawLevelFieldCrumbledSand(LEVELX(x), LEVELY(y));
1667 void DrawLevelElement(int x, int y, int element)
1669 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1670 DrawScreenElement(SCREENX(x), SCREENY(y), element);
1673 void DrawScreenField(int x, int y)
1675 int lx = LEVELX(x), ly = LEVELY(y);
1676 int element, content;
1678 if (!IN_LEV_FIELD(lx, ly))
1680 if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
1683 element = getBorderElement(lx, ly);
1685 DrawScreenElement(x, y, element);
1690 element = Feld[lx][ly];
1691 content = Store[lx][ly];
1693 if (IS_MOVING(lx, ly))
1695 int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
1696 boolean cut_mode = NO_CUTTING;
1698 if (element == EL_QUICKSAND_EMPTYING ||
1699 element == EL_QUICKSAND_FAST_EMPTYING ||
1700 element == EL_MAGIC_WALL_EMPTYING ||
1701 element == EL_BD_MAGIC_WALL_EMPTYING ||
1702 element == EL_DC_MAGIC_WALL_EMPTYING ||
1703 element == EL_AMOEBA_DROPPING)
1704 cut_mode = CUT_ABOVE;
1705 else if (element == EL_QUICKSAND_FILLING ||
1706 element == EL_QUICKSAND_FAST_FILLING ||
1707 element == EL_MAGIC_WALL_FILLING ||
1708 element == EL_BD_MAGIC_WALL_FILLING ||
1709 element == EL_DC_MAGIC_WALL_FILLING)
1710 cut_mode = CUT_BELOW;
1713 if (lx == 9 && ly == 1)
1714 printf("::: %s [%d] [%d, %d] [%d]\n",
1715 EL_NAME(TILE_GFX_ELEMENT(lx, ly)),
1716 el_act2crm(TILE_GFX_ELEMENT(lx, ly), ACTION_DEFAULT),
1717 element_info[EL_QUICKSAND_EMPTYING].graphic[ACTION_DEFAULT],
1718 element_info[EL_QUICKSAND_EMPTYING].crumbled[ACTION_DEFAULT],
1719 GFX_CRUMBLED(TILE_GFX_ELEMENT(lx, ly)));
1722 if (cut_mode == CUT_ABOVE)
1724 DrawScreenElement(x, y, element);
1726 DrawScreenElementShifted(x, y, 0, 0, element, NO_CUTTING);
1729 DrawScreenElement(x, y, EL_EMPTY);
1732 DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
1733 else if (cut_mode == NO_CUTTING)
1734 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
1737 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
1740 if (cut_mode == CUT_BELOW &&
1741 IN_LEV_FIELD(lx, ly + 1) && IN_SCR_FIELD(x, y + 1))
1742 DrawLevelElement(lx, ly + 1, element);
1746 if (content == EL_ACID)
1748 int dir = MovDir[lx][ly];
1749 int newlx = lx + (dir == MV_LEFT ? -1 : dir == MV_RIGHT ? +1 : 0);
1750 int newly = ly + (dir == MV_UP ? -1 : dir == MV_DOWN ? +1 : 0);
1752 DrawLevelElementThruMask(newlx, newly, EL_ACID);
1755 else if (IS_BLOCKED(lx, ly))
1760 boolean cut_mode = NO_CUTTING;
1761 int element_old, content_old;
1763 Blocked2Moving(lx, ly, &oldx, &oldy);
1766 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
1767 MovDir[oldx][oldy] == MV_RIGHT);
1769 element_old = Feld[oldx][oldy];
1770 content_old = Store[oldx][oldy];
1772 if (element_old == EL_QUICKSAND_EMPTYING ||
1773 element_old == EL_QUICKSAND_FAST_EMPTYING ||
1774 element_old == EL_MAGIC_WALL_EMPTYING ||
1775 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
1776 element_old == EL_DC_MAGIC_WALL_EMPTYING ||
1777 element_old == EL_AMOEBA_DROPPING)
1778 cut_mode = CUT_ABOVE;
1780 DrawScreenElement(x, y, EL_EMPTY);
1783 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
1785 else if (cut_mode == NO_CUTTING)
1786 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
1789 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
1792 else if (IS_DRAWABLE(element))
1793 DrawScreenElement(x, y, element);
1795 DrawScreenElement(x, y, EL_EMPTY);
1798 void DrawLevelField(int x, int y)
1800 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1801 DrawScreenField(SCREENX(x), SCREENY(y));
1802 else if (IS_MOVING(x, y))
1806 Moving2Blocked(x, y, &newx, &newy);
1807 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
1808 DrawScreenField(SCREENX(newx), SCREENY(newy));
1810 else if (IS_BLOCKED(x, y))
1814 Blocked2Moving(x, y, &oldx, &oldy);
1815 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
1816 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
1820 void DrawMiniElement(int x, int y, int element)
1824 graphic = el2edimg(element);
1825 DrawMiniGraphic(x, y, graphic);
1828 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
1830 int x = sx + scroll_x, y = sy + scroll_y;
1832 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
1833 DrawMiniElement(sx, sy, EL_EMPTY);
1834 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
1835 DrawMiniElement(sx, sy, Feld[x][y]);
1837 DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
1840 void DrawEnvelopeBackground(int envelope_nr, int startx, int starty,
1841 int x, int y, int xsize, int ysize, int font_nr)
1843 int font_width = getFontWidth(font_nr);
1844 int font_height = getFontHeight(font_nr);
1845 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1848 int dst_x = SX + startx + x * font_width;
1849 int dst_y = SY + starty + y * font_height;
1850 int width = graphic_info[graphic].width;
1851 int height = graphic_info[graphic].height;
1852 int inner_width = MAX(width - 2 * font_width, font_width);
1853 int inner_height = MAX(height - 2 * font_height, font_height);
1854 int inner_sx = (width >= 3 * font_width ? font_width : 0);
1855 int inner_sy = (height >= 3 * font_height ? font_height : 0);
1856 boolean draw_masked = graphic_info[graphic].draw_masked;
1858 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1860 if (src_bitmap == NULL || width < font_width || height < font_height)
1862 ClearRectangle(drawto, dst_x, dst_y, font_width, font_height);
1866 src_x += (x == 0 ? 0 : x == xsize - 1 ? width - font_width :
1867 inner_sx + (x - 1) * font_width % inner_width);
1868 src_y += (y == 0 ? 0 : y == ysize - 1 ? height - font_height :
1869 inner_sy + (y - 1) * font_height % inner_height);
1873 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1874 dst_x - src_x, dst_y - src_y);
1875 BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1879 BlitBitmap(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1883 void AnimateEnvelope(int envelope_nr, int anim_mode, int action)
1885 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1886 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1887 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
1888 boolean ffwd_delay = (tape.playing && tape.fast_forward);
1889 boolean no_delay = (tape.warp_forward);
1890 unsigned long anim_delay = 0;
1891 int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
1892 int anim_delay_value = (no_delay ? 0 : frame_delay_value);
1893 int font_nr = FONT_ENVELOPE_1 + envelope_nr;
1894 int font_width = getFontWidth(font_nr);
1895 int font_height = getFontHeight(font_nr);
1896 int max_xsize = level.envelope[envelope_nr].xsize;
1897 int max_ysize = level.envelope[envelope_nr].ysize;
1898 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
1899 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
1900 int xend = max_xsize;
1901 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
1902 int xstep = (xstart < xend ? 1 : 0);
1903 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
1906 for (x = xstart, y = ystart; x <= xend && y <= yend; x += xstep, y += ystep)
1908 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
1909 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
1910 int sx = (SXSIZE - xsize * font_width) / 2;
1911 int sy = (SYSIZE - ysize * font_height) / 2;
1914 SetDrawtoField(DRAW_BUFFERED);
1916 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
1918 SetDrawtoField(DRAW_BACKBUFFER);
1920 for (yy = 0; yy < ysize; yy++) for (xx = 0; xx < xsize; xx++)
1921 DrawEnvelopeBackground(envelope_nr, sx,sy, xx,yy, xsize, ysize, font_nr);
1924 DrawTextBuffer(SX + sx + font_width, SY + sy + font_height,
1925 level.envelope[envelope_nr].text, font_nr, max_xsize,
1926 xsize - 2, ysize - 2, mask_mode,
1927 level.envelope[envelope_nr].autowrap,
1928 level.envelope[envelope_nr].centered, FALSE);
1930 DrawTextToTextArea(SX + sx + font_width, SY + sy + font_height,
1931 level.envelope[envelope_nr].text, font_nr, max_xsize,
1932 xsize - 2, ysize - 2, mask_mode);
1935 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
1938 WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
1942 void ShowEnvelope(int envelope_nr)
1944 int element = EL_ENVELOPE_1 + envelope_nr;
1945 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1946 int sound_opening = element_info[element].sound[ACTION_OPENING];
1947 int sound_closing = element_info[element].sound[ACTION_CLOSING];
1948 boolean ffwd_delay = (tape.playing && tape.fast_forward);
1949 boolean no_delay = (tape.warp_forward);
1950 int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
1951 int wait_delay_value = (no_delay ? 0 : normal_delay_value);
1952 int anim_mode = graphic_info[graphic].anim_mode;
1953 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
1954 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
1956 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
1958 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
1960 if (anim_mode == ANIM_DEFAULT)
1961 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_OPENING);
1963 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_OPENING);
1966 Delay(wait_delay_value);
1968 WaitForEventToContinue();
1970 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
1972 if (anim_mode != ANIM_NONE)
1973 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_CLOSING);
1975 if (anim_mode == ANIM_DEFAULT)
1976 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_CLOSING);
1978 game.envelope_active = FALSE;
1980 SetDrawtoField(DRAW_BUFFERED);
1982 redraw_mask |= REDRAW_FIELD;
1986 void DrawPreviewElement(int dst_x, int dst_y, int element, int tilesize)
1990 int graphic = el2preimg(element);
1992 getSizedGraphicSource(graphic, 0, tilesize, &src_bitmap, &src_x, &src_y);
1993 BlitBitmap(src_bitmap, drawto, src_x, src_y, tilesize, tilesize, dst_x,dst_y);
2001 SetMainBackgroundImage(IMG_BACKGROUND_PLAYING);
2002 SetDrawBackgroundMask(REDRAW_FIELD);
2004 SetDrawBackgroundMask(REDRAW_NONE);
2009 for (x = BX1; x <= BX2; x++)
2010 for (y = BY1; y <= BY2; y++)
2011 DrawScreenField(x, y);
2013 redraw_mask |= REDRAW_FIELD;
2016 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
2020 for (x = 0; x < size_x; x++)
2021 for (y = 0; y < size_y; y++)
2022 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
2024 redraw_mask |= REDRAW_FIELD;
2027 static void DrawPreviewLevelExt(int from_x, int from_y)
2029 boolean show_level_border = (BorderElement != EL_EMPTY);
2030 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
2031 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
2032 int tile_size = preview.tile_size;
2033 int preview_width = preview.xsize * tile_size;
2034 int preview_height = preview.ysize * tile_size;
2035 int real_preview_xsize = MIN(level_xsize, preview.xsize);
2036 int real_preview_ysize = MIN(level_ysize, preview.ysize);
2037 int dst_x = SX + ALIGNED_XPOS(preview.x, preview_width, preview.align);
2038 int dst_y = SY + ALIGNED_YPOS(preview.y, preview_height, preview.valign);
2041 DrawBackground(dst_x, dst_y, preview_width, preview_height);
2043 dst_x += (preview_width - real_preview_xsize * tile_size) / 2;
2044 dst_y += (preview_height - real_preview_ysize * tile_size) / 2;
2046 for (x = 0; x < real_preview_xsize; x++)
2048 for (y = 0; y < real_preview_ysize; y++)
2050 int lx = from_x + x + (show_level_border ? -1 : 0);
2051 int ly = from_y + y + (show_level_border ? -1 : 0);
2052 int element = (IN_LEV_FIELD(lx, ly) ? level.field[lx][ly] :
2053 getBorderElement(lx, ly));
2055 DrawPreviewElement(dst_x + x * tile_size, dst_y + y * tile_size,
2056 element, tile_size);
2060 redraw_mask |= REDRAW_MICROLEVEL;
2063 #define MICROLABEL_EMPTY 0
2064 #define MICROLABEL_LEVEL_NAME 1
2065 #define MICROLABEL_LEVEL_AUTHOR_HEAD 2
2066 #define MICROLABEL_LEVEL_AUTHOR 3
2067 #define MICROLABEL_IMPORTED_FROM_HEAD 4
2068 #define MICROLABEL_IMPORTED_FROM 5
2069 #define MICROLABEL_IMPORTED_BY_HEAD 6
2070 #define MICROLABEL_IMPORTED_BY 7
2072 static int getMaxTextLength(struct TextPosInfo *pos, int font_nr)
2074 int max_text_width = SXSIZE;
2075 int font_width = getFontWidth(font_nr);
2077 if (pos->align == ALIGN_CENTER)
2078 max_text_width = (pos->x < SXSIZE / 2 ? pos->x * 2 : (SXSIZE - pos->x) * 2);
2079 else if (pos->align == ALIGN_RIGHT)
2080 max_text_width = pos->x;
2082 max_text_width = SXSIZE - pos->x;
2084 return max_text_width / font_width;
2087 static void DrawPreviewLevelLabelExt(int mode)
2089 struct TextPosInfo *pos = &menu.main.text.level_info_2;
2090 char label_text[MAX_OUTPUT_LINESIZE + 1];
2091 int max_len_label_text;
2093 int font_nr = pos->font;
2096 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
2097 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
2098 mode == MICROLABEL_IMPORTED_BY_HEAD)
2099 font_nr = pos->font_alt;
2101 int font_nr = FONT_TEXT_2;
2104 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
2105 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
2106 mode == MICROLABEL_IMPORTED_BY_HEAD)
2107 font_nr = FONT_TEXT_3;
2111 max_len_label_text = getMaxTextLength(pos, font_nr);
2113 max_len_label_text = SXSIZE / getFontWidth(font_nr);
2117 if (pos->size != -1)
2118 max_len_label_text = pos->size;
2121 for (i = 0; i < max_len_label_text; i++)
2122 label_text[i] = ' ';
2123 label_text[max_len_label_text] = '\0';
2125 if (strlen(label_text) > 0)
2128 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2130 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
2131 int lypos = MICROLABEL2_YPOS;
2133 DrawText(lxpos, lypos, label_text, font_nr);
2138 (mode == MICROLABEL_LEVEL_NAME ? level.name :
2139 mode == MICROLABEL_LEVEL_AUTHOR_HEAD ? "created by" :
2140 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
2141 mode == MICROLABEL_IMPORTED_FROM_HEAD ? "imported from" :
2142 mode == MICROLABEL_IMPORTED_FROM ? leveldir_current->imported_from :
2143 mode == MICROLABEL_IMPORTED_BY_HEAD ? "imported by" :
2144 mode == MICROLABEL_IMPORTED_BY ? leveldir_current->imported_by :""),
2145 max_len_label_text);
2146 label_text[max_len_label_text] = '\0';
2148 if (strlen(label_text) > 0)
2151 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2153 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
2154 int lypos = MICROLABEL2_YPOS;
2156 DrawText(lxpos, lypos, label_text, font_nr);
2160 redraw_mask |= REDRAW_MICROLEVEL;
2163 void DrawPreviewLevel(boolean restart)
2165 static unsigned long scroll_delay = 0;
2166 static unsigned long label_delay = 0;
2167 static int from_x, from_y, scroll_direction;
2168 static int label_state, label_counter;
2169 unsigned long scroll_delay_value = preview.step_delay;
2170 boolean show_level_border = (BorderElement != EL_EMPTY);
2171 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
2172 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
2173 int last_game_status = game_status; /* save current game status */
2176 /* force PREVIEW font on preview level */
2177 game_status = GAME_MODE_PSEUDO_PREVIEW;
2185 if (preview.anim_mode == ANIM_CENTERED)
2187 if (level_xsize > preview.xsize)
2188 from_x = (level_xsize - preview.xsize) / 2;
2189 if (level_ysize > preview.ysize)
2190 from_y = (level_ysize - preview.ysize) / 2;
2193 from_x += preview.xoffset;
2194 from_y += preview.yoffset;
2196 scroll_direction = MV_RIGHT;
2200 DrawPreviewLevelExt(from_x, from_y);
2201 DrawPreviewLevelLabelExt(label_state);
2203 /* initialize delay counters */
2204 DelayReached(&scroll_delay, 0);
2205 DelayReached(&label_delay, 0);
2207 if (leveldir_current->name)
2209 struct TextPosInfo *pos = &menu.main.text.level_info_1;
2210 char label_text[MAX_OUTPUT_LINESIZE + 1];
2212 int font_nr = pos->font;
2214 int font_nr = FONT_TEXT_1;
2217 int max_len_label_text = getMaxTextLength(pos, font_nr);
2219 int max_len_label_text = SXSIZE / getFontWidth(font_nr);
2227 if (pos->size != -1)
2228 max_len_label_text = pos->size;
2231 strncpy(label_text, leveldir_current->name, max_len_label_text);
2232 label_text[max_len_label_text] = '\0';
2235 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2237 lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
2238 lypos = SY + MICROLABEL1_YPOS;
2240 DrawText(lxpos, lypos, label_text, font_nr);
2244 game_status = last_game_status; /* restore current game status */
2249 /* scroll preview level, if needed */
2250 if (preview.anim_mode != ANIM_NONE &&
2251 (level_xsize > preview.xsize || level_ysize > preview.ysize) &&
2252 DelayReached(&scroll_delay, scroll_delay_value))
2254 switch (scroll_direction)
2259 from_x -= preview.step_offset;
2260 from_x = (from_x < 0 ? 0 : from_x);
2263 scroll_direction = MV_UP;
2267 if (from_x < level_xsize - preview.xsize)
2269 from_x += preview.step_offset;
2270 from_x = (from_x > level_xsize - preview.xsize ?
2271 level_xsize - preview.xsize : from_x);
2274 scroll_direction = MV_DOWN;
2280 from_y -= preview.step_offset;
2281 from_y = (from_y < 0 ? 0 : from_y);
2284 scroll_direction = MV_RIGHT;
2288 if (from_y < level_ysize - preview.ysize)
2290 from_y += preview.step_offset;
2291 from_y = (from_y > level_ysize - preview.ysize ?
2292 level_ysize - preview.ysize : from_y);
2295 scroll_direction = MV_LEFT;
2302 DrawPreviewLevelExt(from_x, from_y);
2305 /* !!! THIS ALL SUCKS -- SHOULD BE CLEANLY REWRITTEN !!! */
2306 /* redraw micro level label, if needed */
2307 if (!strEqual(level.name, NAMELESS_LEVEL_NAME) &&
2308 !strEqual(level.author, ANONYMOUS_NAME) &&
2309 !strEqual(level.author, leveldir_current->name) &&
2310 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
2312 int max_label_counter = 23;
2314 if (leveldir_current->imported_from != NULL &&
2315 strlen(leveldir_current->imported_from) > 0)
2316 max_label_counter += 14;
2317 if (leveldir_current->imported_by != NULL &&
2318 strlen(leveldir_current->imported_by) > 0)
2319 max_label_counter += 14;
2321 label_counter = (label_counter + 1) % max_label_counter;
2322 label_state = (label_counter >= 0 && label_counter <= 7 ?
2323 MICROLABEL_LEVEL_NAME :
2324 label_counter >= 9 && label_counter <= 12 ?
2325 MICROLABEL_LEVEL_AUTHOR_HEAD :
2326 label_counter >= 14 && label_counter <= 21 ?
2327 MICROLABEL_LEVEL_AUTHOR :
2328 label_counter >= 23 && label_counter <= 26 ?
2329 MICROLABEL_IMPORTED_FROM_HEAD :
2330 label_counter >= 28 && label_counter <= 35 ?
2331 MICROLABEL_IMPORTED_FROM :
2332 label_counter >= 37 && label_counter <= 40 ?
2333 MICROLABEL_IMPORTED_BY_HEAD :
2334 label_counter >= 42 && label_counter <= 49 ?
2335 MICROLABEL_IMPORTED_BY : MICROLABEL_EMPTY);
2337 if (leveldir_current->imported_from == NULL &&
2338 (label_state == MICROLABEL_IMPORTED_FROM_HEAD ||
2339 label_state == MICROLABEL_IMPORTED_FROM))
2340 label_state = (label_state == MICROLABEL_IMPORTED_FROM_HEAD ?
2341 MICROLABEL_IMPORTED_BY_HEAD : MICROLABEL_IMPORTED_BY);
2343 DrawPreviewLevelLabelExt(label_state);
2346 game_status = last_game_status; /* restore current game status */
2349 inline void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
2350 int graphic, int sync_frame, int mask_mode)
2352 int frame = getGraphicAnimationFrame(graphic, sync_frame);
2354 if (mask_mode == USE_MASKING)
2355 DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
2357 DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
2360 inline void DrawGraphicAnimation(int x, int y, int graphic)
2362 int lx = LEVELX(x), ly = LEVELY(y);
2364 if (!IN_SCR_FIELD(x, y))
2367 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
2368 graphic, GfxFrame[lx][ly], NO_MASKING);
2369 MarkTileDirty(x, y);
2372 void DrawLevelGraphicAnimation(int x, int y, int graphic)
2374 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
2377 void DrawLevelElementAnimation(int x, int y, int element)
2379 int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
2381 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
2384 inline void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
2386 int sx = SCREENX(x), sy = SCREENY(y);
2388 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
2391 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
2394 DrawGraphicAnimation(sx, sy, graphic);
2397 if (GFX_CRUMBLED(TILE_GFX_ELEMENT(x, y)))
2398 DrawLevelFieldCrumbledSand(x, y);
2400 if (GFX_CRUMBLED(Feld[x][y]))
2401 DrawLevelFieldCrumbledSand(x, y);
2405 void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
2407 int sx = SCREENX(x), sy = SCREENY(y);
2410 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
2413 graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
2415 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
2418 DrawGraphicAnimation(sx, sy, graphic);
2420 if (GFX_CRUMBLED(element))
2421 DrawLevelFieldCrumbledSand(x, y);
2424 static int getPlayerGraphic(struct PlayerInfo *player, int move_dir)
2426 if (player->use_murphy)
2428 /* this works only because currently only one player can be "murphy" ... */
2429 static int last_horizontal_dir = MV_LEFT;
2430 int graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir);
2432 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
2433 last_horizontal_dir = move_dir;
2435 if (graphic == IMG_SP_MURPHY) /* undefined => use special graphic */
2437 int direction = (player->is_snapping ? move_dir : last_horizontal_dir);
2439 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
2445 return el_act_dir2img(player->artwork_element, player->GfxAction,move_dir);
2448 static boolean equalGraphics(int graphic1, int graphic2)
2450 struct GraphicInfo *g1 = &graphic_info[graphic1];
2451 struct GraphicInfo *g2 = &graphic_info[graphic2];
2453 return (g1->bitmap == g2->bitmap &&
2454 g1->src_x == g2->src_x &&
2455 g1->src_y == g2->src_y &&
2456 g1->anim_frames == g2->anim_frames &&
2457 g1->anim_delay == g2->anim_delay &&
2458 g1->anim_mode == g2->anim_mode);
2461 void DrawAllPlayers()
2465 for (i = 0; i < MAX_PLAYERS; i++)
2466 if (stored_player[i].active)
2467 DrawPlayer(&stored_player[i]);
2470 void DrawPlayerField(int x, int y)
2472 if (!IS_PLAYER(x, y))
2475 DrawPlayer(PLAYERINFO(x, y));
2478 #define TEST_DRAW_PLAYER_OVER_PUSHED_ELEMENT 1
2480 void DrawPlayer(struct PlayerInfo *player)
2482 int jx = player->jx;
2483 int jy = player->jy;
2484 int move_dir = player->MovDir;
2485 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? +1 : 0);
2486 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? +1 : 0);
2487 int last_jx = (player->is_moving ? jx - dx : jx);
2488 int last_jy = (player->is_moving ? jy - dy : jy);
2489 int next_jx = jx + dx;
2490 int next_jy = jy + dy;
2491 boolean player_is_moving = (player->MovPos ? TRUE : FALSE);
2492 boolean player_is_opaque = FALSE;
2493 int sx = SCREENX(jx), sy = SCREENY(jy);
2494 int sxx = 0, syy = 0;
2495 int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
2497 int action = ACTION_DEFAULT;
2498 int last_player_graphic = getPlayerGraphic(player, move_dir);
2499 int last_player_frame = player->Frame;
2502 /* GfxElement[][] is set to the element the player is digging or collecting;
2503 remove also for off-screen player if the player is not moving anymore */
2504 if (IN_LEV_FIELD(jx, jy) && !player_is_moving)
2505 GfxElement[jx][jy] = EL_UNDEFINED;
2507 if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
2511 if (!IN_LEV_FIELD(jx, jy))
2513 printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
2514 printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
2515 printf("DrawPlayerField(): This should never happen!\n");
2520 if (element == EL_EXPLOSION)
2523 action = (player->is_pushing ? ACTION_PUSHING :
2524 player->is_digging ? ACTION_DIGGING :
2525 player->is_collecting ? ACTION_COLLECTING :
2526 player->is_moving ? ACTION_MOVING :
2527 player->is_snapping ? ACTION_SNAPPING :
2528 player->is_dropping ? ACTION_DROPPING :
2529 player->is_waiting ? player->action_waiting : ACTION_DEFAULT);
2531 if (player->is_waiting)
2532 move_dir = player->dir_waiting;
2534 InitPlayerGfxAnimation(player, action, move_dir);
2536 /* ----------------------------------------------------------------------- */
2537 /* draw things in the field the player is leaving, if needed */
2538 /* ----------------------------------------------------------------------- */
2540 if (player->is_moving)
2542 if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
2544 DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
2546 if (last_element == EL_DYNAMITE_ACTIVE ||
2547 last_element == EL_EM_DYNAMITE_ACTIVE ||
2548 last_element == EL_SP_DISK_RED_ACTIVE)
2549 DrawDynamite(last_jx, last_jy);
2551 DrawLevelFieldThruMask(last_jx, last_jy);
2553 else if (last_element == EL_DYNAMITE_ACTIVE ||
2554 last_element == EL_EM_DYNAMITE_ACTIVE ||
2555 last_element == EL_SP_DISK_RED_ACTIVE)
2556 DrawDynamite(last_jx, last_jy);
2558 /* !!! this is not enough to prevent flickering of players which are
2559 moving next to each others without a free tile between them -- this
2560 can only be solved by drawing all players layer by layer (first the
2561 background, then the foreground etc.) !!! => TODO */
2562 else if (!IS_PLAYER(last_jx, last_jy))
2563 DrawLevelField(last_jx, last_jy);
2566 DrawLevelField(last_jx, last_jy);
2569 if (player->is_pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
2570 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
2573 if (!IN_SCR_FIELD(sx, sy))
2576 /* ----------------------------------------------------------------------- */
2577 /* draw things behind the player, if needed */
2578 /* ----------------------------------------------------------------------- */
2581 DrawLevelElement(jx, jy, Back[jx][jy]);
2582 else if (IS_ACTIVE_BOMB(element))
2583 DrawLevelElement(jx, jy, EL_EMPTY);
2586 if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
2588 int old_element = GfxElement[jx][jy];
2589 int old_graphic = el_act_dir2img(old_element, action, move_dir);
2590 int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
2592 if (GFX_CRUMBLED(old_element))
2593 DrawLevelFieldCrumbledSandDigging(jx, jy, move_dir, player->StepFrame);
2595 DrawGraphic(sx, sy, old_graphic, frame);
2597 if (graphic_info[old_graphic].anim_mode & ANIM_OPAQUE_PLAYER)
2598 player_is_opaque = TRUE;
2602 GfxElement[jx][jy] = EL_UNDEFINED;
2604 /* make sure that pushed elements are drawn with correct frame rate */
2606 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
2608 if (player->is_pushing && player->is_moving && !IS_ANIM_MODE_CE(graphic))
2609 GfxFrame[jx][jy] = player->StepFrame;
2611 if (player->is_pushing && player->is_moving)
2612 GfxFrame[jx][jy] = player->StepFrame;
2615 DrawLevelField(jx, jy);
2619 #if !TEST_DRAW_PLAYER_OVER_PUSHED_ELEMENT
2620 /* ----------------------------------------------------------------------- */
2621 /* draw player himself */
2622 /* ----------------------------------------------------------------------- */
2624 graphic = getPlayerGraphic(player, move_dir);
2626 /* in the case of changed player action or direction, prevent the current
2627 animation frame from being restarted for identical animations */
2628 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
2629 player->Frame = last_player_frame;
2631 frame = getGraphicAnimationFrame(graphic, player->Frame);
2635 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
2636 sxx = player->GfxPos;
2638 syy = player->GfxPos;
2641 if (!setup.soft_scrolling && ScreenMovPos)
2644 if (player_is_opaque)
2645 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
2647 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
2649 if (SHIELD_ON(player))
2651 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
2652 IMG_SHIELD_NORMAL_ACTIVE);
2653 int frame = getGraphicAnimationFrame(graphic, -1);
2655 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
2659 #if TEST_DRAW_PLAYER_OVER_PUSHED_ELEMENT
2662 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
2663 sxx = player->GfxPos;
2665 syy = player->GfxPos;
2669 /* ----------------------------------------------------------------------- */
2670 /* draw things the player is pushing, if needed */
2671 /* ----------------------------------------------------------------------- */
2674 printf("::: %d, %d [%d, %d] [%d]\n",
2675 player->is_pushing, player_is_moving, player->GfxAction,
2676 player->is_moving, player_is_moving);
2680 if (player->is_pushing && player->is_moving)
2682 int px = SCREENX(jx), py = SCREENY(jy);
2683 int pxx = (TILEX - ABS(sxx)) * dx;
2684 int pyy = (TILEY - ABS(syy)) * dy;
2685 int gfx_frame = GfxFrame[jx][jy];
2691 if (!IS_MOVING(jx, jy)) /* push movement already finished */
2693 element = Feld[next_jx][next_jy];
2694 gfx_frame = GfxFrame[next_jx][next_jy];
2697 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
2700 sync_frame = (IS_ANIM_MODE_CE(graphic) ? gfx_frame : player->StepFrame);
2701 frame = getGraphicAnimationFrame(graphic, sync_frame);
2703 frame = getGraphicAnimationFrame(graphic, player->StepFrame);
2706 /* draw background element under pushed element (like the Sokoban field) */
2707 if (Back[next_jx][next_jy])
2708 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
2711 printf("::: %d, %d, %d [%d] [%d, %d, %d] [%d] [%d, %d]\n",
2712 jx, px, player->GfxPos, player->is_pushing, dx, sxx, pxx,
2713 IS_MOVING(jx, jy), graphic, frame);
2717 /* do not draw (EM style) pushing animation when pushing is finished */
2718 if (graphic_info[graphic].double_movement && !IS_MOVING(jx, jy))
2719 DrawLevelElement(next_jx, next_jy, Feld[next_jx][next_jy]);
2721 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
2723 /* masked drawing is needed for EMC style (double) movement graphics */
2724 /* !!! (ONLY WHEN DRAWING PUSHED ELEMENT OVER THE PLAYER) !!! */
2725 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
2730 #if TEST_DRAW_PLAYER_OVER_PUSHED_ELEMENT
2731 /* ----------------------------------------------------------------------- */
2732 /* draw player himself */
2733 /* ----------------------------------------------------------------------- */
2735 graphic = getPlayerGraphic(player, move_dir);
2737 /* in the case of changed player action or direction, prevent the current
2738 animation frame from being restarted for identical animations */
2739 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
2740 player->Frame = last_player_frame;
2742 frame = getGraphicAnimationFrame(graphic, player->Frame);
2746 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
2747 sxx = player->GfxPos;
2749 syy = player->GfxPos;
2752 if (!setup.soft_scrolling && ScreenMovPos)
2755 if (player_is_opaque)
2756 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
2758 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
2760 if (SHIELD_ON(player))
2762 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
2763 IMG_SHIELD_NORMAL_ACTIVE);
2764 int frame = getGraphicAnimationFrame(graphic, -1);
2766 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
2770 /* ----------------------------------------------------------------------- */
2771 /* draw things in front of player (active dynamite or dynabombs) */
2772 /* ----------------------------------------------------------------------- */
2774 if (IS_ACTIVE_BOMB(element))
2776 graphic = el2img(element);
2777 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
2779 if (game.emulation == EMU_SUPAPLEX)
2780 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
2782 DrawGraphicThruMask(sx, sy, graphic, frame);
2785 if (player_is_moving && last_element == EL_EXPLOSION)
2787 int element = (GfxElement[last_jx][last_jy] != EL_UNDEFINED ?
2788 GfxElement[last_jx][last_jy] : EL_EMPTY);
2789 int graphic = el_act2img(element, ACTION_EXPLODING);
2790 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
2791 int phase = ExplodePhase[last_jx][last_jy] - 1;
2792 int frame = getGraphicAnimationFrame(graphic, phase - delay);
2795 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
2798 /* ----------------------------------------------------------------------- */
2799 /* draw elements the player is just walking/passing through/under */
2800 /* ----------------------------------------------------------------------- */
2802 if (player_is_moving)
2804 /* handle the field the player is leaving ... */
2805 if (IS_ACCESSIBLE_INSIDE(last_element))
2806 DrawLevelField(last_jx, last_jy);
2807 else if (IS_ACCESSIBLE_UNDER(last_element))
2808 DrawLevelFieldThruMask(last_jx, last_jy);
2811 /* do not redraw accessible elements if the player is just pushing them */
2812 if (!player_is_moving || !player->is_pushing)
2814 /* ... and the field the player is entering */
2815 if (IS_ACCESSIBLE_INSIDE(element))
2816 DrawLevelField(jx, jy);
2817 else if (IS_ACCESSIBLE_UNDER(element))
2818 DrawLevelFieldThruMask(jx, jy);
2821 MarkTileDirty(sx, sy);
2824 /* ------------------------------------------------------------------------- */
2826 void WaitForEventToContinue()
2828 boolean still_wait = TRUE;
2830 /* simulate releasing mouse button over last gadget, if still pressed */
2832 HandleGadgets(-1, -1, 0);
2834 button_status = MB_RELEASED;
2850 case EVENT_BUTTONPRESS:
2851 case EVENT_KEYPRESS:
2855 case EVENT_KEYRELEASE:
2856 ClearPlayerAction();
2860 HandleOtherEvents(&event);
2864 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2871 /* don't eat all CPU time */
2876 #define MAX_REQUEST_LINES 13
2877 #define MAX_REQUEST_LINE_FONT1_LEN 7
2878 #define MAX_REQUEST_LINE_FONT2_LEN 10
2880 boolean Request(char *text, unsigned int req_state)
2882 int mx, my, ty, result = -1;
2883 unsigned int old_door_state;
2884 int last_game_status = game_status; /* save current game status */
2885 int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
2886 int font_nr = FONT_TEXT_2;
2887 int max_word_len = 0;
2890 for (text_ptr = text; *text_ptr; text_ptr++)
2892 max_word_len = (*text_ptr != ' ' ? max_word_len + 1 : 0);
2894 if (max_word_len > MAX_REQUEST_LINE_FONT1_LEN)
2896 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
2898 font_nr = FONT_TEXT_1;
2900 font_nr = FONT_LEVEL_NUMBER;
2907 if (game_status == GAME_MODE_PLAYING)
2909 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
2910 BlitScreenToBitmap_EM(backbuffer);
2911 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
2912 BlitScreenToBitmap_SP(backbuffer);
2915 /* disable deactivated drawing when quick-loading level tape recording */
2916 if (tape.playing && tape.deactivate_display)
2917 TapeDeactivateDisplayOff(TRUE);
2919 SetMouseCursor(CURSOR_DEFAULT);
2921 #if defined(NETWORK_AVALIABLE)
2922 /* pause network game while waiting for request to answer */
2923 if (options.network &&
2924 game_status == GAME_MODE_PLAYING &&
2925 req_state & REQUEST_WAIT_FOR_INPUT)
2926 SendToServer_PausePlaying();
2929 old_door_state = GetDoorState();
2931 /* simulate releasing mouse button over last gadget, if still pressed */
2933 HandleGadgets(-1, -1, 0);
2937 if (old_door_state & DOOR_OPEN_1)
2939 CloseDoor(DOOR_CLOSE_1);
2941 /* save old door content */
2942 BlitBitmap(bitmap_db_door, bitmap_db_door,
2943 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
2944 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
2948 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
2951 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2953 /* clear door drawing field */
2954 DrawBackground(DX, DY, DXSIZE, DYSIZE);
2956 /* force DOOR font inside door area */
2957 game_status = GAME_MODE_PSEUDO_DOOR;
2959 /* write text for request */
2960 for (ty = 0; ty < MAX_REQUEST_LINES; ty++)
2962 char text_line[max_request_line_len + 1];
2968 for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
2971 if (!tc || tc == ' ')
2982 strncpy(text_line, text, tl);
2985 DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
2986 DY + 8 + ty * (getFontHeight(font_nr) + 2),
2987 text_line, font_nr);
2989 text += tl + (tc == ' ' ? 1 : 0);
2992 game_status = last_game_status; /* restore current game status */
2994 if (req_state & REQ_ASK)
2996 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
2997 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
2999 else if (req_state & REQ_CONFIRM)
3001 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
3003 else if (req_state & REQ_PLAYER)
3005 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
3006 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
3007 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
3008 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
3011 /* copy request gadgets to door backbuffer */
3012 BlitBitmap(drawto, bitmap_db_door,
3013 DX, DY, DXSIZE, DYSIZE,
3014 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
3016 OpenDoor(DOOR_OPEN_1);
3018 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
3020 if (game_status == GAME_MODE_PLAYING)
3022 SetPanelBackground();
3023 SetDrawBackgroundMask(REDRAW_DOOR_1);
3027 SetDrawBackgroundMask(REDRAW_FIELD);
3033 if (game_status != GAME_MODE_MAIN)
3036 button_status = MB_RELEASED;
3038 request_gadget_id = -1;
3040 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3052 case EVENT_BUTTONPRESS:
3053 case EVENT_BUTTONRELEASE:
3054 case EVENT_MOTIONNOTIFY:
3056 if (event.type == EVENT_MOTIONNOTIFY)
3058 if (!PointerInWindow(window))
3059 continue; /* window and pointer are on different screens */
3064 motion_status = TRUE;
3065 mx = ((MotionEvent *) &event)->x;
3066 my = ((MotionEvent *) &event)->y;
3070 motion_status = FALSE;
3071 mx = ((ButtonEvent *) &event)->x;
3072 my = ((ButtonEvent *) &event)->y;
3073 if (event.type == EVENT_BUTTONPRESS)
3074 button_status = ((ButtonEvent *) &event)->button;
3076 button_status = MB_RELEASED;
3079 /* this sets 'request_gadget_id' */
3080 HandleGadgets(mx, my, button_status);
3082 switch (request_gadget_id)
3084 case TOOL_CTRL_ID_YES:
3087 case TOOL_CTRL_ID_NO:
3090 case TOOL_CTRL_ID_CONFIRM:
3091 result = TRUE | FALSE;
3094 case TOOL_CTRL_ID_PLAYER_1:
3097 case TOOL_CTRL_ID_PLAYER_2:
3100 case TOOL_CTRL_ID_PLAYER_3:
3103 case TOOL_CTRL_ID_PLAYER_4:
3114 case EVENT_KEYPRESS:
3115 switch (GetEventKey((KeyEvent *)&event, TRUE))
3118 if (req_state & REQ_CONFIRM)
3134 if (req_state & REQ_PLAYER)
3138 case EVENT_KEYRELEASE:
3139 ClearPlayerAction();
3143 HandleOtherEvents(&event);
3147 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
3149 int joy = AnyJoystick();
3151 if (joy & JOY_BUTTON_1)
3153 else if (joy & JOY_BUTTON_2)
3159 if (game_status == GAME_MODE_PLAYING && local_player->LevelSolved_GameEnd)
3161 HandleGameActions();
3167 if (!PendingEvent()) /* delay only if no pending events */
3178 if (!PendingEvent()) /* delay only if no pending events */
3181 /* don't eat all CPU time */
3188 if (game_status != GAME_MODE_MAIN)
3193 if (!(req_state & REQ_STAY_OPEN))
3195 CloseDoor(DOOR_CLOSE_1);
3197 if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
3198 (req_state & REQ_REOPEN))
3199 OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
3204 if (game_status == GAME_MODE_PLAYING)
3206 SetPanelBackground();
3207 SetDrawBackgroundMask(REDRAW_DOOR_1);
3211 SetDrawBackgroundMask(REDRAW_FIELD);
3214 #if defined(NETWORK_AVALIABLE)
3215 /* continue network game after request */
3216 if (options.network &&
3217 game_status == GAME_MODE_PLAYING &&
3218 req_state & REQUEST_WAIT_FOR_INPUT)
3219 SendToServer_ContinuePlaying();
3222 /* restore deactivated drawing when quick-loading level tape recording */
3223 if (tape.playing && tape.deactivate_display)
3224 TapeDeactivateDisplayOn();
3229 unsigned int OpenDoor(unsigned int door_state)
3231 if (door_state & DOOR_COPY_BACK)
3233 if (door_state & DOOR_OPEN_1)
3234 BlitBitmap(bitmap_db_door, bitmap_db_door,
3235 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
3236 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
3238 if (door_state & DOOR_OPEN_2)
3239 BlitBitmap(bitmap_db_door, bitmap_db_door,
3240 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY2, VXSIZE, VYSIZE,
3241 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
3243 door_state &= ~DOOR_COPY_BACK;
3246 return MoveDoor(door_state);
3249 unsigned int CloseDoor(unsigned int door_state)
3251 unsigned int old_door_state = GetDoorState();
3253 if (!(door_state & DOOR_NO_COPY_BACK))
3255 if (old_door_state & DOOR_OPEN_1)
3256 BlitBitmap(backbuffer, bitmap_db_door,
3257 DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
3259 if (old_door_state & DOOR_OPEN_2)
3260 BlitBitmap(backbuffer, bitmap_db_door,
3261 VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
3263 door_state &= ~DOOR_NO_COPY_BACK;
3266 return MoveDoor(door_state);
3269 unsigned int GetDoorState()
3271 return MoveDoor(DOOR_GET_STATE);
3274 unsigned int SetDoorState(unsigned int door_state)
3276 return MoveDoor(door_state | DOOR_SET_STATE);
3279 unsigned int MoveDoor(unsigned int door_state)
3281 static int door1 = DOOR_OPEN_1;
3282 static int door2 = DOOR_CLOSE_2;
3283 unsigned long door_delay = 0;
3284 unsigned long door_delay_value;
3287 if (door_1.width < 0 || door_1.width > DXSIZE)
3288 door_1.width = DXSIZE;
3289 if (door_1.height < 0 || door_1.height > DYSIZE)
3290 door_1.height = DYSIZE;
3291 if (door_2.width < 0 || door_2.width > VXSIZE)
3292 door_2.width = VXSIZE;
3293 if (door_2.height < 0 || door_2.height > VYSIZE)
3294 door_2.height = VYSIZE;
3296 if (door_state == DOOR_GET_STATE)
3297 return (door1 | door2);
3299 if (door_state & DOOR_SET_STATE)
3301 if (door_state & DOOR_ACTION_1)
3302 door1 = door_state & DOOR_ACTION_1;
3303 if (door_state & DOOR_ACTION_2)
3304 door2 = door_state & DOOR_ACTION_2;
3306 return (door1 | door2);
3309 if (!(door_state & DOOR_FORCE_REDRAW))
3311 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
3312 door_state &= ~DOOR_OPEN_1;
3313 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
3314 door_state &= ~DOOR_CLOSE_1;
3315 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
3316 door_state &= ~DOOR_OPEN_2;
3317 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
3318 door_state &= ~DOOR_CLOSE_2;
3321 door_delay_value = (door_state & DOOR_ACTION_1 ? door_1.step_delay :
3324 if (setup.quick_doors)
3326 stepsize = 20; /* must be chosen to always draw last frame */
3327 door_delay_value = 0;
3330 if (global.autoplay_leveldir)
3332 door_state |= DOOR_NO_DELAY;
3333 door_state &= ~DOOR_CLOSE_ALL;
3337 if (game_status == GAME_MODE_EDITOR)
3338 door_state |= DOOR_NO_DELAY;
3341 if (door_state & DOOR_ACTION)
3343 boolean handle_door_1 = (door_state & DOOR_ACTION_1);
3344 boolean handle_door_2 = (door_state & DOOR_ACTION_2);
3345 boolean door_1_done = (!handle_door_1);
3346 boolean door_2_done = (!handle_door_2);
3347 boolean door_1_vertical = (door_1.anim_mode & ANIM_VERTICAL);
3348 boolean door_2_vertical = (door_2.anim_mode & ANIM_VERTICAL);
3349 int door_size_1 = (door_1_vertical ? door_1.height : door_1.width);
3350 int door_size_2 = (door_2_vertical ? door_2.height : door_2.width);
3351 int max_door_size_1 = (door_1_vertical ? DYSIZE : DXSIZE);
3352 int max_door_size_2 = (door_2_vertical ? VYSIZE : VXSIZE);
3353 int door_size = (handle_door_1 ? door_size_1 : door_size_2);
3354 int max_door_size = (handle_door_1 ? max_door_size_1 : max_door_size_2);
3355 int door_skip = max_door_size - door_size;
3356 int end = door_size;
3357 int start = ((door_state & DOOR_NO_DELAY) ? end : 0);
3360 if (!(door_state & DOOR_NO_DELAY) && !setup.quick_doors)
3362 /* opening door sound has priority over simultaneously closing door */
3363 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
3364 PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
3365 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
3366 PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
3369 for (k = start; k <= end && !(door_1_done && door_2_done); k += stepsize)
3372 Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
3373 GC gc = bitmap->stored_clip_gc;
3375 if (door_state & DOOR_ACTION_1)
3377 int a = MIN(x * door_1.step_offset, end);
3378 int p = (door_state & DOOR_OPEN_1 ? end - a : a);
3379 int i = p + door_skip;
3381 if (door_1.anim_mode & ANIM_STATIC_PANEL)
3383 BlitBitmap(bitmap_db_door, drawto,
3384 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1,
3385 DXSIZE, DYSIZE, DX, DY);
3389 BlitBitmap(bitmap_db_door, drawto,
3390 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + p / 2,
3391 DXSIZE, DYSIZE - p / 2, DX, DY);
3393 ClearRectangle(drawto, DX, DY + DYSIZE - p / 2, DXSIZE, p / 2);
3396 if (door_1.anim_mode & ANIM_HORIZONTAL && x <= DXSIZE)
3398 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
3399 int dst1_x = DX + DXSIZE - i, dst1_y = DY;
3400 int src2_x = DXSIZE - i, src2_y = DOOR_GFX_PAGEY1;
3401 int dst2_x = DX, dst2_y = DY;
3402 int width = i, height = DYSIZE;
3404 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3405 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3408 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3409 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3412 else if (door_1.anim_mode & ANIM_VERTICAL && x <= DYSIZE)
3414 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
3415 int dst1_x = DX, dst1_y = DY + DYSIZE - i;
3416 int src2_x = 0, src2_y = DOOR_GFX_PAGEY1 + DYSIZE - i;
3417 int dst2_x = DX, dst2_y = DY;
3418 int width = DXSIZE, height = i;
3420 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3421 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3424 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3425 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3428 else if (x <= DXSIZE) /* ANIM_DEFAULT */
3430 int j = (door_1.anim_mode == ANIM_DEFAULT ? (DXSIZE - i) / 3 : 0);
3432 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
3433 BlitBitmapMasked(bitmap, drawto,
3434 DXSIZE, DOOR_GFX_PAGEY1, i, 77,
3435 DX + DXSIZE - i, DY + j);
3436 BlitBitmapMasked(bitmap, drawto,
3437 DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
3438 DX + DXSIZE - i, DY + 140 + j);
3439 SetClipOrigin(bitmap, gc, DX - DXSIZE + i,
3440 DY - (DOOR_GFX_PAGEY1 + j));
3441 BlitBitmapMasked(bitmap, drawto,
3442 DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
3444 BlitBitmapMasked(bitmap, drawto,
3445 DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
3448 BlitBitmapMasked(bitmap, drawto,
3449 DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
3451 BlitBitmapMasked(bitmap, drawto,
3452 DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
3454 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
3455 BlitBitmapMasked(bitmap, drawto,
3456 DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
3457 DX + DXSIZE - i, DY + 77 + j);
3458 BlitBitmapMasked(bitmap, drawto,
3459 DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
3460 DX + DXSIZE - i, DY + 203 + j);
3463 redraw_mask |= REDRAW_DOOR_1;
3464 door_1_done = (a == end);
3467 if (door_state & DOOR_ACTION_2)
3469 int a = MIN(x * door_2.step_offset, door_size);
3470 int p = (door_state & DOOR_OPEN_2 ? door_size - a : a);
3471 int i = p + door_skip;
3473 if (door_2.anim_mode & ANIM_STATIC_PANEL)
3475 BlitBitmap(bitmap_db_door, drawto,
3476 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2,
3477 VXSIZE, VYSIZE, VX, VY);
3479 else if (x <= VYSIZE)
3481 BlitBitmap(bitmap_db_door, drawto,
3482 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + p / 2,
3483 VXSIZE, VYSIZE - p / 2, VX, VY);
3485 ClearRectangle(drawto, VX, VY + VYSIZE - p / 2, VXSIZE, p / 2);
3488 if (door_2.anim_mode & ANIM_HORIZONTAL && x <= VXSIZE)
3490 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
3491 int dst1_x = VX + VXSIZE - i, dst1_y = VY;
3492 int src2_x = VXSIZE - i, src2_y = DOOR_GFX_PAGEY2;
3493 int dst2_x = VX, dst2_y = VY;
3494 int width = i, height = VYSIZE;
3496 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3497 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3500 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3501 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3504 else if (door_2.anim_mode & ANIM_VERTICAL && x <= VYSIZE)
3506 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
3507 int dst1_x = VX, dst1_y = VY + VYSIZE - i;
3508 int src2_x = 0, src2_y = DOOR_GFX_PAGEY2 + VYSIZE - i;
3509 int dst2_x = VX, dst2_y = VY;
3510 int width = VXSIZE, height = i;
3512 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3513 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3516 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3517 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3520 else if (x <= VXSIZE) /* ANIM_DEFAULT */
3522 int j = (door_2.anim_mode == ANIM_DEFAULT ? (VXSIZE - i) / 3 : 0);
3524 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
3525 BlitBitmapMasked(bitmap, drawto,
3526 VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
3527 VX + VXSIZE - i, VY + j);
3528 SetClipOrigin(bitmap, gc,
3529 VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
3530 BlitBitmapMasked(bitmap, drawto,
3531 VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
3534 BlitBitmapMasked(bitmap, drawto,
3535 VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
3536 i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
3537 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
3538 BlitBitmapMasked(bitmap, drawto,
3539 VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
3541 VX + VXSIZE - i, VY + VYSIZE / 2 + j);
3544 redraw_mask |= REDRAW_DOOR_2;
3545 door_2_done = (a == VXSIZE);
3548 if (!(door_state & DOOR_NO_DELAY))
3552 if (game_status == GAME_MODE_MAIN)
3555 WaitUntilDelayReached(&door_delay, door_delay_value);
3560 if (door_state & DOOR_ACTION_1)
3561 door1 = door_state & DOOR_ACTION_1;
3562 if (door_state & DOOR_ACTION_2)
3563 door2 = door_state & DOOR_ACTION_2;
3565 return (door1 | door2);
3568 void DrawSpecialEditorDoor()
3570 /* draw bigger toolbox window */
3571 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
3572 DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
3574 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
3575 EX - 6, VY - 4, EXSIZE + 12, EYSIZE - VYSIZE + 4,
3578 redraw_mask |= REDRAW_ALL;
3581 void UndrawSpecialEditorDoor()
3583 /* draw normal tape recorder window */
3584 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
3585 EX - 6, EY - 12, EXSIZE + 12, EYSIZE - VYSIZE + 12,
3588 redraw_mask |= REDRAW_ALL;
3592 /* ---------- new tool button stuff ---------------------------------------- */
3594 /* graphic position values for tool buttons */
3595 #define TOOL_BUTTON_YES_XPOS 2
3596 #define TOOL_BUTTON_YES_YPOS 250
3597 #define TOOL_BUTTON_YES_GFX_YPOS 0
3598 #define TOOL_BUTTON_YES_XSIZE 46
3599 #define TOOL_BUTTON_YES_YSIZE 28
3600 #define TOOL_BUTTON_NO_XPOS 52
3601 #define TOOL_BUTTON_NO_YPOS TOOL_BUTTON_YES_YPOS
3602 #define TOOL_BUTTON_NO_GFX_YPOS TOOL_BUTTON_YES_GFX_YPOS
3603 #define TOOL_BUTTON_NO_XSIZE TOOL_BUTTON_YES_XSIZE
3604 #define TOOL_BUTTON_NO_YSIZE TOOL_BUTTON_YES_YSIZE
3605 #define TOOL_BUTTON_CONFIRM_XPOS TOOL_BUTTON_YES_XPOS
3606 #define TOOL_BUTTON_CONFIRM_YPOS TOOL_BUTTON_YES_YPOS
3607 #define TOOL_BUTTON_CONFIRM_GFX_YPOS 30
3608 #define TOOL_BUTTON_CONFIRM_XSIZE 96
3609 #define TOOL_BUTTON_CONFIRM_YSIZE TOOL_BUTTON_YES_YSIZE
3610 #define TOOL_BUTTON_PLAYER_XSIZE 30
3611 #define TOOL_BUTTON_PLAYER_YSIZE 30
3612 #define TOOL_BUTTON_PLAYER_GFX_XPOS 5
3613 #define TOOL_BUTTON_PLAYER_GFX_YPOS 185
3614 #define TOOL_BUTTON_PLAYER_XPOS (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
3615 #define TOOL_BUTTON_PLAYER_YPOS (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
3616 #define TOOL_BUTTON_PLAYER1_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3617 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
3618 #define TOOL_BUTTON_PLAYER2_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3619 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
3620 #define TOOL_BUTTON_PLAYER3_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3621 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
3622 #define TOOL_BUTTON_PLAYER4_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3623 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
3624 #define TOOL_BUTTON_PLAYER1_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3625 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
3626 #define TOOL_BUTTON_PLAYER2_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3627 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
3628 #define TOOL_BUTTON_PLAYER3_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3629 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
3630 #define TOOL_BUTTON_PLAYER4_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3631 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
3640 } toolbutton_info[NUM_TOOL_BUTTONS] =
3643 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_GFX_YPOS,
3644 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_YPOS,
3645 TOOL_BUTTON_YES_XSIZE, TOOL_BUTTON_YES_YSIZE,
3650 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_GFX_YPOS,
3651 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_YPOS,
3652 TOOL_BUTTON_NO_XSIZE, TOOL_BUTTON_NO_YSIZE,
3657 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_GFX_YPOS,
3658 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_YPOS,
3659 TOOL_BUTTON_CONFIRM_XSIZE, TOOL_BUTTON_CONFIRM_YSIZE,
3660 TOOL_CTRL_ID_CONFIRM,
3664 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3665 TOOL_BUTTON_PLAYER1_XPOS, TOOL_BUTTON_PLAYER1_YPOS,
3666 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3667 TOOL_CTRL_ID_PLAYER_1,
3671 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3672 TOOL_BUTTON_PLAYER2_XPOS, TOOL_BUTTON_PLAYER2_YPOS,
3673 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3674 TOOL_CTRL_ID_PLAYER_2,
3678 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3679 TOOL_BUTTON_PLAYER3_XPOS, TOOL_BUTTON_PLAYER3_YPOS,
3680 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3681 TOOL_CTRL_ID_PLAYER_3,
3685 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3686 TOOL_BUTTON_PLAYER4_XPOS, TOOL_BUTTON_PLAYER4_YPOS,
3687 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3688 TOOL_CTRL_ID_PLAYER_4,
3693 void CreateToolButtons()
3697 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3699 Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
3700 Bitmap *deco_bitmap = None;
3701 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
3702 struct GadgetInfo *gi;
3703 unsigned long event_mask;
3704 int gd_xoffset, gd_yoffset;
3705 int gd_x1, gd_x2, gd_y;
3708 event_mask = GD_EVENT_RELEASED;
3710 gd_xoffset = toolbutton_info[i].xpos;
3711 gd_yoffset = toolbutton_info[i].ypos;
3712 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
3713 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
3714 gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
3716 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
3718 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
3720 getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr),
3721 &deco_bitmap, &deco_x, &deco_y);
3722 deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
3723 deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
3726 gi = CreateGadget(GDI_CUSTOM_ID, id,
3727 GDI_INFO_TEXT, toolbutton_info[i].infotext,
3728 GDI_X, DX + toolbutton_info[i].x,
3729 GDI_Y, DY + toolbutton_info[i].y,
3730 GDI_WIDTH, toolbutton_info[i].width,
3731 GDI_HEIGHT, toolbutton_info[i].height,
3732 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
3733 GDI_STATE, GD_BUTTON_UNPRESSED,
3734 GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
3735 GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
3736 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
3737 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
3738 GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
3739 GDI_DECORATION_SHIFTING, 1, 1,
3740 GDI_DIRECT_DRAW, FALSE,
3741 GDI_EVENT_MASK, event_mask,
3742 GDI_CALLBACK_ACTION, HandleToolButtons,
3746 Error(ERR_EXIT, "cannot create gadget");
3748 tool_gadget[id] = gi;
3752 void FreeToolButtons()
3756 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3757 FreeGadget(tool_gadget[i]);
3760 static void UnmapToolButtons()
3764 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3765 UnmapGadget(tool_gadget[i]);
3768 static void HandleToolButtons(struct GadgetInfo *gi)
3770 request_gadget_id = gi->custom_id;
3773 static struct Mapping_EM_to_RND_object
3776 boolean is_rnd_to_em_mapping; /* unique mapping EM <-> RND */
3777 boolean is_backside; /* backside of moving element */
3783 em_object_mapping_list[] =
3786 Xblank, TRUE, FALSE,
3790 Yacid_splash_eB, FALSE, FALSE,
3791 EL_ACID_SPLASH_RIGHT, -1, -1
3794 Yacid_splash_wB, FALSE, FALSE,
3795 EL_ACID_SPLASH_LEFT, -1, -1
3798 #ifdef EM_ENGINE_BAD_ROLL
3800 Xstone_force_e, FALSE, FALSE,
3801 EL_ROCK, -1, MV_BIT_RIGHT
3804 Xstone_force_w, FALSE, FALSE,
3805 EL_ROCK, -1, MV_BIT_LEFT
3808 Xnut_force_e, FALSE, FALSE,
3809 EL_NUT, -1, MV_BIT_RIGHT
3812 Xnut_force_w, FALSE, FALSE,
3813 EL_NUT, -1, MV_BIT_LEFT
3816 Xspring_force_e, FALSE, FALSE,
3817 EL_SPRING, -1, MV_BIT_RIGHT
3820 Xspring_force_w, FALSE, FALSE,
3821 EL_SPRING, -1, MV_BIT_LEFT
3824 Xemerald_force_e, FALSE, FALSE,
3825 EL_EMERALD, -1, MV_BIT_RIGHT
3828 Xemerald_force_w, FALSE, FALSE,
3829 EL_EMERALD, -1, MV_BIT_LEFT
3832 Xdiamond_force_e, FALSE, FALSE,
3833 EL_DIAMOND, -1, MV_BIT_RIGHT
3836 Xdiamond_force_w, FALSE, FALSE,
3837 EL_DIAMOND, -1, MV_BIT_LEFT
3840 Xbomb_force_e, FALSE, FALSE,
3841 EL_BOMB, -1, MV_BIT_RIGHT
3844 Xbomb_force_w, FALSE, FALSE,
3845 EL_BOMB, -1, MV_BIT_LEFT
3847 #endif /* EM_ENGINE_BAD_ROLL */
3850 Xstone, TRUE, FALSE,
3854 Xstone_pause, FALSE, FALSE,
3858 Xstone_fall, FALSE, FALSE,
3862 Ystone_s, FALSE, FALSE,
3863 EL_ROCK, ACTION_FALLING, -1
3866 Ystone_sB, FALSE, TRUE,
3867 EL_ROCK, ACTION_FALLING, -1
3870 Ystone_e, FALSE, FALSE,
3871 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
3874 Ystone_eB, FALSE, TRUE,
3875 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
3878 Ystone_w, FALSE, FALSE,
3879 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
3882 Ystone_wB, FALSE, TRUE,
3883 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
3890 Xnut_pause, FALSE, FALSE,
3894 Xnut_fall, FALSE, FALSE,
3898 Ynut_s, FALSE, FALSE,
3899 EL_NUT, ACTION_FALLING, -1
3902 Ynut_sB, FALSE, TRUE,
3903 EL_NUT, ACTION_FALLING, -1
3906 Ynut_e, FALSE, FALSE,
3907 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
3910 Ynut_eB, FALSE, TRUE,
3911 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
3914 Ynut_w, FALSE, FALSE,
3915 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
3918 Ynut_wB, FALSE, TRUE,
3919 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
3922 Xbug_n, TRUE, FALSE,
3926 Xbug_e, TRUE, FALSE,
3927 EL_BUG_RIGHT, -1, -1
3930 Xbug_s, TRUE, FALSE,
3934 Xbug_w, TRUE, FALSE,
3938 Xbug_gon, FALSE, FALSE,
3942 Xbug_goe, FALSE, FALSE,
3943 EL_BUG_RIGHT, -1, -1
3946 Xbug_gos, FALSE, FALSE,
3950 Xbug_gow, FALSE, FALSE,
3954 Ybug_n, FALSE, FALSE,
3955 EL_BUG, ACTION_MOVING, MV_BIT_UP
3958 Ybug_nB, FALSE, TRUE,
3959 EL_BUG, ACTION_MOVING, MV_BIT_UP
3962 Ybug_e, FALSE, FALSE,
3963 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
3966 Ybug_eB, FALSE, TRUE,
3967 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
3970 Ybug_s, FALSE, FALSE,
3971 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
3974 Ybug_sB, FALSE, TRUE,
3975 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
3978 Ybug_w, FALSE, FALSE,
3979 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
3982 Ybug_wB, FALSE, TRUE,
3983 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
3986 Ybug_w_n, FALSE, FALSE,
3987 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
3990 Ybug_n_e, FALSE, FALSE,
3991 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
3994 Ybug_e_s, FALSE, FALSE,
3995 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
3998 Ybug_s_w, FALSE, FALSE,
3999 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
4002 Ybug_e_n, FALSE, FALSE,
4003 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
4006 Ybug_s_e, FALSE, FALSE,
4007 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
4010 Ybug_w_s, FALSE, FALSE,
4011 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
4014 Ybug_n_w, FALSE, FALSE,
4015 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
4018 Ybug_stone, FALSE, FALSE,
4019 EL_BUG, ACTION_SMASHED_BY_ROCK, -1
4022 Ybug_spring, FALSE, FALSE,
4023 EL_BUG, ACTION_SMASHED_BY_SPRING, -1
4026 Xtank_n, TRUE, FALSE,
4027 EL_SPACESHIP_UP, -1, -1
4030 Xtank_e, TRUE, FALSE,
4031 EL_SPACESHIP_RIGHT, -1, -1
4034 Xtank_s, TRUE, FALSE,
4035 EL_SPACESHIP_DOWN, -1, -1
4038 Xtank_w, TRUE, FALSE,
4039 EL_SPACESHIP_LEFT, -1, -1
4042 Xtank_gon, FALSE, FALSE,
4043 EL_SPACESHIP_UP, -1, -1
4046 Xtank_goe, FALSE, FALSE,
4047 EL_SPACESHIP_RIGHT, -1, -1
4050 Xtank_gos, FALSE, FALSE,
4051 EL_SPACESHIP_DOWN, -1, -1
4054 Xtank_gow, FALSE, FALSE,
4055 EL_SPACESHIP_LEFT, -1, -1
4058 Ytank_n, FALSE, FALSE,
4059 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
4062 Ytank_nB, FALSE, TRUE,
4063 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
4066 Ytank_e, FALSE, FALSE,
4067 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
4070 Ytank_eB, FALSE, TRUE,
4071 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
4074 Ytank_s, FALSE, FALSE,
4075 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
4078 Ytank_sB, FALSE, TRUE,
4079 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
4082 Ytank_w, FALSE, FALSE,
4083 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
4086 Ytank_wB, FALSE, TRUE,
4087 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
4090 Ytank_w_n, FALSE, FALSE,
4091 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
4094 Ytank_n_e, FALSE, FALSE,
4095 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
4098 Ytank_e_s, FALSE, FALSE,
4099 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
4102 Ytank_s_w, FALSE, FALSE,
4103 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
4106 Ytank_e_n, FALSE, FALSE,
4107 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
4110 Ytank_s_e, FALSE, FALSE,
4111 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
4114 Ytank_w_s, FALSE, FALSE,
4115 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
4118 Ytank_n_w, FALSE, FALSE,
4119 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
4122 Ytank_stone, FALSE, FALSE,
4123 EL_SPACESHIP, ACTION_SMASHED_BY_ROCK, -1
4126 Ytank_spring, FALSE, FALSE,
4127 EL_SPACESHIP, ACTION_SMASHED_BY_SPRING, -1
4130 Xandroid, TRUE, FALSE,
4131 EL_EMC_ANDROID, ACTION_ACTIVE, -1
4134 Xandroid_1_n, FALSE, FALSE,
4135 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
4138 Xandroid_2_n, FALSE, FALSE,
4139 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
4142 Xandroid_1_e, FALSE, FALSE,
4143 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
4146 Xandroid_2_e, FALSE, FALSE,
4147 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
4150 Xandroid_1_w, FALSE, FALSE,
4151 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
4154 Xandroid_2_w, FALSE, FALSE,
4155 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
4158 Xandroid_1_s, FALSE, FALSE,
4159 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
4162 Xandroid_2_s, FALSE, FALSE,
4163 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
4166 Yandroid_n, FALSE, FALSE,
4167 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
4170 Yandroid_nB, FALSE, TRUE,
4171 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
4174 Yandroid_ne, FALSE, FALSE,
4175 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPRIGHT
4178 Yandroid_neB, FALSE, TRUE,
4179 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPRIGHT
4182 Yandroid_e, FALSE, FALSE,
4183 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
4186 Yandroid_eB, FALSE, TRUE,
4187 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
4190 Yandroid_se, FALSE, FALSE,
4191 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNRIGHT
4194 Yandroid_seB, FALSE, TRUE,
4195 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNRIGHT
4198 Yandroid_s, FALSE, FALSE,
4199 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
4202 Yandroid_sB, FALSE, TRUE,
4203 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
4206 Yandroid_sw, FALSE, FALSE,
4207 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNLEFT
4210 Yandroid_swB, FALSE, TRUE,
4211 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNLEFT
4214 Yandroid_w, FALSE, FALSE,
4215 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
4218 Yandroid_wB, FALSE, TRUE,
4219 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
4222 Yandroid_nw, FALSE, FALSE,
4223 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPLEFT
4226 Yandroid_nwB, FALSE, TRUE,
4227 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPLEFT
4230 Xspring, TRUE, FALSE,
4234 Xspring_pause, FALSE, FALSE,
4238 Xspring_e, FALSE, FALSE,
4242 Xspring_w, FALSE, FALSE,
4246 Xspring_fall, FALSE, FALSE,
4250 Yspring_s, FALSE, FALSE,
4251 EL_SPRING, ACTION_FALLING, -1
4254 Yspring_sB, FALSE, TRUE,
4255 EL_SPRING, ACTION_FALLING, -1
4258 Yspring_e, FALSE, FALSE,
4259 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
4262 Yspring_eB, FALSE, TRUE,
4263 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
4266 Yspring_w, FALSE, FALSE,
4267 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
4270 Yspring_wB, FALSE, TRUE,
4271 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
4274 Yspring_kill_e, FALSE, FALSE,
4275 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
4278 Yspring_kill_eB, FALSE, TRUE,
4279 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
4282 Yspring_kill_w, FALSE, FALSE,
4283 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
4286 Yspring_kill_wB, FALSE, TRUE,
4287 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
4290 Xeater_n, TRUE, FALSE,
4291 EL_YAMYAM_UP, -1, -1
4294 Xeater_e, TRUE, FALSE,
4295 EL_YAMYAM_RIGHT, -1, -1
4298 Xeater_w, TRUE, FALSE,
4299 EL_YAMYAM_LEFT, -1, -1
4302 Xeater_s, TRUE, FALSE,
4303 EL_YAMYAM_DOWN, -1, -1
4306 Yeater_n, FALSE, FALSE,
4307 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
4310 Yeater_nB, FALSE, TRUE,
4311 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
4314 Yeater_e, FALSE, FALSE,
4315 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
4318 Yeater_eB, FALSE, TRUE,
4319 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
4322 Yeater_s, FALSE, FALSE,
4323 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
4326 Yeater_sB, FALSE, TRUE,
4327 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
4330 Yeater_w, FALSE, FALSE,
4331 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
4334 Yeater_wB, FALSE, TRUE,
4335 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
4338 Yeater_stone, FALSE, FALSE,
4339 EL_YAMYAM, ACTION_SMASHED_BY_ROCK, -1
4342 Yeater_spring, FALSE, FALSE,
4343 EL_YAMYAM, ACTION_SMASHED_BY_SPRING, -1
4346 Xalien, TRUE, FALSE,
4350 Xalien_pause, FALSE, FALSE,
4354 Yalien_n, FALSE, FALSE,
4355 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
4358 Yalien_nB, FALSE, TRUE,
4359 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
4362 Yalien_e, FALSE, FALSE,
4363 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
4366 Yalien_eB, FALSE, TRUE,
4367 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
4370 Yalien_s, FALSE, FALSE,
4371 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
4374 Yalien_sB, FALSE, TRUE,
4375 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
4378 Yalien_w, FALSE, FALSE,
4379 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
4382 Yalien_wB, FALSE, TRUE,
4383 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
4386 Yalien_stone, FALSE, FALSE,
4387 EL_ROBOT, ACTION_SMASHED_BY_ROCK, -1
4390 Yalien_spring, FALSE, FALSE,
4391 EL_ROBOT, ACTION_SMASHED_BY_SPRING, -1
4394 Xemerald, TRUE, FALSE,
4398 Xemerald_pause, FALSE, FALSE,
4402 Xemerald_fall, FALSE, FALSE,
4406 Xemerald_shine, FALSE, FALSE,
4407 EL_EMERALD, ACTION_TWINKLING, -1
4410 Yemerald_s, FALSE, FALSE,
4411 EL_EMERALD, ACTION_FALLING, -1
4414 Yemerald_sB, FALSE, TRUE,
4415 EL_EMERALD, ACTION_FALLING, -1
4418 Yemerald_e, FALSE, FALSE,
4419 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
4422 Yemerald_eB, FALSE, TRUE,
4423 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
4426 Yemerald_w, FALSE, FALSE,
4427 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
4430 Yemerald_wB, FALSE, TRUE,
4431 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
4434 Yemerald_eat, FALSE, FALSE,
4435 EL_EMERALD, ACTION_COLLECTING, -1
4438 Yemerald_stone, FALSE, FALSE,
4439 EL_NUT, ACTION_BREAKING, -1
4442 Xdiamond, TRUE, FALSE,
4446 Xdiamond_pause, FALSE, FALSE,
4450 Xdiamond_fall, FALSE, FALSE,
4454 Xdiamond_shine, FALSE, FALSE,
4455 EL_DIAMOND, ACTION_TWINKLING, -1
4458 Ydiamond_s, FALSE, FALSE,
4459 EL_DIAMOND, ACTION_FALLING, -1
4462 Ydiamond_sB, FALSE, TRUE,
4463 EL_DIAMOND, ACTION_FALLING, -1
4466 Ydiamond_e, FALSE, FALSE,
4467 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
4470 Ydiamond_eB, FALSE, TRUE,
4471 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
4474 Ydiamond_w, FALSE, FALSE,
4475 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
4478 Ydiamond_wB, FALSE, TRUE,
4479 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
4482 Ydiamond_eat, FALSE, FALSE,
4483 EL_DIAMOND, ACTION_COLLECTING, -1
4486 Ydiamond_stone, FALSE, FALSE,
4487 EL_DIAMOND, ACTION_SMASHED_BY_ROCK, -1
4490 Xdrip_fall, TRUE, FALSE,
4491 EL_AMOEBA_DROP, -1, -1
4494 Xdrip_stretch, FALSE, FALSE,
4495 EL_AMOEBA_DROP, ACTION_FALLING, -1
4498 Xdrip_stretchB, FALSE, TRUE,
4499 EL_AMOEBA_DROP, ACTION_FALLING, -1
4502 Xdrip_eat, FALSE, FALSE,
4503 EL_AMOEBA_DROP, ACTION_GROWING, -1
4506 Ydrip_s1, FALSE, FALSE,
4507 EL_AMOEBA_DROP, ACTION_FALLING, -1
4510 Ydrip_s1B, FALSE, TRUE,
4511 EL_AMOEBA_DROP, ACTION_FALLING, -1
4514 Ydrip_s2, FALSE, FALSE,
4515 EL_AMOEBA_DROP, ACTION_FALLING, -1
4518 Ydrip_s2B, FALSE, TRUE,
4519 EL_AMOEBA_DROP, ACTION_FALLING, -1
4526 Xbomb_pause, FALSE, FALSE,
4530 Xbomb_fall, FALSE, FALSE,
4534 Ybomb_s, FALSE, FALSE,
4535 EL_BOMB, ACTION_FALLING, -1
4538 Ybomb_sB, FALSE, TRUE,
4539 EL_BOMB, ACTION_FALLING, -1
4542 Ybomb_e, FALSE, FALSE,
4543 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
4546 Ybomb_eB, FALSE, TRUE,
4547 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
4550 Ybomb_w, FALSE, FALSE,
4551 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
4554 Ybomb_wB, FALSE, TRUE,
4555 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
4558 Ybomb_eat, FALSE, FALSE,
4559 EL_BOMB, ACTION_ACTIVATING, -1
4562 Xballoon, TRUE, FALSE,
4566 Yballoon_n, FALSE, FALSE,
4567 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
4570 Yballoon_nB, FALSE, TRUE,
4571 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
4574 Yballoon_e, FALSE, FALSE,
4575 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
4578 Yballoon_eB, FALSE, TRUE,
4579 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
4582 Yballoon_s, FALSE, FALSE,
4583 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
4586 Yballoon_sB, FALSE, TRUE,
4587 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
4590 Yballoon_w, FALSE, FALSE,
4591 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
4594 Yballoon_wB, FALSE, TRUE,
4595 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
4598 Xgrass, TRUE, FALSE,
4599 EL_EMC_GRASS, -1, -1
4602 Ygrass_nB, FALSE, FALSE,
4603 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_UP
4606 Ygrass_eB, FALSE, FALSE,
4607 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_RIGHT
4610 Ygrass_sB, FALSE, FALSE,
4611 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_DOWN
4614 Ygrass_wB, FALSE, FALSE,
4615 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_LEFT
4622 Ydirt_nB, FALSE, FALSE,
4623 EL_SAND, ACTION_DIGGING, MV_BIT_UP
4626 Ydirt_eB, FALSE, FALSE,
4627 EL_SAND, ACTION_DIGGING, MV_BIT_RIGHT
4630 Ydirt_sB, FALSE, FALSE,
4631 EL_SAND, ACTION_DIGGING, MV_BIT_DOWN
4634 Ydirt_wB, FALSE, FALSE,
4635 EL_SAND, ACTION_DIGGING, MV_BIT_LEFT
4638 Xacid_ne, TRUE, FALSE,
4639 EL_ACID_POOL_TOPRIGHT, -1, -1
4642 Xacid_se, TRUE, FALSE,
4643 EL_ACID_POOL_BOTTOMRIGHT, -1, -1
4646 Xacid_s, TRUE, FALSE,
4647 EL_ACID_POOL_BOTTOM, -1, -1
4650 Xacid_sw, TRUE, FALSE,
4651 EL_ACID_POOL_BOTTOMLEFT, -1, -1
4654 Xacid_nw, TRUE, FALSE,
4655 EL_ACID_POOL_TOPLEFT, -1, -1
4658 Xacid_1, TRUE, FALSE,
4662 Xacid_2, FALSE, FALSE,
4666 Xacid_3, FALSE, FALSE,
4670 Xacid_4, FALSE, FALSE,
4674 Xacid_5, FALSE, FALSE,
4678 Xacid_6, FALSE, FALSE,
4682 Xacid_7, FALSE, FALSE,
4686 Xacid_8, FALSE, FALSE,
4690 Xball_1, TRUE, FALSE,
4691 EL_EMC_MAGIC_BALL, -1, -1
4694 Xball_1B, FALSE, FALSE,
4695 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4698 Xball_2, FALSE, FALSE,
4699 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4702 Xball_2B, FALSE, FALSE,
4703 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4706 Yball_eat, FALSE, FALSE,
4707 EL_EMC_MAGIC_BALL, ACTION_DROPPING, -1
4710 Ykey_1_eat, FALSE, FALSE,
4711 EL_EM_KEY_1, ACTION_COLLECTING, -1
4714 Ykey_2_eat, FALSE, FALSE,
4715 EL_EM_KEY_2, ACTION_COLLECTING, -1
4718 Ykey_3_eat, FALSE, FALSE,
4719 EL_EM_KEY_3, ACTION_COLLECTING, -1
4722 Ykey_4_eat, FALSE, FALSE,
4723 EL_EM_KEY_4, ACTION_COLLECTING, -1
4726 Ykey_5_eat, FALSE, FALSE,
4727 EL_EMC_KEY_5, ACTION_COLLECTING, -1
4730 Ykey_6_eat, FALSE, FALSE,
4731 EL_EMC_KEY_6, ACTION_COLLECTING, -1
4734 Ykey_7_eat, FALSE, FALSE,
4735 EL_EMC_KEY_7, ACTION_COLLECTING, -1
4738 Ykey_8_eat, FALSE, FALSE,
4739 EL_EMC_KEY_8, ACTION_COLLECTING, -1
4742 Ylenses_eat, FALSE, FALSE,
4743 EL_EMC_LENSES, ACTION_COLLECTING, -1
4746 Ymagnify_eat, FALSE, FALSE,
4747 EL_EMC_MAGNIFIER, ACTION_COLLECTING, -1
4750 Ygrass_eat, FALSE, FALSE,
4751 EL_EMC_GRASS, ACTION_SNAPPING, -1
4754 Ydirt_eat, FALSE, FALSE,
4755 EL_SAND, ACTION_SNAPPING, -1
4758 Xgrow_ns, TRUE, FALSE,
4759 EL_EXPANDABLE_WALL_VERTICAL, -1, -1
4762 Ygrow_ns_eat, FALSE, FALSE,
4763 EL_EXPANDABLE_WALL_VERTICAL, ACTION_GROWING, -1
4766 Xgrow_ew, TRUE, FALSE,
4767 EL_EXPANDABLE_WALL_HORIZONTAL, -1, -1
4770 Ygrow_ew_eat, FALSE, FALSE,
4771 EL_EXPANDABLE_WALL_HORIZONTAL, ACTION_GROWING, -1
4774 Xwonderwall, TRUE, FALSE,
4775 EL_MAGIC_WALL, -1, -1
4778 XwonderwallB, FALSE, FALSE,
4779 EL_MAGIC_WALL, ACTION_ACTIVE, -1
4782 Xamoeba_1, TRUE, FALSE,
4783 EL_AMOEBA_DRY, ACTION_OTHER, -1
4786 Xamoeba_2, FALSE, FALSE,
4787 EL_AMOEBA_DRY, ACTION_OTHER, -1
4790 Xamoeba_3, FALSE, FALSE,
4791 EL_AMOEBA_DRY, ACTION_OTHER, -1
4794 Xamoeba_4, FALSE, FALSE,
4795 EL_AMOEBA_DRY, ACTION_OTHER, -1
4798 Xamoeba_5, TRUE, FALSE,
4799 EL_AMOEBA_WET, ACTION_OTHER, -1
4802 Xamoeba_6, FALSE, FALSE,
4803 EL_AMOEBA_WET, ACTION_OTHER, -1
4806 Xamoeba_7, FALSE, FALSE,
4807 EL_AMOEBA_WET, ACTION_OTHER, -1
4810 Xamoeba_8, FALSE, FALSE,
4811 EL_AMOEBA_WET, ACTION_OTHER, -1
4814 Xdoor_1, TRUE, FALSE,
4815 EL_EM_GATE_1, -1, -1
4818 Xdoor_2, TRUE, FALSE,
4819 EL_EM_GATE_2, -1, -1
4822 Xdoor_3, TRUE, FALSE,
4823 EL_EM_GATE_3, -1, -1
4826 Xdoor_4, TRUE, FALSE,
4827 EL_EM_GATE_4, -1, -1
4830 Xdoor_5, TRUE, FALSE,
4831 EL_EMC_GATE_5, -1, -1
4834 Xdoor_6, TRUE, FALSE,
4835 EL_EMC_GATE_6, -1, -1
4838 Xdoor_7, TRUE, FALSE,
4839 EL_EMC_GATE_7, -1, -1
4842 Xdoor_8, TRUE, FALSE,
4843 EL_EMC_GATE_8, -1, -1
4846 Xkey_1, TRUE, FALSE,
4850 Xkey_2, TRUE, FALSE,
4854 Xkey_3, TRUE, FALSE,
4858 Xkey_4, TRUE, FALSE,
4862 Xkey_5, TRUE, FALSE,
4863 EL_EMC_KEY_5, -1, -1
4866 Xkey_6, TRUE, FALSE,
4867 EL_EMC_KEY_6, -1, -1
4870 Xkey_7, TRUE, FALSE,
4871 EL_EMC_KEY_7, -1, -1
4874 Xkey_8, TRUE, FALSE,
4875 EL_EMC_KEY_8, -1, -1
4878 Xwind_n, TRUE, FALSE,
4879 EL_BALLOON_SWITCH_UP, -1, -1
4882 Xwind_e, TRUE, FALSE,
4883 EL_BALLOON_SWITCH_RIGHT, -1, -1
4886 Xwind_s, TRUE, FALSE,
4887 EL_BALLOON_SWITCH_DOWN, -1, -1
4890 Xwind_w, TRUE, FALSE,
4891 EL_BALLOON_SWITCH_LEFT, -1, -1
4894 Xwind_nesw, TRUE, FALSE,
4895 EL_BALLOON_SWITCH_ANY, -1, -1
4898 Xwind_stop, TRUE, FALSE,
4899 EL_BALLOON_SWITCH_NONE, -1, -1
4903 EL_EM_EXIT_CLOSED, -1, -1
4906 Xexit_1, TRUE, FALSE,
4907 EL_EM_EXIT_OPEN, -1, -1
4910 Xexit_2, FALSE, FALSE,
4911 EL_EM_EXIT_OPEN, -1, -1
4914 Xexit_3, FALSE, FALSE,
4915 EL_EM_EXIT_OPEN, -1, -1
4918 Xdynamite, TRUE, FALSE,
4919 EL_EM_DYNAMITE, -1, -1
4922 Ydynamite_eat, FALSE, FALSE,
4923 EL_EM_DYNAMITE, ACTION_COLLECTING, -1
4926 Xdynamite_1, TRUE, FALSE,
4927 EL_EM_DYNAMITE_ACTIVE, -1, -1
4930 Xdynamite_2, FALSE, FALSE,
4931 EL_EM_DYNAMITE_ACTIVE, -1, -1
4934 Xdynamite_3, FALSE, FALSE,
4935 EL_EM_DYNAMITE_ACTIVE, -1, -1
4938 Xdynamite_4, FALSE, FALSE,
4939 EL_EM_DYNAMITE_ACTIVE, -1, -1
4942 Xbumper, TRUE, FALSE,
4943 EL_EMC_SPRING_BUMPER, -1, -1
4946 XbumperB, FALSE, FALSE,
4947 EL_EMC_SPRING_BUMPER, ACTION_ACTIVE, -1
4950 Xwheel, TRUE, FALSE,
4951 EL_ROBOT_WHEEL, -1, -1
4954 XwheelB, FALSE, FALSE,
4955 EL_ROBOT_WHEEL, ACTION_ACTIVE, -1
4958 Xswitch, TRUE, FALSE,
4959 EL_EMC_MAGIC_BALL_SWITCH, -1, -1
4962 XswitchB, FALSE, FALSE,
4963 EL_EMC_MAGIC_BALL_SWITCH, ACTION_ACTIVE, -1
4967 EL_QUICKSAND_EMPTY, -1, -1
4970 Xsand_stone, TRUE, FALSE,
4971 EL_QUICKSAND_FULL, -1, -1
4974 Xsand_stonein_1, FALSE, TRUE,
4975 EL_ROCK, ACTION_FILLING, -1
4978 Xsand_stonein_2, FALSE, TRUE,
4979 EL_ROCK, ACTION_FILLING, -1
4982 Xsand_stonein_3, FALSE, TRUE,
4983 EL_ROCK, ACTION_FILLING, -1
4986 Xsand_stonein_4, FALSE, TRUE,
4987 EL_ROCK, ACTION_FILLING, -1
4991 Xsand_stonesand_1, FALSE, FALSE,
4992 EL_QUICKSAND_EMPTYING, -1, -1
4995 Xsand_stonesand_2, FALSE, FALSE,
4996 EL_QUICKSAND_EMPTYING, -1, -1
4999 Xsand_stonesand_3, FALSE, FALSE,
5000 EL_QUICKSAND_EMPTYING, -1, -1
5003 Xsand_stonesand_4, FALSE, FALSE,
5004 EL_QUICKSAND_EMPTYING, -1, -1
5007 Xsand_stonesand_quickout_1, FALSE, FALSE,
5008 EL_QUICKSAND_EMPTYING, -1, -1
5011 Xsand_stonesand_quickout_2, FALSE, FALSE,
5012 EL_QUICKSAND_EMPTYING, -1, -1
5016 Xsand_stonesand_1, FALSE, FALSE,
5017 EL_QUICKSAND_FULL, -1, -1
5020 Xsand_stonesand_2, FALSE, FALSE,
5021 EL_QUICKSAND_FULL, -1, -1
5024 Xsand_stonesand_3, FALSE, FALSE,
5025 EL_QUICKSAND_FULL, -1, -1
5028 Xsand_stonesand_4, FALSE, FALSE,
5029 EL_QUICKSAND_FULL, -1, -1
5033 Xsand_stoneout_1, FALSE, FALSE,
5034 EL_ROCK, ACTION_EMPTYING, -1
5037 Xsand_stoneout_2, FALSE, FALSE,
5038 EL_ROCK, ACTION_EMPTYING, -1
5042 Xsand_sandstone_1, FALSE, FALSE,
5043 EL_QUICKSAND_FILLING, -1, -1
5046 Xsand_sandstone_2, FALSE, FALSE,
5047 EL_QUICKSAND_FILLING, -1, -1
5050 Xsand_sandstone_3, FALSE, FALSE,
5051 EL_QUICKSAND_FILLING, -1, -1
5054 Xsand_sandstone_4, FALSE, FALSE,
5055 EL_QUICKSAND_FILLING, -1, -1
5059 Xsand_sandstone_1, FALSE, FALSE,
5060 EL_QUICKSAND_FULL, -1, -1
5063 Xsand_sandstone_2, FALSE, FALSE,
5064 EL_QUICKSAND_FULL, -1, -1
5067 Xsand_sandstone_3, FALSE, FALSE,
5068 EL_QUICKSAND_FULL, -1, -1
5071 Xsand_sandstone_4, FALSE, FALSE,
5072 EL_QUICKSAND_FULL, -1, -1
5076 Xplant, TRUE, FALSE,
5077 EL_EMC_PLANT, -1, -1
5080 Yplant, FALSE, FALSE,
5081 EL_EMC_PLANT, -1, -1
5084 Xlenses, TRUE, FALSE,
5085 EL_EMC_LENSES, -1, -1
5088 Xmagnify, TRUE, FALSE,
5089 EL_EMC_MAGNIFIER, -1, -1
5092 Xdripper, TRUE, FALSE,
5093 EL_EMC_DRIPPER, -1, -1
5096 XdripperB, FALSE, FALSE,
5097 EL_EMC_DRIPPER, ACTION_ACTIVE, -1
5100 Xfake_blank, TRUE, FALSE,
5101 EL_INVISIBLE_WALL, -1, -1
5104 Xfake_blankB, FALSE, FALSE,
5105 EL_INVISIBLE_WALL, ACTION_ACTIVE, -1
5108 Xfake_grass, TRUE, FALSE,
5109 EL_EMC_FAKE_GRASS, -1, -1
5112 Xfake_grassB, FALSE, FALSE,
5113 EL_EMC_FAKE_GRASS, ACTION_ACTIVE, -1
5116 Xfake_door_1, TRUE, FALSE,
5117 EL_EM_GATE_1_GRAY, -1, -1
5120 Xfake_door_2, TRUE, FALSE,
5121 EL_EM_GATE_2_GRAY, -1, -1
5124 Xfake_door_3, TRUE, FALSE,
5125 EL_EM_GATE_3_GRAY, -1, -1
5128 Xfake_door_4, TRUE, FALSE,
5129 EL_EM_GATE_4_GRAY, -1, -1
5132 Xfake_door_5, TRUE, FALSE,
5133 EL_EMC_GATE_5_GRAY, -1, -1
5136 Xfake_door_6, TRUE, FALSE,
5137 EL_EMC_GATE_6_GRAY, -1, -1
5140 Xfake_door_7, TRUE, FALSE,
5141 EL_EMC_GATE_7_GRAY, -1, -1
5144 Xfake_door_8, TRUE, FALSE,
5145 EL_EMC_GATE_8_GRAY, -1, -1
5148 Xfake_acid_1, TRUE, FALSE,
5149 EL_EMC_FAKE_ACID, -1, -1
5152 Xfake_acid_2, FALSE, FALSE,
5153 EL_EMC_FAKE_ACID, -1, -1
5156 Xfake_acid_3, FALSE, FALSE,
5157 EL_EMC_FAKE_ACID, -1, -1
5160 Xfake_acid_4, FALSE, FALSE,
5161 EL_EMC_FAKE_ACID, -1, -1
5164 Xfake_acid_5, FALSE, FALSE,
5165 EL_EMC_FAKE_ACID, -1, -1
5168 Xfake_acid_6, FALSE, FALSE,
5169 EL_EMC_FAKE_ACID, -1, -1
5172 Xfake_acid_7, FALSE, FALSE,
5173 EL_EMC_FAKE_ACID, -1, -1
5176 Xfake_acid_8, FALSE, FALSE,
5177 EL_EMC_FAKE_ACID, -1, -1
5180 Xsteel_1, TRUE, FALSE,
5181 EL_STEELWALL, -1, -1
5184 Xsteel_2, TRUE, FALSE,
5185 EL_EMC_STEELWALL_2, -1, -1
5188 Xsteel_3, TRUE, FALSE,
5189 EL_EMC_STEELWALL_3, -1, -1
5192 Xsteel_4, TRUE, FALSE,
5193 EL_EMC_STEELWALL_4, -1, -1
5196 Xwall_1, TRUE, FALSE,
5200 Xwall_2, TRUE, FALSE,
5201 EL_EMC_WALL_14, -1, -1
5204 Xwall_3, TRUE, FALSE,
5205 EL_EMC_WALL_15, -1, -1
5208 Xwall_4, TRUE, FALSE,
5209 EL_EMC_WALL_16, -1, -1
5212 Xround_wall_1, TRUE, FALSE,
5213 EL_WALL_SLIPPERY, -1, -1
5216 Xround_wall_2, TRUE, FALSE,
5217 EL_EMC_WALL_SLIPPERY_2, -1, -1
5220 Xround_wall_3, TRUE, FALSE,
5221 EL_EMC_WALL_SLIPPERY_3, -1, -1
5224 Xround_wall_4, TRUE, FALSE,
5225 EL_EMC_WALL_SLIPPERY_4, -1, -1
5228 Xdecor_1, TRUE, FALSE,
5229 EL_EMC_WALL_8, -1, -1
5232 Xdecor_2, TRUE, FALSE,
5233 EL_EMC_WALL_6, -1, -1
5236 Xdecor_3, TRUE, FALSE,
5237 EL_EMC_WALL_4, -1, -1
5240 Xdecor_4, TRUE, FALSE,
5241 EL_EMC_WALL_7, -1, -1
5244 Xdecor_5, TRUE, FALSE,
5245 EL_EMC_WALL_5, -1, -1
5248 Xdecor_6, TRUE, FALSE,
5249 EL_EMC_WALL_9, -1, -1
5252 Xdecor_7, TRUE, FALSE,
5253 EL_EMC_WALL_10, -1, -1
5256 Xdecor_8, TRUE, FALSE,
5257 EL_EMC_WALL_1, -1, -1
5260 Xdecor_9, TRUE, FALSE,
5261 EL_EMC_WALL_2, -1, -1
5264 Xdecor_10, TRUE, FALSE,
5265 EL_EMC_WALL_3, -1, -1
5268 Xdecor_11, TRUE, FALSE,
5269 EL_EMC_WALL_11, -1, -1
5272 Xdecor_12, TRUE, FALSE,
5273 EL_EMC_WALL_12, -1, -1
5276 Xalpha_0, TRUE, FALSE,
5277 EL_CHAR('0'), -1, -1
5280 Xalpha_1, TRUE, FALSE,
5281 EL_CHAR('1'), -1, -1
5284 Xalpha_2, TRUE, FALSE,
5285 EL_CHAR('2'), -1, -1
5288 Xalpha_3, TRUE, FALSE,
5289 EL_CHAR('3'), -1, -1
5292 Xalpha_4, TRUE, FALSE,
5293 EL_CHAR('4'), -1, -1
5296 Xalpha_5, TRUE, FALSE,
5297 EL_CHAR('5'), -1, -1
5300 Xalpha_6, TRUE, FALSE,
5301 EL_CHAR('6'), -1, -1
5304 Xalpha_7, TRUE, FALSE,
5305 EL_CHAR('7'), -1, -1
5308 Xalpha_8, TRUE, FALSE,
5309 EL_CHAR('8'), -1, -1
5312 Xalpha_9, TRUE, FALSE,
5313 EL_CHAR('9'), -1, -1
5316 Xalpha_excla, TRUE, FALSE,
5317 EL_CHAR('!'), -1, -1
5320 Xalpha_quote, TRUE, FALSE,
5321 EL_CHAR('"'), -1, -1
5324 Xalpha_comma, TRUE, FALSE,
5325 EL_CHAR(','), -1, -1
5328 Xalpha_minus, TRUE, FALSE,
5329 EL_CHAR('-'), -1, -1
5332 Xalpha_perio, TRUE, FALSE,
5333 EL_CHAR('.'), -1, -1
5336 Xalpha_colon, TRUE, FALSE,
5337 EL_CHAR(':'), -1, -1
5340 Xalpha_quest, TRUE, FALSE,
5341 EL_CHAR('?'), -1, -1
5344 Xalpha_a, TRUE, FALSE,
5345 EL_CHAR('A'), -1, -1
5348 Xalpha_b, TRUE, FALSE,
5349 EL_CHAR('B'), -1, -1
5352 Xalpha_c, TRUE, FALSE,
5353 EL_CHAR('C'), -1, -1
5356 Xalpha_d, TRUE, FALSE,
5357 EL_CHAR('D'), -1, -1
5360 Xalpha_e, TRUE, FALSE,
5361 EL_CHAR('E'), -1, -1
5364 Xalpha_f, TRUE, FALSE,
5365 EL_CHAR('F'), -1, -1
5368 Xalpha_g, TRUE, FALSE,
5369 EL_CHAR('G'), -1, -1
5372 Xalpha_h, TRUE, FALSE,
5373 EL_CHAR('H'), -1, -1
5376 Xalpha_i, TRUE, FALSE,
5377 EL_CHAR('I'), -1, -1
5380 Xalpha_j, TRUE, FALSE,
5381 EL_CHAR('J'), -1, -1
5384 Xalpha_k, TRUE, FALSE,
5385 EL_CHAR('K'), -1, -1
5388 Xalpha_l, TRUE, FALSE,
5389 EL_CHAR('L'), -1, -1
5392 Xalpha_m, TRUE, FALSE,
5393 EL_CHAR('M'), -1, -1
5396 Xalpha_n, TRUE, FALSE,
5397 EL_CHAR('N'), -1, -1
5400 Xalpha_o, TRUE, FALSE,
5401 EL_CHAR('O'), -1, -1
5404 Xalpha_p, TRUE, FALSE,
5405 EL_CHAR('P'), -1, -1
5408 Xalpha_q, TRUE, FALSE,
5409 EL_CHAR('Q'), -1, -1
5412 Xalpha_r, TRUE, FALSE,
5413 EL_CHAR('R'), -1, -1
5416 Xalpha_s, TRUE, FALSE,
5417 EL_CHAR('S'), -1, -1
5420 Xalpha_t, TRUE, FALSE,
5421 EL_CHAR('T'), -1, -1
5424 Xalpha_u, TRUE, FALSE,
5425 EL_CHAR('U'), -1, -1
5428 Xalpha_v, TRUE, FALSE,
5429 EL_CHAR('V'), -1, -1
5432 Xalpha_w, TRUE, FALSE,
5433 EL_CHAR('W'), -1, -1
5436 Xalpha_x, TRUE, FALSE,
5437 EL_CHAR('X'), -1, -1
5440 Xalpha_y, TRUE, FALSE,
5441 EL_CHAR('Y'), -1, -1
5444 Xalpha_z, TRUE, FALSE,
5445 EL_CHAR('Z'), -1, -1
5448 Xalpha_arrow_e, TRUE, FALSE,
5449 EL_CHAR('>'), -1, -1
5452 Xalpha_arrow_w, TRUE, FALSE,
5453 EL_CHAR('<'), -1, -1
5456 Xalpha_copyr, TRUE, FALSE,
5457 EL_CHAR('©'), -1, -1
5461 Xboom_bug, FALSE, FALSE,
5462 EL_BUG, ACTION_EXPLODING, -1
5465 Xboom_bomb, FALSE, FALSE,
5466 EL_BOMB, ACTION_EXPLODING, -1
5469 Xboom_android, FALSE, FALSE,
5470 EL_EMC_ANDROID, ACTION_OTHER, -1
5473 Xboom_1, FALSE, FALSE,
5474 EL_DEFAULT, ACTION_EXPLODING, -1
5477 Xboom_2, FALSE, FALSE,
5478 EL_DEFAULT, ACTION_EXPLODING, -1
5481 Znormal, FALSE, FALSE,
5485 Zdynamite, FALSE, FALSE,
5489 Zplayer, FALSE, FALSE,
5493 ZBORDER, FALSE, FALSE,
5503 static struct Mapping_EM_to_RND_player
5512 em_player_mapping_list[] =
5516 EL_PLAYER_1, ACTION_MOVING, MV_BIT_UP,
5520 EL_PLAYER_1, ACTION_MOVING, MV_BIT_RIGHT,
5524 EL_PLAYER_1, ACTION_MOVING, MV_BIT_DOWN,
5528 EL_PLAYER_1, ACTION_MOVING, MV_BIT_LEFT,
5532 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_UP,
5536 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_RIGHT,
5540 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_DOWN,
5544 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_LEFT,
5548 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_UP,
5552 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_RIGHT,
5556 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_DOWN,
5560 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_LEFT,
5564 EL_PLAYER_2, ACTION_MOVING, MV_BIT_UP,
5568 EL_PLAYER_2, ACTION_MOVING, MV_BIT_RIGHT,
5572 EL_PLAYER_2, ACTION_MOVING, MV_BIT_DOWN,
5576 EL_PLAYER_2, ACTION_MOVING, MV_BIT_LEFT,
5580 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_UP,
5584 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_RIGHT,
5588 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_DOWN,
5592 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_LEFT,
5596 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_UP,
5600 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_RIGHT,
5604 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_DOWN,
5608 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_LEFT,
5612 EL_PLAYER_1, ACTION_DEFAULT, -1,
5616 EL_PLAYER_2, ACTION_DEFAULT, -1,
5620 EL_PLAYER_3, ACTION_MOVING, MV_BIT_UP,
5624 EL_PLAYER_3, ACTION_MOVING, MV_BIT_RIGHT,
5628 EL_PLAYER_3, ACTION_MOVING, MV_BIT_DOWN,
5632 EL_PLAYER_3, ACTION_MOVING, MV_BIT_LEFT,
5636 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_UP,
5640 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_RIGHT,
5644 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_DOWN,
5648 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_LEFT,
5652 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_UP,
5656 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_RIGHT,
5660 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_DOWN,
5664 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_LEFT,
5668 EL_PLAYER_4, ACTION_MOVING, MV_BIT_UP,
5672 EL_PLAYER_4, ACTION_MOVING, MV_BIT_RIGHT,
5676 EL_PLAYER_4, ACTION_MOVING, MV_BIT_DOWN,
5680 EL_PLAYER_4, ACTION_MOVING, MV_BIT_LEFT,
5684 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_UP,
5688 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_RIGHT,
5692 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_DOWN,
5696 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_LEFT,
5700 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_UP,
5704 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_RIGHT,
5708 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_DOWN,
5712 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_LEFT,
5716 EL_PLAYER_3, ACTION_DEFAULT, -1,
5720 EL_PLAYER_4, ACTION_DEFAULT, -1,
5729 int map_element_RND_to_EM(int element_rnd)
5731 static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
5732 static boolean mapping_initialized = FALSE;
5734 if (!mapping_initialized)
5738 /* return "Xalpha_quest" for all undefined elements in mapping array */
5739 for (i = 0; i < NUM_FILE_ELEMENTS; i++)
5740 mapping_RND_to_EM[i] = Xalpha_quest;
5742 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5743 if (em_object_mapping_list[i].is_rnd_to_em_mapping)
5744 mapping_RND_to_EM[em_object_mapping_list[i].element_rnd] =
5745 em_object_mapping_list[i].element_em;
5747 mapping_initialized = TRUE;
5750 if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
5751 return mapping_RND_to_EM[element_rnd];
5753 Error(ERR_WARN, "invalid RND level element %d", element_rnd);
5758 int map_element_EM_to_RND(int element_em)
5760 static unsigned short mapping_EM_to_RND[TILE_MAX];
5761 static boolean mapping_initialized = FALSE;
5763 if (!mapping_initialized)
5767 /* return "EL_UNKNOWN" for all undefined elements in mapping array */
5768 for (i = 0; i < TILE_MAX; i++)
5769 mapping_EM_to_RND[i] = EL_UNKNOWN;
5771 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5772 mapping_EM_to_RND[em_object_mapping_list[i].element_em] =
5773 em_object_mapping_list[i].element_rnd;
5775 mapping_initialized = TRUE;
5778 if (element_em >= 0 && element_em < TILE_MAX)
5779 return mapping_EM_to_RND[element_em];
5781 Error(ERR_WARN, "invalid EM level element %d", element_em);
5786 void map_android_clone_elements_RND_to_EM(struct LevelInfo *level)
5788 struct LevelInfo_EM *level_em = level->native_em_level;
5789 struct LEVEL *lev = level_em->lev;
5792 for (i = 0; i < TILE_MAX; i++)
5793 lev->android_array[i] = Xblank;
5795 for (i = 0; i < level->num_android_clone_elements; i++)
5797 int element_rnd = level->android_clone_element[i];
5798 int element_em = map_element_RND_to_EM(element_rnd);
5800 for (j = 0; em_object_mapping_list[j].element_em != -1; j++)
5801 if (em_object_mapping_list[j].element_rnd == element_rnd)
5802 lev->android_array[em_object_mapping_list[j].element_em] = element_em;
5806 void map_android_clone_elements_EM_to_RND(struct LevelInfo *level)
5808 struct LevelInfo_EM *level_em = level->native_em_level;
5809 struct LEVEL *lev = level_em->lev;
5812 level->num_android_clone_elements = 0;
5814 for (i = 0; i < TILE_MAX; i++)
5816 int element_em = lev->android_array[i];
5818 boolean element_found = FALSE;
5820 if (element_em == Xblank)
5823 element_rnd = map_element_EM_to_RND(element_em);
5825 for (j = 0; j < level->num_android_clone_elements; j++)
5826 if (level->android_clone_element[j] == element_rnd)
5827 element_found = TRUE;
5831 level->android_clone_element[level->num_android_clone_elements++] =
5834 if (level->num_android_clone_elements == MAX_ANDROID_ELEMENTS)
5839 if (level->num_android_clone_elements == 0)
5841 level->num_android_clone_elements = 1;
5842 level->android_clone_element[0] = EL_EMPTY;
5846 int map_direction_RND_to_EM(int direction)
5848 return (direction == MV_UP ? 0 :
5849 direction == MV_RIGHT ? 1 :
5850 direction == MV_DOWN ? 2 :
5851 direction == MV_LEFT ? 3 :
5855 int map_direction_EM_to_RND(int direction)
5857 return (direction == 0 ? MV_UP :
5858 direction == 1 ? MV_RIGHT :
5859 direction == 2 ? MV_DOWN :
5860 direction == 3 ? MV_LEFT :
5864 int get_next_element(int element)
5868 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
5869 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
5870 case EL_QUICKSAND_FAST_FILLING: return EL_QUICKSAND_FAST_FULL;
5871 case EL_QUICKSAND_FAST_EMPTYING: return EL_QUICKSAND_FAST_EMPTY;
5872 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
5873 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
5874 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
5875 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
5876 case EL_DC_MAGIC_WALL_FILLING: return EL_DC_MAGIC_WALL_FULL;
5877 case EL_DC_MAGIC_WALL_EMPTYING: return EL_DC_MAGIC_WALL_ACTIVE;
5878 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
5880 default: return element;
5885 int el_act_dir2img(int element, int action, int direction)
5887 element = GFX_ELEMENT(element);
5889 if (direction == MV_NONE)
5890 return element_info[element].graphic[action];
5892 direction = MV_DIR_TO_BIT(direction);
5894 return element_info[element].direction_graphic[action][direction];
5897 int el_act_dir2img(int element, int action, int direction)
5899 element = GFX_ELEMENT(element);
5900 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
5902 /* direction_graphic[][] == graphic[] for undefined direction graphics */
5903 return element_info[element].direction_graphic[action][direction];
5908 static int el_act_dir2crm(int element, int action, int direction)
5910 element = GFX_ELEMENT(element);
5912 if (direction == MV_NONE)
5913 return element_info[element].crumbled[action];
5915 direction = MV_DIR_TO_BIT(direction);
5917 return element_info[element].direction_crumbled[action][direction];
5920 static int el_act_dir2crm(int element, int action, int direction)
5922 element = GFX_ELEMENT(element);
5923 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
5925 /* direction_graphic[][] == graphic[] for undefined direction graphics */
5926 return element_info[element].direction_crumbled[action][direction];
5930 int el_act2img(int element, int action)
5932 element = GFX_ELEMENT(element);
5934 return element_info[element].graphic[action];
5937 int el_act2crm(int element, int action)
5939 element = GFX_ELEMENT(element);
5941 return element_info[element].crumbled[action];
5944 int el_dir2img(int element, int direction)
5946 element = GFX_ELEMENT(element);
5948 return el_act_dir2img(element, ACTION_DEFAULT, direction);
5951 int el2baseimg(int element)
5953 return element_info[element].graphic[ACTION_DEFAULT];
5956 int el2img(int element)
5958 element = GFX_ELEMENT(element);
5960 return element_info[element].graphic[ACTION_DEFAULT];
5963 int el2edimg(int element)
5965 element = GFX_ELEMENT(element);
5967 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
5970 int el2preimg(int element)
5972 element = GFX_ELEMENT(element);
5974 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
5977 int el2panelimg(int element)
5979 element = GFX_ELEMENT(element);
5981 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PANEL];
5984 int font2baseimg(int font_nr)
5986 return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
5989 int getBeltNrFromBeltElement(int element)
5991 return (element < EL_CONVEYOR_BELT_2_LEFT ? 0 :
5992 element < EL_CONVEYOR_BELT_3_LEFT ? 1 :
5993 element < EL_CONVEYOR_BELT_4_LEFT ? 2 : 3);
5996 int getBeltNrFromBeltActiveElement(int element)
5998 return (element < EL_CONVEYOR_BELT_2_LEFT_ACTIVE ? 0 :
5999 element < EL_CONVEYOR_BELT_3_LEFT_ACTIVE ? 1 :
6000 element < EL_CONVEYOR_BELT_4_LEFT_ACTIVE ? 2 : 3);
6003 int getBeltNrFromBeltSwitchElement(int element)
6005 return (element < EL_CONVEYOR_BELT_2_SWITCH_LEFT ? 0 :
6006 element < EL_CONVEYOR_BELT_3_SWITCH_LEFT ? 1 :
6007 element < EL_CONVEYOR_BELT_4_SWITCH_LEFT ? 2 : 3);
6010 int getBeltDirNrFromBeltElement(int element)
6012 static int belt_base_element[4] =
6014 EL_CONVEYOR_BELT_1_LEFT,
6015 EL_CONVEYOR_BELT_2_LEFT,
6016 EL_CONVEYOR_BELT_3_LEFT,
6017 EL_CONVEYOR_BELT_4_LEFT
6020 int belt_nr = getBeltNrFromBeltElement(element);
6021 int belt_dir_nr = element - belt_base_element[belt_nr];
6023 return (belt_dir_nr % 3);
6026 int getBeltDirNrFromBeltSwitchElement(int element)
6028 static int belt_base_element[4] =
6030 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
6031 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
6032 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
6033 EL_CONVEYOR_BELT_4_SWITCH_LEFT
6036 int belt_nr = getBeltNrFromBeltSwitchElement(element);
6037 int belt_dir_nr = element - belt_base_element[belt_nr];
6039 return (belt_dir_nr % 3);
6042 int getBeltDirFromBeltElement(int element)
6044 static int belt_move_dir[3] =
6051 int belt_dir_nr = getBeltDirNrFromBeltElement(element);
6053 return belt_move_dir[belt_dir_nr];
6056 int getBeltDirFromBeltSwitchElement(int element)
6058 static int belt_move_dir[3] =
6065 int belt_dir_nr = getBeltDirNrFromBeltSwitchElement(element);
6067 return belt_move_dir[belt_dir_nr];
6070 int getBeltElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
6072 static int belt_base_element[4] =
6074 EL_CONVEYOR_BELT_1_LEFT,
6075 EL_CONVEYOR_BELT_2_LEFT,
6076 EL_CONVEYOR_BELT_3_LEFT,
6077 EL_CONVEYOR_BELT_4_LEFT
6080 return belt_base_element[belt_nr] + belt_dir_nr;
6083 int getBeltElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
6085 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
6087 return getBeltElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
6090 int getBeltSwitchElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
6092 static int belt_base_element[4] =
6094 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
6095 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
6096 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
6097 EL_CONVEYOR_BELT_4_SWITCH_LEFT
6100 return belt_base_element[belt_nr] + belt_dir_nr;
6103 int getBeltSwitchElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
6105 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
6107 return getBeltSwitchElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
6110 int getNumActivePlayers_EM()
6112 int num_players = 0;
6118 for (i = 0; i < MAX_PLAYERS; i++)
6119 if (tape.player_participates[i])
6125 int getGameFrameDelay_EM(int native_em_game_frame_delay)
6127 int game_frame_delay_value;
6129 game_frame_delay_value =
6130 (tape.playing && tape.fast_forward ? FfwdFrameDelay :
6131 GameFrameDelay == GAME_FRAME_DELAY ? native_em_game_frame_delay :
6134 if (tape.playing && tape.warp_forward && !tape.pausing)
6135 game_frame_delay_value = 0;
6137 return game_frame_delay_value;
6140 unsigned int InitRND(long seed)
6142 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
6143 return InitEngineRandom_EM(seed);
6144 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
6145 return InitEngineRandom_SP(seed);
6147 return InitEngineRandom_RND(seed);
6151 static struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
6152 static struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
6155 inline static int get_effective_element_EM(int tile, int frame_em)
6157 int element = object_mapping[tile].element_rnd;
6158 int action = object_mapping[tile].action;
6159 boolean is_backside = object_mapping[tile].is_backside;
6160 boolean action_removing = (action == ACTION_DIGGING ||
6161 action == ACTION_SNAPPING ||
6162 action == ACTION_COLLECTING);
6168 case Yacid_splash_eB:
6169 case Yacid_splash_wB:
6170 return (frame_em > 5 ? EL_EMPTY : element);
6176 else /* frame_em == 7 */
6180 case Yacid_splash_eB:
6181 case Yacid_splash_wB:
6184 case Yemerald_stone:
6187 case Ydiamond_stone:
6191 case Xdrip_stretchB:
6210 case Xsand_stonein_1:
6211 case Xsand_stonein_2:
6212 case Xsand_stonein_3:
6213 case Xsand_stonein_4:
6217 return (is_backside || action_removing ? EL_EMPTY : element);
6222 inline static boolean check_linear_animation_EM(int tile)
6226 case Xsand_stonesand_1:
6227 case Xsand_stonesand_quickout_1:
6228 case Xsand_sandstone_1:
6229 case Xsand_stonein_1:
6230 case Xsand_stoneout_1:
6255 inline static void set_crumbled_graphics_EM(struct GraphicInfo_EM *g_em,
6256 boolean has_crumbled_graphics,
6257 int crumbled, int sync_frame)
6259 /* if element can be crumbled, but certain action graphics are just empty
6260 space (like instantly snapping sand to empty space in 1 frame), do not
6261 treat these empty space graphics as crumbled graphics in EMC engine */
6262 if (crumbled == IMG_EMPTY_SPACE)
6263 has_crumbled_graphics = FALSE;
6265 if (has_crumbled_graphics)
6267 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
6268 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
6269 g_crumbled->anim_delay,
6270 g_crumbled->anim_mode,
6271 g_crumbled->anim_start_frame,
6274 getGraphicSource(crumbled, frame_crumbled, &g_em->crumbled_bitmap,
6275 &g_em->crumbled_src_x, &g_em->crumbled_src_y);
6277 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
6279 g_em->has_crumbled_graphics = TRUE;
6283 g_em->crumbled_bitmap = NULL;
6284 g_em->crumbled_src_x = 0;
6285 g_em->crumbled_src_y = 0;
6286 g_em->crumbled_border_size = 0;
6288 g_em->has_crumbled_graphics = FALSE;
6292 void ResetGfxAnimation_EM(int x, int y, int tile)
6297 void SetGfxAnimation_EM(struct GraphicInfo_EM *g_em,
6298 int tile, int frame_em, int x, int y)
6300 int action = object_mapping[tile].action;
6302 int direction = object_mapping[tile].direction;
6303 int effective_element = get_effective_element_EM(tile, frame_em);
6304 int graphic = (direction == MV_NONE ?
6305 el_act2img(effective_element, action) :
6306 el_act_dir2img(effective_element, action, direction));
6307 struct GraphicInfo *g = &graphic_info[graphic];
6310 boolean action_removing = (action == ACTION_DIGGING ||
6311 action == ACTION_SNAPPING ||
6312 action == ACTION_COLLECTING);
6313 boolean action_moving = (action == ACTION_FALLING ||
6314 action == ACTION_MOVING ||
6315 action == ACTION_PUSHING ||
6316 action == ACTION_EATING ||
6317 action == ACTION_FILLING ||
6318 action == ACTION_EMPTYING);
6319 boolean action_falling = (action == ACTION_FALLING ||
6320 action == ACTION_FILLING ||
6321 action == ACTION_EMPTYING);
6323 /* special case: graphic uses "2nd movement tile" and has defined
6324 7 frames for movement animation (or less) => use default graphic
6325 for last (8th) frame which ends the movement animation */
6326 if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
6328 action = ACTION_DEFAULT; /* (keep action_* unchanged for now) */
6329 graphic = (direction == MV_NONE ?
6330 el_act2img(effective_element, action) :
6331 el_act_dir2img(effective_element, action, direction));
6333 g = &graphic_info[graphic];
6337 if (tile == Xsand_stonesand_1 ||
6338 tile == Xsand_stonesand_2 ||
6339 tile == Xsand_stonesand_3 ||
6340 tile == Xsand_stonesand_4)
6341 printf("::: 1: quicksand frame %d [%d]\n", GfxFrame[x][y], tile);
6345 if ((action_removing || check_linear_animation_EM(tile)) && frame_em == 0)
6349 // printf("::: resetting... [%d]\n", tile);
6352 if (action_removing || check_linear_animation_EM(tile))
6354 GfxFrame[x][y] = frame_em;
6356 // printf("::: resetting... [%d]\n", tile);
6359 else if (action_moving)
6361 boolean is_backside = object_mapping[tile].is_backside;
6365 int direction = object_mapping[tile].direction;
6366 int move_dir = (action_falling ? MV_DOWN : direction);
6371 /* !!! TEST !!! NEW !!! DOES NOT WORK RIGHT YET !!! */
6372 if (g->double_movement && frame_em == 0)
6376 // printf("::: resetting... [%d]\n", tile);
6380 if (move_dir == MV_LEFT)
6381 GfxFrame[x - 1][y] = GfxFrame[x][y];
6382 else if (move_dir == MV_RIGHT)
6383 GfxFrame[x + 1][y] = GfxFrame[x][y];
6384 else if (move_dir == MV_UP)
6385 GfxFrame[x][y - 1] = GfxFrame[x][y];
6386 else if (move_dir == MV_DOWN)
6387 GfxFrame[x][y + 1] = GfxFrame[x][y];
6394 /* special case: animation for Xsand_stonesand_quickout_1/2 twice as fast */
6395 if (tile == Xsand_stonesand_quickout_1 ||
6396 tile == Xsand_stonesand_quickout_2)
6401 if (tile == Xsand_stonesand_1 ||
6402 tile == Xsand_stonesand_2 ||
6403 tile == Xsand_stonesand_3 ||
6404 tile == Xsand_stonesand_4)
6405 printf("::: 2: quicksand frame %d [%d]\n", GfxFrame[x][y], tile);
6409 if (graphic_info[graphic].anim_global_sync)
6410 sync_frame = FrameCounter;
6411 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
6412 sync_frame = GfxFrame[x][y];
6414 sync_frame = 0; /* playfield border (pseudo steel) */
6416 SetRandomAnimationValue(x, y);
6418 int frame = getAnimationFrame(g->anim_frames,
6421 g->anim_start_frame,
6424 g_em->unique_identifier =
6425 (graphic << 16) | ((frame % 8) << 12) | (g_em->width << 6) | g_em->height;
6429 void getGraphicSourceObjectExt_EM(struct GraphicInfo_EM *g_em,
6430 int tile, int frame_em, int x, int y)
6432 int action = object_mapping[tile].action;
6433 int direction = object_mapping[tile].direction;
6434 boolean is_backside = object_mapping[tile].is_backside;
6435 int effective_element = get_effective_element_EM(tile, frame_em);
6437 int effective_action = action;
6439 int effective_action = (frame_em < 7 ? action : ACTION_DEFAULT);
6441 int graphic = (direction == MV_NONE ?
6442 el_act2img(effective_element, effective_action) :
6443 el_act_dir2img(effective_element, effective_action,
6445 int crumbled = (direction == MV_NONE ?
6446 el_act2crm(effective_element, effective_action) :
6447 el_act_dir2crm(effective_element, effective_action,
6449 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
6450 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
6451 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
6452 struct GraphicInfo *g = &graphic_info[graphic];
6454 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
6458 /* special case: graphic uses "2nd movement tile" and has defined
6459 7 frames for movement animation (or less) => use default graphic
6460 for last (8th) frame which ends the movement animation */
6461 if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
6463 effective_action = ACTION_DEFAULT;
6464 graphic = (direction == MV_NONE ?
6465 el_act2img(effective_element, effective_action) :
6466 el_act_dir2img(effective_element, effective_action,
6468 crumbled = (direction == MV_NONE ?
6469 el_act2crm(effective_element, effective_action) :
6470 el_act_dir2crm(effective_element, effective_action,
6473 g = &graphic_info[graphic];
6483 if (frame_em == 0) /* reset animation frame for certain elements */
6485 if (check_linear_animation_EM(tile))
6490 if (graphic_info[graphic].anim_global_sync)
6491 sync_frame = FrameCounter;
6492 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
6493 sync_frame = GfxFrame[x][y];
6495 sync_frame = 0; /* playfield border (pseudo steel) */
6497 SetRandomAnimationValue(x, y);
6502 int xxx_sync_frame = (i == Xdrip_stretch ? 7 :
6503 i == Xdrip_stretchB ? 7 :
6504 i == Ydrip_s2 ? j + 8 :
6505 i == Ydrip_s2B ? j + 8 :
6514 i == Xfake_acid_1 ? 0 :
6515 i == Xfake_acid_2 ? 10 :
6516 i == Xfake_acid_3 ? 20 :
6517 i == Xfake_acid_4 ? 30 :
6518 i == Xfake_acid_5 ? 40 :
6519 i == Xfake_acid_6 ? 50 :
6520 i == Xfake_acid_7 ? 60 :
6521 i == Xfake_acid_8 ? 70 :
6523 i == Xball_2B ? j + 8 :
6524 i == Yball_eat ? j + 1 :
6525 i == Ykey_1_eat ? j + 1 :
6526 i == Ykey_2_eat ? j + 1 :
6527 i == Ykey_3_eat ? j + 1 :
6528 i == Ykey_4_eat ? j + 1 :
6529 i == Ykey_5_eat ? j + 1 :
6530 i == Ykey_6_eat ? j + 1 :
6531 i == Ykey_7_eat ? j + 1 :
6532 i == Ykey_8_eat ? j + 1 :
6533 i == Ylenses_eat ? j + 1 :
6534 i == Ymagnify_eat ? j + 1 :
6535 i == Ygrass_eat ? j + 1 :
6536 i == Ydirt_eat ? j + 1 :
6537 i == Xamoeba_1 ? 0 :
6538 i == Xamoeba_2 ? 1 :
6539 i == Xamoeba_3 ? 2 :
6540 i == Xamoeba_4 ? 3 :
6541 i == Xamoeba_5 ? 0 :
6542 i == Xamoeba_6 ? 1 :
6543 i == Xamoeba_7 ? 2 :
6544 i == Xamoeba_8 ? 3 :
6545 i == Xexit_2 ? j + 8 :
6546 i == Xexit_3 ? j + 16 :
6547 i == Xdynamite_1 ? 0 :
6548 i == Xdynamite_2 ? 8 :
6549 i == Xdynamite_3 ? 16 :
6550 i == Xdynamite_4 ? 24 :
6551 i == Xsand_stonein_1 ? j + 1 :
6552 i == Xsand_stonein_2 ? j + 9 :
6553 i == Xsand_stonein_3 ? j + 17 :
6554 i == Xsand_stonein_4 ? j + 25 :
6555 i == Xsand_stoneout_1 && j == 0 ? 0 :
6556 i == Xsand_stoneout_1 && j == 1 ? 0 :
6557 i == Xsand_stoneout_1 && j == 2 ? 1 :
6558 i == Xsand_stoneout_1 && j == 3 ? 2 :
6559 i == Xsand_stoneout_1 && j == 4 ? 2 :
6560 i == Xsand_stoneout_1 && j == 5 ? 3 :
6561 i == Xsand_stoneout_1 && j == 6 ? 4 :
6562 i == Xsand_stoneout_1 && j == 7 ? 4 :
6563 i == Xsand_stoneout_2 && j == 0 ? 5 :
6564 i == Xsand_stoneout_2 && j == 1 ? 6 :
6565 i == Xsand_stoneout_2 && j == 2 ? 7 :
6566 i == Xsand_stoneout_2 && j == 3 ? 8 :
6567 i == Xsand_stoneout_2 && j == 4 ? 9 :
6568 i == Xsand_stoneout_2 && j == 5 ? 11 :
6569 i == Xsand_stoneout_2 && j == 6 ? 13 :
6570 i == Xsand_stoneout_2 && j == 7 ? 15 :
6571 i == Xboom_bug && j == 1 ? 2 :
6572 i == Xboom_bug && j == 2 ? 2 :
6573 i == Xboom_bug && j == 3 ? 4 :
6574 i == Xboom_bug && j == 4 ? 4 :
6575 i == Xboom_bug && j == 5 ? 2 :
6576 i == Xboom_bug && j == 6 ? 2 :
6577 i == Xboom_bug && j == 7 ? 0 :
6578 i == Xboom_bomb && j == 1 ? 2 :
6579 i == Xboom_bomb && j == 2 ? 2 :
6580 i == Xboom_bomb && j == 3 ? 4 :
6581 i == Xboom_bomb && j == 4 ? 4 :
6582 i == Xboom_bomb && j == 5 ? 2 :
6583 i == Xboom_bomb && j == 6 ? 2 :
6584 i == Xboom_bomb && j == 7 ? 0 :
6585 i == Xboom_android && j == 7 ? 6 :
6586 i == Xboom_1 && j == 1 ? 2 :
6587 i == Xboom_1 && j == 2 ? 2 :
6588 i == Xboom_1 && j == 3 ? 4 :
6589 i == Xboom_1 && j == 4 ? 4 :
6590 i == Xboom_1 && j == 5 ? 6 :
6591 i == Xboom_1 && j == 6 ? 6 :
6592 i == Xboom_1 && j == 7 ? 8 :
6593 i == Xboom_2 && j == 0 ? 8 :
6594 i == Xboom_2 && j == 1 ? 8 :
6595 i == Xboom_2 && j == 2 ? 10 :
6596 i == Xboom_2 && j == 3 ? 10 :
6597 i == Xboom_2 && j == 4 ? 10 :
6598 i == Xboom_2 && j == 5 ? 12 :
6599 i == Xboom_2 && j == 6 ? 12 :
6600 i == Xboom_2 && j == 7 ? 12 :
6602 special_animation && j == 4 ? 3 :
6603 effective_action != action ? 0 :
6609 int xxx_effective_action;
6610 int xxx_has_action_graphics;
6613 int element = object_mapping[i].element_rnd;
6614 int action = object_mapping[i].action;
6615 int direction = object_mapping[i].direction;
6616 boolean is_backside = object_mapping[i].is_backside;
6618 boolean action_removing = (action == ACTION_DIGGING ||
6619 action == ACTION_SNAPPING ||
6620 action == ACTION_COLLECTING);
6622 boolean action_exploding = ((action == ACTION_EXPLODING ||
6623 action == ACTION_SMASHED_BY_ROCK ||
6624 action == ACTION_SMASHED_BY_SPRING) &&
6625 element != EL_DIAMOND);
6626 boolean action_active = (action == ACTION_ACTIVE);
6627 boolean action_other = (action == ACTION_OTHER);
6631 int effective_element = get_effective_element_EM(i, j);
6633 int effective_element = (j > 5 && i == Yacid_splash_eB ? EL_EMPTY :
6634 j > 5 && i == Yacid_splash_wB ? EL_EMPTY :
6636 i == Xdrip_stretch ? element :
6637 i == Xdrip_stretchB ? element :
6638 i == Ydrip_s1 ? element :
6639 i == Ydrip_s1B ? element :
6640 i == Xball_1B ? element :
6641 i == Xball_2 ? element :
6642 i == Xball_2B ? element :
6643 i == Yball_eat ? element :
6644 i == Ykey_1_eat ? element :
6645 i == Ykey_2_eat ? element :
6646 i == Ykey_3_eat ? element :
6647 i == Ykey_4_eat ? element :
6648 i == Ykey_5_eat ? element :
6649 i == Ykey_6_eat ? element :
6650 i == Ykey_7_eat ? element :
6651 i == Ykey_8_eat ? element :
6652 i == Ylenses_eat ? element :
6653 i == Ymagnify_eat ? element :
6654 i == Ygrass_eat ? element :
6655 i == Ydirt_eat ? element :
6656 i == Yemerald_stone ? EL_EMERALD :
6657 i == Ydiamond_stone ? EL_ROCK :
6658 i == Xsand_stonein_1 ? element :
6659 i == Xsand_stonein_2 ? element :
6660 i == Xsand_stonein_3 ? element :
6661 i == Xsand_stonein_4 ? element :
6662 is_backside ? EL_EMPTY :
6663 action_removing ? EL_EMPTY :
6666 int effective_action = (j < 7 ? action :
6667 i == Xdrip_stretch ? action :
6668 i == Xdrip_stretchB ? action :
6669 i == Ydrip_s1 ? action :
6670 i == Ydrip_s1B ? action :
6671 i == Xball_1B ? action :
6672 i == Xball_2 ? action :
6673 i == Xball_2B ? action :
6674 i == Yball_eat ? action :
6675 i == Ykey_1_eat ? action :
6676 i == Ykey_2_eat ? action :
6677 i == Ykey_3_eat ? action :
6678 i == Ykey_4_eat ? action :
6679 i == Ykey_5_eat ? action :
6680 i == Ykey_6_eat ? action :
6681 i == Ykey_7_eat ? action :
6682 i == Ykey_8_eat ? action :
6683 i == Ylenses_eat ? action :
6684 i == Ymagnify_eat ? action :
6685 i == Ygrass_eat ? action :
6686 i == Ydirt_eat ? action :
6687 i == Xsand_stonein_1 ? action :
6688 i == Xsand_stonein_2 ? action :
6689 i == Xsand_stonein_3 ? action :
6690 i == Xsand_stonein_4 ? action :
6691 i == Xsand_stoneout_1 ? action :
6692 i == Xsand_stoneout_2 ? action :
6693 i == Xboom_android ? ACTION_EXPLODING :
6694 action_exploding ? ACTION_EXPLODING :
6695 action_active ? action :
6696 action_other ? action :
6698 int graphic = (el_act_dir2img(effective_element, effective_action,
6700 int crumbled = (el_act_dir2crm(effective_element, effective_action,
6702 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
6703 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
6704 boolean has_action_graphics = (graphic != base_graphic);
6705 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
6706 struct GraphicInfo *g = &graphic_info[graphic];
6708 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
6710 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
6713 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
6714 boolean special_animation = (action != ACTION_DEFAULT &&
6715 g->anim_frames == 3 &&
6716 g->anim_delay == 2 &&
6717 g->anim_mode & ANIM_LINEAR);
6718 xxx_sync_frame = (i == Xdrip_stretch ? 7 :
6719 i == Xdrip_stretchB ? 7 :
6720 i == Ydrip_s2 ? j + 8 :
6721 i == Ydrip_s2B ? j + 8 :
6730 i == Xfake_acid_1 ? 0 :
6731 i == Xfake_acid_2 ? 10 :
6732 i == Xfake_acid_3 ? 20 :
6733 i == Xfake_acid_4 ? 30 :
6734 i == Xfake_acid_5 ? 40 :
6735 i == Xfake_acid_6 ? 50 :
6736 i == Xfake_acid_7 ? 60 :
6737 i == Xfake_acid_8 ? 70 :
6739 i == Xball_2B ? j + 8 :
6740 i == Yball_eat ? j + 1 :
6741 i == Ykey_1_eat ? j + 1 :
6742 i == Ykey_2_eat ? j + 1 :
6743 i == Ykey_3_eat ? j + 1 :
6744 i == Ykey_4_eat ? j + 1 :
6745 i == Ykey_5_eat ? j + 1 :
6746 i == Ykey_6_eat ? j + 1 :
6747 i == Ykey_7_eat ? j + 1 :
6748 i == Ykey_8_eat ? j + 1 :
6749 i == Ylenses_eat ? j + 1 :
6750 i == Ymagnify_eat ? j + 1 :
6751 i == Ygrass_eat ? j + 1 :
6752 i == Ydirt_eat ? j + 1 :
6753 i == Xamoeba_1 ? 0 :
6754 i == Xamoeba_2 ? 1 :
6755 i == Xamoeba_3 ? 2 :
6756 i == Xamoeba_4 ? 3 :
6757 i == Xamoeba_5 ? 0 :
6758 i == Xamoeba_6 ? 1 :
6759 i == Xamoeba_7 ? 2 :
6760 i == Xamoeba_8 ? 3 :
6761 i == Xexit_2 ? j + 8 :
6762 i == Xexit_3 ? j + 16 :
6763 i == Xdynamite_1 ? 0 :
6764 i == Xdynamite_2 ? 8 :
6765 i == Xdynamite_3 ? 16 :
6766 i == Xdynamite_4 ? 24 :
6767 i == Xsand_stonein_1 ? j + 1 :
6768 i == Xsand_stonein_2 ? j + 9 :
6769 i == Xsand_stonein_3 ? j + 17 :
6770 i == Xsand_stonein_4 ? j + 25 :
6771 i == Xsand_stoneout_1 && j == 0 ? 0 :
6772 i == Xsand_stoneout_1 && j == 1 ? 0 :
6773 i == Xsand_stoneout_1 && j == 2 ? 1 :
6774 i == Xsand_stoneout_1 && j == 3 ? 2 :
6775 i == Xsand_stoneout_1 && j == 4 ? 2 :
6776 i == Xsand_stoneout_1 && j == 5 ? 3 :
6777 i == Xsand_stoneout_1 && j == 6 ? 4 :
6778 i == Xsand_stoneout_1 && j == 7 ? 4 :
6779 i == Xsand_stoneout_2 && j == 0 ? 5 :
6780 i == Xsand_stoneout_2 && j == 1 ? 6 :
6781 i == Xsand_stoneout_2 && j == 2 ? 7 :
6782 i == Xsand_stoneout_2 && j == 3 ? 8 :
6783 i == Xsand_stoneout_2 && j == 4 ? 9 :
6784 i == Xsand_stoneout_2 && j == 5 ? 11 :
6785 i == Xsand_stoneout_2 && j == 6 ? 13 :
6786 i == Xsand_stoneout_2 && j == 7 ? 15 :
6787 i == Xboom_bug && j == 1 ? 2 :
6788 i == Xboom_bug && j == 2 ? 2 :
6789 i == Xboom_bug && j == 3 ? 4 :
6790 i == Xboom_bug && j == 4 ? 4 :
6791 i == Xboom_bug && j == 5 ? 2 :
6792 i == Xboom_bug && j == 6 ? 2 :
6793 i == Xboom_bug && j == 7 ? 0 :
6794 i == Xboom_bomb && j == 1 ? 2 :
6795 i == Xboom_bomb && j == 2 ? 2 :
6796 i == Xboom_bomb && j == 3 ? 4 :
6797 i == Xboom_bomb && j == 4 ? 4 :
6798 i == Xboom_bomb && j == 5 ? 2 :
6799 i == Xboom_bomb && j == 6 ? 2 :
6800 i == Xboom_bomb && j == 7 ? 0 :
6801 i == Xboom_android && j == 7 ? 6 :
6802 i == Xboom_1 && j == 1 ? 2 :
6803 i == Xboom_1 && j == 2 ? 2 :
6804 i == Xboom_1 && j == 3 ? 4 :
6805 i == Xboom_1 && j == 4 ? 4 :
6806 i == Xboom_1 && j == 5 ? 6 :
6807 i == Xboom_1 && j == 6 ? 6 :
6808 i == Xboom_1 && j == 7 ? 8 :
6809 i == Xboom_2 && j == 0 ? 8 :
6810 i == Xboom_2 && j == 1 ? 8 :
6811 i == Xboom_2 && j == 2 ? 10 :
6812 i == Xboom_2 && j == 3 ? 10 :
6813 i == Xboom_2 && j == 4 ? 10 :
6814 i == Xboom_2 && j == 5 ? 12 :
6815 i == Xboom_2 && j == 6 ? 12 :
6816 i == Xboom_2 && j == 7 ? 12 :
6817 special_animation && j == 4 ? 3 :
6818 effective_action != action ? 0 :
6821 xxx_effective_action = effective_action;
6822 xxx_has_action_graphics = has_action_graphics;
6827 int frame = getAnimationFrame(g->anim_frames,
6830 g->anim_start_frame,
6844 int old_src_x = g_em->src_x;
6845 int old_src_y = g_em->src_y;
6849 getGraphicSourceExt(graphic, frame, &g_em->bitmap, &g_em->src_x, &g_em->src_y,
6850 g->double_movement && is_backside);
6852 getGraphicSourceExt(graphic, frame, &g_em->bitmap,
6853 &g_em->src_x, &g_em->src_y, FALSE);
6864 if (graphic == IMG_BUG_MOVING_RIGHT)
6865 printf("::: %d, %d, %d: %d, %d [%d, %d -> %d, %d]\n", graphic, x, y,
6866 g->double_movement, is_backside,
6867 old_src_x, old_src_y, g_em->src_x, g_em->src_y);
6875 g_em->src_offset_x = 0;
6876 g_em->src_offset_y = 0;
6877 g_em->dst_offset_x = 0;
6878 g_em->dst_offset_y = 0;
6879 g_em->width = TILEX;
6880 g_em->height = TILEY;
6882 g_em->preserve_background = FALSE;
6885 /* (updating the "crumbled" graphic definitions is probably not really needed,
6886 as animations for crumbled graphics can't be longer than one EMC cycle) */
6888 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
6893 g_em->crumbled_bitmap = NULL;
6894 g_em->crumbled_src_x = 0;
6895 g_em->crumbled_src_y = 0;
6897 g_em->has_crumbled_graphics = FALSE;
6899 if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
6901 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
6902 g_crumbled->anim_delay,
6903 g_crumbled->anim_mode,
6904 g_crumbled->anim_start_frame,
6907 getGraphicSource(crumbled, frame_crumbled, &g_em->crumbled_bitmap,
6908 &g_em->crumbled_src_x, &g_em->crumbled_src_y);
6910 g_em->has_crumbled_graphics = TRUE;
6916 int effective_action = xxx_effective_action;
6917 int has_action_graphics = xxx_has_action_graphics;
6919 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
6920 effective_action == ACTION_MOVING ||
6921 effective_action == ACTION_PUSHING ||
6922 effective_action == ACTION_EATING)) ||
6923 (!has_action_graphics && (effective_action == ACTION_FILLING ||
6924 effective_action == ACTION_EMPTYING)))
6927 (effective_action == ACTION_FALLING ||
6928 effective_action == ACTION_FILLING ||
6929 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
6930 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
6931 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
6932 int num_steps = (i == Ydrip_s1 ? 16 :
6933 i == Ydrip_s1B ? 16 :
6934 i == Ydrip_s2 ? 16 :
6935 i == Ydrip_s2B ? 16 :
6936 i == Xsand_stonein_1 ? 32 :
6937 i == Xsand_stonein_2 ? 32 :
6938 i == Xsand_stonein_3 ? 32 :
6939 i == Xsand_stonein_4 ? 32 :
6940 i == Xsand_stoneout_1 ? 16 :
6941 i == Xsand_stoneout_2 ? 16 : 8);
6942 int cx = ABS(dx) * (TILEX / num_steps);
6943 int cy = ABS(dy) * (TILEY / num_steps);
6944 int step_frame = (i == Ydrip_s2 ? j + 8 :
6945 i == Ydrip_s2B ? j + 8 :
6946 i == Xsand_stonein_2 ? j + 8 :
6947 i == Xsand_stonein_3 ? j + 16 :
6948 i == Xsand_stonein_4 ? j + 24 :
6949 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
6950 int step = (is_backside ? step_frame : num_steps - step_frame);
6952 if (is_backside) /* tile where movement starts */
6954 if (dx < 0 || dy < 0)
6956 g_em->src_offset_x = cx * step;
6957 g_em->src_offset_y = cy * step;
6961 g_em->dst_offset_x = cx * step;
6962 g_em->dst_offset_y = cy * step;
6965 else /* tile where movement ends */
6967 if (dx < 0 || dy < 0)
6969 g_em->dst_offset_x = cx * step;
6970 g_em->dst_offset_y = cy * step;
6974 g_em->src_offset_x = cx * step;
6975 g_em->src_offset_y = cy * step;
6979 g_em->width = TILEX - cx * step;
6980 g_em->height = TILEY - cy * step;
6983 /* create unique graphic identifier to decide if tile must be redrawn */
6984 /* bit 31 - 16 (16 bit): EM style graphic
6985 bit 15 - 12 ( 4 bit): EM style frame
6986 bit 11 - 6 ( 6 bit): graphic width
6987 bit 5 - 0 ( 6 bit): graphic height */
6988 g_em->unique_identifier =
6989 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
6995 void getGraphicSourcePlayerExt_EM(struct GraphicInfo_EM *g_em,
6996 int player_nr, int anim, int frame_em)
6998 int element = player_mapping[player_nr][anim].element_rnd;
6999 int action = player_mapping[player_nr][anim].action;
7000 int direction = player_mapping[player_nr][anim].direction;
7001 int graphic = (direction == MV_NONE ?
7002 el_act2img(element, action) :
7003 el_act_dir2img(element, action, direction));
7004 struct GraphicInfo *g = &graphic_info[graphic];
7007 InitPlayerGfxAnimation(&stored_player[player_nr], action, direction);
7009 stored_player[player_nr].StepFrame = frame_em;
7011 sync_frame = stored_player[player_nr].Frame;
7013 int frame = getAnimationFrame(g->anim_frames,
7016 g->anim_start_frame,
7019 getGraphicSourceExt(graphic, frame, &g_em->bitmap,
7020 &g_em->src_x, &g_em->src_y, FALSE);
7023 printf("::: %d: %d, %d [%d]\n",
7025 stored_player[player_nr].Frame,
7026 stored_player[player_nr].StepFrame,
7031 void InitGraphicInfo_EM(void)
7034 struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
7035 struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
7040 int num_em_gfx_errors = 0;
7042 if (graphic_info_em_object[0][0].bitmap == NULL)
7044 /* EM graphics not yet initialized in em_open_all() */
7049 printf("::: [4 errors can be ignored (1 x 'bomb', 3 x 'em_dynamite']\n");
7052 /* always start with reliable default values */
7053 for (i = 0; i < TILE_MAX; i++)
7055 object_mapping[i].element_rnd = EL_UNKNOWN;
7056 object_mapping[i].is_backside = FALSE;
7057 object_mapping[i].action = ACTION_DEFAULT;
7058 object_mapping[i].direction = MV_NONE;
7061 /* always start with reliable default values */
7062 for (p = 0; p < MAX_PLAYERS; p++)
7064 for (i = 0; i < SPR_MAX; i++)
7066 player_mapping[p][i].element_rnd = EL_UNKNOWN;
7067 player_mapping[p][i].action = ACTION_DEFAULT;
7068 player_mapping[p][i].direction = MV_NONE;
7072 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
7074 int e = em_object_mapping_list[i].element_em;
7076 object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd;
7077 object_mapping[e].is_backside = em_object_mapping_list[i].is_backside;
7079 if (em_object_mapping_list[i].action != -1)
7080 object_mapping[e].action = em_object_mapping_list[i].action;
7082 if (em_object_mapping_list[i].direction != -1)
7083 object_mapping[e].direction =
7084 MV_DIR_FROM_BIT(em_object_mapping_list[i].direction);
7087 for (i = 0; em_player_mapping_list[i].action_em != -1; i++)
7089 int a = em_player_mapping_list[i].action_em;
7090 int p = em_player_mapping_list[i].player_nr;
7092 player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd;
7094 if (em_player_mapping_list[i].action != -1)
7095 player_mapping[p][a].action = em_player_mapping_list[i].action;
7097 if (em_player_mapping_list[i].direction != -1)
7098 player_mapping[p][a].direction =
7099 MV_DIR_FROM_BIT(em_player_mapping_list[i].direction);
7102 for (i = 0; i < TILE_MAX; i++)
7104 int element = object_mapping[i].element_rnd;
7105 int action = object_mapping[i].action;
7106 int direction = object_mapping[i].direction;
7107 boolean is_backside = object_mapping[i].is_backside;
7109 boolean action_removing = (action == ACTION_DIGGING ||
7110 action == ACTION_SNAPPING ||
7111 action == ACTION_COLLECTING);
7113 boolean action_exploding = ((action == ACTION_EXPLODING ||
7114 action == ACTION_SMASHED_BY_ROCK ||
7115 action == ACTION_SMASHED_BY_SPRING) &&
7116 element != EL_DIAMOND);
7117 boolean action_active = (action == ACTION_ACTIVE);
7118 boolean action_other = (action == ACTION_OTHER);
7120 for (j = 0; j < 8; j++)
7123 int effective_element = get_effective_element_EM(i, j);
7125 int effective_element = (j > 5 && i == Yacid_splash_eB ? EL_EMPTY :
7126 j > 5 && i == Yacid_splash_wB ? EL_EMPTY :
7128 i == Xdrip_stretch ? element :
7129 i == Xdrip_stretchB ? element :
7130 i == Ydrip_s1 ? element :
7131 i == Ydrip_s1B ? element :
7132 i == Xball_1B ? element :
7133 i == Xball_2 ? element :
7134 i == Xball_2B ? element :
7135 i == Yball_eat ? element :
7136 i == Ykey_1_eat ? element :
7137 i == Ykey_2_eat ? element :
7138 i == Ykey_3_eat ? element :
7139 i == Ykey_4_eat ? element :
7140 i == Ykey_5_eat ? element :
7141 i == Ykey_6_eat ? element :
7142 i == Ykey_7_eat ? element :
7143 i == Ykey_8_eat ? element :
7144 i == Ylenses_eat ? element :
7145 i == Ymagnify_eat ? element :
7146 i == Ygrass_eat ? element :
7147 i == Ydirt_eat ? element :
7148 i == Yemerald_stone ? EL_EMERALD :
7149 i == Ydiamond_stone ? EL_ROCK :
7150 i == Xsand_stonein_1 ? element :
7151 i == Xsand_stonein_2 ? element :
7152 i == Xsand_stonein_3 ? element :
7153 i == Xsand_stonein_4 ? element :
7154 is_backside ? EL_EMPTY :
7155 action_removing ? EL_EMPTY :
7158 int effective_action = (j < 7 ? action :
7159 i == Xdrip_stretch ? action :
7160 i == Xdrip_stretchB ? action :
7161 i == Ydrip_s1 ? action :
7162 i == Ydrip_s1B ? action :
7163 i == Xball_1B ? action :
7164 i == Xball_2 ? action :
7165 i == Xball_2B ? action :
7166 i == Yball_eat ? action :
7167 i == Ykey_1_eat ? action :
7168 i == Ykey_2_eat ? action :
7169 i == Ykey_3_eat ? action :
7170 i == Ykey_4_eat ? action :
7171 i == Ykey_5_eat ? action :
7172 i == Ykey_6_eat ? action :
7173 i == Ykey_7_eat ? action :
7174 i == Ykey_8_eat ? action :
7175 i == Ylenses_eat ? action :
7176 i == Ymagnify_eat ? action :
7177 i == Ygrass_eat ? action :
7178 i == Ydirt_eat ? action :
7179 i == Xsand_stonein_1 ? action :
7180 i == Xsand_stonein_2 ? action :
7181 i == Xsand_stonein_3 ? action :
7182 i == Xsand_stonein_4 ? action :
7183 i == Xsand_stoneout_1 ? action :
7184 i == Xsand_stoneout_2 ? action :
7185 i == Xboom_android ? ACTION_EXPLODING :
7186 action_exploding ? ACTION_EXPLODING :
7187 action_active ? action :
7188 action_other ? action :
7190 int graphic = (el_act_dir2img(effective_element, effective_action,
7192 int crumbled = (el_act_dir2crm(effective_element, effective_action,
7194 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
7195 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
7196 boolean has_action_graphics = (graphic != base_graphic);
7197 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
7198 struct GraphicInfo *g = &graphic_info[graphic];
7200 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
7202 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
7205 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
7206 boolean special_animation = (action != ACTION_DEFAULT &&
7207 g->anim_frames == 3 &&
7208 g->anim_delay == 2 &&
7209 g->anim_mode & ANIM_LINEAR);
7210 int sync_frame = (i == Xdrip_stretch ? 7 :
7211 i == Xdrip_stretchB ? 7 :
7212 i == Ydrip_s2 ? j + 8 :
7213 i == Ydrip_s2B ? j + 8 :
7222 i == Xfake_acid_1 ? 0 :
7223 i == Xfake_acid_2 ? 10 :
7224 i == Xfake_acid_3 ? 20 :
7225 i == Xfake_acid_4 ? 30 :
7226 i == Xfake_acid_5 ? 40 :
7227 i == Xfake_acid_6 ? 50 :
7228 i == Xfake_acid_7 ? 60 :
7229 i == Xfake_acid_8 ? 70 :
7231 i == Xball_2B ? j + 8 :
7232 i == Yball_eat ? j + 1 :
7233 i == Ykey_1_eat ? j + 1 :
7234 i == Ykey_2_eat ? j + 1 :
7235 i == Ykey_3_eat ? j + 1 :
7236 i == Ykey_4_eat ? j + 1 :
7237 i == Ykey_5_eat ? j + 1 :
7238 i == Ykey_6_eat ? j + 1 :
7239 i == Ykey_7_eat ? j + 1 :
7240 i == Ykey_8_eat ? j + 1 :
7241 i == Ylenses_eat ? j + 1 :
7242 i == Ymagnify_eat ? j + 1 :
7243 i == Ygrass_eat ? j + 1 :
7244 i == Ydirt_eat ? j + 1 :
7245 i == Xamoeba_1 ? 0 :
7246 i == Xamoeba_2 ? 1 :
7247 i == Xamoeba_3 ? 2 :
7248 i == Xamoeba_4 ? 3 :
7249 i == Xamoeba_5 ? 0 :
7250 i == Xamoeba_6 ? 1 :
7251 i == Xamoeba_7 ? 2 :
7252 i == Xamoeba_8 ? 3 :
7253 i == Xexit_2 ? j + 8 :
7254 i == Xexit_3 ? j + 16 :
7255 i == Xdynamite_1 ? 0 :
7256 i == Xdynamite_2 ? 8 :
7257 i == Xdynamite_3 ? 16 :
7258 i == Xdynamite_4 ? 24 :
7259 i == Xsand_stonein_1 ? j + 1 :
7260 i == Xsand_stonein_2 ? j + 9 :
7261 i == Xsand_stonein_3 ? j + 17 :
7262 i == Xsand_stonein_4 ? j + 25 :
7263 i == Xsand_stoneout_1 && j == 0 ? 0 :
7264 i == Xsand_stoneout_1 && j == 1 ? 0 :
7265 i == Xsand_stoneout_1 && j == 2 ? 1 :
7266 i == Xsand_stoneout_1 && j == 3 ? 2 :
7267 i == Xsand_stoneout_1 && j == 4 ? 2 :
7268 i == Xsand_stoneout_1 && j == 5 ? 3 :
7269 i == Xsand_stoneout_1 && j == 6 ? 4 :
7270 i == Xsand_stoneout_1 && j == 7 ? 4 :
7271 i == Xsand_stoneout_2 && j == 0 ? 5 :
7272 i == Xsand_stoneout_2 && j == 1 ? 6 :
7273 i == Xsand_stoneout_2 && j == 2 ? 7 :
7274 i == Xsand_stoneout_2 && j == 3 ? 8 :
7275 i == Xsand_stoneout_2 && j == 4 ? 9 :
7276 i == Xsand_stoneout_2 && j == 5 ? 11 :
7277 i == Xsand_stoneout_2 && j == 6 ? 13 :
7278 i == Xsand_stoneout_2 && j == 7 ? 15 :
7279 i == Xboom_bug && j == 1 ? 2 :
7280 i == Xboom_bug && j == 2 ? 2 :
7281 i == Xboom_bug && j == 3 ? 4 :
7282 i == Xboom_bug && j == 4 ? 4 :
7283 i == Xboom_bug && j == 5 ? 2 :
7284 i == Xboom_bug && j == 6 ? 2 :
7285 i == Xboom_bug && j == 7 ? 0 :
7286 i == Xboom_bomb && j == 1 ? 2 :
7287 i == Xboom_bomb && j == 2 ? 2 :
7288 i == Xboom_bomb && j == 3 ? 4 :
7289 i == Xboom_bomb && j == 4 ? 4 :
7290 i == Xboom_bomb && j == 5 ? 2 :
7291 i == Xboom_bomb && j == 6 ? 2 :
7292 i == Xboom_bomb && j == 7 ? 0 :
7293 i == Xboom_android && j == 7 ? 6 :
7294 i == Xboom_1 && j == 1 ? 2 :
7295 i == Xboom_1 && j == 2 ? 2 :
7296 i == Xboom_1 && j == 3 ? 4 :
7297 i == Xboom_1 && j == 4 ? 4 :
7298 i == Xboom_1 && j == 5 ? 6 :
7299 i == Xboom_1 && j == 6 ? 6 :
7300 i == Xboom_1 && j == 7 ? 8 :
7301 i == Xboom_2 && j == 0 ? 8 :
7302 i == Xboom_2 && j == 1 ? 8 :
7303 i == Xboom_2 && j == 2 ? 10 :
7304 i == Xboom_2 && j == 3 ? 10 :
7305 i == Xboom_2 && j == 4 ? 10 :
7306 i == Xboom_2 && j == 5 ? 12 :
7307 i == Xboom_2 && j == 6 ? 12 :
7308 i == Xboom_2 && j == 7 ? 12 :
7309 special_animation && j == 4 ? 3 :
7310 effective_action != action ? 0 :
7314 Bitmap *debug_bitmap = g_em->bitmap;
7315 int debug_src_x = g_em->src_x;
7316 int debug_src_y = g_em->src_y;
7319 int frame = getAnimationFrame(g->anim_frames,
7322 g->anim_start_frame,
7325 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y,
7326 g->double_movement && is_backside);
7328 g_em->bitmap = src_bitmap;
7329 g_em->src_x = src_x;
7330 g_em->src_y = src_y;
7331 g_em->src_offset_x = 0;
7332 g_em->src_offset_y = 0;
7333 g_em->dst_offset_x = 0;
7334 g_em->dst_offset_y = 0;
7335 g_em->width = TILEX;
7336 g_em->height = TILEY;
7338 g_em->preserve_background = FALSE;
7341 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
7346 g_em->crumbled_bitmap = NULL;
7347 g_em->crumbled_src_x = 0;
7348 g_em->crumbled_src_y = 0;
7349 g_em->crumbled_border_size = 0;
7351 g_em->has_crumbled_graphics = FALSE;
7354 if (has_crumbled_graphics && crumbled == IMG_EMPTY_SPACE)
7355 printf("::: empty crumbled: %d [%s], %d, %d\n",
7356 effective_element, element_info[effective_element].token_name,
7357 effective_action, direction);
7360 /* if element can be crumbled, but certain action graphics are just empty
7361 space (like instantly snapping sand to empty space in 1 frame), do not
7362 treat these empty space graphics as crumbled graphics in EMC engine */
7363 if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
7365 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
7366 g_crumbled->anim_delay,
7367 g_crumbled->anim_mode,
7368 g_crumbled->anim_start_frame,
7371 getGraphicSource(crumbled, frame_crumbled, &src_bitmap, &src_x, &src_y);
7373 g_em->has_crumbled_graphics = TRUE;
7374 g_em->crumbled_bitmap = src_bitmap;
7375 g_em->crumbled_src_x = src_x;
7376 g_em->crumbled_src_y = src_y;
7377 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
7381 if (g_em == &graphic_info_em_object[207][0])
7382 printf("... %d, %d [%d, %d, %d, %d] [%d, %d, %d, %d, %d, %d => %d]\n",
7383 graphic_info_em_object[207][0].crumbled_src_x,
7384 graphic_info_em_object[207][0].crumbled_src_y,
7386 crumbled, frame, src_x, src_y,
7391 g->anim_start_frame,
7393 gfx.anim_random_frame,
7398 printf("::: EMC tile %d is crumbled\n", i);
7404 if (element == EL_ROCK &&
7405 effective_action == ACTION_FILLING)
7406 printf("::: has_action_graphics == %d\n", has_action_graphics);
7409 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
7410 effective_action == ACTION_MOVING ||
7411 effective_action == ACTION_PUSHING ||
7412 effective_action == ACTION_EATING)) ||
7413 (!has_action_graphics && (effective_action == ACTION_FILLING ||
7414 effective_action == ACTION_EMPTYING)))
7417 (effective_action == ACTION_FALLING ||
7418 effective_action == ACTION_FILLING ||
7419 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
7420 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
7421 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
7422 int num_steps = (i == Ydrip_s1 ? 16 :
7423 i == Ydrip_s1B ? 16 :
7424 i == Ydrip_s2 ? 16 :
7425 i == Ydrip_s2B ? 16 :
7426 i == Xsand_stonein_1 ? 32 :
7427 i == Xsand_stonein_2 ? 32 :
7428 i == Xsand_stonein_3 ? 32 :
7429 i == Xsand_stonein_4 ? 32 :
7430 i == Xsand_stoneout_1 ? 16 :
7431 i == Xsand_stoneout_2 ? 16 : 8);
7432 int cx = ABS(dx) * (TILEX / num_steps);
7433 int cy = ABS(dy) * (TILEY / num_steps);
7434 int step_frame = (i == Ydrip_s2 ? j + 8 :
7435 i == Ydrip_s2B ? j + 8 :
7436 i == Xsand_stonein_2 ? j + 8 :
7437 i == Xsand_stonein_3 ? j + 16 :
7438 i == Xsand_stonein_4 ? j + 24 :
7439 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
7440 int step = (is_backside ? step_frame : num_steps - step_frame);
7442 if (is_backside) /* tile where movement starts */
7444 if (dx < 0 || dy < 0)
7446 g_em->src_offset_x = cx * step;
7447 g_em->src_offset_y = cy * step;
7451 g_em->dst_offset_x = cx * step;
7452 g_em->dst_offset_y = cy * step;
7455 else /* tile where movement ends */
7457 if (dx < 0 || dy < 0)
7459 g_em->dst_offset_x = cx * step;
7460 g_em->dst_offset_y = cy * step;
7464 g_em->src_offset_x = cx * step;
7465 g_em->src_offset_y = cy * step;
7469 g_em->width = TILEX - cx * step;
7470 g_em->height = TILEY - cy * step;
7473 /* create unique graphic identifier to decide if tile must be redrawn */
7474 /* bit 31 - 16 (16 bit): EM style graphic
7475 bit 15 - 12 ( 4 bit): EM style frame
7476 bit 11 - 6 ( 6 bit): graphic width
7477 bit 5 - 0 ( 6 bit): graphic height */
7478 g_em->unique_identifier =
7479 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
7483 /* skip check for EMC elements not contained in original EMC artwork */
7484 if (element == EL_EMC_FAKE_ACID)
7487 if (g_em->bitmap != debug_bitmap ||
7488 g_em->src_x != debug_src_x ||
7489 g_em->src_y != debug_src_y ||
7490 g_em->src_offset_x != 0 ||
7491 g_em->src_offset_y != 0 ||
7492 g_em->dst_offset_x != 0 ||
7493 g_em->dst_offset_y != 0 ||
7494 g_em->width != TILEX ||
7495 g_em->height != TILEY)
7497 static int last_i = -1;
7505 printf("::: EMC GFX ERROR for element %d -> %d ('%s', '%s', %d)",
7506 i, element, element_info[element].token_name,
7507 element_action_info[effective_action].suffix, direction);
7509 if (element != effective_element)
7510 printf(" [%d ('%s')]",
7512 element_info[effective_element].token_name);
7516 if (g_em->bitmap != debug_bitmap)
7517 printf(" %d (%d): different bitmap! (0x%08x != 0x%08x)\n",
7518 j, is_backside, (int)(g_em->bitmap), (int)(debug_bitmap));
7520 if (g_em->src_x != debug_src_x ||
7521 g_em->src_y != debug_src_y)
7522 printf(" frame %d (%c): %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
7523 j, (is_backside ? 'B' : 'F'),
7524 g_em->src_x, g_em->src_y,
7525 g_em->src_x / 32, g_em->src_y / 32,
7526 debug_src_x, debug_src_y,
7527 debug_src_x / 32, debug_src_y / 32);
7529 if (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 printf(" %d (%d): offsets %d,%d and %d,%d should be all 0\n",
7535 g_em->src_offset_x, g_em->src_offset_y,
7536 g_em->dst_offset_x, g_em->dst_offset_y);
7538 if (g_em->width != TILEX ||
7539 g_em->height != TILEY)
7540 printf(" %d (%d): size %d,%d should be %d,%d\n",
7542 g_em->width, g_em->height, TILEX, TILEY);
7544 num_em_gfx_errors++;
7551 for (i = 0; i < TILE_MAX; i++)
7553 for (j = 0; j < 8; j++)
7555 int element = object_mapping[i].element_rnd;
7556 int action = object_mapping[i].action;
7557 int direction = object_mapping[i].direction;
7558 boolean is_backside = object_mapping[i].is_backside;
7559 int graphic_action = el_act_dir2img(element, action, direction);
7560 int graphic_default = el_act_dir2img(element, ACTION_DEFAULT, direction);
7562 if ((action == ACTION_SMASHED_BY_ROCK ||
7563 action == ACTION_SMASHED_BY_SPRING ||
7564 action == ACTION_EATING) &&
7565 graphic_action == graphic_default)
7567 int e = (action == ACTION_SMASHED_BY_ROCK ? Ystone_s :
7568 action == ACTION_SMASHED_BY_SPRING ? Yspring_s :
7569 direction == MV_LEFT ? (is_backside? Yspring_wB: Yspring_w) :
7570 direction == MV_RIGHT ? (is_backside? Yspring_eB: Yspring_e) :
7573 /* no separate animation for "smashed by rock" -- use rock instead */
7574 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
7575 struct GraphicInfo_EM *g_xx = &graphic_info_em_object[e][7 - j];
7577 g_em->bitmap = g_xx->bitmap;
7578 g_em->src_x = g_xx->src_x;
7579 g_em->src_y = g_xx->src_y;
7580 g_em->src_offset_x = g_xx->src_offset_x;
7581 g_em->src_offset_y = g_xx->src_offset_y;
7582 g_em->dst_offset_x = g_xx->dst_offset_x;
7583 g_em->dst_offset_y = g_xx->dst_offset_y;
7584 g_em->width = g_xx->width;
7585 g_em->height = g_xx->height;
7586 g_em->unique_identifier = g_xx->unique_identifier;
7589 g_em->preserve_background = TRUE;
7594 for (p = 0; p < MAX_PLAYERS; p++)
7596 for (i = 0; i < SPR_MAX; i++)
7598 int element = player_mapping[p][i].element_rnd;
7599 int action = player_mapping[p][i].action;
7600 int direction = player_mapping[p][i].direction;
7602 for (j = 0; j < 8; j++)
7604 int effective_element = element;
7605 int effective_action = action;
7606 int graphic = (direction == MV_NONE ?
7607 el_act2img(effective_element, effective_action) :
7608 el_act_dir2img(effective_element, effective_action,
7610 struct GraphicInfo *g = &graphic_info[graphic];
7611 struct GraphicInfo_EM *g_em = &graphic_info_em_player[p][i][7 - j];
7617 Bitmap *debug_bitmap = g_em->bitmap;
7618 int debug_src_x = g_em->src_x;
7619 int debug_src_y = g_em->src_y;
7622 int frame = getAnimationFrame(g->anim_frames,
7625 g->anim_start_frame,
7628 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
7630 g_em->bitmap = src_bitmap;
7631 g_em->src_x = src_x;
7632 g_em->src_y = src_y;
7633 g_em->src_offset_x = 0;
7634 g_em->src_offset_y = 0;
7635 g_em->dst_offset_x = 0;
7636 g_em->dst_offset_y = 0;
7637 g_em->width = TILEX;
7638 g_em->height = TILEY;
7642 /* skip check for EMC elements not contained in original EMC artwork */
7643 if (element == EL_PLAYER_3 ||
7644 element == EL_PLAYER_4)
7647 if (g_em->bitmap != debug_bitmap ||
7648 g_em->src_x != debug_src_x ||
7649 g_em->src_y != debug_src_y)
7651 static int last_i = -1;
7659 printf("::: EMC GFX ERROR for p/a %d/%d -> %d ('%s', '%s', %d)",
7660 p, i, element, element_info[element].token_name,
7661 element_action_info[effective_action].suffix, direction);
7663 if (element != effective_element)
7664 printf(" [%d ('%s')]",
7666 element_info[effective_element].token_name);
7670 if (g_em->bitmap != debug_bitmap)
7671 printf(" %d: different bitmap! (0x%08x != 0x%08x)\n",
7672 j, (int)(g_em->bitmap), (int)(debug_bitmap));
7674 if (g_em->src_x != debug_src_x ||
7675 g_em->src_y != debug_src_y)
7676 printf(" frame %d: %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
7678 g_em->src_x, g_em->src_y,
7679 g_em->src_x / 32, g_em->src_y / 32,
7680 debug_src_x, debug_src_y,
7681 debug_src_x / 32, debug_src_y / 32);
7683 num_em_gfx_errors++;
7693 printf("::: [%d errors found]\n", num_em_gfx_errors);
7699 void PlayMenuSoundExt(int sound)
7701 if (sound == SND_UNDEFINED)
7704 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
7705 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
7708 if (IS_LOOP_SOUND(sound))
7709 PlaySoundLoop(sound);
7714 void PlayMenuSound()
7716 PlayMenuSoundExt(menu.sound[game_status]);
7719 void PlayMenuSoundStereo(int sound, int stereo_position)
7721 if (sound == SND_UNDEFINED)
7724 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
7725 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
7728 if (IS_LOOP_SOUND(sound))
7729 PlaySoundExt(sound, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_LOOP);
7731 PlaySoundStereo(sound, stereo_position);
7734 void PlayMenuSoundIfLoopExt(int sound)
7736 if (sound == SND_UNDEFINED)
7739 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
7740 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
7743 if (IS_LOOP_SOUND(sound))
7744 PlaySoundLoop(sound);
7747 void PlayMenuSoundIfLoop()
7749 PlayMenuSoundIfLoopExt(menu.sound[game_status]);
7752 void PlayMenuMusicExt(int music)
7754 if (music == MUS_UNDEFINED)
7757 if (!setup.sound_music)
7763 void PlayMenuMusic()
7765 PlayMenuMusicExt(menu.music[game_status]);
7768 void PlaySoundActivating()
7771 PlaySound(SND_MENU_ITEM_ACTIVATING);
7775 void PlaySoundSelecting()
7778 PlaySound(SND_MENU_ITEM_SELECTING);
7782 void ToggleFullscreenIfNeeded()
7784 boolean change_fullscreen = (setup.fullscreen !=
7785 video.fullscreen_enabled);
7786 boolean change_fullscreen_mode = (video.fullscreen_enabled &&
7787 !strEqual(setup.fullscreen_mode,
7788 video.fullscreen_mode_current));
7790 if (!video.fullscreen_available)
7794 if (change_fullscreen || change_fullscreen_mode)
7796 if (setup.fullscreen != video.fullscreen_enabled ||
7797 setup.fullscreen_mode != video.fullscreen_mode_current)
7800 Bitmap *tmp_backbuffer = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
7802 /* save backbuffer content which gets lost when toggling fullscreen mode */
7803 BlitBitmap(backbuffer, tmp_backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
7806 if (change_fullscreen_mode)
7808 if (setup.fullscreen && video.fullscreen_enabled)
7811 /* keep fullscreen, but change fullscreen mode (screen resolution) */
7813 /* (this is now set in sdl.c) */
7815 video.fullscreen_mode_current = setup.fullscreen_mode;
7817 video.fullscreen_enabled = FALSE; /* force new fullscreen mode */
7820 /* toggle fullscreen */
7821 ChangeVideoModeIfNeeded(setup.fullscreen);
7823 setup.fullscreen = video.fullscreen_enabled;
7825 /* restore backbuffer content from temporary backbuffer backup bitmap */
7826 BlitBitmap(tmp_backbuffer, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
7828 FreeBitmap(tmp_backbuffer);
7831 /* update visible window/screen */
7832 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
7834 redraw_mask = REDRAW_ALL;