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 && !game.envelope_active)
153 width = gfx.sxsize + 2 * TILEX;
154 height = gfx.sysize + 2 * TILEY;
160 int x1 = (x - SX) / TILEX, y1 = (y - SY) / TILEY;
161 int x2 = (x - SX + width) / TILEX, y2 = (y - SY + height) / TILEY;
163 for (xx = BX1; xx <= BX2; xx++)
164 for (yy = BY1; yy <= BY2; yy++)
165 if (xx >= x1 && xx <= x2 && yy >= y1 && yy <= y2)
166 DrawScreenField(xx, yy);
170 if (setup.soft_scrolling)
172 int fx = FX, fy = FY;
174 fx += (ScreenMovDir & (MV_LEFT|MV_RIGHT) ? ScreenGfxPos : 0);
175 fy += (ScreenMovDir & (MV_UP|MV_DOWN) ? ScreenGfxPos : 0);
177 BlitBitmap(fieldbuffer, backbuffer, fx,fy, SXSIZE,SYSIZE, SX,SY);
189 BlitBitmap(drawto, window, x, y, width, height, x, y);
192 void DrawMaskedBorder_Rect(int x, int y, int width, int height)
194 Bitmap *bitmap = graphic_info[IMG_GLOBAL_BORDER].bitmap;
196 SetClipOrigin(bitmap, bitmap->stored_clip_gc, 0, 0);
197 BlitBitmapMasked(bitmap, backbuffer, x, y, width, height, x, y);
200 void DrawMaskedBorder_FIELD()
202 if (global.border_status >= GAME_MODE_TITLE &&
203 global.border_status <= GAME_MODE_PLAYING &&
204 border.draw_masked[global.border_status])
205 DrawMaskedBorder_Rect(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
208 void DrawMaskedBorder_DOOR_1()
210 if (border.draw_masked[GFX_SPECIAL_ARG_DOOR] &&
211 (global.border_status != GAME_MODE_EDITOR ||
212 border.draw_masked[GFX_SPECIAL_ARG_EDITOR]))
213 DrawMaskedBorder_Rect(DX, DY, DXSIZE, DYSIZE);
216 void DrawMaskedBorder_DOOR_2()
218 if (border.draw_masked[GFX_SPECIAL_ARG_DOOR] &&
219 global.border_status != GAME_MODE_EDITOR)
220 DrawMaskedBorder_Rect(VX, VY, VXSIZE, VYSIZE);
223 void DrawMaskedBorder_DOOR_3()
225 /* currently not available */
228 void DrawMaskedBorder_ALL()
230 DrawMaskedBorder_FIELD();
231 DrawMaskedBorder_DOOR_1();
232 DrawMaskedBorder_DOOR_2();
233 DrawMaskedBorder_DOOR_3();
236 void DrawMaskedBorder(int redraw_mask)
238 /* never draw masked screen borders on borderless screens */
239 if (effectiveGameStatus() == GAME_MODE_LOADING ||
240 effectiveGameStatus() == GAME_MODE_TITLE)
243 if (redraw_mask & REDRAW_ALL)
244 DrawMaskedBorder_ALL();
247 if (redraw_mask & REDRAW_FIELD)
248 DrawMaskedBorder_FIELD();
249 if (redraw_mask & REDRAW_DOOR_1)
250 DrawMaskedBorder_DOOR_1();
251 if (redraw_mask & REDRAW_DOOR_2)
252 DrawMaskedBorder_DOOR_2();
253 if (redraw_mask & REDRAW_DOOR_3)
254 DrawMaskedBorder_DOOR_3();
261 DrawBuffer *buffer = (drawto_field == window ? backbuffer : drawto_field);
264 printf("::: TILES TO REFRESH: %d\n", redraw_tiles);
265 for (x = 0; x < SCR_FIELDX; x++)
266 for (y = 0 ; y < SCR_FIELDY; y++)
267 if (redraw[redraw_x1 + x][redraw_y1 + y])
268 printf("::: - %d, %d [%s]\n",
269 LEVELX(x), LEVELY(y),
270 EL_NAME(Feld[LEVELX(x)][LEVELY(y)]));
273 if (redraw_mask & REDRAW_TILES && redraw_tiles > REDRAWTILES_THRESHOLD)
274 redraw_mask |= REDRAW_FIELD;
276 if (redraw_mask & REDRAW_FIELD)
277 redraw_mask &= ~REDRAW_TILES;
279 if (redraw_mask == REDRAW_NONE)
282 if (redraw_mask & REDRAW_TILES &&
283 game_status == GAME_MODE_PLAYING &&
284 border.draw_masked[GAME_MODE_PLAYING])
285 redraw_mask |= REDRAW_FIELD;
287 if (global.fps_slowdown && game_status == GAME_MODE_PLAYING)
289 static boolean last_frame_skipped = FALSE;
290 boolean skip_even_when_not_scrolling = TRUE;
291 boolean just_scrolling = (ScreenMovDir != 0);
292 boolean verbose = FALSE;
294 if (global.fps_slowdown_factor > 1 &&
295 (FrameCounter % global.fps_slowdown_factor) &&
296 (just_scrolling || skip_even_when_not_scrolling))
298 redraw_mask &= ~REDRAW_MAIN;
300 last_frame_skipped = TRUE;
303 printf("FRAME SKIPPED\n");
307 if (last_frame_skipped)
308 redraw_mask |= REDRAW_FIELD;
310 last_frame_skipped = FALSE;
313 printf("frame not skipped\n");
317 /* synchronize X11 graphics at this point; if we would synchronize the
318 display immediately after the buffer switching (after the XFlush),
319 this could mean that we have to wait for the graphics to complete,
320 although we could go on doing calculations for the next frame */
324 /* prevent drawing masked border to backbuffer when using playfield buffer */
325 if (game_status != GAME_MODE_PLAYING ||
326 redraw_mask & REDRAW_FROM_BACKBUFFER ||
327 buffer == backbuffer)
328 DrawMaskedBorder(redraw_mask);
330 DrawMaskedBorder(redraw_mask & REDRAW_DOORS);
332 if (redraw_mask & REDRAW_ALL)
334 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
336 redraw_mask = REDRAW_NONE;
339 if (redraw_mask & REDRAW_FIELD)
341 if (game_status != GAME_MODE_PLAYING ||
342 redraw_mask & REDRAW_FROM_BACKBUFFER)
344 BlitBitmap(backbuffer, window,
345 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE, REAL_SX, REAL_SY);
349 int fx = FX, fy = FY;
351 if (setup.soft_scrolling)
353 fx += (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
354 fy += (ScreenMovDir & (MV_UP | MV_DOWN) ? ScreenGfxPos : 0);
357 if (setup.soft_scrolling ||
358 ABS(ScreenMovPos) + ScrollStepSize == TILEX ||
359 ABS(ScreenMovPos) == ScrollStepSize ||
360 redraw_tiles > REDRAWTILES_THRESHOLD)
362 if (border.draw_masked[GAME_MODE_PLAYING])
364 if (buffer != backbuffer)
366 /* copy playfield buffer to backbuffer to add masked border */
367 BlitBitmap(buffer, backbuffer, fx, fy, SXSIZE, SYSIZE, SX, SY);
368 DrawMaskedBorder(REDRAW_FIELD);
371 BlitBitmap(backbuffer, window,
372 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
377 BlitBitmap(buffer, window, fx, fy, SXSIZE, SYSIZE, SX, SY);
382 printf("redrawing all (ScreenGfxPos == %d) because %s\n",
384 (setup.soft_scrolling ?
385 "setup.soft_scrolling" :
386 ABS(ScreenGfxPos) + ScrollStepSize == TILEX ?
387 "ABS(ScreenGfxPos) + ScrollStepSize == TILEX" :
388 ABS(ScreenGfxPos) == ScrollStepSize ?
389 "ABS(ScreenGfxPos) == ScrollStepSize" :
390 "redraw_tiles > REDRAWTILES_THRESHOLD"));
396 redraw_mask &= ~REDRAW_MAIN;
399 if (redraw_mask & REDRAW_DOORS)
401 if (redraw_mask & REDRAW_DOOR_1)
402 BlitBitmap(backbuffer, window, DX, DY, DXSIZE, DYSIZE, DX, DY);
404 if (redraw_mask & REDRAW_DOOR_2)
405 BlitBitmap(backbuffer, window, VX, VY, VXSIZE, VYSIZE, VX, VY);
407 if (redraw_mask & REDRAW_DOOR_3)
408 BlitBitmap(backbuffer, window, EX, EY, EXSIZE, EYSIZE, EX, EY);
410 redraw_mask &= ~REDRAW_DOORS;
413 if (redraw_mask & REDRAW_MICROLEVEL)
415 BlitBitmap(backbuffer, window, SX, SY + 10 * TILEY, SXSIZE, 7 * TILEY,
416 SX, SY + 10 * TILEY);
418 redraw_mask &= ~REDRAW_MICROLEVEL;
421 if (redraw_mask & REDRAW_TILES)
423 for (x = 0; x < SCR_FIELDX; x++)
424 for (y = 0 ; y < SCR_FIELDY; y++)
425 if (redraw[redraw_x1 + x][redraw_y1 + y])
426 BlitBitmap(buffer, window,
427 FX + x * TILEX, FY + y * TILEY, TILEX, TILEY,
428 SX + x * TILEX, SY + y * TILEY);
431 if (redraw_mask & REDRAW_FPS) /* display frames per second */
436 sprintf(info1, " (only every %d. frame)", global.fps_slowdown_factor);
437 if (!global.fps_slowdown)
440 sprintf(text, "%04.1f fps%s", global.frames_per_second, info1);
442 DrawTextExt(window, SX + SXSIZE + SX, 0, text, FONT_TEXT_2, BLIT_OPAQUE);
444 DrawTextExt(window, SX, SY, text, FONT_TEXT_2, BLIT_OPAQUE);
450 for (x = 0; x < MAX_BUF_XSIZE; x++)
451 for (y = 0; y < MAX_BUF_YSIZE; y++)
454 redraw_mask = REDRAW_NONE;
457 static void FadeCrossSaveBackbuffer()
459 BlitBitmap(backbuffer, bitmap_db_cross, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
462 static void FadeExt(int fade_mask, int fade_mode, int fade_type)
464 static int fade_type_skip = FADE_TYPE_NONE;
465 void (*draw_border_function)(void) = NULL;
466 Bitmap *bitmap = (fade_mode & FADE_TYPE_TRANSFORM ? bitmap_db_cross : NULL);
467 int x, y, width, height;
468 int fade_delay, post_delay;
470 if (fade_type == FADE_TYPE_FADE_OUT)
472 if (fade_type_skip != FADE_TYPE_NONE)
475 printf("::: skipping %d ... [%d] (X)\n", fade_mode, fade_type_skip);
478 /* skip all fade operations until specified fade operation */
479 if (fade_type & fade_type_skip)
480 fade_type_skip = FADE_TYPE_NONE;
485 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
487 FadeCrossSaveBackbuffer();
493 redraw_mask |= fade_mask;
495 if (fade_type == FADE_TYPE_SKIP)
498 printf("::: will skip %d ... [%d]\n", fade_mode, fade_type_skip);
501 fade_type_skip = fade_mode;
506 if (fade_type_skip != FADE_TYPE_NONE)
509 printf("::: skipping %d ... [%d]\n", fade_mode, fade_type_skip);
512 /* skip all fade operations until specified fade operation */
513 if (fade_type & fade_type_skip)
514 fade_type_skip = FADE_TYPE_NONE;
520 if (global.autoplay_leveldir)
522 // fading.fade_mode = FADE_MODE_NONE;
529 if (fading.fade_mode == FADE_MODE_NONE)
537 /* !!! what abount fade_mask == REDRAW_FIELD | REDRAW_ALL ??? !!! */
540 printf("::: NOW FADING %d ... [%d]\n", fade_mode, fade_type);
544 if (fade_mask == REDRAW_NONE)
545 fade_mask = REDRAW_FIELD;
548 // if (fade_mask & REDRAW_FIELD)
549 if (fade_mask == REDRAW_FIELD)
554 height = FULL_SYSIZE;
556 fade_delay = fading.fade_delay;
557 post_delay = (fade_mode == FADE_MODE_FADE_OUT ? fading.post_delay : 0);
559 if (border.draw_masked_when_fading)
560 draw_border_function = DrawMaskedBorder_FIELD; /* update when fading */
562 DrawMaskedBorder_FIELD(); /* draw once */
564 else /* REDRAW_ALL */
571 fade_delay = fading.fade_delay;
572 post_delay = (fade_mode == FADE_MODE_FADE_OUT ? fading.post_delay : 0);
576 if (!setup.fade_screens ||
578 fading.fade_mode == FADE_MODE_NONE)
580 if (!setup.fade_screens || fade_delay == 0)
583 if (fade_mode == FADE_MODE_FADE_OUT)
587 if (fade_mode == FADE_MODE_FADE_OUT &&
588 fading.fade_mode != FADE_MODE_NONE)
589 ClearRectangle(backbuffer, x, y, width, height);
593 BlitBitmap(backbuffer, window, x, y, width, height, x, y);
594 redraw_mask = REDRAW_NONE;
602 FadeRectangle(bitmap, x, y, width, height, fade_mode, fade_delay, post_delay,
603 draw_border_function);
605 redraw_mask &= ~fade_mask;
608 void FadeIn(int fade_mask)
610 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
611 FadeExt(fade_mask, fading.fade_mode, FADE_TYPE_FADE_IN);
613 FadeExt(fade_mask, FADE_MODE_FADE_IN, FADE_TYPE_FADE_IN);
616 void FadeOut(int fade_mask)
618 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
619 FadeExt(fade_mask, fading.fade_mode, FADE_TYPE_FADE_OUT);
621 FadeExt(fade_mask, FADE_MODE_FADE_OUT, FADE_TYPE_FADE_OUT);
623 global.border_status = game_status;
626 static void FadeSetLeaveNext(struct TitleFadingInfo fading_leave, boolean set)
628 static struct TitleFadingInfo fading_leave_stored;
631 fading_leave_stored = fading_leave;
633 fading = fading_leave_stored;
636 void FadeSetEnterMenu()
638 fading = menu.enter_menu;
641 printf("::: storing enter_menu\n");
644 FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
647 void FadeSetLeaveMenu()
649 fading = menu.leave_menu;
652 printf("::: storing leave_menu\n");
655 FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
658 void FadeSetEnterScreen()
660 fading = menu.enter_screen[game_status];
663 printf("::: storing leave_screen[%d]\n", game_status);
666 FadeSetLeaveNext(menu.leave_screen[game_status], TRUE); /* store */
669 void FadeSetNextScreen()
671 fading = menu.next_screen;
674 printf("::: storing next_screen\n");
677 // (do not overwrite fade mode set by FadeSetEnterScreen)
678 // FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
681 void FadeSetLeaveScreen()
684 printf("::: recalling last stored value\n");
687 FadeSetLeaveNext(menu.leave_screen[game_status], FALSE); /* recall */
690 void FadeSetFromType(int type)
692 if (type & TYPE_ENTER_SCREEN)
693 FadeSetEnterScreen();
694 else if (type & TYPE_ENTER)
696 else if (type & TYPE_LEAVE)
700 void FadeSetDisabled()
702 static struct TitleFadingInfo fading_none = { FADE_MODE_NONE, -1, -1, -1 };
704 fading = fading_none;
707 void FadeSkipNextFadeIn()
709 FadeExt(0, FADE_MODE_SKIP_FADE_IN, FADE_TYPE_SKIP);
712 void FadeSkipNextFadeOut()
714 FadeExt(0, FADE_MODE_SKIP_FADE_OUT, FADE_TYPE_SKIP);
717 void SetWindowBackgroundImageIfDefined(int graphic)
719 if (graphic_info[graphic].bitmap)
720 SetWindowBackgroundBitmap(graphic_info[graphic].bitmap);
723 void SetMainBackgroundImageIfDefined(int graphic)
725 if (graphic_info[graphic].bitmap)
726 SetMainBackgroundBitmap(graphic_info[graphic].bitmap);
729 void SetDoorBackgroundImageIfDefined(int graphic)
731 if (graphic_info[graphic].bitmap)
732 SetDoorBackgroundBitmap(graphic_info[graphic].bitmap);
735 void SetWindowBackgroundImage(int graphic)
737 SetWindowBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
738 graphic_info[graphic].bitmap ?
739 graphic_info[graphic].bitmap :
740 graphic_info[IMG_BACKGROUND].bitmap);
743 void SetMainBackgroundImage(int graphic)
745 SetMainBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
746 graphic_info[graphic].bitmap ?
747 graphic_info[graphic].bitmap :
748 graphic_info[IMG_BACKGROUND].bitmap);
751 void SetDoorBackgroundImage(int graphic)
753 SetDoorBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
754 graphic_info[graphic].bitmap ?
755 graphic_info[graphic].bitmap :
756 graphic_info[IMG_BACKGROUND].bitmap);
759 void SetPanelBackground()
761 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, bitmap_db_panel,
762 DOOR_GFX_PAGEX5, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE, 0, 0);
764 SetDoorBackgroundBitmap(bitmap_db_panel);
767 void DrawBackground(int x, int y, int width, int height)
769 /* !!! "drawto" might still point to playfield buffer here (see below) !!! */
770 /* (when entering hall of fame after playing) */
772 ClearRectangleOnBackground(drawto, x, y, width, height);
774 ClearRectangleOnBackground(backbuffer, x, y, width, height);
777 redraw_mask |= REDRAW_FIELD;
780 void DrawBackgroundForFont(int x, int y, int width, int height, int font_nr)
782 struct FontBitmapInfo *font = getFontBitmapInfo(font_nr);
784 if (font->bitmap == NULL)
787 DrawBackground(x, y, width, height);
790 void DrawBackgroundForGraphic(int x, int y, int width, int height, int graphic)
792 struct GraphicInfo *g = &graphic_info[graphic];
794 if (g->bitmap == NULL)
797 DrawBackground(x, y, width, height);
802 /* !!! "drawto" might still point to playfield buffer here (see above) !!! */
803 /* (when entering hall of fame after playing) */
804 DrawBackground(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
806 /* !!! maybe this should be done before clearing the background !!! */
807 if (setup.soft_scrolling && game_status == GAME_MODE_PLAYING)
809 ClearRectangle(fieldbuffer, 0, 0, FXSIZE, FYSIZE);
810 SetDrawtoField(DRAW_BUFFERED);
813 SetDrawtoField(DRAW_BACKBUFFER);
816 void MarkTileDirty(int x, int y)
818 int xx = redraw_x1 + x;
819 int yy = redraw_y1 + y;
824 redraw[xx][yy] = TRUE;
825 redraw_mask |= REDRAW_TILES;
828 void SetBorderElement()
832 BorderElement = EL_EMPTY;
834 for (y = 0; y < lev_fieldy && BorderElement == EL_EMPTY; y++)
836 for (x = 0; x < lev_fieldx; x++)
838 if (!IS_INDESTRUCTIBLE(Feld[x][y]))
839 BorderElement = EL_STEELWALL;
841 if (y != 0 && y != lev_fieldy - 1 && x != lev_fieldx - 1)
847 void FloodFillLevel(int from_x, int from_y, int fill_element,
848 short field[MAX_LEV_FIELDX][MAX_LEV_FIELDY],
849 int max_fieldx, int max_fieldy)
853 static int check[4][2] = { { -1, 0 }, { 0, -1 }, { 1, 0 }, { 0, 1 } };
854 static int safety = 0;
856 /* check if starting field still has the desired content */
857 if (field[from_x][from_y] == fill_element)
862 if (safety > max_fieldx * max_fieldy)
863 Error(ERR_EXIT, "Something went wrong in 'FloodFill()'. Please debug.");
865 old_element = field[from_x][from_y];
866 field[from_x][from_y] = fill_element;
868 for (i = 0; i < 4; i++)
870 x = from_x + check[i][0];
871 y = from_y + check[i][1];
873 if (IN_FIELD(x, y, max_fieldx, max_fieldy) && field[x][y] == old_element)
874 FloodFillLevel(x, y, fill_element, field, max_fieldx, max_fieldy);
880 void SetRandomAnimationValue(int x, int y)
882 gfx.anim_random_frame = GfxRandom[x][y];
885 inline int getGraphicAnimationFrame(int graphic, int sync_frame)
887 /* animation synchronized with global frame counter, not move position */
888 if (graphic_info[graphic].anim_global_sync || sync_frame < 0)
889 sync_frame = FrameCounter;
891 return getAnimationFrame(graphic_info[graphic].anim_frames,
892 graphic_info[graphic].anim_delay,
893 graphic_info[graphic].anim_mode,
894 graphic_info[graphic].anim_start_frame,
898 void getSizedGraphicSource(int graphic, int frame, int tilesize_raw,
899 Bitmap **bitmap, int *x, int *y)
903 int width_mult, width_div;
904 int height_mult, height_div;
908 { 15, 16, 2, 3 }, /* 1 x 1 */
909 { 7, 8, 2, 3 }, /* 2 x 2 */
910 { 3, 4, 2, 3 }, /* 4 x 4 */
911 { 1, 2, 2, 3 }, /* 8 x 8 */
912 { 0, 1, 2, 3 }, /* 16 x 16 */
913 { 0, 1, 0, 1 }, /* 32 x 32 */
915 struct GraphicInfo *g = &graphic_info[graphic];
916 Bitmap *src_bitmap = g->bitmap;
917 int tilesize = MIN(MAX(1, tilesize_raw), TILESIZE);
918 int offset_calc_pos = log_2(tilesize);
919 int width_mult = offset_calc[offset_calc_pos].width_mult;
920 int width_div = offset_calc[offset_calc_pos].width_div;
921 int height_mult = offset_calc[offset_calc_pos].height_mult;
922 int height_div = offset_calc[offset_calc_pos].height_div;
923 int startx = src_bitmap->width * width_mult / width_div;
924 int starty = src_bitmap->height * height_mult / height_div;
925 int src_x = g->src_x * tilesize / TILESIZE;
926 int src_y = g->src_y * tilesize / TILESIZE;
927 int width = g->width * tilesize / TILESIZE;
928 int height = g->height * tilesize / TILESIZE;
929 int offset_x = g->offset_x * tilesize / TILESIZE;
930 int offset_y = g->offset_y * tilesize / TILESIZE;
932 if (g->offset_y == 0) /* frames are ordered horizontally */
934 int max_width = g->anim_frames_per_line * width;
935 int pos = (src_y / height) * max_width + src_x + frame * offset_x;
937 src_x = pos % max_width;
938 src_y = src_y % height + pos / max_width * height;
940 else if (g->offset_x == 0) /* frames are ordered vertically */
942 int max_height = g->anim_frames_per_line * height;
943 int pos = (src_x / width) * max_height + src_y + frame * offset_y;
945 src_x = src_x % width + pos / max_height * width;
946 src_y = pos % max_height;
948 else /* frames are ordered diagonally */
950 src_x = src_x + frame * offset_x;
951 src_y = src_y + frame * offset_y;
954 *bitmap = src_bitmap;
959 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
962 getSizedGraphicSource(graphic, 0, MINI_TILESIZE, bitmap, x, y);
964 struct GraphicInfo *g = &graphic_info[graphic];
966 int mini_starty = g->bitmap->height * 2 / 3;
969 *x = mini_startx + g->src_x / 2;
970 *y = mini_starty + g->src_y / 2;
974 inline void getGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
975 int *x, int *y, boolean get_backside)
977 struct GraphicInfo *g = &graphic_info[graphic];
978 int src_x = g->src_x + (get_backside ? g->offset2_x : 0);
979 int src_y = g->src_y + (get_backside ? g->offset2_y : 0);
983 if (g->offset_y == 0) /* frames are ordered horizontally */
985 int max_width = g->anim_frames_per_line * g->width;
986 int pos = (src_y / g->height) * max_width + src_x + frame * g->offset_x;
988 *x = pos % max_width;
989 *y = src_y % g->height + pos / max_width * g->height;
991 else if (g->offset_x == 0) /* frames are ordered vertically */
993 int max_height = g->anim_frames_per_line * g->height;
994 int pos = (src_x / g->width) * max_height + src_y + frame * g->offset_y;
996 *x = src_x % g->width + pos / max_height * g->width;
997 *y = pos % max_height;
999 else /* frames are ordered diagonally */
1001 *x = src_x + frame * g->offset_x;
1002 *y = src_y + frame * g->offset_y;
1006 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
1008 getGraphicSourceExt(graphic, frame, bitmap, x, y, FALSE);
1011 void DrawGraphic(int x, int y, int graphic, int frame)
1014 if (!IN_SCR_FIELD(x, y))
1016 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
1017 printf("DrawGraphic(): This should never happen!\n");
1022 DrawGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic, frame);
1023 MarkTileDirty(x, y);
1026 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
1032 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1033 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
1036 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
1039 if (!IN_SCR_FIELD(x, y))
1041 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
1042 printf("DrawGraphicThruMask(): This should never happen!\n");
1047 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y *TILEY, graphic,
1049 MarkTileDirty(x, y);
1052 void DrawGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y, int graphic,
1058 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1060 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1061 dst_x - src_x, dst_y - src_y);
1062 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dst_x, dst_y);
1065 void DrawSizedGraphic(int x, int y, int graphic, int frame, int tilesize)
1067 DrawSizedGraphicExt(drawto, SX + x * tilesize, SY + y * tilesize, graphic,
1069 MarkTileDirty(x / tilesize, y / tilesize);
1072 void DrawSizedGraphicExt(DrawBuffer *d, int x, int y, int graphic, int frame,
1078 getSizedGraphicSource(graphic, frame, tilesize, &src_bitmap, &src_x, &src_y);
1079 BlitBitmap(src_bitmap, d, src_x, src_y, tilesize, tilesize, x, y);
1082 void DrawMiniGraphic(int x, int y, int graphic)
1084 DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
1085 MarkTileDirty(x / 2, y / 2);
1088 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
1093 getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1094 BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
1097 inline static void DrawGraphicShiftedNormal(int x, int y, int dx, int dy,
1098 int graphic, int frame,
1099 int cut_mode, int mask_mode)
1104 int width = TILEX, height = TILEY;
1107 if (dx || dy) /* shifted graphic */
1109 if (x < BX1) /* object enters playfield from the left */
1116 else if (x > BX2) /* object enters playfield from the right */
1122 else if (x==BX1 && dx < 0) /* object leaves playfield to the left */
1128 else if (x==BX2 && dx > 0) /* object leaves playfield to the right */
1130 else if (dx) /* general horizontal movement */
1131 MarkTileDirty(x + SIGN(dx), y);
1133 if (y < BY1) /* object enters playfield from the top */
1135 if (cut_mode==CUT_BELOW) /* object completely above top border */
1143 else if (y > BY2) /* object enters playfield from the bottom */
1149 else if (y==BY1 && dy < 0) /* object leaves playfield to the top */
1155 else if (dy > 0 && cut_mode == CUT_ABOVE)
1157 if (y == BY2) /* object completely above bottom border */
1163 MarkTileDirty(x, y + 1);
1164 } /* object leaves playfield to the bottom */
1165 else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
1167 else if (dy) /* general vertical movement */
1168 MarkTileDirty(x, y + SIGN(dy));
1172 if (!IN_SCR_FIELD(x, y))
1174 printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
1175 printf("DrawGraphicShifted(): This should never happen!\n");
1180 if (width > 0 && height > 0)
1182 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1187 dst_x = FX + x * TILEX + dx;
1188 dst_y = FY + y * TILEY + dy;
1190 if (mask_mode == USE_MASKING)
1192 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1193 dst_x - src_x, dst_y - src_y);
1194 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1198 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1201 MarkTileDirty(x, y);
1205 inline static void DrawGraphicShiftedDouble(int x, int y, int dx, int dy,
1206 int graphic, int frame,
1207 int cut_mode, int mask_mode)
1212 int width = TILEX, height = TILEY;
1215 int x2 = x + SIGN(dx);
1216 int y2 = y + SIGN(dy);
1217 int anim_frames = graphic_info[graphic].anim_frames;
1218 int sync_frame = (dx ? ABS(dx) : ABS(dy)) * anim_frames / TILESIZE;
1219 boolean draw_start_tile = (cut_mode != CUT_ABOVE); /* only for falling! */
1220 boolean draw_end_tile = (cut_mode != CUT_BELOW); /* only for falling! */
1222 /* re-calculate animation frame for two-tile movement animation */
1223 frame = getGraphicAnimationFrame(graphic, sync_frame);
1225 /* check if movement start graphic inside screen area and should be drawn */
1226 if (draw_start_tile && IN_SCR_FIELD(x1, y1))
1228 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, TRUE);
1230 dst_x = FX + x1 * TILEX;
1231 dst_y = FY + y1 * TILEY;
1233 if (mask_mode == USE_MASKING)
1235 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1236 dst_x - src_x, dst_y - src_y);
1237 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1241 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1244 MarkTileDirty(x1, y1);
1247 /* check if movement end graphic inside screen area and should be drawn */
1248 if (draw_end_tile && IN_SCR_FIELD(x2, y2))
1250 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
1252 dst_x = FX + x2 * TILEX;
1253 dst_y = FY + y2 * TILEY;
1255 if (mask_mode == USE_MASKING)
1257 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1258 dst_x - src_x, dst_y - src_y);
1259 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1263 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1266 MarkTileDirty(x2, y2);
1270 static void DrawGraphicShifted(int x, int y, int dx, int dy,
1271 int graphic, int frame,
1272 int cut_mode, int mask_mode)
1276 DrawGraphic(x, y, graphic, frame);
1281 if (graphic_info[graphic].double_movement) /* EM style movement images */
1282 DrawGraphicShiftedDouble(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1284 DrawGraphicShiftedNormal(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1287 void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
1288 int frame, int cut_mode)
1290 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, USE_MASKING);
1293 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
1294 int cut_mode, int mask_mode)
1296 int lx = LEVELX(x), ly = LEVELY(y);
1300 if (IN_LEV_FIELD(lx, ly))
1302 SetRandomAnimationValue(lx, ly);
1304 graphic = el_act_dir2img(element, GfxAction[lx][ly], GfxDir[lx][ly]);
1305 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1307 /* do not use double (EM style) movement graphic when not moving */
1308 if (graphic_info[graphic].double_movement && !dx && !dy)
1310 graphic = el_act_dir2img(element, ACTION_DEFAULT, GfxDir[lx][ly]);
1311 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1314 else /* border element */
1316 graphic = el2img(element);
1317 frame = getGraphicAnimationFrame(graphic, -1);
1320 if (element == EL_EXPANDABLE_WALL)
1322 boolean left_stopped = FALSE, right_stopped = FALSE;
1324 if (!IN_LEV_FIELD(lx - 1, ly) || IS_WALL(Feld[lx - 1][ly]))
1325 left_stopped = TRUE;
1326 if (!IN_LEV_FIELD(lx + 1, ly) || IS_WALL(Feld[lx + 1][ly]))
1327 right_stopped = TRUE;
1329 if (left_stopped && right_stopped)
1331 else if (left_stopped)
1333 graphic = IMG_EXPANDABLE_WALL_GROWING_RIGHT;
1334 frame = graphic_info[graphic].anim_frames - 1;
1336 else if (right_stopped)
1338 graphic = IMG_EXPANDABLE_WALL_GROWING_LEFT;
1339 frame = graphic_info[graphic].anim_frames - 1;
1344 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
1345 else if (mask_mode == USE_MASKING)
1346 DrawGraphicThruMask(x, y, graphic, frame);
1348 DrawGraphic(x, y, graphic, frame);
1351 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
1352 int cut_mode, int mask_mode)
1354 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1355 DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
1356 cut_mode, mask_mode);
1359 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
1362 DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1365 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
1368 DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1371 void DrawLevelElementThruMask(int x, int y, int element)
1373 DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1376 void DrawLevelFieldThruMask(int x, int y)
1378 DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
1381 /* !!! implementation of quicksand is totally broken !!! */
1382 #define IS_CRUMBLED_TILE(x, y, e) \
1383 (GFX_CRUMBLED(e) && (!IN_LEV_FIELD(x, y) || \
1384 !IS_MOVING(x, y) || \
1385 (e) == EL_QUICKSAND_EMPTYING || \
1386 (e) == EL_QUICKSAND_FAST_EMPTYING))
1388 static void DrawLevelFieldCrumbledSandExt(int x, int y, int graphic, int frame)
1392 int sx = SCREENX(x), sy = SCREENY(y);
1394 int width, height, cx, cy, i;
1395 int crumbled_border_size = graphic_info[graphic].border_size;
1396 static int xy[4][2] =
1404 if (!IN_LEV_FIELD(x, y))
1407 element = TILE_GFX_ELEMENT(x, y);
1409 /* crumble field itself */
1411 if (IS_CRUMBLED_TILE(x, y, element))
1413 if (GFX_CRUMBLED(element) && !IS_MOVING(x, y))
1416 if (!IN_SCR_FIELD(sx, sy))
1419 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1421 for (i = 0; i < 4; i++)
1423 int xx = x + xy[i][0];
1424 int yy = y + xy[i][1];
1426 element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1429 /* check if neighbour field is of same type */
1431 if (IS_CRUMBLED_TILE(xx, yy, element))
1434 if (GFX_CRUMBLED(element) && !IS_MOVING(xx, yy))
1438 if (i == 1 || i == 2)
1440 width = crumbled_border_size;
1442 cx = (i == 2 ? TILEX - crumbled_border_size : 0);
1448 height = crumbled_border_size;
1450 cy = (i == 3 ? TILEY - crumbled_border_size : 0);
1453 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1454 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
1457 MarkTileDirty(sx, sy);
1459 else /* crumble neighbour fields */
1461 for (i = 0; i < 4; i++)
1463 int xx = x + xy[i][0];
1464 int yy = y + xy[i][1];
1465 int sxx = sx + xy[i][0];
1466 int syy = sy + xy[i][1];
1469 if (!IN_LEV_FIELD(xx, yy) ||
1470 !IN_SCR_FIELD(sxx, syy))
1473 if (!IN_LEV_FIELD(xx, yy) ||
1474 !IN_SCR_FIELD(sxx, syy) ||
1479 if (Feld[xx][yy] == EL_ELEMENT_SNAPPING)
1482 element = TILE_GFX_ELEMENT(xx, yy);
1485 if (!IS_CRUMBLED_TILE(xx, yy, element))
1488 if (!GFX_CRUMBLED(element))
1492 graphic = el_act2crm(element, ACTION_DEFAULT);
1493 crumbled_border_size = graphic_info[graphic].border_size;
1495 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1497 if (i == 1 || i == 2)
1499 width = crumbled_border_size;
1501 cx = (i == 1 ? TILEX - crumbled_border_size : 0);
1507 height = crumbled_border_size;
1509 cy = (i == 0 ? TILEY - crumbled_border_size : 0);
1512 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1513 width, height, FX + sxx * TILEX + cx, FY + syy * TILEY + cy);
1515 MarkTileDirty(sxx, syy);
1520 void DrawLevelFieldCrumbledSand(int x, int y)
1524 if (!IN_LEV_FIELD(x, y))
1528 /* !!! CHECK THIS !!! */
1531 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
1532 GFX_CRUMBLED(GfxElement[x][y]))
1535 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
1536 GfxElement[x][y] != EL_UNDEFINED &&
1537 GFX_CRUMBLED(GfxElement[x][y]))
1539 DrawLevelFieldCrumbledSandDigging(x, y, GfxDir[x][y], GfxFrame[x][y]);
1546 graphic = el_act2crm(TILE_GFX_ELEMENT(x, y), ACTION_DEFAULT);
1548 graphic = el_act2crm(Feld[x][y], ACTION_DEFAULT);
1551 DrawLevelFieldCrumbledSandExt(x, y, graphic, 0);
1554 void DrawLevelFieldCrumbledSandDigging(int x, int y, int direction,
1557 int graphic1 = el_act_dir2img(GfxElement[x][y], ACTION_DIGGING, direction);
1558 int graphic2 = el_act_dir2crm(GfxElement[x][y], ACTION_DIGGING, direction);
1559 int frame1 = getGraphicAnimationFrame(graphic1, step_frame);
1560 int frame2 = getGraphicAnimationFrame(graphic2, step_frame);
1561 int sx = SCREENX(x), sy = SCREENY(y);
1563 DrawGraphic(sx, sy, graphic1, frame1);
1564 DrawLevelFieldCrumbledSandExt(x, y, graphic2, frame2);
1567 void DrawLevelFieldCrumbledSandNeighbours(int x, int y)
1569 int sx = SCREENX(x), sy = SCREENY(y);
1570 static int xy[4][2] =
1579 for (i = 0; i < 4; i++)
1581 int xx = x + xy[i][0];
1582 int yy = y + xy[i][1];
1583 int sxx = sx + xy[i][0];
1584 int syy = sy + xy[i][1];
1586 if (!IN_LEV_FIELD(xx, yy) ||
1587 !IN_SCR_FIELD(sxx, syy) ||
1588 !GFX_CRUMBLED(Feld[xx][yy]) ||
1592 DrawLevelField(xx, yy);
1596 static int getBorderElement(int x, int y)
1600 { EL_STEELWALL_TOPLEFT, EL_INVISIBLE_STEELWALL_TOPLEFT },
1601 { EL_STEELWALL_TOPRIGHT, EL_INVISIBLE_STEELWALL_TOPRIGHT },
1602 { EL_STEELWALL_BOTTOMLEFT, EL_INVISIBLE_STEELWALL_BOTTOMLEFT },
1603 { EL_STEELWALL_BOTTOMRIGHT, EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
1604 { EL_STEELWALL_VERTICAL, EL_INVISIBLE_STEELWALL_VERTICAL },
1605 { EL_STEELWALL_HORIZONTAL, EL_INVISIBLE_STEELWALL_HORIZONTAL },
1606 { EL_STEELWALL, EL_INVISIBLE_STEELWALL }
1608 int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
1609 int steel_position = (x == -1 && y == -1 ? 0 :
1610 x == lev_fieldx && y == -1 ? 1 :
1611 x == -1 && y == lev_fieldy ? 2 :
1612 x == lev_fieldx && y == lev_fieldy ? 3 :
1613 x == -1 || x == lev_fieldx ? 4 :
1614 y == -1 || y == lev_fieldy ? 5 : 6);
1616 return border[steel_position][steel_type];
1619 void DrawScreenElement(int x, int y, int element)
1621 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
1622 DrawLevelFieldCrumbledSand(LEVELX(x), LEVELY(y));
1625 void DrawLevelElement(int x, int y, int element)
1627 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1628 DrawScreenElement(SCREENX(x), SCREENY(y), element);
1631 void DrawScreenField(int x, int y)
1633 int lx = LEVELX(x), ly = LEVELY(y);
1634 int element, content;
1636 if (!IN_LEV_FIELD(lx, ly))
1638 if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
1641 element = getBorderElement(lx, ly);
1643 DrawScreenElement(x, y, element);
1648 element = Feld[lx][ly];
1649 content = Store[lx][ly];
1651 if (IS_MOVING(lx, ly))
1653 int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
1654 boolean cut_mode = NO_CUTTING;
1656 if (element == EL_QUICKSAND_EMPTYING ||
1657 element == EL_QUICKSAND_FAST_EMPTYING ||
1658 element == EL_MAGIC_WALL_EMPTYING ||
1659 element == EL_BD_MAGIC_WALL_EMPTYING ||
1660 element == EL_DC_MAGIC_WALL_EMPTYING ||
1661 element == EL_AMOEBA_DROPPING)
1662 cut_mode = CUT_ABOVE;
1663 else if (element == EL_QUICKSAND_FILLING ||
1664 element == EL_QUICKSAND_FAST_FILLING ||
1665 element == EL_MAGIC_WALL_FILLING ||
1666 element == EL_BD_MAGIC_WALL_FILLING ||
1667 element == EL_DC_MAGIC_WALL_FILLING)
1668 cut_mode = CUT_BELOW;
1671 if (lx == 9 && ly == 1)
1672 printf("::: %s [%d] [%d, %d] [%d]\n",
1673 EL_NAME(TILE_GFX_ELEMENT(lx, ly)),
1674 el_act2crm(TILE_GFX_ELEMENT(lx, ly), ACTION_DEFAULT),
1675 element_info[EL_QUICKSAND_EMPTYING].graphic[ACTION_DEFAULT],
1676 element_info[EL_QUICKSAND_EMPTYING].crumbled[ACTION_DEFAULT],
1677 GFX_CRUMBLED(TILE_GFX_ELEMENT(lx, ly)));
1680 if (cut_mode == CUT_ABOVE)
1682 DrawScreenElement(x, y, element);
1684 DrawScreenElementShifted(x, y, 0, 0, element, NO_CUTTING);
1687 DrawScreenElement(x, y, EL_EMPTY);
1690 DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
1691 else if (cut_mode == NO_CUTTING)
1692 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
1695 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
1698 if (cut_mode == CUT_BELOW &&
1699 IN_LEV_FIELD(lx, ly + 1) && IN_SCR_FIELD(x, y + 1))
1700 DrawLevelElement(lx, ly + 1, element);
1704 if (content == EL_ACID)
1706 int dir = MovDir[lx][ly];
1707 int newlx = lx + (dir == MV_LEFT ? -1 : dir == MV_RIGHT ? +1 : 0);
1708 int newly = ly + (dir == MV_UP ? -1 : dir == MV_DOWN ? +1 : 0);
1710 DrawLevelElementThruMask(newlx, newly, EL_ACID);
1713 else if (IS_BLOCKED(lx, ly))
1718 boolean cut_mode = NO_CUTTING;
1719 int element_old, content_old;
1721 Blocked2Moving(lx, ly, &oldx, &oldy);
1724 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
1725 MovDir[oldx][oldy] == MV_RIGHT);
1727 element_old = Feld[oldx][oldy];
1728 content_old = Store[oldx][oldy];
1730 if (element_old == EL_QUICKSAND_EMPTYING ||
1731 element_old == EL_QUICKSAND_FAST_EMPTYING ||
1732 element_old == EL_MAGIC_WALL_EMPTYING ||
1733 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
1734 element_old == EL_DC_MAGIC_WALL_EMPTYING ||
1735 element_old == EL_AMOEBA_DROPPING)
1736 cut_mode = CUT_ABOVE;
1738 DrawScreenElement(x, y, EL_EMPTY);
1741 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
1743 else if (cut_mode == NO_CUTTING)
1744 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
1747 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
1750 else if (IS_DRAWABLE(element))
1751 DrawScreenElement(x, y, element);
1753 DrawScreenElement(x, y, EL_EMPTY);
1756 void DrawLevelField(int x, int y)
1758 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1759 DrawScreenField(SCREENX(x), SCREENY(y));
1760 else if (IS_MOVING(x, y))
1764 Moving2Blocked(x, y, &newx, &newy);
1765 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
1766 DrawScreenField(SCREENX(newx), SCREENY(newy));
1768 else if (IS_BLOCKED(x, y))
1772 Blocked2Moving(x, y, &oldx, &oldy);
1773 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
1774 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
1778 void DrawMiniElement(int x, int y, int element)
1782 graphic = el2edimg(element);
1783 DrawMiniGraphic(x, y, graphic);
1786 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
1788 int x = sx + scroll_x, y = sy + scroll_y;
1790 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
1791 DrawMiniElement(sx, sy, EL_EMPTY);
1792 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
1793 DrawMiniElement(sx, sy, Feld[x][y]);
1795 DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
1798 void DrawEnvelopeBackground(int envelope_nr, int startx, int starty,
1799 int x, int y, int xsize, int ysize, int font_nr)
1801 int font_width = getFontWidth(font_nr);
1802 int font_height = getFontHeight(font_nr);
1803 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1806 int dst_x = SX + startx + x * font_width;
1807 int dst_y = SY + starty + y * font_height;
1808 int width = graphic_info[graphic].width;
1809 int height = graphic_info[graphic].height;
1810 int inner_width = MAX(width - 2 * font_width, font_width);
1811 int inner_height = MAX(height - 2 * font_height, font_height);
1812 int inner_sx = (width >= 3 * font_width ? font_width : 0);
1813 int inner_sy = (height >= 3 * font_height ? font_height : 0);
1814 boolean draw_masked = graphic_info[graphic].draw_masked;
1816 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1818 if (src_bitmap == NULL || width < font_width || height < font_height)
1820 ClearRectangle(drawto, dst_x, dst_y, font_width, font_height);
1824 src_x += (x == 0 ? 0 : x == xsize - 1 ? width - font_width :
1825 inner_sx + (x - 1) * font_width % inner_width);
1826 src_y += (y == 0 ? 0 : y == ysize - 1 ? height - font_height :
1827 inner_sy + (y - 1) * font_height % inner_height);
1831 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1832 dst_x - src_x, dst_y - src_y);
1833 BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1837 BlitBitmap(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1841 void AnimateEnvelope(int envelope_nr, int anim_mode, int action)
1843 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1844 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1845 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
1846 boolean ffwd_delay = (tape.playing && tape.fast_forward);
1847 boolean no_delay = (tape.warp_forward);
1848 unsigned long anim_delay = 0;
1849 int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
1850 int anim_delay_value = (no_delay ? 0 : frame_delay_value);
1851 int font_nr = FONT_ENVELOPE_1 + envelope_nr;
1852 int font_width = getFontWidth(font_nr);
1853 int font_height = getFontHeight(font_nr);
1854 int max_xsize = level.envelope[envelope_nr].xsize;
1855 int max_ysize = level.envelope[envelope_nr].ysize;
1856 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
1857 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
1858 int xend = max_xsize;
1859 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
1860 int xstep = (xstart < xend ? 1 : 0);
1861 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
1864 for (x = xstart, y = ystart; x <= xend && y <= yend; x += xstep, y += ystep)
1866 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
1867 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
1868 int sx = (SXSIZE - xsize * font_width) / 2;
1869 int sy = (SYSIZE - ysize * font_height) / 2;
1872 SetDrawtoField(DRAW_BUFFERED);
1874 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
1876 SetDrawtoField(DRAW_BACKBUFFER);
1878 for (yy = 0; yy < ysize; yy++) for (xx = 0; xx < xsize; xx++)
1879 DrawEnvelopeBackground(envelope_nr, sx,sy, xx,yy, xsize, ysize, font_nr);
1882 DrawTextBuffer(SX + sx + font_width, SY + sy + font_height,
1883 level.envelope[envelope_nr].text, font_nr, max_xsize,
1884 xsize - 2, ysize - 2, mask_mode,
1885 level.envelope[envelope_nr].autowrap,
1886 level.envelope[envelope_nr].centered, FALSE);
1888 DrawTextToTextArea(SX + sx + font_width, SY + sy + font_height,
1889 level.envelope[envelope_nr].text, font_nr, max_xsize,
1890 xsize - 2, ysize - 2, mask_mode);
1893 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
1896 WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
1900 void ShowEnvelope(int envelope_nr)
1902 int element = EL_ENVELOPE_1 + envelope_nr;
1903 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1904 int sound_opening = element_info[element].sound[ACTION_OPENING];
1905 int sound_closing = element_info[element].sound[ACTION_CLOSING];
1906 boolean ffwd_delay = (tape.playing && tape.fast_forward);
1907 boolean no_delay = (tape.warp_forward);
1908 int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
1909 int wait_delay_value = (no_delay ? 0 : normal_delay_value);
1910 int anim_mode = graphic_info[graphic].anim_mode;
1911 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
1912 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
1914 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
1916 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
1918 if (anim_mode == ANIM_DEFAULT)
1919 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_OPENING);
1921 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_OPENING);
1924 Delay(wait_delay_value);
1926 WaitForEventToContinue();
1928 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
1930 if (anim_mode != ANIM_NONE)
1931 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_CLOSING);
1933 if (anim_mode == ANIM_DEFAULT)
1934 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_CLOSING);
1936 game.envelope_active = FALSE;
1938 SetDrawtoField(DRAW_BUFFERED);
1940 redraw_mask |= REDRAW_FIELD;
1944 void DrawPreviewElement(int dst_x, int dst_y, int element, int tilesize)
1948 int graphic = el2preimg(element);
1950 getSizedGraphicSource(graphic, 0, tilesize, &src_bitmap, &src_x, &src_y);
1951 BlitBitmap(src_bitmap, drawto, src_x, src_y, tilesize, tilesize, dst_x,dst_y);
1959 SetMainBackgroundImage(IMG_BACKGROUND_PLAYING);
1960 SetDrawBackgroundMask(REDRAW_FIELD);
1962 SetDrawBackgroundMask(REDRAW_NONE);
1967 for (x = BX1; x <= BX2; x++)
1968 for (y = BY1; y <= BY2; y++)
1969 DrawScreenField(x, y);
1971 redraw_mask |= REDRAW_FIELD;
1974 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
1978 for (x = 0; x < size_x; x++)
1979 for (y = 0; y < size_y; y++)
1980 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
1982 redraw_mask |= REDRAW_FIELD;
1985 static void DrawPreviewLevelExt(int from_x, int from_y)
1987 boolean show_level_border = (BorderElement != EL_EMPTY);
1988 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
1989 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
1990 int tile_size = preview.tile_size;
1991 int preview_width = preview.xsize * tile_size;
1992 int preview_height = preview.ysize * tile_size;
1993 int real_preview_xsize = MIN(level_xsize, preview.xsize);
1994 int real_preview_ysize = MIN(level_ysize, preview.ysize);
1995 int dst_x = SX + ALIGNED_XPOS(preview.x, preview_width, preview.align);
1996 int dst_y = SY + ALIGNED_YPOS(preview.y, preview_height, preview.valign);
1999 DrawBackground(dst_x, dst_y, preview_width, preview_height);
2001 dst_x += (preview_width - real_preview_xsize * tile_size) / 2;
2002 dst_y += (preview_height - real_preview_ysize * tile_size) / 2;
2004 for (x = 0; x < real_preview_xsize; x++)
2006 for (y = 0; y < real_preview_ysize; y++)
2008 int lx = from_x + x + (show_level_border ? -1 : 0);
2009 int ly = from_y + y + (show_level_border ? -1 : 0);
2010 int element = (IN_LEV_FIELD(lx, ly) ? level.field[lx][ly] :
2011 getBorderElement(lx, ly));
2013 DrawPreviewElement(dst_x + x * tile_size, dst_y + y * tile_size,
2014 element, tile_size);
2018 redraw_mask |= REDRAW_MICROLEVEL;
2021 #define MICROLABEL_EMPTY 0
2022 #define MICROLABEL_LEVEL_NAME 1
2023 #define MICROLABEL_LEVEL_AUTHOR_HEAD 2
2024 #define MICROLABEL_LEVEL_AUTHOR 3
2025 #define MICROLABEL_IMPORTED_FROM_HEAD 4
2026 #define MICROLABEL_IMPORTED_FROM 5
2027 #define MICROLABEL_IMPORTED_BY_HEAD 6
2028 #define MICROLABEL_IMPORTED_BY 7
2030 static int getMaxTextLength(struct TextPosInfo *pos, int font_nr)
2032 int max_text_width = SXSIZE;
2033 int font_width = getFontWidth(font_nr);
2035 if (pos->align == ALIGN_CENTER)
2036 max_text_width = (pos->x < SXSIZE / 2 ? pos->x * 2 : (SXSIZE - pos->x) * 2);
2037 else if (pos->align == ALIGN_RIGHT)
2038 max_text_width = pos->x;
2040 max_text_width = SXSIZE - pos->x;
2042 return max_text_width / font_width;
2045 static void DrawPreviewLevelLabelExt(int mode)
2047 struct TextPosInfo *pos = &menu.main.text.level_info_2;
2048 char label_text[MAX_OUTPUT_LINESIZE + 1];
2049 int max_len_label_text;
2051 int font_nr = pos->font;
2054 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
2055 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
2056 mode == MICROLABEL_IMPORTED_BY_HEAD)
2057 font_nr = pos->font_alt;
2059 int font_nr = FONT_TEXT_2;
2062 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
2063 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
2064 mode == MICROLABEL_IMPORTED_BY_HEAD)
2065 font_nr = FONT_TEXT_3;
2069 max_len_label_text = getMaxTextLength(pos, font_nr);
2071 max_len_label_text = SXSIZE / getFontWidth(font_nr);
2075 if (pos->size != -1)
2076 max_len_label_text = pos->size;
2079 for (i = 0; i < max_len_label_text; i++)
2080 label_text[i] = ' ';
2081 label_text[max_len_label_text] = '\0';
2083 if (strlen(label_text) > 0)
2086 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2088 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
2089 int lypos = MICROLABEL2_YPOS;
2091 DrawText(lxpos, lypos, label_text, font_nr);
2096 (mode == MICROLABEL_LEVEL_NAME ? level.name :
2097 mode == MICROLABEL_LEVEL_AUTHOR_HEAD ? "created by" :
2098 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
2099 mode == MICROLABEL_IMPORTED_FROM_HEAD ? "imported from" :
2100 mode == MICROLABEL_IMPORTED_FROM ? leveldir_current->imported_from :
2101 mode == MICROLABEL_IMPORTED_BY_HEAD ? "imported by" :
2102 mode == MICROLABEL_IMPORTED_BY ? leveldir_current->imported_by :""),
2103 max_len_label_text);
2104 label_text[max_len_label_text] = '\0';
2106 if (strlen(label_text) > 0)
2109 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2111 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
2112 int lypos = MICROLABEL2_YPOS;
2114 DrawText(lxpos, lypos, label_text, font_nr);
2118 redraw_mask |= REDRAW_MICROLEVEL;
2121 void DrawPreviewLevel(boolean restart)
2123 static unsigned long scroll_delay = 0;
2124 static unsigned long label_delay = 0;
2125 static int from_x, from_y, scroll_direction;
2126 static int label_state, label_counter;
2127 unsigned long scroll_delay_value = preview.step_delay;
2128 boolean show_level_border = (BorderElement != EL_EMPTY);
2129 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
2130 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
2131 int last_game_status = game_status; /* save current game status */
2134 /* force PREVIEW font on preview level */
2135 game_status = GAME_MODE_PSEUDO_PREVIEW;
2143 if (preview.anim_mode == ANIM_CENTERED)
2145 if (level_xsize > preview.xsize)
2146 from_x = (level_xsize - preview.xsize) / 2;
2147 if (level_ysize > preview.ysize)
2148 from_y = (level_ysize - preview.ysize) / 2;
2151 from_x += preview.xoffset;
2152 from_y += preview.yoffset;
2154 scroll_direction = MV_RIGHT;
2158 DrawPreviewLevelExt(from_x, from_y);
2159 DrawPreviewLevelLabelExt(label_state);
2161 /* initialize delay counters */
2162 DelayReached(&scroll_delay, 0);
2163 DelayReached(&label_delay, 0);
2165 if (leveldir_current->name)
2167 struct TextPosInfo *pos = &menu.main.text.level_info_1;
2168 char label_text[MAX_OUTPUT_LINESIZE + 1];
2170 int font_nr = pos->font;
2172 int font_nr = FONT_TEXT_1;
2175 int max_len_label_text = getMaxTextLength(pos, font_nr);
2177 int max_len_label_text = SXSIZE / getFontWidth(font_nr);
2185 if (pos->size != -1)
2186 max_len_label_text = pos->size;
2189 strncpy(label_text, leveldir_current->name, max_len_label_text);
2190 label_text[max_len_label_text] = '\0';
2193 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2195 lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
2196 lypos = SY + MICROLABEL1_YPOS;
2198 DrawText(lxpos, lypos, label_text, font_nr);
2202 game_status = last_game_status; /* restore current game status */
2207 /* scroll preview level, if needed */
2208 if (preview.anim_mode != ANIM_NONE &&
2209 (level_xsize > preview.xsize || level_ysize > preview.ysize) &&
2210 DelayReached(&scroll_delay, scroll_delay_value))
2212 switch (scroll_direction)
2217 from_x -= preview.step_offset;
2218 from_x = (from_x < 0 ? 0 : from_x);
2221 scroll_direction = MV_UP;
2225 if (from_x < level_xsize - preview.xsize)
2227 from_x += preview.step_offset;
2228 from_x = (from_x > level_xsize - preview.xsize ?
2229 level_xsize - preview.xsize : from_x);
2232 scroll_direction = MV_DOWN;
2238 from_y -= preview.step_offset;
2239 from_y = (from_y < 0 ? 0 : from_y);
2242 scroll_direction = MV_RIGHT;
2246 if (from_y < level_ysize - preview.ysize)
2248 from_y += preview.step_offset;
2249 from_y = (from_y > level_ysize - preview.ysize ?
2250 level_ysize - preview.ysize : from_y);
2253 scroll_direction = MV_LEFT;
2260 DrawPreviewLevelExt(from_x, from_y);
2263 /* !!! THIS ALL SUCKS -- SHOULD BE CLEANLY REWRITTEN !!! */
2264 /* redraw micro level label, if needed */
2265 if (!strEqual(level.name, NAMELESS_LEVEL_NAME) &&
2266 !strEqual(level.author, ANONYMOUS_NAME) &&
2267 !strEqual(level.author, leveldir_current->name) &&
2268 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
2270 int max_label_counter = 23;
2272 if (leveldir_current->imported_from != NULL &&
2273 strlen(leveldir_current->imported_from) > 0)
2274 max_label_counter += 14;
2275 if (leveldir_current->imported_by != NULL &&
2276 strlen(leveldir_current->imported_by) > 0)
2277 max_label_counter += 14;
2279 label_counter = (label_counter + 1) % max_label_counter;
2280 label_state = (label_counter >= 0 && label_counter <= 7 ?
2281 MICROLABEL_LEVEL_NAME :
2282 label_counter >= 9 && label_counter <= 12 ?
2283 MICROLABEL_LEVEL_AUTHOR_HEAD :
2284 label_counter >= 14 && label_counter <= 21 ?
2285 MICROLABEL_LEVEL_AUTHOR :
2286 label_counter >= 23 && label_counter <= 26 ?
2287 MICROLABEL_IMPORTED_FROM_HEAD :
2288 label_counter >= 28 && label_counter <= 35 ?
2289 MICROLABEL_IMPORTED_FROM :
2290 label_counter >= 37 && label_counter <= 40 ?
2291 MICROLABEL_IMPORTED_BY_HEAD :
2292 label_counter >= 42 && label_counter <= 49 ?
2293 MICROLABEL_IMPORTED_BY : MICROLABEL_EMPTY);
2295 if (leveldir_current->imported_from == NULL &&
2296 (label_state == MICROLABEL_IMPORTED_FROM_HEAD ||
2297 label_state == MICROLABEL_IMPORTED_FROM))
2298 label_state = (label_state == MICROLABEL_IMPORTED_FROM_HEAD ?
2299 MICROLABEL_IMPORTED_BY_HEAD : MICROLABEL_IMPORTED_BY);
2301 DrawPreviewLevelLabelExt(label_state);
2304 game_status = last_game_status; /* restore current game status */
2307 inline void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
2308 int graphic, int sync_frame, int mask_mode)
2310 int frame = getGraphicAnimationFrame(graphic, sync_frame);
2312 if (mask_mode == USE_MASKING)
2313 DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
2315 DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
2318 inline void DrawGraphicAnimation(int x, int y, int graphic)
2320 int lx = LEVELX(x), ly = LEVELY(y);
2322 if (!IN_SCR_FIELD(x, y))
2325 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
2326 graphic, GfxFrame[lx][ly], NO_MASKING);
2327 MarkTileDirty(x, y);
2330 void DrawLevelGraphicAnimation(int x, int y, int graphic)
2332 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
2335 void DrawLevelElementAnimation(int x, int y, int element)
2337 int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
2339 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
2342 inline void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
2344 int sx = SCREENX(x), sy = SCREENY(y);
2346 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
2349 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
2352 DrawGraphicAnimation(sx, sy, graphic);
2355 if (GFX_CRUMBLED(TILE_GFX_ELEMENT(x, y)))
2356 DrawLevelFieldCrumbledSand(x, y);
2358 if (GFX_CRUMBLED(Feld[x][y]))
2359 DrawLevelFieldCrumbledSand(x, y);
2363 void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
2365 int sx = SCREENX(x), sy = SCREENY(y);
2368 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
2371 graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
2373 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
2376 DrawGraphicAnimation(sx, sy, graphic);
2378 if (GFX_CRUMBLED(element))
2379 DrawLevelFieldCrumbledSand(x, y);
2382 static int getPlayerGraphic(struct PlayerInfo *player, int move_dir)
2384 if (player->use_murphy)
2386 /* this works only because currently only one player can be "murphy" ... */
2387 static int last_horizontal_dir = MV_LEFT;
2388 int graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir);
2390 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
2391 last_horizontal_dir = move_dir;
2393 if (graphic == IMG_SP_MURPHY) /* undefined => use special graphic */
2395 int direction = (player->is_snapping ? move_dir : last_horizontal_dir);
2397 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
2403 return el_act_dir2img(player->artwork_element, player->GfxAction,move_dir);
2406 static boolean equalGraphics(int graphic1, int graphic2)
2408 struct GraphicInfo *g1 = &graphic_info[graphic1];
2409 struct GraphicInfo *g2 = &graphic_info[graphic2];
2411 return (g1->bitmap == g2->bitmap &&
2412 g1->src_x == g2->src_x &&
2413 g1->src_y == g2->src_y &&
2414 g1->anim_frames == g2->anim_frames &&
2415 g1->anim_delay == g2->anim_delay &&
2416 g1->anim_mode == g2->anim_mode);
2419 void DrawAllPlayers()
2423 for (i = 0; i < MAX_PLAYERS; i++)
2424 if (stored_player[i].active)
2425 DrawPlayer(&stored_player[i]);
2428 void DrawPlayerField(int x, int y)
2430 if (!IS_PLAYER(x, y))
2433 DrawPlayer(PLAYERINFO(x, y));
2436 void DrawPlayer(struct PlayerInfo *player)
2438 int jx = player->jx;
2439 int jy = player->jy;
2440 int move_dir = player->MovDir;
2441 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? +1 : 0);
2442 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? +1 : 0);
2443 int last_jx = (player->is_moving ? jx - dx : jx);
2444 int last_jy = (player->is_moving ? jy - dy : jy);
2445 int next_jx = jx + dx;
2446 int next_jy = jy + dy;
2447 boolean player_is_moving = (player->MovPos ? TRUE : FALSE);
2448 boolean player_is_opaque = FALSE;
2449 int sx = SCREENX(jx), sy = SCREENY(jy);
2450 int sxx = 0, syy = 0;
2451 int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
2453 int action = ACTION_DEFAULT;
2454 int last_player_graphic = getPlayerGraphic(player, move_dir);
2455 int last_player_frame = player->Frame;
2458 /* GfxElement[][] is set to the element the player is digging or collecting;
2459 remove also for off-screen player if the player is not moving anymore */
2460 if (IN_LEV_FIELD(jx, jy) && !player_is_moving)
2461 GfxElement[jx][jy] = EL_UNDEFINED;
2463 if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
2467 if (!IN_LEV_FIELD(jx, jy))
2469 printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
2470 printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
2471 printf("DrawPlayerField(): This should never happen!\n");
2476 if (element == EL_EXPLOSION)
2479 action = (player->is_pushing ? ACTION_PUSHING :
2480 player->is_digging ? ACTION_DIGGING :
2481 player->is_collecting ? ACTION_COLLECTING :
2482 player->is_moving ? ACTION_MOVING :
2483 player->is_snapping ? ACTION_SNAPPING :
2484 player->is_dropping ? ACTION_DROPPING :
2485 player->is_waiting ? player->action_waiting : ACTION_DEFAULT);
2487 if (player->is_waiting)
2488 move_dir = player->dir_waiting;
2490 InitPlayerGfxAnimation(player, action, move_dir);
2492 /* ----------------------------------------------------------------------- */
2493 /* draw things in the field the player is leaving, if needed */
2494 /* ----------------------------------------------------------------------- */
2496 if (player->is_moving)
2498 if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
2500 DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
2502 if (last_element == EL_DYNAMITE_ACTIVE ||
2503 last_element == EL_EM_DYNAMITE_ACTIVE ||
2504 last_element == EL_SP_DISK_RED_ACTIVE)
2505 DrawDynamite(last_jx, last_jy);
2507 DrawLevelFieldThruMask(last_jx, last_jy);
2509 else if (last_element == EL_DYNAMITE_ACTIVE ||
2510 last_element == EL_EM_DYNAMITE_ACTIVE ||
2511 last_element == EL_SP_DISK_RED_ACTIVE)
2512 DrawDynamite(last_jx, last_jy);
2514 /* !!! this is not enough to prevent flickering of players which are
2515 moving next to each others without a free tile between them -- this
2516 can only be solved by drawing all players layer by layer (first the
2517 background, then the foreground etc.) !!! => TODO */
2518 else if (!IS_PLAYER(last_jx, last_jy))
2519 DrawLevelField(last_jx, last_jy);
2522 DrawLevelField(last_jx, last_jy);
2525 if (player->is_pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
2526 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
2529 if (!IN_SCR_FIELD(sx, sy))
2532 /* ----------------------------------------------------------------------- */
2533 /* draw things behind the player, if needed */
2534 /* ----------------------------------------------------------------------- */
2537 DrawLevelElement(jx, jy, Back[jx][jy]);
2538 else if (IS_ACTIVE_BOMB(element))
2539 DrawLevelElement(jx, jy, EL_EMPTY);
2542 if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
2544 int old_element = GfxElement[jx][jy];
2545 int old_graphic = el_act_dir2img(old_element, action, move_dir);
2546 int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
2548 if (GFX_CRUMBLED(old_element))
2549 DrawLevelFieldCrumbledSandDigging(jx, jy, move_dir, player->StepFrame);
2551 DrawGraphic(sx, sy, old_graphic, frame);
2553 if (graphic_info[old_graphic].anim_mode & ANIM_OPAQUE_PLAYER)
2554 player_is_opaque = TRUE;
2558 GfxElement[jx][jy] = EL_UNDEFINED;
2560 /* make sure that pushed elements are drawn with correct frame rate */
2562 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
2564 if (player->is_pushing && player->is_moving && !IS_ANIM_MODE_CE(graphic))
2565 GfxFrame[jx][jy] = player->StepFrame;
2567 if (player->is_pushing && player->is_moving)
2568 GfxFrame[jx][jy] = player->StepFrame;
2571 DrawLevelField(jx, jy);
2575 /* ----------------------------------------------------------------------- */
2576 /* draw player himself */
2577 /* ----------------------------------------------------------------------- */
2579 graphic = getPlayerGraphic(player, move_dir);
2581 /* in the case of changed player action or direction, prevent the current
2582 animation frame from being restarted for identical animations */
2583 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
2584 player->Frame = last_player_frame;
2586 frame = getGraphicAnimationFrame(graphic, player->Frame);
2590 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
2591 sxx = player->GfxPos;
2593 syy = player->GfxPos;
2596 if (!setup.soft_scrolling && ScreenMovPos)
2599 if (player_is_opaque)
2600 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
2602 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
2604 if (SHIELD_ON(player))
2606 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
2607 IMG_SHIELD_NORMAL_ACTIVE);
2608 int frame = getGraphicAnimationFrame(graphic, -1);
2610 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
2613 /* ----------------------------------------------------------------------- */
2614 /* draw things the player is pushing, if needed */
2615 /* ----------------------------------------------------------------------- */
2618 printf("::: %d, %d [%d, %d] [%d]\n",
2619 player->is_pushing, player_is_moving, player->GfxAction,
2620 player->is_moving, player_is_moving);
2624 if (player->is_pushing && player->is_moving)
2626 int px = SCREENX(jx), py = SCREENY(jy);
2627 int pxx = (TILEX - ABS(sxx)) * dx;
2628 int pyy = (TILEY - ABS(syy)) * dy;
2629 int gfx_frame = GfxFrame[jx][jy];
2635 if (!IS_MOVING(jx, jy)) /* push movement already finished */
2637 element = Feld[next_jx][next_jy];
2638 gfx_frame = GfxFrame[next_jx][next_jy];
2641 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
2644 sync_frame = (IS_ANIM_MODE_CE(graphic) ? gfx_frame : player->StepFrame);
2645 frame = getGraphicAnimationFrame(graphic, sync_frame);
2647 frame = getGraphicAnimationFrame(graphic, player->StepFrame);
2650 /* draw background element under pushed element (like the Sokoban field) */
2651 if (Back[next_jx][next_jy])
2652 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
2654 /* masked drawing is needed for EMC style (double) movement graphics */
2655 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
2659 /* ----------------------------------------------------------------------- */
2660 /* draw things in front of player (active dynamite or dynabombs) */
2661 /* ----------------------------------------------------------------------- */
2663 if (IS_ACTIVE_BOMB(element))
2665 graphic = el2img(element);
2666 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
2668 if (game.emulation == EMU_SUPAPLEX)
2669 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
2671 DrawGraphicThruMask(sx, sy, graphic, frame);
2674 if (player_is_moving && last_element == EL_EXPLOSION)
2676 int element = (GfxElement[last_jx][last_jy] != EL_UNDEFINED ?
2677 GfxElement[last_jx][last_jy] : EL_EMPTY);
2678 int graphic = el_act2img(element, ACTION_EXPLODING);
2679 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
2680 int phase = ExplodePhase[last_jx][last_jy] - 1;
2681 int frame = getGraphicAnimationFrame(graphic, phase - delay);
2684 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
2687 /* ----------------------------------------------------------------------- */
2688 /* draw elements the player is just walking/passing through/under */
2689 /* ----------------------------------------------------------------------- */
2691 if (player_is_moving)
2693 /* handle the field the player is leaving ... */
2694 if (IS_ACCESSIBLE_INSIDE(last_element))
2695 DrawLevelField(last_jx, last_jy);
2696 else if (IS_ACCESSIBLE_UNDER(last_element))
2697 DrawLevelFieldThruMask(last_jx, last_jy);
2700 /* do not redraw accessible elements if the player is just pushing them */
2701 if (!player_is_moving || !player->is_pushing)
2703 /* ... and the field the player is entering */
2704 if (IS_ACCESSIBLE_INSIDE(element))
2705 DrawLevelField(jx, jy);
2706 else if (IS_ACCESSIBLE_UNDER(element))
2707 DrawLevelFieldThruMask(jx, jy);
2710 MarkTileDirty(sx, sy);
2713 /* ------------------------------------------------------------------------- */
2715 void WaitForEventToContinue()
2717 boolean still_wait = TRUE;
2719 /* simulate releasing mouse button over last gadget, if still pressed */
2721 HandleGadgets(-1, -1, 0);
2723 button_status = MB_RELEASED;
2739 case EVENT_BUTTONPRESS:
2740 case EVENT_KEYPRESS:
2744 case EVENT_KEYRELEASE:
2745 ClearPlayerAction();
2749 HandleOtherEvents(&event);
2753 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2760 /* don't eat all CPU time */
2765 #define MAX_REQUEST_LINES 13
2766 #define MAX_REQUEST_LINE_FONT1_LEN 7
2767 #define MAX_REQUEST_LINE_FONT2_LEN 10
2769 boolean Request(char *text, unsigned int req_state)
2771 int mx, my, ty, result = -1;
2772 unsigned int old_door_state;
2773 int last_game_status = game_status; /* save current game status */
2774 int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
2775 int font_nr = FONT_TEXT_2;
2776 int max_word_len = 0;
2779 for (text_ptr = text; *text_ptr; text_ptr++)
2781 max_word_len = (*text_ptr != ' ' ? max_word_len + 1 : 0);
2783 if (max_word_len > MAX_REQUEST_LINE_FONT1_LEN)
2785 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
2787 font_nr = FONT_TEXT_1;
2789 font_nr = FONT_LEVEL_NUMBER;
2796 if (game_status == GAME_MODE_PLAYING &&
2797 level.game_engine_type == GAME_ENGINE_TYPE_EM)
2798 BlitScreenToBitmap_EM(backbuffer);
2800 /* disable deactivated drawing when quick-loading level tape recording */
2801 if (tape.playing && tape.deactivate_display)
2802 TapeDeactivateDisplayOff(TRUE);
2804 SetMouseCursor(CURSOR_DEFAULT);
2806 #if defined(NETWORK_AVALIABLE)
2807 /* pause network game while waiting for request to answer */
2808 if (options.network &&
2809 game_status == GAME_MODE_PLAYING &&
2810 req_state & REQUEST_WAIT_FOR_INPUT)
2811 SendToServer_PausePlaying();
2814 old_door_state = GetDoorState();
2816 /* simulate releasing mouse button over last gadget, if still pressed */
2818 HandleGadgets(-1, -1, 0);
2822 if (old_door_state & DOOR_OPEN_1)
2824 CloseDoor(DOOR_CLOSE_1);
2826 /* save old door content */
2827 BlitBitmap(bitmap_db_door, bitmap_db_door,
2828 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
2829 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
2833 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
2836 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2838 /* clear door drawing field */
2839 DrawBackground(DX, DY, DXSIZE, DYSIZE);
2841 /* force DOOR font inside door area */
2842 game_status = GAME_MODE_PSEUDO_DOOR;
2844 /* write text for request */
2845 for (ty = 0; ty < MAX_REQUEST_LINES; ty++)
2847 char text_line[max_request_line_len + 1];
2853 for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
2856 if (!tc || tc == ' ')
2867 strncpy(text_line, text, tl);
2870 DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
2871 DY + 8 + ty * (getFontHeight(font_nr) + 2),
2872 text_line, font_nr);
2874 text += tl + (tc == ' ' ? 1 : 0);
2877 game_status = last_game_status; /* restore current game status */
2879 if (req_state & REQ_ASK)
2881 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
2882 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
2884 else if (req_state & REQ_CONFIRM)
2886 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
2888 else if (req_state & REQ_PLAYER)
2890 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
2891 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
2892 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
2893 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
2896 /* copy request gadgets to door backbuffer */
2897 BlitBitmap(drawto, bitmap_db_door,
2898 DX, DY, DXSIZE, DYSIZE,
2899 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2901 OpenDoor(DOOR_OPEN_1);
2903 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
2905 if (game_status == GAME_MODE_PLAYING)
2907 SetPanelBackground();
2908 SetDrawBackgroundMask(REDRAW_DOOR_1);
2912 SetDrawBackgroundMask(REDRAW_FIELD);
2918 if (game_status != GAME_MODE_MAIN)
2921 button_status = MB_RELEASED;
2923 request_gadget_id = -1;
2925 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2937 case EVENT_BUTTONPRESS:
2938 case EVENT_BUTTONRELEASE:
2939 case EVENT_MOTIONNOTIFY:
2941 if (event.type == EVENT_MOTIONNOTIFY)
2943 if (!PointerInWindow(window))
2944 continue; /* window and pointer are on different screens */
2949 motion_status = TRUE;
2950 mx = ((MotionEvent *) &event)->x;
2951 my = ((MotionEvent *) &event)->y;
2955 motion_status = FALSE;
2956 mx = ((ButtonEvent *) &event)->x;
2957 my = ((ButtonEvent *) &event)->y;
2958 if (event.type == EVENT_BUTTONPRESS)
2959 button_status = ((ButtonEvent *) &event)->button;
2961 button_status = MB_RELEASED;
2964 /* this sets 'request_gadget_id' */
2965 HandleGadgets(mx, my, button_status);
2967 switch (request_gadget_id)
2969 case TOOL_CTRL_ID_YES:
2972 case TOOL_CTRL_ID_NO:
2975 case TOOL_CTRL_ID_CONFIRM:
2976 result = TRUE | FALSE;
2979 case TOOL_CTRL_ID_PLAYER_1:
2982 case TOOL_CTRL_ID_PLAYER_2:
2985 case TOOL_CTRL_ID_PLAYER_3:
2988 case TOOL_CTRL_ID_PLAYER_4:
2999 case EVENT_KEYPRESS:
3000 switch (GetEventKey((KeyEvent *)&event, TRUE))
3003 if (req_state & REQ_CONFIRM)
3019 if (req_state & REQ_PLAYER)
3023 case EVENT_KEYRELEASE:
3024 ClearPlayerAction();
3028 HandleOtherEvents(&event);
3032 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
3034 int joy = AnyJoystick();
3036 if (joy & JOY_BUTTON_1)
3038 else if (joy & JOY_BUTTON_2)
3044 if (game_status == GAME_MODE_PLAYING && local_player->LevelSolved_GameEnd)
3046 HandleGameActions();
3052 if (!PendingEvent()) /* delay only if no pending events */
3063 if (!PendingEvent()) /* delay only if no pending events */
3066 /* don't eat all CPU time */
3073 if (game_status != GAME_MODE_MAIN)
3078 if (!(req_state & REQ_STAY_OPEN))
3080 CloseDoor(DOOR_CLOSE_1);
3082 if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
3083 (req_state & REQ_REOPEN))
3084 OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
3089 if (game_status == GAME_MODE_PLAYING)
3091 SetPanelBackground();
3092 SetDrawBackgroundMask(REDRAW_DOOR_1);
3096 SetDrawBackgroundMask(REDRAW_FIELD);
3099 #if defined(NETWORK_AVALIABLE)
3100 /* continue network game after request */
3101 if (options.network &&
3102 game_status == GAME_MODE_PLAYING &&
3103 req_state & REQUEST_WAIT_FOR_INPUT)
3104 SendToServer_ContinuePlaying();
3107 /* restore deactivated drawing when quick-loading level tape recording */
3108 if (tape.playing && tape.deactivate_display)
3109 TapeDeactivateDisplayOn();
3114 unsigned int OpenDoor(unsigned int door_state)
3116 if (door_state & DOOR_COPY_BACK)
3118 if (door_state & DOOR_OPEN_1)
3119 BlitBitmap(bitmap_db_door, bitmap_db_door,
3120 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
3121 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
3123 if (door_state & DOOR_OPEN_2)
3124 BlitBitmap(bitmap_db_door, bitmap_db_door,
3125 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY2, VXSIZE, VYSIZE,
3126 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
3128 door_state &= ~DOOR_COPY_BACK;
3131 return MoveDoor(door_state);
3134 unsigned int CloseDoor(unsigned int door_state)
3136 unsigned int old_door_state = GetDoorState();
3138 if (!(door_state & DOOR_NO_COPY_BACK))
3140 if (old_door_state & DOOR_OPEN_1)
3141 BlitBitmap(backbuffer, bitmap_db_door,
3142 DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
3144 if (old_door_state & DOOR_OPEN_2)
3145 BlitBitmap(backbuffer, bitmap_db_door,
3146 VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
3148 door_state &= ~DOOR_NO_COPY_BACK;
3151 return MoveDoor(door_state);
3154 unsigned int GetDoorState()
3156 return MoveDoor(DOOR_GET_STATE);
3159 unsigned int SetDoorState(unsigned int door_state)
3161 return MoveDoor(door_state | DOOR_SET_STATE);
3164 unsigned int MoveDoor(unsigned int door_state)
3166 static int door1 = DOOR_OPEN_1;
3167 static int door2 = DOOR_CLOSE_2;
3168 unsigned long door_delay = 0;
3169 unsigned long door_delay_value;
3172 if (door_1.width < 0 || door_1.width > DXSIZE)
3173 door_1.width = DXSIZE;
3174 if (door_1.height < 0 || door_1.height > DYSIZE)
3175 door_1.height = DYSIZE;
3176 if (door_2.width < 0 || door_2.width > VXSIZE)
3177 door_2.width = VXSIZE;
3178 if (door_2.height < 0 || door_2.height > VYSIZE)
3179 door_2.height = VYSIZE;
3181 if (door_state == DOOR_GET_STATE)
3182 return (door1 | door2);
3184 if (door_state & DOOR_SET_STATE)
3186 if (door_state & DOOR_ACTION_1)
3187 door1 = door_state & DOOR_ACTION_1;
3188 if (door_state & DOOR_ACTION_2)
3189 door2 = door_state & DOOR_ACTION_2;
3191 return (door1 | door2);
3194 if (!(door_state & DOOR_FORCE_REDRAW))
3196 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
3197 door_state &= ~DOOR_OPEN_1;
3198 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
3199 door_state &= ~DOOR_CLOSE_1;
3200 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
3201 door_state &= ~DOOR_OPEN_2;
3202 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
3203 door_state &= ~DOOR_CLOSE_2;
3206 door_delay_value = (door_state & DOOR_ACTION_1 ? door_1.step_delay :
3209 if (setup.quick_doors)
3211 stepsize = 20; /* must be chosen to always draw last frame */
3212 door_delay_value = 0;
3215 if (global.autoplay_leveldir)
3217 door_state |= DOOR_NO_DELAY;
3218 door_state &= ~DOOR_CLOSE_ALL;
3222 if (game_status == GAME_MODE_EDITOR)
3223 door_state |= DOOR_NO_DELAY;
3226 if (door_state & DOOR_ACTION)
3228 boolean handle_door_1 = (door_state & DOOR_ACTION_1);
3229 boolean handle_door_2 = (door_state & DOOR_ACTION_2);
3230 boolean door_1_done = (!handle_door_1);
3231 boolean door_2_done = (!handle_door_2);
3232 boolean door_1_vertical = (door_1.anim_mode & ANIM_VERTICAL);
3233 boolean door_2_vertical = (door_2.anim_mode & ANIM_VERTICAL);
3234 int door_size_1 = (door_1_vertical ? door_1.height : door_1.width);
3235 int door_size_2 = (door_2_vertical ? door_2.height : door_2.width);
3236 int max_door_size_1 = (door_1_vertical ? DYSIZE : DXSIZE);
3237 int max_door_size_2 = (door_2_vertical ? VYSIZE : VXSIZE);
3238 int door_size = (handle_door_1 ? door_size_1 : door_size_2);
3239 int max_door_size = (handle_door_1 ? max_door_size_1 : max_door_size_2);
3240 int door_skip = max_door_size - door_size;
3241 int end = door_size;
3242 int start = ((door_state & DOOR_NO_DELAY) ? end : 0);
3245 if (!(door_state & DOOR_NO_DELAY) && !setup.quick_doors)
3247 /* opening door sound has priority over simultaneously closing door */
3248 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
3249 PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
3250 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
3251 PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
3254 for (k = start; k <= end && !(door_1_done && door_2_done); k += stepsize)
3257 Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
3258 GC gc = bitmap->stored_clip_gc;
3260 if (door_state & DOOR_ACTION_1)
3262 int a = MIN(x * door_1.step_offset, end);
3263 int p = (door_state & DOOR_OPEN_1 ? end - a : a);
3264 int i = p + door_skip;
3266 if (door_1.anim_mode & ANIM_STATIC_PANEL)
3268 BlitBitmap(bitmap_db_door, drawto,
3269 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1,
3270 DXSIZE, DYSIZE, DX, DY);
3274 BlitBitmap(bitmap_db_door, drawto,
3275 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + p / 2,
3276 DXSIZE, DYSIZE - p / 2, DX, DY);
3278 ClearRectangle(drawto, DX, DY + DYSIZE - p / 2, DXSIZE, p / 2);
3281 if (door_1.anim_mode & ANIM_HORIZONTAL && x <= DXSIZE)
3283 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
3284 int dst1_x = DX + DXSIZE - i, dst1_y = DY;
3285 int src2_x = DXSIZE - i, src2_y = DOOR_GFX_PAGEY1;
3286 int dst2_x = DX, dst2_y = DY;
3287 int width = i, height = DYSIZE;
3289 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3290 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3293 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3294 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3297 else if (door_1.anim_mode & ANIM_VERTICAL && x <= DYSIZE)
3299 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
3300 int dst1_x = DX, dst1_y = DY + DYSIZE - i;
3301 int src2_x = 0, src2_y = DOOR_GFX_PAGEY1 + DYSIZE - i;
3302 int dst2_x = DX, dst2_y = DY;
3303 int width = DXSIZE, height = i;
3305 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3306 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3309 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3310 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3313 else if (x <= DXSIZE) /* ANIM_DEFAULT */
3315 int j = (door_1.anim_mode == ANIM_DEFAULT ? (DXSIZE - i) / 3 : 0);
3317 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
3318 BlitBitmapMasked(bitmap, drawto,
3319 DXSIZE, DOOR_GFX_PAGEY1, i, 77,
3320 DX + DXSIZE - i, DY + j);
3321 BlitBitmapMasked(bitmap, drawto,
3322 DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
3323 DX + DXSIZE - i, DY + 140 + j);
3324 SetClipOrigin(bitmap, gc, DX - DXSIZE + i,
3325 DY - (DOOR_GFX_PAGEY1 + j));
3326 BlitBitmapMasked(bitmap, drawto,
3327 DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
3329 BlitBitmapMasked(bitmap, drawto,
3330 DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
3333 BlitBitmapMasked(bitmap, drawto,
3334 DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
3336 BlitBitmapMasked(bitmap, drawto,
3337 DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
3339 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
3340 BlitBitmapMasked(bitmap, drawto,
3341 DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
3342 DX + DXSIZE - i, DY + 77 + j);
3343 BlitBitmapMasked(bitmap, drawto,
3344 DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
3345 DX + DXSIZE - i, DY + 203 + j);
3348 redraw_mask |= REDRAW_DOOR_1;
3349 door_1_done = (a == end);
3352 if (door_state & DOOR_ACTION_2)
3354 int a = MIN(x * door_2.step_offset, door_size);
3355 int p = (door_state & DOOR_OPEN_2 ? door_size - a : a);
3356 int i = p + door_skip;
3358 if (door_2.anim_mode & ANIM_STATIC_PANEL)
3360 BlitBitmap(bitmap_db_door, drawto,
3361 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2,
3362 VXSIZE, VYSIZE, VX, VY);
3364 else if (x <= VYSIZE)
3366 BlitBitmap(bitmap_db_door, drawto,
3367 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + p / 2,
3368 VXSIZE, VYSIZE - p / 2, VX, VY);
3370 ClearRectangle(drawto, VX, VY + VYSIZE - p / 2, VXSIZE, p / 2);
3373 if (door_2.anim_mode & ANIM_HORIZONTAL && x <= VXSIZE)
3375 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
3376 int dst1_x = VX + VXSIZE - i, dst1_y = VY;
3377 int src2_x = VXSIZE - i, src2_y = DOOR_GFX_PAGEY2;
3378 int dst2_x = VX, dst2_y = VY;
3379 int width = i, height = VYSIZE;
3381 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3382 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3385 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3386 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3389 else if (door_2.anim_mode & ANIM_VERTICAL && x <= VYSIZE)
3391 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
3392 int dst1_x = VX, dst1_y = VY + VYSIZE - i;
3393 int src2_x = 0, src2_y = DOOR_GFX_PAGEY2 + VYSIZE - i;
3394 int dst2_x = VX, dst2_y = VY;
3395 int width = VXSIZE, height = i;
3397 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3398 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3401 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3402 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3405 else if (x <= VXSIZE) /* ANIM_DEFAULT */
3407 int j = (door_2.anim_mode == ANIM_DEFAULT ? (VXSIZE - i) / 3 : 0);
3409 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
3410 BlitBitmapMasked(bitmap, drawto,
3411 VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
3412 VX + VXSIZE - i, VY + j);
3413 SetClipOrigin(bitmap, gc,
3414 VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
3415 BlitBitmapMasked(bitmap, drawto,
3416 VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
3419 BlitBitmapMasked(bitmap, drawto,
3420 VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
3421 i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
3422 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
3423 BlitBitmapMasked(bitmap, drawto,
3424 VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
3426 VX + VXSIZE - i, VY + VYSIZE / 2 + j);
3429 redraw_mask |= REDRAW_DOOR_2;
3430 door_2_done = (a == VXSIZE);
3433 if (!(door_state & DOOR_NO_DELAY))
3437 if (game_status == GAME_MODE_MAIN)
3440 WaitUntilDelayReached(&door_delay, door_delay_value);
3445 if (door_state & DOOR_ACTION_1)
3446 door1 = door_state & DOOR_ACTION_1;
3447 if (door_state & DOOR_ACTION_2)
3448 door2 = door_state & DOOR_ACTION_2;
3450 return (door1 | door2);
3453 void DrawSpecialEditorDoor()
3455 /* draw bigger toolbox window */
3456 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
3457 DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
3459 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
3460 EX - 6, VY - 4, EXSIZE + 12, EYSIZE - VYSIZE + 4,
3463 redraw_mask |= REDRAW_ALL;
3466 void UndrawSpecialEditorDoor()
3468 /* draw normal tape recorder window */
3469 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
3470 EX - 6, EY - 12, EXSIZE + 12, EYSIZE - VYSIZE + 12,
3473 redraw_mask |= REDRAW_ALL;
3477 /* ---------- new tool button stuff ---------------------------------------- */
3479 /* graphic position values for tool buttons */
3480 #define TOOL_BUTTON_YES_XPOS 2
3481 #define TOOL_BUTTON_YES_YPOS 250
3482 #define TOOL_BUTTON_YES_GFX_YPOS 0
3483 #define TOOL_BUTTON_YES_XSIZE 46
3484 #define TOOL_BUTTON_YES_YSIZE 28
3485 #define TOOL_BUTTON_NO_XPOS 52
3486 #define TOOL_BUTTON_NO_YPOS TOOL_BUTTON_YES_YPOS
3487 #define TOOL_BUTTON_NO_GFX_YPOS TOOL_BUTTON_YES_GFX_YPOS
3488 #define TOOL_BUTTON_NO_XSIZE TOOL_BUTTON_YES_XSIZE
3489 #define TOOL_BUTTON_NO_YSIZE TOOL_BUTTON_YES_YSIZE
3490 #define TOOL_BUTTON_CONFIRM_XPOS TOOL_BUTTON_YES_XPOS
3491 #define TOOL_BUTTON_CONFIRM_YPOS TOOL_BUTTON_YES_YPOS
3492 #define TOOL_BUTTON_CONFIRM_GFX_YPOS 30
3493 #define TOOL_BUTTON_CONFIRM_XSIZE 96
3494 #define TOOL_BUTTON_CONFIRM_YSIZE TOOL_BUTTON_YES_YSIZE
3495 #define TOOL_BUTTON_PLAYER_XSIZE 30
3496 #define TOOL_BUTTON_PLAYER_YSIZE 30
3497 #define TOOL_BUTTON_PLAYER_GFX_XPOS 5
3498 #define TOOL_BUTTON_PLAYER_GFX_YPOS 185
3499 #define TOOL_BUTTON_PLAYER_XPOS (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
3500 #define TOOL_BUTTON_PLAYER_YPOS (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
3501 #define TOOL_BUTTON_PLAYER1_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3502 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
3503 #define TOOL_BUTTON_PLAYER2_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3504 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
3505 #define TOOL_BUTTON_PLAYER3_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3506 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
3507 #define TOOL_BUTTON_PLAYER4_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3508 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
3509 #define TOOL_BUTTON_PLAYER1_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3510 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
3511 #define TOOL_BUTTON_PLAYER2_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3512 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
3513 #define TOOL_BUTTON_PLAYER3_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3514 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
3515 #define TOOL_BUTTON_PLAYER4_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3516 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
3525 } toolbutton_info[NUM_TOOL_BUTTONS] =
3528 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_GFX_YPOS,
3529 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_YPOS,
3530 TOOL_BUTTON_YES_XSIZE, TOOL_BUTTON_YES_YSIZE,
3535 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_GFX_YPOS,
3536 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_YPOS,
3537 TOOL_BUTTON_NO_XSIZE, TOOL_BUTTON_NO_YSIZE,
3542 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_GFX_YPOS,
3543 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_YPOS,
3544 TOOL_BUTTON_CONFIRM_XSIZE, TOOL_BUTTON_CONFIRM_YSIZE,
3545 TOOL_CTRL_ID_CONFIRM,
3549 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3550 TOOL_BUTTON_PLAYER1_XPOS, TOOL_BUTTON_PLAYER1_YPOS,
3551 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3552 TOOL_CTRL_ID_PLAYER_1,
3556 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3557 TOOL_BUTTON_PLAYER2_XPOS, TOOL_BUTTON_PLAYER2_YPOS,
3558 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3559 TOOL_CTRL_ID_PLAYER_2,
3563 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3564 TOOL_BUTTON_PLAYER3_XPOS, TOOL_BUTTON_PLAYER3_YPOS,
3565 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3566 TOOL_CTRL_ID_PLAYER_3,
3570 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3571 TOOL_BUTTON_PLAYER4_XPOS, TOOL_BUTTON_PLAYER4_YPOS,
3572 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3573 TOOL_CTRL_ID_PLAYER_4,
3578 void CreateToolButtons()
3582 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3584 Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
3585 Bitmap *deco_bitmap = None;
3586 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
3587 struct GadgetInfo *gi;
3588 unsigned long event_mask;
3589 int gd_xoffset, gd_yoffset;
3590 int gd_x1, gd_x2, gd_y;
3593 event_mask = GD_EVENT_RELEASED;
3595 gd_xoffset = toolbutton_info[i].xpos;
3596 gd_yoffset = toolbutton_info[i].ypos;
3597 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
3598 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
3599 gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
3601 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
3603 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
3605 getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr),
3606 &deco_bitmap, &deco_x, &deco_y);
3607 deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
3608 deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
3611 gi = CreateGadget(GDI_CUSTOM_ID, id,
3612 GDI_INFO_TEXT, toolbutton_info[i].infotext,
3613 GDI_X, DX + toolbutton_info[i].x,
3614 GDI_Y, DY + toolbutton_info[i].y,
3615 GDI_WIDTH, toolbutton_info[i].width,
3616 GDI_HEIGHT, toolbutton_info[i].height,
3617 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
3618 GDI_STATE, GD_BUTTON_UNPRESSED,
3619 GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
3620 GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
3621 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
3622 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
3623 GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
3624 GDI_DECORATION_SHIFTING, 1, 1,
3625 GDI_DIRECT_DRAW, FALSE,
3626 GDI_EVENT_MASK, event_mask,
3627 GDI_CALLBACK_ACTION, HandleToolButtons,
3631 Error(ERR_EXIT, "cannot create gadget");
3633 tool_gadget[id] = gi;
3637 void FreeToolButtons()
3641 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3642 FreeGadget(tool_gadget[i]);
3645 static void UnmapToolButtons()
3649 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3650 UnmapGadget(tool_gadget[i]);
3653 static void HandleToolButtons(struct GadgetInfo *gi)
3655 request_gadget_id = gi->custom_id;
3658 static struct Mapping_EM_to_RND_object
3661 boolean is_rnd_to_em_mapping; /* unique mapping EM <-> RND */
3662 boolean is_backside; /* backside of moving element */
3668 em_object_mapping_list[] =
3671 Xblank, TRUE, FALSE,
3675 Yacid_splash_eB, FALSE, FALSE,
3676 EL_ACID_SPLASH_RIGHT, -1, -1
3679 Yacid_splash_wB, FALSE, FALSE,
3680 EL_ACID_SPLASH_LEFT, -1, -1
3683 #ifdef EM_ENGINE_BAD_ROLL
3685 Xstone_force_e, FALSE, FALSE,
3686 EL_ROCK, -1, MV_BIT_RIGHT
3689 Xstone_force_w, FALSE, FALSE,
3690 EL_ROCK, -1, MV_BIT_LEFT
3693 Xnut_force_e, FALSE, FALSE,
3694 EL_NUT, -1, MV_BIT_RIGHT
3697 Xnut_force_w, FALSE, FALSE,
3698 EL_NUT, -1, MV_BIT_LEFT
3701 Xspring_force_e, FALSE, FALSE,
3702 EL_SPRING, -1, MV_BIT_RIGHT
3705 Xspring_force_w, FALSE, FALSE,
3706 EL_SPRING, -1, MV_BIT_LEFT
3709 Xemerald_force_e, FALSE, FALSE,
3710 EL_EMERALD, -1, MV_BIT_RIGHT
3713 Xemerald_force_w, FALSE, FALSE,
3714 EL_EMERALD, -1, MV_BIT_LEFT
3717 Xdiamond_force_e, FALSE, FALSE,
3718 EL_DIAMOND, -1, MV_BIT_RIGHT
3721 Xdiamond_force_w, FALSE, FALSE,
3722 EL_DIAMOND, -1, MV_BIT_LEFT
3725 Xbomb_force_e, FALSE, FALSE,
3726 EL_BOMB, -1, MV_BIT_RIGHT
3729 Xbomb_force_w, FALSE, FALSE,
3730 EL_BOMB, -1, MV_BIT_LEFT
3732 #endif /* EM_ENGINE_BAD_ROLL */
3735 Xstone, TRUE, FALSE,
3739 Xstone_pause, FALSE, FALSE,
3743 Xstone_fall, FALSE, FALSE,
3747 Ystone_s, FALSE, FALSE,
3748 EL_ROCK, ACTION_FALLING, -1
3751 Ystone_sB, FALSE, TRUE,
3752 EL_ROCK, ACTION_FALLING, -1
3755 Ystone_e, FALSE, FALSE,
3756 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
3759 Ystone_eB, FALSE, TRUE,
3760 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
3763 Ystone_w, FALSE, FALSE,
3764 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
3767 Ystone_wB, FALSE, TRUE,
3768 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
3775 Xnut_pause, FALSE, FALSE,
3779 Xnut_fall, FALSE, FALSE,
3783 Ynut_s, FALSE, FALSE,
3784 EL_NUT, ACTION_FALLING, -1
3787 Ynut_sB, FALSE, TRUE,
3788 EL_NUT, ACTION_FALLING, -1
3791 Ynut_e, FALSE, FALSE,
3792 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
3795 Ynut_eB, FALSE, TRUE,
3796 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
3799 Ynut_w, FALSE, FALSE,
3800 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
3803 Ynut_wB, FALSE, TRUE,
3804 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
3807 Xbug_n, TRUE, FALSE,
3811 Xbug_e, TRUE, FALSE,
3812 EL_BUG_RIGHT, -1, -1
3815 Xbug_s, TRUE, FALSE,
3819 Xbug_w, TRUE, FALSE,
3823 Xbug_gon, FALSE, FALSE,
3827 Xbug_goe, FALSE, FALSE,
3828 EL_BUG_RIGHT, -1, -1
3831 Xbug_gos, FALSE, FALSE,
3835 Xbug_gow, FALSE, FALSE,
3839 Ybug_n, FALSE, FALSE,
3840 EL_BUG, ACTION_MOVING, MV_BIT_UP
3843 Ybug_nB, FALSE, TRUE,
3844 EL_BUG, ACTION_MOVING, MV_BIT_UP
3847 Ybug_e, FALSE, FALSE,
3848 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
3851 Ybug_eB, FALSE, TRUE,
3852 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
3855 Ybug_s, FALSE, FALSE,
3856 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
3859 Ybug_sB, FALSE, TRUE,
3860 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
3863 Ybug_w, FALSE, FALSE,
3864 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
3867 Ybug_wB, FALSE, TRUE,
3868 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
3871 Ybug_w_n, FALSE, FALSE,
3872 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
3875 Ybug_n_e, FALSE, FALSE,
3876 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
3879 Ybug_e_s, FALSE, FALSE,
3880 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
3883 Ybug_s_w, FALSE, FALSE,
3884 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
3887 Ybug_e_n, FALSE, FALSE,
3888 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
3891 Ybug_s_e, FALSE, FALSE,
3892 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
3895 Ybug_w_s, FALSE, FALSE,
3896 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
3899 Ybug_n_w, FALSE, FALSE,
3900 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
3903 Ybug_stone, FALSE, FALSE,
3904 EL_BUG, ACTION_SMASHED_BY_ROCK, -1
3907 Ybug_spring, FALSE, FALSE,
3908 EL_BUG, ACTION_SMASHED_BY_SPRING, -1
3911 Xtank_n, TRUE, FALSE,
3912 EL_SPACESHIP_UP, -1, -1
3915 Xtank_e, TRUE, FALSE,
3916 EL_SPACESHIP_RIGHT, -1, -1
3919 Xtank_s, TRUE, FALSE,
3920 EL_SPACESHIP_DOWN, -1, -1
3923 Xtank_w, TRUE, FALSE,
3924 EL_SPACESHIP_LEFT, -1, -1
3927 Xtank_gon, FALSE, FALSE,
3928 EL_SPACESHIP_UP, -1, -1
3931 Xtank_goe, FALSE, FALSE,
3932 EL_SPACESHIP_RIGHT, -1, -1
3935 Xtank_gos, FALSE, FALSE,
3936 EL_SPACESHIP_DOWN, -1, -1
3939 Xtank_gow, FALSE, FALSE,
3940 EL_SPACESHIP_LEFT, -1, -1
3943 Ytank_n, FALSE, FALSE,
3944 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
3947 Ytank_nB, FALSE, TRUE,
3948 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
3951 Ytank_e, FALSE, FALSE,
3952 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
3955 Ytank_eB, FALSE, TRUE,
3956 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
3959 Ytank_s, FALSE, FALSE,
3960 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
3963 Ytank_sB, FALSE, TRUE,
3964 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
3967 Ytank_w, FALSE, FALSE,
3968 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
3971 Ytank_wB, FALSE, TRUE,
3972 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
3975 Ytank_w_n, FALSE, FALSE,
3976 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
3979 Ytank_n_e, FALSE, FALSE,
3980 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
3983 Ytank_e_s, FALSE, FALSE,
3984 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
3987 Ytank_s_w, FALSE, FALSE,
3988 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
3991 Ytank_e_n, FALSE, FALSE,
3992 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
3995 Ytank_s_e, FALSE, FALSE,
3996 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
3999 Ytank_w_s, FALSE, FALSE,
4000 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
4003 Ytank_n_w, FALSE, FALSE,
4004 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
4007 Ytank_stone, FALSE, FALSE,
4008 EL_SPACESHIP, ACTION_SMASHED_BY_ROCK, -1
4011 Ytank_spring, FALSE, FALSE,
4012 EL_SPACESHIP, ACTION_SMASHED_BY_SPRING, -1
4015 Xandroid, TRUE, FALSE,
4016 EL_EMC_ANDROID, ACTION_ACTIVE, -1
4019 Xandroid_1_n, FALSE, FALSE,
4020 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
4023 Xandroid_2_n, FALSE, FALSE,
4024 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
4027 Xandroid_1_e, FALSE, FALSE,
4028 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
4031 Xandroid_2_e, FALSE, FALSE,
4032 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
4035 Xandroid_1_w, FALSE, FALSE,
4036 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
4039 Xandroid_2_w, FALSE, FALSE,
4040 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
4043 Xandroid_1_s, FALSE, FALSE,
4044 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
4047 Xandroid_2_s, FALSE, FALSE,
4048 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
4051 Yandroid_n, FALSE, FALSE,
4052 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
4055 Yandroid_nB, FALSE, TRUE,
4056 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
4059 Yandroid_ne, FALSE, FALSE,
4060 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPRIGHT
4063 Yandroid_neB, FALSE, TRUE,
4064 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPRIGHT
4067 Yandroid_e, FALSE, FALSE,
4068 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
4071 Yandroid_eB, FALSE, TRUE,
4072 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
4075 Yandroid_se, FALSE, FALSE,
4076 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNRIGHT
4079 Yandroid_seB, FALSE, TRUE,
4080 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNRIGHT
4083 Yandroid_s, FALSE, FALSE,
4084 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
4087 Yandroid_sB, FALSE, TRUE,
4088 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
4091 Yandroid_sw, FALSE, FALSE,
4092 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNLEFT
4095 Yandroid_swB, FALSE, TRUE,
4096 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNLEFT
4099 Yandroid_w, FALSE, FALSE,
4100 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
4103 Yandroid_wB, FALSE, TRUE,
4104 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
4107 Yandroid_nw, FALSE, FALSE,
4108 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPLEFT
4111 Yandroid_nwB, FALSE, TRUE,
4112 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPLEFT
4115 Xspring, TRUE, FALSE,
4119 Xspring_pause, FALSE, FALSE,
4123 Xspring_e, FALSE, FALSE,
4127 Xspring_w, FALSE, FALSE,
4131 Xspring_fall, FALSE, FALSE,
4135 Yspring_s, FALSE, FALSE,
4136 EL_SPRING, ACTION_FALLING, -1
4139 Yspring_sB, FALSE, TRUE,
4140 EL_SPRING, ACTION_FALLING, -1
4143 Yspring_e, FALSE, FALSE,
4144 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
4147 Yspring_eB, FALSE, TRUE,
4148 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
4151 Yspring_w, FALSE, FALSE,
4152 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
4155 Yspring_wB, FALSE, TRUE,
4156 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
4159 Yspring_kill_e, FALSE, FALSE,
4160 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
4163 Yspring_kill_eB, FALSE, TRUE,
4164 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
4167 Yspring_kill_w, FALSE, FALSE,
4168 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
4171 Yspring_kill_wB, FALSE, TRUE,
4172 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
4175 Xeater_n, TRUE, FALSE,
4176 EL_YAMYAM_UP, -1, -1
4179 Xeater_e, TRUE, FALSE,
4180 EL_YAMYAM_RIGHT, -1, -1
4183 Xeater_w, TRUE, FALSE,
4184 EL_YAMYAM_LEFT, -1, -1
4187 Xeater_s, TRUE, FALSE,
4188 EL_YAMYAM_DOWN, -1, -1
4191 Yeater_n, FALSE, FALSE,
4192 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
4195 Yeater_nB, FALSE, TRUE,
4196 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
4199 Yeater_e, FALSE, FALSE,
4200 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
4203 Yeater_eB, FALSE, TRUE,
4204 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
4207 Yeater_s, FALSE, FALSE,
4208 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
4211 Yeater_sB, FALSE, TRUE,
4212 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
4215 Yeater_w, FALSE, FALSE,
4216 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
4219 Yeater_wB, FALSE, TRUE,
4220 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
4223 Yeater_stone, FALSE, FALSE,
4224 EL_YAMYAM, ACTION_SMASHED_BY_ROCK, -1
4227 Yeater_spring, FALSE, FALSE,
4228 EL_YAMYAM, ACTION_SMASHED_BY_SPRING, -1
4231 Xalien, TRUE, FALSE,
4235 Xalien_pause, FALSE, FALSE,
4239 Yalien_n, FALSE, FALSE,
4240 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
4243 Yalien_nB, FALSE, TRUE,
4244 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
4247 Yalien_e, FALSE, FALSE,
4248 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
4251 Yalien_eB, FALSE, TRUE,
4252 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
4255 Yalien_s, FALSE, FALSE,
4256 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
4259 Yalien_sB, FALSE, TRUE,
4260 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
4263 Yalien_w, FALSE, FALSE,
4264 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
4267 Yalien_wB, FALSE, TRUE,
4268 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
4271 Yalien_stone, FALSE, FALSE,
4272 EL_ROBOT, ACTION_SMASHED_BY_ROCK, -1
4275 Yalien_spring, FALSE, FALSE,
4276 EL_ROBOT, ACTION_SMASHED_BY_SPRING, -1
4279 Xemerald, TRUE, FALSE,
4283 Xemerald_pause, FALSE, FALSE,
4287 Xemerald_fall, FALSE, FALSE,
4291 Xemerald_shine, FALSE, FALSE,
4292 EL_EMERALD, ACTION_TWINKLING, -1
4295 Yemerald_s, FALSE, FALSE,
4296 EL_EMERALD, ACTION_FALLING, -1
4299 Yemerald_sB, FALSE, TRUE,
4300 EL_EMERALD, ACTION_FALLING, -1
4303 Yemerald_e, FALSE, FALSE,
4304 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
4307 Yemerald_eB, FALSE, TRUE,
4308 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
4311 Yemerald_w, FALSE, FALSE,
4312 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
4315 Yemerald_wB, FALSE, TRUE,
4316 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
4319 Yemerald_eat, FALSE, FALSE,
4320 EL_EMERALD, ACTION_COLLECTING, -1
4323 Yemerald_stone, FALSE, FALSE,
4324 EL_NUT, ACTION_BREAKING, -1
4327 Xdiamond, TRUE, FALSE,
4331 Xdiamond_pause, FALSE, FALSE,
4335 Xdiamond_fall, FALSE, FALSE,
4339 Xdiamond_shine, FALSE, FALSE,
4340 EL_DIAMOND, ACTION_TWINKLING, -1
4343 Ydiamond_s, FALSE, FALSE,
4344 EL_DIAMOND, ACTION_FALLING, -1
4347 Ydiamond_sB, FALSE, TRUE,
4348 EL_DIAMOND, ACTION_FALLING, -1
4351 Ydiamond_e, FALSE, FALSE,
4352 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
4355 Ydiamond_eB, FALSE, TRUE,
4356 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
4359 Ydiamond_w, FALSE, FALSE,
4360 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
4363 Ydiamond_wB, FALSE, TRUE,
4364 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
4367 Ydiamond_eat, FALSE, FALSE,
4368 EL_DIAMOND, ACTION_COLLECTING, -1
4371 Ydiamond_stone, FALSE, FALSE,
4372 EL_DIAMOND, ACTION_SMASHED_BY_ROCK, -1
4375 Xdrip_fall, TRUE, FALSE,
4376 EL_AMOEBA_DROP, -1, -1
4379 Xdrip_stretch, FALSE, FALSE,
4380 EL_AMOEBA_DROP, ACTION_FALLING, -1
4383 Xdrip_stretchB, FALSE, TRUE,
4384 EL_AMOEBA_DROP, ACTION_FALLING, -1
4387 Xdrip_eat, FALSE, FALSE,
4388 EL_AMOEBA_DROP, ACTION_GROWING, -1
4391 Ydrip_s1, FALSE, FALSE,
4392 EL_AMOEBA_DROP, ACTION_FALLING, -1
4395 Ydrip_s1B, FALSE, TRUE,
4396 EL_AMOEBA_DROP, ACTION_FALLING, -1
4399 Ydrip_s2, FALSE, FALSE,
4400 EL_AMOEBA_DROP, ACTION_FALLING, -1
4403 Ydrip_s2B, FALSE, TRUE,
4404 EL_AMOEBA_DROP, ACTION_FALLING, -1
4411 Xbomb_pause, FALSE, FALSE,
4415 Xbomb_fall, FALSE, FALSE,
4419 Ybomb_s, FALSE, FALSE,
4420 EL_BOMB, ACTION_FALLING, -1
4423 Ybomb_sB, FALSE, TRUE,
4424 EL_BOMB, ACTION_FALLING, -1
4427 Ybomb_e, FALSE, FALSE,
4428 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
4431 Ybomb_eB, FALSE, TRUE,
4432 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
4435 Ybomb_w, FALSE, FALSE,
4436 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
4439 Ybomb_wB, FALSE, TRUE,
4440 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
4443 Ybomb_eat, FALSE, FALSE,
4444 EL_BOMB, ACTION_ACTIVATING, -1
4447 Xballoon, TRUE, FALSE,
4451 Yballoon_n, FALSE, FALSE,
4452 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
4455 Yballoon_nB, FALSE, TRUE,
4456 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
4459 Yballoon_e, FALSE, FALSE,
4460 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
4463 Yballoon_eB, FALSE, TRUE,
4464 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
4467 Yballoon_s, FALSE, FALSE,
4468 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
4471 Yballoon_sB, FALSE, TRUE,
4472 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
4475 Yballoon_w, FALSE, FALSE,
4476 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
4479 Yballoon_wB, FALSE, TRUE,
4480 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
4483 Xgrass, TRUE, FALSE,
4484 EL_EMC_GRASS, -1, -1
4487 Ygrass_nB, FALSE, FALSE,
4488 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_UP
4491 Ygrass_eB, FALSE, FALSE,
4492 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_RIGHT
4495 Ygrass_sB, FALSE, FALSE,
4496 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_DOWN
4499 Ygrass_wB, FALSE, FALSE,
4500 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_LEFT
4507 Ydirt_nB, FALSE, FALSE,
4508 EL_SAND, ACTION_DIGGING, MV_BIT_UP
4511 Ydirt_eB, FALSE, FALSE,
4512 EL_SAND, ACTION_DIGGING, MV_BIT_RIGHT
4515 Ydirt_sB, FALSE, FALSE,
4516 EL_SAND, ACTION_DIGGING, MV_BIT_DOWN
4519 Ydirt_wB, FALSE, FALSE,
4520 EL_SAND, ACTION_DIGGING, MV_BIT_LEFT
4523 Xacid_ne, TRUE, FALSE,
4524 EL_ACID_POOL_TOPRIGHT, -1, -1
4527 Xacid_se, TRUE, FALSE,
4528 EL_ACID_POOL_BOTTOMRIGHT, -1, -1
4531 Xacid_s, TRUE, FALSE,
4532 EL_ACID_POOL_BOTTOM, -1, -1
4535 Xacid_sw, TRUE, FALSE,
4536 EL_ACID_POOL_BOTTOMLEFT, -1, -1
4539 Xacid_nw, TRUE, FALSE,
4540 EL_ACID_POOL_TOPLEFT, -1, -1
4543 Xacid_1, TRUE, FALSE,
4547 Xacid_2, FALSE, FALSE,
4551 Xacid_3, FALSE, FALSE,
4555 Xacid_4, FALSE, FALSE,
4559 Xacid_5, FALSE, FALSE,
4563 Xacid_6, FALSE, FALSE,
4567 Xacid_7, FALSE, FALSE,
4571 Xacid_8, FALSE, FALSE,
4575 Xball_1, TRUE, FALSE,
4576 EL_EMC_MAGIC_BALL, -1, -1
4579 Xball_1B, FALSE, FALSE,
4580 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4583 Xball_2, FALSE, FALSE,
4584 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4587 Xball_2B, FALSE, FALSE,
4588 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4591 Yball_eat, FALSE, FALSE,
4592 EL_EMC_MAGIC_BALL, ACTION_DROPPING, -1
4595 Ykey_1_eat, FALSE, FALSE,
4596 EL_EM_KEY_1, ACTION_COLLECTING, -1
4599 Ykey_2_eat, FALSE, FALSE,
4600 EL_EM_KEY_2, ACTION_COLLECTING, -1
4603 Ykey_3_eat, FALSE, FALSE,
4604 EL_EM_KEY_3, ACTION_COLLECTING, -1
4607 Ykey_4_eat, FALSE, FALSE,
4608 EL_EM_KEY_4, ACTION_COLLECTING, -1
4611 Ykey_5_eat, FALSE, FALSE,
4612 EL_EMC_KEY_5, ACTION_COLLECTING, -1
4615 Ykey_6_eat, FALSE, FALSE,
4616 EL_EMC_KEY_6, ACTION_COLLECTING, -1
4619 Ykey_7_eat, FALSE, FALSE,
4620 EL_EMC_KEY_7, ACTION_COLLECTING, -1
4623 Ykey_8_eat, FALSE, FALSE,
4624 EL_EMC_KEY_8, ACTION_COLLECTING, -1
4627 Ylenses_eat, FALSE, FALSE,
4628 EL_EMC_LENSES, ACTION_COLLECTING, -1
4631 Ymagnify_eat, FALSE, FALSE,
4632 EL_EMC_MAGNIFIER, ACTION_COLLECTING, -1
4635 Ygrass_eat, FALSE, FALSE,
4636 EL_EMC_GRASS, ACTION_SNAPPING, -1
4639 Ydirt_eat, FALSE, FALSE,
4640 EL_SAND, ACTION_SNAPPING, -1
4643 Xgrow_ns, TRUE, FALSE,
4644 EL_EXPANDABLE_WALL_VERTICAL, -1, -1
4647 Ygrow_ns_eat, FALSE, FALSE,
4648 EL_EXPANDABLE_WALL_VERTICAL, ACTION_GROWING, -1
4651 Xgrow_ew, TRUE, FALSE,
4652 EL_EXPANDABLE_WALL_HORIZONTAL, -1, -1
4655 Ygrow_ew_eat, FALSE, FALSE,
4656 EL_EXPANDABLE_WALL_HORIZONTAL, ACTION_GROWING, -1
4659 Xwonderwall, TRUE, FALSE,
4660 EL_MAGIC_WALL, -1, -1
4663 XwonderwallB, FALSE, FALSE,
4664 EL_MAGIC_WALL, ACTION_ACTIVE, -1
4667 Xamoeba_1, TRUE, FALSE,
4668 EL_AMOEBA_DRY, ACTION_OTHER, -1
4671 Xamoeba_2, FALSE, FALSE,
4672 EL_AMOEBA_DRY, ACTION_OTHER, -1
4675 Xamoeba_3, FALSE, FALSE,
4676 EL_AMOEBA_DRY, ACTION_OTHER, -1
4679 Xamoeba_4, FALSE, FALSE,
4680 EL_AMOEBA_DRY, ACTION_OTHER, -1
4683 Xamoeba_5, TRUE, FALSE,
4684 EL_AMOEBA_WET, ACTION_OTHER, -1
4687 Xamoeba_6, FALSE, FALSE,
4688 EL_AMOEBA_WET, ACTION_OTHER, -1
4691 Xamoeba_7, FALSE, FALSE,
4692 EL_AMOEBA_WET, ACTION_OTHER, -1
4695 Xamoeba_8, FALSE, FALSE,
4696 EL_AMOEBA_WET, ACTION_OTHER, -1
4699 Xdoor_1, TRUE, FALSE,
4700 EL_EM_GATE_1, -1, -1
4703 Xdoor_2, TRUE, FALSE,
4704 EL_EM_GATE_2, -1, -1
4707 Xdoor_3, TRUE, FALSE,
4708 EL_EM_GATE_3, -1, -1
4711 Xdoor_4, TRUE, FALSE,
4712 EL_EM_GATE_4, -1, -1
4715 Xdoor_5, TRUE, FALSE,
4716 EL_EMC_GATE_5, -1, -1
4719 Xdoor_6, TRUE, FALSE,
4720 EL_EMC_GATE_6, -1, -1
4723 Xdoor_7, TRUE, FALSE,
4724 EL_EMC_GATE_7, -1, -1
4727 Xdoor_8, TRUE, FALSE,
4728 EL_EMC_GATE_8, -1, -1
4731 Xkey_1, TRUE, FALSE,
4735 Xkey_2, TRUE, FALSE,
4739 Xkey_3, TRUE, FALSE,
4743 Xkey_4, TRUE, FALSE,
4747 Xkey_5, TRUE, FALSE,
4748 EL_EMC_KEY_5, -1, -1
4751 Xkey_6, TRUE, FALSE,
4752 EL_EMC_KEY_6, -1, -1
4755 Xkey_7, TRUE, FALSE,
4756 EL_EMC_KEY_7, -1, -1
4759 Xkey_8, TRUE, FALSE,
4760 EL_EMC_KEY_8, -1, -1
4763 Xwind_n, TRUE, FALSE,
4764 EL_BALLOON_SWITCH_UP, -1, -1
4767 Xwind_e, TRUE, FALSE,
4768 EL_BALLOON_SWITCH_RIGHT, -1, -1
4771 Xwind_s, TRUE, FALSE,
4772 EL_BALLOON_SWITCH_DOWN, -1, -1
4775 Xwind_w, TRUE, FALSE,
4776 EL_BALLOON_SWITCH_LEFT, -1, -1
4779 Xwind_nesw, TRUE, FALSE,
4780 EL_BALLOON_SWITCH_ANY, -1, -1
4783 Xwind_stop, TRUE, FALSE,
4784 EL_BALLOON_SWITCH_NONE, -1, -1
4788 EL_EM_EXIT_CLOSED, -1, -1
4791 Xexit_1, TRUE, FALSE,
4792 EL_EM_EXIT_OPEN, -1, -1
4795 Xexit_2, FALSE, FALSE,
4796 EL_EM_EXIT_OPEN, -1, -1
4799 Xexit_3, FALSE, FALSE,
4800 EL_EM_EXIT_OPEN, -1, -1
4803 Xdynamite, TRUE, FALSE,
4804 EL_EM_DYNAMITE, -1, -1
4807 Ydynamite_eat, FALSE, FALSE,
4808 EL_EM_DYNAMITE, ACTION_COLLECTING, -1
4811 Xdynamite_1, TRUE, FALSE,
4812 EL_EM_DYNAMITE_ACTIVE, -1, -1
4815 Xdynamite_2, FALSE, FALSE,
4816 EL_EM_DYNAMITE_ACTIVE, -1, -1
4819 Xdynamite_3, FALSE, FALSE,
4820 EL_EM_DYNAMITE_ACTIVE, -1, -1
4823 Xdynamite_4, FALSE, FALSE,
4824 EL_EM_DYNAMITE_ACTIVE, -1, -1
4827 Xbumper, TRUE, FALSE,
4828 EL_EMC_SPRING_BUMPER, -1, -1
4831 XbumperB, FALSE, FALSE,
4832 EL_EMC_SPRING_BUMPER, ACTION_ACTIVE, -1
4835 Xwheel, TRUE, FALSE,
4836 EL_ROBOT_WHEEL, -1, -1
4839 XwheelB, FALSE, FALSE,
4840 EL_ROBOT_WHEEL, ACTION_ACTIVE, -1
4843 Xswitch, TRUE, FALSE,
4844 EL_EMC_MAGIC_BALL_SWITCH, -1, -1
4847 XswitchB, FALSE, FALSE,
4848 EL_EMC_MAGIC_BALL_SWITCH, ACTION_ACTIVE, -1
4852 EL_QUICKSAND_EMPTY, -1, -1
4855 Xsand_stone, TRUE, FALSE,
4856 EL_QUICKSAND_FULL, -1, -1
4859 Xsand_stonein_1, FALSE, TRUE,
4860 EL_ROCK, ACTION_FILLING, -1
4863 Xsand_stonein_2, FALSE, TRUE,
4864 EL_ROCK, ACTION_FILLING, -1
4867 Xsand_stonein_3, FALSE, TRUE,
4868 EL_ROCK, ACTION_FILLING, -1
4871 Xsand_stonein_4, FALSE, TRUE,
4872 EL_ROCK, ACTION_FILLING, -1
4876 Xsand_stonesand_1, FALSE, FALSE,
4877 EL_QUICKSAND_EMPTYING, -1, -1
4880 Xsand_stonesand_2, FALSE, FALSE,
4881 EL_QUICKSAND_EMPTYING, -1, -1
4884 Xsand_stonesand_3, FALSE, FALSE,
4885 EL_QUICKSAND_EMPTYING, -1, -1
4888 Xsand_stonesand_4, FALSE, FALSE,
4889 EL_QUICKSAND_EMPTYING, -1, -1
4892 Xsand_stonesand_quickout_1, FALSE, FALSE,
4893 EL_QUICKSAND_EMPTYING, -1, -1
4896 Xsand_stonesand_quickout_2, FALSE, FALSE,
4897 EL_QUICKSAND_EMPTYING, -1, -1
4901 Xsand_stonesand_1, FALSE, FALSE,
4902 EL_QUICKSAND_FULL, -1, -1
4905 Xsand_stonesand_2, FALSE, FALSE,
4906 EL_QUICKSAND_FULL, -1, -1
4909 Xsand_stonesand_3, FALSE, FALSE,
4910 EL_QUICKSAND_FULL, -1, -1
4913 Xsand_stonesand_4, FALSE, FALSE,
4914 EL_QUICKSAND_FULL, -1, -1
4918 Xsand_stoneout_1, FALSE, FALSE,
4919 EL_ROCK, ACTION_EMPTYING, -1
4922 Xsand_stoneout_2, FALSE, FALSE,
4923 EL_ROCK, ACTION_EMPTYING, -1
4927 Xsand_sandstone_1, FALSE, FALSE,
4928 EL_QUICKSAND_FILLING, -1, -1
4931 Xsand_sandstone_2, FALSE, FALSE,
4932 EL_QUICKSAND_FILLING, -1, -1
4935 Xsand_sandstone_3, FALSE, FALSE,
4936 EL_QUICKSAND_FILLING, -1, -1
4939 Xsand_sandstone_4, FALSE, FALSE,
4940 EL_QUICKSAND_FILLING, -1, -1
4944 Xsand_sandstone_1, FALSE, FALSE,
4945 EL_QUICKSAND_FULL, -1, -1
4948 Xsand_sandstone_2, FALSE, FALSE,
4949 EL_QUICKSAND_FULL, -1, -1
4952 Xsand_sandstone_3, FALSE, FALSE,
4953 EL_QUICKSAND_FULL, -1, -1
4956 Xsand_sandstone_4, FALSE, FALSE,
4957 EL_QUICKSAND_FULL, -1, -1
4961 Xplant, TRUE, FALSE,
4962 EL_EMC_PLANT, -1, -1
4965 Yplant, FALSE, FALSE,
4966 EL_EMC_PLANT, -1, -1
4969 Xlenses, TRUE, FALSE,
4970 EL_EMC_LENSES, -1, -1
4973 Xmagnify, TRUE, FALSE,
4974 EL_EMC_MAGNIFIER, -1, -1
4977 Xdripper, TRUE, FALSE,
4978 EL_EMC_DRIPPER, -1, -1
4981 XdripperB, FALSE, FALSE,
4982 EL_EMC_DRIPPER, ACTION_ACTIVE, -1
4985 Xfake_blank, TRUE, FALSE,
4986 EL_INVISIBLE_WALL, -1, -1
4989 Xfake_blankB, FALSE, FALSE,
4990 EL_INVISIBLE_WALL, ACTION_ACTIVE, -1
4993 Xfake_grass, TRUE, FALSE,
4994 EL_EMC_FAKE_GRASS, -1, -1
4997 Xfake_grassB, FALSE, FALSE,
4998 EL_EMC_FAKE_GRASS, ACTION_ACTIVE, -1
5001 Xfake_door_1, TRUE, FALSE,
5002 EL_EM_GATE_1_GRAY, -1, -1
5005 Xfake_door_2, TRUE, FALSE,
5006 EL_EM_GATE_2_GRAY, -1, -1
5009 Xfake_door_3, TRUE, FALSE,
5010 EL_EM_GATE_3_GRAY, -1, -1
5013 Xfake_door_4, TRUE, FALSE,
5014 EL_EM_GATE_4_GRAY, -1, -1
5017 Xfake_door_5, TRUE, FALSE,
5018 EL_EMC_GATE_5_GRAY, -1, -1
5021 Xfake_door_6, TRUE, FALSE,
5022 EL_EMC_GATE_6_GRAY, -1, -1
5025 Xfake_door_7, TRUE, FALSE,
5026 EL_EMC_GATE_7_GRAY, -1, -1
5029 Xfake_door_8, TRUE, FALSE,
5030 EL_EMC_GATE_8_GRAY, -1, -1
5033 Xfake_acid_1, TRUE, FALSE,
5034 EL_EMC_FAKE_ACID, -1, -1
5037 Xfake_acid_2, FALSE, FALSE,
5038 EL_EMC_FAKE_ACID, -1, -1
5041 Xfake_acid_3, FALSE, FALSE,
5042 EL_EMC_FAKE_ACID, -1, -1
5045 Xfake_acid_4, FALSE, FALSE,
5046 EL_EMC_FAKE_ACID, -1, -1
5049 Xfake_acid_5, FALSE, FALSE,
5050 EL_EMC_FAKE_ACID, -1, -1
5053 Xfake_acid_6, FALSE, FALSE,
5054 EL_EMC_FAKE_ACID, -1, -1
5057 Xfake_acid_7, FALSE, FALSE,
5058 EL_EMC_FAKE_ACID, -1, -1
5061 Xfake_acid_8, FALSE, FALSE,
5062 EL_EMC_FAKE_ACID, -1, -1
5065 Xsteel_1, TRUE, FALSE,
5066 EL_STEELWALL, -1, -1
5069 Xsteel_2, TRUE, FALSE,
5070 EL_EMC_STEELWALL_2, -1, -1
5073 Xsteel_3, TRUE, FALSE,
5074 EL_EMC_STEELWALL_3, -1, -1
5077 Xsteel_4, TRUE, FALSE,
5078 EL_EMC_STEELWALL_4, -1, -1
5081 Xwall_1, TRUE, FALSE,
5085 Xwall_2, TRUE, FALSE,
5086 EL_EMC_WALL_14, -1, -1
5089 Xwall_3, TRUE, FALSE,
5090 EL_EMC_WALL_15, -1, -1
5093 Xwall_4, TRUE, FALSE,
5094 EL_EMC_WALL_16, -1, -1
5097 Xround_wall_1, TRUE, FALSE,
5098 EL_WALL_SLIPPERY, -1, -1
5101 Xround_wall_2, TRUE, FALSE,
5102 EL_EMC_WALL_SLIPPERY_2, -1, -1
5105 Xround_wall_3, TRUE, FALSE,
5106 EL_EMC_WALL_SLIPPERY_3, -1, -1
5109 Xround_wall_4, TRUE, FALSE,
5110 EL_EMC_WALL_SLIPPERY_4, -1, -1
5113 Xdecor_1, TRUE, FALSE,
5114 EL_EMC_WALL_8, -1, -1
5117 Xdecor_2, TRUE, FALSE,
5118 EL_EMC_WALL_6, -1, -1
5121 Xdecor_3, TRUE, FALSE,
5122 EL_EMC_WALL_4, -1, -1
5125 Xdecor_4, TRUE, FALSE,
5126 EL_EMC_WALL_7, -1, -1
5129 Xdecor_5, TRUE, FALSE,
5130 EL_EMC_WALL_5, -1, -1
5133 Xdecor_6, TRUE, FALSE,
5134 EL_EMC_WALL_9, -1, -1
5137 Xdecor_7, TRUE, FALSE,
5138 EL_EMC_WALL_10, -1, -1
5141 Xdecor_8, TRUE, FALSE,
5142 EL_EMC_WALL_1, -1, -1
5145 Xdecor_9, TRUE, FALSE,
5146 EL_EMC_WALL_2, -1, -1
5149 Xdecor_10, TRUE, FALSE,
5150 EL_EMC_WALL_3, -1, -1
5153 Xdecor_11, TRUE, FALSE,
5154 EL_EMC_WALL_11, -1, -1
5157 Xdecor_12, TRUE, FALSE,
5158 EL_EMC_WALL_12, -1, -1
5161 Xalpha_0, TRUE, FALSE,
5162 EL_CHAR('0'), -1, -1
5165 Xalpha_1, TRUE, FALSE,
5166 EL_CHAR('1'), -1, -1
5169 Xalpha_2, TRUE, FALSE,
5170 EL_CHAR('2'), -1, -1
5173 Xalpha_3, TRUE, FALSE,
5174 EL_CHAR('3'), -1, -1
5177 Xalpha_4, TRUE, FALSE,
5178 EL_CHAR('4'), -1, -1
5181 Xalpha_5, TRUE, FALSE,
5182 EL_CHAR('5'), -1, -1
5185 Xalpha_6, TRUE, FALSE,
5186 EL_CHAR('6'), -1, -1
5189 Xalpha_7, TRUE, FALSE,
5190 EL_CHAR('7'), -1, -1
5193 Xalpha_8, TRUE, FALSE,
5194 EL_CHAR('8'), -1, -1
5197 Xalpha_9, TRUE, FALSE,
5198 EL_CHAR('9'), -1, -1
5201 Xalpha_excla, TRUE, FALSE,
5202 EL_CHAR('!'), -1, -1
5205 Xalpha_quote, TRUE, FALSE,
5206 EL_CHAR('"'), -1, -1
5209 Xalpha_comma, TRUE, FALSE,
5210 EL_CHAR(','), -1, -1
5213 Xalpha_minus, TRUE, FALSE,
5214 EL_CHAR('-'), -1, -1
5217 Xalpha_perio, TRUE, FALSE,
5218 EL_CHAR('.'), -1, -1
5221 Xalpha_colon, TRUE, FALSE,
5222 EL_CHAR(':'), -1, -1
5225 Xalpha_quest, TRUE, FALSE,
5226 EL_CHAR('?'), -1, -1
5229 Xalpha_a, TRUE, FALSE,
5230 EL_CHAR('A'), -1, -1
5233 Xalpha_b, TRUE, FALSE,
5234 EL_CHAR('B'), -1, -1
5237 Xalpha_c, TRUE, FALSE,
5238 EL_CHAR('C'), -1, -1
5241 Xalpha_d, TRUE, FALSE,
5242 EL_CHAR('D'), -1, -1
5245 Xalpha_e, TRUE, FALSE,
5246 EL_CHAR('E'), -1, -1
5249 Xalpha_f, TRUE, FALSE,
5250 EL_CHAR('F'), -1, -1
5253 Xalpha_g, TRUE, FALSE,
5254 EL_CHAR('G'), -1, -1
5257 Xalpha_h, TRUE, FALSE,
5258 EL_CHAR('H'), -1, -1
5261 Xalpha_i, TRUE, FALSE,
5262 EL_CHAR('I'), -1, -1
5265 Xalpha_j, TRUE, FALSE,
5266 EL_CHAR('J'), -1, -1
5269 Xalpha_k, TRUE, FALSE,
5270 EL_CHAR('K'), -1, -1
5273 Xalpha_l, TRUE, FALSE,
5274 EL_CHAR('L'), -1, -1
5277 Xalpha_m, TRUE, FALSE,
5278 EL_CHAR('M'), -1, -1
5281 Xalpha_n, TRUE, FALSE,
5282 EL_CHAR('N'), -1, -1
5285 Xalpha_o, TRUE, FALSE,
5286 EL_CHAR('O'), -1, -1
5289 Xalpha_p, TRUE, FALSE,
5290 EL_CHAR('P'), -1, -1
5293 Xalpha_q, TRUE, FALSE,
5294 EL_CHAR('Q'), -1, -1
5297 Xalpha_r, TRUE, FALSE,
5298 EL_CHAR('R'), -1, -1
5301 Xalpha_s, TRUE, FALSE,
5302 EL_CHAR('S'), -1, -1
5305 Xalpha_t, TRUE, FALSE,
5306 EL_CHAR('T'), -1, -1
5309 Xalpha_u, TRUE, FALSE,
5310 EL_CHAR('U'), -1, -1
5313 Xalpha_v, TRUE, FALSE,
5314 EL_CHAR('V'), -1, -1
5317 Xalpha_w, TRUE, FALSE,
5318 EL_CHAR('W'), -1, -1
5321 Xalpha_x, TRUE, FALSE,
5322 EL_CHAR('X'), -1, -1
5325 Xalpha_y, TRUE, FALSE,
5326 EL_CHAR('Y'), -1, -1
5329 Xalpha_z, TRUE, FALSE,
5330 EL_CHAR('Z'), -1, -1
5333 Xalpha_arrow_e, TRUE, FALSE,
5334 EL_CHAR('>'), -1, -1
5337 Xalpha_arrow_w, TRUE, FALSE,
5338 EL_CHAR('<'), -1, -1
5341 Xalpha_copyr, TRUE, FALSE,
5342 EL_CHAR('©'), -1, -1
5346 Xboom_bug, FALSE, FALSE,
5347 EL_BUG, ACTION_EXPLODING, -1
5350 Xboom_bomb, FALSE, FALSE,
5351 EL_BOMB, ACTION_EXPLODING, -1
5354 Xboom_android, FALSE, FALSE,
5355 EL_EMC_ANDROID, ACTION_OTHER, -1
5358 Xboom_1, FALSE, FALSE,
5359 EL_DEFAULT, ACTION_EXPLODING, -1
5362 Xboom_2, FALSE, FALSE,
5363 EL_DEFAULT, ACTION_EXPLODING, -1
5366 Znormal, FALSE, FALSE,
5370 Zdynamite, FALSE, FALSE,
5374 Zplayer, FALSE, FALSE,
5378 ZBORDER, FALSE, FALSE,
5388 static struct Mapping_EM_to_RND_player
5397 em_player_mapping_list[] =
5401 EL_PLAYER_1, ACTION_MOVING, MV_BIT_UP,
5405 EL_PLAYER_1, ACTION_MOVING, MV_BIT_RIGHT,
5409 EL_PLAYER_1, ACTION_MOVING, MV_BIT_DOWN,
5413 EL_PLAYER_1, ACTION_MOVING, MV_BIT_LEFT,
5417 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_UP,
5421 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_RIGHT,
5425 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_DOWN,
5429 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_LEFT,
5433 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_UP,
5437 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_RIGHT,
5441 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_DOWN,
5445 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_LEFT,
5449 EL_PLAYER_2, ACTION_MOVING, MV_BIT_UP,
5453 EL_PLAYER_2, ACTION_MOVING, MV_BIT_RIGHT,
5457 EL_PLAYER_2, ACTION_MOVING, MV_BIT_DOWN,
5461 EL_PLAYER_2, ACTION_MOVING, MV_BIT_LEFT,
5465 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_UP,
5469 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_RIGHT,
5473 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_DOWN,
5477 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_LEFT,
5481 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_UP,
5485 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_RIGHT,
5489 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_DOWN,
5493 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_LEFT,
5497 EL_PLAYER_1, ACTION_DEFAULT, -1,
5501 EL_PLAYER_2, ACTION_DEFAULT, -1,
5505 EL_PLAYER_3, ACTION_MOVING, MV_BIT_UP,
5509 EL_PLAYER_3, ACTION_MOVING, MV_BIT_RIGHT,
5513 EL_PLAYER_3, ACTION_MOVING, MV_BIT_DOWN,
5517 EL_PLAYER_3, ACTION_MOVING, MV_BIT_LEFT,
5521 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_UP,
5525 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_RIGHT,
5529 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_DOWN,
5533 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_LEFT,
5537 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_UP,
5541 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_RIGHT,
5545 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_DOWN,
5549 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_LEFT,
5553 EL_PLAYER_4, ACTION_MOVING, MV_BIT_UP,
5557 EL_PLAYER_4, ACTION_MOVING, MV_BIT_RIGHT,
5561 EL_PLAYER_4, ACTION_MOVING, MV_BIT_DOWN,
5565 EL_PLAYER_4, ACTION_MOVING, MV_BIT_LEFT,
5569 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_UP,
5573 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_RIGHT,
5577 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_DOWN,
5581 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_LEFT,
5585 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_UP,
5589 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_RIGHT,
5593 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_DOWN,
5597 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_LEFT,
5601 EL_PLAYER_3, ACTION_DEFAULT, -1,
5605 EL_PLAYER_4, ACTION_DEFAULT, -1,
5614 int map_element_RND_to_EM(int element_rnd)
5616 static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
5617 static boolean mapping_initialized = FALSE;
5619 if (!mapping_initialized)
5623 /* return "Xalpha_quest" for all undefined elements in mapping array */
5624 for (i = 0; i < NUM_FILE_ELEMENTS; i++)
5625 mapping_RND_to_EM[i] = Xalpha_quest;
5627 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5628 if (em_object_mapping_list[i].is_rnd_to_em_mapping)
5629 mapping_RND_to_EM[em_object_mapping_list[i].element_rnd] =
5630 em_object_mapping_list[i].element_em;
5632 mapping_initialized = TRUE;
5635 if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
5636 return mapping_RND_to_EM[element_rnd];
5638 Error(ERR_WARN, "invalid RND level element %d", element_rnd);
5643 int map_element_EM_to_RND(int element_em)
5645 static unsigned short mapping_EM_to_RND[TILE_MAX];
5646 static boolean mapping_initialized = FALSE;
5648 if (!mapping_initialized)
5652 /* return "EL_UNKNOWN" for all undefined elements in mapping array */
5653 for (i = 0; i < TILE_MAX; i++)
5654 mapping_EM_to_RND[i] = EL_UNKNOWN;
5656 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5657 mapping_EM_to_RND[em_object_mapping_list[i].element_em] =
5658 em_object_mapping_list[i].element_rnd;
5660 mapping_initialized = TRUE;
5663 if (element_em >= 0 && element_em < TILE_MAX)
5664 return mapping_EM_to_RND[element_em];
5666 Error(ERR_WARN, "invalid EM level element %d", element_em);
5671 void map_android_clone_elements_RND_to_EM(struct LevelInfo *level)
5673 struct LevelInfo_EM *level_em = level->native_em_level;
5674 struct LEVEL *lev = level_em->lev;
5677 for (i = 0; i < TILE_MAX; i++)
5678 lev->android_array[i] = Xblank;
5680 for (i = 0; i < level->num_android_clone_elements; i++)
5682 int element_rnd = level->android_clone_element[i];
5683 int element_em = map_element_RND_to_EM(element_rnd);
5685 for (j = 0; em_object_mapping_list[j].element_em != -1; j++)
5686 if (em_object_mapping_list[j].element_rnd == element_rnd)
5687 lev->android_array[em_object_mapping_list[j].element_em] = element_em;
5691 void map_android_clone_elements_EM_to_RND(struct LevelInfo *level)
5693 struct LevelInfo_EM *level_em = level->native_em_level;
5694 struct LEVEL *lev = level_em->lev;
5697 level->num_android_clone_elements = 0;
5699 for (i = 0; i < TILE_MAX; i++)
5701 int element_em = lev->android_array[i];
5703 boolean element_found = FALSE;
5705 if (element_em == Xblank)
5708 element_rnd = map_element_EM_to_RND(element_em);
5710 for (j = 0; j < level->num_android_clone_elements; j++)
5711 if (level->android_clone_element[j] == element_rnd)
5712 element_found = TRUE;
5716 level->android_clone_element[level->num_android_clone_elements++] =
5719 if (level->num_android_clone_elements == MAX_ANDROID_ELEMENTS)
5724 if (level->num_android_clone_elements == 0)
5726 level->num_android_clone_elements = 1;
5727 level->android_clone_element[0] = EL_EMPTY;
5731 int map_direction_RND_to_EM(int direction)
5733 return (direction == MV_UP ? 0 :
5734 direction == MV_RIGHT ? 1 :
5735 direction == MV_DOWN ? 2 :
5736 direction == MV_LEFT ? 3 :
5740 int map_direction_EM_to_RND(int direction)
5742 return (direction == 0 ? MV_UP :
5743 direction == 1 ? MV_RIGHT :
5744 direction == 2 ? MV_DOWN :
5745 direction == 3 ? MV_LEFT :
5749 int get_next_element(int element)
5753 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
5754 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
5755 case EL_QUICKSAND_FAST_FILLING: return EL_QUICKSAND_FAST_FULL;
5756 case EL_QUICKSAND_FAST_EMPTYING: return EL_QUICKSAND_FAST_EMPTY;
5757 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
5758 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
5759 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
5760 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
5761 case EL_DC_MAGIC_WALL_FILLING: return EL_DC_MAGIC_WALL_FULL;
5762 case EL_DC_MAGIC_WALL_EMPTYING: return EL_DC_MAGIC_WALL_ACTIVE;
5763 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
5765 default: return element;
5770 int el_act_dir2img(int element, int action, int direction)
5772 element = GFX_ELEMENT(element);
5774 if (direction == MV_NONE)
5775 return element_info[element].graphic[action];
5777 direction = MV_DIR_TO_BIT(direction);
5779 return element_info[element].direction_graphic[action][direction];
5782 int el_act_dir2img(int element, int action, int direction)
5784 element = GFX_ELEMENT(element);
5785 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
5787 /* direction_graphic[][] == graphic[] for undefined direction graphics */
5788 return element_info[element].direction_graphic[action][direction];
5793 static int el_act_dir2crm(int element, int action, int direction)
5795 element = GFX_ELEMENT(element);
5797 if (direction == MV_NONE)
5798 return element_info[element].crumbled[action];
5800 direction = MV_DIR_TO_BIT(direction);
5802 return element_info[element].direction_crumbled[action][direction];
5805 static int el_act_dir2crm(int element, int action, int direction)
5807 element = GFX_ELEMENT(element);
5808 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
5810 /* direction_graphic[][] == graphic[] for undefined direction graphics */
5811 return element_info[element].direction_crumbled[action][direction];
5815 int el_act2img(int element, int action)
5817 element = GFX_ELEMENT(element);
5819 return element_info[element].graphic[action];
5822 int el_act2crm(int element, int action)
5824 element = GFX_ELEMENT(element);
5826 return element_info[element].crumbled[action];
5829 int el_dir2img(int element, int direction)
5831 element = GFX_ELEMENT(element);
5833 return el_act_dir2img(element, ACTION_DEFAULT, direction);
5836 int el2baseimg(int element)
5838 return element_info[element].graphic[ACTION_DEFAULT];
5841 int el2img(int element)
5843 element = GFX_ELEMENT(element);
5845 return element_info[element].graphic[ACTION_DEFAULT];
5848 int el2edimg(int element)
5850 element = GFX_ELEMENT(element);
5852 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
5855 int el2preimg(int element)
5857 element = GFX_ELEMENT(element);
5859 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
5862 int el2panelimg(int element)
5864 element = GFX_ELEMENT(element);
5866 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PANEL];
5869 int font2baseimg(int font_nr)
5871 return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
5874 int getBeltNrFromBeltElement(int element)
5876 return (element < EL_CONVEYOR_BELT_2_LEFT ? 0 :
5877 element < EL_CONVEYOR_BELT_3_LEFT ? 1 :
5878 element < EL_CONVEYOR_BELT_4_LEFT ? 2 : 3);
5881 int getBeltNrFromBeltActiveElement(int element)
5883 return (element < EL_CONVEYOR_BELT_2_LEFT_ACTIVE ? 0 :
5884 element < EL_CONVEYOR_BELT_3_LEFT_ACTIVE ? 1 :
5885 element < EL_CONVEYOR_BELT_4_LEFT_ACTIVE ? 2 : 3);
5888 int getBeltNrFromBeltSwitchElement(int element)
5890 return (element < EL_CONVEYOR_BELT_2_SWITCH_LEFT ? 0 :
5891 element < EL_CONVEYOR_BELT_3_SWITCH_LEFT ? 1 :
5892 element < EL_CONVEYOR_BELT_4_SWITCH_LEFT ? 2 : 3);
5895 int getBeltDirNrFromBeltElement(int element)
5897 static int belt_base_element[4] =
5899 EL_CONVEYOR_BELT_1_LEFT,
5900 EL_CONVEYOR_BELT_2_LEFT,
5901 EL_CONVEYOR_BELT_3_LEFT,
5902 EL_CONVEYOR_BELT_4_LEFT
5905 int belt_nr = getBeltNrFromBeltElement(element);
5906 int belt_dir_nr = element - belt_base_element[belt_nr];
5908 return (belt_dir_nr % 3);
5911 int getBeltDirNrFromBeltSwitchElement(int element)
5913 static int belt_base_element[4] =
5915 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
5916 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
5917 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
5918 EL_CONVEYOR_BELT_4_SWITCH_LEFT
5921 int belt_nr = getBeltNrFromBeltSwitchElement(element);
5922 int belt_dir_nr = element - belt_base_element[belt_nr];
5924 return (belt_dir_nr % 3);
5927 int getBeltDirFromBeltElement(int element)
5929 static int belt_move_dir[3] =
5936 int belt_dir_nr = getBeltDirNrFromBeltElement(element);
5938 return belt_move_dir[belt_dir_nr];
5941 int getBeltDirFromBeltSwitchElement(int element)
5943 static int belt_move_dir[3] =
5950 int belt_dir_nr = getBeltDirNrFromBeltSwitchElement(element);
5952 return belt_move_dir[belt_dir_nr];
5955 int getBeltElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
5957 static int belt_base_element[4] =
5959 EL_CONVEYOR_BELT_1_LEFT,
5960 EL_CONVEYOR_BELT_2_LEFT,
5961 EL_CONVEYOR_BELT_3_LEFT,
5962 EL_CONVEYOR_BELT_4_LEFT
5965 return belt_base_element[belt_nr] + belt_dir_nr;
5968 int getBeltElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
5970 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
5972 return getBeltElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
5975 int getBeltSwitchElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
5977 static int belt_base_element[4] =
5979 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
5980 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
5981 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
5982 EL_CONVEYOR_BELT_4_SWITCH_LEFT
5985 return belt_base_element[belt_nr] + belt_dir_nr;
5988 int getBeltSwitchElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
5990 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
5992 return getBeltSwitchElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
5995 int getNumActivePlayers_EM()
5997 int num_players = 0;
6003 for (i = 0; i < MAX_PLAYERS; i++)
6004 if (tape.player_participates[i])
6010 int getGameFrameDelay_EM(int native_em_game_frame_delay)
6012 int game_frame_delay_value;
6014 game_frame_delay_value =
6015 (tape.playing && tape.fast_forward ? FfwdFrameDelay :
6016 GameFrameDelay == GAME_FRAME_DELAY ? native_em_game_frame_delay :
6019 if (tape.playing && tape.warp_forward && !tape.pausing)
6020 game_frame_delay_value = 0;
6022 return game_frame_delay_value;
6025 unsigned int InitRND(long seed)
6027 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
6028 return InitEngineRandom_EM(seed);
6030 return InitEngineRandom_RND(seed);
6034 static struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
6035 static struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
6038 inline static int get_effective_element_EM(int tile, int frame_em)
6040 int element = object_mapping[tile].element_rnd;
6041 int action = object_mapping[tile].action;
6042 boolean is_backside = object_mapping[tile].is_backside;
6043 boolean action_removing = (action == ACTION_DIGGING ||
6044 action == ACTION_SNAPPING ||
6045 action == ACTION_COLLECTING);
6051 case Yacid_splash_eB:
6052 case Yacid_splash_wB:
6053 return (frame_em > 5 ? EL_EMPTY : element);
6059 else /* frame_em == 7 */
6063 case Yacid_splash_eB:
6064 case Yacid_splash_wB:
6067 case Yemerald_stone:
6070 case Ydiamond_stone:
6074 case Xdrip_stretchB:
6093 case Xsand_stonein_1:
6094 case Xsand_stonein_2:
6095 case Xsand_stonein_3:
6096 case Xsand_stonein_4:
6100 return (is_backside || action_removing ? EL_EMPTY : element);
6105 inline static boolean check_linear_animation_EM(int tile)
6109 case Xsand_stonesand_1:
6110 case Xsand_stonesand_quickout_1:
6111 case Xsand_sandstone_1:
6112 case Xsand_stonein_1:
6113 case Xsand_stoneout_1:
6138 inline static void set_crumbled_graphics_EM(struct GraphicInfo_EM *g_em,
6139 boolean has_crumbled_graphics,
6140 int crumbled, int sync_frame)
6142 /* if element can be crumbled, but certain action graphics are just empty
6143 space (like instantly snapping sand to empty space in 1 frame), do not
6144 treat these empty space graphics as crumbled graphics in EMC engine */
6145 if (crumbled == IMG_EMPTY_SPACE)
6146 has_crumbled_graphics = FALSE;
6148 if (has_crumbled_graphics)
6150 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
6151 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
6152 g_crumbled->anim_delay,
6153 g_crumbled->anim_mode,
6154 g_crumbled->anim_start_frame,
6157 getGraphicSource(crumbled, frame_crumbled, &g_em->crumbled_bitmap,
6158 &g_em->crumbled_src_x, &g_em->crumbled_src_y);
6160 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
6162 g_em->has_crumbled_graphics = TRUE;
6166 g_em->crumbled_bitmap = NULL;
6167 g_em->crumbled_src_x = 0;
6168 g_em->crumbled_src_y = 0;
6169 g_em->crumbled_border_size = 0;
6171 g_em->has_crumbled_graphics = FALSE;
6175 void ResetGfxAnimation_EM(int x, int y, int tile)
6180 void SetGfxAnimation_EM(struct GraphicInfo_EM *g_em,
6181 int tile, int frame_em, int x, int y)
6183 int action = object_mapping[tile].action;
6185 int direction = object_mapping[tile].direction;
6186 int effective_element = get_effective_element_EM(tile, frame_em);
6187 int graphic = (direction == MV_NONE ?
6188 el_act2img(effective_element, action) :
6189 el_act_dir2img(effective_element, action, direction));
6190 struct GraphicInfo *g = &graphic_info[graphic];
6193 boolean action_removing = (action == ACTION_DIGGING ||
6194 action == ACTION_SNAPPING ||
6195 action == ACTION_COLLECTING);
6196 boolean action_moving = (action == ACTION_FALLING ||
6197 action == ACTION_MOVING ||
6198 action == ACTION_PUSHING ||
6199 action == ACTION_EATING ||
6200 action == ACTION_FILLING ||
6201 action == ACTION_EMPTYING);
6202 boolean action_falling = (action == ACTION_FALLING ||
6203 action == ACTION_FILLING ||
6204 action == ACTION_EMPTYING);
6207 if (tile == Xsand_stonesand_1 ||
6208 tile == Xsand_stonesand_2 ||
6209 tile == Xsand_stonesand_3 ||
6210 tile == Xsand_stonesand_4)
6211 printf("::: 1: quicksand frame %d [%d]\n", GfxFrame[x][y], tile);
6215 if ((action_removing || check_linear_animation_EM(tile)) && frame_em == 0)
6219 // printf("::: resetting... [%d]\n", tile);
6222 if (action_removing || check_linear_animation_EM(tile))
6224 GfxFrame[x][y] = frame_em;
6226 // printf("::: resetting... [%d]\n", tile);
6229 else if (action_moving)
6231 boolean is_backside = object_mapping[tile].is_backside;
6235 int direction = object_mapping[tile].direction;
6236 int move_dir = (action_falling ? MV_DOWN : direction);
6240 if (move_dir == MV_LEFT)
6241 GfxFrame[x - 1][y] = GfxFrame[x][y];
6242 else if (move_dir == MV_RIGHT)
6243 GfxFrame[x + 1][y] = GfxFrame[x][y];
6244 else if (move_dir == MV_UP)
6245 GfxFrame[x][y - 1] = GfxFrame[x][y];
6246 else if (move_dir == MV_DOWN)
6247 GfxFrame[x][y + 1] = GfxFrame[x][y];
6254 /* special case: animation for Xsand_stonesand_quickout_1/2 twice as fast */
6255 if (tile == Xsand_stonesand_quickout_1 ||
6256 tile == Xsand_stonesand_quickout_2)
6261 if (tile == Xsand_stonesand_1 ||
6262 tile == Xsand_stonesand_2 ||
6263 tile == Xsand_stonesand_3 ||
6264 tile == Xsand_stonesand_4)
6265 printf("::: 2: quicksand frame %d [%d]\n", GfxFrame[x][y], tile);
6269 if (graphic_info[graphic].anim_global_sync)
6270 sync_frame = FrameCounter;
6271 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
6272 sync_frame = GfxFrame[x][y];
6274 sync_frame = 0; /* playfield border (pseudo steel) */
6276 SetRandomAnimationValue(x, y);
6278 int frame = getAnimationFrame(g->anim_frames,
6281 g->anim_start_frame,
6284 g_em->unique_identifier =
6285 (graphic << 16) | ((frame % 8) << 12) | (g_em->width << 6) | g_em->height;
6289 void getGraphicSourceObjectExt_EM(struct GraphicInfo_EM *g_em,
6290 int tile, int frame_em, int x, int y)
6292 int action = object_mapping[tile].action;
6293 int direction = object_mapping[tile].direction;
6294 int effective_element = get_effective_element_EM(tile, frame_em);
6295 int graphic = (direction == MV_NONE ?
6296 el_act2img(effective_element, action) :
6297 el_act_dir2img(effective_element, action, direction));
6298 int crumbled = (direction == MV_NONE ?
6299 el_act2crm(effective_element, action) :
6300 el_act_dir2crm(effective_element, action, direction));
6301 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
6302 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
6303 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
6304 struct GraphicInfo *g = &graphic_info[graphic];
6306 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
6311 if (frame_em == 0) /* reset animation frame for certain elements */
6313 if (check_linear_animation_EM(tile))
6318 if (graphic_info[graphic].anim_global_sync)
6319 sync_frame = FrameCounter;
6320 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
6321 sync_frame = GfxFrame[x][y];
6323 sync_frame = 0; /* playfield border (pseudo steel) */
6325 SetRandomAnimationValue(x, y);
6327 int frame = getAnimationFrame(g->anim_frames,
6330 g->anim_start_frame,
6333 getGraphicSourceExt(graphic, frame, &g_em->bitmap,
6334 &g_em->src_x, &g_em->src_y, FALSE);
6336 /* (updating the "crumbled" graphic definitions is probably not really needed,
6337 as animations for crumbled graphics can't be longer than one EMC cycle) */
6339 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
6344 g_em->crumbled_bitmap = NULL;
6345 g_em->crumbled_src_x = 0;
6346 g_em->crumbled_src_y = 0;
6348 g_em->has_crumbled_graphics = FALSE;
6350 if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
6352 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
6353 g_crumbled->anim_delay,
6354 g_crumbled->anim_mode,
6355 g_crumbled->anim_start_frame,
6358 getGraphicSource(crumbled, frame_crumbled, &g_em->crumbled_bitmap,
6359 &g_em->crumbled_src_x, &g_em->crumbled_src_y);
6361 g_em->has_crumbled_graphics = TRUE;
6366 void getGraphicSourcePlayerExt_EM(struct GraphicInfo_EM *g_em,
6367 int player_nr, int anim, int frame_em)
6369 int element = player_mapping[player_nr][anim].element_rnd;
6370 int action = player_mapping[player_nr][anim].action;
6371 int direction = player_mapping[player_nr][anim].direction;
6372 int graphic = (direction == MV_NONE ?
6373 el_act2img(element, action) :
6374 el_act_dir2img(element, action, direction));
6375 struct GraphicInfo *g = &graphic_info[graphic];
6378 InitPlayerGfxAnimation(&stored_player[player_nr], action, direction);
6380 stored_player[player_nr].StepFrame = frame_em;
6382 sync_frame = stored_player[player_nr].Frame;
6384 int frame = getAnimationFrame(g->anim_frames,
6387 g->anim_start_frame,
6390 getGraphicSourceExt(graphic, frame, &g_em->bitmap,
6391 &g_em->src_x, &g_em->src_y, FALSE);
6394 printf("::: %d: %d, %d [%d]\n",
6396 stored_player[player_nr].Frame,
6397 stored_player[player_nr].StepFrame,
6402 void InitGraphicInfo_EM(void)
6405 struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
6406 struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
6411 int num_em_gfx_errors = 0;
6413 if (graphic_info_em_object[0][0].bitmap == NULL)
6415 /* EM graphics not yet initialized in em_open_all() */
6420 printf("::: [4 errors can be ignored (1 x 'bomb', 3 x 'em_dynamite']\n");
6423 /* always start with reliable default values */
6424 for (i = 0; i < TILE_MAX; i++)
6426 object_mapping[i].element_rnd = EL_UNKNOWN;
6427 object_mapping[i].is_backside = FALSE;
6428 object_mapping[i].action = ACTION_DEFAULT;
6429 object_mapping[i].direction = MV_NONE;
6432 /* always start with reliable default values */
6433 for (p = 0; p < MAX_PLAYERS; p++)
6435 for (i = 0; i < SPR_MAX; i++)
6437 player_mapping[p][i].element_rnd = EL_UNKNOWN;
6438 player_mapping[p][i].action = ACTION_DEFAULT;
6439 player_mapping[p][i].direction = MV_NONE;
6443 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
6445 int e = em_object_mapping_list[i].element_em;
6447 object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd;
6448 object_mapping[e].is_backside = em_object_mapping_list[i].is_backside;
6450 if (em_object_mapping_list[i].action != -1)
6451 object_mapping[e].action = em_object_mapping_list[i].action;
6453 if (em_object_mapping_list[i].direction != -1)
6454 object_mapping[e].direction =
6455 MV_DIR_FROM_BIT(em_object_mapping_list[i].direction);
6458 for (i = 0; em_player_mapping_list[i].action_em != -1; i++)
6460 int a = em_player_mapping_list[i].action_em;
6461 int p = em_player_mapping_list[i].player_nr;
6463 player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd;
6465 if (em_player_mapping_list[i].action != -1)
6466 player_mapping[p][a].action = em_player_mapping_list[i].action;
6468 if (em_player_mapping_list[i].direction != -1)
6469 player_mapping[p][a].direction =
6470 MV_DIR_FROM_BIT(em_player_mapping_list[i].direction);
6473 for (i = 0; i < TILE_MAX; i++)
6475 int element = object_mapping[i].element_rnd;
6476 int action = object_mapping[i].action;
6477 int direction = object_mapping[i].direction;
6478 boolean is_backside = object_mapping[i].is_backside;
6480 boolean action_removing = (action == ACTION_DIGGING ||
6481 action == ACTION_SNAPPING ||
6482 action == ACTION_COLLECTING);
6484 boolean action_exploding = ((action == ACTION_EXPLODING ||
6485 action == ACTION_SMASHED_BY_ROCK ||
6486 action == ACTION_SMASHED_BY_SPRING) &&
6487 element != EL_DIAMOND);
6488 boolean action_active = (action == ACTION_ACTIVE);
6489 boolean action_other = (action == ACTION_OTHER);
6491 for (j = 0; j < 8; j++)
6494 int effective_element = get_effective_element_EM(i, j);
6496 int effective_element = (j > 5 && i == Yacid_splash_eB ? EL_EMPTY :
6497 j > 5 && i == Yacid_splash_wB ? EL_EMPTY :
6499 i == Xdrip_stretch ? element :
6500 i == Xdrip_stretchB ? element :
6501 i == Ydrip_s1 ? element :
6502 i == Ydrip_s1B ? element :
6503 i == Xball_1B ? element :
6504 i == Xball_2 ? element :
6505 i == Xball_2B ? element :
6506 i == Yball_eat ? element :
6507 i == Ykey_1_eat ? element :
6508 i == Ykey_2_eat ? element :
6509 i == Ykey_3_eat ? element :
6510 i == Ykey_4_eat ? element :
6511 i == Ykey_5_eat ? element :
6512 i == Ykey_6_eat ? element :
6513 i == Ykey_7_eat ? element :
6514 i == Ykey_8_eat ? element :
6515 i == Ylenses_eat ? element :
6516 i == Ymagnify_eat ? element :
6517 i == Ygrass_eat ? element :
6518 i == Ydirt_eat ? element :
6519 i == Yemerald_stone ? EL_EMERALD :
6520 i == Ydiamond_stone ? EL_ROCK :
6521 i == Xsand_stonein_1 ? element :
6522 i == Xsand_stonein_2 ? element :
6523 i == Xsand_stonein_3 ? element :
6524 i == Xsand_stonein_4 ? element :
6525 is_backside ? EL_EMPTY :
6526 action_removing ? EL_EMPTY :
6529 int effective_action = (j < 7 ? action :
6530 i == Xdrip_stretch ? action :
6531 i == Xdrip_stretchB ? action :
6532 i == Ydrip_s1 ? action :
6533 i == Ydrip_s1B ? action :
6534 i == Xball_1B ? action :
6535 i == Xball_2 ? action :
6536 i == Xball_2B ? action :
6537 i == Yball_eat ? action :
6538 i == Ykey_1_eat ? action :
6539 i == Ykey_2_eat ? action :
6540 i == Ykey_3_eat ? action :
6541 i == Ykey_4_eat ? action :
6542 i == Ykey_5_eat ? action :
6543 i == Ykey_6_eat ? action :
6544 i == Ykey_7_eat ? action :
6545 i == Ykey_8_eat ? action :
6546 i == Ylenses_eat ? action :
6547 i == Ymagnify_eat ? action :
6548 i == Ygrass_eat ? action :
6549 i == Ydirt_eat ? action :
6550 i == Xsand_stonein_1 ? action :
6551 i == Xsand_stonein_2 ? action :
6552 i == Xsand_stonein_3 ? action :
6553 i == Xsand_stonein_4 ? action :
6554 i == Xsand_stoneout_1 ? action :
6555 i == Xsand_stoneout_2 ? action :
6556 i == Xboom_android ? ACTION_EXPLODING :
6557 action_exploding ? ACTION_EXPLODING :
6558 action_active ? action :
6559 action_other ? action :
6561 int graphic = (el_act_dir2img(effective_element, effective_action,
6563 int crumbled = (el_act_dir2crm(effective_element, effective_action,
6565 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
6566 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
6567 boolean has_action_graphics = (graphic != base_graphic);
6568 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
6569 struct GraphicInfo *g = &graphic_info[graphic];
6571 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
6573 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
6576 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
6577 boolean special_animation = (action != ACTION_DEFAULT &&
6578 g->anim_frames == 3 &&
6579 g->anim_delay == 2 &&
6580 g->anim_mode & ANIM_LINEAR);
6581 int sync_frame = (i == Xdrip_stretch ? 7 :
6582 i == Xdrip_stretchB ? 7 :
6583 i == Ydrip_s2 ? j + 8 :
6584 i == Ydrip_s2B ? j + 8 :
6593 i == Xfake_acid_1 ? 0 :
6594 i == Xfake_acid_2 ? 10 :
6595 i == Xfake_acid_3 ? 20 :
6596 i == Xfake_acid_4 ? 30 :
6597 i == Xfake_acid_5 ? 40 :
6598 i == Xfake_acid_6 ? 50 :
6599 i == Xfake_acid_7 ? 60 :
6600 i == Xfake_acid_8 ? 70 :
6602 i == Xball_2B ? j + 8 :
6603 i == Yball_eat ? j + 1 :
6604 i == Ykey_1_eat ? j + 1 :
6605 i == Ykey_2_eat ? j + 1 :
6606 i == Ykey_3_eat ? j + 1 :
6607 i == Ykey_4_eat ? j + 1 :
6608 i == Ykey_5_eat ? j + 1 :
6609 i == Ykey_6_eat ? j + 1 :
6610 i == Ykey_7_eat ? j + 1 :
6611 i == Ykey_8_eat ? j + 1 :
6612 i == Ylenses_eat ? j + 1 :
6613 i == Ymagnify_eat ? j + 1 :
6614 i == Ygrass_eat ? j + 1 :
6615 i == Ydirt_eat ? j + 1 :
6616 i == Xamoeba_1 ? 0 :
6617 i == Xamoeba_2 ? 1 :
6618 i == Xamoeba_3 ? 2 :
6619 i == Xamoeba_4 ? 3 :
6620 i == Xamoeba_5 ? 0 :
6621 i == Xamoeba_6 ? 1 :
6622 i == Xamoeba_7 ? 2 :
6623 i == Xamoeba_8 ? 3 :
6624 i == Xexit_2 ? j + 8 :
6625 i == Xexit_3 ? j + 16 :
6626 i == Xdynamite_1 ? 0 :
6627 i == Xdynamite_2 ? 8 :
6628 i == Xdynamite_3 ? 16 :
6629 i == Xdynamite_4 ? 24 :
6630 i == Xsand_stonein_1 ? j + 1 :
6631 i == Xsand_stonein_2 ? j + 9 :
6632 i == Xsand_stonein_3 ? j + 17 :
6633 i == Xsand_stonein_4 ? j + 25 :
6634 i == Xsand_stoneout_1 && j == 0 ? 0 :
6635 i == Xsand_stoneout_1 && j == 1 ? 0 :
6636 i == Xsand_stoneout_1 && j == 2 ? 1 :
6637 i == Xsand_stoneout_1 && j == 3 ? 2 :
6638 i == Xsand_stoneout_1 && j == 4 ? 2 :
6639 i == Xsand_stoneout_1 && j == 5 ? 3 :
6640 i == Xsand_stoneout_1 && j == 6 ? 4 :
6641 i == Xsand_stoneout_1 && j == 7 ? 4 :
6642 i == Xsand_stoneout_2 && j == 0 ? 5 :
6643 i == Xsand_stoneout_2 && j == 1 ? 6 :
6644 i == Xsand_stoneout_2 && j == 2 ? 7 :
6645 i == Xsand_stoneout_2 && j == 3 ? 8 :
6646 i == Xsand_stoneout_2 && j == 4 ? 9 :
6647 i == Xsand_stoneout_2 && j == 5 ? 11 :
6648 i == Xsand_stoneout_2 && j == 6 ? 13 :
6649 i == Xsand_stoneout_2 && j == 7 ? 15 :
6650 i == Xboom_bug && j == 1 ? 2 :
6651 i == Xboom_bug && j == 2 ? 2 :
6652 i == Xboom_bug && j == 3 ? 4 :
6653 i == Xboom_bug && j == 4 ? 4 :
6654 i == Xboom_bug && j == 5 ? 2 :
6655 i == Xboom_bug && j == 6 ? 2 :
6656 i == Xboom_bug && j == 7 ? 0 :
6657 i == Xboom_bomb && j == 1 ? 2 :
6658 i == Xboom_bomb && j == 2 ? 2 :
6659 i == Xboom_bomb && j == 3 ? 4 :
6660 i == Xboom_bomb && j == 4 ? 4 :
6661 i == Xboom_bomb && j == 5 ? 2 :
6662 i == Xboom_bomb && j == 6 ? 2 :
6663 i == Xboom_bomb && j == 7 ? 0 :
6664 i == Xboom_android && j == 7 ? 6 :
6665 i == Xboom_1 && j == 1 ? 2 :
6666 i == Xboom_1 && j == 2 ? 2 :
6667 i == Xboom_1 && j == 3 ? 4 :
6668 i == Xboom_1 && j == 4 ? 4 :
6669 i == Xboom_1 && j == 5 ? 6 :
6670 i == Xboom_1 && j == 6 ? 6 :
6671 i == Xboom_1 && j == 7 ? 8 :
6672 i == Xboom_2 && j == 0 ? 8 :
6673 i == Xboom_2 && j == 1 ? 8 :
6674 i == Xboom_2 && j == 2 ? 10 :
6675 i == Xboom_2 && j == 3 ? 10 :
6676 i == Xboom_2 && j == 4 ? 10 :
6677 i == Xboom_2 && j == 5 ? 12 :
6678 i == Xboom_2 && j == 6 ? 12 :
6679 i == Xboom_2 && j == 7 ? 12 :
6680 special_animation && j == 4 ? 3 :
6681 effective_action != action ? 0 :
6685 Bitmap *debug_bitmap = g_em->bitmap;
6686 int debug_src_x = g_em->src_x;
6687 int debug_src_y = g_em->src_y;
6690 int frame = getAnimationFrame(g->anim_frames,
6693 g->anim_start_frame,
6696 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y,
6697 g->double_movement && is_backside);
6699 g_em->bitmap = src_bitmap;
6700 g_em->src_x = src_x;
6701 g_em->src_y = src_y;
6702 g_em->src_offset_x = 0;
6703 g_em->src_offset_y = 0;
6704 g_em->dst_offset_x = 0;
6705 g_em->dst_offset_y = 0;
6706 g_em->width = TILEX;
6707 g_em->height = TILEY;
6709 g_em->preserve_background = FALSE;
6712 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
6717 g_em->crumbled_bitmap = NULL;
6718 g_em->crumbled_src_x = 0;
6719 g_em->crumbled_src_y = 0;
6720 g_em->crumbled_border_size = 0;
6722 g_em->has_crumbled_graphics = FALSE;
6725 if (has_crumbled_graphics && crumbled == IMG_EMPTY_SPACE)
6726 printf("::: empty crumbled: %d [%s], %d, %d\n",
6727 effective_element, element_info[effective_element].token_name,
6728 effective_action, direction);
6731 /* if element can be crumbled, but certain action graphics are just empty
6732 space (like instantly snapping sand to empty space in 1 frame), do not
6733 treat these empty space graphics as crumbled graphics in EMC engine */
6734 if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
6736 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
6737 g_crumbled->anim_delay,
6738 g_crumbled->anim_mode,
6739 g_crumbled->anim_start_frame,
6742 getGraphicSource(crumbled, frame_crumbled, &src_bitmap, &src_x, &src_y);
6744 g_em->has_crumbled_graphics = TRUE;
6745 g_em->crumbled_bitmap = src_bitmap;
6746 g_em->crumbled_src_x = src_x;
6747 g_em->crumbled_src_y = src_y;
6748 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
6752 if (g_em == &graphic_info_em_object[207][0])
6753 printf("... %d, %d [%d, %d, %d, %d] [%d, %d, %d, %d, %d, %d => %d]\n",
6754 graphic_info_em_object[207][0].crumbled_src_x,
6755 graphic_info_em_object[207][0].crumbled_src_y,
6757 crumbled, frame, src_x, src_y,
6762 g->anim_start_frame,
6764 gfx.anim_random_frame,
6769 printf("::: EMC tile %d is crumbled\n", i);
6775 if (element == EL_ROCK &&
6776 effective_action == ACTION_FILLING)
6777 printf("::: has_action_graphics == %d\n", has_action_graphics);
6780 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
6781 effective_action == ACTION_MOVING ||
6782 effective_action == ACTION_PUSHING ||
6783 effective_action == ACTION_EATING)) ||
6784 (!has_action_graphics && (effective_action == ACTION_FILLING ||
6785 effective_action == ACTION_EMPTYING)))
6788 (effective_action == ACTION_FALLING ||
6789 effective_action == ACTION_FILLING ||
6790 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
6791 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
6792 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
6793 int num_steps = (i == Ydrip_s1 ? 16 :
6794 i == Ydrip_s1B ? 16 :
6795 i == Ydrip_s2 ? 16 :
6796 i == Ydrip_s2B ? 16 :
6797 i == Xsand_stonein_1 ? 32 :
6798 i == Xsand_stonein_2 ? 32 :
6799 i == Xsand_stonein_3 ? 32 :
6800 i == Xsand_stonein_4 ? 32 :
6801 i == Xsand_stoneout_1 ? 16 :
6802 i == Xsand_stoneout_2 ? 16 : 8);
6803 int cx = ABS(dx) * (TILEX / num_steps);
6804 int cy = ABS(dy) * (TILEY / num_steps);
6805 int step_frame = (i == Ydrip_s2 ? j + 8 :
6806 i == Ydrip_s2B ? j + 8 :
6807 i == Xsand_stonein_2 ? j + 8 :
6808 i == Xsand_stonein_3 ? j + 16 :
6809 i == Xsand_stonein_4 ? j + 24 :
6810 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
6811 int step = (is_backside ? step_frame : num_steps - step_frame);
6813 if (is_backside) /* tile where movement starts */
6815 if (dx < 0 || dy < 0)
6817 g_em->src_offset_x = cx * step;
6818 g_em->src_offset_y = cy * step;
6822 g_em->dst_offset_x = cx * step;
6823 g_em->dst_offset_y = cy * step;
6826 else /* tile where movement ends */
6828 if (dx < 0 || dy < 0)
6830 g_em->dst_offset_x = cx * step;
6831 g_em->dst_offset_y = cy * step;
6835 g_em->src_offset_x = cx * step;
6836 g_em->src_offset_y = cy * step;
6840 g_em->width = TILEX - cx * step;
6841 g_em->height = TILEY - cy * step;
6844 /* create unique graphic identifier to decide if tile must be redrawn */
6845 /* bit 31 - 16 (16 bit): EM style graphic
6846 bit 15 - 12 ( 4 bit): EM style frame
6847 bit 11 - 6 ( 6 bit): graphic width
6848 bit 5 - 0 ( 6 bit): graphic height */
6849 g_em->unique_identifier =
6850 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
6854 /* skip check for EMC elements not contained in original EMC artwork */
6855 if (element == EL_EMC_FAKE_ACID)
6858 if (g_em->bitmap != debug_bitmap ||
6859 g_em->src_x != debug_src_x ||
6860 g_em->src_y != debug_src_y ||
6861 g_em->src_offset_x != 0 ||
6862 g_em->src_offset_y != 0 ||
6863 g_em->dst_offset_x != 0 ||
6864 g_em->dst_offset_y != 0 ||
6865 g_em->width != TILEX ||
6866 g_em->height != TILEY)
6868 static int last_i = -1;
6876 printf("::: EMC GFX ERROR for element %d -> %d ('%s', '%s', %d)",
6877 i, element, element_info[element].token_name,
6878 element_action_info[effective_action].suffix, direction);
6880 if (element != effective_element)
6881 printf(" [%d ('%s')]",
6883 element_info[effective_element].token_name);
6887 if (g_em->bitmap != debug_bitmap)
6888 printf(" %d (%d): different bitmap! (0x%08x != 0x%08x)\n",
6889 j, is_backside, (int)(g_em->bitmap), (int)(debug_bitmap));
6891 if (g_em->src_x != debug_src_x ||
6892 g_em->src_y != debug_src_y)
6893 printf(" frame %d (%c): %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
6894 j, (is_backside ? 'B' : 'F'),
6895 g_em->src_x, g_em->src_y,
6896 g_em->src_x / 32, g_em->src_y / 32,
6897 debug_src_x, debug_src_y,
6898 debug_src_x / 32, debug_src_y / 32);
6900 if (g_em->src_offset_x != 0 ||
6901 g_em->src_offset_y != 0 ||
6902 g_em->dst_offset_x != 0 ||
6903 g_em->dst_offset_y != 0)
6904 printf(" %d (%d): offsets %d,%d and %d,%d should be all 0\n",
6906 g_em->src_offset_x, g_em->src_offset_y,
6907 g_em->dst_offset_x, g_em->dst_offset_y);
6909 if (g_em->width != TILEX ||
6910 g_em->height != TILEY)
6911 printf(" %d (%d): size %d,%d should be %d,%d\n",
6913 g_em->width, g_em->height, TILEX, TILEY);
6915 num_em_gfx_errors++;
6922 for (i = 0; i < TILE_MAX; i++)
6924 for (j = 0; j < 8; j++)
6926 int element = object_mapping[i].element_rnd;
6927 int action = object_mapping[i].action;
6928 int direction = object_mapping[i].direction;
6929 boolean is_backside = object_mapping[i].is_backside;
6930 int graphic_action = el_act_dir2img(element, action, direction);
6931 int graphic_default = el_act_dir2img(element, ACTION_DEFAULT, direction);
6933 if ((action == ACTION_SMASHED_BY_ROCK ||
6934 action == ACTION_SMASHED_BY_SPRING ||
6935 action == ACTION_EATING) &&
6936 graphic_action == graphic_default)
6938 int e = (action == ACTION_SMASHED_BY_ROCK ? Ystone_s :
6939 action == ACTION_SMASHED_BY_SPRING ? Yspring_s :
6940 direction == MV_LEFT ? (is_backside? Yspring_wB: Yspring_w) :
6941 direction == MV_RIGHT ? (is_backside? Yspring_eB: Yspring_e) :
6944 /* no separate animation for "smashed by rock" -- use rock instead */
6945 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
6946 struct GraphicInfo_EM *g_xx = &graphic_info_em_object[e][7 - j];
6948 g_em->bitmap = g_xx->bitmap;
6949 g_em->src_x = g_xx->src_x;
6950 g_em->src_y = g_xx->src_y;
6951 g_em->src_offset_x = g_xx->src_offset_x;
6952 g_em->src_offset_y = g_xx->src_offset_y;
6953 g_em->dst_offset_x = g_xx->dst_offset_x;
6954 g_em->dst_offset_y = g_xx->dst_offset_y;
6955 g_em->width = g_xx->width;
6956 g_em->height = g_xx->height;
6957 g_em->unique_identifier = g_xx->unique_identifier;
6960 g_em->preserve_background = TRUE;
6965 for (p = 0; p < MAX_PLAYERS; p++)
6967 for (i = 0; i < SPR_MAX; i++)
6969 int element = player_mapping[p][i].element_rnd;
6970 int action = player_mapping[p][i].action;
6971 int direction = player_mapping[p][i].direction;
6973 for (j = 0; j < 8; j++)
6975 int effective_element = element;
6976 int effective_action = action;
6977 int graphic = (direction == MV_NONE ?
6978 el_act2img(effective_element, effective_action) :
6979 el_act_dir2img(effective_element, effective_action,
6981 struct GraphicInfo *g = &graphic_info[graphic];
6982 struct GraphicInfo_EM *g_em = &graphic_info_em_player[p][i][7 - j];
6988 Bitmap *debug_bitmap = g_em->bitmap;
6989 int debug_src_x = g_em->src_x;
6990 int debug_src_y = g_em->src_y;
6993 int frame = getAnimationFrame(g->anim_frames,
6996 g->anim_start_frame,
6999 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
7001 g_em->bitmap = src_bitmap;
7002 g_em->src_x = src_x;
7003 g_em->src_y = src_y;
7004 g_em->src_offset_x = 0;
7005 g_em->src_offset_y = 0;
7006 g_em->dst_offset_x = 0;
7007 g_em->dst_offset_y = 0;
7008 g_em->width = TILEX;
7009 g_em->height = TILEY;
7013 /* skip check for EMC elements not contained in original EMC artwork */
7014 if (element == EL_PLAYER_3 ||
7015 element == EL_PLAYER_4)
7018 if (g_em->bitmap != debug_bitmap ||
7019 g_em->src_x != debug_src_x ||
7020 g_em->src_y != debug_src_y)
7022 static int last_i = -1;
7030 printf("::: EMC GFX ERROR for p/a %d/%d -> %d ('%s', '%s', %d)",
7031 p, i, element, element_info[element].token_name,
7032 element_action_info[effective_action].suffix, direction);
7034 if (element != effective_element)
7035 printf(" [%d ('%s')]",
7037 element_info[effective_element].token_name);
7041 if (g_em->bitmap != debug_bitmap)
7042 printf(" %d: different bitmap! (0x%08x != 0x%08x)\n",
7043 j, (int)(g_em->bitmap), (int)(debug_bitmap));
7045 if (g_em->src_x != debug_src_x ||
7046 g_em->src_y != debug_src_y)
7047 printf(" frame %d: %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
7049 g_em->src_x, g_em->src_y,
7050 g_em->src_x / 32, g_em->src_y / 32,
7051 debug_src_x, debug_src_y,
7052 debug_src_x / 32, debug_src_y / 32);
7054 num_em_gfx_errors++;
7064 printf("::: [%d errors found]\n", num_em_gfx_errors);
7070 void PlayMenuSoundExt(int sound)
7072 if (sound == SND_UNDEFINED)
7075 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
7076 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
7079 if (IS_LOOP_SOUND(sound))
7080 PlaySoundLoop(sound);
7085 void PlayMenuSound()
7087 PlayMenuSoundExt(menu.sound[game_status]);
7090 void PlayMenuSoundStereo(int sound, int stereo_position)
7092 if (sound == SND_UNDEFINED)
7095 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
7096 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
7099 if (IS_LOOP_SOUND(sound))
7100 PlaySoundExt(sound, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_LOOP);
7102 PlaySoundStereo(sound, stereo_position);
7105 void PlayMenuSoundIfLoopExt(int sound)
7107 if (sound == SND_UNDEFINED)
7110 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
7111 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
7114 if (IS_LOOP_SOUND(sound))
7115 PlaySoundLoop(sound);
7118 void PlayMenuSoundIfLoop()
7120 PlayMenuSoundIfLoopExt(menu.sound[game_status]);
7123 void PlayMenuMusicExt(int music)
7125 if (music == MUS_UNDEFINED)
7128 if (!setup.sound_music)
7134 void PlayMenuMusic()
7136 PlayMenuMusicExt(menu.music[game_status]);
7139 void PlaySoundActivating()
7142 PlaySound(SND_MENU_ITEM_ACTIVATING);
7146 void PlaySoundSelecting()
7149 PlaySound(SND_MENU_ITEM_SELECTING);
7153 void ToggleFullscreenIfNeeded()
7155 boolean change_fullscreen = (setup.fullscreen !=
7156 video.fullscreen_enabled);
7157 boolean change_fullscreen_mode = (video.fullscreen_enabled &&
7158 !strEqual(setup.fullscreen_mode,
7159 video.fullscreen_mode_current));
7161 if (!video.fullscreen_available)
7165 if (change_fullscreen || change_fullscreen_mode)
7167 if (setup.fullscreen != video.fullscreen_enabled ||
7168 setup.fullscreen_mode != video.fullscreen_mode_current)
7171 Bitmap *tmp_backbuffer = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
7173 /* save backbuffer content which gets lost when toggling fullscreen mode */
7174 BlitBitmap(backbuffer, tmp_backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
7177 if (change_fullscreen_mode)
7179 if (setup.fullscreen && video.fullscreen_enabled)
7182 /* keep fullscreen, but change fullscreen mode (screen resolution) */
7184 /* (this is now set in sdl.c) */
7186 video.fullscreen_mode_current = setup.fullscreen_mode;
7188 video.fullscreen_enabled = FALSE; /* force new fullscreen mode */
7191 /* toggle fullscreen */
7192 ChangeVideoModeIfNeeded(setup.fullscreen);
7194 setup.fullscreen = video.fullscreen_enabled;
7196 /* restore backbuffer content from temporary backbuffer backup bitmap */
7197 BlitBitmap(tmp_backbuffer, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
7199 FreeBitmap(tmp_backbuffer);
7202 /* update visible window/screen */
7203 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
7205 redraw_mask = REDRAW_ALL;