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;
507 printf("::: !!! FADING %d ... [%d] [%d]\n", fade_mode, fade_type,
512 fade_delay = fading.fade_delay;
513 post_delay = (fade_mode == FADE_MODE_FADE_OUT ? fading.post_delay : 0);
516 if (fade_type_skip != FADE_TYPE_NONE)
519 printf("::: skipping %d ... [%d]\n", fade_mode, fade_type_skip);
522 /* skip all fade operations until specified fade operation */
523 if (fade_type & fade_type_skip)
524 fade_type_skip = FADE_TYPE_NONE;
534 if (global.autoplay_leveldir)
536 // fading.fade_mode = FADE_MODE_NONE;
543 if (fading.fade_mode == FADE_MODE_NONE)
551 /* !!! what about fade_mask == REDRAW_FIELD | REDRAW_ALL ??? !!! */
554 printf("::: NOW FADING %d ... [%d]\n", fade_mode, fade_type);
558 if (fade_mask == REDRAW_NONE)
559 fade_mask = REDRAW_FIELD;
562 // if (fade_mask & REDRAW_FIELD)
563 if (fade_mask == REDRAW_FIELD)
568 height = FULL_SYSIZE;
571 fade_delay = fading.fade_delay;
572 post_delay = (fade_mode == FADE_MODE_FADE_OUT ? fading.post_delay : 0);
575 if (border.draw_masked_when_fading)
576 draw_border_function = DrawMaskedBorder_FIELD; /* update when fading */
578 DrawMaskedBorder_FIELD(); /* draw once */
580 else /* REDRAW_ALL */
588 fade_delay = fading.fade_delay;
589 post_delay = (fade_mode == FADE_MODE_FADE_OUT ? fading.post_delay : 0);
594 if (!setup.fade_screens ||
596 fading.fade_mode == FADE_MODE_NONE)
598 if (!setup.fade_screens || fade_delay == 0)
601 if (fade_mode == FADE_MODE_FADE_OUT)
605 if (fade_mode == FADE_MODE_FADE_OUT &&
606 fading.fade_mode != FADE_MODE_NONE)
607 ClearRectangle(backbuffer, x, y, width, height);
611 BlitBitmap(backbuffer, window, x, y, width, height, x, y);
612 redraw_mask = REDRAW_NONE;
620 FadeRectangle(bitmap, x, y, width, height, fade_mode, fade_delay, post_delay,
621 draw_border_function);
623 redraw_mask &= ~fade_mask;
626 void FadeIn(int fade_mask)
628 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
629 FadeExt(fade_mask, fading.fade_mode, FADE_TYPE_FADE_IN);
631 FadeExt(fade_mask, FADE_MODE_FADE_IN, FADE_TYPE_FADE_IN);
634 void FadeOut(int fade_mask)
636 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
637 FadeExt(fade_mask, fading.fade_mode, FADE_TYPE_FADE_OUT);
639 FadeExt(fade_mask, FADE_MODE_FADE_OUT, FADE_TYPE_FADE_OUT);
641 global.border_status = game_status;
644 static void FadeSetLeaveNext(struct TitleFadingInfo fading_leave, boolean set)
646 static struct TitleFadingInfo fading_leave_stored;
649 fading_leave_stored = fading_leave;
651 fading = fading_leave_stored;
654 void FadeSetEnterMenu()
656 fading = menu.enter_menu;
659 printf("::: storing enter_menu\n");
662 FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
665 void FadeSetLeaveMenu()
667 fading = menu.leave_menu;
670 printf("::: storing leave_menu\n");
673 FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
676 void FadeSetEnterScreen()
678 fading = menu.enter_screen[game_status];
681 printf("::: storing leave_screen[%d]\n", game_status);
684 FadeSetLeaveNext(menu.leave_screen[game_status], TRUE); /* store */
687 void FadeSetNextScreen()
689 fading = menu.next_screen;
692 printf("::: storing next_screen\n");
695 // (do not overwrite fade mode set by FadeSetEnterScreen)
696 // FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
699 void FadeSetLeaveScreen()
702 printf("::: recalling last stored value\n");
705 FadeSetLeaveNext(menu.leave_screen[game_status], FALSE); /* recall */
708 void FadeSetFromType(int type)
710 if (type & TYPE_ENTER_SCREEN)
711 FadeSetEnterScreen();
712 else if (type & TYPE_ENTER)
714 else if (type & TYPE_LEAVE)
718 void FadeSetDisabled()
720 static struct TitleFadingInfo fading_none = { FADE_MODE_NONE, -1, -1, -1 };
722 fading = fading_none;
725 void FadeSkipNextFadeIn()
727 FadeExt(0, FADE_MODE_SKIP_FADE_IN, FADE_TYPE_SKIP);
730 void FadeSkipNextFadeOut()
732 FadeExt(0, FADE_MODE_SKIP_FADE_OUT, FADE_TYPE_SKIP);
735 void SetWindowBackgroundImageIfDefined(int graphic)
737 if (graphic_info[graphic].bitmap)
738 SetWindowBackgroundBitmap(graphic_info[graphic].bitmap);
741 void SetMainBackgroundImageIfDefined(int graphic)
743 if (graphic_info[graphic].bitmap)
744 SetMainBackgroundBitmap(graphic_info[graphic].bitmap);
747 void SetDoorBackgroundImageIfDefined(int graphic)
749 if (graphic_info[graphic].bitmap)
750 SetDoorBackgroundBitmap(graphic_info[graphic].bitmap);
753 void SetWindowBackgroundImage(int graphic)
755 SetWindowBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
756 graphic_info[graphic].bitmap ?
757 graphic_info[graphic].bitmap :
758 graphic_info[IMG_BACKGROUND].bitmap);
761 void SetMainBackgroundImage(int graphic)
763 SetMainBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
764 graphic_info[graphic].bitmap ?
765 graphic_info[graphic].bitmap :
766 graphic_info[IMG_BACKGROUND].bitmap);
769 void SetDoorBackgroundImage(int graphic)
771 SetDoorBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
772 graphic_info[graphic].bitmap ?
773 graphic_info[graphic].bitmap :
774 graphic_info[IMG_BACKGROUND].bitmap);
777 void SetPanelBackground()
779 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, bitmap_db_panel,
780 DOOR_GFX_PAGEX5, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE, 0, 0);
782 SetDoorBackgroundBitmap(bitmap_db_panel);
785 void DrawBackground(int x, int y, int width, int height)
787 /* !!! "drawto" might still point to playfield buffer here (see below) !!! */
788 /* (when entering hall of fame after playing) */
790 ClearRectangleOnBackground(drawto, x, y, width, height);
792 ClearRectangleOnBackground(backbuffer, x, y, width, height);
795 redraw_mask |= REDRAW_FIELD;
798 void DrawBackgroundForFont(int x, int y, int width, int height, int font_nr)
800 struct FontBitmapInfo *font = getFontBitmapInfo(font_nr);
802 if (font->bitmap == NULL)
805 DrawBackground(x, y, width, height);
808 void DrawBackgroundForGraphic(int x, int y, int width, int height, int graphic)
810 struct GraphicInfo *g = &graphic_info[graphic];
812 if (g->bitmap == NULL)
815 DrawBackground(x, y, width, height);
820 /* !!! "drawto" might still point to playfield buffer here (see above) !!! */
821 /* (when entering hall of fame after playing) */
822 DrawBackground(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
824 /* !!! maybe this should be done before clearing the background !!! */
825 if (setup.soft_scrolling && game_status == GAME_MODE_PLAYING)
827 ClearRectangle(fieldbuffer, 0, 0, FXSIZE, FYSIZE);
828 SetDrawtoField(DRAW_BUFFERED);
831 SetDrawtoField(DRAW_BACKBUFFER);
834 void MarkTileDirty(int x, int y)
836 int xx = redraw_x1 + x;
837 int yy = redraw_y1 + y;
842 redraw[xx][yy] = TRUE;
843 redraw_mask |= REDRAW_TILES;
846 void SetBorderElement()
850 BorderElement = EL_EMPTY;
852 for (y = 0; y < lev_fieldy && BorderElement == EL_EMPTY; y++)
854 for (x = 0; x < lev_fieldx; x++)
856 if (!IS_INDESTRUCTIBLE(Feld[x][y]))
857 BorderElement = EL_STEELWALL;
859 if (y != 0 && y != lev_fieldy - 1 && x != lev_fieldx - 1)
865 void FloodFillLevel(int from_x, int from_y, int fill_element,
866 short field[MAX_LEV_FIELDX][MAX_LEV_FIELDY],
867 int max_fieldx, int max_fieldy)
871 static int check[4][2] = { { -1, 0 }, { 0, -1 }, { 1, 0 }, { 0, 1 } };
872 static int safety = 0;
874 /* check if starting field still has the desired content */
875 if (field[from_x][from_y] == fill_element)
880 if (safety > max_fieldx * max_fieldy)
881 Error(ERR_EXIT, "Something went wrong in 'FloodFill()'. Please debug.");
883 old_element = field[from_x][from_y];
884 field[from_x][from_y] = fill_element;
886 for (i = 0; i < 4; i++)
888 x = from_x + check[i][0];
889 y = from_y + check[i][1];
891 if (IN_FIELD(x, y, max_fieldx, max_fieldy) && field[x][y] == old_element)
892 FloodFillLevel(x, y, fill_element, field, max_fieldx, max_fieldy);
898 void SetRandomAnimationValue(int x, int y)
900 gfx.anim_random_frame = GfxRandom[x][y];
903 inline int getGraphicAnimationFrame(int graphic, int sync_frame)
905 /* animation synchronized with global frame counter, not move position */
906 if (graphic_info[graphic].anim_global_sync || sync_frame < 0)
907 sync_frame = FrameCounter;
909 return getAnimationFrame(graphic_info[graphic].anim_frames,
910 graphic_info[graphic].anim_delay,
911 graphic_info[graphic].anim_mode,
912 graphic_info[graphic].anim_start_frame,
916 void getSizedGraphicSource(int graphic, int frame, int tilesize_raw,
917 Bitmap **bitmap, int *x, int *y)
921 int width_mult, width_div;
922 int height_mult, height_div;
926 { 15, 16, 2, 3 }, /* 1 x 1 */
927 { 7, 8, 2, 3 }, /* 2 x 2 */
928 { 3, 4, 2, 3 }, /* 4 x 4 */
929 { 1, 2, 2, 3 }, /* 8 x 8 */
930 { 0, 1, 2, 3 }, /* 16 x 16 */
931 { 0, 1, 0, 1 }, /* 32 x 32 */
933 struct GraphicInfo *g = &graphic_info[graphic];
934 Bitmap *src_bitmap = g->bitmap;
935 int tilesize = MIN(MAX(1, tilesize_raw), TILESIZE);
936 int offset_calc_pos = log_2(tilesize);
937 int width_mult = offset_calc[offset_calc_pos].width_mult;
938 int width_div = offset_calc[offset_calc_pos].width_div;
939 int height_mult = offset_calc[offset_calc_pos].height_mult;
940 int height_div = offset_calc[offset_calc_pos].height_div;
941 int startx = src_bitmap->width * width_mult / width_div;
942 int starty = src_bitmap->height * height_mult / height_div;
943 int src_x = g->src_x * tilesize / TILESIZE;
944 int src_y = g->src_y * tilesize / TILESIZE;
945 int width = g->width * tilesize / TILESIZE;
946 int height = g->height * tilesize / TILESIZE;
947 int offset_x = g->offset_x * tilesize / TILESIZE;
948 int offset_y = g->offset_y * tilesize / TILESIZE;
950 if (g->offset_y == 0) /* frames are ordered horizontally */
952 int max_width = g->anim_frames_per_line * width;
953 int pos = (src_y / height) * max_width + src_x + frame * offset_x;
955 src_x = pos % max_width;
956 src_y = src_y % height + pos / max_width * height;
958 else if (g->offset_x == 0) /* frames are ordered vertically */
960 int max_height = g->anim_frames_per_line * height;
961 int pos = (src_x / width) * max_height + src_y + frame * offset_y;
963 src_x = src_x % width + pos / max_height * width;
964 src_y = pos % max_height;
966 else /* frames are ordered diagonally */
968 src_x = src_x + frame * offset_x;
969 src_y = src_y + frame * offset_y;
972 *bitmap = src_bitmap;
977 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
980 getSizedGraphicSource(graphic, 0, MINI_TILESIZE, bitmap, x, y);
982 struct GraphicInfo *g = &graphic_info[graphic];
984 int mini_starty = g->bitmap->height * 2 / 3;
987 *x = mini_startx + g->src_x / 2;
988 *y = mini_starty + g->src_y / 2;
992 inline void getGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
993 int *x, int *y, boolean get_backside)
995 struct GraphicInfo *g = &graphic_info[graphic];
996 int src_x = g->src_x + (get_backside ? g->offset2_x : 0);
997 int src_y = g->src_y + (get_backside ? g->offset2_y : 0);
1001 if (g->offset_y == 0) /* frames are ordered horizontally */
1003 int max_width = g->anim_frames_per_line * g->width;
1004 int pos = (src_y / g->height) * max_width + src_x + frame * g->offset_x;
1006 *x = pos % max_width;
1007 *y = src_y % g->height + pos / max_width * g->height;
1009 else if (g->offset_x == 0) /* frames are ordered vertically */
1011 int max_height = g->anim_frames_per_line * g->height;
1012 int pos = (src_x / g->width) * max_height + src_y + frame * g->offset_y;
1014 *x = src_x % g->width + pos / max_height * g->width;
1015 *y = pos % max_height;
1017 else /* frames are ordered diagonally */
1019 *x = src_x + frame * g->offset_x;
1020 *y = src_y + frame * g->offset_y;
1024 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
1026 getGraphicSourceExt(graphic, frame, bitmap, x, y, FALSE);
1029 void DrawGraphic(int x, int y, int graphic, int frame)
1032 if (!IN_SCR_FIELD(x, y))
1034 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
1035 printf("DrawGraphic(): This should never happen!\n");
1040 DrawGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic, frame);
1041 MarkTileDirty(x, y);
1044 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
1050 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1051 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
1054 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
1057 if (!IN_SCR_FIELD(x, y))
1059 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
1060 printf("DrawGraphicThruMask(): This should never happen!\n");
1065 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y *TILEY, graphic,
1067 MarkTileDirty(x, y);
1070 void DrawGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y, int graphic,
1076 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1078 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1079 dst_x - src_x, dst_y - src_y);
1080 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dst_x, dst_y);
1083 void DrawSizedGraphic(int x, int y, int graphic, int frame, int tilesize)
1085 DrawSizedGraphicExt(drawto, SX + x * tilesize, SY + y * tilesize, graphic,
1087 MarkTileDirty(x / tilesize, y / tilesize);
1090 void DrawSizedGraphicExt(DrawBuffer *d, int x, int y, int graphic, int frame,
1096 getSizedGraphicSource(graphic, frame, tilesize, &src_bitmap, &src_x, &src_y);
1097 BlitBitmap(src_bitmap, d, src_x, src_y, tilesize, tilesize, x, y);
1100 void DrawMiniGraphic(int x, int y, int graphic)
1102 DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
1103 MarkTileDirty(x / 2, y / 2);
1106 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
1111 getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1112 BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
1115 inline static void DrawGraphicShiftedNormal(int x, int y, int dx, int dy,
1116 int graphic, int frame,
1117 int cut_mode, int mask_mode)
1122 int width = TILEX, height = TILEY;
1125 if (dx || dy) /* shifted graphic */
1127 if (x < BX1) /* object enters playfield from the left */
1134 else if (x > BX2) /* object enters playfield from the right */
1140 else if (x==BX1 && dx < 0) /* object leaves playfield to the left */
1146 else if (x==BX2 && dx > 0) /* object leaves playfield to the right */
1148 else if (dx) /* general horizontal movement */
1149 MarkTileDirty(x + SIGN(dx), y);
1151 if (y < BY1) /* object enters playfield from the top */
1153 if (cut_mode==CUT_BELOW) /* object completely above top border */
1161 else if (y > BY2) /* object enters playfield from the bottom */
1167 else if (y==BY1 && dy < 0) /* object leaves playfield to the top */
1173 else if (dy > 0 && cut_mode == CUT_ABOVE)
1175 if (y == BY2) /* object completely above bottom border */
1181 MarkTileDirty(x, y + 1);
1182 } /* object leaves playfield to the bottom */
1183 else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
1185 else if (dy) /* general vertical movement */
1186 MarkTileDirty(x, y + SIGN(dy));
1190 if (!IN_SCR_FIELD(x, y))
1192 printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
1193 printf("DrawGraphicShifted(): This should never happen!\n");
1198 if (width > 0 && height > 0)
1200 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1205 dst_x = FX + x * TILEX + dx;
1206 dst_y = FY + y * TILEY + dy;
1208 if (mask_mode == USE_MASKING)
1210 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1211 dst_x - src_x, dst_y - src_y);
1212 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1216 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1219 MarkTileDirty(x, y);
1223 inline static void DrawGraphicShiftedDouble(int x, int y, int dx, int dy,
1224 int graphic, int frame,
1225 int cut_mode, int mask_mode)
1230 int width = TILEX, height = TILEY;
1233 int x2 = x + SIGN(dx);
1234 int y2 = y + SIGN(dy);
1235 int anim_frames = graphic_info[graphic].anim_frames;
1236 int sync_frame = (dx ? ABS(dx) : ABS(dy)) * anim_frames / TILESIZE;
1237 boolean draw_start_tile = (cut_mode != CUT_ABOVE); /* only for falling! */
1238 boolean draw_end_tile = (cut_mode != CUT_BELOW); /* only for falling! */
1240 /* re-calculate animation frame for two-tile movement animation */
1241 frame = getGraphicAnimationFrame(graphic, sync_frame);
1243 /* check if movement start graphic inside screen area and should be drawn */
1244 if (draw_start_tile && IN_SCR_FIELD(x1, y1))
1246 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, TRUE);
1248 dst_x = FX + x1 * TILEX;
1249 dst_y = FY + y1 * TILEY;
1251 if (mask_mode == USE_MASKING)
1253 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1254 dst_x - src_x, dst_y - src_y);
1255 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1259 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1262 MarkTileDirty(x1, y1);
1265 /* check if movement end graphic inside screen area and should be drawn */
1266 if (draw_end_tile && IN_SCR_FIELD(x2, y2))
1268 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
1270 dst_x = FX + x2 * TILEX;
1271 dst_y = FY + y2 * TILEY;
1273 if (mask_mode == USE_MASKING)
1275 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1276 dst_x - src_x, dst_y - src_y);
1277 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1281 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1284 MarkTileDirty(x2, y2);
1288 static void DrawGraphicShifted(int x, int y, int dx, int dy,
1289 int graphic, int frame,
1290 int cut_mode, int mask_mode)
1294 DrawGraphic(x, y, graphic, frame);
1299 if (graphic_info[graphic].double_movement) /* EM style movement images */
1300 DrawGraphicShiftedDouble(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1302 DrawGraphicShiftedNormal(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1305 void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
1306 int frame, int cut_mode)
1308 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, USE_MASKING);
1311 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
1312 int cut_mode, int mask_mode)
1314 int lx = LEVELX(x), ly = LEVELY(y);
1318 if (IN_LEV_FIELD(lx, ly))
1320 SetRandomAnimationValue(lx, ly);
1322 graphic = el_act_dir2img(element, GfxAction[lx][ly], GfxDir[lx][ly]);
1323 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1325 /* do not use double (EM style) movement graphic when not moving */
1326 if (graphic_info[graphic].double_movement && !dx && !dy)
1328 graphic = el_act_dir2img(element, ACTION_DEFAULT, GfxDir[lx][ly]);
1329 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1332 else /* border element */
1334 graphic = el2img(element);
1335 frame = getGraphicAnimationFrame(graphic, -1);
1338 if (element == EL_EXPANDABLE_WALL)
1340 boolean left_stopped = FALSE, right_stopped = FALSE;
1342 if (!IN_LEV_FIELD(lx - 1, ly) || IS_WALL(Feld[lx - 1][ly]))
1343 left_stopped = TRUE;
1344 if (!IN_LEV_FIELD(lx + 1, ly) || IS_WALL(Feld[lx + 1][ly]))
1345 right_stopped = TRUE;
1347 if (left_stopped && right_stopped)
1349 else if (left_stopped)
1351 graphic = IMG_EXPANDABLE_WALL_GROWING_RIGHT;
1352 frame = graphic_info[graphic].anim_frames - 1;
1354 else if (right_stopped)
1356 graphic = IMG_EXPANDABLE_WALL_GROWING_LEFT;
1357 frame = graphic_info[graphic].anim_frames - 1;
1362 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
1363 else if (mask_mode == USE_MASKING)
1364 DrawGraphicThruMask(x, y, graphic, frame);
1366 DrawGraphic(x, y, graphic, frame);
1369 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
1370 int cut_mode, int mask_mode)
1372 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1373 DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
1374 cut_mode, mask_mode);
1377 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
1380 DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1383 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
1386 DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1389 void DrawLevelElementThruMask(int x, int y, int element)
1391 DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1394 void DrawLevelFieldThruMask(int x, int y)
1396 DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
1399 /* !!! implementation of quicksand is totally broken !!! */
1400 #define IS_CRUMBLED_TILE(x, y, e) \
1401 (GFX_CRUMBLED(e) && (!IN_LEV_FIELD(x, y) || \
1402 !IS_MOVING(x, y) || \
1403 (e) == EL_QUICKSAND_EMPTYING || \
1404 (e) == EL_QUICKSAND_FAST_EMPTYING))
1406 static void DrawLevelFieldCrumbledSandExt(int x, int y, int graphic, int frame)
1410 int sx = SCREENX(x), sy = SCREENY(y);
1412 int width, height, cx, cy, i;
1413 int crumbled_border_size = graphic_info[graphic].border_size;
1414 static int xy[4][2] =
1422 if (!IN_LEV_FIELD(x, y))
1425 element = TILE_GFX_ELEMENT(x, y);
1427 /* crumble field itself */
1429 if (IS_CRUMBLED_TILE(x, y, element))
1431 if (GFX_CRUMBLED(element) && !IS_MOVING(x, y))
1434 if (!IN_SCR_FIELD(sx, sy))
1437 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1439 for (i = 0; i < 4; i++)
1441 int xx = x + xy[i][0];
1442 int yy = y + xy[i][1];
1444 element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1447 /* check if neighbour field is of same type */
1449 if (IS_CRUMBLED_TILE(xx, yy, element))
1452 if (GFX_CRUMBLED(element) && !IS_MOVING(xx, yy))
1456 if (i == 1 || i == 2)
1458 width = crumbled_border_size;
1460 cx = (i == 2 ? TILEX - crumbled_border_size : 0);
1466 height = crumbled_border_size;
1468 cy = (i == 3 ? TILEY - crumbled_border_size : 0);
1471 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1472 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
1475 MarkTileDirty(sx, sy);
1477 else /* crumble neighbour fields */
1479 for (i = 0; i < 4; i++)
1481 int xx = x + xy[i][0];
1482 int yy = y + xy[i][1];
1483 int sxx = sx + xy[i][0];
1484 int syy = sy + xy[i][1];
1487 if (!IN_LEV_FIELD(xx, yy) ||
1488 !IN_SCR_FIELD(sxx, syy))
1491 if (!IN_LEV_FIELD(xx, yy) ||
1492 !IN_SCR_FIELD(sxx, syy) ||
1497 if (Feld[xx][yy] == EL_ELEMENT_SNAPPING)
1500 element = TILE_GFX_ELEMENT(xx, yy);
1503 if (!IS_CRUMBLED_TILE(xx, yy, element))
1506 if (!GFX_CRUMBLED(element))
1510 graphic = el_act2crm(element, ACTION_DEFAULT);
1511 crumbled_border_size = graphic_info[graphic].border_size;
1513 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1515 if (i == 1 || i == 2)
1517 width = crumbled_border_size;
1519 cx = (i == 1 ? TILEX - crumbled_border_size : 0);
1525 height = crumbled_border_size;
1527 cy = (i == 0 ? TILEY - crumbled_border_size : 0);
1530 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1531 width, height, FX + sxx * TILEX + cx, FY + syy * TILEY + cy);
1533 MarkTileDirty(sxx, syy);
1538 void DrawLevelFieldCrumbledSand(int x, int y)
1542 if (!IN_LEV_FIELD(x, y))
1546 /* !!! CHECK THIS !!! */
1549 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
1550 GFX_CRUMBLED(GfxElement[x][y]))
1553 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
1554 GfxElement[x][y] != EL_UNDEFINED &&
1555 GFX_CRUMBLED(GfxElement[x][y]))
1557 DrawLevelFieldCrumbledSandDigging(x, y, GfxDir[x][y], GfxFrame[x][y]);
1564 graphic = el_act2crm(TILE_GFX_ELEMENT(x, y), ACTION_DEFAULT);
1566 graphic = el_act2crm(Feld[x][y], ACTION_DEFAULT);
1569 DrawLevelFieldCrumbledSandExt(x, y, graphic, 0);
1572 void DrawLevelFieldCrumbledSandDigging(int x, int y, int direction,
1575 int graphic1 = el_act_dir2img(GfxElement[x][y], ACTION_DIGGING, direction);
1576 int graphic2 = el_act_dir2crm(GfxElement[x][y], ACTION_DIGGING, direction);
1577 int frame1 = getGraphicAnimationFrame(graphic1, step_frame);
1578 int frame2 = getGraphicAnimationFrame(graphic2, step_frame);
1579 int sx = SCREENX(x), sy = SCREENY(y);
1581 DrawGraphic(sx, sy, graphic1, frame1);
1582 DrawLevelFieldCrumbledSandExt(x, y, graphic2, frame2);
1585 void DrawLevelFieldCrumbledSandNeighbours(int x, int y)
1587 int sx = SCREENX(x), sy = SCREENY(y);
1588 static int xy[4][2] =
1597 for (i = 0; i < 4; i++)
1599 int xx = x + xy[i][0];
1600 int yy = y + xy[i][1];
1601 int sxx = sx + xy[i][0];
1602 int syy = sy + xy[i][1];
1604 if (!IN_LEV_FIELD(xx, yy) ||
1605 !IN_SCR_FIELD(sxx, syy) ||
1606 !GFX_CRUMBLED(Feld[xx][yy]) ||
1610 DrawLevelField(xx, yy);
1614 static int getBorderElement(int x, int y)
1618 { EL_STEELWALL_TOPLEFT, EL_INVISIBLE_STEELWALL_TOPLEFT },
1619 { EL_STEELWALL_TOPRIGHT, EL_INVISIBLE_STEELWALL_TOPRIGHT },
1620 { EL_STEELWALL_BOTTOMLEFT, EL_INVISIBLE_STEELWALL_BOTTOMLEFT },
1621 { EL_STEELWALL_BOTTOMRIGHT, EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
1622 { EL_STEELWALL_VERTICAL, EL_INVISIBLE_STEELWALL_VERTICAL },
1623 { EL_STEELWALL_HORIZONTAL, EL_INVISIBLE_STEELWALL_HORIZONTAL },
1624 { EL_STEELWALL, EL_INVISIBLE_STEELWALL }
1626 int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
1627 int steel_position = (x == -1 && y == -1 ? 0 :
1628 x == lev_fieldx && y == -1 ? 1 :
1629 x == -1 && y == lev_fieldy ? 2 :
1630 x == lev_fieldx && y == lev_fieldy ? 3 :
1631 x == -1 || x == lev_fieldx ? 4 :
1632 y == -1 || y == lev_fieldy ? 5 : 6);
1634 return border[steel_position][steel_type];
1637 void DrawScreenElement(int x, int y, int element)
1639 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
1640 DrawLevelFieldCrumbledSand(LEVELX(x), LEVELY(y));
1643 void DrawLevelElement(int x, int y, int element)
1645 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1646 DrawScreenElement(SCREENX(x), SCREENY(y), element);
1649 void DrawScreenField(int x, int y)
1651 int lx = LEVELX(x), ly = LEVELY(y);
1652 int element, content;
1654 if (!IN_LEV_FIELD(lx, ly))
1656 if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
1659 element = getBorderElement(lx, ly);
1661 DrawScreenElement(x, y, element);
1666 element = Feld[lx][ly];
1667 content = Store[lx][ly];
1669 if (IS_MOVING(lx, ly))
1671 int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
1672 boolean cut_mode = NO_CUTTING;
1674 if (element == EL_QUICKSAND_EMPTYING ||
1675 element == EL_QUICKSAND_FAST_EMPTYING ||
1676 element == EL_MAGIC_WALL_EMPTYING ||
1677 element == EL_BD_MAGIC_WALL_EMPTYING ||
1678 element == EL_DC_MAGIC_WALL_EMPTYING ||
1679 element == EL_AMOEBA_DROPPING)
1680 cut_mode = CUT_ABOVE;
1681 else if (element == EL_QUICKSAND_FILLING ||
1682 element == EL_QUICKSAND_FAST_FILLING ||
1683 element == EL_MAGIC_WALL_FILLING ||
1684 element == EL_BD_MAGIC_WALL_FILLING ||
1685 element == EL_DC_MAGIC_WALL_FILLING)
1686 cut_mode = CUT_BELOW;
1689 if (lx == 9 && ly == 1)
1690 printf("::: %s [%d] [%d, %d] [%d]\n",
1691 EL_NAME(TILE_GFX_ELEMENT(lx, ly)),
1692 el_act2crm(TILE_GFX_ELEMENT(lx, ly), ACTION_DEFAULT),
1693 element_info[EL_QUICKSAND_EMPTYING].graphic[ACTION_DEFAULT],
1694 element_info[EL_QUICKSAND_EMPTYING].crumbled[ACTION_DEFAULT],
1695 GFX_CRUMBLED(TILE_GFX_ELEMENT(lx, ly)));
1698 if (cut_mode == CUT_ABOVE)
1700 DrawScreenElement(x, y, element);
1702 DrawScreenElementShifted(x, y, 0, 0, element, NO_CUTTING);
1705 DrawScreenElement(x, y, EL_EMPTY);
1708 DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
1709 else if (cut_mode == NO_CUTTING)
1710 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
1713 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
1716 if (cut_mode == CUT_BELOW &&
1717 IN_LEV_FIELD(lx, ly + 1) && IN_SCR_FIELD(x, y + 1))
1718 DrawLevelElement(lx, ly + 1, element);
1722 if (content == EL_ACID)
1724 int dir = MovDir[lx][ly];
1725 int newlx = lx + (dir == MV_LEFT ? -1 : dir == MV_RIGHT ? +1 : 0);
1726 int newly = ly + (dir == MV_UP ? -1 : dir == MV_DOWN ? +1 : 0);
1728 DrawLevelElementThruMask(newlx, newly, EL_ACID);
1731 else if (IS_BLOCKED(lx, ly))
1736 boolean cut_mode = NO_CUTTING;
1737 int element_old, content_old;
1739 Blocked2Moving(lx, ly, &oldx, &oldy);
1742 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
1743 MovDir[oldx][oldy] == MV_RIGHT);
1745 element_old = Feld[oldx][oldy];
1746 content_old = Store[oldx][oldy];
1748 if (element_old == EL_QUICKSAND_EMPTYING ||
1749 element_old == EL_QUICKSAND_FAST_EMPTYING ||
1750 element_old == EL_MAGIC_WALL_EMPTYING ||
1751 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
1752 element_old == EL_DC_MAGIC_WALL_EMPTYING ||
1753 element_old == EL_AMOEBA_DROPPING)
1754 cut_mode = CUT_ABOVE;
1756 DrawScreenElement(x, y, EL_EMPTY);
1759 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
1761 else if (cut_mode == NO_CUTTING)
1762 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
1765 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
1768 else if (IS_DRAWABLE(element))
1769 DrawScreenElement(x, y, element);
1771 DrawScreenElement(x, y, EL_EMPTY);
1774 void DrawLevelField(int x, int y)
1776 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1777 DrawScreenField(SCREENX(x), SCREENY(y));
1778 else if (IS_MOVING(x, y))
1782 Moving2Blocked(x, y, &newx, &newy);
1783 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
1784 DrawScreenField(SCREENX(newx), SCREENY(newy));
1786 else if (IS_BLOCKED(x, y))
1790 Blocked2Moving(x, y, &oldx, &oldy);
1791 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
1792 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
1796 void DrawMiniElement(int x, int y, int element)
1800 graphic = el2edimg(element);
1801 DrawMiniGraphic(x, y, graphic);
1804 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
1806 int x = sx + scroll_x, y = sy + scroll_y;
1808 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
1809 DrawMiniElement(sx, sy, EL_EMPTY);
1810 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
1811 DrawMiniElement(sx, sy, Feld[x][y]);
1813 DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
1816 void DrawEnvelopeBackground(int envelope_nr, int startx, int starty,
1817 int x, int y, int xsize, int ysize, int font_nr)
1819 int font_width = getFontWidth(font_nr);
1820 int font_height = getFontHeight(font_nr);
1821 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1824 int dst_x = SX + startx + x * font_width;
1825 int dst_y = SY + starty + y * font_height;
1826 int width = graphic_info[graphic].width;
1827 int height = graphic_info[graphic].height;
1828 int inner_width = MAX(width - 2 * font_width, font_width);
1829 int inner_height = MAX(height - 2 * font_height, font_height);
1830 int inner_sx = (width >= 3 * font_width ? font_width : 0);
1831 int inner_sy = (height >= 3 * font_height ? font_height : 0);
1832 boolean draw_masked = graphic_info[graphic].draw_masked;
1834 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1836 if (src_bitmap == NULL || width < font_width || height < font_height)
1838 ClearRectangle(drawto, dst_x, dst_y, font_width, font_height);
1842 src_x += (x == 0 ? 0 : x == xsize - 1 ? width - font_width :
1843 inner_sx + (x - 1) * font_width % inner_width);
1844 src_y += (y == 0 ? 0 : y == ysize - 1 ? height - font_height :
1845 inner_sy + (y - 1) * font_height % inner_height);
1849 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1850 dst_x - src_x, dst_y - src_y);
1851 BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1855 BlitBitmap(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1859 void AnimateEnvelope(int envelope_nr, int anim_mode, int action)
1861 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1862 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1863 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
1864 boolean ffwd_delay = (tape.playing && tape.fast_forward);
1865 boolean no_delay = (tape.warp_forward);
1866 unsigned long anim_delay = 0;
1867 int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
1868 int anim_delay_value = (no_delay ? 0 : frame_delay_value);
1869 int font_nr = FONT_ENVELOPE_1 + envelope_nr;
1870 int font_width = getFontWidth(font_nr);
1871 int font_height = getFontHeight(font_nr);
1872 int max_xsize = level.envelope[envelope_nr].xsize;
1873 int max_ysize = level.envelope[envelope_nr].ysize;
1874 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
1875 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
1876 int xend = max_xsize;
1877 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
1878 int xstep = (xstart < xend ? 1 : 0);
1879 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
1882 for (x = xstart, y = ystart; x <= xend && y <= yend; x += xstep, y += ystep)
1884 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
1885 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
1886 int sx = (SXSIZE - xsize * font_width) / 2;
1887 int sy = (SYSIZE - ysize * font_height) / 2;
1890 SetDrawtoField(DRAW_BUFFERED);
1892 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
1894 SetDrawtoField(DRAW_BACKBUFFER);
1896 for (yy = 0; yy < ysize; yy++) for (xx = 0; xx < xsize; xx++)
1897 DrawEnvelopeBackground(envelope_nr, sx,sy, xx,yy, xsize, ysize, font_nr);
1900 DrawTextBuffer(SX + sx + font_width, SY + sy + font_height,
1901 level.envelope[envelope_nr].text, font_nr, max_xsize,
1902 xsize - 2, ysize - 2, mask_mode,
1903 level.envelope[envelope_nr].autowrap,
1904 level.envelope[envelope_nr].centered, FALSE);
1906 DrawTextToTextArea(SX + sx + font_width, SY + sy + font_height,
1907 level.envelope[envelope_nr].text, font_nr, max_xsize,
1908 xsize - 2, ysize - 2, mask_mode);
1911 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
1914 WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
1918 void ShowEnvelope(int envelope_nr)
1920 int element = EL_ENVELOPE_1 + envelope_nr;
1921 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1922 int sound_opening = element_info[element].sound[ACTION_OPENING];
1923 int sound_closing = element_info[element].sound[ACTION_CLOSING];
1924 boolean ffwd_delay = (tape.playing && tape.fast_forward);
1925 boolean no_delay = (tape.warp_forward);
1926 int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
1927 int wait_delay_value = (no_delay ? 0 : normal_delay_value);
1928 int anim_mode = graphic_info[graphic].anim_mode;
1929 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
1930 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
1932 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
1934 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
1936 if (anim_mode == ANIM_DEFAULT)
1937 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_OPENING);
1939 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_OPENING);
1942 Delay(wait_delay_value);
1944 WaitForEventToContinue();
1946 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
1948 if (anim_mode != ANIM_NONE)
1949 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_CLOSING);
1951 if (anim_mode == ANIM_DEFAULT)
1952 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_CLOSING);
1954 game.envelope_active = FALSE;
1956 SetDrawtoField(DRAW_BUFFERED);
1958 redraw_mask |= REDRAW_FIELD;
1962 void DrawPreviewElement(int dst_x, int dst_y, int element, int tilesize)
1966 int graphic = el2preimg(element);
1968 getSizedGraphicSource(graphic, 0, tilesize, &src_bitmap, &src_x, &src_y);
1969 BlitBitmap(src_bitmap, drawto, src_x, src_y, tilesize, tilesize, dst_x,dst_y);
1977 SetMainBackgroundImage(IMG_BACKGROUND_PLAYING);
1978 SetDrawBackgroundMask(REDRAW_FIELD);
1980 SetDrawBackgroundMask(REDRAW_NONE);
1985 for (x = BX1; x <= BX2; x++)
1986 for (y = BY1; y <= BY2; y++)
1987 DrawScreenField(x, y);
1989 redraw_mask |= REDRAW_FIELD;
1992 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
1996 for (x = 0; x < size_x; x++)
1997 for (y = 0; y < size_y; y++)
1998 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
2000 redraw_mask |= REDRAW_FIELD;
2003 static void DrawPreviewLevelExt(int from_x, int from_y)
2005 boolean show_level_border = (BorderElement != EL_EMPTY);
2006 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
2007 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
2008 int tile_size = preview.tile_size;
2009 int preview_width = preview.xsize * tile_size;
2010 int preview_height = preview.ysize * tile_size;
2011 int real_preview_xsize = MIN(level_xsize, preview.xsize);
2012 int real_preview_ysize = MIN(level_ysize, preview.ysize);
2013 int dst_x = SX + ALIGNED_XPOS(preview.x, preview_width, preview.align);
2014 int dst_y = SY + ALIGNED_YPOS(preview.y, preview_height, preview.valign);
2017 DrawBackground(dst_x, dst_y, preview_width, preview_height);
2019 dst_x += (preview_width - real_preview_xsize * tile_size) / 2;
2020 dst_y += (preview_height - real_preview_ysize * tile_size) / 2;
2022 for (x = 0; x < real_preview_xsize; x++)
2024 for (y = 0; y < real_preview_ysize; y++)
2026 int lx = from_x + x + (show_level_border ? -1 : 0);
2027 int ly = from_y + y + (show_level_border ? -1 : 0);
2028 int element = (IN_LEV_FIELD(lx, ly) ? level.field[lx][ly] :
2029 getBorderElement(lx, ly));
2031 DrawPreviewElement(dst_x + x * tile_size, dst_y + y * tile_size,
2032 element, tile_size);
2036 redraw_mask |= REDRAW_MICROLEVEL;
2039 #define MICROLABEL_EMPTY 0
2040 #define MICROLABEL_LEVEL_NAME 1
2041 #define MICROLABEL_LEVEL_AUTHOR_HEAD 2
2042 #define MICROLABEL_LEVEL_AUTHOR 3
2043 #define MICROLABEL_IMPORTED_FROM_HEAD 4
2044 #define MICROLABEL_IMPORTED_FROM 5
2045 #define MICROLABEL_IMPORTED_BY_HEAD 6
2046 #define MICROLABEL_IMPORTED_BY 7
2048 static int getMaxTextLength(struct TextPosInfo *pos, int font_nr)
2050 int max_text_width = SXSIZE;
2051 int font_width = getFontWidth(font_nr);
2053 if (pos->align == ALIGN_CENTER)
2054 max_text_width = (pos->x < SXSIZE / 2 ? pos->x * 2 : (SXSIZE - pos->x) * 2);
2055 else if (pos->align == ALIGN_RIGHT)
2056 max_text_width = pos->x;
2058 max_text_width = SXSIZE - pos->x;
2060 return max_text_width / font_width;
2063 static void DrawPreviewLevelLabelExt(int mode)
2065 struct TextPosInfo *pos = &menu.main.text.level_info_2;
2066 char label_text[MAX_OUTPUT_LINESIZE + 1];
2067 int max_len_label_text;
2069 int font_nr = pos->font;
2072 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
2073 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
2074 mode == MICROLABEL_IMPORTED_BY_HEAD)
2075 font_nr = pos->font_alt;
2077 int font_nr = FONT_TEXT_2;
2080 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
2081 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
2082 mode == MICROLABEL_IMPORTED_BY_HEAD)
2083 font_nr = FONT_TEXT_3;
2087 max_len_label_text = getMaxTextLength(pos, font_nr);
2089 max_len_label_text = SXSIZE / getFontWidth(font_nr);
2093 if (pos->size != -1)
2094 max_len_label_text = pos->size;
2097 for (i = 0; i < max_len_label_text; i++)
2098 label_text[i] = ' ';
2099 label_text[max_len_label_text] = '\0';
2101 if (strlen(label_text) > 0)
2104 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2106 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
2107 int lypos = MICROLABEL2_YPOS;
2109 DrawText(lxpos, lypos, label_text, font_nr);
2114 (mode == MICROLABEL_LEVEL_NAME ? level.name :
2115 mode == MICROLABEL_LEVEL_AUTHOR_HEAD ? "created by" :
2116 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
2117 mode == MICROLABEL_IMPORTED_FROM_HEAD ? "imported from" :
2118 mode == MICROLABEL_IMPORTED_FROM ? leveldir_current->imported_from :
2119 mode == MICROLABEL_IMPORTED_BY_HEAD ? "imported by" :
2120 mode == MICROLABEL_IMPORTED_BY ? leveldir_current->imported_by :""),
2121 max_len_label_text);
2122 label_text[max_len_label_text] = '\0';
2124 if (strlen(label_text) > 0)
2127 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2129 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
2130 int lypos = MICROLABEL2_YPOS;
2132 DrawText(lxpos, lypos, label_text, font_nr);
2136 redraw_mask |= REDRAW_MICROLEVEL;
2139 void DrawPreviewLevel(boolean restart)
2141 static unsigned long scroll_delay = 0;
2142 static unsigned long label_delay = 0;
2143 static int from_x, from_y, scroll_direction;
2144 static int label_state, label_counter;
2145 unsigned long scroll_delay_value = preview.step_delay;
2146 boolean show_level_border = (BorderElement != EL_EMPTY);
2147 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
2148 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
2149 int last_game_status = game_status; /* save current game status */
2152 /* force PREVIEW font on preview level */
2153 game_status = GAME_MODE_PSEUDO_PREVIEW;
2161 if (preview.anim_mode == ANIM_CENTERED)
2163 if (level_xsize > preview.xsize)
2164 from_x = (level_xsize - preview.xsize) / 2;
2165 if (level_ysize > preview.ysize)
2166 from_y = (level_ysize - preview.ysize) / 2;
2169 from_x += preview.xoffset;
2170 from_y += preview.yoffset;
2172 scroll_direction = MV_RIGHT;
2176 DrawPreviewLevelExt(from_x, from_y);
2177 DrawPreviewLevelLabelExt(label_state);
2179 /* initialize delay counters */
2180 DelayReached(&scroll_delay, 0);
2181 DelayReached(&label_delay, 0);
2183 if (leveldir_current->name)
2185 struct TextPosInfo *pos = &menu.main.text.level_info_1;
2186 char label_text[MAX_OUTPUT_LINESIZE + 1];
2188 int font_nr = pos->font;
2190 int font_nr = FONT_TEXT_1;
2193 int max_len_label_text = getMaxTextLength(pos, font_nr);
2195 int max_len_label_text = SXSIZE / getFontWidth(font_nr);
2203 if (pos->size != -1)
2204 max_len_label_text = pos->size;
2207 strncpy(label_text, leveldir_current->name, max_len_label_text);
2208 label_text[max_len_label_text] = '\0';
2211 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2213 lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
2214 lypos = SY + MICROLABEL1_YPOS;
2216 DrawText(lxpos, lypos, label_text, font_nr);
2220 game_status = last_game_status; /* restore current game status */
2225 /* scroll preview level, if needed */
2226 if (preview.anim_mode != ANIM_NONE &&
2227 (level_xsize > preview.xsize || level_ysize > preview.ysize) &&
2228 DelayReached(&scroll_delay, scroll_delay_value))
2230 switch (scroll_direction)
2235 from_x -= preview.step_offset;
2236 from_x = (from_x < 0 ? 0 : from_x);
2239 scroll_direction = MV_UP;
2243 if (from_x < level_xsize - preview.xsize)
2245 from_x += preview.step_offset;
2246 from_x = (from_x > level_xsize - preview.xsize ?
2247 level_xsize - preview.xsize : from_x);
2250 scroll_direction = MV_DOWN;
2256 from_y -= preview.step_offset;
2257 from_y = (from_y < 0 ? 0 : from_y);
2260 scroll_direction = MV_RIGHT;
2264 if (from_y < level_ysize - preview.ysize)
2266 from_y += preview.step_offset;
2267 from_y = (from_y > level_ysize - preview.ysize ?
2268 level_ysize - preview.ysize : from_y);
2271 scroll_direction = MV_LEFT;
2278 DrawPreviewLevelExt(from_x, from_y);
2281 /* !!! THIS ALL SUCKS -- SHOULD BE CLEANLY REWRITTEN !!! */
2282 /* redraw micro level label, if needed */
2283 if (!strEqual(level.name, NAMELESS_LEVEL_NAME) &&
2284 !strEqual(level.author, ANONYMOUS_NAME) &&
2285 !strEqual(level.author, leveldir_current->name) &&
2286 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
2288 int max_label_counter = 23;
2290 if (leveldir_current->imported_from != NULL &&
2291 strlen(leveldir_current->imported_from) > 0)
2292 max_label_counter += 14;
2293 if (leveldir_current->imported_by != NULL &&
2294 strlen(leveldir_current->imported_by) > 0)
2295 max_label_counter += 14;
2297 label_counter = (label_counter + 1) % max_label_counter;
2298 label_state = (label_counter >= 0 && label_counter <= 7 ?
2299 MICROLABEL_LEVEL_NAME :
2300 label_counter >= 9 && label_counter <= 12 ?
2301 MICROLABEL_LEVEL_AUTHOR_HEAD :
2302 label_counter >= 14 && label_counter <= 21 ?
2303 MICROLABEL_LEVEL_AUTHOR :
2304 label_counter >= 23 && label_counter <= 26 ?
2305 MICROLABEL_IMPORTED_FROM_HEAD :
2306 label_counter >= 28 && label_counter <= 35 ?
2307 MICROLABEL_IMPORTED_FROM :
2308 label_counter >= 37 && label_counter <= 40 ?
2309 MICROLABEL_IMPORTED_BY_HEAD :
2310 label_counter >= 42 && label_counter <= 49 ?
2311 MICROLABEL_IMPORTED_BY : MICROLABEL_EMPTY);
2313 if (leveldir_current->imported_from == NULL &&
2314 (label_state == MICROLABEL_IMPORTED_FROM_HEAD ||
2315 label_state == MICROLABEL_IMPORTED_FROM))
2316 label_state = (label_state == MICROLABEL_IMPORTED_FROM_HEAD ?
2317 MICROLABEL_IMPORTED_BY_HEAD : MICROLABEL_IMPORTED_BY);
2319 DrawPreviewLevelLabelExt(label_state);
2322 game_status = last_game_status; /* restore current game status */
2325 inline void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
2326 int graphic, int sync_frame, int mask_mode)
2328 int frame = getGraphicAnimationFrame(graphic, sync_frame);
2330 if (mask_mode == USE_MASKING)
2331 DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
2333 DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
2336 inline void DrawGraphicAnimation(int x, int y, int graphic)
2338 int lx = LEVELX(x), ly = LEVELY(y);
2340 if (!IN_SCR_FIELD(x, y))
2343 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
2344 graphic, GfxFrame[lx][ly], NO_MASKING);
2345 MarkTileDirty(x, y);
2348 void DrawLevelGraphicAnimation(int x, int y, int graphic)
2350 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
2353 void DrawLevelElementAnimation(int x, int y, int element)
2355 int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
2357 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
2360 inline void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
2362 int sx = SCREENX(x), sy = SCREENY(y);
2364 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
2367 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
2370 DrawGraphicAnimation(sx, sy, graphic);
2373 if (GFX_CRUMBLED(TILE_GFX_ELEMENT(x, y)))
2374 DrawLevelFieldCrumbledSand(x, y);
2376 if (GFX_CRUMBLED(Feld[x][y]))
2377 DrawLevelFieldCrumbledSand(x, y);
2381 void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
2383 int sx = SCREENX(x), sy = SCREENY(y);
2386 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
2389 graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
2391 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
2394 DrawGraphicAnimation(sx, sy, graphic);
2396 if (GFX_CRUMBLED(element))
2397 DrawLevelFieldCrumbledSand(x, y);
2400 static int getPlayerGraphic(struct PlayerInfo *player, int move_dir)
2402 if (player->use_murphy)
2404 /* this works only because currently only one player can be "murphy" ... */
2405 static int last_horizontal_dir = MV_LEFT;
2406 int graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir);
2408 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
2409 last_horizontal_dir = move_dir;
2411 if (graphic == IMG_SP_MURPHY) /* undefined => use special graphic */
2413 int direction = (player->is_snapping ? move_dir : last_horizontal_dir);
2415 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
2421 return el_act_dir2img(player->artwork_element, player->GfxAction,move_dir);
2424 static boolean equalGraphics(int graphic1, int graphic2)
2426 struct GraphicInfo *g1 = &graphic_info[graphic1];
2427 struct GraphicInfo *g2 = &graphic_info[graphic2];
2429 return (g1->bitmap == g2->bitmap &&
2430 g1->src_x == g2->src_x &&
2431 g1->src_y == g2->src_y &&
2432 g1->anim_frames == g2->anim_frames &&
2433 g1->anim_delay == g2->anim_delay &&
2434 g1->anim_mode == g2->anim_mode);
2437 void DrawAllPlayers()
2441 for (i = 0; i < MAX_PLAYERS; i++)
2442 if (stored_player[i].active)
2443 DrawPlayer(&stored_player[i]);
2446 void DrawPlayerField(int x, int y)
2448 if (!IS_PLAYER(x, y))
2451 DrawPlayer(PLAYERINFO(x, y));
2454 void DrawPlayer(struct PlayerInfo *player)
2456 int jx = player->jx;
2457 int jy = player->jy;
2458 int move_dir = player->MovDir;
2459 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? +1 : 0);
2460 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? +1 : 0);
2461 int last_jx = (player->is_moving ? jx - dx : jx);
2462 int last_jy = (player->is_moving ? jy - dy : jy);
2463 int next_jx = jx + dx;
2464 int next_jy = jy + dy;
2465 boolean player_is_moving = (player->MovPos ? TRUE : FALSE);
2466 boolean player_is_opaque = FALSE;
2467 int sx = SCREENX(jx), sy = SCREENY(jy);
2468 int sxx = 0, syy = 0;
2469 int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
2471 int action = ACTION_DEFAULT;
2472 int last_player_graphic = getPlayerGraphic(player, move_dir);
2473 int last_player_frame = player->Frame;
2476 /* GfxElement[][] is set to the element the player is digging or collecting;
2477 remove also for off-screen player if the player is not moving anymore */
2478 if (IN_LEV_FIELD(jx, jy) && !player_is_moving)
2479 GfxElement[jx][jy] = EL_UNDEFINED;
2481 if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
2485 if (!IN_LEV_FIELD(jx, jy))
2487 printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
2488 printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
2489 printf("DrawPlayerField(): This should never happen!\n");
2494 if (element == EL_EXPLOSION)
2497 action = (player->is_pushing ? ACTION_PUSHING :
2498 player->is_digging ? ACTION_DIGGING :
2499 player->is_collecting ? ACTION_COLLECTING :
2500 player->is_moving ? ACTION_MOVING :
2501 player->is_snapping ? ACTION_SNAPPING :
2502 player->is_dropping ? ACTION_DROPPING :
2503 player->is_waiting ? player->action_waiting : ACTION_DEFAULT);
2505 if (player->is_waiting)
2506 move_dir = player->dir_waiting;
2508 InitPlayerGfxAnimation(player, action, move_dir);
2510 /* ----------------------------------------------------------------------- */
2511 /* draw things in the field the player is leaving, if needed */
2512 /* ----------------------------------------------------------------------- */
2514 if (player->is_moving)
2516 if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
2518 DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
2520 if (last_element == EL_DYNAMITE_ACTIVE ||
2521 last_element == EL_EM_DYNAMITE_ACTIVE ||
2522 last_element == EL_SP_DISK_RED_ACTIVE)
2523 DrawDynamite(last_jx, last_jy);
2525 DrawLevelFieldThruMask(last_jx, last_jy);
2527 else if (last_element == EL_DYNAMITE_ACTIVE ||
2528 last_element == EL_EM_DYNAMITE_ACTIVE ||
2529 last_element == EL_SP_DISK_RED_ACTIVE)
2530 DrawDynamite(last_jx, last_jy);
2532 /* !!! this is not enough to prevent flickering of players which are
2533 moving next to each others without a free tile between them -- this
2534 can only be solved by drawing all players layer by layer (first the
2535 background, then the foreground etc.) !!! => TODO */
2536 else if (!IS_PLAYER(last_jx, last_jy))
2537 DrawLevelField(last_jx, last_jy);
2540 DrawLevelField(last_jx, last_jy);
2543 if (player->is_pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
2544 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
2547 if (!IN_SCR_FIELD(sx, sy))
2550 /* ----------------------------------------------------------------------- */
2551 /* draw things behind the player, if needed */
2552 /* ----------------------------------------------------------------------- */
2555 DrawLevelElement(jx, jy, Back[jx][jy]);
2556 else if (IS_ACTIVE_BOMB(element))
2557 DrawLevelElement(jx, jy, EL_EMPTY);
2560 if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
2562 int old_element = GfxElement[jx][jy];
2563 int old_graphic = el_act_dir2img(old_element, action, move_dir);
2564 int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
2566 if (GFX_CRUMBLED(old_element))
2567 DrawLevelFieldCrumbledSandDigging(jx, jy, move_dir, player->StepFrame);
2569 DrawGraphic(sx, sy, old_graphic, frame);
2571 if (graphic_info[old_graphic].anim_mode & ANIM_OPAQUE_PLAYER)
2572 player_is_opaque = TRUE;
2576 GfxElement[jx][jy] = EL_UNDEFINED;
2578 /* make sure that pushed elements are drawn with correct frame rate */
2580 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
2582 if (player->is_pushing && player->is_moving && !IS_ANIM_MODE_CE(graphic))
2583 GfxFrame[jx][jy] = player->StepFrame;
2585 if (player->is_pushing && player->is_moving)
2586 GfxFrame[jx][jy] = player->StepFrame;
2589 DrawLevelField(jx, jy);
2593 /* ----------------------------------------------------------------------- */
2594 /* draw player himself */
2595 /* ----------------------------------------------------------------------- */
2597 graphic = getPlayerGraphic(player, move_dir);
2599 /* in the case of changed player action or direction, prevent the current
2600 animation frame from being restarted for identical animations */
2601 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
2602 player->Frame = last_player_frame;
2604 frame = getGraphicAnimationFrame(graphic, player->Frame);
2608 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
2609 sxx = player->GfxPos;
2611 syy = player->GfxPos;
2614 if (!setup.soft_scrolling && ScreenMovPos)
2617 if (player_is_opaque)
2618 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
2620 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
2622 if (SHIELD_ON(player))
2624 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
2625 IMG_SHIELD_NORMAL_ACTIVE);
2626 int frame = getGraphicAnimationFrame(graphic, -1);
2628 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
2631 /* ----------------------------------------------------------------------- */
2632 /* draw things the player is pushing, if needed */
2633 /* ----------------------------------------------------------------------- */
2636 printf("::: %d, %d [%d, %d] [%d]\n",
2637 player->is_pushing, player_is_moving, player->GfxAction,
2638 player->is_moving, player_is_moving);
2642 if (player->is_pushing && player->is_moving)
2644 int px = SCREENX(jx), py = SCREENY(jy);
2645 int pxx = (TILEX - ABS(sxx)) * dx;
2646 int pyy = (TILEY - ABS(syy)) * dy;
2647 int gfx_frame = GfxFrame[jx][jy];
2653 if (!IS_MOVING(jx, jy)) /* push movement already finished */
2655 element = Feld[next_jx][next_jy];
2656 gfx_frame = GfxFrame[next_jx][next_jy];
2659 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
2662 sync_frame = (IS_ANIM_MODE_CE(graphic) ? gfx_frame : player->StepFrame);
2663 frame = getGraphicAnimationFrame(graphic, sync_frame);
2665 frame = getGraphicAnimationFrame(graphic, player->StepFrame);
2668 /* draw background element under pushed element (like the Sokoban field) */
2669 if (Back[next_jx][next_jy])
2670 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
2672 /* masked drawing is needed for EMC style (double) movement graphics */
2673 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
2677 /* ----------------------------------------------------------------------- */
2678 /* draw things in front of player (active dynamite or dynabombs) */
2679 /* ----------------------------------------------------------------------- */
2681 if (IS_ACTIVE_BOMB(element))
2683 graphic = el2img(element);
2684 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
2686 if (game.emulation == EMU_SUPAPLEX)
2687 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
2689 DrawGraphicThruMask(sx, sy, graphic, frame);
2692 if (player_is_moving && last_element == EL_EXPLOSION)
2694 int element = (GfxElement[last_jx][last_jy] != EL_UNDEFINED ?
2695 GfxElement[last_jx][last_jy] : EL_EMPTY);
2696 int graphic = el_act2img(element, ACTION_EXPLODING);
2697 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
2698 int phase = ExplodePhase[last_jx][last_jy] - 1;
2699 int frame = getGraphicAnimationFrame(graphic, phase - delay);
2702 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
2705 /* ----------------------------------------------------------------------- */
2706 /* draw elements the player is just walking/passing through/under */
2707 /* ----------------------------------------------------------------------- */
2709 if (player_is_moving)
2711 /* handle the field the player is leaving ... */
2712 if (IS_ACCESSIBLE_INSIDE(last_element))
2713 DrawLevelField(last_jx, last_jy);
2714 else if (IS_ACCESSIBLE_UNDER(last_element))
2715 DrawLevelFieldThruMask(last_jx, last_jy);
2718 /* do not redraw accessible elements if the player is just pushing them */
2719 if (!player_is_moving || !player->is_pushing)
2721 /* ... and the field the player is entering */
2722 if (IS_ACCESSIBLE_INSIDE(element))
2723 DrawLevelField(jx, jy);
2724 else if (IS_ACCESSIBLE_UNDER(element))
2725 DrawLevelFieldThruMask(jx, jy);
2728 MarkTileDirty(sx, sy);
2731 /* ------------------------------------------------------------------------- */
2733 void WaitForEventToContinue()
2735 boolean still_wait = TRUE;
2737 /* simulate releasing mouse button over last gadget, if still pressed */
2739 HandleGadgets(-1, -1, 0);
2741 button_status = MB_RELEASED;
2757 case EVENT_BUTTONPRESS:
2758 case EVENT_KEYPRESS:
2762 case EVENT_KEYRELEASE:
2763 ClearPlayerAction();
2767 HandleOtherEvents(&event);
2771 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2778 /* don't eat all CPU time */
2783 #define MAX_REQUEST_LINES 13
2784 #define MAX_REQUEST_LINE_FONT1_LEN 7
2785 #define MAX_REQUEST_LINE_FONT2_LEN 10
2787 boolean Request(char *text, unsigned int req_state)
2789 int mx, my, ty, result = -1;
2790 unsigned int old_door_state;
2791 int last_game_status = game_status; /* save current game status */
2792 int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
2793 int font_nr = FONT_TEXT_2;
2794 int max_word_len = 0;
2797 for (text_ptr = text; *text_ptr; text_ptr++)
2799 max_word_len = (*text_ptr != ' ' ? max_word_len + 1 : 0);
2801 if (max_word_len > MAX_REQUEST_LINE_FONT1_LEN)
2803 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
2805 font_nr = FONT_TEXT_1;
2807 font_nr = FONT_LEVEL_NUMBER;
2814 if (game_status == GAME_MODE_PLAYING &&
2815 level.game_engine_type == GAME_ENGINE_TYPE_EM)
2816 BlitScreenToBitmap_EM(backbuffer);
2818 /* disable deactivated drawing when quick-loading level tape recording */
2819 if (tape.playing && tape.deactivate_display)
2820 TapeDeactivateDisplayOff(TRUE);
2822 SetMouseCursor(CURSOR_DEFAULT);
2824 #if defined(NETWORK_AVALIABLE)
2825 /* pause network game while waiting for request to answer */
2826 if (options.network &&
2827 game_status == GAME_MODE_PLAYING &&
2828 req_state & REQUEST_WAIT_FOR_INPUT)
2829 SendToServer_PausePlaying();
2832 old_door_state = GetDoorState();
2834 /* simulate releasing mouse button over last gadget, if still pressed */
2836 HandleGadgets(-1, -1, 0);
2840 if (old_door_state & DOOR_OPEN_1)
2842 CloseDoor(DOOR_CLOSE_1);
2844 /* save old door content */
2845 BlitBitmap(bitmap_db_door, bitmap_db_door,
2846 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
2847 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
2851 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
2854 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2856 /* clear door drawing field */
2857 DrawBackground(DX, DY, DXSIZE, DYSIZE);
2859 /* force DOOR font inside door area */
2860 game_status = GAME_MODE_PSEUDO_DOOR;
2862 /* write text for request */
2863 for (ty = 0; ty < MAX_REQUEST_LINES; ty++)
2865 char text_line[max_request_line_len + 1];
2871 for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
2874 if (!tc || tc == ' ')
2885 strncpy(text_line, text, tl);
2888 DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
2889 DY + 8 + ty * (getFontHeight(font_nr) + 2),
2890 text_line, font_nr);
2892 text += tl + (tc == ' ' ? 1 : 0);
2895 game_status = last_game_status; /* restore current game status */
2897 if (req_state & REQ_ASK)
2899 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
2900 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
2902 else if (req_state & REQ_CONFIRM)
2904 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
2906 else if (req_state & REQ_PLAYER)
2908 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
2909 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
2910 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
2911 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
2914 /* copy request gadgets to door backbuffer */
2915 BlitBitmap(drawto, bitmap_db_door,
2916 DX, DY, DXSIZE, DYSIZE,
2917 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2919 OpenDoor(DOOR_OPEN_1);
2921 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
2923 if (game_status == GAME_MODE_PLAYING)
2925 SetPanelBackground();
2926 SetDrawBackgroundMask(REDRAW_DOOR_1);
2930 SetDrawBackgroundMask(REDRAW_FIELD);
2936 if (game_status != GAME_MODE_MAIN)
2939 button_status = MB_RELEASED;
2941 request_gadget_id = -1;
2943 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2955 case EVENT_BUTTONPRESS:
2956 case EVENT_BUTTONRELEASE:
2957 case EVENT_MOTIONNOTIFY:
2959 if (event.type == EVENT_MOTIONNOTIFY)
2961 if (!PointerInWindow(window))
2962 continue; /* window and pointer are on different screens */
2967 motion_status = TRUE;
2968 mx = ((MotionEvent *) &event)->x;
2969 my = ((MotionEvent *) &event)->y;
2973 motion_status = FALSE;
2974 mx = ((ButtonEvent *) &event)->x;
2975 my = ((ButtonEvent *) &event)->y;
2976 if (event.type == EVENT_BUTTONPRESS)
2977 button_status = ((ButtonEvent *) &event)->button;
2979 button_status = MB_RELEASED;
2982 /* this sets 'request_gadget_id' */
2983 HandleGadgets(mx, my, button_status);
2985 switch (request_gadget_id)
2987 case TOOL_CTRL_ID_YES:
2990 case TOOL_CTRL_ID_NO:
2993 case TOOL_CTRL_ID_CONFIRM:
2994 result = TRUE | FALSE;
2997 case TOOL_CTRL_ID_PLAYER_1:
3000 case TOOL_CTRL_ID_PLAYER_2:
3003 case TOOL_CTRL_ID_PLAYER_3:
3006 case TOOL_CTRL_ID_PLAYER_4:
3017 case EVENT_KEYPRESS:
3018 switch (GetEventKey((KeyEvent *)&event, TRUE))
3021 if (req_state & REQ_CONFIRM)
3037 if (req_state & REQ_PLAYER)
3041 case EVENT_KEYRELEASE:
3042 ClearPlayerAction();
3046 HandleOtherEvents(&event);
3050 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
3052 int joy = AnyJoystick();
3054 if (joy & JOY_BUTTON_1)
3056 else if (joy & JOY_BUTTON_2)
3062 if (game_status == GAME_MODE_PLAYING && local_player->LevelSolved_GameEnd)
3064 HandleGameActions();
3070 if (!PendingEvent()) /* delay only if no pending events */
3081 if (!PendingEvent()) /* delay only if no pending events */
3084 /* don't eat all CPU time */
3091 if (game_status != GAME_MODE_MAIN)
3096 if (!(req_state & REQ_STAY_OPEN))
3098 CloseDoor(DOOR_CLOSE_1);
3100 if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
3101 (req_state & REQ_REOPEN))
3102 OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
3107 if (game_status == GAME_MODE_PLAYING)
3109 SetPanelBackground();
3110 SetDrawBackgroundMask(REDRAW_DOOR_1);
3114 SetDrawBackgroundMask(REDRAW_FIELD);
3117 #if defined(NETWORK_AVALIABLE)
3118 /* continue network game after request */
3119 if (options.network &&
3120 game_status == GAME_MODE_PLAYING &&
3121 req_state & REQUEST_WAIT_FOR_INPUT)
3122 SendToServer_ContinuePlaying();
3125 /* restore deactivated drawing when quick-loading level tape recording */
3126 if (tape.playing && tape.deactivate_display)
3127 TapeDeactivateDisplayOn();
3132 unsigned int OpenDoor(unsigned int door_state)
3134 if (door_state & DOOR_COPY_BACK)
3136 if (door_state & DOOR_OPEN_1)
3137 BlitBitmap(bitmap_db_door, bitmap_db_door,
3138 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
3139 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
3141 if (door_state & DOOR_OPEN_2)
3142 BlitBitmap(bitmap_db_door, bitmap_db_door,
3143 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY2, VXSIZE, VYSIZE,
3144 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
3146 door_state &= ~DOOR_COPY_BACK;
3149 return MoveDoor(door_state);
3152 unsigned int CloseDoor(unsigned int door_state)
3154 unsigned int old_door_state = GetDoorState();
3156 if (!(door_state & DOOR_NO_COPY_BACK))
3158 if (old_door_state & DOOR_OPEN_1)
3159 BlitBitmap(backbuffer, bitmap_db_door,
3160 DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
3162 if (old_door_state & DOOR_OPEN_2)
3163 BlitBitmap(backbuffer, bitmap_db_door,
3164 VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
3166 door_state &= ~DOOR_NO_COPY_BACK;
3169 return MoveDoor(door_state);
3172 unsigned int GetDoorState()
3174 return MoveDoor(DOOR_GET_STATE);
3177 unsigned int SetDoorState(unsigned int door_state)
3179 return MoveDoor(door_state | DOOR_SET_STATE);
3182 unsigned int MoveDoor(unsigned int door_state)
3184 static int door1 = DOOR_OPEN_1;
3185 static int door2 = DOOR_CLOSE_2;
3186 unsigned long door_delay = 0;
3187 unsigned long door_delay_value;
3190 if (door_1.width < 0 || door_1.width > DXSIZE)
3191 door_1.width = DXSIZE;
3192 if (door_1.height < 0 || door_1.height > DYSIZE)
3193 door_1.height = DYSIZE;
3194 if (door_2.width < 0 || door_2.width > VXSIZE)
3195 door_2.width = VXSIZE;
3196 if (door_2.height < 0 || door_2.height > VYSIZE)
3197 door_2.height = VYSIZE;
3199 if (door_state == DOOR_GET_STATE)
3200 return (door1 | door2);
3202 if (door_state & DOOR_SET_STATE)
3204 if (door_state & DOOR_ACTION_1)
3205 door1 = door_state & DOOR_ACTION_1;
3206 if (door_state & DOOR_ACTION_2)
3207 door2 = door_state & DOOR_ACTION_2;
3209 return (door1 | door2);
3212 if (!(door_state & DOOR_FORCE_REDRAW))
3214 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
3215 door_state &= ~DOOR_OPEN_1;
3216 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
3217 door_state &= ~DOOR_CLOSE_1;
3218 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
3219 door_state &= ~DOOR_OPEN_2;
3220 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
3221 door_state &= ~DOOR_CLOSE_2;
3224 door_delay_value = (door_state & DOOR_ACTION_1 ? door_1.step_delay :
3227 if (setup.quick_doors)
3229 stepsize = 20; /* must be chosen to always draw last frame */
3230 door_delay_value = 0;
3233 if (global.autoplay_leveldir)
3235 door_state |= DOOR_NO_DELAY;
3236 door_state &= ~DOOR_CLOSE_ALL;
3240 if (game_status == GAME_MODE_EDITOR)
3241 door_state |= DOOR_NO_DELAY;
3244 if (door_state & DOOR_ACTION)
3246 boolean handle_door_1 = (door_state & DOOR_ACTION_1);
3247 boolean handle_door_2 = (door_state & DOOR_ACTION_2);
3248 boolean door_1_done = (!handle_door_1);
3249 boolean door_2_done = (!handle_door_2);
3250 boolean door_1_vertical = (door_1.anim_mode & ANIM_VERTICAL);
3251 boolean door_2_vertical = (door_2.anim_mode & ANIM_VERTICAL);
3252 int door_size_1 = (door_1_vertical ? door_1.height : door_1.width);
3253 int door_size_2 = (door_2_vertical ? door_2.height : door_2.width);
3254 int max_door_size_1 = (door_1_vertical ? DYSIZE : DXSIZE);
3255 int max_door_size_2 = (door_2_vertical ? VYSIZE : VXSIZE);
3256 int door_size = (handle_door_1 ? door_size_1 : door_size_2);
3257 int max_door_size = (handle_door_1 ? max_door_size_1 : max_door_size_2);
3258 int door_skip = max_door_size - door_size;
3259 int end = door_size;
3260 int start = ((door_state & DOOR_NO_DELAY) ? end : 0);
3263 if (!(door_state & DOOR_NO_DELAY) && !setup.quick_doors)
3265 /* opening door sound has priority over simultaneously closing door */
3266 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
3267 PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
3268 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
3269 PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
3272 for (k = start; k <= end && !(door_1_done && door_2_done); k += stepsize)
3275 Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
3276 GC gc = bitmap->stored_clip_gc;
3278 if (door_state & DOOR_ACTION_1)
3280 int a = MIN(x * door_1.step_offset, end);
3281 int p = (door_state & DOOR_OPEN_1 ? end - a : a);
3282 int i = p + door_skip;
3284 if (door_1.anim_mode & ANIM_STATIC_PANEL)
3286 BlitBitmap(bitmap_db_door, drawto,
3287 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1,
3288 DXSIZE, DYSIZE, DX, DY);
3292 BlitBitmap(bitmap_db_door, drawto,
3293 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + p / 2,
3294 DXSIZE, DYSIZE - p / 2, DX, DY);
3296 ClearRectangle(drawto, DX, DY + DYSIZE - p / 2, DXSIZE, p / 2);
3299 if (door_1.anim_mode & ANIM_HORIZONTAL && x <= DXSIZE)
3301 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
3302 int dst1_x = DX + DXSIZE - i, dst1_y = DY;
3303 int src2_x = DXSIZE - i, src2_y = DOOR_GFX_PAGEY1;
3304 int dst2_x = DX, dst2_y = DY;
3305 int width = i, height = DYSIZE;
3307 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3308 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3311 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3312 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3315 else if (door_1.anim_mode & ANIM_VERTICAL && x <= DYSIZE)
3317 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
3318 int dst1_x = DX, dst1_y = DY + DYSIZE - i;
3319 int src2_x = 0, src2_y = DOOR_GFX_PAGEY1 + DYSIZE - i;
3320 int dst2_x = DX, dst2_y = DY;
3321 int width = DXSIZE, height = i;
3323 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3324 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3327 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3328 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3331 else if (x <= DXSIZE) /* ANIM_DEFAULT */
3333 int j = (door_1.anim_mode == ANIM_DEFAULT ? (DXSIZE - i) / 3 : 0);
3335 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
3336 BlitBitmapMasked(bitmap, drawto,
3337 DXSIZE, DOOR_GFX_PAGEY1, i, 77,
3338 DX + DXSIZE - i, DY + j);
3339 BlitBitmapMasked(bitmap, drawto,
3340 DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
3341 DX + DXSIZE - i, DY + 140 + j);
3342 SetClipOrigin(bitmap, gc, DX - DXSIZE + i,
3343 DY - (DOOR_GFX_PAGEY1 + j));
3344 BlitBitmapMasked(bitmap, drawto,
3345 DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
3347 BlitBitmapMasked(bitmap, drawto,
3348 DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
3351 BlitBitmapMasked(bitmap, drawto,
3352 DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
3354 BlitBitmapMasked(bitmap, drawto,
3355 DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
3357 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
3358 BlitBitmapMasked(bitmap, drawto,
3359 DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
3360 DX + DXSIZE - i, DY + 77 + j);
3361 BlitBitmapMasked(bitmap, drawto,
3362 DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
3363 DX + DXSIZE - i, DY + 203 + j);
3366 redraw_mask |= REDRAW_DOOR_1;
3367 door_1_done = (a == end);
3370 if (door_state & DOOR_ACTION_2)
3372 int a = MIN(x * door_2.step_offset, door_size);
3373 int p = (door_state & DOOR_OPEN_2 ? door_size - a : a);
3374 int i = p + door_skip;
3376 if (door_2.anim_mode & ANIM_STATIC_PANEL)
3378 BlitBitmap(bitmap_db_door, drawto,
3379 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2,
3380 VXSIZE, VYSIZE, VX, VY);
3382 else if (x <= VYSIZE)
3384 BlitBitmap(bitmap_db_door, drawto,
3385 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + p / 2,
3386 VXSIZE, VYSIZE - p / 2, VX, VY);
3388 ClearRectangle(drawto, VX, VY + VYSIZE - p / 2, VXSIZE, p / 2);
3391 if (door_2.anim_mode & ANIM_HORIZONTAL && x <= VXSIZE)
3393 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
3394 int dst1_x = VX + VXSIZE - i, dst1_y = VY;
3395 int src2_x = VXSIZE - i, src2_y = DOOR_GFX_PAGEY2;
3396 int dst2_x = VX, dst2_y = VY;
3397 int width = i, height = VYSIZE;
3399 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3400 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3403 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3404 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3407 else if (door_2.anim_mode & ANIM_VERTICAL && x <= VYSIZE)
3409 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
3410 int dst1_x = VX, dst1_y = VY + VYSIZE - i;
3411 int src2_x = 0, src2_y = DOOR_GFX_PAGEY2 + VYSIZE - i;
3412 int dst2_x = VX, dst2_y = VY;
3413 int width = VXSIZE, height = i;
3415 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3416 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3419 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3420 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3423 else if (x <= VXSIZE) /* ANIM_DEFAULT */
3425 int j = (door_2.anim_mode == ANIM_DEFAULT ? (VXSIZE - i) / 3 : 0);
3427 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
3428 BlitBitmapMasked(bitmap, drawto,
3429 VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
3430 VX + VXSIZE - i, VY + j);
3431 SetClipOrigin(bitmap, gc,
3432 VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
3433 BlitBitmapMasked(bitmap, drawto,
3434 VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
3437 BlitBitmapMasked(bitmap, drawto,
3438 VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
3439 i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
3440 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
3441 BlitBitmapMasked(bitmap, drawto,
3442 VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
3444 VX + VXSIZE - i, VY + VYSIZE / 2 + j);
3447 redraw_mask |= REDRAW_DOOR_2;
3448 door_2_done = (a == VXSIZE);
3451 if (!(door_state & DOOR_NO_DELAY))
3455 if (game_status == GAME_MODE_MAIN)
3458 WaitUntilDelayReached(&door_delay, door_delay_value);
3463 if (door_state & DOOR_ACTION_1)
3464 door1 = door_state & DOOR_ACTION_1;
3465 if (door_state & DOOR_ACTION_2)
3466 door2 = door_state & DOOR_ACTION_2;
3468 return (door1 | door2);
3471 void DrawSpecialEditorDoor()
3473 /* draw bigger toolbox window */
3474 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
3475 DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
3477 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
3478 EX - 6, VY - 4, EXSIZE + 12, EYSIZE - VYSIZE + 4,
3481 redraw_mask |= REDRAW_ALL;
3484 void UndrawSpecialEditorDoor()
3486 /* draw normal tape recorder window */
3487 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
3488 EX - 6, EY - 12, EXSIZE + 12, EYSIZE - VYSIZE + 12,
3491 redraw_mask |= REDRAW_ALL;
3495 /* ---------- new tool button stuff ---------------------------------------- */
3497 /* graphic position values for tool buttons */
3498 #define TOOL_BUTTON_YES_XPOS 2
3499 #define TOOL_BUTTON_YES_YPOS 250
3500 #define TOOL_BUTTON_YES_GFX_YPOS 0
3501 #define TOOL_BUTTON_YES_XSIZE 46
3502 #define TOOL_BUTTON_YES_YSIZE 28
3503 #define TOOL_BUTTON_NO_XPOS 52
3504 #define TOOL_BUTTON_NO_YPOS TOOL_BUTTON_YES_YPOS
3505 #define TOOL_BUTTON_NO_GFX_YPOS TOOL_BUTTON_YES_GFX_YPOS
3506 #define TOOL_BUTTON_NO_XSIZE TOOL_BUTTON_YES_XSIZE
3507 #define TOOL_BUTTON_NO_YSIZE TOOL_BUTTON_YES_YSIZE
3508 #define TOOL_BUTTON_CONFIRM_XPOS TOOL_BUTTON_YES_XPOS
3509 #define TOOL_BUTTON_CONFIRM_YPOS TOOL_BUTTON_YES_YPOS
3510 #define TOOL_BUTTON_CONFIRM_GFX_YPOS 30
3511 #define TOOL_BUTTON_CONFIRM_XSIZE 96
3512 #define TOOL_BUTTON_CONFIRM_YSIZE TOOL_BUTTON_YES_YSIZE
3513 #define TOOL_BUTTON_PLAYER_XSIZE 30
3514 #define TOOL_BUTTON_PLAYER_YSIZE 30
3515 #define TOOL_BUTTON_PLAYER_GFX_XPOS 5
3516 #define TOOL_BUTTON_PLAYER_GFX_YPOS 185
3517 #define TOOL_BUTTON_PLAYER_XPOS (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
3518 #define TOOL_BUTTON_PLAYER_YPOS (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
3519 #define TOOL_BUTTON_PLAYER1_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3520 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
3521 #define TOOL_BUTTON_PLAYER2_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3522 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
3523 #define TOOL_BUTTON_PLAYER3_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3524 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
3525 #define TOOL_BUTTON_PLAYER4_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3526 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
3527 #define TOOL_BUTTON_PLAYER1_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3528 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
3529 #define TOOL_BUTTON_PLAYER2_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3530 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
3531 #define TOOL_BUTTON_PLAYER3_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3532 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
3533 #define TOOL_BUTTON_PLAYER4_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3534 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
3543 } toolbutton_info[NUM_TOOL_BUTTONS] =
3546 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_GFX_YPOS,
3547 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_YPOS,
3548 TOOL_BUTTON_YES_XSIZE, TOOL_BUTTON_YES_YSIZE,
3553 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_GFX_YPOS,
3554 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_YPOS,
3555 TOOL_BUTTON_NO_XSIZE, TOOL_BUTTON_NO_YSIZE,
3560 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_GFX_YPOS,
3561 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_YPOS,
3562 TOOL_BUTTON_CONFIRM_XSIZE, TOOL_BUTTON_CONFIRM_YSIZE,
3563 TOOL_CTRL_ID_CONFIRM,
3567 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3568 TOOL_BUTTON_PLAYER1_XPOS, TOOL_BUTTON_PLAYER1_YPOS,
3569 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3570 TOOL_CTRL_ID_PLAYER_1,
3574 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3575 TOOL_BUTTON_PLAYER2_XPOS, TOOL_BUTTON_PLAYER2_YPOS,
3576 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3577 TOOL_CTRL_ID_PLAYER_2,
3581 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3582 TOOL_BUTTON_PLAYER3_XPOS, TOOL_BUTTON_PLAYER3_YPOS,
3583 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3584 TOOL_CTRL_ID_PLAYER_3,
3588 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3589 TOOL_BUTTON_PLAYER4_XPOS, TOOL_BUTTON_PLAYER4_YPOS,
3590 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3591 TOOL_CTRL_ID_PLAYER_4,
3596 void CreateToolButtons()
3600 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3602 Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
3603 Bitmap *deco_bitmap = None;
3604 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
3605 struct GadgetInfo *gi;
3606 unsigned long event_mask;
3607 int gd_xoffset, gd_yoffset;
3608 int gd_x1, gd_x2, gd_y;
3611 event_mask = GD_EVENT_RELEASED;
3613 gd_xoffset = toolbutton_info[i].xpos;
3614 gd_yoffset = toolbutton_info[i].ypos;
3615 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
3616 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
3617 gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
3619 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
3621 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
3623 getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr),
3624 &deco_bitmap, &deco_x, &deco_y);
3625 deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
3626 deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
3629 gi = CreateGadget(GDI_CUSTOM_ID, id,
3630 GDI_INFO_TEXT, toolbutton_info[i].infotext,
3631 GDI_X, DX + toolbutton_info[i].x,
3632 GDI_Y, DY + toolbutton_info[i].y,
3633 GDI_WIDTH, toolbutton_info[i].width,
3634 GDI_HEIGHT, toolbutton_info[i].height,
3635 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
3636 GDI_STATE, GD_BUTTON_UNPRESSED,
3637 GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
3638 GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
3639 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
3640 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
3641 GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
3642 GDI_DECORATION_SHIFTING, 1, 1,
3643 GDI_DIRECT_DRAW, FALSE,
3644 GDI_EVENT_MASK, event_mask,
3645 GDI_CALLBACK_ACTION, HandleToolButtons,
3649 Error(ERR_EXIT, "cannot create gadget");
3651 tool_gadget[id] = gi;
3655 void FreeToolButtons()
3659 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3660 FreeGadget(tool_gadget[i]);
3663 static void UnmapToolButtons()
3667 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3668 UnmapGadget(tool_gadget[i]);
3671 static void HandleToolButtons(struct GadgetInfo *gi)
3673 request_gadget_id = gi->custom_id;
3676 static struct Mapping_EM_to_RND_object
3679 boolean is_rnd_to_em_mapping; /* unique mapping EM <-> RND */
3680 boolean is_backside; /* backside of moving element */
3686 em_object_mapping_list[] =
3689 Xblank, TRUE, FALSE,
3693 Yacid_splash_eB, FALSE, FALSE,
3694 EL_ACID_SPLASH_RIGHT, -1, -1
3697 Yacid_splash_wB, FALSE, FALSE,
3698 EL_ACID_SPLASH_LEFT, -1, -1
3701 #ifdef EM_ENGINE_BAD_ROLL
3703 Xstone_force_e, FALSE, FALSE,
3704 EL_ROCK, -1, MV_BIT_RIGHT
3707 Xstone_force_w, FALSE, FALSE,
3708 EL_ROCK, -1, MV_BIT_LEFT
3711 Xnut_force_e, FALSE, FALSE,
3712 EL_NUT, -1, MV_BIT_RIGHT
3715 Xnut_force_w, FALSE, FALSE,
3716 EL_NUT, -1, MV_BIT_LEFT
3719 Xspring_force_e, FALSE, FALSE,
3720 EL_SPRING, -1, MV_BIT_RIGHT
3723 Xspring_force_w, FALSE, FALSE,
3724 EL_SPRING, -1, MV_BIT_LEFT
3727 Xemerald_force_e, FALSE, FALSE,
3728 EL_EMERALD, -1, MV_BIT_RIGHT
3731 Xemerald_force_w, FALSE, FALSE,
3732 EL_EMERALD, -1, MV_BIT_LEFT
3735 Xdiamond_force_e, FALSE, FALSE,
3736 EL_DIAMOND, -1, MV_BIT_RIGHT
3739 Xdiamond_force_w, FALSE, FALSE,
3740 EL_DIAMOND, -1, MV_BIT_LEFT
3743 Xbomb_force_e, FALSE, FALSE,
3744 EL_BOMB, -1, MV_BIT_RIGHT
3747 Xbomb_force_w, FALSE, FALSE,
3748 EL_BOMB, -1, MV_BIT_LEFT
3750 #endif /* EM_ENGINE_BAD_ROLL */
3753 Xstone, TRUE, FALSE,
3757 Xstone_pause, FALSE, FALSE,
3761 Xstone_fall, FALSE, FALSE,
3765 Ystone_s, FALSE, FALSE,
3766 EL_ROCK, ACTION_FALLING, -1
3769 Ystone_sB, FALSE, TRUE,
3770 EL_ROCK, ACTION_FALLING, -1
3773 Ystone_e, FALSE, FALSE,
3774 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
3777 Ystone_eB, FALSE, TRUE,
3778 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
3781 Ystone_w, FALSE, FALSE,
3782 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
3785 Ystone_wB, FALSE, TRUE,
3786 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
3793 Xnut_pause, FALSE, FALSE,
3797 Xnut_fall, FALSE, FALSE,
3801 Ynut_s, FALSE, FALSE,
3802 EL_NUT, ACTION_FALLING, -1
3805 Ynut_sB, FALSE, TRUE,
3806 EL_NUT, ACTION_FALLING, -1
3809 Ynut_e, FALSE, FALSE,
3810 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
3813 Ynut_eB, FALSE, TRUE,
3814 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
3817 Ynut_w, FALSE, FALSE,
3818 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
3821 Ynut_wB, FALSE, TRUE,
3822 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
3825 Xbug_n, TRUE, FALSE,
3829 Xbug_e, TRUE, FALSE,
3830 EL_BUG_RIGHT, -1, -1
3833 Xbug_s, TRUE, FALSE,
3837 Xbug_w, TRUE, FALSE,
3841 Xbug_gon, FALSE, FALSE,
3845 Xbug_goe, FALSE, FALSE,
3846 EL_BUG_RIGHT, -1, -1
3849 Xbug_gos, FALSE, FALSE,
3853 Xbug_gow, FALSE, FALSE,
3857 Ybug_n, FALSE, FALSE,
3858 EL_BUG, ACTION_MOVING, MV_BIT_UP
3861 Ybug_nB, FALSE, TRUE,
3862 EL_BUG, ACTION_MOVING, MV_BIT_UP
3865 Ybug_e, FALSE, FALSE,
3866 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
3869 Ybug_eB, FALSE, TRUE,
3870 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
3873 Ybug_s, FALSE, FALSE,
3874 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
3877 Ybug_sB, FALSE, TRUE,
3878 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
3881 Ybug_w, FALSE, FALSE,
3882 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
3885 Ybug_wB, FALSE, TRUE,
3886 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
3889 Ybug_w_n, FALSE, FALSE,
3890 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
3893 Ybug_n_e, FALSE, FALSE,
3894 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
3897 Ybug_e_s, FALSE, FALSE,
3898 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
3901 Ybug_s_w, FALSE, FALSE,
3902 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
3905 Ybug_e_n, FALSE, FALSE,
3906 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
3909 Ybug_s_e, FALSE, FALSE,
3910 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
3913 Ybug_w_s, FALSE, FALSE,
3914 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
3917 Ybug_n_w, FALSE, FALSE,
3918 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
3921 Ybug_stone, FALSE, FALSE,
3922 EL_BUG, ACTION_SMASHED_BY_ROCK, -1
3925 Ybug_spring, FALSE, FALSE,
3926 EL_BUG, ACTION_SMASHED_BY_SPRING, -1
3929 Xtank_n, TRUE, FALSE,
3930 EL_SPACESHIP_UP, -1, -1
3933 Xtank_e, TRUE, FALSE,
3934 EL_SPACESHIP_RIGHT, -1, -1
3937 Xtank_s, TRUE, FALSE,
3938 EL_SPACESHIP_DOWN, -1, -1
3941 Xtank_w, TRUE, FALSE,
3942 EL_SPACESHIP_LEFT, -1, -1
3945 Xtank_gon, FALSE, FALSE,
3946 EL_SPACESHIP_UP, -1, -1
3949 Xtank_goe, FALSE, FALSE,
3950 EL_SPACESHIP_RIGHT, -1, -1
3953 Xtank_gos, FALSE, FALSE,
3954 EL_SPACESHIP_DOWN, -1, -1
3957 Xtank_gow, FALSE, FALSE,
3958 EL_SPACESHIP_LEFT, -1, -1
3961 Ytank_n, FALSE, FALSE,
3962 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
3965 Ytank_nB, FALSE, TRUE,
3966 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
3969 Ytank_e, FALSE, FALSE,
3970 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
3973 Ytank_eB, FALSE, TRUE,
3974 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
3977 Ytank_s, FALSE, FALSE,
3978 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
3981 Ytank_sB, FALSE, TRUE,
3982 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
3985 Ytank_w, FALSE, FALSE,
3986 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
3989 Ytank_wB, FALSE, TRUE,
3990 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
3993 Ytank_w_n, FALSE, FALSE,
3994 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
3997 Ytank_n_e, FALSE, FALSE,
3998 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
4001 Ytank_e_s, FALSE, FALSE,
4002 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
4005 Ytank_s_w, FALSE, FALSE,
4006 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
4009 Ytank_e_n, FALSE, FALSE,
4010 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
4013 Ytank_s_e, FALSE, FALSE,
4014 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
4017 Ytank_w_s, FALSE, FALSE,
4018 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
4021 Ytank_n_w, FALSE, FALSE,
4022 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
4025 Ytank_stone, FALSE, FALSE,
4026 EL_SPACESHIP, ACTION_SMASHED_BY_ROCK, -1
4029 Ytank_spring, FALSE, FALSE,
4030 EL_SPACESHIP, ACTION_SMASHED_BY_SPRING, -1
4033 Xandroid, TRUE, FALSE,
4034 EL_EMC_ANDROID, ACTION_ACTIVE, -1
4037 Xandroid_1_n, FALSE, FALSE,
4038 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
4041 Xandroid_2_n, FALSE, FALSE,
4042 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
4045 Xandroid_1_e, FALSE, FALSE,
4046 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
4049 Xandroid_2_e, FALSE, FALSE,
4050 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
4053 Xandroid_1_w, FALSE, FALSE,
4054 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
4057 Xandroid_2_w, FALSE, FALSE,
4058 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
4061 Xandroid_1_s, FALSE, FALSE,
4062 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
4065 Xandroid_2_s, FALSE, FALSE,
4066 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
4069 Yandroid_n, FALSE, FALSE,
4070 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
4073 Yandroid_nB, FALSE, TRUE,
4074 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
4077 Yandroid_ne, FALSE, FALSE,
4078 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPRIGHT
4081 Yandroid_neB, FALSE, TRUE,
4082 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPRIGHT
4085 Yandroid_e, FALSE, FALSE,
4086 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
4089 Yandroid_eB, FALSE, TRUE,
4090 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
4093 Yandroid_se, FALSE, FALSE,
4094 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNRIGHT
4097 Yandroid_seB, FALSE, TRUE,
4098 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNRIGHT
4101 Yandroid_s, FALSE, FALSE,
4102 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
4105 Yandroid_sB, FALSE, TRUE,
4106 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
4109 Yandroid_sw, FALSE, FALSE,
4110 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNLEFT
4113 Yandroid_swB, FALSE, TRUE,
4114 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNLEFT
4117 Yandroid_w, FALSE, FALSE,
4118 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
4121 Yandroid_wB, FALSE, TRUE,
4122 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
4125 Yandroid_nw, FALSE, FALSE,
4126 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPLEFT
4129 Yandroid_nwB, FALSE, TRUE,
4130 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPLEFT
4133 Xspring, TRUE, FALSE,
4137 Xspring_pause, FALSE, FALSE,
4141 Xspring_e, FALSE, FALSE,
4145 Xspring_w, FALSE, FALSE,
4149 Xspring_fall, FALSE, FALSE,
4153 Yspring_s, FALSE, FALSE,
4154 EL_SPRING, ACTION_FALLING, -1
4157 Yspring_sB, FALSE, TRUE,
4158 EL_SPRING, ACTION_FALLING, -1
4161 Yspring_e, FALSE, FALSE,
4162 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
4165 Yspring_eB, FALSE, TRUE,
4166 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
4169 Yspring_w, FALSE, FALSE,
4170 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
4173 Yspring_wB, FALSE, TRUE,
4174 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
4177 Yspring_kill_e, FALSE, FALSE,
4178 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
4181 Yspring_kill_eB, FALSE, TRUE,
4182 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
4185 Yspring_kill_w, FALSE, FALSE,
4186 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
4189 Yspring_kill_wB, FALSE, TRUE,
4190 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
4193 Xeater_n, TRUE, FALSE,
4194 EL_YAMYAM_UP, -1, -1
4197 Xeater_e, TRUE, FALSE,
4198 EL_YAMYAM_RIGHT, -1, -1
4201 Xeater_w, TRUE, FALSE,
4202 EL_YAMYAM_LEFT, -1, -1
4205 Xeater_s, TRUE, FALSE,
4206 EL_YAMYAM_DOWN, -1, -1
4209 Yeater_n, FALSE, FALSE,
4210 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
4213 Yeater_nB, FALSE, TRUE,
4214 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
4217 Yeater_e, FALSE, FALSE,
4218 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
4221 Yeater_eB, FALSE, TRUE,
4222 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
4225 Yeater_s, FALSE, FALSE,
4226 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
4229 Yeater_sB, FALSE, TRUE,
4230 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
4233 Yeater_w, FALSE, FALSE,
4234 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
4237 Yeater_wB, FALSE, TRUE,
4238 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
4241 Yeater_stone, FALSE, FALSE,
4242 EL_YAMYAM, ACTION_SMASHED_BY_ROCK, -1
4245 Yeater_spring, FALSE, FALSE,
4246 EL_YAMYAM, ACTION_SMASHED_BY_SPRING, -1
4249 Xalien, TRUE, FALSE,
4253 Xalien_pause, FALSE, FALSE,
4257 Yalien_n, FALSE, FALSE,
4258 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
4261 Yalien_nB, FALSE, TRUE,
4262 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
4265 Yalien_e, FALSE, FALSE,
4266 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
4269 Yalien_eB, FALSE, TRUE,
4270 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
4273 Yalien_s, FALSE, FALSE,
4274 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
4277 Yalien_sB, FALSE, TRUE,
4278 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
4281 Yalien_w, FALSE, FALSE,
4282 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
4285 Yalien_wB, FALSE, TRUE,
4286 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
4289 Yalien_stone, FALSE, FALSE,
4290 EL_ROBOT, ACTION_SMASHED_BY_ROCK, -1
4293 Yalien_spring, FALSE, FALSE,
4294 EL_ROBOT, ACTION_SMASHED_BY_SPRING, -1
4297 Xemerald, TRUE, FALSE,
4301 Xemerald_pause, FALSE, FALSE,
4305 Xemerald_fall, FALSE, FALSE,
4309 Xemerald_shine, FALSE, FALSE,
4310 EL_EMERALD, ACTION_TWINKLING, -1
4313 Yemerald_s, FALSE, FALSE,
4314 EL_EMERALD, ACTION_FALLING, -1
4317 Yemerald_sB, FALSE, TRUE,
4318 EL_EMERALD, ACTION_FALLING, -1
4321 Yemerald_e, FALSE, FALSE,
4322 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
4325 Yemerald_eB, FALSE, TRUE,
4326 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
4329 Yemerald_w, FALSE, FALSE,
4330 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
4333 Yemerald_wB, FALSE, TRUE,
4334 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
4337 Yemerald_eat, FALSE, FALSE,
4338 EL_EMERALD, ACTION_COLLECTING, -1
4341 Yemerald_stone, FALSE, FALSE,
4342 EL_NUT, ACTION_BREAKING, -1
4345 Xdiamond, TRUE, FALSE,
4349 Xdiamond_pause, FALSE, FALSE,
4353 Xdiamond_fall, FALSE, FALSE,
4357 Xdiamond_shine, FALSE, FALSE,
4358 EL_DIAMOND, ACTION_TWINKLING, -1
4361 Ydiamond_s, FALSE, FALSE,
4362 EL_DIAMOND, ACTION_FALLING, -1
4365 Ydiamond_sB, FALSE, TRUE,
4366 EL_DIAMOND, ACTION_FALLING, -1
4369 Ydiamond_e, FALSE, FALSE,
4370 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
4373 Ydiamond_eB, FALSE, TRUE,
4374 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
4377 Ydiamond_w, FALSE, FALSE,
4378 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
4381 Ydiamond_wB, FALSE, TRUE,
4382 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
4385 Ydiamond_eat, FALSE, FALSE,
4386 EL_DIAMOND, ACTION_COLLECTING, -1
4389 Ydiamond_stone, FALSE, FALSE,
4390 EL_DIAMOND, ACTION_SMASHED_BY_ROCK, -1
4393 Xdrip_fall, TRUE, FALSE,
4394 EL_AMOEBA_DROP, -1, -1
4397 Xdrip_stretch, FALSE, FALSE,
4398 EL_AMOEBA_DROP, ACTION_FALLING, -1
4401 Xdrip_stretchB, FALSE, TRUE,
4402 EL_AMOEBA_DROP, ACTION_FALLING, -1
4405 Xdrip_eat, FALSE, FALSE,
4406 EL_AMOEBA_DROP, ACTION_GROWING, -1
4409 Ydrip_s1, FALSE, FALSE,
4410 EL_AMOEBA_DROP, ACTION_FALLING, -1
4413 Ydrip_s1B, FALSE, TRUE,
4414 EL_AMOEBA_DROP, ACTION_FALLING, -1
4417 Ydrip_s2, FALSE, FALSE,
4418 EL_AMOEBA_DROP, ACTION_FALLING, -1
4421 Ydrip_s2B, FALSE, TRUE,
4422 EL_AMOEBA_DROP, ACTION_FALLING, -1
4429 Xbomb_pause, FALSE, FALSE,
4433 Xbomb_fall, FALSE, FALSE,
4437 Ybomb_s, FALSE, FALSE,
4438 EL_BOMB, ACTION_FALLING, -1
4441 Ybomb_sB, FALSE, TRUE,
4442 EL_BOMB, ACTION_FALLING, -1
4445 Ybomb_e, FALSE, FALSE,
4446 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
4449 Ybomb_eB, FALSE, TRUE,
4450 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
4453 Ybomb_w, FALSE, FALSE,
4454 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
4457 Ybomb_wB, FALSE, TRUE,
4458 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
4461 Ybomb_eat, FALSE, FALSE,
4462 EL_BOMB, ACTION_ACTIVATING, -1
4465 Xballoon, TRUE, FALSE,
4469 Yballoon_n, FALSE, FALSE,
4470 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
4473 Yballoon_nB, FALSE, TRUE,
4474 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
4477 Yballoon_e, FALSE, FALSE,
4478 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
4481 Yballoon_eB, FALSE, TRUE,
4482 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
4485 Yballoon_s, FALSE, FALSE,
4486 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
4489 Yballoon_sB, FALSE, TRUE,
4490 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
4493 Yballoon_w, FALSE, FALSE,
4494 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
4497 Yballoon_wB, FALSE, TRUE,
4498 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
4501 Xgrass, TRUE, FALSE,
4502 EL_EMC_GRASS, -1, -1
4505 Ygrass_nB, FALSE, FALSE,
4506 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_UP
4509 Ygrass_eB, FALSE, FALSE,
4510 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_RIGHT
4513 Ygrass_sB, FALSE, FALSE,
4514 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_DOWN
4517 Ygrass_wB, FALSE, FALSE,
4518 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_LEFT
4525 Ydirt_nB, FALSE, FALSE,
4526 EL_SAND, ACTION_DIGGING, MV_BIT_UP
4529 Ydirt_eB, FALSE, FALSE,
4530 EL_SAND, ACTION_DIGGING, MV_BIT_RIGHT
4533 Ydirt_sB, FALSE, FALSE,
4534 EL_SAND, ACTION_DIGGING, MV_BIT_DOWN
4537 Ydirt_wB, FALSE, FALSE,
4538 EL_SAND, ACTION_DIGGING, MV_BIT_LEFT
4541 Xacid_ne, TRUE, FALSE,
4542 EL_ACID_POOL_TOPRIGHT, -1, -1
4545 Xacid_se, TRUE, FALSE,
4546 EL_ACID_POOL_BOTTOMRIGHT, -1, -1
4549 Xacid_s, TRUE, FALSE,
4550 EL_ACID_POOL_BOTTOM, -1, -1
4553 Xacid_sw, TRUE, FALSE,
4554 EL_ACID_POOL_BOTTOMLEFT, -1, -1
4557 Xacid_nw, TRUE, FALSE,
4558 EL_ACID_POOL_TOPLEFT, -1, -1
4561 Xacid_1, TRUE, FALSE,
4565 Xacid_2, FALSE, FALSE,
4569 Xacid_3, FALSE, FALSE,
4573 Xacid_4, FALSE, FALSE,
4577 Xacid_5, FALSE, FALSE,
4581 Xacid_6, FALSE, FALSE,
4585 Xacid_7, FALSE, FALSE,
4589 Xacid_8, FALSE, FALSE,
4593 Xball_1, TRUE, FALSE,
4594 EL_EMC_MAGIC_BALL, -1, -1
4597 Xball_1B, FALSE, FALSE,
4598 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4601 Xball_2, FALSE, FALSE,
4602 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4605 Xball_2B, FALSE, FALSE,
4606 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4609 Yball_eat, FALSE, FALSE,
4610 EL_EMC_MAGIC_BALL, ACTION_DROPPING, -1
4613 Ykey_1_eat, FALSE, FALSE,
4614 EL_EM_KEY_1, ACTION_COLLECTING, -1
4617 Ykey_2_eat, FALSE, FALSE,
4618 EL_EM_KEY_2, ACTION_COLLECTING, -1
4621 Ykey_3_eat, FALSE, FALSE,
4622 EL_EM_KEY_3, ACTION_COLLECTING, -1
4625 Ykey_4_eat, FALSE, FALSE,
4626 EL_EM_KEY_4, ACTION_COLLECTING, -1
4629 Ykey_5_eat, FALSE, FALSE,
4630 EL_EMC_KEY_5, ACTION_COLLECTING, -1
4633 Ykey_6_eat, FALSE, FALSE,
4634 EL_EMC_KEY_6, ACTION_COLLECTING, -1
4637 Ykey_7_eat, FALSE, FALSE,
4638 EL_EMC_KEY_7, ACTION_COLLECTING, -1
4641 Ykey_8_eat, FALSE, FALSE,
4642 EL_EMC_KEY_8, ACTION_COLLECTING, -1
4645 Ylenses_eat, FALSE, FALSE,
4646 EL_EMC_LENSES, ACTION_COLLECTING, -1
4649 Ymagnify_eat, FALSE, FALSE,
4650 EL_EMC_MAGNIFIER, ACTION_COLLECTING, -1
4653 Ygrass_eat, FALSE, FALSE,
4654 EL_EMC_GRASS, ACTION_SNAPPING, -1
4657 Ydirt_eat, FALSE, FALSE,
4658 EL_SAND, ACTION_SNAPPING, -1
4661 Xgrow_ns, TRUE, FALSE,
4662 EL_EXPANDABLE_WALL_VERTICAL, -1, -1
4665 Ygrow_ns_eat, FALSE, FALSE,
4666 EL_EXPANDABLE_WALL_VERTICAL, ACTION_GROWING, -1
4669 Xgrow_ew, TRUE, FALSE,
4670 EL_EXPANDABLE_WALL_HORIZONTAL, -1, -1
4673 Ygrow_ew_eat, FALSE, FALSE,
4674 EL_EXPANDABLE_WALL_HORIZONTAL, ACTION_GROWING, -1
4677 Xwonderwall, TRUE, FALSE,
4678 EL_MAGIC_WALL, -1, -1
4681 XwonderwallB, FALSE, FALSE,
4682 EL_MAGIC_WALL, ACTION_ACTIVE, -1
4685 Xamoeba_1, TRUE, FALSE,
4686 EL_AMOEBA_DRY, ACTION_OTHER, -1
4689 Xamoeba_2, FALSE, FALSE,
4690 EL_AMOEBA_DRY, ACTION_OTHER, -1
4693 Xamoeba_3, FALSE, FALSE,
4694 EL_AMOEBA_DRY, ACTION_OTHER, -1
4697 Xamoeba_4, FALSE, FALSE,
4698 EL_AMOEBA_DRY, ACTION_OTHER, -1
4701 Xamoeba_5, TRUE, FALSE,
4702 EL_AMOEBA_WET, ACTION_OTHER, -1
4705 Xamoeba_6, FALSE, FALSE,
4706 EL_AMOEBA_WET, ACTION_OTHER, -1
4709 Xamoeba_7, FALSE, FALSE,
4710 EL_AMOEBA_WET, ACTION_OTHER, -1
4713 Xamoeba_8, FALSE, FALSE,
4714 EL_AMOEBA_WET, ACTION_OTHER, -1
4717 Xdoor_1, TRUE, FALSE,
4718 EL_EM_GATE_1, -1, -1
4721 Xdoor_2, TRUE, FALSE,
4722 EL_EM_GATE_2, -1, -1
4725 Xdoor_3, TRUE, FALSE,
4726 EL_EM_GATE_3, -1, -1
4729 Xdoor_4, TRUE, FALSE,
4730 EL_EM_GATE_4, -1, -1
4733 Xdoor_5, TRUE, FALSE,
4734 EL_EMC_GATE_5, -1, -1
4737 Xdoor_6, TRUE, FALSE,
4738 EL_EMC_GATE_6, -1, -1
4741 Xdoor_7, TRUE, FALSE,
4742 EL_EMC_GATE_7, -1, -1
4745 Xdoor_8, TRUE, FALSE,
4746 EL_EMC_GATE_8, -1, -1
4749 Xkey_1, TRUE, FALSE,
4753 Xkey_2, TRUE, FALSE,
4757 Xkey_3, TRUE, FALSE,
4761 Xkey_4, TRUE, FALSE,
4765 Xkey_5, TRUE, FALSE,
4766 EL_EMC_KEY_5, -1, -1
4769 Xkey_6, TRUE, FALSE,
4770 EL_EMC_KEY_6, -1, -1
4773 Xkey_7, TRUE, FALSE,
4774 EL_EMC_KEY_7, -1, -1
4777 Xkey_8, TRUE, FALSE,
4778 EL_EMC_KEY_8, -1, -1
4781 Xwind_n, TRUE, FALSE,
4782 EL_BALLOON_SWITCH_UP, -1, -1
4785 Xwind_e, TRUE, FALSE,
4786 EL_BALLOON_SWITCH_RIGHT, -1, -1
4789 Xwind_s, TRUE, FALSE,
4790 EL_BALLOON_SWITCH_DOWN, -1, -1
4793 Xwind_w, TRUE, FALSE,
4794 EL_BALLOON_SWITCH_LEFT, -1, -1
4797 Xwind_nesw, TRUE, FALSE,
4798 EL_BALLOON_SWITCH_ANY, -1, -1
4801 Xwind_stop, TRUE, FALSE,
4802 EL_BALLOON_SWITCH_NONE, -1, -1
4806 EL_EM_EXIT_CLOSED, -1, -1
4809 Xexit_1, TRUE, FALSE,
4810 EL_EM_EXIT_OPEN, -1, -1
4813 Xexit_2, FALSE, FALSE,
4814 EL_EM_EXIT_OPEN, -1, -1
4817 Xexit_3, FALSE, FALSE,
4818 EL_EM_EXIT_OPEN, -1, -1
4821 Xdynamite, TRUE, FALSE,
4822 EL_EM_DYNAMITE, -1, -1
4825 Ydynamite_eat, FALSE, FALSE,
4826 EL_EM_DYNAMITE, ACTION_COLLECTING, -1
4829 Xdynamite_1, TRUE, FALSE,
4830 EL_EM_DYNAMITE_ACTIVE, -1, -1
4833 Xdynamite_2, FALSE, FALSE,
4834 EL_EM_DYNAMITE_ACTIVE, -1, -1
4837 Xdynamite_3, FALSE, FALSE,
4838 EL_EM_DYNAMITE_ACTIVE, -1, -1
4841 Xdynamite_4, FALSE, FALSE,
4842 EL_EM_DYNAMITE_ACTIVE, -1, -1
4845 Xbumper, TRUE, FALSE,
4846 EL_EMC_SPRING_BUMPER, -1, -1
4849 XbumperB, FALSE, FALSE,
4850 EL_EMC_SPRING_BUMPER, ACTION_ACTIVE, -1
4853 Xwheel, TRUE, FALSE,
4854 EL_ROBOT_WHEEL, -1, -1
4857 XwheelB, FALSE, FALSE,
4858 EL_ROBOT_WHEEL, ACTION_ACTIVE, -1
4861 Xswitch, TRUE, FALSE,
4862 EL_EMC_MAGIC_BALL_SWITCH, -1, -1
4865 XswitchB, FALSE, FALSE,
4866 EL_EMC_MAGIC_BALL_SWITCH, ACTION_ACTIVE, -1
4870 EL_QUICKSAND_EMPTY, -1, -1
4873 Xsand_stone, TRUE, FALSE,
4874 EL_QUICKSAND_FULL, -1, -1
4877 Xsand_stonein_1, FALSE, TRUE,
4878 EL_ROCK, ACTION_FILLING, -1
4881 Xsand_stonein_2, FALSE, TRUE,
4882 EL_ROCK, ACTION_FILLING, -1
4885 Xsand_stonein_3, FALSE, TRUE,
4886 EL_ROCK, ACTION_FILLING, -1
4889 Xsand_stonein_4, FALSE, TRUE,
4890 EL_ROCK, ACTION_FILLING, -1
4894 Xsand_stonesand_1, FALSE, FALSE,
4895 EL_QUICKSAND_EMPTYING, -1, -1
4898 Xsand_stonesand_2, FALSE, FALSE,
4899 EL_QUICKSAND_EMPTYING, -1, -1
4902 Xsand_stonesand_3, FALSE, FALSE,
4903 EL_QUICKSAND_EMPTYING, -1, -1
4906 Xsand_stonesand_4, FALSE, FALSE,
4907 EL_QUICKSAND_EMPTYING, -1, -1
4910 Xsand_stonesand_quickout_1, FALSE, FALSE,
4911 EL_QUICKSAND_EMPTYING, -1, -1
4914 Xsand_stonesand_quickout_2, FALSE, FALSE,
4915 EL_QUICKSAND_EMPTYING, -1, -1
4919 Xsand_stonesand_1, FALSE, FALSE,
4920 EL_QUICKSAND_FULL, -1, -1
4923 Xsand_stonesand_2, FALSE, FALSE,
4924 EL_QUICKSAND_FULL, -1, -1
4927 Xsand_stonesand_3, FALSE, FALSE,
4928 EL_QUICKSAND_FULL, -1, -1
4931 Xsand_stonesand_4, FALSE, FALSE,
4932 EL_QUICKSAND_FULL, -1, -1
4936 Xsand_stoneout_1, FALSE, FALSE,
4937 EL_ROCK, ACTION_EMPTYING, -1
4940 Xsand_stoneout_2, FALSE, FALSE,
4941 EL_ROCK, ACTION_EMPTYING, -1
4945 Xsand_sandstone_1, FALSE, FALSE,
4946 EL_QUICKSAND_FILLING, -1, -1
4949 Xsand_sandstone_2, FALSE, FALSE,
4950 EL_QUICKSAND_FILLING, -1, -1
4953 Xsand_sandstone_3, FALSE, FALSE,
4954 EL_QUICKSAND_FILLING, -1, -1
4957 Xsand_sandstone_4, FALSE, FALSE,
4958 EL_QUICKSAND_FILLING, -1, -1
4962 Xsand_sandstone_1, FALSE, FALSE,
4963 EL_QUICKSAND_FULL, -1, -1
4966 Xsand_sandstone_2, FALSE, FALSE,
4967 EL_QUICKSAND_FULL, -1, -1
4970 Xsand_sandstone_3, FALSE, FALSE,
4971 EL_QUICKSAND_FULL, -1, -1
4974 Xsand_sandstone_4, FALSE, FALSE,
4975 EL_QUICKSAND_FULL, -1, -1
4979 Xplant, TRUE, FALSE,
4980 EL_EMC_PLANT, -1, -1
4983 Yplant, FALSE, FALSE,
4984 EL_EMC_PLANT, -1, -1
4987 Xlenses, TRUE, FALSE,
4988 EL_EMC_LENSES, -1, -1
4991 Xmagnify, TRUE, FALSE,
4992 EL_EMC_MAGNIFIER, -1, -1
4995 Xdripper, TRUE, FALSE,
4996 EL_EMC_DRIPPER, -1, -1
4999 XdripperB, FALSE, FALSE,
5000 EL_EMC_DRIPPER, ACTION_ACTIVE, -1
5003 Xfake_blank, TRUE, FALSE,
5004 EL_INVISIBLE_WALL, -1, -1
5007 Xfake_blankB, FALSE, FALSE,
5008 EL_INVISIBLE_WALL, ACTION_ACTIVE, -1
5011 Xfake_grass, TRUE, FALSE,
5012 EL_EMC_FAKE_GRASS, -1, -1
5015 Xfake_grassB, FALSE, FALSE,
5016 EL_EMC_FAKE_GRASS, ACTION_ACTIVE, -1
5019 Xfake_door_1, TRUE, FALSE,
5020 EL_EM_GATE_1_GRAY, -1, -1
5023 Xfake_door_2, TRUE, FALSE,
5024 EL_EM_GATE_2_GRAY, -1, -1
5027 Xfake_door_3, TRUE, FALSE,
5028 EL_EM_GATE_3_GRAY, -1, -1
5031 Xfake_door_4, TRUE, FALSE,
5032 EL_EM_GATE_4_GRAY, -1, -1
5035 Xfake_door_5, TRUE, FALSE,
5036 EL_EMC_GATE_5_GRAY, -1, -1
5039 Xfake_door_6, TRUE, FALSE,
5040 EL_EMC_GATE_6_GRAY, -1, -1
5043 Xfake_door_7, TRUE, FALSE,
5044 EL_EMC_GATE_7_GRAY, -1, -1
5047 Xfake_door_8, TRUE, FALSE,
5048 EL_EMC_GATE_8_GRAY, -1, -1
5051 Xfake_acid_1, TRUE, FALSE,
5052 EL_EMC_FAKE_ACID, -1, -1
5055 Xfake_acid_2, FALSE, FALSE,
5056 EL_EMC_FAKE_ACID, -1, -1
5059 Xfake_acid_3, FALSE, FALSE,
5060 EL_EMC_FAKE_ACID, -1, -1
5063 Xfake_acid_4, FALSE, FALSE,
5064 EL_EMC_FAKE_ACID, -1, -1
5067 Xfake_acid_5, FALSE, FALSE,
5068 EL_EMC_FAKE_ACID, -1, -1
5071 Xfake_acid_6, FALSE, FALSE,
5072 EL_EMC_FAKE_ACID, -1, -1
5075 Xfake_acid_7, FALSE, FALSE,
5076 EL_EMC_FAKE_ACID, -1, -1
5079 Xfake_acid_8, FALSE, FALSE,
5080 EL_EMC_FAKE_ACID, -1, -1
5083 Xsteel_1, TRUE, FALSE,
5084 EL_STEELWALL, -1, -1
5087 Xsteel_2, TRUE, FALSE,
5088 EL_EMC_STEELWALL_2, -1, -1
5091 Xsteel_3, TRUE, FALSE,
5092 EL_EMC_STEELWALL_3, -1, -1
5095 Xsteel_4, TRUE, FALSE,
5096 EL_EMC_STEELWALL_4, -1, -1
5099 Xwall_1, TRUE, FALSE,
5103 Xwall_2, TRUE, FALSE,
5104 EL_EMC_WALL_14, -1, -1
5107 Xwall_3, TRUE, FALSE,
5108 EL_EMC_WALL_15, -1, -1
5111 Xwall_4, TRUE, FALSE,
5112 EL_EMC_WALL_16, -1, -1
5115 Xround_wall_1, TRUE, FALSE,
5116 EL_WALL_SLIPPERY, -1, -1
5119 Xround_wall_2, TRUE, FALSE,
5120 EL_EMC_WALL_SLIPPERY_2, -1, -1
5123 Xround_wall_3, TRUE, FALSE,
5124 EL_EMC_WALL_SLIPPERY_3, -1, -1
5127 Xround_wall_4, TRUE, FALSE,
5128 EL_EMC_WALL_SLIPPERY_4, -1, -1
5131 Xdecor_1, TRUE, FALSE,
5132 EL_EMC_WALL_8, -1, -1
5135 Xdecor_2, TRUE, FALSE,
5136 EL_EMC_WALL_6, -1, -1
5139 Xdecor_3, TRUE, FALSE,
5140 EL_EMC_WALL_4, -1, -1
5143 Xdecor_4, TRUE, FALSE,
5144 EL_EMC_WALL_7, -1, -1
5147 Xdecor_5, TRUE, FALSE,
5148 EL_EMC_WALL_5, -1, -1
5151 Xdecor_6, TRUE, FALSE,
5152 EL_EMC_WALL_9, -1, -1
5155 Xdecor_7, TRUE, FALSE,
5156 EL_EMC_WALL_10, -1, -1
5159 Xdecor_8, TRUE, FALSE,
5160 EL_EMC_WALL_1, -1, -1
5163 Xdecor_9, TRUE, FALSE,
5164 EL_EMC_WALL_2, -1, -1
5167 Xdecor_10, TRUE, FALSE,
5168 EL_EMC_WALL_3, -1, -1
5171 Xdecor_11, TRUE, FALSE,
5172 EL_EMC_WALL_11, -1, -1
5175 Xdecor_12, TRUE, FALSE,
5176 EL_EMC_WALL_12, -1, -1
5179 Xalpha_0, TRUE, FALSE,
5180 EL_CHAR('0'), -1, -1
5183 Xalpha_1, TRUE, FALSE,
5184 EL_CHAR('1'), -1, -1
5187 Xalpha_2, TRUE, FALSE,
5188 EL_CHAR('2'), -1, -1
5191 Xalpha_3, TRUE, FALSE,
5192 EL_CHAR('3'), -1, -1
5195 Xalpha_4, TRUE, FALSE,
5196 EL_CHAR('4'), -1, -1
5199 Xalpha_5, TRUE, FALSE,
5200 EL_CHAR('5'), -1, -1
5203 Xalpha_6, TRUE, FALSE,
5204 EL_CHAR('6'), -1, -1
5207 Xalpha_7, TRUE, FALSE,
5208 EL_CHAR('7'), -1, -1
5211 Xalpha_8, TRUE, FALSE,
5212 EL_CHAR('8'), -1, -1
5215 Xalpha_9, TRUE, FALSE,
5216 EL_CHAR('9'), -1, -1
5219 Xalpha_excla, TRUE, FALSE,
5220 EL_CHAR('!'), -1, -1
5223 Xalpha_quote, TRUE, FALSE,
5224 EL_CHAR('"'), -1, -1
5227 Xalpha_comma, TRUE, FALSE,
5228 EL_CHAR(','), -1, -1
5231 Xalpha_minus, TRUE, FALSE,
5232 EL_CHAR('-'), -1, -1
5235 Xalpha_perio, TRUE, FALSE,
5236 EL_CHAR('.'), -1, -1
5239 Xalpha_colon, TRUE, FALSE,
5240 EL_CHAR(':'), -1, -1
5243 Xalpha_quest, TRUE, FALSE,
5244 EL_CHAR('?'), -1, -1
5247 Xalpha_a, TRUE, FALSE,
5248 EL_CHAR('A'), -1, -1
5251 Xalpha_b, TRUE, FALSE,
5252 EL_CHAR('B'), -1, -1
5255 Xalpha_c, TRUE, FALSE,
5256 EL_CHAR('C'), -1, -1
5259 Xalpha_d, TRUE, FALSE,
5260 EL_CHAR('D'), -1, -1
5263 Xalpha_e, TRUE, FALSE,
5264 EL_CHAR('E'), -1, -1
5267 Xalpha_f, TRUE, FALSE,
5268 EL_CHAR('F'), -1, -1
5271 Xalpha_g, TRUE, FALSE,
5272 EL_CHAR('G'), -1, -1
5275 Xalpha_h, TRUE, FALSE,
5276 EL_CHAR('H'), -1, -1
5279 Xalpha_i, TRUE, FALSE,
5280 EL_CHAR('I'), -1, -1
5283 Xalpha_j, TRUE, FALSE,
5284 EL_CHAR('J'), -1, -1
5287 Xalpha_k, TRUE, FALSE,
5288 EL_CHAR('K'), -1, -1
5291 Xalpha_l, TRUE, FALSE,
5292 EL_CHAR('L'), -1, -1
5295 Xalpha_m, TRUE, FALSE,
5296 EL_CHAR('M'), -1, -1
5299 Xalpha_n, TRUE, FALSE,
5300 EL_CHAR('N'), -1, -1
5303 Xalpha_o, TRUE, FALSE,
5304 EL_CHAR('O'), -1, -1
5307 Xalpha_p, TRUE, FALSE,
5308 EL_CHAR('P'), -1, -1
5311 Xalpha_q, TRUE, FALSE,
5312 EL_CHAR('Q'), -1, -1
5315 Xalpha_r, TRUE, FALSE,
5316 EL_CHAR('R'), -1, -1
5319 Xalpha_s, TRUE, FALSE,
5320 EL_CHAR('S'), -1, -1
5323 Xalpha_t, TRUE, FALSE,
5324 EL_CHAR('T'), -1, -1
5327 Xalpha_u, TRUE, FALSE,
5328 EL_CHAR('U'), -1, -1
5331 Xalpha_v, TRUE, FALSE,
5332 EL_CHAR('V'), -1, -1
5335 Xalpha_w, TRUE, FALSE,
5336 EL_CHAR('W'), -1, -1
5339 Xalpha_x, TRUE, FALSE,
5340 EL_CHAR('X'), -1, -1
5343 Xalpha_y, TRUE, FALSE,
5344 EL_CHAR('Y'), -1, -1
5347 Xalpha_z, TRUE, FALSE,
5348 EL_CHAR('Z'), -1, -1
5351 Xalpha_arrow_e, TRUE, FALSE,
5352 EL_CHAR('>'), -1, -1
5355 Xalpha_arrow_w, TRUE, FALSE,
5356 EL_CHAR('<'), -1, -1
5359 Xalpha_copyr, TRUE, FALSE,
5360 EL_CHAR('©'), -1, -1
5364 Xboom_bug, FALSE, FALSE,
5365 EL_BUG, ACTION_EXPLODING, -1
5368 Xboom_bomb, FALSE, FALSE,
5369 EL_BOMB, ACTION_EXPLODING, -1
5372 Xboom_android, FALSE, FALSE,
5373 EL_EMC_ANDROID, ACTION_OTHER, -1
5376 Xboom_1, FALSE, FALSE,
5377 EL_DEFAULT, ACTION_EXPLODING, -1
5380 Xboom_2, FALSE, FALSE,
5381 EL_DEFAULT, ACTION_EXPLODING, -1
5384 Znormal, FALSE, FALSE,
5388 Zdynamite, FALSE, FALSE,
5392 Zplayer, FALSE, FALSE,
5396 ZBORDER, FALSE, FALSE,
5406 static struct Mapping_EM_to_RND_player
5415 em_player_mapping_list[] =
5419 EL_PLAYER_1, ACTION_MOVING, MV_BIT_UP,
5423 EL_PLAYER_1, ACTION_MOVING, MV_BIT_RIGHT,
5427 EL_PLAYER_1, ACTION_MOVING, MV_BIT_DOWN,
5431 EL_PLAYER_1, ACTION_MOVING, MV_BIT_LEFT,
5435 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_UP,
5439 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_RIGHT,
5443 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_DOWN,
5447 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_LEFT,
5451 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_UP,
5455 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_RIGHT,
5459 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_DOWN,
5463 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_LEFT,
5467 EL_PLAYER_2, ACTION_MOVING, MV_BIT_UP,
5471 EL_PLAYER_2, ACTION_MOVING, MV_BIT_RIGHT,
5475 EL_PLAYER_2, ACTION_MOVING, MV_BIT_DOWN,
5479 EL_PLAYER_2, ACTION_MOVING, MV_BIT_LEFT,
5483 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_UP,
5487 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_RIGHT,
5491 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_DOWN,
5495 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_LEFT,
5499 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_UP,
5503 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_RIGHT,
5507 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_DOWN,
5511 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_LEFT,
5515 EL_PLAYER_1, ACTION_DEFAULT, -1,
5519 EL_PLAYER_2, ACTION_DEFAULT, -1,
5523 EL_PLAYER_3, ACTION_MOVING, MV_BIT_UP,
5527 EL_PLAYER_3, ACTION_MOVING, MV_BIT_RIGHT,
5531 EL_PLAYER_3, ACTION_MOVING, MV_BIT_DOWN,
5535 EL_PLAYER_3, ACTION_MOVING, MV_BIT_LEFT,
5539 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_UP,
5543 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_RIGHT,
5547 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_DOWN,
5551 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_LEFT,
5555 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_UP,
5559 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_RIGHT,
5563 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_DOWN,
5567 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_LEFT,
5571 EL_PLAYER_4, ACTION_MOVING, MV_BIT_UP,
5575 EL_PLAYER_4, ACTION_MOVING, MV_BIT_RIGHT,
5579 EL_PLAYER_4, ACTION_MOVING, MV_BIT_DOWN,
5583 EL_PLAYER_4, ACTION_MOVING, MV_BIT_LEFT,
5587 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_UP,
5591 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_RIGHT,
5595 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_DOWN,
5599 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_LEFT,
5603 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_UP,
5607 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_RIGHT,
5611 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_DOWN,
5615 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_LEFT,
5619 EL_PLAYER_3, ACTION_DEFAULT, -1,
5623 EL_PLAYER_4, ACTION_DEFAULT, -1,
5632 int map_element_RND_to_EM(int element_rnd)
5634 static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
5635 static boolean mapping_initialized = FALSE;
5637 if (!mapping_initialized)
5641 /* return "Xalpha_quest" for all undefined elements in mapping array */
5642 for (i = 0; i < NUM_FILE_ELEMENTS; i++)
5643 mapping_RND_to_EM[i] = Xalpha_quest;
5645 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5646 if (em_object_mapping_list[i].is_rnd_to_em_mapping)
5647 mapping_RND_to_EM[em_object_mapping_list[i].element_rnd] =
5648 em_object_mapping_list[i].element_em;
5650 mapping_initialized = TRUE;
5653 if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
5654 return mapping_RND_to_EM[element_rnd];
5656 Error(ERR_WARN, "invalid RND level element %d", element_rnd);
5661 int map_element_EM_to_RND(int element_em)
5663 static unsigned short mapping_EM_to_RND[TILE_MAX];
5664 static boolean mapping_initialized = FALSE;
5666 if (!mapping_initialized)
5670 /* return "EL_UNKNOWN" for all undefined elements in mapping array */
5671 for (i = 0; i < TILE_MAX; i++)
5672 mapping_EM_to_RND[i] = EL_UNKNOWN;
5674 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5675 mapping_EM_to_RND[em_object_mapping_list[i].element_em] =
5676 em_object_mapping_list[i].element_rnd;
5678 mapping_initialized = TRUE;
5681 if (element_em >= 0 && element_em < TILE_MAX)
5682 return mapping_EM_to_RND[element_em];
5684 Error(ERR_WARN, "invalid EM level element %d", element_em);
5689 void map_android_clone_elements_RND_to_EM(struct LevelInfo *level)
5691 struct LevelInfo_EM *level_em = level->native_em_level;
5692 struct LEVEL *lev = level_em->lev;
5695 for (i = 0; i < TILE_MAX; i++)
5696 lev->android_array[i] = Xblank;
5698 for (i = 0; i < level->num_android_clone_elements; i++)
5700 int element_rnd = level->android_clone_element[i];
5701 int element_em = map_element_RND_to_EM(element_rnd);
5703 for (j = 0; em_object_mapping_list[j].element_em != -1; j++)
5704 if (em_object_mapping_list[j].element_rnd == element_rnd)
5705 lev->android_array[em_object_mapping_list[j].element_em] = element_em;
5709 void map_android_clone_elements_EM_to_RND(struct LevelInfo *level)
5711 struct LevelInfo_EM *level_em = level->native_em_level;
5712 struct LEVEL *lev = level_em->lev;
5715 level->num_android_clone_elements = 0;
5717 for (i = 0; i < TILE_MAX; i++)
5719 int element_em = lev->android_array[i];
5721 boolean element_found = FALSE;
5723 if (element_em == Xblank)
5726 element_rnd = map_element_EM_to_RND(element_em);
5728 for (j = 0; j < level->num_android_clone_elements; j++)
5729 if (level->android_clone_element[j] == element_rnd)
5730 element_found = TRUE;
5734 level->android_clone_element[level->num_android_clone_elements++] =
5737 if (level->num_android_clone_elements == MAX_ANDROID_ELEMENTS)
5742 if (level->num_android_clone_elements == 0)
5744 level->num_android_clone_elements = 1;
5745 level->android_clone_element[0] = EL_EMPTY;
5749 int map_direction_RND_to_EM(int direction)
5751 return (direction == MV_UP ? 0 :
5752 direction == MV_RIGHT ? 1 :
5753 direction == MV_DOWN ? 2 :
5754 direction == MV_LEFT ? 3 :
5758 int map_direction_EM_to_RND(int direction)
5760 return (direction == 0 ? MV_UP :
5761 direction == 1 ? MV_RIGHT :
5762 direction == 2 ? MV_DOWN :
5763 direction == 3 ? MV_LEFT :
5767 int get_next_element(int element)
5771 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
5772 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
5773 case EL_QUICKSAND_FAST_FILLING: return EL_QUICKSAND_FAST_FULL;
5774 case EL_QUICKSAND_FAST_EMPTYING: return EL_QUICKSAND_FAST_EMPTY;
5775 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
5776 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
5777 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
5778 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
5779 case EL_DC_MAGIC_WALL_FILLING: return EL_DC_MAGIC_WALL_FULL;
5780 case EL_DC_MAGIC_WALL_EMPTYING: return EL_DC_MAGIC_WALL_ACTIVE;
5781 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
5783 default: return element;
5788 int el_act_dir2img(int element, int action, int direction)
5790 element = GFX_ELEMENT(element);
5792 if (direction == MV_NONE)
5793 return element_info[element].graphic[action];
5795 direction = MV_DIR_TO_BIT(direction);
5797 return element_info[element].direction_graphic[action][direction];
5800 int el_act_dir2img(int element, int action, int direction)
5802 element = GFX_ELEMENT(element);
5803 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
5805 /* direction_graphic[][] == graphic[] for undefined direction graphics */
5806 return element_info[element].direction_graphic[action][direction];
5811 static int el_act_dir2crm(int element, int action, int direction)
5813 element = GFX_ELEMENT(element);
5815 if (direction == MV_NONE)
5816 return element_info[element].crumbled[action];
5818 direction = MV_DIR_TO_BIT(direction);
5820 return element_info[element].direction_crumbled[action][direction];
5823 static int el_act_dir2crm(int element, int action, int direction)
5825 element = GFX_ELEMENT(element);
5826 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
5828 /* direction_graphic[][] == graphic[] for undefined direction graphics */
5829 return element_info[element].direction_crumbled[action][direction];
5833 int el_act2img(int element, int action)
5835 element = GFX_ELEMENT(element);
5837 return element_info[element].graphic[action];
5840 int el_act2crm(int element, int action)
5842 element = GFX_ELEMENT(element);
5844 return element_info[element].crumbled[action];
5847 int el_dir2img(int element, int direction)
5849 element = GFX_ELEMENT(element);
5851 return el_act_dir2img(element, ACTION_DEFAULT, direction);
5854 int el2baseimg(int element)
5856 return element_info[element].graphic[ACTION_DEFAULT];
5859 int el2img(int element)
5861 element = GFX_ELEMENT(element);
5863 return element_info[element].graphic[ACTION_DEFAULT];
5866 int el2edimg(int element)
5868 element = GFX_ELEMENT(element);
5870 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
5873 int el2preimg(int element)
5875 element = GFX_ELEMENT(element);
5877 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
5880 int el2panelimg(int element)
5882 element = GFX_ELEMENT(element);
5884 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PANEL];
5887 int font2baseimg(int font_nr)
5889 return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
5892 int getBeltNrFromBeltElement(int element)
5894 return (element < EL_CONVEYOR_BELT_2_LEFT ? 0 :
5895 element < EL_CONVEYOR_BELT_3_LEFT ? 1 :
5896 element < EL_CONVEYOR_BELT_4_LEFT ? 2 : 3);
5899 int getBeltNrFromBeltActiveElement(int element)
5901 return (element < EL_CONVEYOR_BELT_2_LEFT_ACTIVE ? 0 :
5902 element < EL_CONVEYOR_BELT_3_LEFT_ACTIVE ? 1 :
5903 element < EL_CONVEYOR_BELT_4_LEFT_ACTIVE ? 2 : 3);
5906 int getBeltNrFromBeltSwitchElement(int element)
5908 return (element < EL_CONVEYOR_BELT_2_SWITCH_LEFT ? 0 :
5909 element < EL_CONVEYOR_BELT_3_SWITCH_LEFT ? 1 :
5910 element < EL_CONVEYOR_BELT_4_SWITCH_LEFT ? 2 : 3);
5913 int getBeltDirNrFromBeltElement(int element)
5915 static int belt_base_element[4] =
5917 EL_CONVEYOR_BELT_1_LEFT,
5918 EL_CONVEYOR_BELT_2_LEFT,
5919 EL_CONVEYOR_BELT_3_LEFT,
5920 EL_CONVEYOR_BELT_4_LEFT
5923 int belt_nr = getBeltNrFromBeltElement(element);
5924 int belt_dir_nr = element - belt_base_element[belt_nr];
5926 return (belt_dir_nr % 3);
5929 int getBeltDirNrFromBeltSwitchElement(int element)
5931 static int belt_base_element[4] =
5933 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
5934 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
5935 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
5936 EL_CONVEYOR_BELT_4_SWITCH_LEFT
5939 int belt_nr = getBeltNrFromBeltSwitchElement(element);
5940 int belt_dir_nr = element - belt_base_element[belt_nr];
5942 return (belt_dir_nr % 3);
5945 int getBeltDirFromBeltElement(int element)
5947 static int belt_move_dir[3] =
5954 int belt_dir_nr = getBeltDirNrFromBeltElement(element);
5956 return belt_move_dir[belt_dir_nr];
5959 int getBeltDirFromBeltSwitchElement(int element)
5961 static int belt_move_dir[3] =
5968 int belt_dir_nr = getBeltDirNrFromBeltSwitchElement(element);
5970 return belt_move_dir[belt_dir_nr];
5973 int getBeltElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
5975 static int belt_base_element[4] =
5977 EL_CONVEYOR_BELT_1_LEFT,
5978 EL_CONVEYOR_BELT_2_LEFT,
5979 EL_CONVEYOR_BELT_3_LEFT,
5980 EL_CONVEYOR_BELT_4_LEFT
5983 return belt_base_element[belt_nr] + belt_dir_nr;
5986 int getBeltElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
5988 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
5990 return getBeltElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
5993 int getBeltSwitchElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
5995 static int belt_base_element[4] =
5997 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
5998 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
5999 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
6000 EL_CONVEYOR_BELT_4_SWITCH_LEFT
6003 return belt_base_element[belt_nr] + belt_dir_nr;
6006 int getBeltSwitchElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
6008 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
6010 return getBeltSwitchElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
6013 int getNumActivePlayers_EM()
6015 int num_players = 0;
6021 for (i = 0; i < MAX_PLAYERS; i++)
6022 if (tape.player_participates[i])
6028 int getGameFrameDelay_EM(int native_em_game_frame_delay)
6030 int game_frame_delay_value;
6032 game_frame_delay_value =
6033 (tape.playing && tape.fast_forward ? FfwdFrameDelay :
6034 GameFrameDelay == GAME_FRAME_DELAY ? native_em_game_frame_delay :
6037 if (tape.playing && tape.warp_forward && !tape.pausing)
6038 game_frame_delay_value = 0;
6040 return game_frame_delay_value;
6043 unsigned int InitRND(long seed)
6045 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
6046 return InitEngineRandom_EM(seed);
6048 return InitEngineRandom_RND(seed);
6052 static struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
6053 static struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
6056 inline static int get_effective_element_EM(int tile, int frame_em)
6058 int element = object_mapping[tile].element_rnd;
6059 int action = object_mapping[tile].action;
6060 boolean is_backside = object_mapping[tile].is_backside;
6061 boolean action_removing = (action == ACTION_DIGGING ||
6062 action == ACTION_SNAPPING ||
6063 action == ACTION_COLLECTING);
6069 case Yacid_splash_eB:
6070 case Yacid_splash_wB:
6071 return (frame_em > 5 ? EL_EMPTY : element);
6077 else /* frame_em == 7 */
6081 case Yacid_splash_eB:
6082 case Yacid_splash_wB:
6085 case Yemerald_stone:
6088 case Ydiamond_stone:
6092 case Xdrip_stretchB:
6111 case Xsand_stonein_1:
6112 case Xsand_stonein_2:
6113 case Xsand_stonein_3:
6114 case Xsand_stonein_4:
6118 return (is_backside || action_removing ? EL_EMPTY : element);
6123 inline static boolean check_linear_animation_EM(int tile)
6127 case Xsand_stonesand_1:
6128 case Xsand_stonesand_quickout_1:
6129 case Xsand_sandstone_1:
6130 case Xsand_stonein_1:
6131 case Xsand_stoneout_1:
6156 inline static void set_crumbled_graphics_EM(struct GraphicInfo_EM *g_em,
6157 boolean has_crumbled_graphics,
6158 int crumbled, int sync_frame)
6160 /* if element can be crumbled, but certain action graphics are just empty
6161 space (like instantly snapping sand to empty space in 1 frame), do not
6162 treat these empty space graphics as crumbled graphics in EMC engine */
6163 if (crumbled == IMG_EMPTY_SPACE)
6164 has_crumbled_graphics = FALSE;
6166 if (has_crumbled_graphics)
6168 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
6169 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
6170 g_crumbled->anim_delay,
6171 g_crumbled->anim_mode,
6172 g_crumbled->anim_start_frame,
6175 getGraphicSource(crumbled, frame_crumbled, &g_em->crumbled_bitmap,
6176 &g_em->crumbled_src_x, &g_em->crumbled_src_y);
6178 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
6180 g_em->has_crumbled_graphics = TRUE;
6184 g_em->crumbled_bitmap = NULL;
6185 g_em->crumbled_src_x = 0;
6186 g_em->crumbled_src_y = 0;
6187 g_em->crumbled_border_size = 0;
6189 g_em->has_crumbled_graphics = FALSE;
6193 void ResetGfxAnimation_EM(int x, int y, int tile)
6198 void SetGfxAnimation_EM(struct GraphicInfo_EM *g_em,
6199 int tile, int frame_em, int x, int y)
6201 int action = object_mapping[tile].action;
6203 int direction = object_mapping[tile].direction;
6204 int effective_element = get_effective_element_EM(tile, frame_em);
6205 int graphic = (direction == MV_NONE ?
6206 el_act2img(effective_element, action) :
6207 el_act_dir2img(effective_element, action, direction));
6208 struct GraphicInfo *g = &graphic_info[graphic];
6211 boolean action_removing = (action == ACTION_DIGGING ||
6212 action == ACTION_SNAPPING ||
6213 action == ACTION_COLLECTING);
6214 boolean action_moving = (action == ACTION_FALLING ||
6215 action == ACTION_MOVING ||
6216 action == ACTION_PUSHING ||
6217 action == ACTION_EATING ||
6218 action == ACTION_FILLING ||
6219 action == ACTION_EMPTYING);
6220 boolean action_falling = (action == ACTION_FALLING ||
6221 action == ACTION_FILLING ||
6222 action == ACTION_EMPTYING);
6224 /* special case: graphic uses "2nd movement tile" and has defined
6225 7 frames for movement animation (or less) => use default graphic
6226 for last (8th) frame which ends the movement animation */
6227 if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
6229 action = ACTION_DEFAULT; /* (keep action_* unchanged for now) */
6230 graphic = (direction == MV_NONE ?
6231 el_act2img(effective_element, action) :
6232 el_act_dir2img(effective_element, action, direction));
6234 g = &graphic_info[graphic];
6238 if (tile == Xsand_stonesand_1 ||
6239 tile == Xsand_stonesand_2 ||
6240 tile == Xsand_stonesand_3 ||
6241 tile == Xsand_stonesand_4)
6242 printf("::: 1: quicksand frame %d [%d]\n", GfxFrame[x][y], tile);
6246 if ((action_removing || check_linear_animation_EM(tile)) && frame_em == 0)
6250 // printf("::: resetting... [%d]\n", tile);
6253 if (action_removing || check_linear_animation_EM(tile))
6255 GfxFrame[x][y] = frame_em;
6257 // printf("::: resetting... [%d]\n", tile);
6260 else if (action_moving)
6262 boolean is_backside = object_mapping[tile].is_backside;
6266 int direction = object_mapping[tile].direction;
6267 int move_dir = (action_falling ? MV_DOWN : direction);
6272 /* !!! TEST !!! NEW !!! DOES NOT WORK RIGHT YET !!! */
6273 if (g->double_movement && frame_em == 0)
6277 // printf("::: resetting... [%d]\n", tile);
6281 if (move_dir == MV_LEFT)
6282 GfxFrame[x - 1][y] = GfxFrame[x][y];
6283 else if (move_dir == MV_RIGHT)
6284 GfxFrame[x + 1][y] = GfxFrame[x][y];
6285 else if (move_dir == MV_UP)
6286 GfxFrame[x][y - 1] = GfxFrame[x][y];
6287 else if (move_dir == MV_DOWN)
6288 GfxFrame[x][y + 1] = GfxFrame[x][y];
6295 /* special case: animation for Xsand_stonesand_quickout_1/2 twice as fast */
6296 if (tile == Xsand_stonesand_quickout_1 ||
6297 tile == Xsand_stonesand_quickout_2)
6302 if (tile == Xsand_stonesand_1 ||
6303 tile == Xsand_stonesand_2 ||
6304 tile == Xsand_stonesand_3 ||
6305 tile == Xsand_stonesand_4)
6306 printf("::: 2: quicksand frame %d [%d]\n", GfxFrame[x][y], tile);
6310 if (graphic_info[graphic].anim_global_sync)
6311 sync_frame = FrameCounter;
6312 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
6313 sync_frame = GfxFrame[x][y];
6315 sync_frame = 0; /* playfield border (pseudo steel) */
6317 SetRandomAnimationValue(x, y);
6319 int frame = getAnimationFrame(g->anim_frames,
6322 g->anim_start_frame,
6325 g_em->unique_identifier =
6326 (graphic << 16) | ((frame % 8) << 12) | (g_em->width << 6) | g_em->height;
6330 void getGraphicSourceObjectExt_EM(struct GraphicInfo_EM *g_em,
6331 int tile, int frame_em, int x, int y)
6333 int action = object_mapping[tile].action;
6334 int direction = object_mapping[tile].direction;
6335 boolean is_backside = object_mapping[tile].is_backside;
6336 int effective_element = get_effective_element_EM(tile, frame_em);
6338 int effective_action = action;
6340 int effective_action = (frame_em < 7 ? action : ACTION_DEFAULT);
6342 int graphic = (direction == MV_NONE ?
6343 el_act2img(effective_element, effective_action) :
6344 el_act_dir2img(effective_element, effective_action,
6346 int crumbled = (direction == MV_NONE ?
6347 el_act2crm(effective_element, effective_action) :
6348 el_act_dir2crm(effective_element, effective_action,
6350 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
6351 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
6352 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
6353 struct GraphicInfo *g = &graphic_info[graphic];
6355 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
6359 /* special case: graphic uses "2nd movement tile" and has defined
6360 7 frames for movement animation (or less) => use default graphic
6361 for last (8th) frame which ends the movement animation */
6362 if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
6364 effective_action = ACTION_DEFAULT;
6365 graphic = (direction == MV_NONE ?
6366 el_act2img(effective_element, effective_action) :
6367 el_act_dir2img(effective_element, effective_action,
6369 crumbled = (direction == MV_NONE ?
6370 el_act2crm(effective_element, effective_action) :
6371 el_act_dir2crm(effective_element, effective_action,
6374 g = &graphic_info[graphic];
6384 if (frame_em == 0) /* reset animation frame for certain elements */
6386 if (check_linear_animation_EM(tile))
6391 if (graphic_info[graphic].anim_global_sync)
6392 sync_frame = FrameCounter;
6393 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
6394 sync_frame = GfxFrame[x][y];
6396 sync_frame = 0; /* playfield border (pseudo steel) */
6398 SetRandomAnimationValue(x, y);
6403 int xxx_sync_frame = (i == Xdrip_stretch ? 7 :
6404 i == Xdrip_stretchB ? 7 :
6405 i == Ydrip_s2 ? j + 8 :
6406 i == Ydrip_s2B ? j + 8 :
6415 i == Xfake_acid_1 ? 0 :
6416 i == Xfake_acid_2 ? 10 :
6417 i == Xfake_acid_3 ? 20 :
6418 i == Xfake_acid_4 ? 30 :
6419 i == Xfake_acid_5 ? 40 :
6420 i == Xfake_acid_6 ? 50 :
6421 i == Xfake_acid_7 ? 60 :
6422 i == Xfake_acid_8 ? 70 :
6424 i == Xball_2B ? j + 8 :
6425 i == Yball_eat ? j + 1 :
6426 i == Ykey_1_eat ? j + 1 :
6427 i == Ykey_2_eat ? j + 1 :
6428 i == Ykey_3_eat ? j + 1 :
6429 i == Ykey_4_eat ? j + 1 :
6430 i == Ykey_5_eat ? j + 1 :
6431 i == Ykey_6_eat ? j + 1 :
6432 i == Ykey_7_eat ? j + 1 :
6433 i == Ykey_8_eat ? j + 1 :
6434 i == Ylenses_eat ? j + 1 :
6435 i == Ymagnify_eat ? j + 1 :
6436 i == Ygrass_eat ? j + 1 :
6437 i == Ydirt_eat ? j + 1 :
6438 i == Xamoeba_1 ? 0 :
6439 i == Xamoeba_2 ? 1 :
6440 i == Xamoeba_3 ? 2 :
6441 i == Xamoeba_4 ? 3 :
6442 i == Xamoeba_5 ? 0 :
6443 i == Xamoeba_6 ? 1 :
6444 i == Xamoeba_7 ? 2 :
6445 i == Xamoeba_8 ? 3 :
6446 i == Xexit_2 ? j + 8 :
6447 i == Xexit_3 ? j + 16 :
6448 i == Xdynamite_1 ? 0 :
6449 i == Xdynamite_2 ? 8 :
6450 i == Xdynamite_3 ? 16 :
6451 i == Xdynamite_4 ? 24 :
6452 i == Xsand_stonein_1 ? j + 1 :
6453 i == Xsand_stonein_2 ? j + 9 :
6454 i == Xsand_stonein_3 ? j + 17 :
6455 i == Xsand_stonein_4 ? j + 25 :
6456 i == Xsand_stoneout_1 && j == 0 ? 0 :
6457 i == Xsand_stoneout_1 && j == 1 ? 0 :
6458 i == Xsand_stoneout_1 && j == 2 ? 1 :
6459 i == Xsand_stoneout_1 && j == 3 ? 2 :
6460 i == Xsand_stoneout_1 && j == 4 ? 2 :
6461 i == Xsand_stoneout_1 && j == 5 ? 3 :
6462 i == Xsand_stoneout_1 && j == 6 ? 4 :
6463 i == Xsand_stoneout_1 && j == 7 ? 4 :
6464 i == Xsand_stoneout_2 && j == 0 ? 5 :
6465 i == Xsand_stoneout_2 && j == 1 ? 6 :
6466 i == Xsand_stoneout_2 && j == 2 ? 7 :
6467 i == Xsand_stoneout_2 && j == 3 ? 8 :
6468 i == Xsand_stoneout_2 && j == 4 ? 9 :
6469 i == Xsand_stoneout_2 && j == 5 ? 11 :
6470 i == Xsand_stoneout_2 && j == 6 ? 13 :
6471 i == Xsand_stoneout_2 && j == 7 ? 15 :
6472 i == Xboom_bug && j == 1 ? 2 :
6473 i == Xboom_bug && j == 2 ? 2 :
6474 i == Xboom_bug && j == 3 ? 4 :
6475 i == Xboom_bug && j == 4 ? 4 :
6476 i == Xboom_bug && j == 5 ? 2 :
6477 i == Xboom_bug && j == 6 ? 2 :
6478 i == Xboom_bug && j == 7 ? 0 :
6479 i == Xboom_bomb && j == 1 ? 2 :
6480 i == Xboom_bomb && j == 2 ? 2 :
6481 i == Xboom_bomb && j == 3 ? 4 :
6482 i == Xboom_bomb && j == 4 ? 4 :
6483 i == Xboom_bomb && j == 5 ? 2 :
6484 i == Xboom_bomb && j == 6 ? 2 :
6485 i == Xboom_bomb && j == 7 ? 0 :
6486 i == Xboom_android && j == 7 ? 6 :
6487 i == Xboom_1 && j == 1 ? 2 :
6488 i == Xboom_1 && j == 2 ? 2 :
6489 i == Xboom_1 && j == 3 ? 4 :
6490 i == Xboom_1 && j == 4 ? 4 :
6491 i == Xboom_1 && j == 5 ? 6 :
6492 i == Xboom_1 && j == 6 ? 6 :
6493 i == Xboom_1 && j == 7 ? 8 :
6494 i == Xboom_2 && j == 0 ? 8 :
6495 i == Xboom_2 && j == 1 ? 8 :
6496 i == Xboom_2 && j == 2 ? 10 :
6497 i == Xboom_2 && j == 3 ? 10 :
6498 i == Xboom_2 && j == 4 ? 10 :
6499 i == Xboom_2 && j == 5 ? 12 :
6500 i == Xboom_2 && j == 6 ? 12 :
6501 i == Xboom_2 && j == 7 ? 12 :
6503 special_animation && j == 4 ? 3 :
6504 effective_action != action ? 0 :
6510 int xxx_effective_action;
6511 int xxx_has_action_graphics;
6514 int element = object_mapping[i].element_rnd;
6515 int action = object_mapping[i].action;
6516 int direction = object_mapping[i].direction;
6517 boolean is_backside = object_mapping[i].is_backside;
6519 boolean action_removing = (action == ACTION_DIGGING ||
6520 action == ACTION_SNAPPING ||
6521 action == ACTION_COLLECTING);
6523 boolean action_exploding = ((action == ACTION_EXPLODING ||
6524 action == ACTION_SMASHED_BY_ROCK ||
6525 action == ACTION_SMASHED_BY_SPRING) &&
6526 element != EL_DIAMOND);
6527 boolean action_active = (action == ACTION_ACTIVE);
6528 boolean action_other = (action == ACTION_OTHER);
6532 int effective_element = get_effective_element_EM(i, j);
6534 int effective_element = (j > 5 && i == Yacid_splash_eB ? EL_EMPTY :
6535 j > 5 && i == Yacid_splash_wB ? EL_EMPTY :
6537 i == Xdrip_stretch ? element :
6538 i == Xdrip_stretchB ? element :
6539 i == Ydrip_s1 ? element :
6540 i == Ydrip_s1B ? element :
6541 i == Xball_1B ? element :
6542 i == Xball_2 ? element :
6543 i == Xball_2B ? element :
6544 i == Yball_eat ? element :
6545 i == Ykey_1_eat ? element :
6546 i == Ykey_2_eat ? element :
6547 i == Ykey_3_eat ? element :
6548 i == Ykey_4_eat ? element :
6549 i == Ykey_5_eat ? element :
6550 i == Ykey_6_eat ? element :
6551 i == Ykey_7_eat ? element :
6552 i == Ykey_8_eat ? element :
6553 i == Ylenses_eat ? element :
6554 i == Ymagnify_eat ? element :
6555 i == Ygrass_eat ? element :
6556 i == Ydirt_eat ? element :
6557 i == Yemerald_stone ? EL_EMERALD :
6558 i == Ydiamond_stone ? EL_ROCK :
6559 i == Xsand_stonein_1 ? element :
6560 i == Xsand_stonein_2 ? element :
6561 i == Xsand_stonein_3 ? element :
6562 i == Xsand_stonein_4 ? element :
6563 is_backside ? EL_EMPTY :
6564 action_removing ? EL_EMPTY :
6567 int effective_action = (j < 7 ? action :
6568 i == Xdrip_stretch ? action :
6569 i == Xdrip_stretchB ? action :
6570 i == Ydrip_s1 ? action :
6571 i == Ydrip_s1B ? action :
6572 i == Xball_1B ? action :
6573 i == Xball_2 ? action :
6574 i == Xball_2B ? action :
6575 i == Yball_eat ? action :
6576 i == Ykey_1_eat ? action :
6577 i == Ykey_2_eat ? action :
6578 i == Ykey_3_eat ? action :
6579 i == Ykey_4_eat ? action :
6580 i == Ykey_5_eat ? action :
6581 i == Ykey_6_eat ? action :
6582 i == Ykey_7_eat ? action :
6583 i == Ykey_8_eat ? action :
6584 i == Ylenses_eat ? action :
6585 i == Ymagnify_eat ? action :
6586 i == Ygrass_eat ? action :
6587 i == Ydirt_eat ? action :
6588 i == Xsand_stonein_1 ? action :
6589 i == Xsand_stonein_2 ? action :
6590 i == Xsand_stonein_3 ? action :
6591 i == Xsand_stonein_4 ? action :
6592 i == Xsand_stoneout_1 ? action :
6593 i == Xsand_stoneout_2 ? action :
6594 i == Xboom_android ? ACTION_EXPLODING :
6595 action_exploding ? ACTION_EXPLODING :
6596 action_active ? action :
6597 action_other ? action :
6599 int graphic = (el_act_dir2img(effective_element, effective_action,
6601 int crumbled = (el_act_dir2crm(effective_element, effective_action,
6603 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
6604 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
6605 boolean has_action_graphics = (graphic != base_graphic);
6606 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
6607 struct GraphicInfo *g = &graphic_info[graphic];
6609 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
6611 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
6614 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
6615 boolean special_animation = (action != ACTION_DEFAULT &&
6616 g->anim_frames == 3 &&
6617 g->anim_delay == 2 &&
6618 g->anim_mode & ANIM_LINEAR);
6619 xxx_sync_frame = (i == Xdrip_stretch ? 7 :
6620 i == Xdrip_stretchB ? 7 :
6621 i == Ydrip_s2 ? j + 8 :
6622 i == Ydrip_s2B ? j + 8 :
6631 i == Xfake_acid_1 ? 0 :
6632 i == Xfake_acid_2 ? 10 :
6633 i == Xfake_acid_3 ? 20 :
6634 i == Xfake_acid_4 ? 30 :
6635 i == Xfake_acid_5 ? 40 :
6636 i == Xfake_acid_6 ? 50 :
6637 i == Xfake_acid_7 ? 60 :
6638 i == Xfake_acid_8 ? 70 :
6640 i == Xball_2B ? j + 8 :
6641 i == Yball_eat ? j + 1 :
6642 i == Ykey_1_eat ? j + 1 :
6643 i == Ykey_2_eat ? j + 1 :
6644 i == Ykey_3_eat ? j + 1 :
6645 i == Ykey_4_eat ? j + 1 :
6646 i == Ykey_5_eat ? j + 1 :
6647 i == Ykey_6_eat ? j + 1 :
6648 i == Ykey_7_eat ? j + 1 :
6649 i == Ykey_8_eat ? j + 1 :
6650 i == Ylenses_eat ? j + 1 :
6651 i == Ymagnify_eat ? j + 1 :
6652 i == Ygrass_eat ? j + 1 :
6653 i == Ydirt_eat ? j + 1 :
6654 i == Xamoeba_1 ? 0 :
6655 i == Xamoeba_2 ? 1 :
6656 i == Xamoeba_3 ? 2 :
6657 i == Xamoeba_4 ? 3 :
6658 i == Xamoeba_5 ? 0 :
6659 i == Xamoeba_6 ? 1 :
6660 i == Xamoeba_7 ? 2 :
6661 i == Xamoeba_8 ? 3 :
6662 i == Xexit_2 ? j + 8 :
6663 i == Xexit_3 ? j + 16 :
6664 i == Xdynamite_1 ? 0 :
6665 i == Xdynamite_2 ? 8 :
6666 i == Xdynamite_3 ? 16 :
6667 i == Xdynamite_4 ? 24 :
6668 i == Xsand_stonein_1 ? j + 1 :
6669 i == Xsand_stonein_2 ? j + 9 :
6670 i == Xsand_stonein_3 ? j + 17 :
6671 i == Xsand_stonein_4 ? j + 25 :
6672 i == Xsand_stoneout_1 && j == 0 ? 0 :
6673 i == Xsand_stoneout_1 && j == 1 ? 0 :
6674 i == Xsand_stoneout_1 && j == 2 ? 1 :
6675 i == Xsand_stoneout_1 && j == 3 ? 2 :
6676 i == Xsand_stoneout_1 && j == 4 ? 2 :
6677 i == Xsand_stoneout_1 && j == 5 ? 3 :
6678 i == Xsand_stoneout_1 && j == 6 ? 4 :
6679 i == Xsand_stoneout_1 && j == 7 ? 4 :
6680 i == Xsand_stoneout_2 && j == 0 ? 5 :
6681 i == Xsand_stoneout_2 && j == 1 ? 6 :
6682 i == Xsand_stoneout_2 && j == 2 ? 7 :
6683 i == Xsand_stoneout_2 && j == 3 ? 8 :
6684 i == Xsand_stoneout_2 && j == 4 ? 9 :
6685 i == Xsand_stoneout_2 && j == 5 ? 11 :
6686 i == Xsand_stoneout_2 && j == 6 ? 13 :
6687 i == Xsand_stoneout_2 && j == 7 ? 15 :
6688 i == Xboom_bug && j == 1 ? 2 :
6689 i == Xboom_bug && j == 2 ? 2 :
6690 i == Xboom_bug && j == 3 ? 4 :
6691 i == Xboom_bug && j == 4 ? 4 :
6692 i == Xboom_bug && j == 5 ? 2 :
6693 i == Xboom_bug && j == 6 ? 2 :
6694 i == Xboom_bug && j == 7 ? 0 :
6695 i == Xboom_bomb && j == 1 ? 2 :
6696 i == Xboom_bomb && j == 2 ? 2 :
6697 i == Xboom_bomb && j == 3 ? 4 :
6698 i == Xboom_bomb && j == 4 ? 4 :
6699 i == Xboom_bomb && j == 5 ? 2 :
6700 i == Xboom_bomb && j == 6 ? 2 :
6701 i == Xboom_bomb && j == 7 ? 0 :
6702 i == Xboom_android && j == 7 ? 6 :
6703 i == Xboom_1 && j == 1 ? 2 :
6704 i == Xboom_1 && j == 2 ? 2 :
6705 i == Xboom_1 && j == 3 ? 4 :
6706 i == Xboom_1 && j == 4 ? 4 :
6707 i == Xboom_1 && j == 5 ? 6 :
6708 i == Xboom_1 && j == 6 ? 6 :
6709 i == Xboom_1 && j == 7 ? 8 :
6710 i == Xboom_2 && j == 0 ? 8 :
6711 i == Xboom_2 && j == 1 ? 8 :
6712 i == Xboom_2 && j == 2 ? 10 :
6713 i == Xboom_2 && j == 3 ? 10 :
6714 i == Xboom_2 && j == 4 ? 10 :
6715 i == Xboom_2 && j == 5 ? 12 :
6716 i == Xboom_2 && j == 6 ? 12 :
6717 i == Xboom_2 && j == 7 ? 12 :
6718 special_animation && j == 4 ? 3 :
6719 effective_action != action ? 0 :
6722 xxx_effective_action = effective_action;
6723 xxx_has_action_graphics = has_action_graphics;
6728 int frame = getAnimationFrame(g->anim_frames,
6731 g->anim_start_frame,
6745 int old_src_x = g_em->src_x;
6746 int old_src_y = g_em->src_y;
6750 getGraphicSourceExt(graphic, frame, &g_em->bitmap, &g_em->src_x, &g_em->src_y,
6751 g->double_movement && is_backside);
6753 getGraphicSourceExt(graphic, frame, &g_em->bitmap,
6754 &g_em->src_x, &g_em->src_y, FALSE);
6765 if (graphic == IMG_BUG_MOVING_RIGHT)
6766 printf("::: %d, %d, %d: %d, %d [%d, %d -> %d, %d]\n", graphic, x, y,
6767 g->double_movement, is_backside,
6768 old_src_x, old_src_y, g_em->src_x, g_em->src_y);
6776 g_em->src_offset_x = 0;
6777 g_em->src_offset_y = 0;
6778 g_em->dst_offset_x = 0;
6779 g_em->dst_offset_y = 0;
6780 g_em->width = TILEX;
6781 g_em->height = TILEY;
6783 g_em->preserve_background = FALSE;
6786 /* (updating the "crumbled" graphic definitions is probably not really needed,
6787 as animations for crumbled graphics can't be longer than one EMC cycle) */
6789 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
6794 g_em->crumbled_bitmap = NULL;
6795 g_em->crumbled_src_x = 0;
6796 g_em->crumbled_src_y = 0;
6798 g_em->has_crumbled_graphics = FALSE;
6800 if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
6802 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
6803 g_crumbled->anim_delay,
6804 g_crumbled->anim_mode,
6805 g_crumbled->anim_start_frame,
6808 getGraphicSource(crumbled, frame_crumbled, &g_em->crumbled_bitmap,
6809 &g_em->crumbled_src_x, &g_em->crumbled_src_y);
6811 g_em->has_crumbled_graphics = TRUE;
6817 int effective_action = xxx_effective_action;
6818 int has_action_graphics = xxx_has_action_graphics;
6820 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
6821 effective_action == ACTION_MOVING ||
6822 effective_action == ACTION_PUSHING ||
6823 effective_action == ACTION_EATING)) ||
6824 (!has_action_graphics && (effective_action == ACTION_FILLING ||
6825 effective_action == ACTION_EMPTYING)))
6828 (effective_action == ACTION_FALLING ||
6829 effective_action == ACTION_FILLING ||
6830 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
6831 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
6832 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
6833 int num_steps = (i == Ydrip_s1 ? 16 :
6834 i == Ydrip_s1B ? 16 :
6835 i == Ydrip_s2 ? 16 :
6836 i == Ydrip_s2B ? 16 :
6837 i == Xsand_stonein_1 ? 32 :
6838 i == Xsand_stonein_2 ? 32 :
6839 i == Xsand_stonein_3 ? 32 :
6840 i == Xsand_stonein_4 ? 32 :
6841 i == Xsand_stoneout_1 ? 16 :
6842 i == Xsand_stoneout_2 ? 16 : 8);
6843 int cx = ABS(dx) * (TILEX / num_steps);
6844 int cy = ABS(dy) * (TILEY / num_steps);
6845 int step_frame = (i == Ydrip_s2 ? j + 8 :
6846 i == Ydrip_s2B ? j + 8 :
6847 i == Xsand_stonein_2 ? j + 8 :
6848 i == Xsand_stonein_3 ? j + 16 :
6849 i == Xsand_stonein_4 ? j + 24 :
6850 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
6851 int step = (is_backside ? step_frame : num_steps - step_frame);
6853 if (is_backside) /* tile where movement starts */
6855 if (dx < 0 || dy < 0)
6857 g_em->src_offset_x = cx * step;
6858 g_em->src_offset_y = cy * step;
6862 g_em->dst_offset_x = cx * step;
6863 g_em->dst_offset_y = cy * step;
6866 else /* tile where movement ends */
6868 if (dx < 0 || dy < 0)
6870 g_em->dst_offset_x = cx * step;
6871 g_em->dst_offset_y = cy * step;
6875 g_em->src_offset_x = cx * step;
6876 g_em->src_offset_y = cy * step;
6880 g_em->width = TILEX - cx * step;
6881 g_em->height = TILEY - cy * step;
6884 /* create unique graphic identifier to decide if tile must be redrawn */
6885 /* bit 31 - 16 (16 bit): EM style graphic
6886 bit 15 - 12 ( 4 bit): EM style frame
6887 bit 11 - 6 ( 6 bit): graphic width
6888 bit 5 - 0 ( 6 bit): graphic height */
6889 g_em->unique_identifier =
6890 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
6896 void getGraphicSourcePlayerExt_EM(struct GraphicInfo_EM *g_em,
6897 int player_nr, int anim, int frame_em)
6899 int element = player_mapping[player_nr][anim].element_rnd;
6900 int action = player_mapping[player_nr][anim].action;
6901 int direction = player_mapping[player_nr][anim].direction;
6902 int graphic = (direction == MV_NONE ?
6903 el_act2img(element, action) :
6904 el_act_dir2img(element, action, direction));
6905 struct GraphicInfo *g = &graphic_info[graphic];
6908 InitPlayerGfxAnimation(&stored_player[player_nr], action, direction);
6910 stored_player[player_nr].StepFrame = frame_em;
6912 sync_frame = stored_player[player_nr].Frame;
6914 int frame = getAnimationFrame(g->anim_frames,
6917 g->anim_start_frame,
6920 getGraphicSourceExt(graphic, frame, &g_em->bitmap,
6921 &g_em->src_x, &g_em->src_y, FALSE);
6924 printf("::: %d: %d, %d [%d]\n",
6926 stored_player[player_nr].Frame,
6927 stored_player[player_nr].StepFrame,
6932 void InitGraphicInfo_EM(void)
6935 struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
6936 struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
6941 int num_em_gfx_errors = 0;
6943 if (graphic_info_em_object[0][0].bitmap == NULL)
6945 /* EM graphics not yet initialized in em_open_all() */
6950 printf("::: [4 errors can be ignored (1 x 'bomb', 3 x 'em_dynamite']\n");
6953 /* always start with reliable default values */
6954 for (i = 0; i < TILE_MAX; i++)
6956 object_mapping[i].element_rnd = EL_UNKNOWN;
6957 object_mapping[i].is_backside = FALSE;
6958 object_mapping[i].action = ACTION_DEFAULT;
6959 object_mapping[i].direction = MV_NONE;
6962 /* always start with reliable default values */
6963 for (p = 0; p < MAX_PLAYERS; p++)
6965 for (i = 0; i < SPR_MAX; i++)
6967 player_mapping[p][i].element_rnd = EL_UNKNOWN;
6968 player_mapping[p][i].action = ACTION_DEFAULT;
6969 player_mapping[p][i].direction = MV_NONE;
6973 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
6975 int e = em_object_mapping_list[i].element_em;
6977 object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd;
6978 object_mapping[e].is_backside = em_object_mapping_list[i].is_backside;
6980 if (em_object_mapping_list[i].action != -1)
6981 object_mapping[e].action = em_object_mapping_list[i].action;
6983 if (em_object_mapping_list[i].direction != -1)
6984 object_mapping[e].direction =
6985 MV_DIR_FROM_BIT(em_object_mapping_list[i].direction);
6988 for (i = 0; em_player_mapping_list[i].action_em != -1; i++)
6990 int a = em_player_mapping_list[i].action_em;
6991 int p = em_player_mapping_list[i].player_nr;
6993 player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd;
6995 if (em_player_mapping_list[i].action != -1)
6996 player_mapping[p][a].action = em_player_mapping_list[i].action;
6998 if (em_player_mapping_list[i].direction != -1)
6999 player_mapping[p][a].direction =
7000 MV_DIR_FROM_BIT(em_player_mapping_list[i].direction);
7003 for (i = 0; i < TILE_MAX; i++)
7005 int element = object_mapping[i].element_rnd;
7006 int action = object_mapping[i].action;
7007 int direction = object_mapping[i].direction;
7008 boolean is_backside = object_mapping[i].is_backside;
7010 boolean action_removing = (action == ACTION_DIGGING ||
7011 action == ACTION_SNAPPING ||
7012 action == ACTION_COLLECTING);
7014 boolean action_exploding = ((action == ACTION_EXPLODING ||
7015 action == ACTION_SMASHED_BY_ROCK ||
7016 action == ACTION_SMASHED_BY_SPRING) &&
7017 element != EL_DIAMOND);
7018 boolean action_active = (action == ACTION_ACTIVE);
7019 boolean action_other = (action == ACTION_OTHER);
7021 for (j = 0; j < 8; j++)
7024 int effective_element = get_effective_element_EM(i, j);
7026 int effective_element = (j > 5 && i == Yacid_splash_eB ? EL_EMPTY :
7027 j > 5 && i == Yacid_splash_wB ? EL_EMPTY :
7029 i == Xdrip_stretch ? element :
7030 i == Xdrip_stretchB ? element :
7031 i == Ydrip_s1 ? element :
7032 i == Ydrip_s1B ? element :
7033 i == Xball_1B ? element :
7034 i == Xball_2 ? element :
7035 i == Xball_2B ? element :
7036 i == Yball_eat ? element :
7037 i == Ykey_1_eat ? element :
7038 i == Ykey_2_eat ? element :
7039 i == Ykey_3_eat ? element :
7040 i == Ykey_4_eat ? element :
7041 i == Ykey_5_eat ? element :
7042 i == Ykey_6_eat ? element :
7043 i == Ykey_7_eat ? element :
7044 i == Ykey_8_eat ? element :
7045 i == Ylenses_eat ? element :
7046 i == Ymagnify_eat ? element :
7047 i == Ygrass_eat ? element :
7048 i == Ydirt_eat ? element :
7049 i == Yemerald_stone ? EL_EMERALD :
7050 i == Ydiamond_stone ? EL_ROCK :
7051 i == Xsand_stonein_1 ? element :
7052 i == Xsand_stonein_2 ? element :
7053 i == Xsand_stonein_3 ? element :
7054 i == Xsand_stonein_4 ? element :
7055 is_backside ? EL_EMPTY :
7056 action_removing ? EL_EMPTY :
7059 int effective_action = (j < 7 ? action :
7060 i == Xdrip_stretch ? action :
7061 i == Xdrip_stretchB ? action :
7062 i == Ydrip_s1 ? action :
7063 i == Ydrip_s1B ? action :
7064 i == Xball_1B ? action :
7065 i == Xball_2 ? action :
7066 i == Xball_2B ? action :
7067 i == Yball_eat ? action :
7068 i == Ykey_1_eat ? action :
7069 i == Ykey_2_eat ? action :
7070 i == Ykey_3_eat ? action :
7071 i == Ykey_4_eat ? action :
7072 i == Ykey_5_eat ? action :
7073 i == Ykey_6_eat ? action :
7074 i == Ykey_7_eat ? action :
7075 i == Ykey_8_eat ? action :
7076 i == Ylenses_eat ? action :
7077 i == Ymagnify_eat ? action :
7078 i == Ygrass_eat ? action :
7079 i == Ydirt_eat ? action :
7080 i == Xsand_stonein_1 ? action :
7081 i == Xsand_stonein_2 ? action :
7082 i == Xsand_stonein_3 ? action :
7083 i == Xsand_stonein_4 ? action :
7084 i == Xsand_stoneout_1 ? action :
7085 i == Xsand_stoneout_2 ? action :
7086 i == Xboom_android ? ACTION_EXPLODING :
7087 action_exploding ? ACTION_EXPLODING :
7088 action_active ? action :
7089 action_other ? action :
7091 int graphic = (el_act_dir2img(effective_element, effective_action,
7093 int crumbled = (el_act_dir2crm(effective_element, effective_action,
7095 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
7096 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
7097 boolean has_action_graphics = (graphic != base_graphic);
7098 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
7099 struct GraphicInfo *g = &graphic_info[graphic];
7101 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
7103 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
7106 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
7107 boolean special_animation = (action != ACTION_DEFAULT &&
7108 g->anim_frames == 3 &&
7109 g->anim_delay == 2 &&
7110 g->anim_mode & ANIM_LINEAR);
7111 int sync_frame = (i == Xdrip_stretch ? 7 :
7112 i == Xdrip_stretchB ? 7 :
7113 i == Ydrip_s2 ? j + 8 :
7114 i == Ydrip_s2B ? j + 8 :
7123 i == Xfake_acid_1 ? 0 :
7124 i == Xfake_acid_2 ? 10 :
7125 i == Xfake_acid_3 ? 20 :
7126 i == Xfake_acid_4 ? 30 :
7127 i == Xfake_acid_5 ? 40 :
7128 i == Xfake_acid_6 ? 50 :
7129 i == Xfake_acid_7 ? 60 :
7130 i == Xfake_acid_8 ? 70 :
7132 i == Xball_2B ? j + 8 :
7133 i == Yball_eat ? j + 1 :
7134 i == Ykey_1_eat ? j + 1 :
7135 i == Ykey_2_eat ? j + 1 :
7136 i == Ykey_3_eat ? j + 1 :
7137 i == Ykey_4_eat ? j + 1 :
7138 i == Ykey_5_eat ? j + 1 :
7139 i == Ykey_6_eat ? j + 1 :
7140 i == Ykey_7_eat ? j + 1 :
7141 i == Ykey_8_eat ? j + 1 :
7142 i == Ylenses_eat ? j + 1 :
7143 i == Ymagnify_eat ? j + 1 :
7144 i == Ygrass_eat ? j + 1 :
7145 i == Ydirt_eat ? j + 1 :
7146 i == Xamoeba_1 ? 0 :
7147 i == Xamoeba_2 ? 1 :
7148 i == Xamoeba_3 ? 2 :
7149 i == Xamoeba_4 ? 3 :
7150 i == Xamoeba_5 ? 0 :
7151 i == Xamoeba_6 ? 1 :
7152 i == Xamoeba_7 ? 2 :
7153 i == Xamoeba_8 ? 3 :
7154 i == Xexit_2 ? j + 8 :
7155 i == Xexit_3 ? j + 16 :
7156 i == Xdynamite_1 ? 0 :
7157 i == Xdynamite_2 ? 8 :
7158 i == Xdynamite_3 ? 16 :
7159 i == Xdynamite_4 ? 24 :
7160 i == Xsand_stonein_1 ? j + 1 :
7161 i == Xsand_stonein_2 ? j + 9 :
7162 i == Xsand_stonein_3 ? j + 17 :
7163 i == Xsand_stonein_4 ? j + 25 :
7164 i == Xsand_stoneout_1 && j == 0 ? 0 :
7165 i == Xsand_stoneout_1 && j == 1 ? 0 :
7166 i == Xsand_stoneout_1 && j == 2 ? 1 :
7167 i == Xsand_stoneout_1 && j == 3 ? 2 :
7168 i == Xsand_stoneout_1 && j == 4 ? 2 :
7169 i == Xsand_stoneout_1 && j == 5 ? 3 :
7170 i == Xsand_stoneout_1 && j == 6 ? 4 :
7171 i == Xsand_stoneout_1 && j == 7 ? 4 :
7172 i == Xsand_stoneout_2 && j == 0 ? 5 :
7173 i == Xsand_stoneout_2 && j == 1 ? 6 :
7174 i == Xsand_stoneout_2 && j == 2 ? 7 :
7175 i == Xsand_stoneout_2 && j == 3 ? 8 :
7176 i == Xsand_stoneout_2 && j == 4 ? 9 :
7177 i == Xsand_stoneout_2 && j == 5 ? 11 :
7178 i == Xsand_stoneout_2 && j == 6 ? 13 :
7179 i == Xsand_stoneout_2 && j == 7 ? 15 :
7180 i == Xboom_bug && j == 1 ? 2 :
7181 i == Xboom_bug && j == 2 ? 2 :
7182 i == Xboom_bug && j == 3 ? 4 :
7183 i == Xboom_bug && j == 4 ? 4 :
7184 i == Xboom_bug && j == 5 ? 2 :
7185 i == Xboom_bug && j == 6 ? 2 :
7186 i == Xboom_bug && j == 7 ? 0 :
7187 i == Xboom_bomb && j == 1 ? 2 :
7188 i == Xboom_bomb && j == 2 ? 2 :
7189 i == Xboom_bomb && j == 3 ? 4 :
7190 i == Xboom_bomb && j == 4 ? 4 :
7191 i == Xboom_bomb && j == 5 ? 2 :
7192 i == Xboom_bomb && j == 6 ? 2 :
7193 i == Xboom_bomb && j == 7 ? 0 :
7194 i == Xboom_android && j == 7 ? 6 :
7195 i == Xboom_1 && j == 1 ? 2 :
7196 i == Xboom_1 && j == 2 ? 2 :
7197 i == Xboom_1 && j == 3 ? 4 :
7198 i == Xboom_1 && j == 4 ? 4 :
7199 i == Xboom_1 && j == 5 ? 6 :
7200 i == Xboom_1 && j == 6 ? 6 :
7201 i == Xboom_1 && j == 7 ? 8 :
7202 i == Xboom_2 && j == 0 ? 8 :
7203 i == Xboom_2 && j == 1 ? 8 :
7204 i == Xboom_2 && j == 2 ? 10 :
7205 i == Xboom_2 && j == 3 ? 10 :
7206 i == Xboom_2 && j == 4 ? 10 :
7207 i == Xboom_2 && j == 5 ? 12 :
7208 i == Xboom_2 && j == 6 ? 12 :
7209 i == Xboom_2 && j == 7 ? 12 :
7210 special_animation && j == 4 ? 3 :
7211 effective_action != action ? 0 :
7215 Bitmap *debug_bitmap = g_em->bitmap;
7216 int debug_src_x = g_em->src_x;
7217 int debug_src_y = g_em->src_y;
7220 int frame = getAnimationFrame(g->anim_frames,
7223 g->anim_start_frame,
7226 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y,
7227 g->double_movement && is_backside);
7229 g_em->bitmap = src_bitmap;
7230 g_em->src_x = src_x;
7231 g_em->src_y = src_y;
7232 g_em->src_offset_x = 0;
7233 g_em->src_offset_y = 0;
7234 g_em->dst_offset_x = 0;
7235 g_em->dst_offset_y = 0;
7236 g_em->width = TILEX;
7237 g_em->height = TILEY;
7239 g_em->preserve_background = FALSE;
7242 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
7247 g_em->crumbled_bitmap = NULL;
7248 g_em->crumbled_src_x = 0;
7249 g_em->crumbled_src_y = 0;
7250 g_em->crumbled_border_size = 0;
7252 g_em->has_crumbled_graphics = FALSE;
7255 if (has_crumbled_graphics && crumbled == IMG_EMPTY_SPACE)
7256 printf("::: empty crumbled: %d [%s], %d, %d\n",
7257 effective_element, element_info[effective_element].token_name,
7258 effective_action, direction);
7261 /* if element can be crumbled, but certain action graphics are just empty
7262 space (like instantly snapping sand to empty space in 1 frame), do not
7263 treat these empty space graphics as crumbled graphics in EMC engine */
7264 if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
7266 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
7267 g_crumbled->anim_delay,
7268 g_crumbled->anim_mode,
7269 g_crumbled->anim_start_frame,
7272 getGraphicSource(crumbled, frame_crumbled, &src_bitmap, &src_x, &src_y);
7274 g_em->has_crumbled_graphics = TRUE;
7275 g_em->crumbled_bitmap = src_bitmap;
7276 g_em->crumbled_src_x = src_x;
7277 g_em->crumbled_src_y = src_y;
7278 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
7282 if (g_em == &graphic_info_em_object[207][0])
7283 printf("... %d, %d [%d, %d, %d, %d] [%d, %d, %d, %d, %d, %d => %d]\n",
7284 graphic_info_em_object[207][0].crumbled_src_x,
7285 graphic_info_em_object[207][0].crumbled_src_y,
7287 crumbled, frame, src_x, src_y,
7292 g->anim_start_frame,
7294 gfx.anim_random_frame,
7299 printf("::: EMC tile %d is crumbled\n", i);
7305 if (element == EL_ROCK &&
7306 effective_action == ACTION_FILLING)
7307 printf("::: has_action_graphics == %d\n", has_action_graphics);
7310 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
7311 effective_action == ACTION_MOVING ||
7312 effective_action == ACTION_PUSHING ||
7313 effective_action == ACTION_EATING)) ||
7314 (!has_action_graphics && (effective_action == ACTION_FILLING ||
7315 effective_action == ACTION_EMPTYING)))
7318 (effective_action == ACTION_FALLING ||
7319 effective_action == ACTION_FILLING ||
7320 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
7321 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
7322 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
7323 int num_steps = (i == Ydrip_s1 ? 16 :
7324 i == Ydrip_s1B ? 16 :
7325 i == Ydrip_s2 ? 16 :
7326 i == Ydrip_s2B ? 16 :
7327 i == Xsand_stonein_1 ? 32 :
7328 i == Xsand_stonein_2 ? 32 :
7329 i == Xsand_stonein_3 ? 32 :
7330 i == Xsand_stonein_4 ? 32 :
7331 i == Xsand_stoneout_1 ? 16 :
7332 i == Xsand_stoneout_2 ? 16 : 8);
7333 int cx = ABS(dx) * (TILEX / num_steps);
7334 int cy = ABS(dy) * (TILEY / num_steps);
7335 int step_frame = (i == Ydrip_s2 ? j + 8 :
7336 i == Ydrip_s2B ? j + 8 :
7337 i == Xsand_stonein_2 ? j + 8 :
7338 i == Xsand_stonein_3 ? j + 16 :
7339 i == Xsand_stonein_4 ? j + 24 :
7340 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
7341 int step = (is_backside ? step_frame : num_steps - step_frame);
7343 if (is_backside) /* tile where movement starts */
7345 if (dx < 0 || dy < 0)
7347 g_em->src_offset_x = cx * step;
7348 g_em->src_offset_y = cy * step;
7352 g_em->dst_offset_x = cx * step;
7353 g_em->dst_offset_y = cy * step;
7356 else /* tile where movement ends */
7358 if (dx < 0 || dy < 0)
7360 g_em->dst_offset_x = cx * step;
7361 g_em->dst_offset_y = cy * step;
7365 g_em->src_offset_x = cx * step;
7366 g_em->src_offset_y = cy * step;
7370 g_em->width = TILEX - cx * step;
7371 g_em->height = TILEY - cy * step;
7374 /* create unique graphic identifier to decide if tile must be redrawn */
7375 /* bit 31 - 16 (16 bit): EM style graphic
7376 bit 15 - 12 ( 4 bit): EM style frame
7377 bit 11 - 6 ( 6 bit): graphic width
7378 bit 5 - 0 ( 6 bit): graphic height */
7379 g_em->unique_identifier =
7380 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
7384 /* skip check for EMC elements not contained in original EMC artwork */
7385 if (element == EL_EMC_FAKE_ACID)
7388 if (g_em->bitmap != debug_bitmap ||
7389 g_em->src_x != debug_src_x ||
7390 g_em->src_y != debug_src_y ||
7391 g_em->src_offset_x != 0 ||
7392 g_em->src_offset_y != 0 ||
7393 g_em->dst_offset_x != 0 ||
7394 g_em->dst_offset_y != 0 ||
7395 g_em->width != TILEX ||
7396 g_em->height != TILEY)
7398 static int last_i = -1;
7406 printf("::: EMC GFX ERROR for element %d -> %d ('%s', '%s', %d)",
7407 i, element, element_info[element].token_name,
7408 element_action_info[effective_action].suffix, direction);
7410 if (element != effective_element)
7411 printf(" [%d ('%s')]",
7413 element_info[effective_element].token_name);
7417 if (g_em->bitmap != debug_bitmap)
7418 printf(" %d (%d): different bitmap! (0x%08x != 0x%08x)\n",
7419 j, is_backside, (int)(g_em->bitmap), (int)(debug_bitmap));
7421 if (g_em->src_x != debug_src_x ||
7422 g_em->src_y != debug_src_y)
7423 printf(" frame %d (%c): %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
7424 j, (is_backside ? 'B' : 'F'),
7425 g_em->src_x, g_em->src_y,
7426 g_em->src_x / 32, g_em->src_y / 32,
7427 debug_src_x, debug_src_y,
7428 debug_src_x / 32, debug_src_y / 32);
7430 if (g_em->src_offset_x != 0 ||
7431 g_em->src_offset_y != 0 ||
7432 g_em->dst_offset_x != 0 ||
7433 g_em->dst_offset_y != 0)
7434 printf(" %d (%d): offsets %d,%d and %d,%d should be all 0\n",
7436 g_em->src_offset_x, g_em->src_offset_y,
7437 g_em->dst_offset_x, g_em->dst_offset_y);
7439 if (g_em->width != TILEX ||
7440 g_em->height != TILEY)
7441 printf(" %d (%d): size %d,%d should be %d,%d\n",
7443 g_em->width, g_em->height, TILEX, TILEY);
7445 num_em_gfx_errors++;
7452 for (i = 0; i < TILE_MAX; i++)
7454 for (j = 0; j < 8; j++)
7456 int element = object_mapping[i].element_rnd;
7457 int action = object_mapping[i].action;
7458 int direction = object_mapping[i].direction;
7459 boolean is_backside = object_mapping[i].is_backside;
7460 int graphic_action = el_act_dir2img(element, action, direction);
7461 int graphic_default = el_act_dir2img(element, ACTION_DEFAULT, direction);
7463 if ((action == ACTION_SMASHED_BY_ROCK ||
7464 action == ACTION_SMASHED_BY_SPRING ||
7465 action == ACTION_EATING) &&
7466 graphic_action == graphic_default)
7468 int e = (action == ACTION_SMASHED_BY_ROCK ? Ystone_s :
7469 action == ACTION_SMASHED_BY_SPRING ? Yspring_s :
7470 direction == MV_LEFT ? (is_backside? Yspring_wB: Yspring_w) :
7471 direction == MV_RIGHT ? (is_backside? Yspring_eB: Yspring_e) :
7474 /* no separate animation for "smashed by rock" -- use rock instead */
7475 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
7476 struct GraphicInfo_EM *g_xx = &graphic_info_em_object[e][7 - j];
7478 g_em->bitmap = g_xx->bitmap;
7479 g_em->src_x = g_xx->src_x;
7480 g_em->src_y = g_xx->src_y;
7481 g_em->src_offset_x = g_xx->src_offset_x;
7482 g_em->src_offset_y = g_xx->src_offset_y;
7483 g_em->dst_offset_x = g_xx->dst_offset_x;
7484 g_em->dst_offset_y = g_xx->dst_offset_y;
7485 g_em->width = g_xx->width;
7486 g_em->height = g_xx->height;
7487 g_em->unique_identifier = g_xx->unique_identifier;
7490 g_em->preserve_background = TRUE;
7495 for (p = 0; p < MAX_PLAYERS; p++)
7497 for (i = 0; i < SPR_MAX; i++)
7499 int element = player_mapping[p][i].element_rnd;
7500 int action = player_mapping[p][i].action;
7501 int direction = player_mapping[p][i].direction;
7503 for (j = 0; j < 8; j++)
7505 int effective_element = element;
7506 int effective_action = action;
7507 int graphic = (direction == MV_NONE ?
7508 el_act2img(effective_element, effective_action) :
7509 el_act_dir2img(effective_element, effective_action,
7511 struct GraphicInfo *g = &graphic_info[graphic];
7512 struct GraphicInfo_EM *g_em = &graphic_info_em_player[p][i][7 - j];
7518 Bitmap *debug_bitmap = g_em->bitmap;
7519 int debug_src_x = g_em->src_x;
7520 int debug_src_y = g_em->src_y;
7523 int frame = getAnimationFrame(g->anim_frames,
7526 g->anim_start_frame,
7529 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
7531 g_em->bitmap = src_bitmap;
7532 g_em->src_x = src_x;
7533 g_em->src_y = src_y;
7534 g_em->src_offset_x = 0;
7535 g_em->src_offset_y = 0;
7536 g_em->dst_offset_x = 0;
7537 g_em->dst_offset_y = 0;
7538 g_em->width = TILEX;
7539 g_em->height = TILEY;
7543 /* skip check for EMC elements not contained in original EMC artwork */
7544 if (element == EL_PLAYER_3 ||
7545 element == EL_PLAYER_4)
7548 if (g_em->bitmap != debug_bitmap ||
7549 g_em->src_x != debug_src_x ||
7550 g_em->src_y != debug_src_y)
7552 static int last_i = -1;
7560 printf("::: EMC GFX ERROR for p/a %d/%d -> %d ('%s', '%s', %d)",
7561 p, i, element, element_info[element].token_name,
7562 element_action_info[effective_action].suffix, direction);
7564 if (element != effective_element)
7565 printf(" [%d ('%s')]",
7567 element_info[effective_element].token_name);
7571 if (g_em->bitmap != debug_bitmap)
7572 printf(" %d: different bitmap! (0x%08x != 0x%08x)\n",
7573 j, (int)(g_em->bitmap), (int)(debug_bitmap));
7575 if (g_em->src_x != debug_src_x ||
7576 g_em->src_y != debug_src_y)
7577 printf(" frame %d: %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
7579 g_em->src_x, g_em->src_y,
7580 g_em->src_x / 32, g_em->src_y / 32,
7581 debug_src_x, debug_src_y,
7582 debug_src_x / 32, debug_src_y / 32);
7584 num_em_gfx_errors++;
7594 printf("::: [%d errors found]\n", num_em_gfx_errors);
7600 void PlayMenuSoundExt(int sound)
7602 if (sound == SND_UNDEFINED)
7605 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
7606 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
7609 if (IS_LOOP_SOUND(sound))
7610 PlaySoundLoop(sound);
7615 void PlayMenuSound()
7617 PlayMenuSoundExt(menu.sound[game_status]);
7620 void PlayMenuSoundStereo(int sound, int stereo_position)
7622 if (sound == SND_UNDEFINED)
7625 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
7626 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
7629 if (IS_LOOP_SOUND(sound))
7630 PlaySoundExt(sound, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_LOOP);
7632 PlaySoundStereo(sound, stereo_position);
7635 void PlayMenuSoundIfLoopExt(int sound)
7637 if (sound == SND_UNDEFINED)
7640 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
7641 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
7644 if (IS_LOOP_SOUND(sound))
7645 PlaySoundLoop(sound);
7648 void PlayMenuSoundIfLoop()
7650 PlayMenuSoundIfLoopExt(menu.sound[game_status]);
7653 void PlayMenuMusicExt(int music)
7655 if (music == MUS_UNDEFINED)
7658 if (!setup.sound_music)
7664 void PlayMenuMusic()
7666 PlayMenuMusicExt(menu.music[game_status]);
7669 void PlaySoundActivating()
7672 PlaySound(SND_MENU_ITEM_ACTIVATING);
7676 void PlaySoundSelecting()
7679 PlaySound(SND_MENU_ITEM_SELECTING);
7683 void ToggleFullscreenIfNeeded()
7685 boolean change_fullscreen = (setup.fullscreen !=
7686 video.fullscreen_enabled);
7687 boolean change_fullscreen_mode = (video.fullscreen_enabled &&
7688 !strEqual(setup.fullscreen_mode,
7689 video.fullscreen_mode_current));
7691 if (!video.fullscreen_available)
7695 if (change_fullscreen || change_fullscreen_mode)
7697 if (setup.fullscreen != video.fullscreen_enabled ||
7698 setup.fullscreen_mode != video.fullscreen_mode_current)
7701 Bitmap *tmp_backbuffer = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
7703 /* save backbuffer content which gets lost when toggling fullscreen mode */
7704 BlitBitmap(backbuffer, tmp_backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
7707 if (change_fullscreen_mode)
7709 if (setup.fullscreen && video.fullscreen_enabled)
7712 /* keep fullscreen, but change fullscreen mode (screen resolution) */
7714 /* (this is now set in sdl.c) */
7716 video.fullscreen_mode_current = setup.fullscreen_mode;
7718 video.fullscreen_enabled = FALSE; /* force new fullscreen mode */
7721 /* toggle fullscreen */
7722 ChangeVideoModeIfNeeded(setup.fullscreen);
7724 setup.fullscreen = video.fullscreen_enabled;
7726 /* restore backbuffer content from temporary backbuffer backup bitmap */
7727 BlitBitmap(tmp_backbuffer, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
7729 FreeBitmap(tmp_backbuffer);
7732 /* update visible window/screen */
7733 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
7735 redraw_mask = REDRAW_ALL;