1 /***********************************************************
2 * Rocks'n'Diamonds -- McDuffin Strikes Back! *
3 *----------------------------------------------------------*
4 * (c) 1995-2006 Artsoft Entertainment *
6 * Detmolder Strasse 189 *
9 * e-mail: info@artsoft.org *
10 *----------------------------------------------------------*
12 ***********************************************************/
14 #include "libgame/libgame.h"
25 /* select level set with EMC X11 graphics before activating EM GFX debugging */
26 #define DEBUG_EM_GFX 0
28 /* tool button identifiers */
29 #define TOOL_CTRL_ID_YES 0
30 #define TOOL_CTRL_ID_NO 1
31 #define TOOL_CTRL_ID_CONFIRM 2
32 #define TOOL_CTRL_ID_PLAYER_1 3
33 #define TOOL_CTRL_ID_PLAYER_2 4
34 #define TOOL_CTRL_ID_PLAYER_3 5
35 #define TOOL_CTRL_ID_PLAYER_4 6
37 #define NUM_TOOL_BUTTONS 7
39 /* forward declaration for internal use */
40 static void UnmapToolButtons();
41 static void HandleToolButtons(struct GadgetInfo *);
42 static int el_act_dir2crm(int, int, int);
43 static int el_act2crm(int, int);
45 static struct GadgetInfo *tool_gadget[NUM_TOOL_BUTTONS];
46 static int request_gadget_id = -1;
48 static char *print_if_not_empty(int element)
50 static char *s = NULL;
51 char *token_name = element_info[element].token_name;
56 s = checked_malloc(strlen(token_name) + 10 + 1);
58 if (element != EL_EMPTY)
59 sprintf(s, "%d\t['%s']", element, token_name);
61 sprintf(s, "%d", element);
66 void DumpTile(int x, int y)
71 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
78 printf("Field Info: SCREEN(%d, %d), LEVEL(%d, %d)\n", sx, sy, x, y);
81 if (!IN_LEV_FIELD(x, y))
83 printf("(not in level field)\n");
89 printf(" Feld: %d\t['%s']\n", Feld[x][y],
90 element_info[Feld[x][y]].token_name);
91 printf(" Back: %s\n", print_if_not_empty(Back[x][y]));
92 printf(" Store: %s\n", print_if_not_empty(Store[x][y]));
93 printf(" Store2: %s\n", print_if_not_empty(Store2[x][y]));
94 printf(" StorePlayer: %s\n", print_if_not_empty(StorePlayer[x][y]));
95 printf(" MovPos: %d\n", MovPos[x][y]);
96 printf(" MovDir: %d\n", MovDir[x][y]);
97 printf(" MovDelay: %d\n", MovDelay[x][y]);
98 printf(" ChangeDelay: %d\n", ChangeDelay[x][y]);
99 printf(" CustomValue: %d\n", CustomValue[x][y]);
100 printf(" GfxElement: %d\n", GfxElement[x][y]);
101 printf(" GfxAction: %d\n", GfxAction[x][y]);
102 printf(" GfxFrame: %d\n", GfxFrame[x][y]);
106 void SetDrawtoField(int mode)
108 if (mode == DRAW_BUFFERED && setup.soft_scrolling)
119 drawto_field = fieldbuffer;
121 else /* DRAW_BACKBUFFER */
127 BX2 = SCR_FIELDX - 1;
128 BY2 = SCR_FIELDY - 1;
132 drawto_field = backbuffer;
136 void RedrawPlayfield(boolean force_redraw, int x, int y, int width, int height)
138 if (game_status == GAME_MODE_PLAYING &&
139 level.game_engine_type == GAME_ENGINE_TYPE_EM)
141 /* currently there is no partial redraw -- always redraw whole playfield */
142 RedrawPlayfield_EM(TRUE);
144 /* blit playfield from scroll buffer to normal back buffer for fading in */
145 BlitScreenToBitmap_EM(backbuffer);
147 else if (game_status == GAME_MODE_PLAYING &&
148 level.game_engine_type == GAME_ENGINE_TYPE_SP)
150 /* currently there is no partial redraw -- always redraw whole playfield */
151 RedrawPlayfield_SP(TRUE);
153 /* blit playfield from scroll buffer to normal back buffer for fading in */
154 BlitScreenToBitmap_SP(backbuffer);
156 else if (game_status == GAME_MODE_PLAYING &&
157 !game.envelope_active)
163 width = gfx.sxsize + 2 * TILEX;
164 height = gfx.sysize + 2 * TILEY;
170 int x1 = (x - SX) / TILEX, y1 = (y - SY) / TILEY;
171 int x2 = (x - SX + width) / TILEX, y2 = (y - SY + height) / TILEY;
173 for (xx = BX1; xx <= BX2; xx++)
174 for (yy = BY1; yy <= BY2; yy++)
175 if (xx >= x1 && xx <= x2 && yy >= y1 && yy <= y2)
176 DrawScreenField(xx, yy);
180 if (setup.soft_scrolling)
182 int fx = FX, fy = FY;
184 fx += (ScreenMovDir & (MV_LEFT|MV_RIGHT) ? ScreenGfxPos : 0);
185 fy += (ScreenMovDir & (MV_UP|MV_DOWN) ? ScreenGfxPos : 0);
187 BlitBitmap(fieldbuffer, backbuffer, fx,fy, SXSIZE,SYSIZE, SX,SY);
199 BlitBitmap(drawto, window, x, y, width, height, x, y);
202 void DrawMaskedBorder_Rect(int x, int y, int width, int height)
204 Bitmap *bitmap = graphic_info[IMG_GLOBAL_BORDER].bitmap;
206 SetClipOrigin(bitmap, bitmap->stored_clip_gc, 0, 0);
207 BlitBitmapMasked(bitmap, backbuffer, x, y, width, height, x, y);
210 void DrawMaskedBorder_FIELD()
212 if (global.border_status >= GAME_MODE_TITLE &&
213 global.border_status <= GAME_MODE_PLAYING &&
214 border.draw_masked[global.border_status])
215 DrawMaskedBorder_Rect(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
218 void DrawMaskedBorder_DOOR_1()
220 if (border.draw_masked[GFX_SPECIAL_ARG_DOOR] &&
221 (global.border_status != GAME_MODE_EDITOR ||
222 border.draw_masked[GFX_SPECIAL_ARG_EDITOR]))
223 DrawMaskedBorder_Rect(DX, DY, DXSIZE, DYSIZE);
226 void DrawMaskedBorder_DOOR_2()
228 if (border.draw_masked[GFX_SPECIAL_ARG_DOOR] &&
229 global.border_status != GAME_MODE_EDITOR)
230 DrawMaskedBorder_Rect(VX, VY, VXSIZE, VYSIZE);
233 void DrawMaskedBorder_DOOR_3()
235 /* currently not available */
238 void DrawMaskedBorder_ALL()
240 DrawMaskedBorder_FIELD();
241 DrawMaskedBorder_DOOR_1();
242 DrawMaskedBorder_DOOR_2();
243 DrawMaskedBorder_DOOR_3();
246 void DrawMaskedBorder(int redraw_mask)
248 /* never draw masked screen borders on borderless screens */
249 if (effectiveGameStatus() == GAME_MODE_LOADING ||
250 effectiveGameStatus() == GAME_MODE_TITLE)
253 if (redraw_mask & REDRAW_ALL)
254 DrawMaskedBorder_ALL();
257 if (redraw_mask & REDRAW_FIELD)
258 DrawMaskedBorder_FIELD();
259 if (redraw_mask & REDRAW_DOOR_1)
260 DrawMaskedBorder_DOOR_1();
261 if (redraw_mask & REDRAW_DOOR_2)
262 DrawMaskedBorder_DOOR_2();
263 if (redraw_mask & REDRAW_DOOR_3)
264 DrawMaskedBorder_DOOR_3();
271 DrawBuffer *buffer = (drawto_field == window ? backbuffer : drawto_field);
274 printf("::: TILES TO REFRESH: %d\n", redraw_tiles);
275 for (x = 0; x < SCR_FIELDX; x++)
276 for (y = 0 ; y < SCR_FIELDY; y++)
277 if (redraw[redraw_x1 + x][redraw_y1 + y])
278 printf("::: - %d, %d [%s]\n",
279 LEVELX(x), LEVELY(y),
280 EL_NAME(Feld[LEVELX(x)][LEVELY(y)]));
283 if (redraw_mask & REDRAW_TILES && redraw_tiles > REDRAWTILES_THRESHOLD)
284 redraw_mask |= REDRAW_FIELD;
286 if (redraw_mask & REDRAW_FIELD)
287 redraw_mask &= ~REDRAW_TILES;
289 if (redraw_mask == REDRAW_NONE)
292 if (redraw_mask & REDRAW_TILES &&
293 game_status == GAME_MODE_PLAYING &&
294 border.draw_masked[GAME_MODE_PLAYING])
295 redraw_mask |= REDRAW_FIELD;
297 if (global.fps_slowdown && game_status == GAME_MODE_PLAYING)
299 static boolean last_frame_skipped = FALSE;
300 boolean skip_even_when_not_scrolling = TRUE;
301 boolean just_scrolling = (ScreenMovDir != 0);
302 boolean verbose = FALSE;
304 if (global.fps_slowdown_factor > 1 &&
305 (FrameCounter % global.fps_slowdown_factor) &&
306 (just_scrolling || skip_even_when_not_scrolling))
308 redraw_mask &= ~REDRAW_MAIN;
310 last_frame_skipped = TRUE;
313 printf("FRAME SKIPPED\n");
317 if (last_frame_skipped)
318 redraw_mask |= REDRAW_FIELD;
320 last_frame_skipped = FALSE;
323 printf("frame not skipped\n");
327 /* synchronize X11 graphics at this point; if we would synchronize the
328 display immediately after the buffer switching (after the XFlush),
329 this could mean that we have to wait for the graphics to complete,
330 although we could go on doing calculations for the next frame */
334 /* prevent drawing masked border to backbuffer when using playfield buffer */
335 if (game_status != GAME_MODE_PLAYING ||
336 redraw_mask & REDRAW_FROM_BACKBUFFER ||
337 buffer == backbuffer)
338 DrawMaskedBorder(redraw_mask);
340 DrawMaskedBorder(redraw_mask & REDRAW_DOORS);
342 if (redraw_mask & REDRAW_ALL)
344 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
346 redraw_mask = REDRAW_NONE;
349 if (redraw_mask & REDRAW_FIELD)
351 if (game_status != GAME_MODE_PLAYING ||
352 redraw_mask & REDRAW_FROM_BACKBUFFER)
354 BlitBitmap(backbuffer, window,
355 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE, REAL_SX, REAL_SY);
359 int fx = FX, fy = FY;
361 if (setup.soft_scrolling)
363 fx += (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
364 fy += (ScreenMovDir & (MV_UP | MV_DOWN) ? ScreenGfxPos : 0);
367 if (setup.soft_scrolling ||
368 ABS(ScreenMovPos) + ScrollStepSize == TILEX ||
369 ABS(ScreenMovPos) == ScrollStepSize ||
370 redraw_tiles > REDRAWTILES_THRESHOLD)
372 if (border.draw_masked[GAME_MODE_PLAYING])
374 if (buffer != backbuffer)
376 /* copy playfield buffer to backbuffer to add masked border */
377 BlitBitmap(buffer, backbuffer, fx, fy, SXSIZE, SYSIZE, SX, SY);
378 DrawMaskedBorder(REDRAW_FIELD);
381 BlitBitmap(backbuffer, window,
382 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
387 BlitBitmap(buffer, window, fx, fy, SXSIZE, SYSIZE, SX, SY);
392 printf("redrawing all (ScreenGfxPos == %d) because %s\n",
394 (setup.soft_scrolling ?
395 "setup.soft_scrolling" :
396 ABS(ScreenGfxPos) + ScrollStepSize == TILEX ?
397 "ABS(ScreenGfxPos) + ScrollStepSize == TILEX" :
398 ABS(ScreenGfxPos) == ScrollStepSize ?
399 "ABS(ScreenGfxPos) == ScrollStepSize" :
400 "redraw_tiles > REDRAWTILES_THRESHOLD"));
406 redraw_mask &= ~REDRAW_MAIN;
409 if (redraw_mask & REDRAW_DOORS)
411 if (redraw_mask & REDRAW_DOOR_1)
412 BlitBitmap(backbuffer, window, DX, DY, DXSIZE, DYSIZE, DX, DY);
414 if (redraw_mask & REDRAW_DOOR_2)
415 BlitBitmap(backbuffer, window, VX, VY, VXSIZE, VYSIZE, VX, VY);
417 if (redraw_mask & REDRAW_DOOR_3)
418 BlitBitmap(backbuffer, window, EX, EY, EXSIZE, EYSIZE, EX, EY);
420 redraw_mask &= ~REDRAW_DOORS;
423 if (redraw_mask & REDRAW_MICROLEVEL)
425 BlitBitmap(backbuffer, window, SX, SY + 10 * TILEY, SXSIZE, 7 * TILEY,
426 SX, SY + 10 * TILEY);
428 redraw_mask &= ~REDRAW_MICROLEVEL;
431 if (redraw_mask & REDRAW_TILES)
433 for (x = 0; x < SCR_FIELDX; x++)
434 for (y = 0 ; y < SCR_FIELDY; y++)
435 if (redraw[redraw_x1 + x][redraw_y1 + y])
436 BlitBitmap(buffer, window,
437 FX + x * TILEX, FY + y * TILEY, TILEX, TILEY,
438 SX + x * TILEX, SY + y * TILEY);
441 if (redraw_mask & REDRAW_FPS) /* display frames per second */
446 sprintf(info1, " (only every %d. frame)", global.fps_slowdown_factor);
447 if (!global.fps_slowdown)
450 sprintf(text, "%04.1f fps%s", global.frames_per_second, info1);
452 DrawTextExt(window, SX + SXSIZE + SX, 0, text, FONT_TEXT_2, BLIT_OPAQUE);
454 DrawTextExt(window, SX, SY, text, FONT_TEXT_2, BLIT_OPAQUE);
460 for (x = 0; x < MAX_BUF_XSIZE; x++)
461 for (y = 0; y < MAX_BUF_YSIZE; y++)
464 redraw_mask = REDRAW_NONE;
467 static void FadeCrossSaveBackbuffer()
469 BlitBitmap(backbuffer, bitmap_db_cross, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
472 static void FadeExt(int fade_mask, int fade_mode, int fade_type)
474 static int fade_type_skip = FADE_TYPE_NONE;
475 void (*draw_border_function)(void) = NULL;
476 Bitmap *bitmap = (fade_mode & FADE_TYPE_TRANSFORM ? bitmap_db_cross : NULL);
477 int x, y, width, height;
478 int fade_delay, post_delay;
480 if (fade_type == FADE_TYPE_FADE_OUT)
482 if (fade_type_skip != FADE_TYPE_NONE)
485 printf("::: skipping %d ... [%d] (X)\n", fade_mode, fade_type_skip);
488 /* skip all fade operations until specified fade operation */
489 if (fade_type & fade_type_skip)
490 fade_type_skip = FADE_TYPE_NONE;
495 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
497 FadeCrossSaveBackbuffer();
503 redraw_mask |= fade_mask;
505 if (fade_type == FADE_TYPE_SKIP)
508 printf("::: will skip %d ... [%d]\n", fade_mode, fade_type_skip);
511 fade_type_skip = fade_mode;
517 printf("::: !!! FADING %d ... [%d] [%d]\n", fade_mode, fade_type,
522 fade_delay = fading.fade_delay;
523 post_delay = (fade_mode == FADE_MODE_FADE_OUT ? fading.post_delay : 0);
526 if (fade_type_skip != FADE_TYPE_NONE)
529 printf("::: skipping %d ... [%d]\n", fade_mode, fade_type_skip);
532 /* skip all fade operations until specified fade operation */
533 if (fade_type & fade_type_skip)
534 fade_type_skip = FADE_TYPE_NONE;
544 if (global.autoplay_leveldir)
546 // fading.fade_mode = FADE_MODE_NONE;
553 if (fading.fade_mode == FADE_MODE_NONE)
561 /* !!! what about fade_mask == REDRAW_FIELD | REDRAW_ALL ??? !!! */
564 printf("::: NOW FADING %d ... [%d]\n", fade_mode, fade_type);
568 if (fade_mask == REDRAW_NONE)
569 fade_mask = REDRAW_FIELD;
572 // if (fade_mask & REDRAW_FIELD)
573 if (fade_mask == REDRAW_FIELD)
578 height = FULL_SYSIZE;
581 fade_delay = fading.fade_delay;
582 post_delay = (fade_mode == FADE_MODE_FADE_OUT ? fading.post_delay : 0);
585 if (border.draw_masked_when_fading)
586 draw_border_function = DrawMaskedBorder_FIELD; /* update when fading */
588 DrawMaskedBorder_FIELD(); /* draw once */
590 else /* REDRAW_ALL */
598 fade_delay = fading.fade_delay;
599 post_delay = (fade_mode == FADE_MODE_FADE_OUT ? fading.post_delay : 0);
604 if (!setup.fade_screens ||
606 fading.fade_mode == FADE_MODE_NONE)
608 if (!setup.fade_screens || fade_delay == 0)
611 if (fade_mode == FADE_MODE_FADE_OUT)
615 if (fade_mode == FADE_MODE_FADE_OUT &&
616 fading.fade_mode != FADE_MODE_NONE)
617 ClearRectangle(backbuffer, x, y, width, height);
621 BlitBitmap(backbuffer, window, x, y, width, height, x, y);
622 redraw_mask = REDRAW_NONE;
630 FadeRectangle(bitmap, x, y, width, height, fade_mode, fade_delay, post_delay,
631 draw_border_function);
633 redraw_mask &= ~fade_mask;
636 void FadeIn(int fade_mask)
638 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
639 FadeExt(fade_mask, fading.fade_mode, FADE_TYPE_FADE_IN);
641 FadeExt(fade_mask, FADE_MODE_FADE_IN, FADE_TYPE_FADE_IN);
644 void FadeOut(int fade_mask)
646 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
647 FadeExt(fade_mask, fading.fade_mode, FADE_TYPE_FADE_OUT);
649 FadeExt(fade_mask, FADE_MODE_FADE_OUT, FADE_TYPE_FADE_OUT);
651 global.border_status = game_status;
654 static void FadeSetLeaveNext(struct TitleFadingInfo fading_leave, boolean set)
656 static struct TitleFadingInfo fading_leave_stored;
659 fading_leave_stored = fading_leave;
661 fading = fading_leave_stored;
664 void FadeSetEnterMenu()
666 fading = menu.enter_menu;
669 printf("::: storing enter_menu\n");
672 FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
675 void FadeSetLeaveMenu()
677 fading = menu.leave_menu;
680 printf("::: storing leave_menu\n");
683 FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
686 void FadeSetEnterScreen()
688 fading = menu.enter_screen[game_status];
691 printf("::: storing leave_screen[%d]\n", game_status);
694 FadeSetLeaveNext(menu.leave_screen[game_status], TRUE); /* store */
697 void FadeSetNextScreen()
699 fading = menu.next_screen;
702 printf("::: storing next_screen\n");
705 // (do not overwrite fade mode set by FadeSetEnterScreen)
706 // FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
709 void FadeSetLeaveScreen()
712 printf("::: recalling last stored value\n");
715 FadeSetLeaveNext(menu.leave_screen[game_status], FALSE); /* recall */
718 void FadeSetFromType(int type)
720 if (type & TYPE_ENTER_SCREEN)
721 FadeSetEnterScreen();
722 else if (type & TYPE_ENTER)
724 else if (type & TYPE_LEAVE)
728 void FadeSetDisabled()
730 static struct TitleFadingInfo fading_none = { FADE_MODE_NONE, -1, -1, -1 };
732 fading = fading_none;
735 void FadeSkipNextFadeIn()
737 FadeExt(0, FADE_MODE_SKIP_FADE_IN, FADE_TYPE_SKIP);
740 void FadeSkipNextFadeOut()
742 FadeExt(0, FADE_MODE_SKIP_FADE_OUT, FADE_TYPE_SKIP);
745 void SetWindowBackgroundImageIfDefined(int graphic)
747 if (graphic_info[graphic].bitmap)
748 SetWindowBackgroundBitmap(graphic_info[graphic].bitmap);
751 void SetMainBackgroundImageIfDefined(int graphic)
753 if (graphic_info[graphic].bitmap)
754 SetMainBackgroundBitmap(graphic_info[graphic].bitmap);
757 void SetDoorBackgroundImageIfDefined(int graphic)
759 if (graphic_info[graphic].bitmap)
760 SetDoorBackgroundBitmap(graphic_info[graphic].bitmap);
763 void SetWindowBackgroundImage(int graphic)
765 SetWindowBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
766 graphic_info[graphic].bitmap ?
767 graphic_info[graphic].bitmap :
768 graphic_info[IMG_BACKGROUND].bitmap);
771 void SetMainBackgroundImage(int graphic)
773 SetMainBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
774 graphic_info[graphic].bitmap ?
775 graphic_info[graphic].bitmap :
776 graphic_info[IMG_BACKGROUND].bitmap);
779 void SetDoorBackgroundImage(int graphic)
781 SetDoorBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
782 graphic_info[graphic].bitmap ?
783 graphic_info[graphic].bitmap :
784 graphic_info[IMG_BACKGROUND].bitmap);
787 void SetPanelBackground()
789 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, bitmap_db_panel,
790 DOOR_GFX_PAGEX5, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE, 0, 0);
792 SetDoorBackgroundBitmap(bitmap_db_panel);
795 void DrawBackground(int x, int y, int width, int height)
797 /* !!! "drawto" might still point to playfield buffer here (see below) !!! */
798 /* (when entering hall of fame after playing) */
800 ClearRectangleOnBackground(drawto, x, y, width, height);
802 ClearRectangleOnBackground(backbuffer, x, y, width, height);
805 redraw_mask |= REDRAW_FIELD;
808 void DrawBackgroundForFont(int x, int y, int width, int height, int font_nr)
810 struct FontBitmapInfo *font = getFontBitmapInfo(font_nr);
812 if (font->bitmap == NULL)
815 DrawBackground(x, y, width, height);
818 void DrawBackgroundForGraphic(int x, int y, int width, int height, int graphic)
820 struct GraphicInfo *g = &graphic_info[graphic];
822 if (g->bitmap == NULL)
825 DrawBackground(x, y, width, height);
830 /* !!! "drawto" might still point to playfield buffer here (see above) !!! */
831 /* (when entering hall of fame after playing) */
832 DrawBackground(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
834 /* !!! maybe this should be done before clearing the background !!! */
835 if (setup.soft_scrolling && game_status == GAME_MODE_PLAYING)
837 ClearRectangle(fieldbuffer, 0, 0, FXSIZE, FYSIZE);
838 SetDrawtoField(DRAW_BUFFERED);
841 SetDrawtoField(DRAW_BACKBUFFER);
844 void MarkTileDirty(int x, int y)
846 int xx = redraw_x1 + x;
847 int yy = redraw_y1 + y;
852 redraw[xx][yy] = TRUE;
853 redraw_mask |= REDRAW_TILES;
856 void SetBorderElement()
860 BorderElement = EL_EMPTY;
862 for (y = 0; y < lev_fieldy && BorderElement == EL_EMPTY; y++)
864 for (x = 0; x < lev_fieldx; x++)
866 if (!IS_INDESTRUCTIBLE(Feld[x][y]))
867 BorderElement = EL_STEELWALL;
869 if (y != 0 && y != lev_fieldy - 1 && x != lev_fieldx - 1)
875 void FloodFillLevel(int from_x, int from_y, int fill_element,
876 short field[MAX_LEV_FIELDX][MAX_LEV_FIELDY],
877 int max_fieldx, int max_fieldy)
881 static int check[4][2] = { { -1, 0 }, { 0, -1 }, { 1, 0 }, { 0, 1 } };
882 static int safety = 0;
884 /* check if starting field still has the desired content */
885 if (field[from_x][from_y] == fill_element)
890 if (safety > max_fieldx * max_fieldy)
891 Error(ERR_EXIT, "Something went wrong in 'FloodFill()'. Please debug.");
893 old_element = field[from_x][from_y];
894 field[from_x][from_y] = fill_element;
896 for (i = 0; i < 4; i++)
898 x = from_x + check[i][0];
899 y = from_y + check[i][1];
901 if (IN_FIELD(x, y, max_fieldx, max_fieldy) && field[x][y] == old_element)
902 FloodFillLevel(x, y, fill_element, field, max_fieldx, max_fieldy);
908 void SetRandomAnimationValue(int x, int y)
910 gfx.anim_random_frame = GfxRandom[x][y];
913 inline int getGraphicAnimationFrame(int graphic, int sync_frame)
915 /* animation synchronized with global frame counter, not move position */
916 if (graphic_info[graphic].anim_global_sync || sync_frame < 0)
917 sync_frame = FrameCounter;
919 return getAnimationFrame(graphic_info[graphic].anim_frames,
920 graphic_info[graphic].anim_delay,
921 graphic_info[graphic].anim_mode,
922 graphic_info[graphic].anim_start_frame,
926 void getSizedGraphicSource(int graphic, int frame, int tilesize_raw,
927 Bitmap **bitmap, int *x, int *y)
931 int width_mult, width_div;
932 int height_mult, height_div;
936 { 15, 16, 2, 3 }, /* 1 x 1 */
937 { 7, 8, 2, 3 }, /* 2 x 2 */
938 { 3, 4, 2, 3 }, /* 4 x 4 */
939 { 1, 2, 2, 3 }, /* 8 x 8 */
940 { 0, 1, 2, 3 }, /* 16 x 16 */
941 { 0, 1, 0, 1 }, /* 32 x 32 */
943 struct GraphicInfo *g = &graphic_info[graphic];
944 Bitmap *src_bitmap = g->bitmap;
945 int tilesize = MIN(MAX(1, tilesize_raw), TILESIZE);
946 int offset_calc_pos = log_2(tilesize);
947 int width_mult = offset_calc[offset_calc_pos].width_mult;
948 int width_div = offset_calc[offset_calc_pos].width_div;
949 int height_mult = offset_calc[offset_calc_pos].height_mult;
950 int height_div = offset_calc[offset_calc_pos].height_div;
951 int startx = src_bitmap->width * width_mult / width_div;
952 int starty = src_bitmap->height * height_mult / height_div;
953 int src_x = g->src_x * tilesize / TILESIZE;
954 int src_y = g->src_y * tilesize / TILESIZE;
955 int width = g->width * tilesize / TILESIZE;
956 int height = g->height * tilesize / TILESIZE;
957 int offset_x = g->offset_x * tilesize / TILESIZE;
958 int offset_y = g->offset_y * tilesize / TILESIZE;
960 if (g->offset_y == 0) /* frames are ordered horizontally */
962 int max_width = g->anim_frames_per_line * width;
963 int pos = (src_y / height) * max_width + src_x + frame * offset_x;
965 src_x = pos % max_width;
966 src_y = src_y % height + pos / max_width * height;
968 else if (g->offset_x == 0) /* frames are ordered vertically */
970 int max_height = g->anim_frames_per_line * height;
971 int pos = (src_x / width) * max_height + src_y + frame * offset_y;
973 src_x = src_x % width + pos / max_height * width;
974 src_y = pos % max_height;
976 else /* frames are ordered diagonally */
978 src_x = src_x + frame * offset_x;
979 src_y = src_y + frame * offset_y;
982 *bitmap = src_bitmap;
987 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
990 getSizedGraphicSource(graphic, 0, MINI_TILESIZE, bitmap, x, y);
992 struct GraphicInfo *g = &graphic_info[graphic];
994 int mini_starty = g->bitmap->height * 2 / 3;
997 *x = mini_startx + g->src_x / 2;
998 *y = mini_starty + g->src_y / 2;
1002 inline void getGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
1003 int *x, int *y, boolean get_backside)
1005 struct GraphicInfo *g = &graphic_info[graphic];
1006 int src_x = g->src_x + (get_backside ? g->offset2_x : 0);
1007 int src_y = g->src_y + (get_backside ? g->offset2_y : 0);
1009 *bitmap = g->bitmap;
1011 if (g->offset_y == 0) /* frames are ordered horizontally */
1013 int max_width = g->anim_frames_per_line * g->width;
1014 int pos = (src_y / g->height) * max_width + src_x + frame * g->offset_x;
1016 *x = pos % max_width;
1017 *y = src_y % g->height + pos / max_width * g->height;
1019 else if (g->offset_x == 0) /* frames are ordered vertically */
1021 int max_height = g->anim_frames_per_line * g->height;
1022 int pos = (src_x / g->width) * max_height + src_y + frame * g->offset_y;
1024 *x = src_x % g->width + pos / max_height * g->width;
1025 *y = pos % max_height;
1027 else /* frames are ordered diagonally */
1029 *x = src_x + frame * g->offset_x;
1030 *y = src_y + frame * g->offset_y;
1034 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
1036 getGraphicSourceExt(graphic, frame, bitmap, x, y, FALSE);
1039 void DrawGraphic(int x, int y, int graphic, int frame)
1042 if (!IN_SCR_FIELD(x, y))
1044 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
1045 printf("DrawGraphic(): This should never happen!\n");
1050 DrawGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic, frame);
1051 MarkTileDirty(x, y);
1054 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
1060 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1061 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
1064 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
1067 if (!IN_SCR_FIELD(x, y))
1069 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
1070 printf("DrawGraphicThruMask(): This should never happen!\n");
1075 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y *TILEY, graphic,
1077 MarkTileDirty(x, y);
1080 void DrawGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y, int graphic,
1086 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1088 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1089 dst_x - src_x, dst_y - src_y);
1090 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dst_x, dst_y);
1093 void DrawSizedGraphic(int x, int y, int graphic, int frame, int tilesize)
1095 DrawSizedGraphicExt(drawto, SX + x * tilesize, SY + y * tilesize, graphic,
1097 MarkTileDirty(x / tilesize, y / tilesize);
1100 void DrawSizedGraphicExt(DrawBuffer *d, int x, int y, int graphic, int frame,
1106 getSizedGraphicSource(graphic, frame, tilesize, &src_bitmap, &src_x, &src_y);
1107 BlitBitmap(src_bitmap, d, src_x, src_y, tilesize, tilesize, x, y);
1110 void DrawMiniGraphic(int x, int y, int graphic)
1112 DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
1113 MarkTileDirty(x / 2, y / 2);
1116 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
1121 getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1122 BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
1125 inline static void DrawGraphicShiftedNormal(int x, int y, int dx, int dy,
1126 int graphic, int frame,
1127 int cut_mode, int mask_mode)
1132 int width = TILEX, height = TILEY;
1135 if (dx || dy) /* shifted graphic */
1137 if (x < BX1) /* object enters playfield from the left */
1144 else if (x > BX2) /* object enters playfield from the right */
1150 else if (x==BX1 && dx < 0) /* object leaves playfield to the left */
1156 else if (x==BX2 && dx > 0) /* object leaves playfield to the right */
1158 else if (dx) /* general horizontal movement */
1159 MarkTileDirty(x + SIGN(dx), y);
1161 if (y < BY1) /* object enters playfield from the top */
1163 if (cut_mode==CUT_BELOW) /* object completely above top border */
1171 else if (y > BY2) /* object enters playfield from the bottom */
1177 else if (y==BY1 && dy < 0) /* object leaves playfield to the top */
1183 else if (dy > 0 && cut_mode == CUT_ABOVE)
1185 if (y == BY2) /* object completely above bottom border */
1191 MarkTileDirty(x, y + 1);
1192 } /* object leaves playfield to the bottom */
1193 else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
1195 else if (dy) /* general vertical movement */
1196 MarkTileDirty(x, y + SIGN(dy));
1200 if (!IN_SCR_FIELD(x, y))
1202 printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
1203 printf("DrawGraphicShifted(): This should never happen!\n");
1208 if (width > 0 && height > 0)
1210 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1215 dst_x = FX + x * TILEX + dx;
1216 dst_y = FY + y * TILEY + dy;
1218 if (mask_mode == USE_MASKING)
1220 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1221 dst_x - src_x, dst_y - src_y);
1222 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1226 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1229 MarkTileDirty(x, y);
1233 inline static void DrawGraphicShiftedDouble(int x, int y, int dx, int dy,
1234 int graphic, int frame,
1235 int cut_mode, int mask_mode)
1240 int width = TILEX, height = TILEY;
1243 int x2 = x + SIGN(dx);
1244 int y2 = y + SIGN(dy);
1245 int anim_frames = graphic_info[graphic].anim_frames;
1246 int sync_frame = (dx ? ABS(dx) : ABS(dy)) * anim_frames / TILESIZE;
1247 boolean draw_start_tile = (cut_mode != CUT_ABOVE); /* only for falling! */
1248 boolean draw_end_tile = (cut_mode != CUT_BELOW); /* only for falling! */
1250 /* re-calculate animation frame for two-tile movement animation */
1251 frame = getGraphicAnimationFrame(graphic, sync_frame);
1253 /* check if movement start graphic inside screen area and should be drawn */
1254 if (draw_start_tile && IN_SCR_FIELD(x1, y1))
1256 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, TRUE);
1258 dst_x = FX + x1 * TILEX;
1259 dst_y = FY + y1 * TILEY;
1261 if (mask_mode == USE_MASKING)
1263 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1264 dst_x - src_x, dst_y - src_y);
1265 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1269 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1272 MarkTileDirty(x1, y1);
1275 /* check if movement end graphic inside screen area and should be drawn */
1276 if (draw_end_tile && IN_SCR_FIELD(x2, y2))
1278 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
1280 dst_x = FX + x2 * TILEX;
1281 dst_y = FY + y2 * TILEY;
1283 if (mask_mode == USE_MASKING)
1285 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1286 dst_x - src_x, dst_y - src_y);
1287 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1291 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1294 MarkTileDirty(x2, y2);
1298 static void DrawGraphicShifted(int x, int y, int dx, int dy,
1299 int graphic, int frame,
1300 int cut_mode, int mask_mode)
1304 DrawGraphic(x, y, graphic, frame);
1309 if (graphic_info[graphic].double_movement) /* EM style movement images */
1310 DrawGraphicShiftedDouble(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1312 DrawGraphicShiftedNormal(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1315 void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
1316 int frame, int cut_mode)
1318 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, USE_MASKING);
1321 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
1322 int cut_mode, int mask_mode)
1324 int lx = LEVELX(x), ly = LEVELY(y);
1328 if (IN_LEV_FIELD(lx, ly))
1330 SetRandomAnimationValue(lx, ly);
1332 graphic = el_act_dir2img(element, GfxAction[lx][ly], GfxDir[lx][ly]);
1333 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1335 /* do not use double (EM style) movement graphic when not moving */
1336 if (graphic_info[graphic].double_movement && !dx && !dy)
1338 graphic = el_act_dir2img(element, ACTION_DEFAULT, GfxDir[lx][ly]);
1339 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1342 else /* border element */
1344 graphic = el2img(element);
1345 frame = getGraphicAnimationFrame(graphic, -1);
1348 if (element == EL_EXPANDABLE_WALL)
1350 boolean left_stopped = FALSE, right_stopped = FALSE;
1352 if (!IN_LEV_FIELD(lx - 1, ly) || IS_WALL(Feld[lx - 1][ly]))
1353 left_stopped = TRUE;
1354 if (!IN_LEV_FIELD(lx + 1, ly) || IS_WALL(Feld[lx + 1][ly]))
1355 right_stopped = TRUE;
1357 if (left_stopped && right_stopped)
1359 else if (left_stopped)
1361 graphic = IMG_EXPANDABLE_WALL_GROWING_RIGHT;
1362 frame = graphic_info[graphic].anim_frames - 1;
1364 else if (right_stopped)
1366 graphic = IMG_EXPANDABLE_WALL_GROWING_LEFT;
1367 frame = graphic_info[graphic].anim_frames - 1;
1372 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
1373 else if (mask_mode == USE_MASKING)
1374 DrawGraphicThruMask(x, y, graphic, frame);
1376 DrawGraphic(x, y, graphic, frame);
1379 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
1380 int cut_mode, int mask_mode)
1382 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1383 DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
1384 cut_mode, mask_mode);
1387 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
1390 DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1393 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
1396 DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1399 void DrawLevelElementThruMask(int x, int y, int element)
1401 DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1404 void DrawLevelFieldThruMask(int x, int y)
1406 DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
1409 /* !!! implementation of quicksand is totally broken !!! */
1410 #define IS_CRUMBLED_TILE(x, y, e) \
1411 (GFX_CRUMBLED(e) && (!IN_LEV_FIELD(x, y) || \
1412 !IS_MOVING(x, y) || \
1413 (e) == EL_QUICKSAND_EMPTYING || \
1414 (e) == EL_QUICKSAND_FAST_EMPTYING))
1416 static void DrawLevelFieldCrumbledSandExt(int x, int y, int graphic, int frame)
1420 int sx = SCREENX(x), sy = SCREENY(y);
1422 int width, height, cx, cy, i;
1423 int crumbled_border_size = graphic_info[graphic].border_size;
1424 static int xy[4][2] =
1432 if (!IN_LEV_FIELD(x, y))
1435 element = TILE_GFX_ELEMENT(x, y);
1437 /* crumble field itself */
1439 if (IS_CRUMBLED_TILE(x, y, element))
1441 if (GFX_CRUMBLED(element) && !IS_MOVING(x, y))
1444 if (!IN_SCR_FIELD(sx, sy))
1447 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1449 for (i = 0; i < 4; i++)
1451 int xx = x + xy[i][0];
1452 int yy = y + xy[i][1];
1454 element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1457 /* check if neighbour field is of same type */
1459 if (IS_CRUMBLED_TILE(xx, yy, element))
1462 if (GFX_CRUMBLED(element) && !IS_MOVING(xx, yy))
1466 if (i == 1 || i == 2)
1468 width = crumbled_border_size;
1470 cx = (i == 2 ? TILEX - crumbled_border_size : 0);
1476 height = crumbled_border_size;
1478 cy = (i == 3 ? TILEY - crumbled_border_size : 0);
1481 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1482 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
1485 MarkTileDirty(sx, sy);
1487 else /* crumble neighbour fields */
1489 for (i = 0; i < 4; i++)
1491 int xx = x + xy[i][0];
1492 int yy = y + xy[i][1];
1493 int sxx = sx + xy[i][0];
1494 int syy = sy + xy[i][1];
1497 if (!IN_LEV_FIELD(xx, yy) ||
1498 !IN_SCR_FIELD(sxx, syy))
1501 if (!IN_LEV_FIELD(xx, yy) ||
1502 !IN_SCR_FIELD(sxx, syy) ||
1507 if (Feld[xx][yy] == EL_ELEMENT_SNAPPING)
1510 element = TILE_GFX_ELEMENT(xx, yy);
1513 if (!IS_CRUMBLED_TILE(xx, yy, element))
1516 if (!GFX_CRUMBLED(element))
1520 graphic = el_act2crm(element, ACTION_DEFAULT);
1521 crumbled_border_size = graphic_info[graphic].border_size;
1523 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1525 if (i == 1 || i == 2)
1527 width = crumbled_border_size;
1529 cx = (i == 1 ? TILEX - crumbled_border_size : 0);
1535 height = crumbled_border_size;
1537 cy = (i == 0 ? TILEY - crumbled_border_size : 0);
1540 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1541 width, height, FX + sxx * TILEX + cx, FY + syy * TILEY + cy);
1543 MarkTileDirty(sxx, syy);
1548 void DrawLevelFieldCrumbledSand(int x, int y)
1552 if (!IN_LEV_FIELD(x, y))
1556 /* !!! CHECK THIS !!! */
1559 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
1560 GFX_CRUMBLED(GfxElement[x][y]))
1563 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
1564 GfxElement[x][y] != EL_UNDEFINED &&
1565 GFX_CRUMBLED(GfxElement[x][y]))
1567 DrawLevelFieldCrumbledSandDigging(x, y, GfxDir[x][y], GfxFrame[x][y]);
1574 graphic = el_act2crm(TILE_GFX_ELEMENT(x, y), ACTION_DEFAULT);
1576 graphic = el_act2crm(Feld[x][y], ACTION_DEFAULT);
1579 DrawLevelFieldCrumbledSandExt(x, y, graphic, 0);
1582 void DrawLevelFieldCrumbledSandDigging(int x, int y, int direction,
1585 int graphic1 = el_act_dir2img(GfxElement[x][y], ACTION_DIGGING, direction);
1586 int graphic2 = el_act_dir2crm(GfxElement[x][y], ACTION_DIGGING, direction);
1587 int frame1 = getGraphicAnimationFrame(graphic1, step_frame);
1588 int frame2 = getGraphicAnimationFrame(graphic2, step_frame);
1589 int sx = SCREENX(x), sy = SCREENY(y);
1591 DrawGraphic(sx, sy, graphic1, frame1);
1592 DrawLevelFieldCrumbledSandExt(x, y, graphic2, frame2);
1595 void DrawLevelFieldCrumbledSandNeighbours(int x, int y)
1597 int sx = SCREENX(x), sy = SCREENY(y);
1598 static int xy[4][2] =
1607 for (i = 0; i < 4; i++)
1609 int xx = x + xy[i][0];
1610 int yy = y + xy[i][1];
1611 int sxx = sx + xy[i][0];
1612 int syy = sy + xy[i][1];
1614 if (!IN_LEV_FIELD(xx, yy) ||
1615 !IN_SCR_FIELD(sxx, syy) ||
1616 !GFX_CRUMBLED(Feld[xx][yy]) ||
1620 DrawLevelField(xx, yy);
1624 static int getBorderElement(int x, int y)
1628 { EL_STEELWALL_TOPLEFT, EL_INVISIBLE_STEELWALL_TOPLEFT },
1629 { EL_STEELWALL_TOPRIGHT, EL_INVISIBLE_STEELWALL_TOPRIGHT },
1630 { EL_STEELWALL_BOTTOMLEFT, EL_INVISIBLE_STEELWALL_BOTTOMLEFT },
1631 { EL_STEELWALL_BOTTOMRIGHT, EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
1632 { EL_STEELWALL_VERTICAL, EL_INVISIBLE_STEELWALL_VERTICAL },
1633 { EL_STEELWALL_HORIZONTAL, EL_INVISIBLE_STEELWALL_HORIZONTAL },
1634 { EL_STEELWALL, EL_INVISIBLE_STEELWALL }
1636 int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
1637 int steel_position = (x == -1 && y == -1 ? 0 :
1638 x == lev_fieldx && y == -1 ? 1 :
1639 x == -1 && y == lev_fieldy ? 2 :
1640 x == lev_fieldx && y == lev_fieldy ? 3 :
1641 x == -1 || x == lev_fieldx ? 4 :
1642 y == -1 || y == lev_fieldy ? 5 : 6);
1644 return border[steel_position][steel_type];
1647 void DrawScreenElement(int x, int y, int element)
1649 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
1650 DrawLevelFieldCrumbledSand(LEVELX(x), LEVELY(y));
1653 void DrawLevelElement(int x, int y, int element)
1655 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1656 DrawScreenElement(SCREENX(x), SCREENY(y), element);
1659 void DrawScreenField(int x, int y)
1661 int lx = LEVELX(x), ly = LEVELY(y);
1662 int element, content;
1664 if (!IN_LEV_FIELD(lx, ly))
1666 if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
1669 element = getBorderElement(lx, ly);
1671 DrawScreenElement(x, y, element);
1676 element = Feld[lx][ly];
1677 content = Store[lx][ly];
1679 if (IS_MOVING(lx, ly))
1681 int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
1682 boolean cut_mode = NO_CUTTING;
1684 if (element == EL_QUICKSAND_EMPTYING ||
1685 element == EL_QUICKSAND_FAST_EMPTYING ||
1686 element == EL_MAGIC_WALL_EMPTYING ||
1687 element == EL_BD_MAGIC_WALL_EMPTYING ||
1688 element == EL_DC_MAGIC_WALL_EMPTYING ||
1689 element == EL_AMOEBA_DROPPING)
1690 cut_mode = CUT_ABOVE;
1691 else if (element == EL_QUICKSAND_FILLING ||
1692 element == EL_QUICKSAND_FAST_FILLING ||
1693 element == EL_MAGIC_WALL_FILLING ||
1694 element == EL_BD_MAGIC_WALL_FILLING ||
1695 element == EL_DC_MAGIC_WALL_FILLING)
1696 cut_mode = CUT_BELOW;
1699 if (lx == 9 && ly == 1)
1700 printf("::: %s [%d] [%d, %d] [%d]\n",
1701 EL_NAME(TILE_GFX_ELEMENT(lx, ly)),
1702 el_act2crm(TILE_GFX_ELEMENT(lx, ly), ACTION_DEFAULT),
1703 element_info[EL_QUICKSAND_EMPTYING].graphic[ACTION_DEFAULT],
1704 element_info[EL_QUICKSAND_EMPTYING].crumbled[ACTION_DEFAULT],
1705 GFX_CRUMBLED(TILE_GFX_ELEMENT(lx, ly)));
1708 if (cut_mode == CUT_ABOVE)
1710 DrawScreenElement(x, y, element);
1712 DrawScreenElementShifted(x, y, 0, 0, element, NO_CUTTING);
1715 DrawScreenElement(x, y, EL_EMPTY);
1718 DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
1719 else if (cut_mode == NO_CUTTING)
1720 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
1723 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
1726 if (cut_mode == CUT_BELOW &&
1727 IN_LEV_FIELD(lx, ly + 1) && IN_SCR_FIELD(x, y + 1))
1728 DrawLevelElement(lx, ly + 1, element);
1732 if (content == EL_ACID)
1734 int dir = MovDir[lx][ly];
1735 int newlx = lx + (dir == MV_LEFT ? -1 : dir == MV_RIGHT ? +1 : 0);
1736 int newly = ly + (dir == MV_UP ? -1 : dir == MV_DOWN ? +1 : 0);
1738 DrawLevelElementThruMask(newlx, newly, EL_ACID);
1741 else if (IS_BLOCKED(lx, ly))
1746 boolean cut_mode = NO_CUTTING;
1747 int element_old, content_old;
1749 Blocked2Moving(lx, ly, &oldx, &oldy);
1752 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
1753 MovDir[oldx][oldy] == MV_RIGHT);
1755 element_old = Feld[oldx][oldy];
1756 content_old = Store[oldx][oldy];
1758 if (element_old == EL_QUICKSAND_EMPTYING ||
1759 element_old == EL_QUICKSAND_FAST_EMPTYING ||
1760 element_old == EL_MAGIC_WALL_EMPTYING ||
1761 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
1762 element_old == EL_DC_MAGIC_WALL_EMPTYING ||
1763 element_old == EL_AMOEBA_DROPPING)
1764 cut_mode = CUT_ABOVE;
1766 DrawScreenElement(x, y, EL_EMPTY);
1769 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
1771 else if (cut_mode == NO_CUTTING)
1772 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
1775 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
1778 else if (IS_DRAWABLE(element))
1779 DrawScreenElement(x, y, element);
1781 DrawScreenElement(x, y, EL_EMPTY);
1784 void DrawLevelField(int x, int y)
1786 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1787 DrawScreenField(SCREENX(x), SCREENY(y));
1788 else if (IS_MOVING(x, y))
1792 Moving2Blocked(x, y, &newx, &newy);
1793 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
1794 DrawScreenField(SCREENX(newx), SCREENY(newy));
1796 else if (IS_BLOCKED(x, y))
1800 Blocked2Moving(x, y, &oldx, &oldy);
1801 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
1802 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
1806 void DrawMiniElement(int x, int y, int element)
1810 graphic = el2edimg(element);
1811 DrawMiniGraphic(x, y, graphic);
1814 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
1816 int x = sx + scroll_x, y = sy + scroll_y;
1818 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
1819 DrawMiniElement(sx, sy, EL_EMPTY);
1820 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
1821 DrawMiniElement(sx, sy, Feld[x][y]);
1823 DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
1826 void DrawEnvelopeBackground(int envelope_nr, int startx, int starty,
1827 int x, int y, int xsize, int ysize, int font_nr)
1829 int font_width = getFontWidth(font_nr);
1830 int font_height = getFontHeight(font_nr);
1831 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1834 int dst_x = SX + startx + x * font_width;
1835 int dst_y = SY + starty + y * font_height;
1836 int width = graphic_info[graphic].width;
1837 int height = graphic_info[graphic].height;
1838 int inner_width = MAX(width - 2 * font_width, font_width);
1839 int inner_height = MAX(height - 2 * font_height, font_height);
1840 int inner_sx = (width >= 3 * font_width ? font_width : 0);
1841 int inner_sy = (height >= 3 * font_height ? font_height : 0);
1842 boolean draw_masked = graphic_info[graphic].draw_masked;
1844 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1846 if (src_bitmap == NULL || width < font_width || height < font_height)
1848 ClearRectangle(drawto, dst_x, dst_y, font_width, font_height);
1852 src_x += (x == 0 ? 0 : x == xsize - 1 ? width - font_width :
1853 inner_sx + (x - 1) * font_width % inner_width);
1854 src_y += (y == 0 ? 0 : y == ysize - 1 ? height - font_height :
1855 inner_sy + (y - 1) * font_height % inner_height);
1859 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1860 dst_x - src_x, dst_y - src_y);
1861 BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1865 BlitBitmap(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1869 void AnimateEnvelope(int envelope_nr, int anim_mode, int action)
1871 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1872 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1873 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
1874 boolean ffwd_delay = (tape.playing && tape.fast_forward);
1875 boolean no_delay = (tape.warp_forward);
1876 unsigned long anim_delay = 0;
1877 int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
1878 int anim_delay_value = (no_delay ? 0 : frame_delay_value);
1879 int font_nr = FONT_ENVELOPE_1 + envelope_nr;
1880 int font_width = getFontWidth(font_nr);
1881 int font_height = getFontHeight(font_nr);
1882 int max_xsize = level.envelope[envelope_nr].xsize;
1883 int max_ysize = level.envelope[envelope_nr].ysize;
1884 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
1885 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
1886 int xend = max_xsize;
1887 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
1888 int xstep = (xstart < xend ? 1 : 0);
1889 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
1892 for (x = xstart, y = ystart; x <= xend && y <= yend; x += xstep, y += ystep)
1894 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
1895 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
1896 int sx = (SXSIZE - xsize * font_width) / 2;
1897 int sy = (SYSIZE - ysize * font_height) / 2;
1900 SetDrawtoField(DRAW_BUFFERED);
1902 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
1904 SetDrawtoField(DRAW_BACKBUFFER);
1906 for (yy = 0; yy < ysize; yy++) for (xx = 0; xx < xsize; xx++)
1907 DrawEnvelopeBackground(envelope_nr, sx,sy, xx,yy, xsize, ysize, font_nr);
1910 DrawTextBuffer(SX + sx + font_width, SY + sy + font_height,
1911 level.envelope[envelope_nr].text, font_nr, max_xsize,
1912 xsize - 2, ysize - 2, mask_mode,
1913 level.envelope[envelope_nr].autowrap,
1914 level.envelope[envelope_nr].centered, FALSE);
1916 DrawTextToTextArea(SX + sx + font_width, SY + sy + font_height,
1917 level.envelope[envelope_nr].text, font_nr, max_xsize,
1918 xsize - 2, ysize - 2, mask_mode);
1921 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
1924 WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
1928 void ShowEnvelope(int envelope_nr)
1930 int element = EL_ENVELOPE_1 + envelope_nr;
1931 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1932 int sound_opening = element_info[element].sound[ACTION_OPENING];
1933 int sound_closing = element_info[element].sound[ACTION_CLOSING];
1934 boolean ffwd_delay = (tape.playing && tape.fast_forward);
1935 boolean no_delay = (tape.warp_forward);
1936 int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
1937 int wait_delay_value = (no_delay ? 0 : normal_delay_value);
1938 int anim_mode = graphic_info[graphic].anim_mode;
1939 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
1940 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
1942 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
1944 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
1946 if (anim_mode == ANIM_DEFAULT)
1947 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_OPENING);
1949 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_OPENING);
1952 Delay(wait_delay_value);
1954 WaitForEventToContinue();
1956 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
1958 if (anim_mode != ANIM_NONE)
1959 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_CLOSING);
1961 if (anim_mode == ANIM_DEFAULT)
1962 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_CLOSING);
1964 game.envelope_active = FALSE;
1966 SetDrawtoField(DRAW_BUFFERED);
1968 redraw_mask |= REDRAW_FIELD;
1972 void DrawPreviewElement(int dst_x, int dst_y, int element, int tilesize)
1976 int graphic = el2preimg(element);
1978 getSizedGraphicSource(graphic, 0, tilesize, &src_bitmap, &src_x, &src_y);
1979 BlitBitmap(src_bitmap, drawto, src_x, src_y, tilesize, tilesize, dst_x,dst_y);
1987 SetMainBackgroundImage(IMG_BACKGROUND_PLAYING);
1988 SetDrawBackgroundMask(REDRAW_FIELD);
1990 SetDrawBackgroundMask(REDRAW_NONE);
1995 for (x = BX1; x <= BX2; x++)
1996 for (y = BY1; y <= BY2; y++)
1997 DrawScreenField(x, y);
1999 redraw_mask |= REDRAW_FIELD;
2002 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
2006 for (x = 0; x < size_x; x++)
2007 for (y = 0; y < size_y; y++)
2008 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
2010 redraw_mask |= REDRAW_FIELD;
2013 static void DrawPreviewLevelExt(int from_x, int from_y)
2015 boolean show_level_border = (BorderElement != EL_EMPTY);
2016 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
2017 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
2018 int tile_size = preview.tile_size;
2019 int preview_width = preview.xsize * tile_size;
2020 int preview_height = preview.ysize * tile_size;
2021 int real_preview_xsize = MIN(level_xsize, preview.xsize);
2022 int real_preview_ysize = MIN(level_ysize, preview.ysize);
2023 int dst_x = SX + ALIGNED_XPOS(preview.x, preview_width, preview.align);
2024 int dst_y = SY + ALIGNED_YPOS(preview.y, preview_height, preview.valign);
2027 DrawBackground(dst_x, dst_y, preview_width, preview_height);
2029 dst_x += (preview_width - real_preview_xsize * tile_size) / 2;
2030 dst_y += (preview_height - real_preview_ysize * tile_size) / 2;
2032 for (x = 0; x < real_preview_xsize; x++)
2034 for (y = 0; y < real_preview_ysize; y++)
2036 int lx = from_x + x + (show_level_border ? -1 : 0);
2037 int ly = from_y + y + (show_level_border ? -1 : 0);
2038 int element = (IN_LEV_FIELD(lx, ly) ? level.field[lx][ly] :
2039 getBorderElement(lx, ly));
2041 DrawPreviewElement(dst_x + x * tile_size, dst_y + y * tile_size,
2042 element, tile_size);
2046 redraw_mask |= REDRAW_MICROLEVEL;
2049 #define MICROLABEL_EMPTY 0
2050 #define MICROLABEL_LEVEL_NAME 1
2051 #define MICROLABEL_LEVEL_AUTHOR_HEAD 2
2052 #define MICROLABEL_LEVEL_AUTHOR 3
2053 #define MICROLABEL_IMPORTED_FROM_HEAD 4
2054 #define MICROLABEL_IMPORTED_FROM 5
2055 #define MICROLABEL_IMPORTED_BY_HEAD 6
2056 #define MICROLABEL_IMPORTED_BY 7
2058 static int getMaxTextLength(struct TextPosInfo *pos, int font_nr)
2060 int max_text_width = SXSIZE;
2061 int font_width = getFontWidth(font_nr);
2063 if (pos->align == ALIGN_CENTER)
2064 max_text_width = (pos->x < SXSIZE / 2 ? pos->x * 2 : (SXSIZE - pos->x) * 2);
2065 else if (pos->align == ALIGN_RIGHT)
2066 max_text_width = pos->x;
2068 max_text_width = SXSIZE - pos->x;
2070 return max_text_width / font_width;
2073 static void DrawPreviewLevelLabelExt(int mode)
2075 struct TextPosInfo *pos = &menu.main.text.level_info_2;
2076 char label_text[MAX_OUTPUT_LINESIZE + 1];
2077 int max_len_label_text;
2079 int font_nr = pos->font;
2082 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
2083 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
2084 mode == MICROLABEL_IMPORTED_BY_HEAD)
2085 font_nr = pos->font_alt;
2087 int font_nr = FONT_TEXT_2;
2090 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
2091 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
2092 mode == MICROLABEL_IMPORTED_BY_HEAD)
2093 font_nr = FONT_TEXT_3;
2097 max_len_label_text = getMaxTextLength(pos, font_nr);
2099 max_len_label_text = SXSIZE / getFontWidth(font_nr);
2103 if (pos->size != -1)
2104 max_len_label_text = pos->size;
2107 for (i = 0; i < max_len_label_text; i++)
2108 label_text[i] = ' ';
2109 label_text[max_len_label_text] = '\0';
2111 if (strlen(label_text) > 0)
2114 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2116 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
2117 int lypos = MICROLABEL2_YPOS;
2119 DrawText(lxpos, lypos, label_text, font_nr);
2124 (mode == MICROLABEL_LEVEL_NAME ? level.name :
2125 mode == MICROLABEL_LEVEL_AUTHOR_HEAD ? "created by" :
2126 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
2127 mode == MICROLABEL_IMPORTED_FROM_HEAD ? "imported from" :
2128 mode == MICROLABEL_IMPORTED_FROM ? leveldir_current->imported_from :
2129 mode == MICROLABEL_IMPORTED_BY_HEAD ? "imported by" :
2130 mode == MICROLABEL_IMPORTED_BY ? leveldir_current->imported_by :""),
2131 max_len_label_text);
2132 label_text[max_len_label_text] = '\0';
2134 if (strlen(label_text) > 0)
2137 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2139 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
2140 int lypos = MICROLABEL2_YPOS;
2142 DrawText(lxpos, lypos, label_text, font_nr);
2146 redraw_mask |= REDRAW_MICROLEVEL;
2149 void DrawPreviewLevel(boolean restart)
2151 static unsigned long scroll_delay = 0;
2152 static unsigned long label_delay = 0;
2153 static int from_x, from_y, scroll_direction;
2154 static int label_state, label_counter;
2155 unsigned long scroll_delay_value = preview.step_delay;
2156 boolean show_level_border = (BorderElement != EL_EMPTY);
2157 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
2158 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
2159 int last_game_status = game_status; /* save current game status */
2162 /* force PREVIEW font on preview level */
2163 game_status = GAME_MODE_PSEUDO_PREVIEW;
2171 if (preview.anim_mode == ANIM_CENTERED)
2173 if (level_xsize > preview.xsize)
2174 from_x = (level_xsize - preview.xsize) / 2;
2175 if (level_ysize > preview.ysize)
2176 from_y = (level_ysize - preview.ysize) / 2;
2179 from_x += preview.xoffset;
2180 from_y += preview.yoffset;
2182 scroll_direction = MV_RIGHT;
2186 DrawPreviewLevelExt(from_x, from_y);
2187 DrawPreviewLevelLabelExt(label_state);
2189 /* initialize delay counters */
2190 DelayReached(&scroll_delay, 0);
2191 DelayReached(&label_delay, 0);
2193 if (leveldir_current->name)
2195 struct TextPosInfo *pos = &menu.main.text.level_info_1;
2196 char label_text[MAX_OUTPUT_LINESIZE + 1];
2198 int font_nr = pos->font;
2200 int font_nr = FONT_TEXT_1;
2203 int max_len_label_text = getMaxTextLength(pos, font_nr);
2205 int max_len_label_text = SXSIZE / getFontWidth(font_nr);
2213 if (pos->size != -1)
2214 max_len_label_text = pos->size;
2217 strncpy(label_text, leveldir_current->name, max_len_label_text);
2218 label_text[max_len_label_text] = '\0';
2221 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2223 lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
2224 lypos = SY + MICROLABEL1_YPOS;
2226 DrawText(lxpos, lypos, label_text, font_nr);
2230 game_status = last_game_status; /* restore current game status */
2235 /* scroll preview level, if needed */
2236 if (preview.anim_mode != ANIM_NONE &&
2237 (level_xsize > preview.xsize || level_ysize > preview.ysize) &&
2238 DelayReached(&scroll_delay, scroll_delay_value))
2240 switch (scroll_direction)
2245 from_x -= preview.step_offset;
2246 from_x = (from_x < 0 ? 0 : from_x);
2249 scroll_direction = MV_UP;
2253 if (from_x < level_xsize - preview.xsize)
2255 from_x += preview.step_offset;
2256 from_x = (from_x > level_xsize - preview.xsize ?
2257 level_xsize - preview.xsize : from_x);
2260 scroll_direction = MV_DOWN;
2266 from_y -= preview.step_offset;
2267 from_y = (from_y < 0 ? 0 : from_y);
2270 scroll_direction = MV_RIGHT;
2274 if (from_y < level_ysize - preview.ysize)
2276 from_y += preview.step_offset;
2277 from_y = (from_y > level_ysize - preview.ysize ?
2278 level_ysize - preview.ysize : from_y);
2281 scroll_direction = MV_LEFT;
2288 DrawPreviewLevelExt(from_x, from_y);
2291 /* !!! THIS ALL SUCKS -- SHOULD BE CLEANLY REWRITTEN !!! */
2292 /* redraw micro level label, if needed */
2293 if (!strEqual(level.name, NAMELESS_LEVEL_NAME) &&
2294 !strEqual(level.author, ANONYMOUS_NAME) &&
2295 !strEqual(level.author, leveldir_current->name) &&
2296 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
2298 int max_label_counter = 23;
2300 if (leveldir_current->imported_from != NULL &&
2301 strlen(leveldir_current->imported_from) > 0)
2302 max_label_counter += 14;
2303 if (leveldir_current->imported_by != NULL &&
2304 strlen(leveldir_current->imported_by) > 0)
2305 max_label_counter += 14;
2307 label_counter = (label_counter + 1) % max_label_counter;
2308 label_state = (label_counter >= 0 && label_counter <= 7 ?
2309 MICROLABEL_LEVEL_NAME :
2310 label_counter >= 9 && label_counter <= 12 ?
2311 MICROLABEL_LEVEL_AUTHOR_HEAD :
2312 label_counter >= 14 && label_counter <= 21 ?
2313 MICROLABEL_LEVEL_AUTHOR :
2314 label_counter >= 23 && label_counter <= 26 ?
2315 MICROLABEL_IMPORTED_FROM_HEAD :
2316 label_counter >= 28 && label_counter <= 35 ?
2317 MICROLABEL_IMPORTED_FROM :
2318 label_counter >= 37 && label_counter <= 40 ?
2319 MICROLABEL_IMPORTED_BY_HEAD :
2320 label_counter >= 42 && label_counter <= 49 ?
2321 MICROLABEL_IMPORTED_BY : MICROLABEL_EMPTY);
2323 if (leveldir_current->imported_from == NULL &&
2324 (label_state == MICROLABEL_IMPORTED_FROM_HEAD ||
2325 label_state == MICROLABEL_IMPORTED_FROM))
2326 label_state = (label_state == MICROLABEL_IMPORTED_FROM_HEAD ?
2327 MICROLABEL_IMPORTED_BY_HEAD : MICROLABEL_IMPORTED_BY);
2329 DrawPreviewLevelLabelExt(label_state);
2332 game_status = last_game_status; /* restore current game status */
2335 inline void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
2336 int graphic, int sync_frame, int mask_mode)
2338 int frame = getGraphicAnimationFrame(graphic, sync_frame);
2340 if (mask_mode == USE_MASKING)
2341 DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
2343 DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
2346 inline void DrawGraphicAnimation(int x, int y, int graphic)
2348 int lx = LEVELX(x), ly = LEVELY(y);
2350 if (!IN_SCR_FIELD(x, y))
2353 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
2354 graphic, GfxFrame[lx][ly], NO_MASKING);
2355 MarkTileDirty(x, y);
2358 void DrawLevelGraphicAnimation(int x, int y, int graphic)
2360 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
2363 void DrawLevelElementAnimation(int x, int y, int element)
2365 int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
2367 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
2370 inline void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
2372 int sx = SCREENX(x), sy = SCREENY(y);
2374 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
2377 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
2380 DrawGraphicAnimation(sx, sy, graphic);
2383 if (GFX_CRUMBLED(TILE_GFX_ELEMENT(x, y)))
2384 DrawLevelFieldCrumbledSand(x, y);
2386 if (GFX_CRUMBLED(Feld[x][y]))
2387 DrawLevelFieldCrumbledSand(x, y);
2391 void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
2393 int sx = SCREENX(x), sy = SCREENY(y);
2396 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
2399 graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
2401 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
2404 DrawGraphicAnimation(sx, sy, graphic);
2406 if (GFX_CRUMBLED(element))
2407 DrawLevelFieldCrumbledSand(x, y);
2410 static int getPlayerGraphic(struct PlayerInfo *player, int move_dir)
2412 if (player->use_murphy)
2414 /* this works only because currently only one player can be "murphy" ... */
2415 static int last_horizontal_dir = MV_LEFT;
2416 int graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir);
2418 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
2419 last_horizontal_dir = move_dir;
2421 if (graphic == IMG_SP_MURPHY) /* undefined => use special graphic */
2423 int direction = (player->is_snapping ? move_dir : last_horizontal_dir);
2425 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
2431 return el_act_dir2img(player->artwork_element, player->GfxAction,move_dir);
2434 static boolean equalGraphics(int graphic1, int graphic2)
2436 struct GraphicInfo *g1 = &graphic_info[graphic1];
2437 struct GraphicInfo *g2 = &graphic_info[graphic2];
2439 return (g1->bitmap == g2->bitmap &&
2440 g1->src_x == g2->src_x &&
2441 g1->src_y == g2->src_y &&
2442 g1->anim_frames == g2->anim_frames &&
2443 g1->anim_delay == g2->anim_delay &&
2444 g1->anim_mode == g2->anim_mode);
2447 void DrawAllPlayers()
2451 for (i = 0; i < MAX_PLAYERS; i++)
2452 if (stored_player[i].active)
2453 DrawPlayer(&stored_player[i]);
2456 void DrawPlayerField(int x, int y)
2458 if (!IS_PLAYER(x, y))
2461 DrawPlayer(PLAYERINFO(x, y));
2464 void DrawPlayer(struct PlayerInfo *player)
2466 int jx = player->jx;
2467 int jy = player->jy;
2468 int move_dir = player->MovDir;
2469 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? +1 : 0);
2470 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? +1 : 0);
2471 int last_jx = (player->is_moving ? jx - dx : jx);
2472 int last_jy = (player->is_moving ? jy - dy : jy);
2473 int next_jx = jx + dx;
2474 int next_jy = jy + dy;
2475 boolean player_is_moving = (player->MovPos ? TRUE : FALSE);
2476 boolean player_is_opaque = FALSE;
2477 int sx = SCREENX(jx), sy = SCREENY(jy);
2478 int sxx = 0, syy = 0;
2479 int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
2481 int action = ACTION_DEFAULT;
2482 int last_player_graphic = getPlayerGraphic(player, move_dir);
2483 int last_player_frame = player->Frame;
2486 /* GfxElement[][] is set to the element the player is digging or collecting;
2487 remove also for off-screen player if the player is not moving anymore */
2488 if (IN_LEV_FIELD(jx, jy) && !player_is_moving)
2489 GfxElement[jx][jy] = EL_UNDEFINED;
2491 if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
2495 if (!IN_LEV_FIELD(jx, jy))
2497 printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
2498 printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
2499 printf("DrawPlayerField(): This should never happen!\n");
2504 if (element == EL_EXPLOSION)
2507 action = (player->is_pushing ? ACTION_PUSHING :
2508 player->is_digging ? ACTION_DIGGING :
2509 player->is_collecting ? ACTION_COLLECTING :
2510 player->is_moving ? ACTION_MOVING :
2511 player->is_snapping ? ACTION_SNAPPING :
2512 player->is_dropping ? ACTION_DROPPING :
2513 player->is_waiting ? player->action_waiting : ACTION_DEFAULT);
2515 if (player->is_waiting)
2516 move_dir = player->dir_waiting;
2518 InitPlayerGfxAnimation(player, action, move_dir);
2520 /* ----------------------------------------------------------------------- */
2521 /* draw things in the field the player is leaving, if needed */
2522 /* ----------------------------------------------------------------------- */
2524 if (player->is_moving)
2526 if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
2528 DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
2530 if (last_element == EL_DYNAMITE_ACTIVE ||
2531 last_element == EL_EM_DYNAMITE_ACTIVE ||
2532 last_element == EL_SP_DISK_RED_ACTIVE)
2533 DrawDynamite(last_jx, last_jy);
2535 DrawLevelFieldThruMask(last_jx, last_jy);
2537 else if (last_element == EL_DYNAMITE_ACTIVE ||
2538 last_element == EL_EM_DYNAMITE_ACTIVE ||
2539 last_element == EL_SP_DISK_RED_ACTIVE)
2540 DrawDynamite(last_jx, last_jy);
2542 /* !!! this is not enough to prevent flickering of players which are
2543 moving next to each others without a free tile between them -- this
2544 can only be solved by drawing all players layer by layer (first the
2545 background, then the foreground etc.) !!! => TODO */
2546 else if (!IS_PLAYER(last_jx, last_jy))
2547 DrawLevelField(last_jx, last_jy);
2550 DrawLevelField(last_jx, last_jy);
2553 if (player->is_pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
2554 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
2557 if (!IN_SCR_FIELD(sx, sy))
2560 /* ----------------------------------------------------------------------- */
2561 /* draw things behind the player, if needed */
2562 /* ----------------------------------------------------------------------- */
2565 DrawLevelElement(jx, jy, Back[jx][jy]);
2566 else if (IS_ACTIVE_BOMB(element))
2567 DrawLevelElement(jx, jy, EL_EMPTY);
2570 if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
2572 int old_element = GfxElement[jx][jy];
2573 int old_graphic = el_act_dir2img(old_element, action, move_dir);
2574 int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
2576 if (GFX_CRUMBLED(old_element))
2577 DrawLevelFieldCrumbledSandDigging(jx, jy, move_dir, player->StepFrame);
2579 DrawGraphic(sx, sy, old_graphic, frame);
2581 if (graphic_info[old_graphic].anim_mode & ANIM_OPAQUE_PLAYER)
2582 player_is_opaque = TRUE;
2586 GfxElement[jx][jy] = EL_UNDEFINED;
2588 /* make sure that pushed elements are drawn with correct frame rate */
2590 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
2592 if (player->is_pushing && player->is_moving && !IS_ANIM_MODE_CE(graphic))
2593 GfxFrame[jx][jy] = player->StepFrame;
2595 if (player->is_pushing && player->is_moving)
2596 GfxFrame[jx][jy] = player->StepFrame;
2599 DrawLevelField(jx, jy);
2603 /* ----------------------------------------------------------------------- */
2604 /* draw player himself */
2605 /* ----------------------------------------------------------------------- */
2607 graphic = getPlayerGraphic(player, move_dir);
2609 /* in the case of changed player action or direction, prevent the current
2610 animation frame from being restarted for identical animations */
2611 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
2612 player->Frame = last_player_frame;
2614 frame = getGraphicAnimationFrame(graphic, player->Frame);
2618 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
2619 sxx = player->GfxPos;
2621 syy = player->GfxPos;
2624 if (!setup.soft_scrolling && ScreenMovPos)
2627 if (player_is_opaque)
2628 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
2630 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
2632 if (SHIELD_ON(player))
2634 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
2635 IMG_SHIELD_NORMAL_ACTIVE);
2636 int frame = getGraphicAnimationFrame(graphic, -1);
2638 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
2641 /* ----------------------------------------------------------------------- */
2642 /* draw things the player is pushing, if needed */
2643 /* ----------------------------------------------------------------------- */
2646 printf("::: %d, %d [%d, %d] [%d]\n",
2647 player->is_pushing, player_is_moving, player->GfxAction,
2648 player->is_moving, player_is_moving);
2652 if (player->is_pushing && player->is_moving)
2654 int px = SCREENX(jx), py = SCREENY(jy);
2655 int pxx = (TILEX - ABS(sxx)) * dx;
2656 int pyy = (TILEY - ABS(syy)) * dy;
2657 int gfx_frame = GfxFrame[jx][jy];
2663 if (!IS_MOVING(jx, jy)) /* push movement already finished */
2665 element = Feld[next_jx][next_jy];
2666 gfx_frame = GfxFrame[next_jx][next_jy];
2669 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
2672 sync_frame = (IS_ANIM_MODE_CE(graphic) ? gfx_frame : player->StepFrame);
2673 frame = getGraphicAnimationFrame(graphic, sync_frame);
2675 frame = getGraphicAnimationFrame(graphic, player->StepFrame);
2678 /* draw background element under pushed element (like the Sokoban field) */
2679 if (Back[next_jx][next_jy])
2680 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
2682 /* masked drawing is needed for EMC style (double) movement graphics */
2683 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
2687 /* ----------------------------------------------------------------------- */
2688 /* draw things in front of player (active dynamite or dynabombs) */
2689 /* ----------------------------------------------------------------------- */
2691 if (IS_ACTIVE_BOMB(element))
2693 graphic = el2img(element);
2694 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
2696 if (game.emulation == EMU_SUPAPLEX)
2697 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
2699 DrawGraphicThruMask(sx, sy, graphic, frame);
2702 if (player_is_moving && last_element == EL_EXPLOSION)
2704 int element = (GfxElement[last_jx][last_jy] != EL_UNDEFINED ?
2705 GfxElement[last_jx][last_jy] : EL_EMPTY);
2706 int graphic = el_act2img(element, ACTION_EXPLODING);
2707 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
2708 int phase = ExplodePhase[last_jx][last_jy] - 1;
2709 int frame = getGraphicAnimationFrame(graphic, phase - delay);
2712 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
2715 /* ----------------------------------------------------------------------- */
2716 /* draw elements the player is just walking/passing through/under */
2717 /* ----------------------------------------------------------------------- */
2719 if (player_is_moving)
2721 /* handle the field the player is leaving ... */
2722 if (IS_ACCESSIBLE_INSIDE(last_element))
2723 DrawLevelField(last_jx, last_jy);
2724 else if (IS_ACCESSIBLE_UNDER(last_element))
2725 DrawLevelFieldThruMask(last_jx, last_jy);
2728 /* do not redraw accessible elements if the player is just pushing them */
2729 if (!player_is_moving || !player->is_pushing)
2731 /* ... and the field the player is entering */
2732 if (IS_ACCESSIBLE_INSIDE(element))
2733 DrawLevelField(jx, jy);
2734 else if (IS_ACCESSIBLE_UNDER(element))
2735 DrawLevelFieldThruMask(jx, jy);
2738 MarkTileDirty(sx, sy);
2741 /* ------------------------------------------------------------------------- */
2743 void WaitForEventToContinue()
2745 boolean still_wait = TRUE;
2747 /* simulate releasing mouse button over last gadget, if still pressed */
2749 HandleGadgets(-1, -1, 0);
2751 button_status = MB_RELEASED;
2767 case EVENT_BUTTONPRESS:
2768 case EVENT_KEYPRESS:
2772 case EVENT_KEYRELEASE:
2773 ClearPlayerAction();
2777 HandleOtherEvents(&event);
2781 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2788 /* don't eat all CPU time */
2793 #define MAX_REQUEST_LINES 13
2794 #define MAX_REQUEST_LINE_FONT1_LEN 7
2795 #define MAX_REQUEST_LINE_FONT2_LEN 10
2797 boolean Request(char *text, unsigned int req_state)
2799 int mx, my, ty, result = -1;
2800 unsigned int old_door_state;
2801 int last_game_status = game_status; /* save current game status */
2802 int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
2803 int font_nr = FONT_TEXT_2;
2804 int max_word_len = 0;
2807 for (text_ptr = text; *text_ptr; text_ptr++)
2809 max_word_len = (*text_ptr != ' ' ? max_word_len + 1 : 0);
2811 if (max_word_len > MAX_REQUEST_LINE_FONT1_LEN)
2813 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
2815 font_nr = FONT_TEXT_1;
2817 font_nr = FONT_LEVEL_NUMBER;
2824 if (game_status == GAME_MODE_PLAYING)
2826 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
2827 BlitScreenToBitmap_EM(backbuffer);
2828 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
2829 BlitScreenToBitmap_SP(backbuffer);
2832 /* disable deactivated drawing when quick-loading level tape recording */
2833 if (tape.playing && tape.deactivate_display)
2834 TapeDeactivateDisplayOff(TRUE);
2836 SetMouseCursor(CURSOR_DEFAULT);
2838 #if defined(NETWORK_AVALIABLE)
2839 /* pause network game while waiting for request to answer */
2840 if (options.network &&
2841 game_status == GAME_MODE_PLAYING &&
2842 req_state & REQUEST_WAIT_FOR_INPUT)
2843 SendToServer_PausePlaying();
2846 old_door_state = GetDoorState();
2848 /* simulate releasing mouse button over last gadget, if still pressed */
2850 HandleGadgets(-1, -1, 0);
2854 if (old_door_state & DOOR_OPEN_1)
2856 CloseDoor(DOOR_CLOSE_1);
2858 /* save old door content */
2859 BlitBitmap(bitmap_db_door, bitmap_db_door,
2860 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
2861 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
2865 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
2868 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2870 /* clear door drawing field */
2871 DrawBackground(DX, DY, DXSIZE, DYSIZE);
2873 /* force DOOR font inside door area */
2874 game_status = GAME_MODE_PSEUDO_DOOR;
2876 /* write text for request */
2877 for (ty = 0; ty < MAX_REQUEST_LINES; ty++)
2879 char text_line[max_request_line_len + 1];
2885 for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
2888 if (!tc || tc == ' ')
2899 strncpy(text_line, text, tl);
2902 DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
2903 DY + 8 + ty * (getFontHeight(font_nr) + 2),
2904 text_line, font_nr);
2906 text += tl + (tc == ' ' ? 1 : 0);
2909 game_status = last_game_status; /* restore current game status */
2911 if (req_state & REQ_ASK)
2913 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
2914 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
2916 else if (req_state & REQ_CONFIRM)
2918 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
2920 else if (req_state & REQ_PLAYER)
2922 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
2923 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
2924 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
2925 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
2928 /* copy request gadgets to door backbuffer */
2929 BlitBitmap(drawto, bitmap_db_door,
2930 DX, DY, DXSIZE, DYSIZE,
2931 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2933 OpenDoor(DOOR_OPEN_1);
2935 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
2937 if (game_status == GAME_MODE_PLAYING)
2939 SetPanelBackground();
2940 SetDrawBackgroundMask(REDRAW_DOOR_1);
2944 SetDrawBackgroundMask(REDRAW_FIELD);
2950 if (game_status != GAME_MODE_MAIN)
2953 button_status = MB_RELEASED;
2955 request_gadget_id = -1;
2957 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2969 case EVENT_BUTTONPRESS:
2970 case EVENT_BUTTONRELEASE:
2971 case EVENT_MOTIONNOTIFY:
2973 if (event.type == EVENT_MOTIONNOTIFY)
2975 if (!PointerInWindow(window))
2976 continue; /* window and pointer are on different screens */
2981 motion_status = TRUE;
2982 mx = ((MotionEvent *) &event)->x;
2983 my = ((MotionEvent *) &event)->y;
2987 motion_status = FALSE;
2988 mx = ((ButtonEvent *) &event)->x;
2989 my = ((ButtonEvent *) &event)->y;
2990 if (event.type == EVENT_BUTTONPRESS)
2991 button_status = ((ButtonEvent *) &event)->button;
2993 button_status = MB_RELEASED;
2996 /* this sets 'request_gadget_id' */
2997 HandleGadgets(mx, my, button_status);
2999 switch (request_gadget_id)
3001 case TOOL_CTRL_ID_YES:
3004 case TOOL_CTRL_ID_NO:
3007 case TOOL_CTRL_ID_CONFIRM:
3008 result = TRUE | FALSE;
3011 case TOOL_CTRL_ID_PLAYER_1:
3014 case TOOL_CTRL_ID_PLAYER_2:
3017 case TOOL_CTRL_ID_PLAYER_3:
3020 case TOOL_CTRL_ID_PLAYER_4:
3031 case EVENT_KEYPRESS:
3032 switch (GetEventKey((KeyEvent *)&event, TRUE))
3035 if (req_state & REQ_CONFIRM)
3051 if (req_state & REQ_PLAYER)
3055 case EVENT_KEYRELEASE:
3056 ClearPlayerAction();
3060 HandleOtherEvents(&event);
3064 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
3066 int joy = AnyJoystick();
3068 if (joy & JOY_BUTTON_1)
3070 else if (joy & JOY_BUTTON_2)
3076 if (game_status == GAME_MODE_PLAYING && local_player->LevelSolved_GameEnd)
3078 HandleGameActions();
3084 if (!PendingEvent()) /* delay only if no pending events */
3095 if (!PendingEvent()) /* delay only if no pending events */
3098 /* don't eat all CPU time */
3105 if (game_status != GAME_MODE_MAIN)
3110 if (!(req_state & REQ_STAY_OPEN))
3112 CloseDoor(DOOR_CLOSE_1);
3114 if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
3115 (req_state & REQ_REOPEN))
3116 OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
3121 if (game_status == GAME_MODE_PLAYING)
3123 SetPanelBackground();
3124 SetDrawBackgroundMask(REDRAW_DOOR_1);
3128 SetDrawBackgroundMask(REDRAW_FIELD);
3131 #if defined(NETWORK_AVALIABLE)
3132 /* continue network game after request */
3133 if (options.network &&
3134 game_status == GAME_MODE_PLAYING &&
3135 req_state & REQUEST_WAIT_FOR_INPUT)
3136 SendToServer_ContinuePlaying();
3139 /* restore deactivated drawing when quick-loading level tape recording */
3140 if (tape.playing && tape.deactivate_display)
3141 TapeDeactivateDisplayOn();
3146 unsigned int OpenDoor(unsigned int door_state)
3148 if (door_state & DOOR_COPY_BACK)
3150 if (door_state & DOOR_OPEN_1)
3151 BlitBitmap(bitmap_db_door, bitmap_db_door,
3152 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
3153 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
3155 if (door_state & DOOR_OPEN_2)
3156 BlitBitmap(bitmap_db_door, bitmap_db_door,
3157 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY2, VXSIZE, VYSIZE,
3158 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
3160 door_state &= ~DOOR_COPY_BACK;
3163 return MoveDoor(door_state);
3166 unsigned int CloseDoor(unsigned int door_state)
3168 unsigned int old_door_state = GetDoorState();
3170 if (!(door_state & DOOR_NO_COPY_BACK))
3172 if (old_door_state & DOOR_OPEN_1)
3173 BlitBitmap(backbuffer, bitmap_db_door,
3174 DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
3176 if (old_door_state & DOOR_OPEN_2)
3177 BlitBitmap(backbuffer, bitmap_db_door,
3178 VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
3180 door_state &= ~DOOR_NO_COPY_BACK;
3183 return MoveDoor(door_state);
3186 unsigned int GetDoorState()
3188 return MoveDoor(DOOR_GET_STATE);
3191 unsigned int SetDoorState(unsigned int door_state)
3193 return MoveDoor(door_state | DOOR_SET_STATE);
3196 unsigned int MoveDoor(unsigned int door_state)
3198 static int door1 = DOOR_OPEN_1;
3199 static int door2 = DOOR_CLOSE_2;
3200 unsigned long door_delay = 0;
3201 unsigned long door_delay_value;
3204 if (door_1.width < 0 || door_1.width > DXSIZE)
3205 door_1.width = DXSIZE;
3206 if (door_1.height < 0 || door_1.height > DYSIZE)
3207 door_1.height = DYSIZE;
3208 if (door_2.width < 0 || door_2.width > VXSIZE)
3209 door_2.width = VXSIZE;
3210 if (door_2.height < 0 || door_2.height > VYSIZE)
3211 door_2.height = VYSIZE;
3213 if (door_state == DOOR_GET_STATE)
3214 return (door1 | door2);
3216 if (door_state & DOOR_SET_STATE)
3218 if (door_state & DOOR_ACTION_1)
3219 door1 = door_state & DOOR_ACTION_1;
3220 if (door_state & DOOR_ACTION_2)
3221 door2 = door_state & DOOR_ACTION_2;
3223 return (door1 | door2);
3226 if (!(door_state & DOOR_FORCE_REDRAW))
3228 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
3229 door_state &= ~DOOR_OPEN_1;
3230 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
3231 door_state &= ~DOOR_CLOSE_1;
3232 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
3233 door_state &= ~DOOR_OPEN_2;
3234 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
3235 door_state &= ~DOOR_CLOSE_2;
3238 door_delay_value = (door_state & DOOR_ACTION_1 ? door_1.step_delay :
3241 if (setup.quick_doors)
3243 stepsize = 20; /* must be chosen to always draw last frame */
3244 door_delay_value = 0;
3247 if (global.autoplay_leveldir)
3249 door_state |= DOOR_NO_DELAY;
3250 door_state &= ~DOOR_CLOSE_ALL;
3254 if (game_status == GAME_MODE_EDITOR)
3255 door_state |= DOOR_NO_DELAY;
3258 if (door_state & DOOR_ACTION)
3260 boolean handle_door_1 = (door_state & DOOR_ACTION_1);
3261 boolean handle_door_2 = (door_state & DOOR_ACTION_2);
3262 boolean door_1_done = (!handle_door_1);
3263 boolean door_2_done = (!handle_door_2);
3264 boolean door_1_vertical = (door_1.anim_mode & ANIM_VERTICAL);
3265 boolean door_2_vertical = (door_2.anim_mode & ANIM_VERTICAL);
3266 int door_size_1 = (door_1_vertical ? door_1.height : door_1.width);
3267 int door_size_2 = (door_2_vertical ? door_2.height : door_2.width);
3268 int max_door_size_1 = (door_1_vertical ? DYSIZE : DXSIZE);
3269 int max_door_size_2 = (door_2_vertical ? VYSIZE : VXSIZE);
3270 int door_size = (handle_door_1 ? door_size_1 : door_size_2);
3271 int max_door_size = (handle_door_1 ? max_door_size_1 : max_door_size_2);
3272 int door_skip = max_door_size - door_size;
3273 int end = door_size;
3274 int start = ((door_state & DOOR_NO_DELAY) ? end : 0);
3277 if (!(door_state & DOOR_NO_DELAY) && !setup.quick_doors)
3279 /* opening door sound has priority over simultaneously closing door */
3280 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
3281 PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
3282 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
3283 PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
3286 for (k = start; k <= end && !(door_1_done && door_2_done); k += stepsize)
3289 Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
3290 GC gc = bitmap->stored_clip_gc;
3292 if (door_state & DOOR_ACTION_1)
3294 int a = MIN(x * door_1.step_offset, end);
3295 int p = (door_state & DOOR_OPEN_1 ? end - a : a);
3296 int i = p + door_skip;
3298 if (door_1.anim_mode & ANIM_STATIC_PANEL)
3300 BlitBitmap(bitmap_db_door, drawto,
3301 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1,
3302 DXSIZE, DYSIZE, DX, DY);
3306 BlitBitmap(bitmap_db_door, drawto,
3307 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + p / 2,
3308 DXSIZE, DYSIZE - p / 2, DX, DY);
3310 ClearRectangle(drawto, DX, DY + DYSIZE - p / 2, DXSIZE, p / 2);
3313 if (door_1.anim_mode & ANIM_HORIZONTAL && x <= DXSIZE)
3315 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
3316 int dst1_x = DX + DXSIZE - i, dst1_y = DY;
3317 int src2_x = DXSIZE - i, src2_y = DOOR_GFX_PAGEY1;
3318 int dst2_x = DX, dst2_y = DY;
3319 int width = i, height = DYSIZE;
3321 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3322 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3325 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3326 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3329 else if (door_1.anim_mode & ANIM_VERTICAL && x <= DYSIZE)
3331 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
3332 int dst1_x = DX, dst1_y = DY + DYSIZE - i;
3333 int src2_x = 0, src2_y = DOOR_GFX_PAGEY1 + DYSIZE - i;
3334 int dst2_x = DX, dst2_y = DY;
3335 int width = DXSIZE, height = i;
3337 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3338 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3341 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3342 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3345 else if (x <= DXSIZE) /* ANIM_DEFAULT */
3347 int j = (door_1.anim_mode == ANIM_DEFAULT ? (DXSIZE - i) / 3 : 0);
3349 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
3350 BlitBitmapMasked(bitmap, drawto,
3351 DXSIZE, DOOR_GFX_PAGEY1, i, 77,
3352 DX + DXSIZE - i, DY + j);
3353 BlitBitmapMasked(bitmap, drawto,
3354 DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
3355 DX + DXSIZE - i, DY + 140 + j);
3356 SetClipOrigin(bitmap, gc, DX - DXSIZE + i,
3357 DY - (DOOR_GFX_PAGEY1 + j));
3358 BlitBitmapMasked(bitmap, drawto,
3359 DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
3361 BlitBitmapMasked(bitmap, drawto,
3362 DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
3365 BlitBitmapMasked(bitmap, drawto,
3366 DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
3368 BlitBitmapMasked(bitmap, drawto,
3369 DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
3371 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
3372 BlitBitmapMasked(bitmap, drawto,
3373 DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
3374 DX + DXSIZE - i, DY + 77 + j);
3375 BlitBitmapMasked(bitmap, drawto,
3376 DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
3377 DX + DXSIZE - i, DY + 203 + j);
3380 redraw_mask |= REDRAW_DOOR_1;
3381 door_1_done = (a == end);
3384 if (door_state & DOOR_ACTION_2)
3386 int a = MIN(x * door_2.step_offset, door_size);
3387 int p = (door_state & DOOR_OPEN_2 ? door_size - a : a);
3388 int i = p + door_skip;
3390 if (door_2.anim_mode & ANIM_STATIC_PANEL)
3392 BlitBitmap(bitmap_db_door, drawto,
3393 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2,
3394 VXSIZE, VYSIZE, VX, VY);
3396 else if (x <= VYSIZE)
3398 BlitBitmap(bitmap_db_door, drawto,
3399 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + p / 2,
3400 VXSIZE, VYSIZE - p / 2, VX, VY);
3402 ClearRectangle(drawto, VX, VY + VYSIZE - p / 2, VXSIZE, p / 2);
3405 if (door_2.anim_mode & ANIM_HORIZONTAL && x <= VXSIZE)
3407 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
3408 int dst1_x = VX + VXSIZE - i, dst1_y = VY;
3409 int src2_x = VXSIZE - i, src2_y = DOOR_GFX_PAGEY2;
3410 int dst2_x = VX, dst2_y = VY;
3411 int width = i, height = VYSIZE;
3413 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3414 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3417 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3418 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3421 else if (door_2.anim_mode & ANIM_VERTICAL && x <= VYSIZE)
3423 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
3424 int dst1_x = VX, dst1_y = VY + VYSIZE - i;
3425 int src2_x = 0, src2_y = DOOR_GFX_PAGEY2 + VYSIZE - i;
3426 int dst2_x = VX, dst2_y = VY;
3427 int width = VXSIZE, height = i;
3429 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3430 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3433 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3434 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3437 else if (x <= VXSIZE) /* ANIM_DEFAULT */
3439 int j = (door_2.anim_mode == ANIM_DEFAULT ? (VXSIZE - i) / 3 : 0);
3441 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
3442 BlitBitmapMasked(bitmap, drawto,
3443 VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
3444 VX + VXSIZE - i, VY + j);
3445 SetClipOrigin(bitmap, gc,
3446 VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
3447 BlitBitmapMasked(bitmap, drawto,
3448 VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
3451 BlitBitmapMasked(bitmap, drawto,
3452 VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
3453 i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
3454 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
3455 BlitBitmapMasked(bitmap, drawto,
3456 VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
3458 VX + VXSIZE - i, VY + VYSIZE / 2 + j);
3461 redraw_mask |= REDRAW_DOOR_2;
3462 door_2_done = (a == VXSIZE);
3465 if (!(door_state & DOOR_NO_DELAY))
3469 if (game_status == GAME_MODE_MAIN)
3472 WaitUntilDelayReached(&door_delay, door_delay_value);
3477 if (door_state & DOOR_ACTION_1)
3478 door1 = door_state & DOOR_ACTION_1;
3479 if (door_state & DOOR_ACTION_2)
3480 door2 = door_state & DOOR_ACTION_2;
3482 return (door1 | door2);
3485 void DrawSpecialEditorDoor()
3487 /* draw bigger toolbox window */
3488 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
3489 DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
3491 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
3492 EX - 6, VY - 4, EXSIZE + 12, EYSIZE - VYSIZE + 4,
3495 redraw_mask |= REDRAW_ALL;
3498 void UndrawSpecialEditorDoor()
3500 /* draw normal tape recorder window */
3501 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
3502 EX - 6, EY - 12, EXSIZE + 12, EYSIZE - VYSIZE + 12,
3505 redraw_mask |= REDRAW_ALL;
3509 /* ---------- new tool button stuff ---------------------------------------- */
3511 /* graphic position values for tool buttons */
3512 #define TOOL_BUTTON_YES_XPOS 2
3513 #define TOOL_BUTTON_YES_YPOS 250
3514 #define TOOL_BUTTON_YES_GFX_YPOS 0
3515 #define TOOL_BUTTON_YES_XSIZE 46
3516 #define TOOL_BUTTON_YES_YSIZE 28
3517 #define TOOL_BUTTON_NO_XPOS 52
3518 #define TOOL_BUTTON_NO_YPOS TOOL_BUTTON_YES_YPOS
3519 #define TOOL_BUTTON_NO_GFX_YPOS TOOL_BUTTON_YES_GFX_YPOS
3520 #define TOOL_BUTTON_NO_XSIZE TOOL_BUTTON_YES_XSIZE
3521 #define TOOL_BUTTON_NO_YSIZE TOOL_BUTTON_YES_YSIZE
3522 #define TOOL_BUTTON_CONFIRM_XPOS TOOL_BUTTON_YES_XPOS
3523 #define TOOL_BUTTON_CONFIRM_YPOS TOOL_BUTTON_YES_YPOS
3524 #define TOOL_BUTTON_CONFIRM_GFX_YPOS 30
3525 #define TOOL_BUTTON_CONFIRM_XSIZE 96
3526 #define TOOL_BUTTON_CONFIRM_YSIZE TOOL_BUTTON_YES_YSIZE
3527 #define TOOL_BUTTON_PLAYER_XSIZE 30
3528 #define TOOL_BUTTON_PLAYER_YSIZE 30
3529 #define TOOL_BUTTON_PLAYER_GFX_XPOS 5
3530 #define TOOL_BUTTON_PLAYER_GFX_YPOS 185
3531 #define TOOL_BUTTON_PLAYER_XPOS (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
3532 #define TOOL_BUTTON_PLAYER_YPOS (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
3533 #define TOOL_BUTTON_PLAYER1_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3534 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
3535 #define TOOL_BUTTON_PLAYER2_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3536 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
3537 #define TOOL_BUTTON_PLAYER3_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3538 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
3539 #define TOOL_BUTTON_PLAYER4_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3540 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
3541 #define TOOL_BUTTON_PLAYER1_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3542 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
3543 #define TOOL_BUTTON_PLAYER2_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3544 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
3545 #define TOOL_BUTTON_PLAYER3_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3546 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
3547 #define TOOL_BUTTON_PLAYER4_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3548 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
3557 } toolbutton_info[NUM_TOOL_BUTTONS] =
3560 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_GFX_YPOS,
3561 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_YPOS,
3562 TOOL_BUTTON_YES_XSIZE, TOOL_BUTTON_YES_YSIZE,
3567 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_GFX_YPOS,
3568 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_YPOS,
3569 TOOL_BUTTON_NO_XSIZE, TOOL_BUTTON_NO_YSIZE,
3574 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_GFX_YPOS,
3575 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_YPOS,
3576 TOOL_BUTTON_CONFIRM_XSIZE, TOOL_BUTTON_CONFIRM_YSIZE,
3577 TOOL_CTRL_ID_CONFIRM,
3581 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3582 TOOL_BUTTON_PLAYER1_XPOS, TOOL_BUTTON_PLAYER1_YPOS,
3583 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3584 TOOL_CTRL_ID_PLAYER_1,
3588 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3589 TOOL_BUTTON_PLAYER2_XPOS, TOOL_BUTTON_PLAYER2_YPOS,
3590 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3591 TOOL_CTRL_ID_PLAYER_2,
3595 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3596 TOOL_BUTTON_PLAYER3_XPOS, TOOL_BUTTON_PLAYER3_YPOS,
3597 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3598 TOOL_CTRL_ID_PLAYER_3,
3602 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3603 TOOL_BUTTON_PLAYER4_XPOS, TOOL_BUTTON_PLAYER4_YPOS,
3604 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3605 TOOL_CTRL_ID_PLAYER_4,
3610 void CreateToolButtons()
3614 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3616 Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
3617 Bitmap *deco_bitmap = None;
3618 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
3619 struct GadgetInfo *gi;
3620 unsigned long event_mask;
3621 int gd_xoffset, gd_yoffset;
3622 int gd_x1, gd_x2, gd_y;
3625 event_mask = GD_EVENT_RELEASED;
3627 gd_xoffset = toolbutton_info[i].xpos;
3628 gd_yoffset = toolbutton_info[i].ypos;
3629 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
3630 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
3631 gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
3633 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
3635 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
3637 getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr),
3638 &deco_bitmap, &deco_x, &deco_y);
3639 deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
3640 deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
3643 gi = CreateGadget(GDI_CUSTOM_ID, id,
3644 GDI_INFO_TEXT, toolbutton_info[i].infotext,
3645 GDI_X, DX + toolbutton_info[i].x,
3646 GDI_Y, DY + toolbutton_info[i].y,
3647 GDI_WIDTH, toolbutton_info[i].width,
3648 GDI_HEIGHT, toolbutton_info[i].height,
3649 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
3650 GDI_STATE, GD_BUTTON_UNPRESSED,
3651 GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
3652 GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
3653 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
3654 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
3655 GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
3656 GDI_DECORATION_SHIFTING, 1, 1,
3657 GDI_DIRECT_DRAW, FALSE,
3658 GDI_EVENT_MASK, event_mask,
3659 GDI_CALLBACK_ACTION, HandleToolButtons,
3663 Error(ERR_EXIT, "cannot create gadget");
3665 tool_gadget[id] = gi;
3669 void FreeToolButtons()
3673 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3674 FreeGadget(tool_gadget[i]);
3677 static void UnmapToolButtons()
3681 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3682 UnmapGadget(tool_gadget[i]);
3685 static void HandleToolButtons(struct GadgetInfo *gi)
3687 request_gadget_id = gi->custom_id;
3690 static struct Mapping_EM_to_RND_object
3693 boolean is_rnd_to_em_mapping; /* unique mapping EM <-> RND */
3694 boolean is_backside; /* backside of moving element */
3700 em_object_mapping_list[] =
3703 Xblank, TRUE, FALSE,
3707 Yacid_splash_eB, FALSE, FALSE,
3708 EL_ACID_SPLASH_RIGHT, -1, -1
3711 Yacid_splash_wB, FALSE, FALSE,
3712 EL_ACID_SPLASH_LEFT, -1, -1
3715 #ifdef EM_ENGINE_BAD_ROLL
3717 Xstone_force_e, FALSE, FALSE,
3718 EL_ROCK, -1, MV_BIT_RIGHT
3721 Xstone_force_w, FALSE, FALSE,
3722 EL_ROCK, -1, MV_BIT_LEFT
3725 Xnut_force_e, FALSE, FALSE,
3726 EL_NUT, -1, MV_BIT_RIGHT
3729 Xnut_force_w, FALSE, FALSE,
3730 EL_NUT, -1, MV_BIT_LEFT
3733 Xspring_force_e, FALSE, FALSE,
3734 EL_SPRING, -1, MV_BIT_RIGHT
3737 Xspring_force_w, FALSE, FALSE,
3738 EL_SPRING, -1, MV_BIT_LEFT
3741 Xemerald_force_e, FALSE, FALSE,
3742 EL_EMERALD, -1, MV_BIT_RIGHT
3745 Xemerald_force_w, FALSE, FALSE,
3746 EL_EMERALD, -1, MV_BIT_LEFT
3749 Xdiamond_force_e, FALSE, FALSE,
3750 EL_DIAMOND, -1, MV_BIT_RIGHT
3753 Xdiamond_force_w, FALSE, FALSE,
3754 EL_DIAMOND, -1, MV_BIT_LEFT
3757 Xbomb_force_e, FALSE, FALSE,
3758 EL_BOMB, -1, MV_BIT_RIGHT
3761 Xbomb_force_w, FALSE, FALSE,
3762 EL_BOMB, -1, MV_BIT_LEFT
3764 #endif /* EM_ENGINE_BAD_ROLL */
3767 Xstone, TRUE, FALSE,
3771 Xstone_pause, FALSE, FALSE,
3775 Xstone_fall, FALSE, FALSE,
3779 Ystone_s, FALSE, FALSE,
3780 EL_ROCK, ACTION_FALLING, -1
3783 Ystone_sB, FALSE, TRUE,
3784 EL_ROCK, ACTION_FALLING, -1
3787 Ystone_e, FALSE, FALSE,
3788 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
3791 Ystone_eB, FALSE, TRUE,
3792 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
3795 Ystone_w, FALSE, FALSE,
3796 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
3799 Ystone_wB, FALSE, TRUE,
3800 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
3807 Xnut_pause, FALSE, FALSE,
3811 Xnut_fall, FALSE, FALSE,
3815 Ynut_s, FALSE, FALSE,
3816 EL_NUT, ACTION_FALLING, -1
3819 Ynut_sB, FALSE, TRUE,
3820 EL_NUT, ACTION_FALLING, -1
3823 Ynut_e, FALSE, FALSE,
3824 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
3827 Ynut_eB, FALSE, TRUE,
3828 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
3831 Ynut_w, FALSE, FALSE,
3832 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
3835 Ynut_wB, FALSE, TRUE,
3836 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
3839 Xbug_n, TRUE, FALSE,
3843 Xbug_e, TRUE, FALSE,
3844 EL_BUG_RIGHT, -1, -1
3847 Xbug_s, TRUE, FALSE,
3851 Xbug_w, TRUE, FALSE,
3855 Xbug_gon, FALSE, FALSE,
3859 Xbug_goe, FALSE, FALSE,
3860 EL_BUG_RIGHT, -1, -1
3863 Xbug_gos, FALSE, FALSE,
3867 Xbug_gow, FALSE, FALSE,
3871 Ybug_n, FALSE, FALSE,
3872 EL_BUG, ACTION_MOVING, MV_BIT_UP
3875 Ybug_nB, FALSE, TRUE,
3876 EL_BUG, ACTION_MOVING, MV_BIT_UP
3879 Ybug_e, FALSE, FALSE,
3880 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
3883 Ybug_eB, FALSE, TRUE,
3884 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
3887 Ybug_s, FALSE, FALSE,
3888 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
3891 Ybug_sB, FALSE, TRUE,
3892 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
3895 Ybug_w, FALSE, FALSE,
3896 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
3899 Ybug_wB, FALSE, TRUE,
3900 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
3903 Ybug_w_n, FALSE, FALSE,
3904 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
3907 Ybug_n_e, FALSE, FALSE,
3908 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
3911 Ybug_e_s, FALSE, FALSE,
3912 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
3915 Ybug_s_w, FALSE, FALSE,
3916 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
3919 Ybug_e_n, FALSE, FALSE,
3920 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
3923 Ybug_s_e, FALSE, FALSE,
3924 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
3927 Ybug_w_s, FALSE, FALSE,
3928 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
3931 Ybug_n_w, FALSE, FALSE,
3932 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
3935 Ybug_stone, FALSE, FALSE,
3936 EL_BUG, ACTION_SMASHED_BY_ROCK, -1
3939 Ybug_spring, FALSE, FALSE,
3940 EL_BUG, ACTION_SMASHED_BY_SPRING, -1
3943 Xtank_n, TRUE, FALSE,
3944 EL_SPACESHIP_UP, -1, -1
3947 Xtank_e, TRUE, FALSE,
3948 EL_SPACESHIP_RIGHT, -1, -1
3951 Xtank_s, TRUE, FALSE,
3952 EL_SPACESHIP_DOWN, -1, -1
3955 Xtank_w, TRUE, FALSE,
3956 EL_SPACESHIP_LEFT, -1, -1
3959 Xtank_gon, FALSE, FALSE,
3960 EL_SPACESHIP_UP, -1, -1
3963 Xtank_goe, FALSE, FALSE,
3964 EL_SPACESHIP_RIGHT, -1, -1
3967 Xtank_gos, FALSE, FALSE,
3968 EL_SPACESHIP_DOWN, -1, -1
3971 Xtank_gow, FALSE, FALSE,
3972 EL_SPACESHIP_LEFT, -1, -1
3975 Ytank_n, FALSE, FALSE,
3976 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
3979 Ytank_nB, FALSE, TRUE,
3980 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
3983 Ytank_e, FALSE, FALSE,
3984 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
3987 Ytank_eB, FALSE, TRUE,
3988 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
3991 Ytank_s, FALSE, FALSE,
3992 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
3995 Ytank_sB, FALSE, TRUE,
3996 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
3999 Ytank_w, FALSE, FALSE,
4000 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
4003 Ytank_wB, FALSE, TRUE,
4004 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
4007 Ytank_w_n, FALSE, FALSE,
4008 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
4011 Ytank_n_e, FALSE, FALSE,
4012 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
4015 Ytank_e_s, FALSE, FALSE,
4016 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
4019 Ytank_s_w, FALSE, FALSE,
4020 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
4023 Ytank_e_n, FALSE, FALSE,
4024 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
4027 Ytank_s_e, FALSE, FALSE,
4028 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
4031 Ytank_w_s, FALSE, FALSE,
4032 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
4035 Ytank_n_w, FALSE, FALSE,
4036 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
4039 Ytank_stone, FALSE, FALSE,
4040 EL_SPACESHIP, ACTION_SMASHED_BY_ROCK, -1
4043 Ytank_spring, FALSE, FALSE,
4044 EL_SPACESHIP, ACTION_SMASHED_BY_SPRING, -1
4047 Xandroid, TRUE, FALSE,
4048 EL_EMC_ANDROID, ACTION_ACTIVE, -1
4051 Xandroid_1_n, FALSE, FALSE,
4052 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
4055 Xandroid_2_n, FALSE, FALSE,
4056 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
4059 Xandroid_1_e, FALSE, FALSE,
4060 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
4063 Xandroid_2_e, FALSE, FALSE,
4064 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
4067 Xandroid_1_w, FALSE, FALSE,
4068 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
4071 Xandroid_2_w, FALSE, FALSE,
4072 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
4075 Xandroid_1_s, FALSE, FALSE,
4076 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
4079 Xandroid_2_s, FALSE, FALSE,
4080 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
4083 Yandroid_n, FALSE, FALSE,
4084 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
4087 Yandroid_nB, FALSE, TRUE,
4088 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
4091 Yandroid_ne, FALSE, FALSE,
4092 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPRIGHT
4095 Yandroid_neB, FALSE, TRUE,
4096 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPRIGHT
4099 Yandroid_e, FALSE, FALSE,
4100 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
4103 Yandroid_eB, FALSE, TRUE,
4104 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
4107 Yandroid_se, FALSE, FALSE,
4108 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNRIGHT
4111 Yandroid_seB, FALSE, TRUE,
4112 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNRIGHT
4115 Yandroid_s, FALSE, FALSE,
4116 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
4119 Yandroid_sB, FALSE, TRUE,
4120 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
4123 Yandroid_sw, FALSE, FALSE,
4124 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNLEFT
4127 Yandroid_swB, FALSE, TRUE,
4128 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNLEFT
4131 Yandroid_w, FALSE, FALSE,
4132 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
4135 Yandroid_wB, FALSE, TRUE,
4136 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
4139 Yandroid_nw, FALSE, FALSE,
4140 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPLEFT
4143 Yandroid_nwB, FALSE, TRUE,
4144 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPLEFT
4147 Xspring, TRUE, FALSE,
4151 Xspring_pause, FALSE, FALSE,
4155 Xspring_e, FALSE, FALSE,
4159 Xspring_w, FALSE, FALSE,
4163 Xspring_fall, FALSE, FALSE,
4167 Yspring_s, FALSE, FALSE,
4168 EL_SPRING, ACTION_FALLING, -1
4171 Yspring_sB, FALSE, TRUE,
4172 EL_SPRING, ACTION_FALLING, -1
4175 Yspring_e, FALSE, FALSE,
4176 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
4179 Yspring_eB, FALSE, TRUE,
4180 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
4183 Yspring_w, FALSE, FALSE,
4184 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
4187 Yspring_wB, FALSE, TRUE,
4188 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
4191 Yspring_kill_e, FALSE, FALSE,
4192 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
4195 Yspring_kill_eB, FALSE, TRUE,
4196 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
4199 Yspring_kill_w, FALSE, FALSE,
4200 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
4203 Yspring_kill_wB, FALSE, TRUE,
4204 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
4207 Xeater_n, TRUE, FALSE,
4208 EL_YAMYAM_UP, -1, -1
4211 Xeater_e, TRUE, FALSE,
4212 EL_YAMYAM_RIGHT, -1, -1
4215 Xeater_w, TRUE, FALSE,
4216 EL_YAMYAM_LEFT, -1, -1
4219 Xeater_s, TRUE, FALSE,
4220 EL_YAMYAM_DOWN, -1, -1
4223 Yeater_n, FALSE, FALSE,
4224 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
4227 Yeater_nB, FALSE, TRUE,
4228 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
4231 Yeater_e, FALSE, FALSE,
4232 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
4235 Yeater_eB, FALSE, TRUE,
4236 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
4239 Yeater_s, FALSE, FALSE,
4240 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
4243 Yeater_sB, FALSE, TRUE,
4244 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
4247 Yeater_w, FALSE, FALSE,
4248 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
4251 Yeater_wB, FALSE, TRUE,
4252 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
4255 Yeater_stone, FALSE, FALSE,
4256 EL_YAMYAM, ACTION_SMASHED_BY_ROCK, -1
4259 Yeater_spring, FALSE, FALSE,
4260 EL_YAMYAM, ACTION_SMASHED_BY_SPRING, -1
4263 Xalien, TRUE, FALSE,
4267 Xalien_pause, FALSE, FALSE,
4271 Yalien_n, FALSE, FALSE,
4272 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
4275 Yalien_nB, FALSE, TRUE,
4276 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
4279 Yalien_e, FALSE, FALSE,
4280 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
4283 Yalien_eB, FALSE, TRUE,
4284 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
4287 Yalien_s, FALSE, FALSE,
4288 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
4291 Yalien_sB, FALSE, TRUE,
4292 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
4295 Yalien_w, FALSE, FALSE,
4296 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
4299 Yalien_wB, FALSE, TRUE,
4300 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
4303 Yalien_stone, FALSE, FALSE,
4304 EL_ROBOT, ACTION_SMASHED_BY_ROCK, -1
4307 Yalien_spring, FALSE, FALSE,
4308 EL_ROBOT, ACTION_SMASHED_BY_SPRING, -1
4311 Xemerald, TRUE, FALSE,
4315 Xemerald_pause, FALSE, FALSE,
4319 Xemerald_fall, FALSE, FALSE,
4323 Xemerald_shine, FALSE, FALSE,
4324 EL_EMERALD, ACTION_TWINKLING, -1
4327 Yemerald_s, FALSE, FALSE,
4328 EL_EMERALD, ACTION_FALLING, -1
4331 Yemerald_sB, FALSE, TRUE,
4332 EL_EMERALD, ACTION_FALLING, -1
4335 Yemerald_e, FALSE, FALSE,
4336 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
4339 Yemerald_eB, FALSE, TRUE,
4340 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
4343 Yemerald_w, FALSE, FALSE,
4344 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
4347 Yemerald_wB, FALSE, TRUE,
4348 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
4351 Yemerald_eat, FALSE, FALSE,
4352 EL_EMERALD, ACTION_COLLECTING, -1
4355 Yemerald_stone, FALSE, FALSE,
4356 EL_NUT, ACTION_BREAKING, -1
4359 Xdiamond, TRUE, FALSE,
4363 Xdiamond_pause, FALSE, FALSE,
4367 Xdiamond_fall, FALSE, FALSE,
4371 Xdiamond_shine, FALSE, FALSE,
4372 EL_DIAMOND, ACTION_TWINKLING, -1
4375 Ydiamond_s, FALSE, FALSE,
4376 EL_DIAMOND, ACTION_FALLING, -1
4379 Ydiamond_sB, FALSE, TRUE,
4380 EL_DIAMOND, ACTION_FALLING, -1
4383 Ydiamond_e, FALSE, FALSE,
4384 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
4387 Ydiamond_eB, FALSE, TRUE,
4388 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
4391 Ydiamond_w, FALSE, FALSE,
4392 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
4395 Ydiamond_wB, FALSE, TRUE,
4396 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
4399 Ydiamond_eat, FALSE, FALSE,
4400 EL_DIAMOND, ACTION_COLLECTING, -1
4403 Ydiamond_stone, FALSE, FALSE,
4404 EL_DIAMOND, ACTION_SMASHED_BY_ROCK, -1
4407 Xdrip_fall, TRUE, FALSE,
4408 EL_AMOEBA_DROP, -1, -1
4411 Xdrip_stretch, FALSE, FALSE,
4412 EL_AMOEBA_DROP, ACTION_FALLING, -1
4415 Xdrip_stretchB, FALSE, TRUE,
4416 EL_AMOEBA_DROP, ACTION_FALLING, -1
4419 Xdrip_eat, FALSE, FALSE,
4420 EL_AMOEBA_DROP, ACTION_GROWING, -1
4423 Ydrip_s1, FALSE, FALSE,
4424 EL_AMOEBA_DROP, ACTION_FALLING, -1
4427 Ydrip_s1B, FALSE, TRUE,
4428 EL_AMOEBA_DROP, ACTION_FALLING, -1
4431 Ydrip_s2, FALSE, FALSE,
4432 EL_AMOEBA_DROP, ACTION_FALLING, -1
4435 Ydrip_s2B, FALSE, TRUE,
4436 EL_AMOEBA_DROP, ACTION_FALLING, -1
4443 Xbomb_pause, FALSE, FALSE,
4447 Xbomb_fall, FALSE, FALSE,
4451 Ybomb_s, FALSE, FALSE,
4452 EL_BOMB, ACTION_FALLING, -1
4455 Ybomb_sB, FALSE, TRUE,
4456 EL_BOMB, ACTION_FALLING, -1
4459 Ybomb_e, FALSE, FALSE,
4460 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
4463 Ybomb_eB, FALSE, TRUE,
4464 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
4467 Ybomb_w, FALSE, FALSE,
4468 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
4471 Ybomb_wB, FALSE, TRUE,
4472 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
4475 Ybomb_eat, FALSE, FALSE,
4476 EL_BOMB, ACTION_ACTIVATING, -1
4479 Xballoon, TRUE, FALSE,
4483 Yballoon_n, FALSE, FALSE,
4484 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
4487 Yballoon_nB, FALSE, TRUE,
4488 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
4491 Yballoon_e, FALSE, FALSE,
4492 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
4495 Yballoon_eB, FALSE, TRUE,
4496 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
4499 Yballoon_s, FALSE, FALSE,
4500 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
4503 Yballoon_sB, FALSE, TRUE,
4504 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
4507 Yballoon_w, FALSE, FALSE,
4508 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
4511 Yballoon_wB, FALSE, TRUE,
4512 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
4515 Xgrass, TRUE, FALSE,
4516 EL_EMC_GRASS, -1, -1
4519 Ygrass_nB, FALSE, FALSE,
4520 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_UP
4523 Ygrass_eB, FALSE, FALSE,
4524 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_RIGHT
4527 Ygrass_sB, FALSE, FALSE,
4528 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_DOWN
4531 Ygrass_wB, FALSE, FALSE,
4532 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_LEFT
4539 Ydirt_nB, FALSE, FALSE,
4540 EL_SAND, ACTION_DIGGING, MV_BIT_UP
4543 Ydirt_eB, FALSE, FALSE,
4544 EL_SAND, ACTION_DIGGING, MV_BIT_RIGHT
4547 Ydirt_sB, FALSE, FALSE,
4548 EL_SAND, ACTION_DIGGING, MV_BIT_DOWN
4551 Ydirt_wB, FALSE, FALSE,
4552 EL_SAND, ACTION_DIGGING, MV_BIT_LEFT
4555 Xacid_ne, TRUE, FALSE,
4556 EL_ACID_POOL_TOPRIGHT, -1, -1
4559 Xacid_se, TRUE, FALSE,
4560 EL_ACID_POOL_BOTTOMRIGHT, -1, -1
4563 Xacid_s, TRUE, FALSE,
4564 EL_ACID_POOL_BOTTOM, -1, -1
4567 Xacid_sw, TRUE, FALSE,
4568 EL_ACID_POOL_BOTTOMLEFT, -1, -1
4571 Xacid_nw, TRUE, FALSE,
4572 EL_ACID_POOL_TOPLEFT, -1, -1
4575 Xacid_1, TRUE, FALSE,
4579 Xacid_2, FALSE, FALSE,
4583 Xacid_3, FALSE, FALSE,
4587 Xacid_4, FALSE, FALSE,
4591 Xacid_5, FALSE, FALSE,
4595 Xacid_6, FALSE, FALSE,
4599 Xacid_7, FALSE, FALSE,
4603 Xacid_8, FALSE, FALSE,
4607 Xball_1, TRUE, FALSE,
4608 EL_EMC_MAGIC_BALL, -1, -1
4611 Xball_1B, FALSE, FALSE,
4612 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4615 Xball_2, FALSE, FALSE,
4616 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4619 Xball_2B, FALSE, FALSE,
4620 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4623 Yball_eat, FALSE, FALSE,
4624 EL_EMC_MAGIC_BALL, ACTION_DROPPING, -1
4627 Ykey_1_eat, FALSE, FALSE,
4628 EL_EM_KEY_1, ACTION_COLLECTING, -1
4631 Ykey_2_eat, FALSE, FALSE,
4632 EL_EM_KEY_2, ACTION_COLLECTING, -1
4635 Ykey_3_eat, FALSE, FALSE,
4636 EL_EM_KEY_3, ACTION_COLLECTING, -1
4639 Ykey_4_eat, FALSE, FALSE,
4640 EL_EM_KEY_4, ACTION_COLLECTING, -1
4643 Ykey_5_eat, FALSE, FALSE,
4644 EL_EMC_KEY_5, ACTION_COLLECTING, -1
4647 Ykey_6_eat, FALSE, FALSE,
4648 EL_EMC_KEY_6, ACTION_COLLECTING, -1
4651 Ykey_7_eat, FALSE, FALSE,
4652 EL_EMC_KEY_7, ACTION_COLLECTING, -1
4655 Ykey_8_eat, FALSE, FALSE,
4656 EL_EMC_KEY_8, ACTION_COLLECTING, -1
4659 Ylenses_eat, FALSE, FALSE,
4660 EL_EMC_LENSES, ACTION_COLLECTING, -1
4663 Ymagnify_eat, FALSE, FALSE,
4664 EL_EMC_MAGNIFIER, ACTION_COLLECTING, -1
4667 Ygrass_eat, FALSE, FALSE,
4668 EL_EMC_GRASS, ACTION_SNAPPING, -1
4671 Ydirt_eat, FALSE, FALSE,
4672 EL_SAND, ACTION_SNAPPING, -1
4675 Xgrow_ns, TRUE, FALSE,
4676 EL_EXPANDABLE_WALL_VERTICAL, -1, -1
4679 Ygrow_ns_eat, FALSE, FALSE,
4680 EL_EXPANDABLE_WALL_VERTICAL, ACTION_GROWING, -1
4683 Xgrow_ew, TRUE, FALSE,
4684 EL_EXPANDABLE_WALL_HORIZONTAL, -1, -1
4687 Ygrow_ew_eat, FALSE, FALSE,
4688 EL_EXPANDABLE_WALL_HORIZONTAL, ACTION_GROWING, -1
4691 Xwonderwall, TRUE, FALSE,
4692 EL_MAGIC_WALL, -1, -1
4695 XwonderwallB, FALSE, FALSE,
4696 EL_MAGIC_WALL, ACTION_ACTIVE, -1
4699 Xamoeba_1, TRUE, FALSE,
4700 EL_AMOEBA_DRY, ACTION_OTHER, -1
4703 Xamoeba_2, FALSE, FALSE,
4704 EL_AMOEBA_DRY, ACTION_OTHER, -1
4707 Xamoeba_3, FALSE, FALSE,
4708 EL_AMOEBA_DRY, ACTION_OTHER, -1
4711 Xamoeba_4, FALSE, FALSE,
4712 EL_AMOEBA_DRY, ACTION_OTHER, -1
4715 Xamoeba_5, TRUE, FALSE,
4716 EL_AMOEBA_WET, ACTION_OTHER, -1
4719 Xamoeba_6, FALSE, FALSE,
4720 EL_AMOEBA_WET, ACTION_OTHER, -1
4723 Xamoeba_7, FALSE, FALSE,
4724 EL_AMOEBA_WET, ACTION_OTHER, -1
4727 Xamoeba_8, FALSE, FALSE,
4728 EL_AMOEBA_WET, ACTION_OTHER, -1
4731 Xdoor_1, TRUE, FALSE,
4732 EL_EM_GATE_1, -1, -1
4735 Xdoor_2, TRUE, FALSE,
4736 EL_EM_GATE_2, -1, -1
4739 Xdoor_3, TRUE, FALSE,
4740 EL_EM_GATE_3, -1, -1
4743 Xdoor_4, TRUE, FALSE,
4744 EL_EM_GATE_4, -1, -1
4747 Xdoor_5, TRUE, FALSE,
4748 EL_EMC_GATE_5, -1, -1
4751 Xdoor_6, TRUE, FALSE,
4752 EL_EMC_GATE_6, -1, -1
4755 Xdoor_7, TRUE, FALSE,
4756 EL_EMC_GATE_7, -1, -1
4759 Xdoor_8, TRUE, FALSE,
4760 EL_EMC_GATE_8, -1, -1
4763 Xkey_1, TRUE, FALSE,
4767 Xkey_2, TRUE, FALSE,
4771 Xkey_3, TRUE, FALSE,
4775 Xkey_4, TRUE, FALSE,
4779 Xkey_5, TRUE, FALSE,
4780 EL_EMC_KEY_5, -1, -1
4783 Xkey_6, TRUE, FALSE,
4784 EL_EMC_KEY_6, -1, -1
4787 Xkey_7, TRUE, FALSE,
4788 EL_EMC_KEY_7, -1, -1
4791 Xkey_8, TRUE, FALSE,
4792 EL_EMC_KEY_8, -1, -1
4795 Xwind_n, TRUE, FALSE,
4796 EL_BALLOON_SWITCH_UP, -1, -1
4799 Xwind_e, TRUE, FALSE,
4800 EL_BALLOON_SWITCH_RIGHT, -1, -1
4803 Xwind_s, TRUE, FALSE,
4804 EL_BALLOON_SWITCH_DOWN, -1, -1
4807 Xwind_w, TRUE, FALSE,
4808 EL_BALLOON_SWITCH_LEFT, -1, -1
4811 Xwind_nesw, TRUE, FALSE,
4812 EL_BALLOON_SWITCH_ANY, -1, -1
4815 Xwind_stop, TRUE, FALSE,
4816 EL_BALLOON_SWITCH_NONE, -1, -1
4820 EL_EM_EXIT_CLOSED, -1, -1
4823 Xexit_1, TRUE, FALSE,
4824 EL_EM_EXIT_OPEN, -1, -1
4827 Xexit_2, FALSE, FALSE,
4828 EL_EM_EXIT_OPEN, -1, -1
4831 Xexit_3, FALSE, FALSE,
4832 EL_EM_EXIT_OPEN, -1, -1
4835 Xdynamite, TRUE, FALSE,
4836 EL_EM_DYNAMITE, -1, -1
4839 Ydynamite_eat, FALSE, FALSE,
4840 EL_EM_DYNAMITE, ACTION_COLLECTING, -1
4843 Xdynamite_1, TRUE, FALSE,
4844 EL_EM_DYNAMITE_ACTIVE, -1, -1
4847 Xdynamite_2, FALSE, FALSE,
4848 EL_EM_DYNAMITE_ACTIVE, -1, -1
4851 Xdynamite_3, FALSE, FALSE,
4852 EL_EM_DYNAMITE_ACTIVE, -1, -1
4855 Xdynamite_4, FALSE, FALSE,
4856 EL_EM_DYNAMITE_ACTIVE, -1, -1
4859 Xbumper, TRUE, FALSE,
4860 EL_EMC_SPRING_BUMPER, -1, -1
4863 XbumperB, FALSE, FALSE,
4864 EL_EMC_SPRING_BUMPER, ACTION_ACTIVE, -1
4867 Xwheel, TRUE, FALSE,
4868 EL_ROBOT_WHEEL, -1, -1
4871 XwheelB, FALSE, FALSE,
4872 EL_ROBOT_WHEEL, ACTION_ACTIVE, -1
4875 Xswitch, TRUE, FALSE,
4876 EL_EMC_MAGIC_BALL_SWITCH, -1, -1
4879 XswitchB, FALSE, FALSE,
4880 EL_EMC_MAGIC_BALL_SWITCH, ACTION_ACTIVE, -1
4884 EL_QUICKSAND_EMPTY, -1, -1
4887 Xsand_stone, TRUE, FALSE,
4888 EL_QUICKSAND_FULL, -1, -1
4891 Xsand_stonein_1, FALSE, TRUE,
4892 EL_ROCK, ACTION_FILLING, -1
4895 Xsand_stonein_2, FALSE, TRUE,
4896 EL_ROCK, ACTION_FILLING, -1
4899 Xsand_stonein_3, FALSE, TRUE,
4900 EL_ROCK, ACTION_FILLING, -1
4903 Xsand_stonein_4, FALSE, TRUE,
4904 EL_ROCK, ACTION_FILLING, -1
4908 Xsand_stonesand_1, FALSE, FALSE,
4909 EL_QUICKSAND_EMPTYING, -1, -1
4912 Xsand_stonesand_2, FALSE, FALSE,
4913 EL_QUICKSAND_EMPTYING, -1, -1
4916 Xsand_stonesand_3, FALSE, FALSE,
4917 EL_QUICKSAND_EMPTYING, -1, -1
4920 Xsand_stonesand_4, FALSE, FALSE,
4921 EL_QUICKSAND_EMPTYING, -1, -1
4924 Xsand_stonesand_quickout_1, FALSE, FALSE,
4925 EL_QUICKSAND_EMPTYING, -1, -1
4928 Xsand_stonesand_quickout_2, FALSE, FALSE,
4929 EL_QUICKSAND_EMPTYING, -1, -1
4933 Xsand_stonesand_1, FALSE, FALSE,
4934 EL_QUICKSAND_FULL, -1, -1
4937 Xsand_stonesand_2, FALSE, FALSE,
4938 EL_QUICKSAND_FULL, -1, -1
4941 Xsand_stonesand_3, FALSE, FALSE,
4942 EL_QUICKSAND_FULL, -1, -1
4945 Xsand_stonesand_4, FALSE, FALSE,
4946 EL_QUICKSAND_FULL, -1, -1
4950 Xsand_stoneout_1, FALSE, FALSE,
4951 EL_ROCK, ACTION_EMPTYING, -1
4954 Xsand_stoneout_2, FALSE, FALSE,
4955 EL_ROCK, ACTION_EMPTYING, -1
4959 Xsand_sandstone_1, FALSE, FALSE,
4960 EL_QUICKSAND_FILLING, -1, -1
4963 Xsand_sandstone_2, FALSE, FALSE,
4964 EL_QUICKSAND_FILLING, -1, -1
4967 Xsand_sandstone_3, FALSE, FALSE,
4968 EL_QUICKSAND_FILLING, -1, -1
4971 Xsand_sandstone_4, FALSE, FALSE,
4972 EL_QUICKSAND_FILLING, -1, -1
4976 Xsand_sandstone_1, FALSE, FALSE,
4977 EL_QUICKSAND_FULL, -1, -1
4980 Xsand_sandstone_2, FALSE, FALSE,
4981 EL_QUICKSAND_FULL, -1, -1
4984 Xsand_sandstone_3, FALSE, FALSE,
4985 EL_QUICKSAND_FULL, -1, -1
4988 Xsand_sandstone_4, FALSE, FALSE,
4989 EL_QUICKSAND_FULL, -1, -1
4993 Xplant, TRUE, FALSE,
4994 EL_EMC_PLANT, -1, -1
4997 Yplant, FALSE, FALSE,
4998 EL_EMC_PLANT, -1, -1
5001 Xlenses, TRUE, FALSE,
5002 EL_EMC_LENSES, -1, -1
5005 Xmagnify, TRUE, FALSE,
5006 EL_EMC_MAGNIFIER, -1, -1
5009 Xdripper, TRUE, FALSE,
5010 EL_EMC_DRIPPER, -1, -1
5013 XdripperB, FALSE, FALSE,
5014 EL_EMC_DRIPPER, ACTION_ACTIVE, -1
5017 Xfake_blank, TRUE, FALSE,
5018 EL_INVISIBLE_WALL, -1, -1
5021 Xfake_blankB, FALSE, FALSE,
5022 EL_INVISIBLE_WALL, ACTION_ACTIVE, -1
5025 Xfake_grass, TRUE, FALSE,
5026 EL_EMC_FAKE_GRASS, -1, -1
5029 Xfake_grassB, FALSE, FALSE,
5030 EL_EMC_FAKE_GRASS, ACTION_ACTIVE, -1
5033 Xfake_door_1, TRUE, FALSE,
5034 EL_EM_GATE_1_GRAY, -1, -1
5037 Xfake_door_2, TRUE, FALSE,
5038 EL_EM_GATE_2_GRAY, -1, -1
5041 Xfake_door_3, TRUE, FALSE,
5042 EL_EM_GATE_3_GRAY, -1, -1
5045 Xfake_door_4, TRUE, FALSE,
5046 EL_EM_GATE_4_GRAY, -1, -1
5049 Xfake_door_5, TRUE, FALSE,
5050 EL_EMC_GATE_5_GRAY, -1, -1
5053 Xfake_door_6, TRUE, FALSE,
5054 EL_EMC_GATE_6_GRAY, -1, -1
5057 Xfake_door_7, TRUE, FALSE,
5058 EL_EMC_GATE_7_GRAY, -1, -1
5061 Xfake_door_8, TRUE, FALSE,
5062 EL_EMC_GATE_8_GRAY, -1, -1
5065 Xfake_acid_1, TRUE, FALSE,
5066 EL_EMC_FAKE_ACID, -1, -1
5069 Xfake_acid_2, FALSE, FALSE,
5070 EL_EMC_FAKE_ACID, -1, -1
5073 Xfake_acid_3, FALSE, FALSE,
5074 EL_EMC_FAKE_ACID, -1, -1
5077 Xfake_acid_4, FALSE, FALSE,
5078 EL_EMC_FAKE_ACID, -1, -1
5081 Xfake_acid_5, FALSE, FALSE,
5082 EL_EMC_FAKE_ACID, -1, -1
5085 Xfake_acid_6, FALSE, FALSE,
5086 EL_EMC_FAKE_ACID, -1, -1
5089 Xfake_acid_7, FALSE, FALSE,
5090 EL_EMC_FAKE_ACID, -1, -1
5093 Xfake_acid_8, FALSE, FALSE,
5094 EL_EMC_FAKE_ACID, -1, -1
5097 Xsteel_1, TRUE, FALSE,
5098 EL_STEELWALL, -1, -1
5101 Xsteel_2, TRUE, FALSE,
5102 EL_EMC_STEELWALL_2, -1, -1
5105 Xsteel_3, TRUE, FALSE,
5106 EL_EMC_STEELWALL_3, -1, -1
5109 Xsteel_4, TRUE, FALSE,
5110 EL_EMC_STEELWALL_4, -1, -1
5113 Xwall_1, TRUE, FALSE,
5117 Xwall_2, TRUE, FALSE,
5118 EL_EMC_WALL_14, -1, -1
5121 Xwall_3, TRUE, FALSE,
5122 EL_EMC_WALL_15, -1, -1
5125 Xwall_4, TRUE, FALSE,
5126 EL_EMC_WALL_16, -1, -1
5129 Xround_wall_1, TRUE, FALSE,
5130 EL_WALL_SLIPPERY, -1, -1
5133 Xround_wall_2, TRUE, FALSE,
5134 EL_EMC_WALL_SLIPPERY_2, -1, -1
5137 Xround_wall_3, TRUE, FALSE,
5138 EL_EMC_WALL_SLIPPERY_3, -1, -1
5141 Xround_wall_4, TRUE, FALSE,
5142 EL_EMC_WALL_SLIPPERY_4, -1, -1
5145 Xdecor_1, TRUE, FALSE,
5146 EL_EMC_WALL_8, -1, -1
5149 Xdecor_2, TRUE, FALSE,
5150 EL_EMC_WALL_6, -1, -1
5153 Xdecor_3, TRUE, FALSE,
5154 EL_EMC_WALL_4, -1, -1
5157 Xdecor_4, TRUE, FALSE,
5158 EL_EMC_WALL_7, -1, -1
5161 Xdecor_5, TRUE, FALSE,
5162 EL_EMC_WALL_5, -1, -1
5165 Xdecor_6, TRUE, FALSE,
5166 EL_EMC_WALL_9, -1, -1
5169 Xdecor_7, TRUE, FALSE,
5170 EL_EMC_WALL_10, -1, -1
5173 Xdecor_8, TRUE, FALSE,
5174 EL_EMC_WALL_1, -1, -1
5177 Xdecor_9, TRUE, FALSE,
5178 EL_EMC_WALL_2, -1, -1
5181 Xdecor_10, TRUE, FALSE,
5182 EL_EMC_WALL_3, -1, -1
5185 Xdecor_11, TRUE, FALSE,
5186 EL_EMC_WALL_11, -1, -1
5189 Xdecor_12, TRUE, FALSE,
5190 EL_EMC_WALL_12, -1, -1
5193 Xalpha_0, TRUE, FALSE,
5194 EL_CHAR('0'), -1, -1
5197 Xalpha_1, TRUE, FALSE,
5198 EL_CHAR('1'), -1, -1
5201 Xalpha_2, TRUE, FALSE,
5202 EL_CHAR('2'), -1, -1
5205 Xalpha_3, TRUE, FALSE,
5206 EL_CHAR('3'), -1, -1
5209 Xalpha_4, TRUE, FALSE,
5210 EL_CHAR('4'), -1, -1
5213 Xalpha_5, TRUE, FALSE,
5214 EL_CHAR('5'), -1, -1
5217 Xalpha_6, TRUE, FALSE,
5218 EL_CHAR('6'), -1, -1
5221 Xalpha_7, TRUE, FALSE,
5222 EL_CHAR('7'), -1, -1
5225 Xalpha_8, TRUE, FALSE,
5226 EL_CHAR('8'), -1, -1
5229 Xalpha_9, TRUE, FALSE,
5230 EL_CHAR('9'), -1, -1
5233 Xalpha_excla, TRUE, FALSE,
5234 EL_CHAR('!'), -1, -1
5237 Xalpha_quote, TRUE, FALSE,
5238 EL_CHAR('"'), -1, -1
5241 Xalpha_comma, TRUE, FALSE,
5242 EL_CHAR(','), -1, -1
5245 Xalpha_minus, TRUE, FALSE,
5246 EL_CHAR('-'), -1, -1
5249 Xalpha_perio, TRUE, FALSE,
5250 EL_CHAR('.'), -1, -1
5253 Xalpha_colon, TRUE, FALSE,
5254 EL_CHAR(':'), -1, -1
5257 Xalpha_quest, TRUE, FALSE,
5258 EL_CHAR('?'), -1, -1
5261 Xalpha_a, TRUE, FALSE,
5262 EL_CHAR('A'), -1, -1
5265 Xalpha_b, TRUE, FALSE,
5266 EL_CHAR('B'), -1, -1
5269 Xalpha_c, TRUE, FALSE,
5270 EL_CHAR('C'), -1, -1
5273 Xalpha_d, TRUE, FALSE,
5274 EL_CHAR('D'), -1, -1
5277 Xalpha_e, TRUE, FALSE,
5278 EL_CHAR('E'), -1, -1
5281 Xalpha_f, TRUE, FALSE,
5282 EL_CHAR('F'), -1, -1
5285 Xalpha_g, TRUE, FALSE,
5286 EL_CHAR('G'), -1, -1
5289 Xalpha_h, TRUE, FALSE,
5290 EL_CHAR('H'), -1, -1
5293 Xalpha_i, TRUE, FALSE,
5294 EL_CHAR('I'), -1, -1
5297 Xalpha_j, TRUE, FALSE,
5298 EL_CHAR('J'), -1, -1
5301 Xalpha_k, TRUE, FALSE,
5302 EL_CHAR('K'), -1, -1
5305 Xalpha_l, TRUE, FALSE,
5306 EL_CHAR('L'), -1, -1
5309 Xalpha_m, TRUE, FALSE,
5310 EL_CHAR('M'), -1, -1
5313 Xalpha_n, TRUE, FALSE,
5314 EL_CHAR('N'), -1, -1
5317 Xalpha_o, TRUE, FALSE,
5318 EL_CHAR('O'), -1, -1
5321 Xalpha_p, TRUE, FALSE,
5322 EL_CHAR('P'), -1, -1
5325 Xalpha_q, TRUE, FALSE,
5326 EL_CHAR('Q'), -1, -1
5329 Xalpha_r, TRUE, FALSE,
5330 EL_CHAR('R'), -1, -1
5333 Xalpha_s, TRUE, FALSE,
5334 EL_CHAR('S'), -1, -1
5337 Xalpha_t, TRUE, FALSE,
5338 EL_CHAR('T'), -1, -1
5341 Xalpha_u, TRUE, FALSE,
5342 EL_CHAR('U'), -1, -1
5345 Xalpha_v, TRUE, FALSE,
5346 EL_CHAR('V'), -1, -1
5349 Xalpha_w, TRUE, FALSE,
5350 EL_CHAR('W'), -1, -1
5353 Xalpha_x, TRUE, FALSE,
5354 EL_CHAR('X'), -1, -1
5357 Xalpha_y, TRUE, FALSE,
5358 EL_CHAR('Y'), -1, -1
5361 Xalpha_z, TRUE, FALSE,
5362 EL_CHAR('Z'), -1, -1
5365 Xalpha_arrow_e, TRUE, FALSE,
5366 EL_CHAR('>'), -1, -1
5369 Xalpha_arrow_w, TRUE, FALSE,
5370 EL_CHAR('<'), -1, -1
5373 Xalpha_copyr, TRUE, FALSE,
5374 EL_CHAR('©'), -1, -1
5378 Xboom_bug, FALSE, FALSE,
5379 EL_BUG, ACTION_EXPLODING, -1
5382 Xboom_bomb, FALSE, FALSE,
5383 EL_BOMB, ACTION_EXPLODING, -1
5386 Xboom_android, FALSE, FALSE,
5387 EL_EMC_ANDROID, ACTION_OTHER, -1
5390 Xboom_1, FALSE, FALSE,
5391 EL_DEFAULT, ACTION_EXPLODING, -1
5394 Xboom_2, FALSE, FALSE,
5395 EL_DEFAULT, ACTION_EXPLODING, -1
5398 Znormal, FALSE, FALSE,
5402 Zdynamite, FALSE, FALSE,
5406 Zplayer, FALSE, FALSE,
5410 ZBORDER, FALSE, FALSE,
5420 static struct Mapping_EM_to_RND_player
5429 em_player_mapping_list[] =
5433 EL_PLAYER_1, ACTION_MOVING, MV_BIT_UP,
5437 EL_PLAYER_1, ACTION_MOVING, MV_BIT_RIGHT,
5441 EL_PLAYER_1, ACTION_MOVING, MV_BIT_DOWN,
5445 EL_PLAYER_1, ACTION_MOVING, MV_BIT_LEFT,
5449 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_UP,
5453 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_RIGHT,
5457 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_DOWN,
5461 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_LEFT,
5465 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_UP,
5469 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_RIGHT,
5473 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_DOWN,
5477 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_LEFT,
5481 EL_PLAYER_2, ACTION_MOVING, MV_BIT_UP,
5485 EL_PLAYER_2, ACTION_MOVING, MV_BIT_RIGHT,
5489 EL_PLAYER_2, ACTION_MOVING, MV_BIT_DOWN,
5493 EL_PLAYER_2, ACTION_MOVING, MV_BIT_LEFT,
5497 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_UP,
5501 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_RIGHT,
5505 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_DOWN,
5509 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_LEFT,
5513 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_UP,
5517 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_RIGHT,
5521 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_DOWN,
5525 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_LEFT,
5529 EL_PLAYER_1, ACTION_DEFAULT, -1,
5533 EL_PLAYER_2, ACTION_DEFAULT, -1,
5537 EL_PLAYER_3, ACTION_MOVING, MV_BIT_UP,
5541 EL_PLAYER_3, ACTION_MOVING, MV_BIT_RIGHT,
5545 EL_PLAYER_3, ACTION_MOVING, MV_BIT_DOWN,
5549 EL_PLAYER_3, ACTION_MOVING, MV_BIT_LEFT,
5553 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_UP,
5557 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_RIGHT,
5561 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_DOWN,
5565 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_LEFT,
5569 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_UP,
5573 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_RIGHT,
5577 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_DOWN,
5581 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_LEFT,
5585 EL_PLAYER_4, ACTION_MOVING, MV_BIT_UP,
5589 EL_PLAYER_4, ACTION_MOVING, MV_BIT_RIGHT,
5593 EL_PLAYER_4, ACTION_MOVING, MV_BIT_DOWN,
5597 EL_PLAYER_4, ACTION_MOVING, MV_BIT_LEFT,
5601 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_UP,
5605 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_RIGHT,
5609 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_DOWN,
5613 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_LEFT,
5617 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_UP,
5621 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_RIGHT,
5625 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_DOWN,
5629 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_LEFT,
5633 EL_PLAYER_3, ACTION_DEFAULT, -1,
5637 EL_PLAYER_4, ACTION_DEFAULT, -1,
5646 int map_element_RND_to_EM(int element_rnd)
5648 static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
5649 static boolean mapping_initialized = FALSE;
5651 if (!mapping_initialized)
5655 /* return "Xalpha_quest" for all undefined elements in mapping array */
5656 for (i = 0; i < NUM_FILE_ELEMENTS; i++)
5657 mapping_RND_to_EM[i] = Xalpha_quest;
5659 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5660 if (em_object_mapping_list[i].is_rnd_to_em_mapping)
5661 mapping_RND_to_EM[em_object_mapping_list[i].element_rnd] =
5662 em_object_mapping_list[i].element_em;
5664 mapping_initialized = TRUE;
5667 if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
5668 return mapping_RND_to_EM[element_rnd];
5670 Error(ERR_WARN, "invalid RND level element %d", element_rnd);
5675 int map_element_EM_to_RND(int element_em)
5677 static unsigned short mapping_EM_to_RND[TILE_MAX];
5678 static boolean mapping_initialized = FALSE;
5680 if (!mapping_initialized)
5684 /* return "EL_UNKNOWN" for all undefined elements in mapping array */
5685 for (i = 0; i < TILE_MAX; i++)
5686 mapping_EM_to_RND[i] = EL_UNKNOWN;
5688 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5689 mapping_EM_to_RND[em_object_mapping_list[i].element_em] =
5690 em_object_mapping_list[i].element_rnd;
5692 mapping_initialized = TRUE;
5695 if (element_em >= 0 && element_em < TILE_MAX)
5696 return mapping_EM_to_RND[element_em];
5698 Error(ERR_WARN, "invalid EM level element %d", element_em);
5703 void map_android_clone_elements_RND_to_EM(struct LevelInfo *level)
5705 struct LevelInfo_EM *level_em = level->native_em_level;
5706 struct LEVEL *lev = level_em->lev;
5709 for (i = 0; i < TILE_MAX; i++)
5710 lev->android_array[i] = Xblank;
5712 for (i = 0; i < level->num_android_clone_elements; i++)
5714 int element_rnd = level->android_clone_element[i];
5715 int element_em = map_element_RND_to_EM(element_rnd);
5717 for (j = 0; em_object_mapping_list[j].element_em != -1; j++)
5718 if (em_object_mapping_list[j].element_rnd == element_rnd)
5719 lev->android_array[em_object_mapping_list[j].element_em] = element_em;
5723 void map_android_clone_elements_EM_to_RND(struct LevelInfo *level)
5725 struct LevelInfo_EM *level_em = level->native_em_level;
5726 struct LEVEL *lev = level_em->lev;
5729 level->num_android_clone_elements = 0;
5731 for (i = 0; i < TILE_MAX; i++)
5733 int element_em = lev->android_array[i];
5735 boolean element_found = FALSE;
5737 if (element_em == Xblank)
5740 element_rnd = map_element_EM_to_RND(element_em);
5742 for (j = 0; j < level->num_android_clone_elements; j++)
5743 if (level->android_clone_element[j] == element_rnd)
5744 element_found = TRUE;
5748 level->android_clone_element[level->num_android_clone_elements++] =
5751 if (level->num_android_clone_elements == MAX_ANDROID_ELEMENTS)
5756 if (level->num_android_clone_elements == 0)
5758 level->num_android_clone_elements = 1;
5759 level->android_clone_element[0] = EL_EMPTY;
5763 int map_direction_RND_to_EM(int direction)
5765 return (direction == MV_UP ? 0 :
5766 direction == MV_RIGHT ? 1 :
5767 direction == MV_DOWN ? 2 :
5768 direction == MV_LEFT ? 3 :
5772 int map_direction_EM_to_RND(int direction)
5774 return (direction == 0 ? MV_UP :
5775 direction == 1 ? MV_RIGHT :
5776 direction == 2 ? MV_DOWN :
5777 direction == 3 ? MV_LEFT :
5781 int get_next_element(int element)
5785 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
5786 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
5787 case EL_QUICKSAND_FAST_FILLING: return EL_QUICKSAND_FAST_FULL;
5788 case EL_QUICKSAND_FAST_EMPTYING: return EL_QUICKSAND_FAST_EMPTY;
5789 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
5790 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
5791 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
5792 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
5793 case EL_DC_MAGIC_WALL_FILLING: return EL_DC_MAGIC_WALL_FULL;
5794 case EL_DC_MAGIC_WALL_EMPTYING: return EL_DC_MAGIC_WALL_ACTIVE;
5795 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
5797 default: return element;
5802 int el_act_dir2img(int element, int action, int direction)
5804 element = GFX_ELEMENT(element);
5806 if (direction == MV_NONE)
5807 return element_info[element].graphic[action];
5809 direction = MV_DIR_TO_BIT(direction);
5811 return element_info[element].direction_graphic[action][direction];
5814 int el_act_dir2img(int element, int action, int direction)
5816 element = GFX_ELEMENT(element);
5817 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
5819 /* direction_graphic[][] == graphic[] for undefined direction graphics */
5820 return element_info[element].direction_graphic[action][direction];
5825 static int el_act_dir2crm(int element, int action, int direction)
5827 element = GFX_ELEMENT(element);
5829 if (direction == MV_NONE)
5830 return element_info[element].crumbled[action];
5832 direction = MV_DIR_TO_BIT(direction);
5834 return element_info[element].direction_crumbled[action][direction];
5837 static int el_act_dir2crm(int element, int action, int direction)
5839 element = GFX_ELEMENT(element);
5840 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
5842 /* direction_graphic[][] == graphic[] for undefined direction graphics */
5843 return element_info[element].direction_crumbled[action][direction];
5847 int el_act2img(int element, int action)
5849 element = GFX_ELEMENT(element);
5851 return element_info[element].graphic[action];
5854 int el_act2crm(int element, int action)
5856 element = GFX_ELEMENT(element);
5858 return element_info[element].crumbled[action];
5861 int el_dir2img(int element, int direction)
5863 element = GFX_ELEMENT(element);
5865 return el_act_dir2img(element, ACTION_DEFAULT, direction);
5868 int el2baseimg(int element)
5870 return element_info[element].graphic[ACTION_DEFAULT];
5873 int el2img(int element)
5875 element = GFX_ELEMENT(element);
5877 return element_info[element].graphic[ACTION_DEFAULT];
5880 int el2edimg(int element)
5882 element = GFX_ELEMENT(element);
5884 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
5887 int el2preimg(int element)
5889 element = GFX_ELEMENT(element);
5891 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
5894 int el2panelimg(int element)
5896 element = GFX_ELEMENT(element);
5898 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PANEL];
5901 int font2baseimg(int font_nr)
5903 return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
5906 int getBeltNrFromBeltElement(int element)
5908 return (element < EL_CONVEYOR_BELT_2_LEFT ? 0 :
5909 element < EL_CONVEYOR_BELT_3_LEFT ? 1 :
5910 element < EL_CONVEYOR_BELT_4_LEFT ? 2 : 3);
5913 int getBeltNrFromBeltActiveElement(int element)
5915 return (element < EL_CONVEYOR_BELT_2_LEFT_ACTIVE ? 0 :
5916 element < EL_CONVEYOR_BELT_3_LEFT_ACTIVE ? 1 :
5917 element < EL_CONVEYOR_BELT_4_LEFT_ACTIVE ? 2 : 3);
5920 int getBeltNrFromBeltSwitchElement(int element)
5922 return (element < EL_CONVEYOR_BELT_2_SWITCH_LEFT ? 0 :
5923 element < EL_CONVEYOR_BELT_3_SWITCH_LEFT ? 1 :
5924 element < EL_CONVEYOR_BELT_4_SWITCH_LEFT ? 2 : 3);
5927 int getBeltDirNrFromBeltElement(int element)
5929 static int belt_base_element[4] =
5931 EL_CONVEYOR_BELT_1_LEFT,
5932 EL_CONVEYOR_BELT_2_LEFT,
5933 EL_CONVEYOR_BELT_3_LEFT,
5934 EL_CONVEYOR_BELT_4_LEFT
5937 int belt_nr = getBeltNrFromBeltElement(element);
5938 int belt_dir_nr = element - belt_base_element[belt_nr];
5940 return (belt_dir_nr % 3);
5943 int getBeltDirNrFromBeltSwitchElement(int element)
5945 static int belt_base_element[4] =
5947 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
5948 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
5949 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
5950 EL_CONVEYOR_BELT_4_SWITCH_LEFT
5953 int belt_nr = getBeltNrFromBeltSwitchElement(element);
5954 int belt_dir_nr = element - belt_base_element[belt_nr];
5956 return (belt_dir_nr % 3);
5959 int getBeltDirFromBeltElement(int element)
5961 static int belt_move_dir[3] =
5968 int belt_dir_nr = getBeltDirNrFromBeltElement(element);
5970 return belt_move_dir[belt_dir_nr];
5973 int getBeltDirFromBeltSwitchElement(int element)
5975 static int belt_move_dir[3] =
5982 int belt_dir_nr = getBeltDirNrFromBeltSwitchElement(element);
5984 return belt_move_dir[belt_dir_nr];
5987 int getBeltElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
5989 static int belt_base_element[4] =
5991 EL_CONVEYOR_BELT_1_LEFT,
5992 EL_CONVEYOR_BELT_2_LEFT,
5993 EL_CONVEYOR_BELT_3_LEFT,
5994 EL_CONVEYOR_BELT_4_LEFT
5997 return belt_base_element[belt_nr] + belt_dir_nr;
6000 int getBeltElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
6002 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
6004 return getBeltElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
6007 int getBeltSwitchElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
6009 static int belt_base_element[4] =
6011 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
6012 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
6013 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
6014 EL_CONVEYOR_BELT_4_SWITCH_LEFT
6017 return belt_base_element[belt_nr] + belt_dir_nr;
6020 int getBeltSwitchElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
6022 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
6024 return getBeltSwitchElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
6027 int getNumActivePlayers_EM()
6029 int num_players = 0;
6035 for (i = 0; i < MAX_PLAYERS; i++)
6036 if (tape.player_participates[i])
6042 int getGameFrameDelay_EM(int native_em_game_frame_delay)
6044 int game_frame_delay_value;
6046 game_frame_delay_value =
6047 (tape.playing && tape.fast_forward ? FfwdFrameDelay :
6048 GameFrameDelay == GAME_FRAME_DELAY ? native_em_game_frame_delay :
6051 if (tape.playing && tape.warp_forward && !tape.pausing)
6052 game_frame_delay_value = 0;
6054 return game_frame_delay_value;
6057 unsigned int InitRND(long seed)
6059 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
6060 return InitEngineRandom_EM(seed);
6061 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
6062 return InitEngineRandom_SP(seed);
6064 return InitEngineRandom_RND(seed);
6068 static struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
6069 static struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
6072 inline static int get_effective_element_EM(int tile, int frame_em)
6074 int element = object_mapping[tile].element_rnd;
6075 int action = object_mapping[tile].action;
6076 boolean is_backside = object_mapping[tile].is_backside;
6077 boolean action_removing = (action == ACTION_DIGGING ||
6078 action == ACTION_SNAPPING ||
6079 action == ACTION_COLLECTING);
6085 case Yacid_splash_eB:
6086 case Yacid_splash_wB:
6087 return (frame_em > 5 ? EL_EMPTY : element);
6093 else /* frame_em == 7 */
6097 case Yacid_splash_eB:
6098 case Yacid_splash_wB:
6101 case Yemerald_stone:
6104 case Ydiamond_stone:
6108 case Xdrip_stretchB:
6127 case Xsand_stonein_1:
6128 case Xsand_stonein_2:
6129 case Xsand_stonein_3:
6130 case Xsand_stonein_4:
6134 return (is_backside || action_removing ? EL_EMPTY : element);
6139 inline static boolean check_linear_animation_EM(int tile)
6143 case Xsand_stonesand_1:
6144 case Xsand_stonesand_quickout_1:
6145 case Xsand_sandstone_1:
6146 case Xsand_stonein_1:
6147 case Xsand_stoneout_1:
6172 inline static void set_crumbled_graphics_EM(struct GraphicInfo_EM *g_em,
6173 boolean has_crumbled_graphics,
6174 int crumbled, int sync_frame)
6176 /* if element can be crumbled, but certain action graphics are just empty
6177 space (like instantly snapping sand to empty space in 1 frame), do not
6178 treat these empty space graphics as crumbled graphics in EMC engine */
6179 if (crumbled == IMG_EMPTY_SPACE)
6180 has_crumbled_graphics = FALSE;
6182 if (has_crumbled_graphics)
6184 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
6185 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
6186 g_crumbled->anim_delay,
6187 g_crumbled->anim_mode,
6188 g_crumbled->anim_start_frame,
6191 getGraphicSource(crumbled, frame_crumbled, &g_em->crumbled_bitmap,
6192 &g_em->crumbled_src_x, &g_em->crumbled_src_y);
6194 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
6196 g_em->has_crumbled_graphics = TRUE;
6200 g_em->crumbled_bitmap = NULL;
6201 g_em->crumbled_src_x = 0;
6202 g_em->crumbled_src_y = 0;
6203 g_em->crumbled_border_size = 0;
6205 g_em->has_crumbled_graphics = FALSE;
6209 void ResetGfxAnimation_EM(int x, int y, int tile)
6214 void SetGfxAnimation_EM(struct GraphicInfo_EM *g_em,
6215 int tile, int frame_em, int x, int y)
6217 int action = object_mapping[tile].action;
6219 int direction = object_mapping[tile].direction;
6220 int effective_element = get_effective_element_EM(tile, frame_em);
6221 int graphic = (direction == MV_NONE ?
6222 el_act2img(effective_element, action) :
6223 el_act_dir2img(effective_element, action, direction));
6224 struct GraphicInfo *g = &graphic_info[graphic];
6227 boolean action_removing = (action == ACTION_DIGGING ||
6228 action == ACTION_SNAPPING ||
6229 action == ACTION_COLLECTING);
6230 boolean action_moving = (action == ACTION_FALLING ||
6231 action == ACTION_MOVING ||
6232 action == ACTION_PUSHING ||
6233 action == ACTION_EATING ||
6234 action == ACTION_FILLING ||
6235 action == ACTION_EMPTYING);
6236 boolean action_falling = (action == ACTION_FALLING ||
6237 action == ACTION_FILLING ||
6238 action == ACTION_EMPTYING);
6240 /* special case: graphic uses "2nd movement tile" and has defined
6241 7 frames for movement animation (or less) => use default graphic
6242 for last (8th) frame which ends the movement animation */
6243 if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
6245 action = ACTION_DEFAULT; /* (keep action_* unchanged for now) */
6246 graphic = (direction == MV_NONE ?
6247 el_act2img(effective_element, action) :
6248 el_act_dir2img(effective_element, action, direction));
6250 g = &graphic_info[graphic];
6254 if (tile == Xsand_stonesand_1 ||
6255 tile == Xsand_stonesand_2 ||
6256 tile == Xsand_stonesand_3 ||
6257 tile == Xsand_stonesand_4)
6258 printf("::: 1: quicksand frame %d [%d]\n", GfxFrame[x][y], tile);
6262 if ((action_removing || check_linear_animation_EM(tile)) && frame_em == 0)
6266 // printf("::: resetting... [%d]\n", tile);
6269 if (action_removing || check_linear_animation_EM(tile))
6271 GfxFrame[x][y] = frame_em;
6273 // printf("::: resetting... [%d]\n", tile);
6276 else if (action_moving)
6278 boolean is_backside = object_mapping[tile].is_backside;
6282 int direction = object_mapping[tile].direction;
6283 int move_dir = (action_falling ? MV_DOWN : direction);
6288 /* !!! TEST !!! NEW !!! DOES NOT WORK RIGHT YET !!! */
6289 if (g->double_movement && frame_em == 0)
6293 // printf("::: resetting... [%d]\n", tile);
6297 if (move_dir == MV_LEFT)
6298 GfxFrame[x - 1][y] = GfxFrame[x][y];
6299 else if (move_dir == MV_RIGHT)
6300 GfxFrame[x + 1][y] = GfxFrame[x][y];
6301 else if (move_dir == MV_UP)
6302 GfxFrame[x][y - 1] = GfxFrame[x][y];
6303 else if (move_dir == MV_DOWN)
6304 GfxFrame[x][y + 1] = GfxFrame[x][y];
6311 /* special case: animation for Xsand_stonesand_quickout_1/2 twice as fast */
6312 if (tile == Xsand_stonesand_quickout_1 ||
6313 tile == Xsand_stonesand_quickout_2)
6318 if (tile == Xsand_stonesand_1 ||
6319 tile == Xsand_stonesand_2 ||
6320 tile == Xsand_stonesand_3 ||
6321 tile == Xsand_stonesand_4)
6322 printf("::: 2: quicksand frame %d [%d]\n", GfxFrame[x][y], tile);
6326 if (graphic_info[graphic].anim_global_sync)
6327 sync_frame = FrameCounter;
6328 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
6329 sync_frame = GfxFrame[x][y];
6331 sync_frame = 0; /* playfield border (pseudo steel) */
6333 SetRandomAnimationValue(x, y);
6335 int frame = getAnimationFrame(g->anim_frames,
6338 g->anim_start_frame,
6341 g_em->unique_identifier =
6342 (graphic << 16) | ((frame % 8) << 12) | (g_em->width << 6) | g_em->height;
6346 void getGraphicSourceObjectExt_EM(struct GraphicInfo_EM *g_em,
6347 int tile, int frame_em, int x, int y)
6349 int action = object_mapping[tile].action;
6350 int direction = object_mapping[tile].direction;
6351 boolean is_backside = object_mapping[tile].is_backside;
6352 int effective_element = get_effective_element_EM(tile, frame_em);
6354 int effective_action = action;
6356 int effective_action = (frame_em < 7 ? action : ACTION_DEFAULT);
6358 int graphic = (direction == MV_NONE ?
6359 el_act2img(effective_element, effective_action) :
6360 el_act_dir2img(effective_element, effective_action,
6362 int crumbled = (direction == MV_NONE ?
6363 el_act2crm(effective_element, effective_action) :
6364 el_act_dir2crm(effective_element, effective_action,
6366 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
6367 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
6368 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
6369 struct GraphicInfo *g = &graphic_info[graphic];
6371 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
6375 /* special case: graphic uses "2nd movement tile" and has defined
6376 7 frames for movement animation (or less) => use default graphic
6377 for last (8th) frame which ends the movement animation */
6378 if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
6380 effective_action = ACTION_DEFAULT;
6381 graphic = (direction == MV_NONE ?
6382 el_act2img(effective_element, effective_action) :
6383 el_act_dir2img(effective_element, effective_action,
6385 crumbled = (direction == MV_NONE ?
6386 el_act2crm(effective_element, effective_action) :
6387 el_act_dir2crm(effective_element, effective_action,
6390 g = &graphic_info[graphic];
6400 if (frame_em == 0) /* reset animation frame for certain elements */
6402 if (check_linear_animation_EM(tile))
6407 if (graphic_info[graphic].anim_global_sync)
6408 sync_frame = FrameCounter;
6409 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
6410 sync_frame = GfxFrame[x][y];
6412 sync_frame = 0; /* playfield border (pseudo steel) */
6414 SetRandomAnimationValue(x, y);
6419 int xxx_sync_frame = (i == Xdrip_stretch ? 7 :
6420 i == Xdrip_stretchB ? 7 :
6421 i == Ydrip_s2 ? j + 8 :
6422 i == Ydrip_s2B ? j + 8 :
6431 i == Xfake_acid_1 ? 0 :
6432 i == Xfake_acid_2 ? 10 :
6433 i == Xfake_acid_3 ? 20 :
6434 i == Xfake_acid_4 ? 30 :
6435 i == Xfake_acid_5 ? 40 :
6436 i == Xfake_acid_6 ? 50 :
6437 i == Xfake_acid_7 ? 60 :
6438 i == Xfake_acid_8 ? 70 :
6440 i == Xball_2B ? j + 8 :
6441 i == Yball_eat ? j + 1 :
6442 i == Ykey_1_eat ? j + 1 :
6443 i == Ykey_2_eat ? j + 1 :
6444 i == Ykey_3_eat ? j + 1 :
6445 i == Ykey_4_eat ? j + 1 :
6446 i == Ykey_5_eat ? j + 1 :
6447 i == Ykey_6_eat ? j + 1 :
6448 i == Ykey_7_eat ? j + 1 :
6449 i == Ykey_8_eat ? j + 1 :
6450 i == Ylenses_eat ? j + 1 :
6451 i == Ymagnify_eat ? j + 1 :
6452 i == Ygrass_eat ? j + 1 :
6453 i == Ydirt_eat ? j + 1 :
6454 i == Xamoeba_1 ? 0 :
6455 i == Xamoeba_2 ? 1 :
6456 i == Xamoeba_3 ? 2 :
6457 i == Xamoeba_4 ? 3 :
6458 i == Xamoeba_5 ? 0 :
6459 i == Xamoeba_6 ? 1 :
6460 i == Xamoeba_7 ? 2 :
6461 i == Xamoeba_8 ? 3 :
6462 i == Xexit_2 ? j + 8 :
6463 i == Xexit_3 ? j + 16 :
6464 i == Xdynamite_1 ? 0 :
6465 i == Xdynamite_2 ? 8 :
6466 i == Xdynamite_3 ? 16 :
6467 i == Xdynamite_4 ? 24 :
6468 i == Xsand_stonein_1 ? j + 1 :
6469 i == Xsand_stonein_2 ? j + 9 :
6470 i == Xsand_stonein_3 ? j + 17 :
6471 i == Xsand_stonein_4 ? j + 25 :
6472 i == Xsand_stoneout_1 && j == 0 ? 0 :
6473 i == Xsand_stoneout_1 && j == 1 ? 0 :
6474 i == Xsand_stoneout_1 && j == 2 ? 1 :
6475 i == Xsand_stoneout_1 && j == 3 ? 2 :
6476 i == Xsand_stoneout_1 && j == 4 ? 2 :
6477 i == Xsand_stoneout_1 && j == 5 ? 3 :
6478 i == Xsand_stoneout_1 && j == 6 ? 4 :
6479 i == Xsand_stoneout_1 && j == 7 ? 4 :
6480 i == Xsand_stoneout_2 && j == 0 ? 5 :
6481 i == Xsand_stoneout_2 && j == 1 ? 6 :
6482 i == Xsand_stoneout_2 && j == 2 ? 7 :
6483 i == Xsand_stoneout_2 && j == 3 ? 8 :
6484 i == Xsand_stoneout_2 && j == 4 ? 9 :
6485 i == Xsand_stoneout_2 && j == 5 ? 11 :
6486 i == Xsand_stoneout_2 && j == 6 ? 13 :
6487 i == Xsand_stoneout_2 && j == 7 ? 15 :
6488 i == Xboom_bug && j == 1 ? 2 :
6489 i == Xboom_bug && j == 2 ? 2 :
6490 i == Xboom_bug && j == 3 ? 4 :
6491 i == Xboom_bug && j == 4 ? 4 :
6492 i == Xboom_bug && j == 5 ? 2 :
6493 i == Xboom_bug && j == 6 ? 2 :
6494 i == Xboom_bug && j == 7 ? 0 :
6495 i == Xboom_bomb && j == 1 ? 2 :
6496 i == Xboom_bomb && j == 2 ? 2 :
6497 i == Xboom_bomb && j == 3 ? 4 :
6498 i == Xboom_bomb && j == 4 ? 4 :
6499 i == Xboom_bomb && j == 5 ? 2 :
6500 i == Xboom_bomb && j == 6 ? 2 :
6501 i == Xboom_bomb && j == 7 ? 0 :
6502 i == Xboom_android && j == 7 ? 6 :
6503 i == Xboom_1 && j == 1 ? 2 :
6504 i == Xboom_1 && j == 2 ? 2 :
6505 i == Xboom_1 && j == 3 ? 4 :
6506 i == Xboom_1 && j == 4 ? 4 :
6507 i == Xboom_1 && j == 5 ? 6 :
6508 i == Xboom_1 && j == 6 ? 6 :
6509 i == Xboom_1 && j == 7 ? 8 :
6510 i == Xboom_2 && j == 0 ? 8 :
6511 i == Xboom_2 && j == 1 ? 8 :
6512 i == Xboom_2 && j == 2 ? 10 :
6513 i == Xboom_2 && j == 3 ? 10 :
6514 i == Xboom_2 && j == 4 ? 10 :
6515 i == Xboom_2 && j == 5 ? 12 :
6516 i == Xboom_2 && j == 6 ? 12 :
6517 i == Xboom_2 && j == 7 ? 12 :
6519 special_animation && j == 4 ? 3 :
6520 effective_action != action ? 0 :
6526 int xxx_effective_action;
6527 int xxx_has_action_graphics;
6530 int element = object_mapping[i].element_rnd;
6531 int action = object_mapping[i].action;
6532 int direction = object_mapping[i].direction;
6533 boolean is_backside = object_mapping[i].is_backside;
6535 boolean action_removing = (action == ACTION_DIGGING ||
6536 action == ACTION_SNAPPING ||
6537 action == ACTION_COLLECTING);
6539 boolean action_exploding = ((action == ACTION_EXPLODING ||
6540 action == ACTION_SMASHED_BY_ROCK ||
6541 action == ACTION_SMASHED_BY_SPRING) &&
6542 element != EL_DIAMOND);
6543 boolean action_active = (action == ACTION_ACTIVE);
6544 boolean action_other = (action == ACTION_OTHER);
6548 int effective_element = get_effective_element_EM(i, j);
6550 int effective_element = (j > 5 && i == Yacid_splash_eB ? EL_EMPTY :
6551 j > 5 && i == Yacid_splash_wB ? EL_EMPTY :
6553 i == Xdrip_stretch ? element :
6554 i == Xdrip_stretchB ? element :
6555 i == Ydrip_s1 ? element :
6556 i == Ydrip_s1B ? element :
6557 i == Xball_1B ? element :
6558 i == Xball_2 ? element :
6559 i == Xball_2B ? element :
6560 i == Yball_eat ? element :
6561 i == Ykey_1_eat ? element :
6562 i == Ykey_2_eat ? element :
6563 i == Ykey_3_eat ? element :
6564 i == Ykey_4_eat ? element :
6565 i == Ykey_5_eat ? element :
6566 i == Ykey_6_eat ? element :
6567 i == Ykey_7_eat ? element :
6568 i == Ykey_8_eat ? element :
6569 i == Ylenses_eat ? element :
6570 i == Ymagnify_eat ? element :
6571 i == Ygrass_eat ? element :
6572 i == Ydirt_eat ? element :
6573 i == Yemerald_stone ? EL_EMERALD :
6574 i == Ydiamond_stone ? EL_ROCK :
6575 i == Xsand_stonein_1 ? element :
6576 i == Xsand_stonein_2 ? element :
6577 i == Xsand_stonein_3 ? element :
6578 i == Xsand_stonein_4 ? element :
6579 is_backside ? EL_EMPTY :
6580 action_removing ? EL_EMPTY :
6583 int effective_action = (j < 7 ? action :
6584 i == Xdrip_stretch ? action :
6585 i == Xdrip_stretchB ? action :
6586 i == Ydrip_s1 ? action :
6587 i == Ydrip_s1B ? action :
6588 i == Xball_1B ? action :
6589 i == Xball_2 ? action :
6590 i == Xball_2B ? action :
6591 i == Yball_eat ? action :
6592 i == Ykey_1_eat ? action :
6593 i == Ykey_2_eat ? action :
6594 i == Ykey_3_eat ? action :
6595 i == Ykey_4_eat ? action :
6596 i == Ykey_5_eat ? action :
6597 i == Ykey_6_eat ? action :
6598 i == Ykey_7_eat ? action :
6599 i == Ykey_8_eat ? action :
6600 i == Ylenses_eat ? action :
6601 i == Ymagnify_eat ? action :
6602 i == Ygrass_eat ? action :
6603 i == Ydirt_eat ? action :
6604 i == Xsand_stonein_1 ? action :
6605 i == Xsand_stonein_2 ? action :
6606 i == Xsand_stonein_3 ? action :
6607 i == Xsand_stonein_4 ? action :
6608 i == Xsand_stoneout_1 ? action :
6609 i == Xsand_stoneout_2 ? action :
6610 i == Xboom_android ? ACTION_EXPLODING :
6611 action_exploding ? ACTION_EXPLODING :
6612 action_active ? action :
6613 action_other ? action :
6615 int graphic = (el_act_dir2img(effective_element, effective_action,
6617 int crumbled = (el_act_dir2crm(effective_element, effective_action,
6619 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
6620 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
6621 boolean has_action_graphics = (graphic != base_graphic);
6622 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
6623 struct GraphicInfo *g = &graphic_info[graphic];
6625 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
6627 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
6630 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
6631 boolean special_animation = (action != ACTION_DEFAULT &&
6632 g->anim_frames == 3 &&
6633 g->anim_delay == 2 &&
6634 g->anim_mode & ANIM_LINEAR);
6635 xxx_sync_frame = (i == Xdrip_stretch ? 7 :
6636 i == Xdrip_stretchB ? 7 :
6637 i == Ydrip_s2 ? j + 8 :
6638 i == Ydrip_s2B ? j + 8 :
6647 i == Xfake_acid_1 ? 0 :
6648 i == Xfake_acid_2 ? 10 :
6649 i == Xfake_acid_3 ? 20 :
6650 i == Xfake_acid_4 ? 30 :
6651 i == Xfake_acid_5 ? 40 :
6652 i == Xfake_acid_6 ? 50 :
6653 i == Xfake_acid_7 ? 60 :
6654 i == Xfake_acid_8 ? 70 :
6656 i == Xball_2B ? j + 8 :
6657 i == Yball_eat ? j + 1 :
6658 i == Ykey_1_eat ? j + 1 :
6659 i == Ykey_2_eat ? j + 1 :
6660 i == Ykey_3_eat ? j + 1 :
6661 i == Ykey_4_eat ? j + 1 :
6662 i == Ykey_5_eat ? j + 1 :
6663 i == Ykey_6_eat ? j + 1 :
6664 i == Ykey_7_eat ? j + 1 :
6665 i == Ykey_8_eat ? j + 1 :
6666 i == Ylenses_eat ? j + 1 :
6667 i == Ymagnify_eat ? j + 1 :
6668 i == Ygrass_eat ? j + 1 :
6669 i == Ydirt_eat ? j + 1 :
6670 i == Xamoeba_1 ? 0 :
6671 i == Xamoeba_2 ? 1 :
6672 i == Xamoeba_3 ? 2 :
6673 i == Xamoeba_4 ? 3 :
6674 i == Xamoeba_5 ? 0 :
6675 i == Xamoeba_6 ? 1 :
6676 i == Xamoeba_7 ? 2 :
6677 i == Xamoeba_8 ? 3 :
6678 i == Xexit_2 ? j + 8 :
6679 i == Xexit_3 ? j + 16 :
6680 i == Xdynamite_1 ? 0 :
6681 i == Xdynamite_2 ? 8 :
6682 i == Xdynamite_3 ? 16 :
6683 i == Xdynamite_4 ? 24 :
6684 i == Xsand_stonein_1 ? j + 1 :
6685 i == Xsand_stonein_2 ? j + 9 :
6686 i == Xsand_stonein_3 ? j + 17 :
6687 i == Xsand_stonein_4 ? j + 25 :
6688 i == Xsand_stoneout_1 && j == 0 ? 0 :
6689 i == Xsand_stoneout_1 && j == 1 ? 0 :
6690 i == Xsand_stoneout_1 && j == 2 ? 1 :
6691 i == Xsand_stoneout_1 && j == 3 ? 2 :
6692 i == Xsand_stoneout_1 && j == 4 ? 2 :
6693 i == Xsand_stoneout_1 && j == 5 ? 3 :
6694 i == Xsand_stoneout_1 && j == 6 ? 4 :
6695 i == Xsand_stoneout_1 && j == 7 ? 4 :
6696 i == Xsand_stoneout_2 && j == 0 ? 5 :
6697 i == Xsand_stoneout_2 && j == 1 ? 6 :
6698 i == Xsand_stoneout_2 && j == 2 ? 7 :
6699 i == Xsand_stoneout_2 && j == 3 ? 8 :
6700 i == Xsand_stoneout_2 && j == 4 ? 9 :
6701 i == Xsand_stoneout_2 && j == 5 ? 11 :
6702 i == Xsand_stoneout_2 && j == 6 ? 13 :
6703 i == Xsand_stoneout_2 && j == 7 ? 15 :
6704 i == Xboom_bug && j == 1 ? 2 :
6705 i == Xboom_bug && j == 2 ? 2 :
6706 i == Xboom_bug && j == 3 ? 4 :
6707 i == Xboom_bug && j == 4 ? 4 :
6708 i == Xboom_bug && j == 5 ? 2 :
6709 i == Xboom_bug && j == 6 ? 2 :
6710 i == Xboom_bug && j == 7 ? 0 :
6711 i == Xboom_bomb && j == 1 ? 2 :
6712 i == Xboom_bomb && j == 2 ? 2 :
6713 i == Xboom_bomb && j == 3 ? 4 :
6714 i == Xboom_bomb && j == 4 ? 4 :
6715 i == Xboom_bomb && j == 5 ? 2 :
6716 i == Xboom_bomb && j == 6 ? 2 :
6717 i == Xboom_bomb && j == 7 ? 0 :
6718 i == Xboom_android && j == 7 ? 6 :
6719 i == Xboom_1 && j == 1 ? 2 :
6720 i == Xboom_1 && j == 2 ? 2 :
6721 i == Xboom_1 && j == 3 ? 4 :
6722 i == Xboom_1 && j == 4 ? 4 :
6723 i == Xboom_1 && j == 5 ? 6 :
6724 i == Xboom_1 && j == 6 ? 6 :
6725 i == Xboom_1 && j == 7 ? 8 :
6726 i == Xboom_2 && j == 0 ? 8 :
6727 i == Xboom_2 && j == 1 ? 8 :
6728 i == Xboom_2 && j == 2 ? 10 :
6729 i == Xboom_2 && j == 3 ? 10 :
6730 i == Xboom_2 && j == 4 ? 10 :
6731 i == Xboom_2 && j == 5 ? 12 :
6732 i == Xboom_2 && j == 6 ? 12 :
6733 i == Xboom_2 && j == 7 ? 12 :
6734 special_animation && j == 4 ? 3 :
6735 effective_action != action ? 0 :
6738 xxx_effective_action = effective_action;
6739 xxx_has_action_graphics = has_action_graphics;
6744 int frame = getAnimationFrame(g->anim_frames,
6747 g->anim_start_frame,
6761 int old_src_x = g_em->src_x;
6762 int old_src_y = g_em->src_y;
6766 getGraphicSourceExt(graphic, frame, &g_em->bitmap, &g_em->src_x, &g_em->src_y,
6767 g->double_movement && is_backside);
6769 getGraphicSourceExt(graphic, frame, &g_em->bitmap,
6770 &g_em->src_x, &g_em->src_y, FALSE);
6781 if (graphic == IMG_BUG_MOVING_RIGHT)
6782 printf("::: %d, %d, %d: %d, %d [%d, %d -> %d, %d]\n", graphic, x, y,
6783 g->double_movement, is_backside,
6784 old_src_x, old_src_y, g_em->src_x, g_em->src_y);
6792 g_em->src_offset_x = 0;
6793 g_em->src_offset_y = 0;
6794 g_em->dst_offset_x = 0;
6795 g_em->dst_offset_y = 0;
6796 g_em->width = TILEX;
6797 g_em->height = TILEY;
6799 g_em->preserve_background = FALSE;
6802 /* (updating the "crumbled" graphic definitions is probably not really needed,
6803 as animations for crumbled graphics can't be longer than one EMC cycle) */
6805 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
6810 g_em->crumbled_bitmap = NULL;
6811 g_em->crumbled_src_x = 0;
6812 g_em->crumbled_src_y = 0;
6814 g_em->has_crumbled_graphics = FALSE;
6816 if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
6818 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
6819 g_crumbled->anim_delay,
6820 g_crumbled->anim_mode,
6821 g_crumbled->anim_start_frame,
6824 getGraphicSource(crumbled, frame_crumbled, &g_em->crumbled_bitmap,
6825 &g_em->crumbled_src_x, &g_em->crumbled_src_y);
6827 g_em->has_crumbled_graphics = TRUE;
6833 int effective_action = xxx_effective_action;
6834 int has_action_graphics = xxx_has_action_graphics;
6836 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
6837 effective_action == ACTION_MOVING ||
6838 effective_action == ACTION_PUSHING ||
6839 effective_action == ACTION_EATING)) ||
6840 (!has_action_graphics && (effective_action == ACTION_FILLING ||
6841 effective_action == ACTION_EMPTYING)))
6844 (effective_action == ACTION_FALLING ||
6845 effective_action == ACTION_FILLING ||
6846 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
6847 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
6848 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
6849 int num_steps = (i == Ydrip_s1 ? 16 :
6850 i == Ydrip_s1B ? 16 :
6851 i == Ydrip_s2 ? 16 :
6852 i == Ydrip_s2B ? 16 :
6853 i == Xsand_stonein_1 ? 32 :
6854 i == Xsand_stonein_2 ? 32 :
6855 i == Xsand_stonein_3 ? 32 :
6856 i == Xsand_stonein_4 ? 32 :
6857 i == Xsand_stoneout_1 ? 16 :
6858 i == Xsand_stoneout_2 ? 16 : 8);
6859 int cx = ABS(dx) * (TILEX / num_steps);
6860 int cy = ABS(dy) * (TILEY / num_steps);
6861 int step_frame = (i == Ydrip_s2 ? j + 8 :
6862 i == Ydrip_s2B ? j + 8 :
6863 i == Xsand_stonein_2 ? j + 8 :
6864 i == Xsand_stonein_3 ? j + 16 :
6865 i == Xsand_stonein_4 ? j + 24 :
6866 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
6867 int step = (is_backside ? step_frame : num_steps - step_frame);
6869 if (is_backside) /* tile where movement starts */
6871 if (dx < 0 || dy < 0)
6873 g_em->src_offset_x = cx * step;
6874 g_em->src_offset_y = cy * step;
6878 g_em->dst_offset_x = cx * step;
6879 g_em->dst_offset_y = cy * step;
6882 else /* tile where movement ends */
6884 if (dx < 0 || dy < 0)
6886 g_em->dst_offset_x = cx * step;
6887 g_em->dst_offset_y = cy * step;
6891 g_em->src_offset_x = cx * step;
6892 g_em->src_offset_y = cy * step;
6896 g_em->width = TILEX - cx * step;
6897 g_em->height = TILEY - cy * step;
6900 /* create unique graphic identifier to decide if tile must be redrawn */
6901 /* bit 31 - 16 (16 bit): EM style graphic
6902 bit 15 - 12 ( 4 bit): EM style frame
6903 bit 11 - 6 ( 6 bit): graphic width
6904 bit 5 - 0 ( 6 bit): graphic height */
6905 g_em->unique_identifier =
6906 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
6912 void getGraphicSourcePlayerExt_EM(struct GraphicInfo_EM *g_em,
6913 int player_nr, int anim, int frame_em)
6915 int element = player_mapping[player_nr][anim].element_rnd;
6916 int action = player_mapping[player_nr][anim].action;
6917 int direction = player_mapping[player_nr][anim].direction;
6918 int graphic = (direction == MV_NONE ?
6919 el_act2img(element, action) :
6920 el_act_dir2img(element, action, direction));
6921 struct GraphicInfo *g = &graphic_info[graphic];
6924 InitPlayerGfxAnimation(&stored_player[player_nr], action, direction);
6926 stored_player[player_nr].StepFrame = frame_em;
6928 sync_frame = stored_player[player_nr].Frame;
6930 int frame = getAnimationFrame(g->anim_frames,
6933 g->anim_start_frame,
6936 getGraphicSourceExt(graphic, frame, &g_em->bitmap,
6937 &g_em->src_x, &g_em->src_y, FALSE);
6940 printf("::: %d: %d, %d [%d]\n",
6942 stored_player[player_nr].Frame,
6943 stored_player[player_nr].StepFrame,
6948 void InitGraphicInfo_EM(void)
6951 struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
6952 struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
6957 int num_em_gfx_errors = 0;
6959 if (graphic_info_em_object[0][0].bitmap == NULL)
6961 /* EM graphics not yet initialized in em_open_all() */
6966 printf("::: [4 errors can be ignored (1 x 'bomb', 3 x 'em_dynamite']\n");
6969 /* always start with reliable default values */
6970 for (i = 0; i < TILE_MAX; i++)
6972 object_mapping[i].element_rnd = EL_UNKNOWN;
6973 object_mapping[i].is_backside = FALSE;
6974 object_mapping[i].action = ACTION_DEFAULT;
6975 object_mapping[i].direction = MV_NONE;
6978 /* always start with reliable default values */
6979 for (p = 0; p < MAX_PLAYERS; p++)
6981 for (i = 0; i < SPR_MAX; i++)
6983 player_mapping[p][i].element_rnd = EL_UNKNOWN;
6984 player_mapping[p][i].action = ACTION_DEFAULT;
6985 player_mapping[p][i].direction = MV_NONE;
6989 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
6991 int e = em_object_mapping_list[i].element_em;
6993 object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd;
6994 object_mapping[e].is_backside = em_object_mapping_list[i].is_backside;
6996 if (em_object_mapping_list[i].action != -1)
6997 object_mapping[e].action = em_object_mapping_list[i].action;
6999 if (em_object_mapping_list[i].direction != -1)
7000 object_mapping[e].direction =
7001 MV_DIR_FROM_BIT(em_object_mapping_list[i].direction);
7004 for (i = 0; em_player_mapping_list[i].action_em != -1; i++)
7006 int a = em_player_mapping_list[i].action_em;
7007 int p = em_player_mapping_list[i].player_nr;
7009 player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd;
7011 if (em_player_mapping_list[i].action != -1)
7012 player_mapping[p][a].action = em_player_mapping_list[i].action;
7014 if (em_player_mapping_list[i].direction != -1)
7015 player_mapping[p][a].direction =
7016 MV_DIR_FROM_BIT(em_player_mapping_list[i].direction);
7019 for (i = 0; i < TILE_MAX; i++)
7021 int element = object_mapping[i].element_rnd;
7022 int action = object_mapping[i].action;
7023 int direction = object_mapping[i].direction;
7024 boolean is_backside = object_mapping[i].is_backside;
7026 boolean action_removing = (action == ACTION_DIGGING ||
7027 action == ACTION_SNAPPING ||
7028 action == ACTION_COLLECTING);
7030 boolean action_exploding = ((action == ACTION_EXPLODING ||
7031 action == ACTION_SMASHED_BY_ROCK ||
7032 action == ACTION_SMASHED_BY_SPRING) &&
7033 element != EL_DIAMOND);
7034 boolean action_active = (action == ACTION_ACTIVE);
7035 boolean action_other = (action == ACTION_OTHER);
7037 for (j = 0; j < 8; j++)
7040 int effective_element = get_effective_element_EM(i, j);
7042 int effective_element = (j > 5 && i == Yacid_splash_eB ? EL_EMPTY :
7043 j > 5 && i == Yacid_splash_wB ? EL_EMPTY :
7045 i == Xdrip_stretch ? element :
7046 i == Xdrip_stretchB ? element :
7047 i == Ydrip_s1 ? element :
7048 i == Ydrip_s1B ? element :
7049 i == Xball_1B ? element :
7050 i == Xball_2 ? element :
7051 i == Xball_2B ? element :
7052 i == Yball_eat ? element :
7053 i == Ykey_1_eat ? element :
7054 i == Ykey_2_eat ? element :
7055 i == Ykey_3_eat ? element :
7056 i == Ykey_4_eat ? element :
7057 i == Ykey_5_eat ? element :
7058 i == Ykey_6_eat ? element :
7059 i == Ykey_7_eat ? element :
7060 i == Ykey_8_eat ? element :
7061 i == Ylenses_eat ? element :
7062 i == Ymagnify_eat ? element :
7063 i == Ygrass_eat ? element :
7064 i == Ydirt_eat ? element :
7065 i == Yemerald_stone ? EL_EMERALD :
7066 i == Ydiamond_stone ? EL_ROCK :
7067 i == Xsand_stonein_1 ? element :
7068 i == Xsand_stonein_2 ? element :
7069 i == Xsand_stonein_3 ? element :
7070 i == Xsand_stonein_4 ? element :
7071 is_backside ? EL_EMPTY :
7072 action_removing ? EL_EMPTY :
7075 int effective_action = (j < 7 ? action :
7076 i == Xdrip_stretch ? action :
7077 i == Xdrip_stretchB ? action :
7078 i == Ydrip_s1 ? action :
7079 i == Ydrip_s1B ? action :
7080 i == Xball_1B ? action :
7081 i == Xball_2 ? action :
7082 i == Xball_2B ? action :
7083 i == Yball_eat ? action :
7084 i == Ykey_1_eat ? action :
7085 i == Ykey_2_eat ? action :
7086 i == Ykey_3_eat ? action :
7087 i == Ykey_4_eat ? action :
7088 i == Ykey_5_eat ? action :
7089 i == Ykey_6_eat ? action :
7090 i == Ykey_7_eat ? action :
7091 i == Ykey_8_eat ? action :
7092 i == Ylenses_eat ? action :
7093 i == Ymagnify_eat ? action :
7094 i == Ygrass_eat ? action :
7095 i == Ydirt_eat ? action :
7096 i == Xsand_stonein_1 ? action :
7097 i == Xsand_stonein_2 ? action :
7098 i == Xsand_stonein_3 ? action :
7099 i == Xsand_stonein_4 ? action :
7100 i == Xsand_stoneout_1 ? action :
7101 i == Xsand_stoneout_2 ? action :
7102 i == Xboom_android ? ACTION_EXPLODING :
7103 action_exploding ? ACTION_EXPLODING :
7104 action_active ? action :
7105 action_other ? action :
7107 int graphic = (el_act_dir2img(effective_element, effective_action,
7109 int crumbled = (el_act_dir2crm(effective_element, effective_action,
7111 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
7112 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
7113 boolean has_action_graphics = (graphic != base_graphic);
7114 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
7115 struct GraphicInfo *g = &graphic_info[graphic];
7117 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
7119 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
7122 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
7123 boolean special_animation = (action != ACTION_DEFAULT &&
7124 g->anim_frames == 3 &&
7125 g->anim_delay == 2 &&
7126 g->anim_mode & ANIM_LINEAR);
7127 int sync_frame = (i == Xdrip_stretch ? 7 :
7128 i == Xdrip_stretchB ? 7 :
7129 i == Ydrip_s2 ? j + 8 :
7130 i == Ydrip_s2B ? j + 8 :
7139 i == Xfake_acid_1 ? 0 :
7140 i == Xfake_acid_2 ? 10 :
7141 i == Xfake_acid_3 ? 20 :
7142 i == Xfake_acid_4 ? 30 :
7143 i == Xfake_acid_5 ? 40 :
7144 i == Xfake_acid_6 ? 50 :
7145 i == Xfake_acid_7 ? 60 :
7146 i == Xfake_acid_8 ? 70 :
7148 i == Xball_2B ? j + 8 :
7149 i == Yball_eat ? j + 1 :
7150 i == Ykey_1_eat ? j + 1 :
7151 i == Ykey_2_eat ? j + 1 :
7152 i == Ykey_3_eat ? j + 1 :
7153 i == Ykey_4_eat ? j + 1 :
7154 i == Ykey_5_eat ? j + 1 :
7155 i == Ykey_6_eat ? j + 1 :
7156 i == Ykey_7_eat ? j + 1 :
7157 i == Ykey_8_eat ? j + 1 :
7158 i == Ylenses_eat ? j + 1 :
7159 i == Ymagnify_eat ? j + 1 :
7160 i == Ygrass_eat ? j + 1 :
7161 i == Ydirt_eat ? j + 1 :
7162 i == Xamoeba_1 ? 0 :
7163 i == Xamoeba_2 ? 1 :
7164 i == Xamoeba_3 ? 2 :
7165 i == Xamoeba_4 ? 3 :
7166 i == Xamoeba_5 ? 0 :
7167 i == Xamoeba_6 ? 1 :
7168 i == Xamoeba_7 ? 2 :
7169 i == Xamoeba_8 ? 3 :
7170 i == Xexit_2 ? j + 8 :
7171 i == Xexit_3 ? j + 16 :
7172 i == Xdynamite_1 ? 0 :
7173 i == Xdynamite_2 ? 8 :
7174 i == Xdynamite_3 ? 16 :
7175 i == Xdynamite_4 ? 24 :
7176 i == Xsand_stonein_1 ? j + 1 :
7177 i == Xsand_stonein_2 ? j + 9 :
7178 i == Xsand_stonein_3 ? j + 17 :
7179 i == Xsand_stonein_4 ? j + 25 :
7180 i == Xsand_stoneout_1 && j == 0 ? 0 :
7181 i == Xsand_stoneout_1 && j == 1 ? 0 :
7182 i == Xsand_stoneout_1 && j == 2 ? 1 :
7183 i == Xsand_stoneout_1 && j == 3 ? 2 :
7184 i == Xsand_stoneout_1 && j == 4 ? 2 :
7185 i == Xsand_stoneout_1 && j == 5 ? 3 :
7186 i == Xsand_stoneout_1 && j == 6 ? 4 :
7187 i == Xsand_stoneout_1 && j == 7 ? 4 :
7188 i == Xsand_stoneout_2 && j == 0 ? 5 :
7189 i == Xsand_stoneout_2 && j == 1 ? 6 :
7190 i == Xsand_stoneout_2 && j == 2 ? 7 :
7191 i == Xsand_stoneout_2 && j == 3 ? 8 :
7192 i == Xsand_stoneout_2 && j == 4 ? 9 :
7193 i == Xsand_stoneout_2 && j == 5 ? 11 :
7194 i == Xsand_stoneout_2 && j == 6 ? 13 :
7195 i == Xsand_stoneout_2 && j == 7 ? 15 :
7196 i == Xboom_bug && j == 1 ? 2 :
7197 i == Xboom_bug && j == 2 ? 2 :
7198 i == Xboom_bug && j == 3 ? 4 :
7199 i == Xboom_bug && j == 4 ? 4 :
7200 i == Xboom_bug && j == 5 ? 2 :
7201 i == Xboom_bug && j == 6 ? 2 :
7202 i == Xboom_bug && j == 7 ? 0 :
7203 i == Xboom_bomb && j == 1 ? 2 :
7204 i == Xboom_bomb && j == 2 ? 2 :
7205 i == Xboom_bomb && j == 3 ? 4 :
7206 i == Xboom_bomb && j == 4 ? 4 :
7207 i == Xboom_bomb && j == 5 ? 2 :
7208 i == Xboom_bomb && j == 6 ? 2 :
7209 i == Xboom_bomb && j == 7 ? 0 :
7210 i == Xboom_android && j == 7 ? 6 :
7211 i == Xboom_1 && j == 1 ? 2 :
7212 i == Xboom_1 && j == 2 ? 2 :
7213 i == Xboom_1 && j == 3 ? 4 :
7214 i == Xboom_1 && j == 4 ? 4 :
7215 i == Xboom_1 && j == 5 ? 6 :
7216 i == Xboom_1 && j == 6 ? 6 :
7217 i == Xboom_1 && j == 7 ? 8 :
7218 i == Xboom_2 && j == 0 ? 8 :
7219 i == Xboom_2 && j == 1 ? 8 :
7220 i == Xboom_2 && j == 2 ? 10 :
7221 i == Xboom_2 && j == 3 ? 10 :
7222 i == Xboom_2 && j == 4 ? 10 :
7223 i == Xboom_2 && j == 5 ? 12 :
7224 i == Xboom_2 && j == 6 ? 12 :
7225 i == Xboom_2 && j == 7 ? 12 :
7226 special_animation && j == 4 ? 3 :
7227 effective_action != action ? 0 :
7231 Bitmap *debug_bitmap = g_em->bitmap;
7232 int debug_src_x = g_em->src_x;
7233 int debug_src_y = g_em->src_y;
7236 int frame = getAnimationFrame(g->anim_frames,
7239 g->anim_start_frame,
7242 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y,
7243 g->double_movement && is_backside);
7245 g_em->bitmap = src_bitmap;
7246 g_em->src_x = src_x;
7247 g_em->src_y = src_y;
7248 g_em->src_offset_x = 0;
7249 g_em->src_offset_y = 0;
7250 g_em->dst_offset_x = 0;
7251 g_em->dst_offset_y = 0;
7252 g_em->width = TILEX;
7253 g_em->height = TILEY;
7255 g_em->preserve_background = FALSE;
7258 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
7263 g_em->crumbled_bitmap = NULL;
7264 g_em->crumbled_src_x = 0;
7265 g_em->crumbled_src_y = 0;
7266 g_em->crumbled_border_size = 0;
7268 g_em->has_crumbled_graphics = FALSE;
7271 if (has_crumbled_graphics && crumbled == IMG_EMPTY_SPACE)
7272 printf("::: empty crumbled: %d [%s], %d, %d\n",
7273 effective_element, element_info[effective_element].token_name,
7274 effective_action, direction);
7277 /* if element can be crumbled, but certain action graphics are just empty
7278 space (like instantly snapping sand to empty space in 1 frame), do not
7279 treat these empty space graphics as crumbled graphics in EMC engine */
7280 if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
7282 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
7283 g_crumbled->anim_delay,
7284 g_crumbled->anim_mode,
7285 g_crumbled->anim_start_frame,
7288 getGraphicSource(crumbled, frame_crumbled, &src_bitmap, &src_x, &src_y);
7290 g_em->has_crumbled_graphics = TRUE;
7291 g_em->crumbled_bitmap = src_bitmap;
7292 g_em->crumbled_src_x = src_x;
7293 g_em->crumbled_src_y = src_y;
7294 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
7298 if (g_em == &graphic_info_em_object[207][0])
7299 printf("... %d, %d [%d, %d, %d, %d] [%d, %d, %d, %d, %d, %d => %d]\n",
7300 graphic_info_em_object[207][0].crumbled_src_x,
7301 graphic_info_em_object[207][0].crumbled_src_y,
7303 crumbled, frame, src_x, src_y,
7308 g->anim_start_frame,
7310 gfx.anim_random_frame,
7315 printf("::: EMC tile %d is crumbled\n", i);
7321 if (element == EL_ROCK &&
7322 effective_action == ACTION_FILLING)
7323 printf("::: has_action_graphics == %d\n", has_action_graphics);
7326 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
7327 effective_action == ACTION_MOVING ||
7328 effective_action == ACTION_PUSHING ||
7329 effective_action == ACTION_EATING)) ||
7330 (!has_action_graphics && (effective_action == ACTION_FILLING ||
7331 effective_action == ACTION_EMPTYING)))
7334 (effective_action == ACTION_FALLING ||
7335 effective_action == ACTION_FILLING ||
7336 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
7337 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
7338 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
7339 int num_steps = (i == Ydrip_s1 ? 16 :
7340 i == Ydrip_s1B ? 16 :
7341 i == Ydrip_s2 ? 16 :
7342 i == Ydrip_s2B ? 16 :
7343 i == Xsand_stonein_1 ? 32 :
7344 i == Xsand_stonein_2 ? 32 :
7345 i == Xsand_stonein_3 ? 32 :
7346 i == Xsand_stonein_4 ? 32 :
7347 i == Xsand_stoneout_1 ? 16 :
7348 i == Xsand_stoneout_2 ? 16 : 8);
7349 int cx = ABS(dx) * (TILEX / num_steps);
7350 int cy = ABS(dy) * (TILEY / num_steps);
7351 int step_frame = (i == Ydrip_s2 ? j + 8 :
7352 i == Ydrip_s2B ? j + 8 :
7353 i == Xsand_stonein_2 ? j + 8 :
7354 i == Xsand_stonein_3 ? j + 16 :
7355 i == Xsand_stonein_4 ? j + 24 :
7356 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
7357 int step = (is_backside ? step_frame : num_steps - step_frame);
7359 if (is_backside) /* tile where movement starts */
7361 if (dx < 0 || dy < 0)
7363 g_em->src_offset_x = cx * step;
7364 g_em->src_offset_y = cy * step;
7368 g_em->dst_offset_x = cx * step;
7369 g_em->dst_offset_y = cy * step;
7372 else /* tile where movement ends */
7374 if (dx < 0 || dy < 0)
7376 g_em->dst_offset_x = cx * step;
7377 g_em->dst_offset_y = cy * step;
7381 g_em->src_offset_x = cx * step;
7382 g_em->src_offset_y = cy * step;
7386 g_em->width = TILEX - cx * step;
7387 g_em->height = TILEY - cy * step;
7390 /* create unique graphic identifier to decide if tile must be redrawn */
7391 /* bit 31 - 16 (16 bit): EM style graphic
7392 bit 15 - 12 ( 4 bit): EM style frame
7393 bit 11 - 6 ( 6 bit): graphic width
7394 bit 5 - 0 ( 6 bit): graphic height */
7395 g_em->unique_identifier =
7396 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
7400 /* skip check for EMC elements not contained in original EMC artwork */
7401 if (element == EL_EMC_FAKE_ACID)
7404 if (g_em->bitmap != debug_bitmap ||
7405 g_em->src_x != debug_src_x ||
7406 g_em->src_y != debug_src_y ||
7407 g_em->src_offset_x != 0 ||
7408 g_em->src_offset_y != 0 ||
7409 g_em->dst_offset_x != 0 ||
7410 g_em->dst_offset_y != 0 ||
7411 g_em->width != TILEX ||
7412 g_em->height != TILEY)
7414 static int last_i = -1;
7422 printf("::: EMC GFX ERROR for element %d -> %d ('%s', '%s', %d)",
7423 i, element, element_info[element].token_name,
7424 element_action_info[effective_action].suffix, direction);
7426 if (element != effective_element)
7427 printf(" [%d ('%s')]",
7429 element_info[effective_element].token_name);
7433 if (g_em->bitmap != debug_bitmap)
7434 printf(" %d (%d): different bitmap! (0x%08x != 0x%08x)\n",
7435 j, is_backside, (int)(g_em->bitmap), (int)(debug_bitmap));
7437 if (g_em->src_x != debug_src_x ||
7438 g_em->src_y != debug_src_y)
7439 printf(" frame %d (%c): %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
7440 j, (is_backside ? 'B' : 'F'),
7441 g_em->src_x, g_em->src_y,
7442 g_em->src_x / 32, g_em->src_y / 32,
7443 debug_src_x, debug_src_y,
7444 debug_src_x / 32, debug_src_y / 32);
7446 if (g_em->src_offset_x != 0 ||
7447 g_em->src_offset_y != 0 ||
7448 g_em->dst_offset_x != 0 ||
7449 g_em->dst_offset_y != 0)
7450 printf(" %d (%d): offsets %d,%d and %d,%d should be all 0\n",
7452 g_em->src_offset_x, g_em->src_offset_y,
7453 g_em->dst_offset_x, g_em->dst_offset_y);
7455 if (g_em->width != TILEX ||
7456 g_em->height != TILEY)
7457 printf(" %d (%d): size %d,%d should be %d,%d\n",
7459 g_em->width, g_em->height, TILEX, TILEY);
7461 num_em_gfx_errors++;
7468 for (i = 0; i < TILE_MAX; i++)
7470 for (j = 0; j < 8; j++)
7472 int element = object_mapping[i].element_rnd;
7473 int action = object_mapping[i].action;
7474 int direction = object_mapping[i].direction;
7475 boolean is_backside = object_mapping[i].is_backside;
7476 int graphic_action = el_act_dir2img(element, action, direction);
7477 int graphic_default = el_act_dir2img(element, ACTION_DEFAULT, direction);
7479 if ((action == ACTION_SMASHED_BY_ROCK ||
7480 action == ACTION_SMASHED_BY_SPRING ||
7481 action == ACTION_EATING) &&
7482 graphic_action == graphic_default)
7484 int e = (action == ACTION_SMASHED_BY_ROCK ? Ystone_s :
7485 action == ACTION_SMASHED_BY_SPRING ? Yspring_s :
7486 direction == MV_LEFT ? (is_backside? Yspring_wB: Yspring_w) :
7487 direction == MV_RIGHT ? (is_backside? Yspring_eB: Yspring_e) :
7490 /* no separate animation for "smashed by rock" -- use rock instead */
7491 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
7492 struct GraphicInfo_EM *g_xx = &graphic_info_em_object[e][7 - j];
7494 g_em->bitmap = g_xx->bitmap;
7495 g_em->src_x = g_xx->src_x;
7496 g_em->src_y = g_xx->src_y;
7497 g_em->src_offset_x = g_xx->src_offset_x;
7498 g_em->src_offset_y = g_xx->src_offset_y;
7499 g_em->dst_offset_x = g_xx->dst_offset_x;
7500 g_em->dst_offset_y = g_xx->dst_offset_y;
7501 g_em->width = g_xx->width;
7502 g_em->height = g_xx->height;
7503 g_em->unique_identifier = g_xx->unique_identifier;
7506 g_em->preserve_background = TRUE;
7511 for (p = 0; p < MAX_PLAYERS; p++)
7513 for (i = 0; i < SPR_MAX; i++)
7515 int element = player_mapping[p][i].element_rnd;
7516 int action = player_mapping[p][i].action;
7517 int direction = player_mapping[p][i].direction;
7519 for (j = 0; j < 8; j++)
7521 int effective_element = element;
7522 int effective_action = action;
7523 int graphic = (direction == MV_NONE ?
7524 el_act2img(effective_element, effective_action) :
7525 el_act_dir2img(effective_element, effective_action,
7527 struct GraphicInfo *g = &graphic_info[graphic];
7528 struct GraphicInfo_EM *g_em = &graphic_info_em_player[p][i][7 - j];
7534 Bitmap *debug_bitmap = g_em->bitmap;
7535 int debug_src_x = g_em->src_x;
7536 int debug_src_y = g_em->src_y;
7539 int frame = getAnimationFrame(g->anim_frames,
7542 g->anim_start_frame,
7545 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
7547 g_em->bitmap = src_bitmap;
7548 g_em->src_x = src_x;
7549 g_em->src_y = src_y;
7550 g_em->src_offset_x = 0;
7551 g_em->src_offset_y = 0;
7552 g_em->dst_offset_x = 0;
7553 g_em->dst_offset_y = 0;
7554 g_em->width = TILEX;
7555 g_em->height = TILEY;
7559 /* skip check for EMC elements not contained in original EMC artwork */
7560 if (element == EL_PLAYER_3 ||
7561 element == EL_PLAYER_4)
7564 if (g_em->bitmap != debug_bitmap ||
7565 g_em->src_x != debug_src_x ||
7566 g_em->src_y != debug_src_y)
7568 static int last_i = -1;
7576 printf("::: EMC GFX ERROR for p/a %d/%d -> %d ('%s', '%s', %d)",
7577 p, i, element, element_info[element].token_name,
7578 element_action_info[effective_action].suffix, direction);
7580 if (element != effective_element)
7581 printf(" [%d ('%s')]",
7583 element_info[effective_element].token_name);
7587 if (g_em->bitmap != debug_bitmap)
7588 printf(" %d: different bitmap! (0x%08x != 0x%08x)\n",
7589 j, (int)(g_em->bitmap), (int)(debug_bitmap));
7591 if (g_em->src_x != debug_src_x ||
7592 g_em->src_y != debug_src_y)
7593 printf(" frame %d: %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
7595 g_em->src_x, g_em->src_y,
7596 g_em->src_x / 32, g_em->src_y / 32,
7597 debug_src_x, debug_src_y,
7598 debug_src_x / 32, debug_src_y / 32);
7600 num_em_gfx_errors++;
7610 printf("::: [%d errors found]\n", num_em_gfx_errors);
7616 void PlayMenuSoundExt(int sound)
7618 if (sound == SND_UNDEFINED)
7621 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
7622 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
7625 if (IS_LOOP_SOUND(sound))
7626 PlaySoundLoop(sound);
7631 void PlayMenuSound()
7633 PlayMenuSoundExt(menu.sound[game_status]);
7636 void PlayMenuSoundStereo(int sound, int stereo_position)
7638 if (sound == SND_UNDEFINED)
7641 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
7642 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
7645 if (IS_LOOP_SOUND(sound))
7646 PlaySoundExt(sound, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_LOOP);
7648 PlaySoundStereo(sound, stereo_position);
7651 void PlayMenuSoundIfLoopExt(int sound)
7653 if (sound == SND_UNDEFINED)
7656 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
7657 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
7660 if (IS_LOOP_SOUND(sound))
7661 PlaySoundLoop(sound);
7664 void PlayMenuSoundIfLoop()
7666 PlayMenuSoundIfLoopExt(menu.sound[game_status]);
7669 void PlayMenuMusicExt(int music)
7671 if (music == MUS_UNDEFINED)
7674 if (!setup.sound_music)
7680 void PlayMenuMusic()
7682 PlayMenuMusicExt(menu.music[game_status]);
7685 void PlaySoundActivating()
7688 PlaySound(SND_MENU_ITEM_ACTIVATING);
7692 void PlaySoundSelecting()
7695 PlaySound(SND_MENU_ITEM_SELECTING);
7699 void ToggleFullscreenIfNeeded()
7701 boolean change_fullscreen = (setup.fullscreen !=
7702 video.fullscreen_enabled);
7703 boolean change_fullscreen_mode = (video.fullscreen_enabled &&
7704 !strEqual(setup.fullscreen_mode,
7705 video.fullscreen_mode_current));
7707 if (!video.fullscreen_available)
7711 if (change_fullscreen || change_fullscreen_mode)
7713 if (setup.fullscreen != video.fullscreen_enabled ||
7714 setup.fullscreen_mode != video.fullscreen_mode_current)
7717 Bitmap *tmp_backbuffer = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
7719 /* save backbuffer content which gets lost when toggling fullscreen mode */
7720 BlitBitmap(backbuffer, tmp_backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
7723 if (change_fullscreen_mode)
7725 if (setup.fullscreen && video.fullscreen_enabled)
7728 /* keep fullscreen, but change fullscreen mode (screen resolution) */
7730 /* (this is now set in sdl.c) */
7732 video.fullscreen_mode_current = setup.fullscreen_mode;
7734 video.fullscreen_enabled = FALSE; /* force new fullscreen mode */
7737 /* toggle fullscreen */
7738 ChangeVideoModeIfNeeded(setup.fullscreen);
7740 setup.fullscreen = video.fullscreen_enabled;
7742 /* restore backbuffer content from temporary backbuffer backup bitmap */
7743 BlitBitmap(tmp_backbuffer, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
7745 FreeBitmap(tmp_backbuffer);
7748 /* update visible window/screen */
7749 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
7751 redraw_mask = REDRAW_ALL;