1 /***********************************************************
2 * Rocks'n'Diamonds -- McDuffin Strikes Back! *
3 *----------------------------------------------------------*
4 * (c) 1995-2006 Artsoft Entertainment *
6 * Detmolder Strasse 189 *
9 * e-mail: info@artsoft.org *
10 *----------------------------------------------------------*
12 ***********************************************************/
14 #include "libgame/libgame.h"
25 /* select level set with EMC X11 graphics before activating EM GFX debugging */
26 #define DEBUG_EM_GFX 0
28 /* tool button identifiers */
29 #define TOOL_CTRL_ID_YES 0
30 #define TOOL_CTRL_ID_NO 1
31 #define TOOL_CTRL_ID_CONFIRM 2
32 #define TOOL_CTRL_ID_PLAYER_1 3
33 #define TOOL_CTRL_ID_PLAYER_2 4
34 #define TOOL_CTRL_ID_PLAYER_3 5
35 #define TOOL_CTRL_ID_PLAYER_4 6
37 #define NUM_TOOL_BUTTONS 7
39 /* forward declaration for internal use */
40 static void UnmapToolButtons();
41 static void HandleToolButtons(struct GadgetInfo *);
42 static int el_act_dir2crm(int, int, int);
43 static int el_act2crm(int, int);
45 static struct GadgetInfo *tool_gadget[NUM_TOOL_BUTTONS];
46 static int request_gadget_id = -1;
48 static char *print_if_not_empty(int element)
50 static char *s = NULL;
51 char *token_name = element_info[element].token_name;
56 s = checked_malloc(strlen(token_name) + 10 + 1);
58 if (element != EL_EMPTY)
59 sprintf(s, "%d\t['%s']", element, token_name);
61 sprintf(s, "%d", element);
66 void DumpTile(int x, int y)
71 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
78 printf("Field Info: SCREEN(%d, %d), LEVEL(%d, %d)\n", sx, sy, x, y);
81 if (!IN_LEV_FIELD(x, y))
83 printf("(not in level field)\n");
89 printf(" Feld: %d\t['%s']\n", Feld[x][y],
90 element_info[Feld[x][y]].token_name);
91 printf(" Back: %s\n", print_if_not_empty(Back[x][y]));
92 printf(" Store: %s\n", print_if_not_empty(Store[x][y]));
93 printf(" Store2: %s\n", print_if_not_empty(Store2[x][y]));
94 printf(" StorePlayer: %s\n", print_if_not_empty(StorePlayer[x][y]));
95 printf(" MovPos: %d\n", MovPos[x][y]);
96 printf(" MovDir: %d\n", MovDir[x][y]);
97 printf(" MovDelay: %d\n", MovDelay[x][y]);
98 printf(" ChangeDelay: %d\n", ChangeDelay[x][y]);
99 printf(" CustomValue: %d\n", CustomValue[x][y]);
100 printf(" GfxElement: %d\n", GfxElement[x][y]);
101 printf(" GfxAction: %d\n", GfxAction[x][y]);
102 printf(" GfxFrame: %d\n", GfxFrame[x][y]);
106 void SetDrawtoField(int mode)
108 if (mode == DRAW_BUFFERED && setup.soft_scrolling)
119 drawto_field = fieldbuffer;
121 else /* DRAW_BACKBUFFER */
127 BX2 = SCR_FIELDX - 1;
128 BY2 = SCR_FIELDY - 1;
132 drawto_field = backbuffer;
136 void RedrawPlayfield(boolean force_redraw, int x, int y, int width, int height)
138 if (game_status == GAME_MODE_PLAYING &&
139 level.game_engine_type == GAME_ENGINE_TYPE_EM)
141 /* currently there is no partial redraw -- always redraw whole playfield */
142 RedrawPlayfield_EM(TRUE);
144 /* blit playfield from scroll buffer to normal back buffer for fading in */
145 BlitScreenToBitmap_EM(backbuffer);
147 else if (game_status == GAME_MODE_PLAYING && !game.envelope_active)
153 width = gfx.sxsize + 2 * TILEX;
154 height = gfx.sysize + 2 * TILEY;
160 int x1 = (x - SX) / TILEX, y1 = (y - SY) / TILEY;
161 int x2 = (x - SX + width) / TILEX, y2 = (y - SY + height) / TILEY;
163 for (xx = BX1; xx <= BX2; xx++)
164 for (yy = BY1; yy <= BY2; yy++)
165 if (xx >= x1 && xx <= x2 && yy >= y1 && yy <= y2)
166 DrawScreenField(xx, yy);
170 if (setup.soft_scrolling)
172 int fx = FX, fy = FY;
174 fx += (ScreenMovDir & (MV_LEFT|MV_RIGHT) ? ScreenGfxPos : 0);
175 fy += (ScreenMovDir & (MV_UP|MV_DOWN) ? ScreenGfxPos : 0);
177 BlitBitmap(fieldbuffer, backbuffer, fx,fy, SXSIZE,SYSIZE, SX,SY);
189 BlitBitmap(drawto, window, x, y, width, height, x, y);
192 void DrawMaskedBorder_Rect(int x, int y, int width, int height)
194 Bitmap *bitmap = graphic_info[IMG_GLOBAL_BORDER].bitmap;
196 SetClipOrigin(bitmap, bitmap->stored_clip_gc, 0, 0);
197 BlitBitmapMasked(bitmap, backbuffer, x, y, width, height, x, y);
200 void DrawMaskedBorder_FIELD()
202 if (global.border_status >= GAME_MODE_TITLE &&
203 global.border_status <= GAME_MODE_PLAYING &&
204 border.draw_masked[global.border_status])
205 DrawMaskedBorder_Rect(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
208 void DrawMaskedBorder_DOOR_1()
210 if (border.draw_masked[GFX_SPECIAL_ARG_DOOR] &&
211 (global.border_status != GAME_MODE_EDITOR ||
212 border.draw_masked[GFX_SPECIAL_ARG_EDITOR]))
213 DrawMaskedBorder_Rect(DX, DY, DXSIZE, DYSIZE);
216 void DrawMaskedBorder_DOOR_2()
218 if (border.draw_masked[GFX_SPECIAL_ARG_DOOR] &&
219 global.border_status != GAME_MODE_EDITOR)
220 DrawMaskedBorder_Rect(VX, VY, VXSIZE, VYSIZE);
223 void DrawMaskedBorder_DOOR_3()
225 /* currently not available */
228 void DrawMaskedBorder_ALL()
230 DrawMaskedBorder_FIELD();
231 DrawMaskedBorder_DOOR_1();
232 DrawMaskedBorder_DOOR_2();
233 DrawMaskedBorder_DOOR_3();
236 void DrawMaskedBorder(int redraw_mask)
238 /* never draw masked screen borders on borderless screens */
239 if (effectiveGameStatus() == GAME_MODE_LOADING ||
240 effectiveGameStatus() == GAME_MODE_TITLE)
243 if (redraw_mask & REDRAW_ALL)
244 DrawMaskedBorder_ALL();
247 if (redraw_mask & REDRAW_FIELD)
248 DrawMaskedBorder_FIELD();
249 if (redraw_mask & REDRAW_DOOR_1)
250 DrawMaskedBorder_DOOR_1();
251 if (redraw_mask & REDRAW_DOOR_2)
252 DrawMaskedBorder_DOOR_2();
253 if (redraw_mask & REDRAW_DOOR_3)
254 DrawMaskedBorder_DOOR_3();
261 DrawBuffer *buffer = (drawto_field == window ? backbuffer : drawto_field);
263 if (redraw_mask & REDRAW_TILES && redraw_tiles > REDRAWTILES_THRESHOLD)
264 redraw_mask |= REDRAW_FIELD;
266 if (redraw_mask & REDRAW_FIELD)
267 redraw_mask &= ~REDRAW_TILES;
269 if (redraw_mask == REDRAW_NONE)
272 if (redraw_mask & REDRAW_TILES &&
273 game_status == GAME_MODE_PLAYING &&
274 border.draw_masked[GAME_MODE_PLAYING])
275 redraw_mask |= REDRAW_FIELD;
277 if (global.fps_slowdown && game_status == GAME_MODE_PLAYING)
279 static boolean last_frame_skipped = FALSE;
280 boolean skip_even_when_not_scrolling = TRUE;
281 boolean just_scrolling = (ScreenMovDir != 0);
282 boolean verbose = FALSE;
284 if (global.fps_slowdown_factor > 1 &&
285 (FrameCounter % global.fps_slowdown_factor) &&
286 (just_scrolling || skip_even_when_not_scrolling))
288 redraw_mask &= ~REDRAW_MAIN;
290 last_frame_skipped = TRUE;
293 printf("FRAME SKIPPED\n");
297 if (last_frame_skipped)
298 redraw_mask |= REDRAW_FIELD;
300 last_frame_skipped = FALSE;
303 printf("frame not skipped\n");
307 /* synchronize X11 graphics at this point; if we would synchronize the
308 display immediately after the buffer switching (after the XFlush),
309 this could mean that we have to wait for the graphics to complete,
310 although we could go on doing calculations for the next frame */
314 /* prevent drawing masked border to backbuffer when using playfield buffer */
315 if (game_status != GAME_MODE_PLAYING ||
316 redraw_mask & REDRAW_FROM_BACKBUFFER ||
317 buffer == backbuffer)
318 DrawMaskedBorder(redraw_mask);
320 DrawMaskedBorder(redraw_mask & REDRAW_DOORS);
322 if (redraw_mask & REDRAW_ALL)
324 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
326 redraw_mask = REDRAW_NONE;
329 if (redraw_mask & REDRAW_FIELD)
331 if (game_status != GAME_MODE_PLAYING ||
332 redraw_mask & REDRAW_FROM_BACKBUFFER)
334 BlitBitmap(backbuffer, window,
335 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE, REAL_SX, REAL_SY);
339 int fx = FX, fy = FY;
341 if (setup.soft_scrolling)
343 fx += (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
344 fy += (ScreenMovDir & (MV_UP | MV_DOWN) ? ScreenGfxPos : 0);
347 if (setup.soft_scrolling ||
348 ABS(ScreenMovPos) + ScrollStepSize == TILEX ||
349 ABS(ScreenMovPos) == ScrollStepSize ||
350 redraw_tiles > REDRAWTILES_THRESHOLD)
352 if (border.draw_masked[GAME_MODE_PLAYING])
354 if (buffer != backbuffer)
356 /* copy playfield buffer to backbuffer to add masked border */
357 BlitBitmap(buffer, backbuffer, fx, fy, SXSIZE, SYSIZE, SX, SY);
358 DrawMaskedBorder(REDRAW_FIELD);
361 BlitBitmap(backbuffer, window,
362 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
367 BlitBitmap(buffer, window, fx, fy, SXSIZE, SYSIZE, SX, SY);
372 printf("redrawing all (ScreenGfxPos == %d) because %s\n",
374 (setup.soft_scrolling ?
375 "setup.soft_scrolling" :
376 ABS(ScreenGfxPos) + ScrollStepSize == TILEX ?
377 "ABS(ScreenGfxPos) + ScrollStepSize == TILEX" :
378 ABS(ScreenGfxPos) == ScrollStepSize ?
379 "ABS(ScreenGfxPos) == ScrollStepSize" :
380 "redraw_tiles > REDRAWTILES_THRESHOLD"));
386 redraw_mask &= ~REDRAW_MAIN;
389 if (redraw_mask & REDRAW_DOORS)
391 if (redraw_mask & REDRAW_DOOR_1)
392 BlitBitmap(backbuffer, window, DX, DY, DXSIZE, DYSIZE, DX, DY);
394 if (redraw_mask & REDRAW_DOOR_2)
395 BlitBitmap(backbuffer, window, VX, VY, VXSIZE, VYSIZE, VX, VY);
397 if (redraw_mask & REDRAW_DOOR_3)
398 BlitBitmap(backbuffer, window, EX, EY, EXSIZE, EYSIZE, EX, EY);
400 redraw_mask &= ~REDRAW_DOORS;
403 if (redraw_mask & REDRAW_MICROLEVEL)
405 BlitBitmap(backbuffer, window, SX, SY + 10 * TILEY, SXSIZE, 7 * TILEY,
406 SX, SY + 10 * TILEY);
408 redraw_mask &= ~REDRAW_MICROLEVEL;
411 if (redraw_mask & REDRAW_TILES)
413 for (x = 0; x < SCR_FIELDX; x++)
414 for (y = 0 ; y < SCR_FIELDY; y++)
415 if (redraw[redraw_x1 + x][redraw_y1 + y])
416 BlitBitmap(buffer, window,
417 FX + x * TILEX, FY + y * TILEY, TILEX, TILEY,
418 SX + x * TILEX, SY + y * TILEY);
421 if (redraw_mask & REDRAW_FPS) /* display frames per second */
426 sprintf(info1, " (only every %d. frame)", global.fps_slowdown_factor);
427 if (!global.fps_slowdown)
430 sprintf(text, "%.1f fps%s", global.frames_per_second, info1);
431 DrawTextExt(window, SX, SY, text, FONT_TEXT_2, BLIT_OPAQUE);
436 for (x = 0; x < MAX_BUF_XSIZE; x++)
437 for (y = 0; y < MAX_BUF_YSIZE; y++)
440 redraw_mask = REDRAW_NONE;
443 static void FadeCrossSaveBackbuffer()
445 BlitBitmap(backbuffer, bitmap_db_cross, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
448 static void FadeExt(int fade_mask, int fade_mode, int fade_type)
450 static int fade_type_skip = FADE_TYPE_NONE;
451 void (*draw_border_function)(void) = NULL;
452 Bitmap *bitmap = (fade_mode & FADE_TYPE_TRANSFORM ? bitmap_db_cross : NULL);
453 int x, y, width, height;
454 int fade_delay, post_delay;
456 if (fade_type == FADE_TYPE_FADE_OUT)
458 if (fade_type_skip != FADE_TYPE_NONE)
461 printf("::: skipping %d ... [%d] (X)\n", fade_mode, fade_type_skip);
464 /* skip all fade operations until specified fade operation */
465 if (fade_type & fade_type_skip)
466 fade_type_skip = FADE_TYPE_NONE;
471 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
473 FadeCrossSaveBackbuffer();
479 redraw_mask |= fade_mask;
481 if (fade_type == FADE_TYPE_SKIP)
484 printf("::: will skip %d ... [%d]\n", fade_mode, fade_type_skip);
487 fade_type_skip = fade_mode;
492 if (fade_type_skip != FADE_TYPE_NONE)
495 printf("::: skipping %d ... [%d]\n", fade_mode, fade_type_skip);
498 /* skip all fade operations until specified fade operation */
499 if (fade_type & fade_type_skip)
500 fade_type_skip = FADE_TYPE_NONE;
506 if (global.autoplay_leveldir)
508 // fading.fade_mode = FADE_MODE_NONE;
515 if (fading.fade_mode == FADE_MODE_NONE)
523 /* !!! what abount fade_mask == REDRAW_FIELD | REDRAW_ALL ??? !!! */
526 printf("::: NOW FADING %d ... [%d]\n", fade_mode, fade_type);
530 if (fade_mask == REDRAW_NONE)
531 fade_mask = REDRAW_FIELD;
534 // if (fade_mask & REDRAW_FIELD)
535 if (fade_mask == REDRAW_FIELD)
540 height = FULL_SYSIZE;
542 fade_delay = fading.fade_delay;
543 post_delay = (fade_mode == FADE_MODE_FADE_OUT ? fading.post_delay : 0);
545 if (border.draw_masked_when_fading)
546 draw_border_function = DrawMaskedBorder_FIELD; /* update when fading */
548 DrawMaskedBorder_FIELD(); /* draw once */
550 else /* REDRAW_ALL */
557 fade_delay = fading.fade_delay;
558 post_delay = (fade_mode == FADE_MODE_FADE_OUT ? fading.post_delay : 0);
562 if (!setup.fade_screens ||
564 fading.fade_mode == FADE_MODE_NONE)
566 if (!setup.fade_screens || fade_delay == 0)
569 if (fade_mode == FADE_MODE_FADE_OUT)
573 if (fade_mode == FADE_MODE_FADE_OUT &&
574 fading.fade_mode != FADE_MODE_NONE)
575 ClearRectangle(backbuffer, x, y, width, height);
579 BlitBitmap(backbuffer, window, x, y, width, height, x, y);
580 redraw_mask = REDRAW_NONE;
588 FadeRectangle(bitmap, x, y, width, height, fade_mode, fade_delay, post_delay,
589 draw_border_function);
591 redraw_mask &= ~fade_mask;
594 void FadeIn(int fade_mask)
596 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
597 FadeExt(fade_mask, fading.fade_mode, FADE_TYPE_FADE_IN);
599 FadeExt(fade_mask, FADE_MODE_FADE_IN, FADE_TYPE_FADE_IN);
602 void FadeOut(int fade_mask)
604 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
605 FadeExt(fade_mask, fading.fade_mode, FADE_TYPE_FADE_OUT);
607 FadeExt(fade_mask, FADE_MODE_FADE_OUT, FADE_TYPE_FADE_OUT);
609 global.border_status = game_status;
612 static void FadeSetLeaveNext(struct TitleFadingInfo fading_leave, boolean set)
614 static struct TitleFadingInfo fading_leave_stored;
617 fading_leave_stored = fading_leave;
619 fading = fading_leave_stored;
622 void FadeSetEnterMenu()
624 fading = menu.enter_menu;
627 printf("::: storing enter_menu\n");
630 FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
633 void FadeSetLeaveMenu()
635 fading = menu.leave_menu;
638 printf("::: storing leave_menu\n");
641 FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
644 void FadeSetEnterScreen()
646 fading = menu.enter_screen[game_status];
649 printf("::: storing leave_screen[%d]\n", game_status);
652 FadeSetLeaveNext(menu.leave_screen[game_status], TRUE); /* store */
655 void FadeSetNextScreen()
657 fading = menu.next_screen;
660 printf("::: storing next_screen\n");
663 // (do not overwrite fade mode set by FadeSetEnterScreen)
664 // FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
667 void FadeSetLeaveScreen()
670 printf("::: recalling last stored value\n");
673 FadeSetLeaveNext(menu.leave_screen[game_status], FALSE); /* recall */
676 void FadeSetFromType(int type)
678 if (type & TYPE_ENTER_SCREEN)
679 FadeSetEnterScreen();
680 else if (type & TYPE_ENTER)
682 else if (type & TYPE_LEAVE)
686 void FadeSetDisabled()
688 static struct TitleFadingInfo fading_none = { FADE_MODE_NONE, -1, -1, -1 };
690 fading = fading_none;
693 void FadeSkipNextFadeIn()
695 FadeExt(0, FADE_MODE_SKIP_FADE_IN, FADE_TYPE_SKIP);
698 void FadeSkipNextFadeOut()
700 FadeExt(0, FADE_MODE_SKIP_FADE_OUT, FADE_TYPE_SKIP);
703 void SetWindowBackgroundImageIfDefined(int graphic)
705 if (graphic_info[graphic].bitmap)
706 SetWindowBackgroundBitmap(graphic_info[graphic].bitmap);
709 void SetMainBackgroundImageIfDefined(int graphic)
711 if (graphic_info[graphic].bitmap)
712 SetMainBackgroundBitmap(graphic_info[graphic].bitmap);
715 void SetDoorBackgroundImageIfDefined(int graphic)
717 if (graphic_info[graphic].bitmap)
718 SetDoorBackgroundBitmap(graphic_info[graphic].bitmap);
721 void SetWindowBackgroundImage(int graphic)
723 SetWindowBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
724 graphic_info[graphic].bitmap ?
725 graphic_info[graphic].bitmap :
726 graphic_info[IMG_BACKGROUND].bitmap);
729 void SetMainBackgroundImage(int graphic)
731 SetMainBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
732 graphic_info[graphic].bitmap ?
733 graphic_info[graphic].bitmap :
734 graphic_info[IMG_BACKGROUND].bitmap);
737 void SetDoorBackgroundImage(int graphic)
739 SetDoorBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
740 graphic_info[graphic].bitmap ?
741 graphic_info[graphic].bitmap :
742 graphic_info[IMG_BACKGROUND].bitmap);
745 void SetPanelBackground()
747 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, bitmap_db_panel,
748 DOOR_GFX_PAGEX5, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE, 0, 0);
750 SetDoorBackgroundBitmap(bitmap_db_panel);
753 void DrawBackground(int x, int y, int width, int height)
755 /* !!! "drawto" might still point to playfield buffer here (see below) !!! */
756 /* (when entering hall of fame after playing) */
758 ClearRectangleOnBackground(drawto, x, y, width, height);
760 ClearRectangleOnBackground(backbuffer, x, y, width, height);
763 redraw_mask |= REDRAW_FIELD;
766 void DrawBackgroundForFont(int x, int y, int width, int height, int font_nr)
768 struct FontBitmapInfo *font = getFontBitmapInfo(font_nr);
770 if (font->bitmap == NULL)
773 DrawBackground(x, y, width, height);
776 void DrawBackgroundForGraphic(int x, int y, int width, int height, int graphic)
778 struct GraphicInfo *g = &graphic_info[graphic];
780 if (g->bitmap == NULL)
783 DrawBackground(x, y, width, height);
788 /* !!! "drawto" might still point to playfield buffer here (see above) !!! */
789 /* (when entering hall of fame after playing) */
790 DrawBackground(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
792 /* !!! maybe this should be done before clearing the background !!! */
793 if (setup.soft_scrolling && game_status == GAME_MODE_PLAYING)
795 ClearRectangle(fieldbuffer, 0, 0, FXSIZE, FYSIZE);
796 SetDrawtoField(DRAW_BUFFERED);
799 SetDrawtoField(DRAW_BACKBUFFER);
802 void MarkTileDirty(int x, int y)
804 int xx = redraw_x1 + x;
805 int yy = redraw_y1 + y;
810 redraw[xx][yy] = TRUE;
811 redraw_mask |= REDRAW_TILES;
814 void SetBorderElement()
818 BorderElement = EL_EMPTY;
820 for (y = 0; y < lev_fieldy && BorderElement == EL_EMPTY; y++)
822 for (x = 0; x < lev_fieldx; x++)
824 if (!IS_INDESTRUCTIBLE(Feld[x][y]))
825 BorderElement = EL_STEELWALL;
827 if (y != 0 && y != lev_fieldy - 1 && x != lev_fieldx - 1)
833 void FloodFillLevel(int from_x, int from_y, int fill_element,
834 short field[MAX_LEV_FIELDX][MAX_LEV_FIELDY],
835 int max_fieldx, int max_fieldy)
839 static int check[4][2] = { { -1, 0 }, { 0, -1 }, { 1, 0 }, { 0, 1 } };
840 static int safety = 0;
842 /* check if starting field still has the desired content */
843 if (field[from_x][from_y] == fill_element)
848 if (safety > max_fieldx * max_fieldy)
849 Error(ERR_EXIT, "Something went wrong in 'FloodFill()'. Please debug.");
851 old_element = field[from_x][from_y];
852 field[from_x][from_y] = fill_element;
854 for (i = 0; i < 4; i++)
856 x = from_x + check[i][0];
857 y = from_y + check[i][1];
859 if (IN_FIELD(x, y, max_fieldx, max_fieldy) && field[x][y] == old_element)
860 FloodFillLevel(x, y, fill_element, field, max_fieldx, max_fieldy);
866 void SetRandomAnimationValue(int x, int y)
868 gfx.anim_random_frame = GfxRandom[x][y];
871 inline int getGraphicAnimationFrame(int graphic, int sync_frame)
873 /* animation synchronized with global frame counter, not move position */
874 if (graphic_info[graphic].anim_global_sync || sync_frame < 0)
875 sync_frame = FrameCounter;
877 return getAnimationFrame(graphic_info[graphic].anim_frames,
878 graphic_info[graphic].anim_delay,
879 graphic_info[graphic].anim_mode,
880 graphic_info[graphic].anim_start_frame,
884 void getSizedGraphicSource(int graphic, int frame, int tilesize_raw,
885 Bitmap **bitmap, int *x, int *y)
889 int width_mult, width_div;
890 int height_mult, height_div;
894 { 15, 16, 2, 3 }, /* 1 x 1 */
895 { 7, 8, 2, 3 }, /* 2 x 2 */
896 { 3, 4, 2, 3 }, /* 4 x 4 */
897 { 1, 2, 2, 3 }, /* 8 x 8 */
898 { 0, 1, 2, 3 }, /* 16 x 16 */
899 { 0, 1, 0, 1 }, /* 32 x 32 */
901 struct GraphicInfo *g = &graphic_info[graphic];
902 Bitmap *src_bitmap = g->bitmap;
903 int tilesize = MIN(MAX(1, tilesize_raw), TILESIZE);
904 int offset_calc_pos = log_2(tilesize);
905 int width_mult = offset_calc[offset_calc_pos].width_mult;
906 int width_div = offset_calc[offset_calc_pos].width_div;
907 int height_mult = offset_calc[offset_calc_pos].height_mult;
908 int height_div = offset_calc[offset_calc_pos].height_div;
909 int startx = src_bitmap->width * width_mult / width_div;
910 int starty = src_bitmap->height * height_mult / height_div;
911 int src_x = g->src_x * tilesize / TILESIZE;
912 int src_y = g->src_y * tilesize / TILESIZE;
913 int width = g->width * tilesize / TILESIZE;
914 int height = g->height * tilesize / TILESIZE;
915 int offset_x = g->offset_x * tilesize / TILESIZE;
916 int offset_y = g->offset_y * tilesize / TILESIZE;
918 if (g->offset_y == 0) /* frames are ordered horizontally */
920 int max_width = g->anim_frames_per_line * width;
921 int pos = (src_y / height) * max_width + src_x + frame * offset_x;
923 src_x = pos % max_width;
924 src_y = src_y % height + pos / max_width * height;
926 else if (g->offset_x == 0) /* frames are ordered vertically */
928 int max_height = g->anim_frames_per_line * height;
929 int pos = (src_x / width) * max_height + src_y + frame * offset_y;
931 src_x = src_x % width + pos / max_height * width;
932 src_y = pos % max_height;
934 else /* frames are ordered diagonally */
936 src_x = src_x + frame * offset_x;
937 src_y = src_y + frame * offset_y;
940 *bitmap = src_bitmap;
945 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
948 getSizedGraphicSource(graphic, 0, MINI_TILESIZE, bitmap, x, y);
950 struct GraphicInfo *g = &graphic_info[graphic];
952 int mini_starty = g->bitmap->height * 2 / 3;
955 *x = mini_startx + g->src_x / 2;
956 *y = mini_starty + g->src_y / 2;
960 inline void getGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
961 int *x, int *y, boolean get_backside)
963 struct GraphicInfo *g = &graphic_info[graphic];
964 int src_x = g->src_x + (get_backside ? g->offset2_x : 0);
965 int src_y = g->src_y + (get_backside ? g->offset2_y : 0);
969 if (g->offset_y == 0) /* frames are ordered horizontally */
971 int max_width = g->anim_frames_per_line * g->width;
972 int pos = (src_y / g->height) * max_width + src_x + frame * g->offset_x;
974 *x = pos % max_width;
975 *y = src_y % g->height + pos / max_width * g->height;
977 else if (g->offset_x == 0) /* frames are ordered vertically */
979 int max_height = g->anim_frames_per_line * g->height;
980 int pos = (src_x / g->width) * max_height + src_y + frame * g->offset_y;
982 *x = src_x % g->width + pos / max_height * g->width;
983 *y = pos % max_height;
985 else /* frames are ordered diagonally */
987 *x = src_x + frame * g->offset_x;
988 *y = src_y + frame * g->offset_y;
992 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
994 getGraphicSourceExt(graphic, frame, bitmap, x, y, FALSE);
997 void DrawGraphic(int x, int y, int graphic, int frame)
1000 if (!IN_SCR_FIELD(x, y))
1002 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
1003 printf("DrawGraphic(): This should never happen!\n");
1008 DrawGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic, frame);
1009 MarkTileDirty(x, y);
1012 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
1018 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1019 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
1022 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
1025 if (!IN_SCR_FIELD(x, y))
1027 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
1028 printf("DrawGraphicThruMask(): This should never happen!\n");
1033 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y *TILEY, graphic,
1035 MarkTileDirty(x, y);
1038 void DrawGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y, int graphic,
1044 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1046 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1047 dst_x - src_x, dst_y - src_y);
1048 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dst_x, dst_y);
1051 void DrawSizedGraphic(int x, int y, int graphic, int frame, int tilesize)
1053 DrawSizedGraphicExt(drawto, SX + x * tilesize, SY + y * tilesize, graphic,
1055 MarkTileDirty(x / tilesize, y / tilesize);
1058 void DrawSizedGraphicExt(DrawBuffer *d, int x, int y, int graphic, int frame,
1064 getSizedGraphicSource(graphic, frame, tilesize, &src_bitmap, &src_x, &src_y);
1065 BlitBitmap(src_bitmap, d, src_x, src_y, tilesize, tilesize, x, y);
1068 void DrawMiniGraphic(int x, int y, int graphic)
1070 DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
1071 MarkTileDirty(x / 2, y / 2);
1074 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
1079 getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1080 BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
1083 inline static void DrawGraphicShiftedNormal(int x, int y, int dx, int dy,
1084 int graphic, int frame,
1085 int cut_mode, int mask_mode)
1090 int width = TILEX, height = TILEY;
1093 if (dx || dy) /* shifted graphic */
1095 if (x < BX1) /* object enters playfield from the left */
1102 else if (x > BX2) /* object enters playfield from the right */
1108 else if (x==BX1 && dx < 0) /* object leaves playfield to the left */
1114 else if (x==BX2 && dx > 0) /* object leaves playfield to the right */
1116 else if (dx) /* general horizontal movement */
1117 MarkTileDirty(x + SIGN(dx), y);
1119 if (y < BY1) /* object enters playfield from the top */
1121 if (cut_mode==CUT_BELOW) /* object completely above top border */
1129 else if (y > BY2) /* object enters playfield from the bottom */
1135 else if (y==BY1 && dy < 0) /* object leaves playfield to the top */
1141 else if (dy > 0 && cut_mode == CUT_ABOVE)
1143 if (y == BY2) /* object completely above bottom border */
1149 MarkTileDirty(x, y + 1);
1150 } /* object leaves playfield to the bottom */
1151 else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
1153 else if (dy) /* general vertical movement */
1154 MarkTileDirty(x, y + SIGN(dy));
1158 if (!IN_SCR_FIELD(x, y))
1160 printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
1161 printf("DrawGraphicShifted(): This should never happen!\n");
1166 if (width > 0 && height > 0)
1168 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1173 dst_x = FX + x * TILEX + dx;
1174 dst_y = FY + y * TILEY + dy;
1176 if (mask_mode == USE_MASKING)
1178 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1179 dst_x - src_x, dst_y - src_y);
1180 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1184 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1187 MarkTileDirty(x, y);
1191 inline static void DrawGraphicShiftedDouble(int x, int y, int dx, int dy,
1192 int graphic, int frame,
1193 int cut_mode, int mask_mode)
1198 int width = TILEX, height = TILEY;
1201 int x2 = x + SIGN(dx);
1202 int y2 = y + SIGN(dy);
1203 int anim_frames = graphic_info[graphic].anim_frames;
1204 int sync_frame = (dx ? ABS(dx) : ABS(dy)) * anim_frames / TILESIZE;
1205 boolean draw_start_tile = (cut_mode != CUT_ABOVE); /* only for falling! */
1206 boolean draw_end_tile = (cut_mode != CUT_BELOW); /* only for falling! */
1208 /* re-calculate animation frame for two-tile movement animation */
1209 frame = getGraphicAnimationFrame(graphic, sync_frame);
1211 /* check if movement start graphic inside screen area and should be drawn */
1212 if (draw_start_tile && IN_SCR_FIELD(x1, y1))
1214 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, TRUE);
1216 dst_x = FX + x1 * TILEX;
1217 dst_y = FY + y1 * TILEY;
1219 if (mask_mode == USE_MASKING)
1221 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1222 dst_x - src_x, dst_y - src_y);
1223 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1227 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1230 MarkTileDirty(x1, y1);
1233 /* check if movement end graphic inside screen area and should be drawn */
1234 if (draw_end_tile && IN_SCR_FIELD(x2, y2))
1236 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
1238 dst_x = FX + x2 * TILEX;
1239 dst_y = FY + y2 * TILEY;
1241 if (mask_mode == USE_MASKING)
1243 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1244 dst_x - src_x, dst_y - src_y);
1245 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1249 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1252 MarkTileDirty(x2, y2);
1256 static void DrawGraphicShifted(int x, int y, int dx, int dy,
1257 int graphic, int frame,
1258 int cut_mode, int mask_mode)
1262 DrawGraphic(x, y, graphic, frame);
1267 if (graphic_info[graphic].double_movement) /* EM style movement images */
1268 DrawGraphicShiftedDouble(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1270 DrawGraphicShiftedNormal(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1273 void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
1274 int frame, int cut_mode)
1276 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, USE_MASKING);
1279 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
1280 int cut_mode, int mask_mode)
1282 int lx = LEVELX(x), ly = LEVELY(y);
1286 if (IN_LEV_FIELD(lx, ly))
1288 SetRandomAnimationValue(lx, ly);
1290 graphic = el_act_dir2img(element, GfxAction[lx][ly], GfxDir[lx][ly]);
1291 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1293 /* do not use double (EM style) movement graphic when not moving */
1294 if (graphic_info[graphic].double_movement && !dx && !dy)
1296 graphic = el_act_dir2img(element, ACTION_DEFAULT, GfxDir[lx][ly]);
1297 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1300 else /* border element */
1302 graphic = el2img(element);
1303 frame = getGraphicAnimationFrame(graphic, -1);
1306 if (element == EL_EXPANDABLE_WALL)
1308 boolean left_stopped = FALSE, right_stopped = FALSE;
1310 if (!IN_LEV_FIELD(lx - 1, ly) || IS_WALL(Feld[lx - 1][ly]))
1311 left_stopped = TRUE;
1312 if (!IN_LEV_FIELD(lx + 1, ly) || IS_WALL(Feld[lx + 1][ly]))
1313 right_stopped = TRUE;
1315 if (left_stopped && right_stopped)
1317 else if (left_stopped)
1319 graphic = IMG_EXPANDABLE_WALL_GROWING_RIGHT;
1320 frame = graphic_info[graphic].anim_frames - 1;
1322 else if (right_stopped)
1324 graphic = IMG_EXPANDABLE_WALL_GROWING_LEFT;
1325 frame = graphic_info[graphic].anim_frames - 1;
1330 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
1331 else if (mask_mode == USE_MASKING)
1332 DrawGraphicThruMask(x, y, graphic, frame);
1334 DrawGraphic(x, y, graphic, frame);
1337 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
1338 int cut_mode, int mask_mode)
1340 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1341 DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
1342 cut_mode, mask_mode);
1345 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
1348 DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1351 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
1354 DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1357 void DrawLevelElementThruMask(int x, int y, int element)
1359 DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1362 void DrawLevelFieldThruMask(int x, int y)
1364 DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
1367 static void DrawLevelFieldCrumbledSandExt(int x, int y, int graphic, int frame)
1371 int sx = SCREENX(x), sy = SCREENY(y);
1373 int width, height, cx, cy, i;
1374 int crumbled_border_size = graphic_info[graphic].border_size;
1375 static int xy[4][2] =
1383 if (!IN_LEV_FIELD(x, y))
1386 element = TILE_GFX_ELEMENT(x, y);
1388 /* crumble field itself */
1389 if (GFX_CRUMBLED(element) && !IS_MOVING(x, y))
1391 if (!IN_SCR_FIELD(sx, sy))
1394 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1396 for (i = 0; i < 4; i++)
1398 int xx = x + xy[i][0];
1399 int yy = y + xy[i][1];
1401 element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1404 /* check if neighbour field is of same type */
1405 if (GFX_CRUMBLED(element) && !IS_MOVING(xx, yy))
1408 if (i == 1 || i == 2)
1410 width = crumbled_border_size;
1412 cx = (i == 2 ? TILEX - crumbled_border_size : 0);
1418 height = crumbled_border_size;
1420 cy = (i == 3 ? TILEY - crumbled_border_size : 0);
1423 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1424 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
1427 MarkTileDirty(sx, sy);
1429 else /* crumble neighbour fields */
1431 for (i = 0; i < 4; i++)
1433 int xx = x + xy[i][0];
1434 int yy = y + xy[i][1];
1435 int sxx = sx + xy[i][0];
1436 int syy = sy + xy[i][1];
1438 if (!IN_LEV_FIELD(xx, yy) ||
1439 !IN_SCR_FIELD(sxx, syy) ||
1443 if (Feld[xx][yy] == EL_ELEMENT_SNAPPING)
1446 element = TILE_GFX_ELEMENT(xx, yy);
1448 if (!GFX_CRUMBLED(element))
1451 graphic = el_act2crm(element, ACTION_DEFAULT);
1452 crumbled_border_size = graphic_info[graphic].border_size;
1454 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1456 if (i == 1 || i == 2)
1458 width = crumbled_border_size;
1460 cx = (i == 1 ? TILEX - crumbled_border_size : 0);
1466 height = crumbled_border_size;
1468 cy = (i == 0 ? TILEY - crumbled_border_size : 0);
1471 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1472 width, height, FX + sxx * TILEX + cx, FY + syy * TILEY + cy);
1474 MarkTileDirty(sxx, syy);
1479 void DrawLevelFieldCrumbledSand(int x, int y)
1483 if (!IN_LEV_FIELD(x, y))
1487 /* !!! CHECK THIS !!! */
1490 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
1491 GFX_CRUMBLED(GfxElement[x][y]))
1494 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
1495 GfxElement[x][y] != EL_UNDEFINED &&
1496 GFX_CRUMBLED(GfxElement[x][y]))
1498 DrawLevelFieldCrumbledSandDigging(x, y, GfxDir[x][y], GfxFrame[x][y]);
1505 graphic = el_act2crm(TILE_GFX_ELEMENT(x, y), ACTION_DEFAULT);
1507 graphic = el_act2crm(Feld[x][y], ACTION_DEFAULT);
1510 DrawLevelFieldCrumbledSandExt(x, y, graphic, 0);
1513 void DrawLevelFieldCrumbledSandDigging(int x, int y, int direction,
1516 int graphic1 = el_act_dir2img(GfxElement[x][y], ACTION_DIGGING, direction);
1517 int graphic2 = el_act_dir2crm(GfxElement[x][y], ACTION_DIGGING, direction);
1518 int frame1 = getGraphicAnimationFrame(graphic1, step_frame);
1519 int frame2 = getGraphicAnimationFrame(graphic2, step_frame);
1520 int sx = SCREENX(x), sy = SCREENY(y);
1522 DrawGraphic(sx, sy, graphic1, frame1);
1523 DrawLevelFieldCrumbledSandExt(x, y, graphic2, frame2);
1526 void DrawLevelFieldCrumbledSandNeighbours(int x, int y)
1528 int sx = SCREENX(x), sy = SCREENY(y);
1529 static int xy[4][2] =
1538 for (i = 0; i < 4; i++)
1540 int xx = x + xy[i][0];
1541 int yy = y + xy[i][1];
1542 int sxx = sx + xy[i][0];
1543 int syy = sy + xy[i][1];
1545 if (!IN_LEV_FIELD(xx, yy) ||
1546 !IN_SCR_FIELD(sxx, syy) ||
1547 !GFX_CRUMBLED(Feld[xx][yy]) ||
1551 DrawLevelField(xx, yy);
1555 static int getBorderElement(int x, int y)
1559 { EL_STEELWALL_TOPLEFT, EL_INVISIBLE_STEELWALL_TOPLEFT },
1560 { EL_STEELWALL_TOPRIGHT, EL_INVISIBLE_STEELWALL_TOPRIGHT },
1561 { EL_STEELWALL_BOTTOMLEFT, EL_INVISIBLE_STEELWALL_BOTTOMLEFT },
1562 { EL_STEELWALL_BOTTOMRIGHT, EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
1563 { EL_STEELWALL_VERTICAL, EL_INVISIBLE_STEELWALL_VERTICAL },
1564 { EL_STEELWALL_HORIZONTAL, EL_INVISIBLE_STEELWALL_HORIZONTAL },
1565 { EL_STEELWALL, EL_INVISIBLE_STEELWALL }
1567 int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
1568 int steel_position = (x == -1 && y == -1 ? 0 :
1569 x == lev_fieldx && y == -1 ? 1 :
1570 x == -1 && y == lev_fieldy ? 2 :
1571 x == lev_fieldx && y == lev_fieldy ? 3 :
1572 x == -1 || x == lev_fieldx ? 4 :
1573 y == -1 || y == lev_fieldy ? 5 : 6);
1575 return border[steel_position][steel_type];
1578 void DrawScreenElement(int x, int y, int element)
1580 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
1581 DrawLevelFieldCrumbledSand(LEVELX(x), LEVELY(y));
1584 void DrawLevelElement(int x, int y, int element)
1586 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1587 DrawScreenElement(SCREENX(x), SCREENY(y), element);
1590 void DrawScreenField(int x, int y)
1592 int lx = LEVELX(x), ly = LEVELY(y);
1593 int element, content;
1595 if (!IN_LEV_FIELD(lx, ly))
1597 if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
1600 element = getBorderElement(lx, ly);
1602 DrawScreenElement(x, y, element);
1606 element = Feld[lx][ly];
1607 content = Store[lx][ly];
1609 if (IS_MOVING(lx, ly))
1611 int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
1612 boolean cut_mode = NO_CUTTING;
1614 if (element == EL_QUICKSAND_EMPTYING ||
1615 element == EL_QUICKSAND_FAST_EMPTYING ||
1616 element == EL_MAGIC_WALL_EMPTYING ||
1617 element == EL_BD_MAGIC_WALL_EMPTYING ||
1618 element == EL_DC_MAGIC_WALL_EMPTYING ||
1619 element == EL_AMOEBA_DROPPING)
1620 cut_mode = CUT_ABOVE;
1621 else if (element == EL_QUICKSAND_FILLING ||
1622 element == EL_QUICKSAND_FAST_FILLING ||
1623 element == EL_MAGIC_WALL_FILLING ||
1624 element == EL_BD_MAGIC_WALL_FILLING ||
1625 element == EL_DC_MAGIC_WALL_FILLING)
1626 cut_mode = CUT_BELOW;
1628 if (cut_mode == CUT_ABOVE)
1629 DrawScreenElementShifted(x, y, 0, 0, element, NO_CUTTING);
1631 DrawScreenElement(x, y, EL_EMPTY);
1634 DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
1635 else if (cut_mode == NO_CUTTING)
1636 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
1638 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
1640 if (content == EL_ACID)
1642 int dir = MovDir[lx][ly];
1643 int newlx = lx + (dir == MV_LEFT ? -1 : dir == MV_RIGHT ? +1 : 0);
1644 int newly = ly + (dir == MV_UP ? -1 : dir == MV_DOWN ? +1 : 0);
1646 DrawLevelElementThruMask(newlx, newly, EL_ACID);
1649 else if (IS_BLOCKED(lx, ly))
1654 boolean cut_mode = NO_CUTTING;
1655 int element_old, content_old;
1657 Blocked2Moving(lx, ly, &oldx, &oldy);
1660 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
1661 MovDir[oldx][oldy] == MV_RIGHT);
1663 element_old = Feld[oldx][oldy];
1664 content_old = Store[oldx][oldy];
1666 if (element_old == EL_QUICKSAND_EMPTYING ||
1667 element_old == EL_QUICKSAND_FAST_EMPTYING ||
1668 element_old == EL_MAGIC_WALL_EMPTYING ||
1669 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
1670 element_old == EL_DC_MAGIC_WALL_EMPTYING ||
1671 element_old == EL_AMOEBA_DROPPING)
1672 cut_mode = CUT_ABOVE;
1674 DrawScreenElement(x, y, EL_EMPTY);
1677 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
1679 else if (cut_mode == NO_CUTTING)
1680 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
1683 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
1686 else if (IS_DRAWABLE(element))
1687 DrawScreenElement(x, y, element);
1689 DrawScreenElement(x, y, EL_EMPTY);
1692 void DrawLevelField(int x, int y)
1694 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1695 DrawScreenField(SCREENX(x), SCREENY(y));
1696 else if (IS_MOVING(x, y))
1700 Moving2Blocked(x, y, &newx, &newy);
1701 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
1702 DrawScreenField(SCREENX(newx), SCREENY(newy));
1704 else if (IS_BLOCKED(x, y))
1708 Blocked2Moving(x, y, &oldx, &oldy);
1709 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
1710 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
1714 void DrawMiniElement(int x, int y, int element)
1718 graphic = el2edimg(element);
1719 DrawMiniGraphic(x, y, graphic);
1722 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
1724 int x = sx + scroll_x, y = sy + scroll_y;
1726 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
1727 DrawMiniElement(sx, sy, EL_EMPTY);
1728 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
1729 DrawMiniElement(sx, sy, Feld[x][y]);
1731 DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
1734 void DrawEnvelopeBackground(int envelope_nr, int startx, int starty,
1735 int x, int y, int xsize, int ysize, int font_nr)
1737 int font_width = getFontWidth(font_nr);
1738 int font_height = getFontHeight(font_nr);
1739 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1742 int dst_x = SX + startx + x * font_width;
1743 int dst_y = SY + starty + y * font_height;
1744 int width = graphic_info[graphic].width;
1745 int height = graphic_info[graphic].height;
1746 int inner_width = MAX(width - 2 * font_width, font_width);
1747 int inner_height = MAX(height - 2 * font_height, font_height);
1748 int inner_sx = (width >= 3 * font_width ? font_width : 0);
1749 int inner_sy = (height >= 3 * font_height ? font_height : 0);
1750 boolean draw_masked = graphic_info[graphic].draw_masked;
1752 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1754 if (src_bitmap == NULL || width < font_width || height < font_height)
1756 ClearRectangle(drawto, dst_x, dst_y, font_width, font_height);
1760 src_x += (x == 0 ? 0 : x == xsize - 1 ? width - font_width :
1761 inner_sx + (x - 1) * font_width % inner_width);
1762 src_y += (y == 0 ? 0 : y == ysize - 1 ? height - font_height :
1763 inner_sy + (y - 1) * font_height % inner_height);
1767 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1768 dst_x - src_x, dst_y - src_y);
1769 BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1773 BlitBitmap(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1777 void AnimateEnvelope(int envelope_nr, int anim_mode, int action)
1779 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1780 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1781 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
1782 boolean ffwd_delay = (tape.playing && tape.fast_forward);
1783 boolean no_delay = (tape.warp_forward);
1784 unsigned long anim_delay = 0;
1785 int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
1786 int anim_delay_value = (no_delay ? 0 : frame_delay_value);
1787 int font_nr = FONT_ENVELOPE_1 + envelope_nr;
1788 int font_width = getFontWidth(font_nr);
1789 int font_height = getFontHeight(font_nr);
1790 int max_xsize = level.envelope[envelope_nr].xsize;
1791 int max_ysize = level.envelope[envelope_nr].ysize;
1792 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
1793 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
1794 int xend = max_xsize;
1795 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
1796 int xstep = (xstart < xend ? 1 : 0);
1797 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
1800 for (x = xstart, y = ystart; x <= xend && y <= yend; x += xstep, y += ystep)
1802 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
1803 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
1804 int sx = (SXSIZE - xsize * font_width) / 2;
1805 int sy = (SYSIZE - ysize * font_height) / 2;
1808 SetDrawtoField(DRAW_BUFFERED);
1810 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
1812 SetDrawtoField(DRAW_BACKBUFFER);
1814 for (yy = 0; yy < ysize; yy++) for (xx = 0; xx < xsize; xx++)
1815 DrawEnvelopeBackground(envelope_nr, sx,sy, xx,yy, xsize, ysize, font_nr);
1818 DrawTextBuffer(SX + sx + font_width, SY + sy + font_height,
1819 level.envelope[envelope_nr].text, font_nr, max_xsize,
1820 xsize - 2, ysize - 2, mask_mode,
1821 level.envelope[envelope_nr].autowrap,
1822 level.envelope[envelope_nr].centered, FALSE);
1824 DrawTextToTextArea(SX + sx + font_width, SY + sy + font_height,
1825 level.envelope[envelope_nr].text, font_nr, max_xsize,
1826 xsize - 2, ysize - 2, mask_mode);
1829 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
1832 WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
1836 void ShowEnvelope(int envelope_nr)
1838 int element = EL_ENVELOPE_1 + envelope_nr;
1839 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1840 int sound_opening = element_info[element].sound[ACTION_OPENING];
1841 int sound_closing = element_info[element].sound[ACTION_CLOSING];
1842 boolean ffwd_delay = (tape.playing && tape.fast_forward);
1843 boolean no_delay = (tape.warp_forward);
1844 int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
1845 int wait_delay_value = (no_delay ? 0 : normal_delay_value);
1846 int anim_mode = graphic_info[graphic].anim_mode;
1847 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
1848 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
1850 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
1852 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
1854 if (anim_mode == ANIM_DEFAULT)
1855 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_OPENING);
1857 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_OPENING);
1860 Delay(wait_delay_value);
1862 WaitForEventToContinue();
1864 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
1866 if (anim_mode != ANIM_NONE)
1867 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_CLOSING);
1869 if (anim_mode == ANIM_DEFAULT)
1870 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_CLOSING);
1872 game.envelope_active = FALSE;
1874 SetDrawtoField(DRAW_BUFFERED);
1876 redraw_mask |= REDRAW_FIELD;
1880 void DrawPreviewElement(int dst_x, int dst_y, int element, int tilesize)
1884 int graphic = el2preimg(element);
1886 getSizedGraphicSource(graphic, 0, tilesize, &src_bitmap, &src_x, &src_y);
1887 BlitBitmap(src_bitmap, drawto, src_x, src_y, tilesize, tilesize, dst_x,dst_y);
1894 SetDrawBackgroundMask(REDRAW_NONE);
1897 for (x = BX1; x <= BX2; x++)
1898 for (y = BY1; y <= BY2; y++)
1899 DrawScreenField(x, y);
1901 redraw_mask |= REDRAW_FIELD;
1904 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
1908 for (x = 0; x < size_x; x++)
1909 for (y = 0; y < size_y; y++)
1910 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
1912 redraw_mask |= REDRAW_FIELD;
1915 static void DrawPreviewLevelExt(int from_x, int from_y)
1917 boolean show_level_border = (BorderElement != EL_EMPTY);
1918 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
1919 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
1920 int tile_size = preview.tile_size;
1921 int preview_width = preview.xsize * tile_size;
1922 int preview_height = preview.ysize * tile_size;
1923 int real_preview_xsize = MIN(level_xsize, preview.xsize);
1924 int real_preview_ysize = MIN(level_ysize, preview.ysize);
1925 int dst_x = SX + ALIGNED_XPOS(preview.x, preview_width, preview.align);
1926 int dst_y = SY + ALIGNED_YPOS(preview.y, preview_height, preview.valign);
1929 DrawBackground(dst_x, dst_y, preview_width, preview_height);
1931 dst_x += (preview_width - real_preview_xsize * tile_size) / 2;
1932 dst_y += (preview_height - real_preview_ysize * tile_size) / 2;
1934 for (x = 0; x < real_preview_xsize; x++)
1936 for (y = 0; y < real_preview_ysize; y++)
1938 int lx = from_x + x + (show_level_border ? -1 : 0);
1939 int ly = from_y + y + (show_level_border ? -1 : 0);
1940 int element = (IN_LEV_FIELD(lx, ly) ? level.field[lx][ly] :
1941 getBorderElement(lx, ly));
1943 DrawPreviewElement(dst_x + x * tile_size, dst_y + y * tile_size,
1944 element, tile_size);
1948 redraw_mask |= REDRAW_MICROLEVEL;
1951 #define MICROLABEL_EMPTY 0
1952 #define MICROLABEL_LEVEL_NAME 1
1953 #define MICROLABEL_LEVEL_AUTHOR_HEAD 2
1954 #define MICROLABEL_LEVEL_AUTHOR 3
1955 #define MICROLABEL_IMPORTED_FROM_HEAD 4
1956 #define MICROLABEL_IMPORTED_FROM 5
1957 #define MICROLABEL_IMPORTED_BY_HEAD 6
1958 #define MICROLABEL_IMPORTED_BY 7
1960 static int getMaxTextLength(struct TextPosInfo *pos, int font_nr)
1962 int max_text_width = SXSIZE;
1963 int font_width = getFontWidth(font_nr);
1965 if (pos->align == ALIGN_CENTER)
1966 max_text_width = (pos->x < SXSIZE / 2 ? pos->x * 2 : (SXSIZE - pos->x) * 2);
1967 else if (pos->align == ALIGN_RIGHT)
1968 max_text_width = pos->x;
1970 max_text_width = SXSIZE - pos->x;
1972 return max_text_width / font_width;
1975 static void DrawPreviewLevelLabelExt(int mode)
1977 struct TextPosInfo *pos = &menu.main.text.level_info_2;
1978 char label_text[MAX_OUTPUT_LINESIZE + 1];
1979 int max_len_label_text;
1981 int font_nr = pos->font;
1984 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
1985 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
1986 mode == MICROLABEL_IMPORTED_BY_HEAD)
1987 font_nr = pos->font_alt;
1989 int font_nr = FONT_TEXT_2;
1992 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
1993 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
1994 mode == MICROLABEL_IMPORTED_BY_HEAD)
1995 font_nr = FONT_TEXT_3;
1999 max_len_label_text = getMaxTextLength(pos, font_nr);
2001 max_len_label_text = SXSIZE / getFontWidth(font_nr);
2005 if (pos->size != -1)
2006 max_len_label_text = pos->size;
2009 for (i = 0; i < max_len_label_text; i++)
2010 label_text[i] = ' ';
2011 label_text[max_len_label_text] = '\0';
2013 if (strlen(label_text) > 0)
2016 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2018 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
2019 int lypos = MICROLABEL2_YPOS;
2021 DrawText(lxpos, lypos, label_text, font_nr);
2026 (mode == MICROLABEL_LEVEL_NAME ? level.name :
2027 mode == MICROLABEL_LEVEL_AUTHOR_HEAD ? "created by" :
2028 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
2029 mode == MICROLABEL_IMPORTED_FROM_HEAD ? "imported from" :
2030 mode == MICROLABEL_IMPORTED_FROM ? leveldir_current->imported_from :
2031 mode == MICROLABEL_IMPORTED_BY_HEAD ? "imported by" :
2032 mode == MICROLABEL_IMPORTED_BY ? leveldir_current->imported_by :""),
2033 max_len_label_text);
2034 label_text[max_len_label_text] = '\0';
2036 if (strlen(label_text) > 0)
2039 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2041 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
2042 int lypos = MICROLABEL2_YPOS;
2044 DrawText(lxpos, lypos, label_text, font_nr);
2048 redraw_mask |= REDRAW_MICROLEVEL;
2051 void DrawPreviewLevel(boolean restart)
2053 static unsigned long scroll_delay = 0;
2054 static unsigned long label_delay = 0;
2055 static int from_x, from_y, scroll_direction;
2056 static int label_state, label_counter;
2057 unsigned long scroll_delay_value = preview.step_delay;
2058 boolean show_level_border = (BorderElement != EL_EMPTY);
2059 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
2060 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
2061 int last_game_status = game_status; /* save current game status */
2064 /* force PREVIEW font on preview level */
2065 game_status = GAME_MODE_PSEUDO_PREVIEW;
2073 if (preview.anim_mode == ANIM_CENTERED)
2075 if (level_xsize > preview.xsize)
2076 from_x = (level_xsize - preview.xsize) / 2;
2077 if (level_ysize > preview.ysize)
2078 from_y = (level_ysize - preview.ysize) / 2;
2081 from_x += preview.xoffset;
2082 from_y += preview.yoffset;
2084 scroll_direction = MV_RIGHT;
2088 DrawPreviewLevelExt(from_x, from_y);
2089 DrawPreviewLevelLabelExt(label_state);
2091 /* initialize delay counters */
2092 DelayReached(&scroll_delay, 0);
2093 DelayReached(&label_delay, 0);
2095 if (leveldir_current->name)
2097 struct TextPosInfo *pos = &menu.main.text.level_info_1;
2098 char label_text[MAX_OUTPUT_LINESIZE + 1];
2100 int font_nr = pos->font;
2102 int font_nr = FONT_TEXT_1;
2105 int max_len_label_text = getMaxTextLength(pos, font_nr);
2107 int max_len_label_text = SXSIZE / getFontWidth(font_nr);
2115 if (pos->size != -1)
2116 max_len_label_text = pos->size;
2119 strncpy(label_text, leveldir_current->name, max_len_label_text);
2120 label_text[max_len_label_text] = '\0';
2123 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2125 lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
2126 lypos = SY + MICROLABEL1_YPOS;
2128 DrawText(lxpos, lypos, label_text, font_nr);
2132 game_status = last_game_status; /* restore current game status */
2137 /* scroll preview level, if needed */
2138 if (preview.anim_mode != ANIM_NONE &&
2139 (level_xsize > preview.xsize || level_ysize > preview.ysize) &&
2140 DelayReached(&scroll_delay, scroll_delay_value))
2142 switch (scroll_direction)
2147 from_x -= preview.step_offset;
2148 from_x = (from_x < 0 ? 0 : from_x);
2151 scroll_direction = MV_UP;
2155 if (from_x < level_xsize - preview.xsize)
2157 from_x += preview.step_offset;
2158 from_x = (from_x > level_xsize - preview.xsize ?
2159 level_xsize - preview.xsize : from_x);
2162 scroll_direction = MV_DOWN;
2168 from_y -= preview.step_offset;
2169 from_y = (from_y < 0 ? 0 : from_y);
2172 scroll_direction = MV_RIGHT;
2176 if (from_y < level_ysize - preview.ysize)
2178 from_y += preview.step_offset;
2179 from_y = (from_y > level_ysize - preview.ysize ?
2180 level_ysize - preview.ysize : from_y);
2183 scroll_direction = MV_LEFT;
2190 DrawPreviewLevelExt(from_x, from_y);
2193 /* !!! THIS ALL SUCKS -- SHOULD BE CLEANLY REWRITTEN !!! */
2194 /* redraw micro level label, if needed */
2195 if (!strEqual(level.name, NAMELESS_LEVEL_NAME) &&
2196 !strEqual(level.author, ANONYMOUS_NAME) &&
2197 !strEqual(level.author, leveldir_current->name) &&
2198 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
2200 int max_label_counter = 23;
2202 if (leveldir_current->imported_from != NULL &&
2203 strlen(leveldir_current->imported_from) > 0)
2204 max_label_counter += 14;
2205 if (leveldir_current->imported_by != NULL &&
2206 strlen(leveldir_current->imported_by) > 0)
2207 max_label_counter += 14;
2209 label_counter = (label_counter + 1) % max_label_counter;
2210 label_state = (label_counter >= 0 && label_counter <= 7 ?
2211 MICROLABEL_LEVEL_NAME :
2212 label_counter >= 9 && label_counter <= 12 ?
2213 MICROLABEL_LEVEL_AUTHOR_HEAD :
2214 label_counter >= 14 && label_counter <= 21 ?
2215 MICROLABEL_LEVEL_AUTHOR :
2216 label_counter >= 23 && label_counter <= 26 ?
2217 MICROLABEL_IMPORTED_FROM_HEAD :
2218 label_counter >= 28 && label_counter <= 35 ?
2219 MICROLABEL_IMPORTED_FROM :
2220 label_counter >= 37 && label_counter <= 40 ?
2221 MICROLABEL_IMPORTED_BY_HEAD :
2222 label_counter >= 42 && label_counter <= 49 ?
2223 MICROLABEL_IMPORTED_BY : MICROLABEL_EMPTY);
2225 if (leveldir_current->imported_from == NULL &&
2226 (label_state == MICROLABEL_IMPORTED_FROM_HEAD ||
2227 label_state == MICROLABEL_IMPORTED_FROM))
2228 label_state = (label_state == MICROLABEL_IMPORTED_FROM_HEAD ?
2229 MICROLABEL_IMPORTED_BY_HEAD : MICROLABEL_IMPORTED_BY);
2231 DrawPreviewLevelLabelExt(label_state);
2234 game_status = last_game_status; /* restore current game status */
2237 inline void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
2238 int graphic, int sync_frame, int mask_mode)
2240 int frame = getGraphicAnimationFrame(graphic, sync_frame);
2242 if (mask_mode == USE_MASKING)
2243 DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
2245 DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
2248 inline void DrawGraphicAnimation(int x, int y, int graphic)
2250 int lx = LEVELX(x), ly = LEVELY(y);
2252 if (!IN_SCR_FIELD(x, y))
2255 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
2256 graphic, GfxFrame[lx][ly], NO_MASKING);
2257 MarkTileDirty(x, y);
2260 void DrawLevelGraphicAnimation(int x, int y, int graphic)
2262 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
2265 void DrawLevelElementAnimation(int x, int y, int element)
2267 int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
2269 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
2272 inline void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
2274 int sx = SCREENX(x), sy = SCREENY(y);
2276 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
2279 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
2282 DrawGraphicAnimation(sx, sy, graphic);
2285 if (GFX_CRUMBLED(TILE_GFX_ELEMENT(x, y)))
2286 DrawLevelFieldCrumbledSand(x, y);
2288 if (GFX_CRUMBLED(Feld[x][y]))
2289 DrawLevelFieldCrumbledSand(x, y);
2293 void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
2295 int sx = SCREENX(x), sy = SCREENY(y);
2298 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
2301 graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
2303 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
2306 DrawGraphicAnimation(sx, sy, graphic);
2308 if (GFX_CRUMBLED(element))
2309 DrawLevelFieldCrumbledSand(x, y);
2312 static int getPlayerGraphic(struct PlayerInfo *player, int move_dir)
2314 if (player->use_murphy)
2316 /* this works only because currently only one player can be "murphy" ... */
2317 static int last_horizontal_dir = MV_LEFT;
2318 int graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir);
2320 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
2321 last_horizontal_dir = move_dir;
2323 if (graphic == IMG_SP_MURPHY) /* undefined => use special graphic */
2325 int direction = (player->is_snapping ? move_dir : last_horizontal_dir);
2327 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
2333 return el_act_dir2img(player->artwork_element, player->GfxAction,move_dir);
2336 static boolean equalGraphics(int graphic1, int graphic2)
2338 struct GraphicInfo *g1 = &graphic_info[graphic1];
2339 struct GraphicInfo *g2 = &graphic_info[graphic2];
2341 return (g1->bitmap == g2->bitmap &&
2342 g1->src_x == g2->src_x &&
2343 g1->src_y == g2->src_y &&
2344 g1->anim_frames == g2->anim_frames &&
2345 g1->anim_delay == g2->anim_delay &&
2346 g1->anim_mode == g2->anim_mode);
2349 void DrawAllPlayers()
2353 for (i = 0; i < MAX_PLAYERS; i++)
2354 if (stored_player[i].active)
2355 DrawPlayer(&stored_player[i]);
2358 void DrawPlayerField(int x, int y)
2360 if (!IS_PLAYER(x, y))
2363 DrawPlayer(PLAYERINFO(x, y));
2366 void DrawPlayer(struct PlayerInfo *player)
2368 int jx = player->jx;
2369 int jy = player->jy;
2370 int move_dir = player->MovDir;
2371 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? +1 : 0);
2372 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? +1 : 0);
2373 int last_jx = (player->is_moving ? jx - dx : jx);
2374 int last_jy = (player->is_moving ? jy - dy : jy);
2375 int next_jx = jx + dx;
2376 int next_jy = jy + dy;
2377 boolean player_is_moving = (player->MovPos ? TRUE : FALSE);
2378 boolean player_is_opaque = FALSE;
2379 int sx = SCREENX(jx), sy = SCREENY(jy);
2380 int sxx = 0, syy = 0;
2381 int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
2383 int action = ACTION_DEFAULT;
2384 int last_player_graphic = getPlayerGraphic(player, move_dir);
2385 int last_player_frame = player->Frame;
2388 /* GfxElement[][] is set to the element the player is digging or collecting;
2389 remove also for off-screen player if the player is not moving anymore */
2390 if (IN_LEV_FIELD(jx, jy) && !player_is_moving)
2391 GfxElement[jx][jy] = EL_UNDEFINED;
2393 if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
2397 if (!IN_LEV_FIELD(jx, jy))
2399 printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
2400 printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
2401 printf("DrawPlayerField(): This should never happen!\n");
2406 if (element == EL_EXPLOSION)
2409 action = (player->is_pushing ? ACTION_PUSHING :
2410 player->is_digging ? ACTION_DIGGING :
2411 player->is_collecting ? ACTION_COLLECTING :
2412 player->is_moving ? ACTION_MOVING :
2413 player->is_snapping ? ACTION_SNAPPING :
2414 player->is_dropping ? ACTION_DROPPING :
2415 player->is_waiting ? player->action_waiting : ACTION_DEFAULT);
2417 if (player->is_waiting)
2418 move_dir = player->dir_waiting;
2420 InitPlayerGfxAnimation(player, action, move_dir);
2422 /* ----------------------------------------------------------------------- */
2423 /* draw things in the field the player is leaving, if needed */
2424 /* ----------------------------------------------------------------------- */
2426 if (player->is_moving)
2428 if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
2430 DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
2432 if (last_element == EL_DYNAMITE_ACTIVE ||
2433 last_element == EL_EM_DYNAMITE_ACTIVE ||
2434 last_element == EL_SP_DISK_RED_ACTIVE)
2435 DrawDynamite(last_jx, last_jy);
2437 DrawLevelFieldThruMask(last_jx, last_jy);
2439 else if (last_element == EL_DYNAMITE_ACTIVE ||
2440 last_element == EL_EM_DYNAMITE_ACTIVE ||
2441 last_element == EL_SP_DISK_RED_ACTIVE)
2442 DrawDynamite(last_jx, last_jy);
2444 /* !!! this is not enough to prevent flickering of players which are
2445 moving next to each others without a free tile between them -- this
2446 can only be solved by drawing all players layer by layer (first the
2447 background, then the foreground etc.) !!! => TODO */
2448 else if (!IS_PLAYER(last_jx, last_jy))
2449 DrawLevelField(last_jx, last_jy);
2452 DrawLevelField(last_jx, last_jy);
2455 if (player->is_pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
2456 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
2459 if (!IN_SCR_FIELD(sx, sy))
2462 /* ----------------------------------------------------------------------- */
2463 /* draw things behind the player, if needed */
2464 /* ----------------------------------------------------------------------- */
2467 DrawLevelElement(jx, jy, Back[jx][jy]);
2468 else if (IS_ACTIVE_BOMB(element))
2469 DrawLevelElement(jx, jy, EL_EMPTY);
2472 if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
2474 int old_element = GfxElement[jx][jy];
2475 int old_graphic = el_act_dir2img(old_element, action, move_dir);
2476 int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
2478 if (GFX_CRUMBLED(old_element))
2479 DrawLevelFieldCrumbledSandDigging(jx, jy, move_dir, player->StepFrame);
2481 DrawGraphic(sx, sy, old_graphic, frame);
2483 if (graphic_info[old_graphic].anim_mode & ANIM_OPAQUE_PLAYER)
2484 player_is_opaque = TRUE;
2488 GfxElement[jx][jy] = EL_UNDEFINED;
2490 /* make sure that pushed elements are drawn with correct frame rate */
2492 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
2494 if (player->is_pushing && player->is_moving && !IS_ANIM_MODE_CE(graphic))
2495 GfxFrame[jx][jy] = player->StepFrame;
2497 if (player->is_pushing && player->is_moving)
2498 GfxFrame[jx][jy] = player->StepFrame;
2501 DrawLevelField(jx, jy);
2505 /* ----------------------------------------------------------------------- */
2506 /* draw player himself */
2507 /* ----------------------------------------------------------------------- */
2509 graphic = getPlayerGraphic(player, move_dir);
2511 /* in the case of changed player action or direction, prevent the current
2512 animation frame from being restarted for identical animations */
2513 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
2514 player->Frame = last_player_frame;
2516 frame = getGraphicAnimationFrame(graphic, player->Frame);
2520 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
2521 sxx = player->GfxPos;
2523 syy = player->GfxPos;
2526 if (!setup.soft_scrolling && ScreenMovPos)
2529 if (player_is_opaque)
2530 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
2532 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
2534 if (SHIELD_ON(player))
2536 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
2537 IMG_SHIELD_NORMAL_ACTIVE);
2538 int frame = getGraphicAnimationFrame(graphic, -1);
2540 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
2543 /* ----------------------------------------------------------------------- */
2544 /* draw things the player is pushing, if needed */
2545 /* ----------------------------------------------------------------------- */
2548 printf("::: %d, %d [%d, %d] [%d]\n",
2549 player->is_pushing, player_is_moving, player->GfxAction,
2550 player->is_moving, player_is_moving);
2554 if (player->is_pushing && player->is_moving)
2556 int px = SCREENX(jx), py = SCREENY(jy);
2557 int pxx = (TILEX - ABS(sxx)) * dx;
2558 int pyy = (TILEY - ABS(syy)) * dy;
2559 int gfx_frame = GfxFrame[jx][jy];
2565 if (!IS_MOVING(jx, jy)) /* push movement already finished */
2567 element = Feld[next_jx][next_jy];
2568 gfx_frame = GfxFrame[next_jx][next_jy];
2571 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
2574 sync_frame = (IS_ANIM_MODE_CE(graphic) ? gfx_frame : player->StepFrame);
2575 frame = getGraphicAnimationFrame(graphic, sync_frame);
2577 frame = getGraphicAnimationFrame(graphic, player->StepFrame);
2580 /* draw background element under pushed element (like the Sokoban field) */
2581 if (Back[next_jx][next_jy])
2582 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
2584 /* masked drawing is needed for EMC style (double) movement graphics */
2585 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
2589 /* ----------------------------------------------------------------------- */
2590 /* draw things in front of player (active dynamite or dynabombs) */
2591 /* ----------------------------------------------------------------------- */
2593 if (IS_ACTIVE_BOMB(element))
2595 graphic = el2img(element);
2596 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
2598 if (game.emulation == EMU_SUPAPLEX)
2599 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
2601 DrawGraphicThruMask(sx, sy, graphic, frame);
2604 if (player_is_moving && last_element == EL_EXPLOSION)
2606 int element = (GfxElement[last_jx][last_jy] != EL_UNDEFINED ?
2607 GfxElement[last_jx][last_jy] : EL_EMPTY);
2608 int graphic = el_act2img(element, ACTION_EXPLODING);
2609 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
2610 int phase = ExplodePhase[last_jx][last_jy] - 1;
2611 int frame = getGraphicAnimationFrame(graphic, phase - delay);
2614 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
2617 /* ----------------------------------------------------------------------- */
2618 /* draw elements the player is just walking/passing through/under */
2619 /* ----------------------------------------------------------------------- */
2621 if (player_is_moving)
2623 /* handle the field the player is leaving ... */
2624 if (IS_ACCESSIBLE_INSIDE(last_element))
2625 DrawLevelField(last_jx, last_jy);
2626 else if (IS_ACCESSIBLE_UNDER(last_element))
2627 DrawLevelFieldThruMask(last_jx, last_jy);
2630 /* do not redraw accessible elements if the player is just pushing them */
2631 if (!player_is_moving || !player->is_pushing)
2633 /* ... and the field the player is entering */
2634 if (IS_ACCESSIBLE_INSIDE(element))
2635 DrawLevelField(jx, jy);
2636 else if (IS_ACCESSIBLE_UNDER(element))
2637 DrawLevelFieldThruMask(jx, jy);
2640 MarkTileDirty(sx, sy);
2643 /* ------------------------------------------------------------------------- */
2645 void WaitForEventToContinue()
2647 boolean still_wait = TRUE;
2649 /* simulate releasing mouse button over last gadget, if still pressed */
2651 HandleGadgets(-1, -1, 0);
2653 button_status = MB_RELEASED;
2669 case EVENT_BUTTONPRESS:
2670 case EVENT_KEYPRESS:
2674 case EVENT_KEYRELEASE:
2675 ClearPlayerAction();
2679 HandleOtherEvents(&event);
2683 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2690 /* don't eat all CPU time */
2695 #define MAX_REQUEST_LINES 13
2696 #define MAX_REQUEST_LINE_FONT1_LEN 7
2697 #define MAX_REQUEST_LINE_FONT2_LEN 10
2699 boolean Request(char *text, unsigned int req_state)
2701 int mx, my, ty, result = -1;
2702 unsigned int old_door_state;
2703 int last_game_status = game_status; /* save current game status */
2704 int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
2705 int font_nr = FONT_TEXT_2;
2706 int max_word_len = 0;
2709 for (text_ptr = text; *text_ptr; text_ptr++)
2711 max_word_len = (*text_ptr != ' ' ? max_word_len + 1 : 0);
2713 if (max_word_len > MAX_REQUEST_LINE_FONT1_LEN)
2715 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
2717 font_nr = FONT_TEXT_1;
2719 font_nr = FONT_LEVEL_NUMBER;
2726 if (game_status == GAME_MODE_PLAYING &&
2727 level.game_engine_type == GAME_ENGINE_TYPE_EM)
2728 BlitScreenToBitmap_EM(backbuffer);
2730 /* disable deactivated drawing when quick-loading level tape recording */
2731 if (tape.playing && tape.deactivate_display)
2732 TapeDeactivateDisplayOff(TRUE);
2734 SetMouseCursor(CURSOR_DEFAULT);
2736 #if defined(NETWORK_AVALIABLE)
2737 /* pause network game while waiting for request to answer */
2738 if (options.network &&
2739 game_status == GAME_MODE_PLAYING &&
2740 req_state & REQUEST_WAIT_FOR_INPUT)
2741 SendToServer_PausePlaying();
2744 old_door_state = GetDoorState();
2746 /* simulate releasing mouse button over last gadget, if still pressed */
2748 HandleGadgets(-1, -1, 0);
2752 if (old_door_state & DOOR_OPEN_1)
2754 CloseDoor(DOOR_CLOSE_1);
2756 /* save old door content */
2757 BlitBitmap(bitmap_db_door, bitmap_db_door,
2758 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
2759 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
2763 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
2766 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2768 /* clear door drawing field */
2769 DrawBackground(DX, DY, DXSIZE, DYSIZE);
2771 /* force DOOR font inside door area */
2772 game_status = GAME_MODE_PSEUDO_DOOR;
2774 /* write text for request */
2775 for (ty = 0; ty < MAX_REQUEST_LINES; ty++)
2777 char text_line[max_request_line_len + 1];
2783 for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
2786 if (!tc || tc == ' ')
2797 strncpy(text_line, text, tl);
2800 DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
2801 DY + 8 + ty * (getFontHeight(font_nr) + 2),
2802 text_line, font_nr);
2804 text += tl + (tc == ' ' ? 1 : 0);
2807 game_status = last_game_status; /* restore current game status */
2809 if (req_state & REQ_ASK)
2811 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
2812 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
2814 else if (req_state & REQ_CONFIRM)
2816 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
2818 else if (req_state & REQ_PLAYER)
2820 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
2821 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
2822 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
2823 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
2826 /* copy request gadgets to door backbuffer */
2827 BlitBitmap(drawto, bitmap_db_door,
2828 DX, DY, DXSIZE, DYSIZE,
2829 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2831 OpenDoor(DOOR_OPEN_1);
2833 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
2835 if (game_status == GAME_MODE_PLAYING)
2837 SetPanelBackground();
2838 SetDrawBackgroundMask(REDRAW_DOOR_1);
2842 SetDrawBackgroundMask(REDRAW_FIELD);
2848 if (game_status != GAME_MODE_MAIN)
2851 button_status = MB_RELEASED;
2853 request_gadget_id = -1;
2855 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2867 case EVENT_BUTTONPRESS:
2868 case EVENT_BUTTONRELEASE:
2869 case EVENT_MOTIONNOTIFY:
2871 if (event.type == EVENT_MOTIONNOTIFY)
2873 if (!PointerInWindow(window))
2874 continue; /* window and pointer are on different screens */
2879 motion_status = TRUE;
2880 mx = ((MotionEvent *) &event)->x;
2881 my = ((MotionEvent *) &event)->y;
2885 motion_status = FALSE;
2886 mx = ((ButtonEvent *) &event)->x;
2887 my = ((ButtonEvent *) &event)->y;
2888 if (event.type == EVENT_BUTTONPRESS)
2889 button_status = ((ButtonEvent *) &event)->button;
2891 button_status = MB_RELEASED;
2894 /* this sets 'request_gadget_id' */
2895 HandleGadgets(mx, my, button_status);
2897 switch (request_gadget_id)
2899 case TOOL_CTRL_ID_YES:
2902 case TOOL_CTRL_ID_NO:
2905 case TOOL_CTRL_ID_CONFIRM:
2906 result = TRUE | FALSE;
2909 case TOOL_CTRL_ID_PLAYER_1:
2912 case TOOL_CTRL_ID_PLAYER_2:
2915 case TOOL_CTRL_ID_PLAYER_3:
2918 case TOOL_CTRL_ID_PLAYER_4:
2929 case EVENT_KEYPRESS:
2930 switch (GetEventKey((KeyEvent *)&event, TRUE))
2933 if (req_state & REQ_CONFIRM)
2949 if (req_state & REQ_PLAYER)
2953 case EVENT_KEYRELEASE:
2954 ClearPlayerAction();
2958 HandleOtherEvents(&event);
2962 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2964 int joy = AnyJoystick();
2966 if (joy & JOY_BUTTON_1)
2968 else if (joy & JOY_BUTTON_2)
2974 if (game_status == GAME_MODE_PLAYING && local_player->LevelSolved_GameEnd)
2976 HandleGameActions();
2982 if (!PendingEvent()) /* delay only if no pending events */
2993 if (!PendingEvent()) /* delay only if no pending events */
2996 /* don't eat all CPU time */
3003 if (game_status != GAME_MODE_MAIN)
3008 if (!(req_state & REQ_STAY_OPEN))
3010 CloseDoor(DOOR_CLOSE_1);
3012 if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
3013 (req_state & REQ_REOPEN))
3014 OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
3019 if (game_status == GAME_MODE_PLAYING)
3021 SetPanelBackground();
3022 SetDrawBackgroundMask(REDRAW_DOOR_1);
3026 SetDrawBackgroundMask(REDRAW_FIELD);
3029 #if defined(NETWORK_AVALIABLE)
3030 /* continue network game after request */
3031 if (options.network &&
3032 game_status == GAME_MODE_PLAYING &&
3033 req_state & REQUEST_WAIT_FOR_INPUT)
3034 SendToServer_ContinuePlaying();
3037 /* restore deactivated drawing when quick-loading level tape recording */
3038 if (tape.playing && tape.deactivate_display)
3039 TapeDeactivateDisplayOn();
3044 unsigned int OpenDoor(unsigned int door_state)
3046 if (door_state & DOOR_COPY_BACK)
3048 if (door_state & DOOR_OPEN_1)
3049 BlitBitmap(bitmap_db_door, bitmap_db_door,
3050 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
3051 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
3053 if (door_state & DOOR_OPEN_2)
3054 BlitBitmap(bitmap_db_door, bitmap_db_door,
3055 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY2, VXSIZE, VYSIZE,
3056 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
3058 door_state &= ~DOOR_COPY_BACK;
3061 return MoveDoor(door_state);
3064 unsigned int CloseDoor(unsigned int door_state)
3066 unsigned int old_door_state = GetDoorState();
3068 if (!(door_state & DOOR_NO_COPY_BACK))
3070 if (old_door_state & DOOR_OPEN_1)
3071 BlitBitmap(backbuffer, bitmap_db_door,
3072 DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
3074 if (old_door_state & DOOR_OPEN_2)
3075 BlitBitmap(backbuffer, bitmap_db_door,
3076 VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
3078 door_state &= ~DOOR_NO_COPY_BACK;
3081 return MoveDoor(door_state);
3084 unsigned int GetDoorState()
3086 return MoveDoor(DOOR_GET_STATE);
3089 unsigned int SetDoorState(unsigned int door_state)
3091 return MoveDoor(door_state | DOOR_SET_STATE);
3094 unsigned int MoveDoor(unsigned int door_state)
3096 static int door1 = DOOR_OPEN_1;
3097 static int door2 = DOOR_CLOSE_2;
3098 unsigned long door_delay = 0;
3099 unsigned long door_delay_value;
3102 if (door_1.width < 0 || door_1.width > DXSIZE)
3103 door_1.width = DXSIZE;
3104 if (door_1.height < 0 || door_1.height > DYSIZE)
3105 door_1.height = DYSIZE;
3106 if (door_2.width < 0 || door_2.width > VXSIZE)
3107 door_2.width = VXSIZE;
3108 if (door_2.height < 0 || door_2.height > VYSIZE)
3109 door_2.height = VYSIZE;
3111 if (door_state == DOOR_GET_STATE)
3112 return (door1 | door2);
3114 if (door_state & DOOR_SET_STATE)
3116 if (door_state & DOOR_ACTION_1)
3117 door1 = door_state & DOOR_ACTION_1;
3118 if (door_state & DOOR_ACTION_2)
3119 door2 = door_state & DOOR_ACTION_2;
3121 return (door1 | door2);
3124 if (!(door_state & DOOR_FORCE_REDRAW))
3126 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
3127 door_state &= ~DOOR_OPEN_1;
3128 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
3129 door_state &= ~DOOR_CLOSE_1;
3130 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
3131 door_state &= ~DOOR_OPEN_2;
3132 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
3133 door_state &= ~DOOR_CLOSE_2;
3136 door_delay_value = (door_state & DOOR_ACTION_1 ? door_1.step_delay :
3139 if (setup.quick_doors)
3141 stepsize = 20; /* must be chosen to always draw last frame */
3142 door_delay_value = 0;
3145 if (global.autoplay_leveldir)
3147 door_state |= DOOR_NO_DELAY;
3148 door_state &= ~DOOR_CLOSE_ALL;
3151 if (door_state & DOOR_ACTION)
3153 boolean handle_door_1 = (door_state & DOOR_ACTION_1);
3154 boolean handle_door_2 = (door_state & DOOR_ACTION_2);
3155 boolean door_1_done = (!handle_door_1);
3156 boolean door_2_done = (!handle_door_2);
3157 boolean door_1_vertical = (door_1.anim_mode & ANIM_VERTICAL);
3158 boolean door_2_vertical = (door_2.anim_mode & ANIM_VERTICAL);
3159 int door_size_1 = (door_1_vertical ? door_1.height : door_1.width);
3160 int door_size_2 = (door_2_vertical ? door_2.height : door_2.width);
3161 int max_door_size_1 = (door_1_vertical ? DYSIZE : DXSIZE);
3162 int max_door_size_2 = (door_2_vertical ? VYSIZE : VXSIZE);
3163 int door_size = (handle_door_1 ? door_size_1 : door_size_2);
3164 int max_door_size = (handle_door_1 ? max_door_size_1 : max_door_size_2);
3165 int door_skip = max_door_size - door_size;
3166 int end = door_size;
3167 int start = ((door_state & DOOR_NO_DELAY) ? end : 0);
3170 if (!(door_state & DOOR_NO_DELAY) && !setup.quick_doors)
3172 /* opening door sound has priority over simultaneously closing door */
3173 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
3174 PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
3175 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
3176 PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
3179 for (k = start; k <= end && !(door_1_done && door_2_done); k += stepsize)
3182 Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
3183 GC gc = bitmap->stored_clip_gc;
3185 if (door_state & DOOR_ACTION_1)
3187 int a = MIN(x * door_1.step_offset, end);
3188 int p = (door_state & DOOR_OPEN_1 ? end - a : a);
3189 int i = p + door_skip;
3191 if (door_1.anim_mode & ANIM_STATIC_PANEL)
3193 BlitBitmap(bitmap_db_door, drawto,
3194 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1,
3195 DXSIZE, DYSIZE, DX, DY);
3199 BlitBitmap(bitmap_db_door, drawto,
3200 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + p / 2,
3201 DXSIZE, DYSIZE - p / 2, DX, DY);
3203 ClearRectangle(drawto, DX, DY + DYSIZE - p / 2, DXSIZE, p / 2);
3206 if (door_1.anim_mode & ANIM_HORIZONTAL && x <= DXSIZE)
3208 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
3209 int dst1_x = DX + DXSIZE - i, dst1_y = DY;
3210 int src2_x = DXSIZE - i, src2_y = DOOR_GFX_PAGEY1;
3211 int dst2_x = DX, dst2_y = DY;
3212 int width = i, height = DYSIZE;
3214 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3215 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3218 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3219 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3222 else if (door_1.anim_mode & ANIM_VERTICAL && x <= DYSIZE)
3224 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
3225 int dst1_x = DX, dst1_y = DY + DYSIZE - i;
3226 int src2_x = 0, src2_y = DOOR_GFX_PAGEY1 + DYSIZE - i;
3227 int dst2_x = DX, dst2_y = DY;
3228 int width = DXSIZE, height = i;
3230 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3231 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3234 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3235 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3238 else if (x <= DXSIZE) /* ANIM_DEFAULT */
3240 int j = (door_1.anim_mode == ANIM_DEFAULT ? (DXSIZE - i) / 3 : 0);
3242 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
3243 BlitBitmapMasked(bitmap, drawto,
3244 DXSIZE, DOOR_GFX_PAGEY1, i, 77,
3245 DX + DXSIZE - i, DY + j);
3246 BlitBitmapMasked(bitmap, drawto,
3247 DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
3248 DX + DXSIZE - i, DY + 140 + j);
3249 SetClipOrigin(bitmap, gc, DX - DXSIZE + i,
3250 DY - (DOOR_GFX_PAGEY1 + j));
3251 BlitBitmapMasked(bitmap, drawto,
3252 DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
3254 BlitBitmapMasked(bitmap, drawto,
3255 DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
3258 BlitBitmapMasked(bitmap, drawto,
3259 DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
3261 BlitBitmapMasked(bitmap, drawto,
3262 DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
3264 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
3265 BlitBitmapMasked(bitmap, drawto,
3266 DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
3267 DX + DXSIZE - i, DY + 77 + j);
3268 BlitBitmapMasked(bitmap, drawto,
3269 DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
3270 DX + DXSIZE - i, DY + 203 + j);
3273 redraw_mask |= REDRAW_DOOR_1;
3274 door_1_done = (a == end);
3277 if (door_state & DOOR_ACTION_2)
3279 int a = MIN(x * door_2.step_offset, door_size);
3280 int p = (door_state & DOOR_OPEN_2 ? door_size - a : a);
3281 int i = p + door_skip;
3283 if (door_2.anim_mode & ANIM_STATIC_PANEL)
3285 BlitBitmap(bitmap_db_door, drawto,
3286 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2,
3287 VXSIZE, VYSIZE, VX, VY);
3289 else if (x <= VYSIZE)
3291 BlitBitmap(bitmap_db_door, drawto,
3292 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + p / 2,
3293 VXSIZE, VYSIZE - p / 2, VX, VY);
3295 ClearRectangle(drawto, VX, VY + VYSIZE - p / 2, VXSIZE, p / 2);
3298 if (door_2.anim_mode & ANIM_HORIZONTAL && x <= VXSIZE)
3300 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
3301 int dst1_x = VX + VXSIZE - i, dst1_y = VY;
3302 int src2_x = VXSIZE - i, src2_y = DOOR_GFX_PAGEY2;
3303 int dst2_x = VX, dst2_y = VY;
3304 int width = i, height = VYSIZE;
3306 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3307 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3310 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3311 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3314 else if (door_2.anim_mode & ANIM_VERTICAL && x <= VYSIZE)
3316 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
3317 int dst1_x = VX, dst1_y = VY + VYSIZE - i;
3318 int src2_x = 0, src2_y = DOOR_GFX_PAGEY2 + VYSIZE - i;
3319 int dst2_x = VX, dst2_y = VY;
3320 int width = VXSIZE, height = i;
3322 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3323 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3326 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3327 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3330 else if (x <= VXSIZE) /* ANIM_DEFAULT */
3332 int j = (door_2.anim_mode == ANIM_DEFAULT ? (VXSIZE - i) / 3 : 0);
3334 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
3335 BlitBitmapMasked(bitmap, drawto,
3336 VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
3337 VX + VXSIZE - i, VY + j);
3338 SetClipOrigin(bitmap, gc,
3339 VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
3340 BlitBitmapMasked(bitmap, drawto,
3341 VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
3344 BlitBitmapMasked(bitmap, drawto,
3345 VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
3346 i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
3347 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
3348 BlitBitmapMasked(bitmap, drawto,
3349 VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
3351 VX + VXSIZE - i, VY + VYSIZE / 2 + j);
3354 redraw_mask |= REDRAW_DOOR_2;
3355 door_2_done = (a == VXSIZE);
3358 if (!(door_state & DOOR_NO_DELAY))
3362 if (game_status == GAME_MODE_MAIN)
3365 WaitUntilDelayReached(&door_delay, door_delay_value);
3370 if (door_state & DOOR_ACTION_1)
3371 door1 = door_state & DOOR_ACTION_1;
3372 if (door_state & DOOR_ACTION_2)
3373 door2 = door_state & DOOR_ACTION_2;
3375 return (door1 | door2);
3378 void DrawSpecialEditorDoor()
3380 /* draw bigger toolbox window */
3381 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
3382 DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
3384 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
3385 EX - 6, VY - 4, EXSIZE + 12, EYSIZE - VYSIZE + 4,
3388 redraw_mask |= REDRAW_ALL;
3391 void UndrawSpecialEditorDoor()
3393 /* draw normal tape recorder window */
3394 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
3395 EX - 6, EY - 12, EXSIZE + 12, EYSIZE - VYSIZE + 12,
3398 redraw_mask |= REDRAW_ALL;
3402 /* ---------- new tool button stuff ---------------------------------------- */
3404 /* graphic position values for tool buttons */
3405 #define TOOL_BUTTON_YES_XPOS 2
3406 #define TOOL_BUTTON_YES_YPOS 250
3407 #define TOOL_BUTTON_YES_GFX_YPOS 0
3408 #define TOOL_BUTTON_YES_XSIZE 46
3409 #define TOOL_BUTTON_YES_YSIZE 28
3410 #define TOOL_BUTTON_NO_XPOS 52
3411 #define TOOL_BUTTON_NO_YPOS TOOL_BUTTON_YES_YPOS
3412 #define TOOL_BUTTON_NO_GFX_YPOS TOOL_BUTTON_YES_GFX_YPOS
3413 #define TOOL_BUTTON_NO_XSIZE TOOL_BUTTON_YES_XSIZE
3414 #define TOOL_BUTTON_NO_YSIZE TOOL_BUTTON_YES_YSIZE
3415 #define TOOL_BUTTON_CONFIRM_XPOS TOOL_BUTTON_YES_XPOS
3416 #define TOOL_BUTTON_CONFIRM_YPOS TOOL_BUTTON_YES_YPOS
3417 #define TOOL_BUTTON_CONFIRM_GFX_YPOS 30
3418 #define TOOL_BUTTON_CONFIRM_XSIZE 96
3419 #define TOOL_BUTTON_CONFIRM_YSIZE TOOL_BUTTON_YES_YSIZE
3420 #define TOOL_BUTTON_PLAYER_XSIZE 30
3421 #define TOOL_BUTTON_PLAYER_YSIZE 30
3422 #define TOOL_BUTTON_PLAYER_GFX_XPOS 5
3423 #define TOOL_BUTTON_PLAYER_GFX_YPOS 185
3424 #define TOOL_BUTTON_PLAYER_XPOS (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
3425 #define TOOL_BUTTON_PLAYER_YPOS (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
3426 #define TOOL_BUTTON_PLAYER1_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3427 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
3428 #define TOOL_BUTTON_PLAYER2_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3429 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
3430 #define TOOL_BUTTON_PLAYER3_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3431 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
3432 #define TOOL_BUTTON_PLAYER4_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3433 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
3434 #define TOOL_BUTTON_PLAYER1_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3435 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
3436 #define TOOL_BUTTON_PLAYER2_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3437 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
3438 #define TOOL_BUTTON_PLAYER3_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3439 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
3440 #define TOOL_BUTTON_PLAYER4_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3441 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
3450 } toolbutton_info[NUM_TOOL_BUTTONS] =
3453 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_GFX_YPOS,
3454 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_YPOS,
3455 TOOL_BUTTON_YES_XSIZE, TOOL_BUTTON_YES_YSIZE,
3460 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_GFX_YPOS,
3461 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_YPOS,
3462 TOOL_BUTTON_NO_XSIZE, TOOL_BUTTON_NO_YSIZE,
3467 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_GFX_YPOS,
3468 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_YPOS,
3469 TOOL_BUTTON_CONFIRM_XSIZE, TOOL_BUTTON_CONFIRM_YSIZE,
3470 TOOL_CTRL_ID_CONFIRM,
3474 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3475 TOOL_BUTTON_PLAYER1_XPOS, TOOL_BUTTON_PLAYER1_YPOS,
3476 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3477 TOOL_CTRL_ID_PLAYER_1,
3481 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3482 TOOL_BUTTON_PLAYER2_XPOS, TOOL_BUTTON_PLAYER2_YPOS,
3483 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3484 TOOL_CTRL_ID_PLAYER_2,
3488 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3489 TOOL_BUTTON_PLAYER3_XPOS, TOOL_BUTTON_PLAYER3_YPOS,
3490 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3491 TOOL_CTRL_ID_PLAYER_3,
3495 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3496 TOOL_BUTTON_PLAYER4_XPOS, TOOL_BUTTON_PLAYER4_YPOS,
3497 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3498 TOOL_CTRL_ID_PLAYER_4,
3503 void CreateToolButtons()
3507 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3509 Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
3510 Bitmap *deco_bitmap = None;
3511 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
3512 struct GadgetInfo *gi;
3513 unsigned long event_mask;
3514 int gd_xoffset, gd_yoffset;
3515 int gd_x1, gd_x2, gd_y;
3518 event_mask = GD_EVENT_RELEASED;
3520 gd_xoffset = toolbutton_info[i].xpos;
3521 gd_yoffset = toolbutton_info[i].ypos;
3522 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
3523 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
3524 gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
3526 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
3528 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
3530 getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr),
3531 &deco_bitmap, &deco_x, &deco_y);
3532 deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
3533 deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
3536 gi = CreateGadget(GDI_CUSTOM_ID, id,
3537 GDI_INFO_TEXT, toolbutton_info[i].infotext,
3538 GDI_X, DX + toolbutton_info[i].x,
3539 GDI_Y, DY + toolbutton_info[i].y,
3540 GDI_WIDTH, toolbutton_info[i].width,
3541 GDI_HEIGHT, toolbutton_info[i].height,
3542 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
3543 GDI_STATE, GD_BUTTON_UNPRESSED,
3544 GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
3545 GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
3546 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
3547 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
3548 GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
3549 GDI_DECORATION_SHIFTING, 1, 1,
3550 GDI_DIRECT_DRAW, FALSE,
3551 GDI_EVENT_MASK, event_mask,
3552 GDI_CALLBACK_ACTION, HandleToolButtons,
3556 Error(ERR_EXIT, "cannot create gadget");
3558 tool_gadget[id] = gi;
3562 void FreeToolButtons()
3566 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3567 FreeGadget(tool_gadget[i]);
3570 static void UnmapToolButtons()
3574 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3575 UnmapGadget(tool_gadget[i]);
3578 static void HandleToolButtons(struct GadgetInfo *gi)
3580 request_gadget_id = gi->custom_id;
3583 static struct Mapping_EM_to_RND_object
3586 boolean is_rnd_to_em_mapping; /* unique mapping EM <-> RND */
3587 boolean is_backside; /* backside of moving element */
3593 em_object_mapping_list[] =
3596 Xblank, TRUE, FALSE,
3600 Yacid_splash_eB, FALSE, FALSE,
3601 EL_ACID_SPLASH_RIGHT, -1, -1
3604 Yacid_splash_wB, FALSE, FALSE,
3605 EL_ACID_SPLASH_LEFT, -1, -1
3608 #ifdef EM_ENGINE_BAD_ROLL
3610 Xstone_force_e, FALSE, FALSE,
3611 EL_ROCK, -1, MV_BIT_RIGHT
3614 Xstone_force_w, FALSE, FALSE,
3615 EL_ROCK, -1, MV_BIT_LEFT
3618 Xnut_force_e, FALSE, FALSE,
3619 EL_NUT, -1, MV_BIT_RIGHT
3622 Xnut_force_w, FALSE, FALSE,
3623 EL_NUT, -1, MV_BIT_LEFT
3626 Xspring_force_e, FALSE, FALSE,
3627 EL_SPRING, -1, MV_BIT_RIGHT
3630 Xspring_force_w, FALSE, FALSE,
3631 EL_SPRING, -1, MV_BIT_LEFT
3634 Xemerald_force_e, FALSE, FALSE,
3635 EL_EMERALD, -1, MV_BIT_RIGHT
3638 Xemerald_force_w, FALSE, FALSE,
3639 EL_EMERALD, -1, MV_BIT_LEFT
3642 Xdiamond_force_e, FALSE, FALSE,
3643 EL_DIAMOND, -1, MV_BIT_RIGHT
3646 Xdiamond_force_w, FALSE, FALSE,
3647 EL_DIAMOND, -1, MV_BIT_LEFT
3650 Xbomb_force_e, FALSE, FALSE,
3651 EL_BOMB, -1, MV_BIT_RIGHT
3654 Xbomb_force_w, FALSE, FALSE,
3655 EL_BOMB, -1, MV_BIT_LEFT
3657 #endif /* EM_ENGINE_BAD_ROLL */
3660 Xstone, TRUE, FALSE,
3664 Xstone_pause, FALSE, FALSE,
3668 Xstone_fall, FALSE, FALSE,
3672 Ystone_s, FALSE, FALSE,
3673 EL_ROCK, ACTION_FALLING, -1
3676 Ystone_sB, FALSE, TRUE,
3677 EL_ROCK, ACTION_FALLING, -1
3680 Ystone_e, FALSE, FALSE,
3681 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
3684 Ystone_eB, FALSE, TRUE,
3685 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
3688 Ystone_w, FALSE, FALSE,
3689 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
3692 Ystone_wB, FALSE, TRUE,
3693 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
3700 Xnut_pause, FALSE, FALSE,
3704 Xnut_fall, FALSE, FALSE,
3708 Ynut_s, FALSE, FALSE,
3709 EL_NUT, ACTION_FALLING, -1
3712 Ynut_sB, FALSE, TRUE,
3713 EL_NUT, ACTION_FALLING, -1
3716 Ynut_e, FALSE, FALSE,
3717 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
3720 Ynut_eB, FALSE, TRUE,
3721 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
3724 Ynut_w, FALSE, FALSE,
3725 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
3728 Ynut_wB, FALSE, TRUE,
3729 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
3732 Xbug_n, TRUE, FALSE,
3736 Xbug_e, TRUE, FALSE,
3737 EL_BUG_RIGHT, -1, -1
3740 Xbug_s, TRUE, FALSE,
3744 Xbug_w, TRUE, FALSE,
3748 Xbug_gon, FALSE, FALSE,
3752 Xbug_goe, FALSE, FALSE,
3753 EL_BUG_RIGHT, -1, -1
3756 Xbug_gos, FALSE, FALSE,
3760 Xbug_gow, FALSE, FALSE,
3764 Ybug_n, FALSE, FALSE,
3765 EL_BUG, ACTION_MOVING, MV_BIT_UP
3768 Ybug_nB, FALSE, TRUE,
3769 EL_BUG, ACTION_MOVING, MV_BIT_UP
3772 Ybug_e, FALSE, FALSE,
3773 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
3776 Ybug_eB, FALSE, TRUE,
3777 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
3780 Ybug_s, FALSE, FALSE,
3781 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
3784 Ybug_sB, FALSE, TRUE,
3785 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
3788 Ybug_w, FALSE, FALSE,
3789 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
3792 Ybug_wB, FALSE, TRUE,
3793 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
3796 Ybug_w_n, FALSE, FALSE,
3797 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
3800 Ybug_n_e, FALSE, FALSE,
3801 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
3804 Ybug_e_s, FALSE, FALSE,
3805 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
3808 Ybug_s_w, FALSE, FALSE,
3809 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
3812 Ybug_e_n, FALSE, FALSE,
3813 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
3816 Ybug_s_e, FALSE, FALSE,
3817 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
3820 Ybug_w_s, FALSE, FALSE,
3821 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
3824 Ybug_n_w, FALSE, FALSE,
3825 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
3828 Ybug_stone, FALSE, FALSE,
3829 EL_BUG, ACTION_SMASHED_BY_ROCK, -1
3832 Ybug_spring, FALSE, FALSE,
3833 EL_BUG, ACTION_SMASHED_BY_SPRING, -1
3836 Xtank_n, TRUE, FALSE,
3837 EL_SPACESHIP_UP, -1, -1
3840 Xtank_e, TRUE, FALSE,
3841 EL_SPACESHIP_RIGHT, -1, -1
3844 Xtank_s, TRUE, FALSE,
3845 EL_SPACESHIP_DOWN, -1, -1
3848 Xtank_w, TRUE, FALSE,
3849 EL_SPACESHIP_LEFT, -1, -1
3852 Xtank_gon, FALSE, FALSE,
3853 EL_SPACESHIP_UP, -1, -1
3856 Xtank_goe, FALSE, FALSE,
3857 EL_SPACESHIP_RIGHT, -1, -1
3860 Xtank_gos, FALSE, FALSE,
3861 EL_SPACESHIP_DOWN, -1, -1
3864 Xtank_gow, FALSE, FALSE,
3865 EL_SPACESHIP_LEFT, -1, -1
3868 Ytank_n, FALSE, FALSE,
3869 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
3872 Ytank_nB, FALSE, TRUE,
3873 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
3876 Ytank_e, FALSE, FALSE,
3877 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
3880 Ytank_eB, FALSE, TRUE,
3881 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
3884 Ytank_s, FALSE, FALSE,
3885 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
3888 Ytank_sB, FALSE, TRUE,
3889 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
3892 Ytank_w, FALSE, FALSE,
3893 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
3896 Ytank_wB, FALSE, TRUE,
3897 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
3900 Ytank_w_n, FALSE, FALSE,
3901 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
3904 Ytank_n_e, FALSE, FALSE,
3905 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
3908 Ytank_e_s, FALSE, FALSE,
3909 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
3912 Ytank_s_w, FALSE, FALSE,
3913 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
3916 Ytank_e_n, FALSE, FALSE,
3917 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
3920 Ytank_s_e, FALSE, FALSE,
3921 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
3924 Ytank_w_s, FALSE, FALSE,
3925 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
3928 Ytank_n_w, FALSE, FALSE,
3929 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
3932 Ytank_stone, FALSE, FALSE,
3933 EL_SPACESHIP, ACTION_SMASHED_BY_ROCK, -1
3936 Ytank_spring, FALSE, FALSE,
3937 EL_SPACESHIP, ACTION_SMASHED_BY_SPRING, -1
3940 Xandroid, TRUE, FALSE,
3941 EL_EMC_ANDROID, ACTION_ACTIVE, -1
3944 Xandroid_1_n, FALSE, FALSE,
3945 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
3948 Xandroid_2_n, FALSE, FALSE,
3949 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
3952 Xandroid_1_e, FALSE, FALSE,
3953 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
3956 Xandroid_2_e, FALSE, FALSE,
3957 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
3960 Xandroid_1_w, FALSE, FALSE,
3961 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
3964 Xandroid_2_w, FALSE, FALSE,
3965 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
3968 Xandroid_1_s, FALSE, FALSE,
3969 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
3972 Xandroid_2_s, FALSE, FALSE,
3973 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
3976 Yandroid_n, FALSE, FALSE,
3977 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
3980 Yandroid_nB, FALSE, TRUE,
3981 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
3984 Yandroid_ne, FALSE, FALSE,
3985 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPRIGHT
3988 Yandroid_neB, FALSE, TRUE,
3989 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPRIGHT
3992 Yandroid_e, FALSE, FALSE,
3993 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
3996 Yandroid_eB, FALSE, TRUE,
3997 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
4000 Yandroid_se, FALSE, FALSE,
4001 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNRIGHT
4004 Yandroid_seB, FALSE, TRUE,
4005 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNRIGHT
4008 Yandroid_s, FALSE, FALSE,
4009 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
4012 Yandroid_sB, FALSE, TRUE,
4013 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
4016 Yandroid_sw, FALSE, FALSE,
4017 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNLEFT
4020 Yandroid_swB, FALSE, TRUE,
4021 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNLEFT
4024 Yandroid_w, FALSE, FALSE,
4025 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
4028 Yandroid_wB, FALSE, TRUE,
4029 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
4032 Yandroid_nw, FALSE, FALSE,
4033 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPLEFT
4036 Yandroid_nwB, FALSE, TRUE,
4037 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPLEFT
4040 Xspring, TRUE, FALSE,
4044 Xspring_pause, FALSE, FALSE,
4048 Xspring_e, FALSE, FALSE,
4052 Xspring_w, FALSE, FALSE,
4056 Xspring_fall, FALSE, FALSE,
4060 Yspring_s, FALSE, FALSE,
4061 EL_SPRING, ACTION_FALLING, -1
4064 Yspring_sB, FALSE, TRUE,
4065 EL_SPRING, ACTION_FALLING, -1
4068 Yspring_e, FALSE, FALSE,
4069 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
4072 Yspring_eB, FALSE, TRUE,
4073 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
4076 Yspring_w, FALSE, FALSE,
4077 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
4080 Yspring_wB, FALSE, TRUE,
4081 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
4084 Yspring_kill_e, FALSE, FALSE,
4085 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
4088 Yspring_kill_eB, FALSE, TRUE,
4089 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
4092 Yspring_kill_w, FALSE, FALSE,
4093 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
4096 Yspring_kill_wB, FALSE, TRUE,
4097 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
4100 Xeater_n, TRUE, FALSE,
4101 EL_YAMYAM_UP, -1, -1
4104 Xeater_e, TRUE, FALSE,
4105 EL_YAMYAM_RIGHT, -1, -1
4108 Xeater_w, TRUE, FALSE,
4109 EL_YAMYAM_LEFT, -1, -1
4112 Xeater_s, TRUE, FALSE,
4113 EL_YAMYAM_DOWN, -1, -1
4116 Yeater_n, FALSE, FALSE,
4117 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
4120 Yeater_nB, FALSE, TRUE,
4121 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
4124 Yeater_e, FALSE, FALSE,
4125 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
4128 Yeater_eB, FALSE, TRUE,
4129 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
4132 Yeater_s, FALSE, FALSE,
4133 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
4136 Yeater_sB, FALSE, TRUE,
4137 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
4140 Yeater_w, FALSE, FALSE,
4141 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
4144 Yeater_wB, FALSE, TRUE,
4145 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
4148 Yeater_stone, FALSE, FALSE,
4149 EL_YAMYAM, ACTION_SMASHED_BY_ROCK, -1
4152 Yeater_spring, FALSE, FALSE,
4153 EL_YAMYAM, ACTION_SMASHED_BY_SPRING, -1
4156 Xalien, TRUE, FALSE,
4160 Xalien_pause, FALSE, FALSE,
4164 Yalien_n, FALSE, FALSE,
4165 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
4168 Yalien_nB, FALSE, TRUE,
4169 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
4172 Yalien_e, FALSE, FALSE,
4173 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
4176 Yalien_eB, FALSE, TRUE,
4177 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
4180 Yalien_s, FALSE, FALSE,
4181 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
4184 Yalien_sB, FALSE, TRUE,
4185 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
4188 Yalien_w, FALSE, FALSE,
4189 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
4192 Yalien_wB, FALSE, TRUE,
4193 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
4196 Yalien_stone, FALSE, FALSE,
4197 EL_ROBOT, ACTION_SMASHED_BY_ROCK, -1
4200 Yalien_spring, FALSE, FALSE,
4201 EL_ROBOT, ACTION_SMASHED_BY_SPRING, -1
4204 Xemerald, TRUE, FALSE,
4208 Xemerald_pause, FALSE, FALSE,
4212 Xemerald_fall, FALSE, FALSE,
4216 Xemerald_shine, FALSE, FALSE,
4217 EL_EMERALD, ACTION_TWINKLING, -1
4220 Yemerald_s, FALSE, FALSE,
4221 EL_EMERALD, ACTION_FALLING, -1
4224 Yemerald_sB, FALSE, TRUE,
4225 EL_EMERALD, ACTION_FALLING, -1
4228 Yemerald_e, FALSE, FALSE,
4229 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
4232 Yemerald_eB, FALSE, TRUE,
4233 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
4236 Yemerald_w, FALSE, FALSE,
4237 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
4240 Yemerald_wB, FALSE, TRUE,
4241 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
4244 Yemerald_eat, FALSE, FALSE,
4245 EL_EMERALD, ACTION_COLLECTING, -1
4248 Yemerald_stone, FALSE, FALSE,
4249 EL_NUT, ACTION_BREAKING, -1
4252 Xdiamond, TRUE, FALSE,
4256 Xdiamond_pause, FALSE, FALSE,
4260 Xdiamond_fall, FALSE, FALSE,
4264 Xdiamond_shine, FALSE, FALSE,
4265 EL_DIAMOND, ACTION_TWINKLING, -1
4268 Ydiamond_s, FALSE, FALSE,
4269 EL_DIAMOND, ACTION_FALLING, -1
4272 Ydiamond_sB, FALSE, TRUE,
4273 EL_DIAMOND, ACTION_FALLING, -1
4276 Ydiamond_e, FALSE, FALSE,
4277 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
4280 Ydiamond_eB, FALSE, TRUE,
4281 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
4284 Ydiamond_w, FALSE, FALSE,
4285 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
4288 Ydiamond_wB, FALSE, TRUE,
4289 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
4292 Ydiamond_eat, FALSE, FALSE,
4293 EL_DIAMOND, ACTION_COLLECTING, -1
4296 Ydiamond_stone, FALSE, FALSE,
4297 EL_DIAMOND, ACTION_SMASHED_BY_ROCK, -1
4300 Xdrip_fall, TRUE, FALSE,
4301 EL_AMOEBA_DROP, -1, -1
4304 Xdrip_stretch, FALSE, FALSE,
4305 EL_AMOEBA_DROP, ACTION_FALLING, -1
4308 Xdrip_stretchB, FALSE, TRUE,
4309 EL_AMOEBA_DROP, ACTION_FALLING, -1
4312 Xdrip_eat, FALSE, FALSE,
4313 EL_AMOEBA_DROP, ACTION_GROWING, -1
4316 Ydrip_s1, FALSE, FALSE,
4317 EL_AMOEBA_DROP, ACTION_FALLING, -1
4320 Ydrip_s1B, FALSE, TRUE,
4321 EL_AMOEBA_DROP, ACTION_FALLING, -1
4324 Ydrip_s2, FALSE, FALSE,
4325 EL_AMOEBA_DROP, ACTION_FALLING, -1
4328 Ydrip_s2B, FALSE, TRUE,
4329 EL_AMOEBA_DROP, ACTION_FALLING, -1
4336 Xbomb_pause, FALSE, FALSE,
4340 Xbomb_fall, FALSE, FALSE,
4344 Ybomb_s, FALSE, FALSE,
4345 EL_BOMB, ACTION_FALLING, -1
4348 Ybomb_sB, FALSE, TRUE,
4349 EL_BOMB, ACTION_FALLING, -1
4352 Ybomb_e, FALSE, FALSE,
4353 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
4356 Ybomb_eB, FALSE, TRUE,
4357 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
4360 Ybomb_w, FALSE, FALSE,
4361 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
4364 Ybomb_wB, FALSE, TRUE,
4365 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
4368 Ybomb_eat, FALSE, FALSE,
4369 EL_BOMB, ACTION_ACTIVATING, -1
4372 Xballoon, TRUE, FALSE,
4376 Yballoon_n, FALSE, FALSE,
4377 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
4380 Yballoon_nB, FALSE, TRUE,
4381 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
4384 Yballoon_e, FALSE, FALSE,
4385 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
4388 Yballoon_eB, FALSE, TRUE,
4389 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
4392 Yballoon_s, FALSE, FALSE,
4393 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
4396 Yballoon_sB, FALSE, TRUE,
4397 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
4400 Yballoon_w, FALSE, FALSE,
4401 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
4404 Yballoon_wB, FALSE, TRUE,
4405 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
4408 Xgrass, TRUE, FALSE,
4409 EL_EMC_GRASS, -1, -1
4412 Ygrass_nB, FALSE, FALSE,
4413 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_UP
4416 Ygrass_eB, FALSE, FALSE,
4417 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_RIGHT
4420 Ygrass_sB, FALSE, FALSE,
4421 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_DOWN
4424 Ygrass_wB, FALSE, FALSE,
4425 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_LEFT
4432 Ydirt_nB, FALSE, FALSE,
4433 EL_SAND, ACTION_DIGGING, MV_BIT_UP
4436 Ydirt_eB, FALSE, FALSE,
4437 EL_SAND, ACTION_DIGGING, MV_BIT_RIGHT
4440 Ydirt_sB, FALSE, FALSE,
4441 EL_SAND, ACTION_DIGGING, MV_BIT_DOWN
4444 Ydirt_wB, FALSE, FALSE,
4445 EL_SAND, ACTION_DIGGING, MV_BIT_LEFT
4448 Xacid_ne, TRUE, FALSE,
4449 EL_ACID_POOL_TOPRIGHT, -1, -1
4452 Xacid_se, TRUE, FALSE,
4453 EL_ACID_POOL_BOTTOMRIGHT, -1, -1
4456 Xacid_s, TRUE, FALSE,
4457 EL_ACID_POOL_BOTTOM, -1, -1
4460 Xacid_sw, TRUE, FALSE,
4461 EL_ACID_POOL_BOTTOMLEFT, -1, -1
4464 Xacid_nw, TRUE, FALSE,
4465 EL_ACID_POOL_TOPLEFT, -1, -1
4468 Xacid_1, TRUE, FALSE,
4472 Xacid_2, FALSE, FALSE,
4476 Xacid_3, FALSE, FALSE,
4480 Xacid_4, FALSE, FALSE,
4484 Xacid_5, FALSE, FALSE,
4488 Xacid_6, FALSE, FALSE,
4492 Xacid_7, FALSE, FALSE,
4496 Xacid_8, FALSE, FALSE,
4500 Xball_1, TRUE, FALSE,
4501 EL_EMC_MAGIC_BALL, -1, -1
4504 Xball_1B, FALSE, FALSE,
4505 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4508 Xball_2, FALSE, FALSE,
4509 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4512 Xball_2B, FALSE, FALSE,
4513 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4516 Yball_eat, FALSE, FALSE,
4517 EL_EMC_MAGIC_BALL, ACTION_DROPPING, -1
4520 Ykey_1_eat, FALSE, FALSE,
4521 EL_EM_KEY_1, ACTION_COLLECTING, -1
4524 Ykey_2_eat, FALSE, FALSE,
4525 EL_EM_KEY_2, ACTION_COLLECTING, -1
4528 Ykey_3_eat, FALSE, FALSE,
4529 EL_EM_KEY_3, ACTION_COLLECTING, -1
4532 Ykey_4_eat, FALSE, FALSE,
4533 EL_EM_KEY_4, ACTION_COLLECTING, -1
4536 Ykey_5_eat, FALSE, FALSE,
4537 EL_EMC_KEY_5, ACTION_COLLECTING, -1
4540 Ykey_6_eat, FALSE, FALSE,
4541 EL_EMC_KEY_6, ACTION_COLLECTING, -1
4544 Ykey_7_eat, FALSE, FALSE,
4545 EL_EMC_KEY_7, ACTION_COLLECTING, -1
4548 Ykey_8_eat, FALSE, FALSE,
4549 EL_EMC_KEY_8, ACTION_COLLECTING, -1
4552 Ylenses_eat, FALSE, FALSE,
4553 EL_EMC_LENSES, ACTION_COLLECTING, -1
4556 Ymagnify_eat, FALSE, FALSE,
4557 EL_EMC_MAGNIFIER, ACTION_COLLECTING, -1
4560 Ygrass_eat, FALSE, FALSE,
4561 EL_EMC_GRASS, ACTION_SNAPPING, -1
4564 Ydirt_eat, FALSE, FALSE,
4565 EL_SAND, ACTION_SNAPPING, -1
4568 Xgrow_ns, TRUE, FALSE,
4569 EL_EXPANDABLE_WALL_VERTICAL, -1, -1
4572 Ygrow_ns_eat, FALSE, FALSE,
4573 EL_EXPANDABLE_WALL_VERTICAL, ACTION_GROWING, -1
4576 Xgrow_ew, TRUE, FALSE,
4577 EL_EXPANDABLE_WALL_HORIZONTAL, -1, -1
4580 Ygrow_ew_eat, FALSE, FALSE,
4581 EL_EXPANDABLE_WALL_HORIZONTAL, ACTION_GROWING, -1
4584 Xwonderwall, TRUE, FALSE,
4585 EL_MAGIC_WALL, -1, -1
4588 XwonderwallB, FALSE, FALSE,
4589 EL_MAGIC_WALL, ACTION_ACTIVE, -1
4592 Xamoeba_1, TRUE, FALSE,
4593 EL_AMOEBA_DRY, ACTION_OTHER, -1
4596 Xamoeba_2, FALSE, FALSE,
4597 EL_AMOEBA_DRY, ACTION_OTHER, -1
4600 Xamoeba_3, FALSE, FALSE,
4601 EL_AMOEBA_DRY, ACTION_OTHER, -1
4604 Xamoeba_4, FALSE, FALSE,
4605 EL_AMOEBA_DRY, ACTION_OTHER, -1
4608 Xamoeba_5, TRUE, FALSE,
4609 EL_AMOEBA_WET, ACTION_OTHER, -1
4612 Xamoeba_6, FALSE, FALSE,
4613 EL_AMOEBA_WET, ACTION_OTHER, -1
4616 Xamoeba_7, FALSE, FALSE,
4617 EL_AMOEBA_WET, ACTION_OTHER, -1
4620 Xamoeba_8, FALSE, FALSE,
4621 EL_AMOEBA_WET, ACTION_OTHER, -1
4624 Xdoor_1, TRUE, FALSE,
4625 EL_EM_GATE_1, -1, -1
4628 Xdoor_2, TRUE, FALSE,
4629 EL_EM_GATE_2, -1, -1
4632 Xdoor_3, TRUE, FALSE,
4633 EL_EM_GATE_3, -1, -1
4636 Xdoor_4, TRUE, FALSE,
4637 EL_EM_GATE_4, -1, -1
4640 Xdoor_5, TRUE, FALSE,
4641 EL_EMC_GATE_5, -1, -1
4644 Xdoor_6, TRUE, FALSE,
4645 EL_EMC_GATE_6, -1, -1
4648 Xdoor_7, TRUE, FALSE,
4649 EL_EMC_GATE_7, -1, -1
4652 Xdoor_8, TRUE, FALSE,
4653 EL_EMC_GATE_8, -1, -1
4656 Xkey_1, TRUE, FALSE,
4660 Xkey_2, TRUE, FALSE,
4664 Xkey_3, TRUE, FALSE,
4668 Xkey_4, TRUE, FALSE,
4672 Xkey_5, TRUE, FALSE,
4673 EL_EMC_KEY_5, -1, -1
4676 Xkey_6, TRUE, FALSE,
4677 EL_EMC_KEY_6, -1, -1
4680 Xkey_7, TRUE, FALSE,
4681 EL_EMC_KEY_7, -1, -1
4684 Xkey_8, TRUE, FALSE,
4685 EL_EMC_KEY_8, -1, -1
4688 Xwind_n, TRUE, FALSE,
4689 EL_BALLOON_SWITCH_UP, -1, -1
4692 Xwind_e, TRUE, FALSE,
4693 EL_BALLOON_SWITCH_RIGHT, -1, -1
4696 Xwind_s, TRUE, FALSE,
4697 EL_BALLOON_SWITCH_DOWN, -1, -1
4700 Xwind_w, TRUE, FALSE,
4701 EL_BALLOON_SWITCH_LEFT, -1, -1
4704 Xwind_nesw, TRUE, FALSE,
4705 EL_BALLOON_SWITCH_ANY, -1, -1
4708 Xwind_stop, TRUE, FALSE,
4709 EL_BALLOON_SWITCH_NONE, -1, -1
4713 EL_EM_EXIT_CLOSED, -1, -1
4716 Xexit_1, TRUE, FALSE,
4717 EL_EM_EXIT_OPEN, -1, -1
4720 Xexit_2, FALSE, FALSE,
4721 EL_EM_EXIT_OPEN, -1, -1
4724 Xexit_3, FALSE, FALSE,
4725 EL_EM_EXIT_OPEN, -1, -1
4728 Xdynamite, TRUE, FALSE,
4729 EL_EM_DYNAMITE, -1, -1
4732 Ydynamite_eat, FALSE, FALSE,
4733 EL_EM_DYNAMITE, ACTION_COLLECTING, -1
4736 Xdynamite_1, TRUE, FALSE,
4737 EL_EM_DYNAMITE_ACTIVE, -1, -1
4740 Xdynamite_2, FALSE, FALSE,
4741 EL_EM_DYNAMITE_ACTIVE, -1, -1
4744 Xdynamite_3, FALSE, FALSE,
4745 EL_EM_DYNAMITE_ACTIVE, -1, -1
4748 Xdynamite_4, FALSE, FALSE,
4749 EL_EM_DYNAMITE_ACTIVE, -1, -1
4752 Xbumper, TRUE, FALSE,
4753 EL_EMC_SPRING_BUMPER, -1, -1
4756 XbumperB, FALSE, FALSE,
4757 EL_EMC_SPRING_BUMPER, ACTION_ACTIVE, -1
4760 Xwheel, TRUE, FALSE,
4761 EL_ROBOT_WHEEL, -1, -1
4764 XwheelB, FALSE, FALSE,
4765 EL_ROBOT_WHEEL, ACTION_ACTIVE, -1
4768 Xswitch, TRUE, FALSE,
4769 EL_EMC_MAGIC_BALL_SWITCH, -1, -1
4772 XswitchB, FALSE, FALSE,
4773 EL_EMC_MAGIC_BALL_SWITCH, ACTION_ACTIVE, -1
4777 EL_QUICKSAND_EMPTY, -1, -1
4780 Xsand_stone, TRUE, FALSE,
4781 EL_QUICKSAND_FULL, -1, -1
4784 Xsand_stonein_1, FALSE, TRUE,
4785 EL_ROCK, ACTION_FILLING, -1
4788 Xsand_stonein_2, FALSE, TRUE,
4789 EL_ROCK, ACTION_FILLING, -1
4792 Xsand_stonein_3, FALSE, TRUE,
4793 EL_ROCK, ACTION_FILLING, -1
4796 Xsand_stonein_4, FALSE, TRUE,
4797 EL_ROCK, ACTION_FILLING, -1
4801 Xsand_stonesand_1, FALSE, FALSE,
4802 EL_QUICKSAND_EMPTYING, -1, -1
4805 Xsand_stonesand_2, FALSE, FALSE,
4806 EL_QUICKSAND_EMPTYING, -1, -1
4809 Xsand_stonesand_3, FALSE, FALSE,
4810 EL_QUICKSAND_EMPTYING, -1, -1
4813 Xsand_stonesand_4, FALSE, FALSE,
4814 EL_QUICKSAND_EMPTYING, -1, -1
4818 Xsand_stonesand_1, FALSE, FALSE,
4819 EL_QUICKSAND_FULL, -1, -1
4822 Xsand_stonesand_2, FALSE, FALSE,
4823 EL_QUICKSAND_FULL, -1, -1
4826 Xsand_stonesand_3, FALSE, FALSE,
4827 EL_QUICKSAND_FULL, -1, -1
4830 Xsand_stonesand_4, FALSE, FALSE,
4831 EL_QUICKSAND_FULL, -1, -1
4835 Xsand_stoneout_1, FALSE, FALSE,
4836 EL_ROCK, ACTION_EMPTYING, -1
4839 Xsand_stoneout_2, FALSE, FALSE,
4840 EL_ROCK, ACTION_EMPTYING, -1
4844 Xsand_sandstone_1, FALSE, FALSE,
4845 EL_QUICKSAND_FILLING, -1, -1
4848 Xsand_sandstone_2, FALSE, FALSE,
4849 EL_QUICKSAND_FILLING, -1, -1
4852 Xsand_sandstone_3, FALSE, FALSE,
4853 EL_QUICKSAND_FILLING, -1, -1
4856 Xsand_sandstone_4, FALSE, FALSE,
4857 EL_QUICKSAND_FILLING, -1, -1
4861 Xsand_sandstone_1, FALSE, FALSE,
4862 EL_QUICKSAND_FULL, -1, -1
4865 Xsand_sandstone_2, FALSE, FALSE,
4866 EL_QUICKSAND_FULL, -1, -1
4869 Xsand_sandstone_3, FALSE, FALSE,
4870 EL_QUICKSAND_FULL, -1, -1
4873 Xsand_sandstone_4, FALSE, FALSE,
4874 EL_QUICKSAND_FULL, -1, -1
4878 Xplant, TRUE, FALSE,
4879 EL_EMC_PLANT, -1, -1
4882 Yplant, FALSE, FALSE,
4883 EL_EMC_PLANT, -1, -1
4886 Xlenses, TRUE, FALSE,
4887 EL_EMC_LENSES, -1, -1
4890 Xmagnify, TRUE, FALSE,
4891 EL_EMC_MAGNIFIER, -1, -1
4894 Xdripper, TRUE, FALSE,
4895 EL_EMC_DRIPPER, -1, -1
4898 XdripperB, FALSE, FALSE,
4899 EL_EMC_DRIPPER, ACTION_ACTIVE, -1
4902 Xfake_blank, TRUE, FALSE,
4903 EL_INVISIBLE_WALL, -1, -1
4906 Xfake_blankB, FALSE, FALSE,
4907 EL_INVISIBLE_WALL, ACTION_ACTIVE, -1
4910 Xfake_grass, TRUE, FALSE,
4911 EL_EMC_FAKE_GRASS, -1, -1
4914 Xfake_grassB, FALSE, FALSE,
4915 EL_EMC_FAKE_GRASS, ACTION_ACTIVE, -1
4918 Xfake_door_1, TRUE, FALSE,
4919 EL_EM_GATE_1_GRAY, -1, -1
4922 Xfake_door_2, TRUE, FALSE,
4923 EL_EM_GATE_2_GRAY, -1, -1
4926 Xfake_door_3, TRUE, FALSE,
4927 EL_EM_GATE_3_GRAY, -1, -1
4930 Xfake_door_4, TRUE, FALSE,
4931 EL_EM_GATE_4_GRAY, -1, -1
4934 Xfake_door_5, TRUE, FALSE,
4935 EL_EMC_GATE_5_GRAY, -1, -1
4938 Xfake_door_6, TRUE, FALSE,
4939 EL_EMC_GATE_6_GRAY, -1, -1
4942 Xfake_door_7, TRUE, FALSE,
4943 EL_EMC_GATE_7_GRAY, -1, -1
4946 Xfake_door_8, TRUE, FALSE,
4947 EL_EMC_GATE_8_GRAY, -1, -1
4950 Xfake_acid_1, TRUE, FALSE,
4951 EL_EMC_FAKE_ACID, -1, -1
4954 Xfake_acid_2, FALSE, FALSE,
4955 EL_EMC_FAKE_ACID, -1, -1
4958 Xfake_acid_3, FALSE, FALSE,
4959 EL_EMC_FAKE_ACID, -1, -1
4962 Xfake_acid_4, FALSE, FALSE,
4963 EL_EMC_FAKE_ACID, -1, -1
4966 Xfake_acid_5, FALSE, FALSE,
4967 EL_EMC_FAKE_ACID, -1, -1
4970 Xfake_acid_6, FALSE, FALSE,
4971 EL_EMC_FAKE_ACID, -1, -1
4974 Xfake_acid_7, FALSE, FALSE,
4975 EL_EMC_FAKE_ACID, -1, -1
4978 Xfake_acid_8, FALSE, FALSE,
4979 EL_EMC_FAKE_ACID, -1, -1
4982 Xsteel_1, TRUE, FALSE,
4983 EL_STEELWALL, -1, -1
4986 Xsteel_2, TRUE, FALSE,
4987 EL_EMC_STEELWALL_2, -1, -1
4990 Xsteel_3, TRUE, FALSE,
4991 EL_EMC_STEELWALL_3, -1, -1
4994 Xsteel_4, TRUE, FALSE,
4995 EL_EMC_STEELWALL_4, -1, -1
4998 Xwall_1, TRUE, FALSE,
5002 Xwall_2, TRUE, FALSE,
5003 EL_EMC_WALL_14, -1, -1
5006 Xwall_3, TRUE, FALSE,
5007 EL_EMC_WALL_15, -1, -1
5010 Xwall_4, TRUE, FALSE,
5011 EL_EMC_WALL_16, -1, -1
5014 Xround_wall_1, TRUE, FALSE,
5015 EL_WALL_SLIPPERY, -1, -1
5018 Xround_wall_2, TRUE, FALSE,
5019 EL_EMC_WALL_SLIPPERY_2, -1, -1
5022 Xround_wall_3, TRUE, FALSE,
5023 EL_EMC_WALL_SLIPPERY_3, -1, -1
5026 Xround_wall_4, TRUE, FALSE,
5027 EL_EMC_WALL_SLIPPERY_4, -1, -1
5030 Xdecor_1, TRUE, FALSE,
5031 EL_EMC_WALL_8, -1, -1
5034 Xdecor_2, TRUE, FALSE,
5035 EL_EMC_WALL_6, -1, -1
5038 Xdecor_3, TRUE, FALSE,
5039 EL_EMC_WALL_4, -1, -1
5042 Xdecor_4, TRUE, FALSE,
5043 EL_EMC_WALL_7, -1, -1
5046 Xdecor_5, TRUE, FALSE,
5047 EL_EMC_WALL_5, -1, -1
5050 Xdecor_6, TRUE, FALSE,
5051 EL_EMC_WALL_9, -1, -1
5054 Xdecor_7, TRUE, FALSE,
5055 EL_EMC_WALL_10, -1, -1
5058 Xdecor_8, TRUE, FALSE,
5059 EL_EMC_WALL_1, -1, -1
5062 Xdecor_9, TRUE, FALSE,
5063 EL_EMC_WALL_2, -1, -1
5066 Xdecor_10, TRUE, FALSE,
5067 EL_EMC_WALL_3, -1, -1
5070 Xdecor_11, TRUE, FALSE,
5071 EL_EMC_WALL_11, -1, -1
5074 Xdecor_12, TRUE, FALSE,
5075 EL_EMC_WALL_12, -1, -1
5078 Xalpha_0, TRUE, FALSE,
5079 EL_CHAR('0'), -1, -1
5082 Xalpha_1, TRUE, FALSE,
5083 EL_CHAR('1'), -1, -1
5086 Xalpha_2, TRUE, FALSE,
5087 EL_CHAR('2'), -1, -1
5090 Xalpha_3, TRUE, FALSE,
5091 EL_CHAR('3'), -1, -1
5094 Xalpha_4, TRUE, FALSE,
5095 EL_CHAR('4'), -1, -1
5098 Xalpha_5, TRUE, FALSE,
5099 EL_CHAR('5'), -1, -1
5102 Xalpha_6, TRUE, FALSE,
5103 EL_CHAR('6'), -1, -1
5106 Xalpha_7, TRUE, FALSE,
5107 EL_CHAR('7'), -1, -1
5110 Xalpha_8, TRUE, FALSE,
5111 EL_CHAR('8'), -1, -1
5114 Xalpha_9, TRUE, FALSE,
5115 EL_CHAR('9'), -1, -1
5118 Xalpha_excla, TRUE, FALSE,
5119 EL_CHAR('!'), -1, -1
5122 Xalpha_quote, TRUE, FALSE,
5123 EL_CHAR('"'), -1, -1
5126 Xalpha_comma, TRUE, FALSE,
5127 EL_CHAR(','), -1, -1
5130 Xalpha_minus, TRUE, FALSE,
5131 EL_CHAR('-'), -1, -1
5134 Xalpha_perio, TRUE, FALSE,
5135 EL_CHAR('.'), -1, -1
5138 Xalpha_colon, TRUE, FALSE,
5139 EL_CHAR(':'), -1, -1
5142 Xalpha_quest, TRUE, FALSE,
5143 EL_CHAR('?'), -1, -1
5146 Xalpha_a, TRUE, FALSE,
5147 EL_CHAR('A'), -1, -1
5150 Xalpha_b, TRUE, FALSE,
5151 EL_CHAR('B'), -1, -1
5154 Xalpha_c, TRUE, FALSE,
5155 EL_CHAR('C'), -1, -1
5158 Xalpha_d, TRUE, FALSE,
5159 EL_CHAR('D'), -1, -1
5162 Xalpha_e, TRUE, FALSE,
5163 EL_CHAR('E'), -1, -1
5166 Xalpha_f, TRUE, FALSE,
5167 EL_CHAR('F'), -1, -1
5170 Xalpha_g, TRUE, FALSE,
5171 EL_CHAR('G'), -1, -1
5174 Xalpha_h, TRUE, FALSE,
5175 EL_CHAR('H'), -1, -1
5178 Xalpha_i, TRUE, FALSE,
5179 EL_CHAR('I'), -1, -1
5182 Xalpha_j, TRUE, FALSE,
5183 EL_CHAR('J'), -1, -1
5186 Xalpha_k, TRUE, FALSE,
5187 EL_CHAR('K'), -1, -1
5190 Xalpha_l, TRUE, FALSE,
5191 EL_CHAR('L'), -1, -1
5194 Xalpha_m, TRUE, FALSE,
5195 EL_CHAR('M'), -1, -1
5198 Xalpha_n, TRUE, FALSE,
5199 EL_CHAR('N'), -1, -1
5202 Xalpha_o, TRUE, FALSE,
5203 EL_CHAR('O'), -1, -1
5206 Xalpha_p, TRUE, FALSE,
5207 EL_CHAR('P'), -1, -1
5210 Xalpha_q, TRUE, FALSE,
5211 EL_CHAR('Q'), -1, -1
5214 Xalpha_r, TRUE, FALSE,
5215 EL_CHAR('R'), -1, -1
5218 Xalpha_s, TRUE, FALSE,
5219 EL_CHAR('S'), -1, -1
5222 Xalpha_t, TRUE, FALSE,
5223 EL_CHAR('T'), -1, -1
5226 Xalpha_u, TRUE, FALSE,
5227 EL_CHAR('U'), -1, -1
5230 Xalpha_v, TRUE, FALSE,
5231 EL_CHAR('V'), -1, -1
5234 Xalpha_w, TRUE, FALSE,
5235 EL_CHAR('W'), -1, -1
5238 Xalpha_x, TRUE, FALSE,
5239 EL_CHAR('X'), -1, -1
5242 Xalpha_y, TRUE, FALSE,
5243 EL_CHAR('Y'), -1, -1
5246 Xalpha_z, TRUE, FALSE,
5247 EL_CHAR('Z'), -1, -1
5250 Xalpha_arrow_e, TRUE, FALSE,
5251 EL_CHAR('>'), -1, -1
5254 Xalpha_arrow_w, TRUE, FALSE,
5255 EL_CHAR('<'), -1, -1
5258 Xalpha_copyr, TRUE, FALSE,
5259 EL_CHAR('©'), -1, -1
5263 Xboom_bug, FALSE, FALSE,
5264 EL_BUG, ACTION_EXPLODING, -1
5267 Xboom_bomb, FALSE, FALSE,
5268 EL_BOMB, ACTION_EXPLODING, -1
5271 Xboom_android, FALSE, FALSE,
5272 EL_EMC_ANDROID, ACTION_OTHER, -1
5275 Xboom_1, FALSE, FALSE,
5276 EL_DEFAULT, ACTION_EXPLODING, -1
5279 Xboom_2, FALSE, FALSE,
5280 EL_DEFAULT, ACTION_EXPLODING, -1
5283 Znormal, FALSE, FALSE,
5287 Zdynamite, FALSE, FALSE,
5291 Zplayer, FALSE, FALSE,
5295 ZBORDER, FALSE, FALSE,
5305 static struct Mapping_EM_to_RND_player
5314 em_player_mapping_list[] =
5318 EL_PLAYER_1, ACTION_MOVING, MV_BIT_UP,
5322 EL_PLAYER_1, ACTION_MOVING, MV_BIT_RIGHT,
5326 EL_PLAYER_1, ACTION_MOVING, MV_BIT_DOWN,
5330 EL_PLAYER_1, ACTION_MOVING, MV_BIT_LEFT,
5334 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_UP,
5338 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_RIGHT,
5342 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_DOWN,
5346 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_LEFT,
5350 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_UP,
5354 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_RIGHT,
5358 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_DOWN,
5362 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_LEFT,
5366 EL_PLAYER_2, ACTION_MOVING, MV_BIT_UP,
5370 EL_PLAYER_2, ACTION_MOVING, MV_BIT_RIGHT,
5374 EL_PLAYER_2, ACTION_MOVING, MV_BIT_DOWN,
5378 EL_PLAYER_2, ACTION_MOVING, MV_BIT_LEFT,
5382 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_UP,
5386 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_RIGHT,
5390 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_DOWN,
5394 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_LEFT,
5398 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_UP,
5402 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_RIGHT,
5406 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_DOWN,
5410 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_LEFT,
5414 EL_PLAYER_1, ACTION_DEFAULT, -1,
5418 EL_PLAYER_2, ACTION_DEFAULT, -1,
5422 EL_PLAYER_3, ACTION_MOVING, MV_BIT_UP,
5426 EL_PLAYER_3, ACTION_MOVING, MV_BIT_RIGHT,
5430 EL_PLAYER_3, ACTION_MOVING, MV_BIT_DOWN,
5434 EL_PLAYER_3, ACTION_MOVING, MV_BIT_LEFT,
5438 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_UP,
5442 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_RIGHT,
5446 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_DOWN,
5450 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_LEFT,
5454 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_UP,
5458 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_RIGHT,
5462 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_DOWN,
5466 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_LEFT,
5470 EL_PLAYER_4, ACTION_MOVING, MV_BIT_UP,
5474 EL_PLAYER_4, ACTION_MOVING, MV_BIT_RIGHT,
5478 EL_PLAYER_4, ACTION_MOVING, MV_BIT_DOWN,
5482 EL_PLAYER_4, ACTION_MOVING, MV_BIT_LEFT,
5486 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_UP,
5490 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_RIGHT,
5494 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_DOWN,
5498 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_LEFT,
5502 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_UP,
5506 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_RIGHT,
5510 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_DOWN,
5514 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_LEFT,
5518 EL_PLAYER_3, ACTION_DEFAULT, -1,
5522 EL_PLAYER_4, ACTION_DEFAULT, -1,
5531 int map_element_RND_to_EM(int element_rnd)
5533 static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
5534 static boolean mapping_initialized = FALSE;
5536 if (!mapping_initialized)
5540 /* return "Xalpha_quest" for all undefined elements in mapping array */
5541 for (i = 0; i < NUM_FILE_ELEMENTS; i++)
5542 mapping_RND_to_EM[i] = Xalpha_quest;
5544 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5545 if (em_object_mapping_list[i].is_rnd_to_em_mapping)
5546 mapping_RND_to_EM[em_object_mapping_list[i].element_rnd] =
5547 em_object_mapping_list[i].element_em;
5549 mapping_initialized = TRUE;
5552 if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
5553 return mapping_RND_to_EM[element_rnd];
5555 Error(ERR_WARN, "invalid RND level element %d", element_rnd);
5560 int map_element_EM_to_RND(int element_em)
5562 static unsigned short mapping_EM_to_RND[TILE_MAX];
5563 static boolean mapping_initialized = FALSE;
5565 if (!mapping_initialized)
5569 /* return "EL_UNKNOWN" for all undefined elements in mapping array */
5570 for (i = 0; i < TILE_MAX; i++)
5571 mapping_EM_to_RND[i] = EL_UNKNOWN;
5573 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5574 mapping_EM_to_RND[em_object_mapping_list[i].element_em] =
5575 em_object_mapping_list[i].element_rnd;
5577 mapping_initialized = TRUE;
5580 if (element_em >= 0 && element_em < TILE_MAX)
5581 return mapping_EM_to_RND[element_em];
5583 Error(ERR_WARN, "invalid EM level element %d", element_em);
5588 void map_android_clone_elements_RND_to_EM(struct LevelInfo *level)
5590 struct LevelInfo_EM *level_em = level->native_em_level;
5591 struct LEVEL *lev = level_em->lev;
5594 for (i = 0; i < TILE_MAX; i++)
5595 lev->android_array[i] = Xblank;
5597 for (i = 0; i < level->num_android_clone_elements; i++)
5599 int element_rnd = level->android_clone_element[i];
5600 int element_em = map_element_RND_to_EM(element_rnd);
5602 for (j = 0; em_object_mapping_list[j].element_em != -1; j++)
5603 if (em_object_mapping_list[j].element_rnd == element_rnd)
5604 lev->android_array[em_object_mapping_list[j].element_em] = element_em;
5608 void map_android_clone_elements_EM_to_RND(struct LevelInfo *level)
5610 struct LevelInfo_EM *level_em = level->native_em_level;
5611 struct LEVEL *lev = level_em->lev;
5614 level->num_android_clone_elements = 0;
5616 for (i = 0; i < TILE_MAX; i++)
5618 int element_em = lev->android_array[i];
5620 boolean element_found = FALSE;
5622 if (element_em == Xblank)
5625 element_rnd = map_element_EM_to_RND(element_em);
5627 for (j = 0; j < level->num_android_clone_elements; j++)
5628 if (level->android_clone_element[j] == element_rnd)
5629 element_found = TRUE;
5633 level->android_clone_element[level->num_android_clone_elements++] =
5636 if (level->num_android_clone_elements == MAX_ANDROID_ELEMENTS)
5641 if (level->num_android_clone_elements == 0)
5643 level->num_android_clone_elements = 1;
5644 level->android_clone_element[0] = EL_EMPTY;
5648 int map_direction_RND_to_EM(int direction)
5650 return (direction == MV_UP ? 0 :
5651 direction == MV_RIGHT ? 1 :
5652 direction == MV_DOWN ? 2 :
5653 direction == MV_LEFT ? 3 :
5657 int map_direction_EM_to_RND(int direction)
5659 return (direction == 0 ? MV_UP :
5660 direction == 1 ? MV_RIGHT :
5661 direction == 2 ? MV_DOWN :
5662 direction == 3 ? MV_LEFT :
5666 int get_next_element(int element)
5670 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
5671 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
5672 case EL_QUICKSAND_FAST_FILLING: return EL_QUICKSAND_FAST_FULL;
5673 case EL_QUICKSAND_FAST_EMPTYING: return EL_QUICKSAND_FAST_EMPTY;
5674 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
5675 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
5676 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
5677 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
5678 case EL_DC_MAGIC_WALL_FILLING: return EL_DC_MAGIC_WALL_FULL;
5679 case EL_DC_MAGIC_WALL_EMPTYING: return EL_DC_MAGIC_WALL_ACTIVE;
5680 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
5682 default: return element;
5687 int el_act_dir2img(int element, int action, int direction)
5689 element = GFX_ELEMENT(element);
5691 if (direction == MV_NONE)
5692 return element_info[element].graphic[action];
5694 direction = MV_DIR_TO_BIT(direction);
5696 return element_info[element].direction_graphic[action][direction];
5699 int el_act_dir2img(int element, int action, int direction)
5701 element = GFX_ELEMENT(element);
5702 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
5704 /* direction_graphic[][] == graphic[] for undefined direction graphics */
5705 return element_info[element].direction_graphic[action][direction];
5710 static int el_act_dir2crm(int element, int action, int direction)
5712 element = GFX_ELEMENT(element);
5714 if (direction == MV_NONE)
5715 return element_info[element].crumbled[action];
5717 direction = MV_DIR_TO_BIT(direction);
5719 return element_info[element].direction_crumbled[action][direction];
5722 static int el_act_dir2crm(int element, int action, int direction)
5724 element = GFX_ELEMENT(element);
5725 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
5727 /* direction_graphic[][] == graphic[] for undefined direction graphics */
5728 return element_info[element].direction_crumbled[action][direction];
5732 int el_act2img(int element, int action)
5734 element = GFX_ELEMENT(element);
5736 return element_info[element].graphic[action];
5739 int el_act2crm(int element, int action)
5741 element = GFX_ELEMENT(element);
5743 return element_info[element].crumbled[action];
5746 int el_dir2img(int element, int direction)
5748 element = GFX_ELEMENT(element);
5750 return el_act_dir2img(element, ACTION_DEFAULT, direction);
5753 int el2baseimg(int element)
5755 return element_info[element].graphic[ACTION_DEFAULT];
5758 int el2img(int element)
5760 element = GFX_ELEMENT(element);
5762 return element_info[element].graphic[ACTION_DEFAULT];
5765 int el2edimg(int element)
5767 element = GFX_ELEMENT(element);
5769 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
5772 int el2preimg(int element)
5774 element = GFX_ELEMENT(element);
5776 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
5779 int el2panelimg(int element)
5781 element = GFX_ELEMENT(element);
5783 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PANEL];
5786 int font2baseimg(int font_nr)
5788 return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
5791 int getBeltNrFromBeltElement(int element)
5793 return (element < EL_CONVEYOR_BELT_2_LEFT ? 0 :
5794 element < EL_CONVEYOR_BELT_3_LEFT ? 1 :
5795 element < EL_CONVEYOR_BELT_4_LEFT ? 2 : 3);
5798 int getBeltNrFromBeltActiveElement(int element)
5800 return (element < EL_CONVEYOR_BELT_2_LEFT_ACTIVE ? 0 :
5801 element < EL_CONVEYOR_BELT_3_LEFT_ACTIVE ? 1 :
5802 element < EL_CONVEYOR_BELT_4_LEFT_ACTIVE ? 2 : 3);
5805 int getBeltNrFromBeltSwitchElement(int element)
5807 return (element < EL_CONVEYOR_BELT_2_SWITCH_LEFT ? 0 :
5808 element < EL_CONVEYOR_BELT_3_SWITCH_LEFT ? 1 :
5809 element < EL_CONVEYOR_BELT_4_SWITCH_LEFT ? 2 : 3);
5812 int getBeltDirNrFromBeltElement(int element)
5814 static int belt_base_element[4] =
5816 EL_CONVEYOR_BELT_1_LEFT,
5817 EL_CONVEYOR_BELT_2_LEFT,
5818 EL_CONVEYOR_BELT_3_LEFT,
5819 EL_CONVEYOR_BELT_4_LEFT
5822 int belt_nr = getBeltNrFromBeltElement(element);
5823 int belt_dir_nr = element - belt_base_element[belt_nr];
5825 return (belt_dir_nr % 3);
5828 int getBeltDirNrFromBeltSwitchElement(int element)
5830 static int belt_base_element[4] =
5832 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
5833 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
5834 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
5835 EL_CONVEYOR_BELT_4_SWITCH_LEFT
5838 int belt_nr = getBeltNrFromBeltSwitchElement(element);
5839 int belt_dir_nr = element - belt_base_element[belt_nr];
5841 return (belt_dir_nr % 3);
5844 int getBeltDirFromBeltElement(int element)
5846 static int belt_move_dir[3] =
5853 int belt_dir_nr = getBeltDirNrFromBeltElement(element);
5855 return belt_move_dir[belt_dir_nr];
5858 int getBeltDirFromBeltSwitchElement(int element)
5860 static int belt_move_dir[3] =
5867 int belt_dir_nr = getBeltDirNrFromBeltSwitchElement(element);
5869 return belt_move_dir[belt_dir_nr];
5872 int getBeltElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
5874 static int belt_base_element[4] =
5876 EL_CONVEYOR_BELT_1_LEFT,
5877 EL_CONVEYOR_BELT_2_LEFT,
5878 EL_CONVEYOR_BELT_3_LEFT,
5879 EL_CONVEYOR_BELT_4_LEFT
5882 return belt_base_element[belt_nr] + belt_dir_nr;
5885 int getBeltElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
5887 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
5889 return getBeltElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
5892 int getBeltSwitchElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
5894 static int belt_base_element[4] =
5896 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
5897 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
5898 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
5899 EL_CONVEYOR_BELT_4_SWITCH_LEFT
5902 return belt_base_element[belt_nr] + belt_dir_nr;
5905 int getBeltSwitchElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
5907 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
5909 return getBeltSwitchElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
5912 int getNumActivePlayers_EM()
5914 int num_players = 0;
5920 for (i = 0; i < MAX_PLAYERS; i++)
5921 if (tape.player_participates[i])
5927 int getGameFrameDelay_EM(int native_em_game_frame_delay)
5929 int game_frame_delay_value;
5931 game_frame_delay_value =
5932 (tape.playing && tape.fast_forward ? FfwdFrameDelay :
5933 GameFrameDelay == GAME_FRAME_DELAY ? native_em_game_frame_delay :
5936 if (tape.playing && tape.warp_forward && !tape.pausing)
5937 game_frame_delay_value = 0;
5939 return game_frame_delay_value;
5942 unsigned int InitRND(long seed)
5944 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
5945 return InitEngineRandom_EM(seed);
5947 return InitEngineRandom_RND(seed);
5951 static struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
5952 static struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
5955 inline static int get_effective_element_EM(int tile, int frame_em)
5957 int element = object_mapping[tile].element_rnd;
5958 int action = object_mapping[tile].action;
5959 boolean is_backside = object_mapping[tile].is_backside;
5960 boolean action_removing = (action == ACTION_DIGGING ||
5961 action == ACTION_SNAPPING ||
5962 action == ACTION_COLLECTING);
5968 case Yacid_splash_eB:
5969 case Yacid_splash_wB:
5970 return (frame_em > 5 ? EL_EMPTY : element);
5976 else /* frame_em == 7 */
5980 case Yacid_splash_eB:
5981 case Yacid_splash_wB:
5984 case Yemerald_stone:
5987 case Ydiamond_stone:
5991 case Xdrip_stretchB:
6010 case Xsand_stonein_1:
6011 case Xsand_stonein_2:
6012 case Xsand_stonein_3:
6013 case Xsand_stonein_4:
6017 return (is_backside || action_removing ? EL_EMPTY : element);
6022 inline static boolean check_linear_animation_EM(int tile)
6026 case Xsand_stonesand_1:
6027 case Xsand_sandstone_1:
6052 inline static void set_crumbled_graphics_EM(struct GraphicInfo_EM *g_em,
6053 boolean has_crumbled_graphics,
6054 int crumbled, int sync_frame)
6056 /* if element can be crumbled, but certain action graphics are just empty
6057 space (like instantly snapping sand to empty space in 1 frame), do not
6058 treat these empty space graphics as crumbled graphics in EMC engine */
6059 if (crumbled == IMG_EMPTY_SPACE)
6060 has_crumbled_graphics = FALSE;
6062 if (has_crumbled_graphics)
6064 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
6065 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
6066 g_crumbled->anim_delay,
6067 g_crumbled->anim_mode,
6068 g_crumbled->anim_start_frame,
6071 getGraphicSource(crumbled, frame_crumbled, &g_em->crumbled_bitmap,
6072 &g_em->crumbled_src_x, &g_em->crumbled_src_y);
6074 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
6076 g_em->has_crumbled_graphics = TRUE;
6080 g_em->crumbled_bitmap = NULL;
6081 g_em->crumbled_src_x = 0;
6082 g_em->crumbled_src_y = 0;
6083 g_em->crumbled_border_size = 0;
6085 g_em->has_crumbled_graphics = FALSE;
6089 void ResetGfxAnimation_EM(int x, int y, int tile)
6094 void SetGfxAnimation_EM(int tile, int frame_em, int x, int y)
6096 int action = object_mapping[tile].action;
6097 boolean action_removing = (action == ACTION_DIGGING ||
6098 action == ACTION_SNAPPING ||
6099 action == ACTION_COLLECTING);
6100 boolean action_moving = (action == ACTION_FALLING ||
6101 action == ACTION_MOVING ||
6102 action == ACTION_PUSHING ||
6103 action == ACTION_EATING ||
6104 action == ACTION_FILLING ||
6105 action == ACTION_EMPTYING);
6106 boolean action_falling = (action == ACTION_FALLING ||
6107 action == ACTION_FILLING ||
6108 action == ACTION_EMPTYING);
6110 if (action_removing || check_linear_animation_EM(tile))
6112 GfxFrame[x][y] = frame_em;
6114 else if (action_moving)
6116 boolean is_backside = object_mapping[tile].is_backside;
6120 int direction = object_mapping[tile].direction;
6121 int move_dir = (action_falling ? MV_DOWN : direction);
6125 if (move_dir == MV_LEFT)
6126 GfxFrame[x - 1][y] = GfxFrame[x][y];
6127 else if (move_dir == MV_RIGHT)
6128 GfxFrame[x + 1][y] = GfxFrame[x][y];
6129 else if (move_dir == MV_UP)
6130 GfxFrame[x][y - 1] = GfxFrame[x][y];
6131 else if (move_dir == MV_DOWN)
6132 GfxFrame[x][y + 1] = GfxFrame[x][y];
6141 void getGraphicSourceObjectExt_EM(struct GraphicInfo_EM *g_em,
6142 int tile, int frame_em, int x, int y)
6144 int action = object_mapping[tile].action;
6145 int direction = object_mapping[tile].direction;
6146 int effective_element = get_effective_element_EM(tile, frame_em);
6147 int graphic = (direction == MV_NONE ?
6148 el_act2img(effective_element, action) :
6149 el_act_dir2img(effective_element, action, direction));
6150 int crumbled = (direction == MV_NONE ?
6151 el_act2crm(effective_element, action) :
6152 el_act_dir2crm(effective_element, action, direction));
6153 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
6154 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
6155 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
6156 struct GraphicInfo *g = &graphic_info[graphic];
6158 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
6163 if (frame_em == 0) /* reset animation frame for certain elements */
6165 if (check_linear_animation_EM(tile))
6170 if (graphic_info[graphic].anim_global_sync)
6171 sync_frame = FrameCounter;
6172 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
6173 sync_frame = GfxFrame[x][y];
6175 sync_frame = 0; /* playfield border (pseudo steel) */
6177 SetRandomAnimationValue(x, y);
6179 int frame = getAnimationFrame(g->anim_frames,
6182 g->anim_start_frame,
6185 getGraphicSourceExt(graphic, frame, &g_em->bitmap,
6186 &g_em->src_x, &g_em->src_y, FALSE);
6188 /* (updating the "crumbled" graphic definitions is probably not really needed,
6189 as animations for crumbled graphics can't be longer than one EMC cycle) */
6191 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
6196 g_em->crumbled_bitmap = NULL;
6197 g_em->crumbled_src_x = 0;
6198 g_em->crumbled_src_y = 0;
6200 g_em->has_crumbled_graphics = FALSE;
6202 if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
6204 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
6205 g_crumbled->anim_delay,
6206 g_crumbled->anim_mode,
6207 g_crumbled->anim_start_frame,
6210 getGraphicSource(crumbled, frame_crumbled, &g_em->crumbled_bitmap,
6211 &g_em->crumbled_src_x, &g_em->crumbled_src_y);
6213 g_em->has_crumbled_graphics = TRUE;
6218 void getGraphicSourcePlayerExt_EM(struct GraphicInfo_EM *g_em,
6219 int player_nr, int anim, int frame_em)
6221 int element = player_mapping[player_nr][anim].element_rnd;
6222 int action = player_mapping[player_nr][anim].action;
6223 int direction = player_mapping[player_nr][anim].direction;
6224 int graphic = (direction == MV_NONE ?
6225 el_act2img(element, action) :
6226 el_act_dir2img(element, action, direction));
6227 struct GraphicInfo *g = &graphic_info[graphic];
6230 InitPlayerGfxAnimation(&stored_player[player_nr], action, direction);
6232 stored_player[player_nr].StepFrame = frame_em;
6234 sync_frame = stored_player[player_nr].Frame;
6236 int frame = getAnimationFrame(g->anim_frames,
6239 g->anim_start_frame,
6242 getGraphicSourceExt(graphic, frame, &g_em->bitmap,
6243 &g_em->src_x, &g_em->src_y, FALSE);
6246 printf("::: %d: %d, %d [%d]\n",
6248 stored_player[player_nr].Frame,
6249 stored_player[player_nr].StepFrame,
6254 void InitGraphicInfo_EM(void)
6257 struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
6258 struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
6263 int num_em_gfx_errors = 0;
6265 if (graphic_info_em_object[0][0].bitmap == NULL)
6267 /* EM graphics not yet initialized in em_open_all() */
6272 printf("::: [4 errors can be ignored (1 x 'bomb', 3 x 'em_dynamite']\n");
6275 /* always start with reliable default values */
6276 for (i = 0; i < TILE_MAX; i++)
6278 object_mapping[i].element_rnd = EL_UNKNOWN;
6279 object_mapping[i].is_backside = FALSE;
6280 object_mapping[i].action = ACTION_DEFAULT;
6281 object_mapping[i].direction = MV_NONE;
6284 /* always start with reliable default values */
6285 for (p = 0; p < MAX_PLAYERS; p++)
6287 for (i = 0; i < SPR_MAX; i++)
6289 player_mapping[p][i].element_rnd = EL_UNKNOWN;
6290 player_mapping[p][i].action = ACTION_DEFAULT;
6291 player_mapping[p][i].direction = MV_NONE;
6295 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
6297 int e = em_object_mapping_list[i].element_em;
6299 object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd;
6300 object_mapping[e].is_backside = em_object_mapping_list[i].is_backside;
6302 if (em_object_mapping_list[i].action != -1)
6303 object_mapping[e].action = em_object_mapping_list[i].action;
6305 if (em_object_mapping_list[i].direction != -1)
6306 object_mapping[e].direction =
6307 MV_DIR_FROM_BIT(em_object_mapping_list[i].direction);
6310 for (i = 0; em_player_mapping_list[i].action_em != -1; i++)
6312 int a = em_player_mapping_list[i].action_em;
6313 int p = em_player_mapping_list[i].player_nr;
6315 player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd;
6317 if (em_player_mapping_list[i].action != -1)
6318 player_mapping[p][a].action = em_player_mapping_list[i].action;
6320 if (em_player_mapping_list[i].direction != -1)
6321 player_mapping[p][a].direction =
6322 MV_DIR_FROM_BIT(em_player_mapping_list[i].direction);
6325 for (i = 0; i < TILE_MAX; i++)
6327 int element = object_mapping[i].element_rnd;
6328 int action = object_mapping[i].action;
6329 int direction = object_mapping[i].direction;
6330 boolean is_backside = object_mapping[i].is_backside;
6332 boolean action_removing = (action == ACTION_DIGGING ||
6333 action == ACTION_SNAPPING ||
6334 action == ACTION_COLLECTING);
6336 boolean action_exploding = ((action == ACTION_EXPLODING ||
6337 action == ACTION_SMASHED_BY_ROCK ||
6338 action == ACTION_SMASHED_BY_SPRING) &&
6339 element != EL_DIAMOND);
6340 boolean action_active = (action == ACTION_ACTIVE);
6341 boolean action_other = (action == ACTION_OTHER);
6343 for (j = 0; j < 8; j++)
6346 int effective_element = get_effective_element_EM(i, j);
6348 int effective_element = (j > 5 && i == Yacid_splash_eB ? EL_EMPTY :
6349 j > 5 && i == Yacid_splash_wB ? EL_EMPTY :
6351 i == Xdrip_stretch ? element :
6352 i == Xdrip_stretchB ? element :
6353 i == Ydrip_s1 ? element :
6354 i == Ydrip_s1B ? element :
6355 i == Xball_1B ? element :
6356 i == Xball_2 ? element :
6357 i == Xball_2B ? element :
6358 i == Yball_eat ? element :
6359 i == Ykey_1_eat ? element :
6360 i == Ykey_2_eat ? element :
6361 i == Ykey_3_eat ? element :
6362 i == Ykey_4_eat ? element :
6363 i == Ykey_5_eat ? element :
6364 i == Ykey_6_eat ? element :
6365 i == Ykey_7_eat ? element :
6366 i == Ykey_8_eat ? element :
6367 i == Ylenses_eat ? element :
6368 i == Ymagnify_eat ? element :
6369 i == Ygrass_eat ? element :
6370 i == Ydirt_eat ? element :
6371 i == Yemerald_stone ? EL_EMERALD :
6372 i == Ydiamond_stone ? EL_ROCK :
6373 i == Xsand_stonein_1 ? element :
6374 i == Xsand_stonein_2 ? element :
6375 i == Xsand_stonein_3 ? element :
6376 i == Xsand_stonein_4 ? element :
6377 is_backside ? EL_EMPTY :
6378 action_removing ? EL_EMPTY :
6381 int effective_action = (j < 7 ? action :
6382 i == Xdrip_stretch ? action :
6383 i == Xdrip_stretchB ? action :
6384 i == Ydrip_s1 ? action :
6385 i == Ydrip_s1B ? action :
6386 i == Xball_1B ? action :
6387 i == Xball_2 ? action :
6388 i == Xball_2B ? action :
6389 i == Yball_eat ? action :
6390 i == Ykey_1_eat ? action :
6391 i == Ykey_2_eat ? action :
6392 i == Ykey_3_eat ? action :
6393 i == Ykey_4_eat ? action :
6394 i == Ykey_5_eat ? action :
6395 i == Ykey_6_eat ? action :
6396 i == Ykey_7_eat ? action :
6397 i == Ykey_8_eat ? action :
6398 i == Ylenses_eat ? action :
6399 i == Ymagnify_eat ? action :
6400 i == Ygrass_eat ? action :
6401 i == Ydirt_eat ? action :
6402 i == Xsand_stonein_1 ? action :
6403 i == Xsand_stonein_2 ? action :
6404 i == Xsand_stonein_3 ? action :
6405 i == Xsand_stonein_4 ? action :
6406 i == Xsand_stoneout_1 ? action :
6407 i == Xsand_stoneout_2 ? action :
6408 i == Xboom_android ? ACTION_EXPLODING :
6409 action_exploding ? ACTION_EXPLODING :
6410 action_active ? action :
6411 action_other ? action :
6413 int graphic = (el_act_dir2img(effective_element, effective_action,
6415 int crumbled = (el_act_dir2crm(effective_element, effective_action,
6417 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
6418 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
6419 boolean has_action_graphics = (graphic != base_graphic);
6420 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
6421 struct GraphicInfo *g = &graphic_info[graphic];
6423 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
6425 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
6428 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
6429 boolean special_animation = (action != ACTION_DEFAULT &&
6430 g->anim_frames == 3 &&
6431 g->anim_delay == 2 &&
6432 g->anim_mode & ANIM_LINEAR);
6433 int sync_frame = (i == Xdrip_stretch ? 7 :
6434 i == Xdrip_stretchB ? 7 :
6435 i == Ydrip_s2 ? j + 8 :
6436 i == Ydrip_s2B ? j + 8 :
6445 i == Xfake_acid_1 ? 0 :
6446 i == Xfake_acid_2 ? 10 :
6447 i == Xfake_acid_3 ? 20 :
6448 i == Xfake_acid_4 ? 30 :
6449 i == Xfake_acid_5 ? 40 :
6450 i == Xfake_acid_6 ? 50 :
6451 i == Xfake_acid_7 ? 60 :
6452 i == Xfake_acid_8 ? 70 :
6454 i == Xball_2B ? j + 8 :
6455 i == Yball_eat ? j + 1 :
6456 i == Ykey_1_eat ? j + 1 :
6457 i == Ykey_2_eat ? j + 1 :
6458 i == Ykey_3_eat ? j + 1 :
6459 i == Ykey_4_eat ? j + 1 :
6460 i == Ykey_5_eat ? j + 1 :
6461 i == Ykey_6_eat ? j + 1 :
6462 i == Ykey_7_eat ? j + 1 :
6463 i == Ykey_8_eat ? j + 1 :
6464 i == Ylenses_eat ? j + 1 :
6465 i == Ymagnify_eat ? j + 1 :
6466 i == Ygrass_eat ? j + 1 :
6467 i == Ydirt_eat ? j + 1 :
6468 i == Xamoeba_1 ? 0 :
6469 i == Xamoeba_2 ? 1 :
6470 i == Xamoeba_3 ? 2 :
6471 i == Xamoeba_4 ? 3 :
6472 i == Xamoeba_5 ? 0 :
6473 i == Xamoeba_6 ? 1 :
6474 i == Xamoeba_7 ? 2 :
6475 i == Xamoeba_8 ? 3 :
6476 i == Xexit_2 ? j + 8 :
6477 i == Xexit_3 ? j + 16 :
6478 i == Xdynamite_1 ? 0 :
6479 i == Xdynamite_2 ? 8 :
6480 i == Xdynamite_3 ? 16 :
6481 i == Xdynamite_4 ? 24 :
6482 i == Xsand_stonein_1 ? j + 1 :
6483 i == Xsand_stonein_2 ? j + 9 :
6484 i == Xsand_stonein_3 ? j + 17 :
6485 i == Xsand_stonein_4 ? j + 25 :
6486 i == Xsand_stoneout_1 && j == 0 ? 0 :
6487 i == Xsand_stoneout_1 && j == 1 ? 0 :
6488 i == Xsand_stoneout_1 && j == 2 ? 1 :
6489 i == Xsand_stoneout_1 && j == 3 ? 2 :
6490 i == Xsand_stoneout_1 && j == 4 ? 2 :
6491 i == Xsand_stoneout_1 && j == 5 ? 3 :
6492 i == Xsand_stoneout_1 && j == 6 ? 4 :
6493 i == Xsand_stoneout_1 && j == 7 ? 4 :
6494 i == Xsand_stoneout_2 && j == 0 ? 5 :
6495 i == Xsand_stoneout_2 && j == 1 ? 6 :
6496 i == Xsand_stoneout_2 && j == 2 ? 7 :
6497 i == Xsand_stoneout_2 && j == 3 ? 8 :
6498 i == Xsand_stoneout_2 && j == 4 ? 9 :
6499 i == Xsand_stoneout_2 && j == 5 ? 11 :
6500 i == Xsand_stoneout_2 && j == 6 ? 13 :
6501 i == Xsand_stoneout_2 && j == 7 ? 15 :
6502 i == Xboom_bug && j == 1 ? 2 :
6503 i == Xboom_bug && j == 2 ? 2 :
6504 i == Xboom_bug && j == 3 ? 4 :
6505 i == Xboom_bug && j == 4 ? 4 :
6506 i == Xboom_bug && j == 5 ? 2 :
6507 i == Xboom_bug && j == 6 ? 2 :
6508 i == Xboom_bug && j == 7 ? 0 :
6509 i == Xboom_bomb && j == 1 ? 2 :
6510 i == Xboom_bomb && j == 2 ? 2 :
6511 i == Xboom_bomb && j == 3 ? 4 :
6512 i == Xboom_bomb && j == 4 ? 4 :
6513 i == Xboom_bomb && j == 5 ? 2 :
6514 i == Xboom_bomb && j == 6 ? 2 :
6515 i == Xboom_bomb && j == 7 ? 0 :
6516 i == Xboom_android && j == 7 ? 6 :
6517 i == Xboom_1 && j == 1 ? 2 :
6518 i == Xboom_1 && j == 2 ? 2 :
6519 i == Xboom_1 && j == 3 ? 4 :
6520 i == Xboom_1 && j == 4 ? 4 :
6521 i == Xboom_1 && j == 5 ? 6 :
6522 i == Xboom_1 && j == 6 ? 6 :
6523 i == Xboom_1 && j == 7 ? 8 :
6524 i == Xboom_2 && j == 0 ? 8 :
6525 i == Xboom_2 && j == 1 ? 8 :
6526 i == Xboom_2 && j == 2 ? 10 :
6527 i == Xboom_2 && j == 3 ? 10 :
6528 i == Xboom_2 && j == 4 ? 10 :
6529 i == Xboom_2 && j == 5 ? 12 :
6530 i == Xboom_2 && j == 6 ? 12 :
6531 i == Xboom_2 && j == 7 ? 12 :
6532 special_animation && j == 4 ? 3 :
6533 effective_action != action ? 0 :
6537 Bitmap *debug_bitmap = g_em->bitmap;
6538 int debug_src_x = g_em->src_x;
6539 int debug_src_y = g_em->src_y;
6542 int frame = getAnimationFrame(g->anim_frames,
6545 g->anim_start_frame,
6548 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y,
6549 g->double_movement && is_backside);
6551 g_em->bitmap = src_bitmap;
6552 g_em->src_x = src_x;
6553 g_em->src_y = src_y;
6554 g_em->src_offset_x = 0;
6555 g_em->src_offset_y = 0;
6556 g_em->dst_offset_x = 0;
6557 g_em->dst_offset_y = 0;
6558 g_em->width = TILEX;
6559 g_em->height = TILEY;
6561 g_em->preserve_background = FALSE;
6564 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
6569 g_em->crumbled_bitmap = NULL;
6570 g_em->crumbled_src_x = 0;
6571 g_em->crumbled_src_y = 0;
6572 g_em->crumbled_border_size = 0;
6574 g_em->has_crumbled_graphics = FALSE;
6577 if (has_crumbled_graphics && crumbled == IMG_EMPTY_SPACE)
6578 printf("::: empty crumbled: %d [%s], %d, %d\n",
6579 effective_element, element_info[effective_element].token_name,
6580 effective_action, direction);
6583 /* if element can be crumbled, but certain action graphics are just empty
6584 space (like instantly snapping sand to empty space in 1 frame), do not
6585 treat these empty space graphics as crumbled graphics in EMC engine */
6586 if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
6588 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
6589 g_crumbled->anim_delay,
6590 g_crumbled->anim_mode,
6591 g_crumbled->anim_start_frame,
6594 getGraphicSource(crumbled, frame_crumbled, &src_bitmap, &src_x, &src_y);
6596 g_em->has_crumbled_graphics = TRUE;
6597 g_em->crumbled_bitmap = src_bitmap;
6598 g_em->crumbled_src_x = src_x;
6599 g_em->crumbled_src_y = src_y;
6600 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
6604 if (g_em == &graphic_info_em_object[207][0])
6605 printf("... %d, %d [%d, %d, %d, %d] [%d, %d, %d, %d, %d, %d => %d]\n",
6606 graphic_info_em_object[207][0].crumbled_src_x,
6607 graphic_info_em_object[207][0].crumbled_src_y,
6609 crumbled, frame, src_x, src_y,
6614 g->anim_start_frame,
6616 gfx.anim_random_frame,
6621 printf("::: EMC tile %d is crumbled\n", i);
6627 if (element == EL_ROCK &&
6628 effective_action == ACTION_FILLING)
6629 printf("::: has_action_graphics == %d\n", has_action_graphics);
6632 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
6633 effective_action == ACTION_MOVING ||
6634 effective_action == ACTION_PUSHING ||
6635 effective_action == ACTION_EATING)) ||
6636 (!has_action_graphics && (effective_action == ACTION_FILLING ||
6637 effective_action == ACTION_EMPTYING)))
6640 (effective_action == ACTION_FALLING ||
6641 effective_action == ACTION_FILLING ||
6642 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
6643 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
6644 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
6645 int num_steps = (i == Ydrip_s1 ? 16 :
6646 i == Ydrip_s1B ? 16 :
6647 i == Ydrip_s2 ? 16 :
6648 i == Ydrip_s2B ? 16 :
6649 i == Xsand_stonein_1 ? 32 :
6650 i == Xsand_stonein_2 ? 32 :
6651 i == Xsand_stonein_3 ? 32 :
6652 i == Xsand_stonein_4 ? 32 :
6653 i == Xsand_stoneout_1 ? 16 :
6654 i == Xsand_stoneout_2 ? 16 : 8);
6655 int cx = ABS(dx) * (TILEX / num_steps);
6656 int cy = ABS(dy) * (TILEY / num_steps);
6657 int step_frame = (i == Ydrip_s2 ? j + 8 :
6658 i == Ydrip_s2B ? j + 8 :
6659 i == Xsand_stonein_2 ? j + 8 :
6660 i == Xsand_stonein_3 ? j + 16 :
6661 i == Xsand_stonein_4 ? j + 24 :
6662 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
6663 int step = (is_backside ? step_frame : num_steps - step_frame);
6665 if (is_backside) /* tile where movement starts */
6667 if (dx < 0 || dy < 0)
6669 g_em->src_offset_x = cx * step;
6670 g_em->src_offset_y = cy * step;
6674 g_em->dst_offset_x = cx * step;
6675 g_em->dst_offset_y = cy * step;
6678 else /* tile where movement ends */
6680 if (dx < 0 || dy < 0)
6682 g_em->dst_offset_x = cx * step;
6683 g_em->dst_offset_y = cy * step;
6687 g_em->src_offset_x = cx * step;
6688 g_em->src_offset_y = cy * step;
6692 g_em->width = TILEX - cx * step;
6693 g_em->height = TILEY - cy * step;
6696 /* create unique graphic identifier to decide if tile must be redrawn */
6697 /* bit 31 - 16 (16 bit): EM style graphic
6698 bit 15 - 12 ( 4 bit): EM style frame
6699 bit 11 - 6 ( 6 bit): graphic width
6700 bit 5 - 0 ( 6 bit): graphic height */
6701 g_em->unique_identifier =
6702 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
6706 /* skip check for EMC elements not contained in original EMC artwork */
6707 if (element == EL_EMC_FAKE_ACID)
6710 if (g_em->bitmap != debug_bitmap ||
6711 g_em->src_x != debug_src_x ||
6712 g_em->src_y != debug_src_y ||
6713 g_em->src_offset_x != 0 ||
6714 g_em->src_offset_y != 0 ||
6715 g_em->dst_offset_x != 0 ||
6716 g_em->dst_offset_y != 0 ||
6717 g_em->width != TILEX ||
6718 g_em->height != TILEY)
6720 static int last_i = -1;
6728 printf("::: EMC GFX ERROR for element %d -> %d ('%s', '%s', %d)",
6729 i, element, element_info[element].token_name,
6730 element_action_info[effective_action].suffix, direction);
6732 if (element != effective_element)
6733 printf(" [%d ('%s')]",
6735 element_info[effective_element].token_name);
6739 if (g_em->bitmap != debug_bitmap)
6740 printf(" %d (%d): different bitmap! (0x%08x != 0x%08x)\n",
6741 j, is_backside, (int)(g_em->bitmap), (int)(debug_bitmap));
6743 if (g_em->src_x != debug_src_x ||
6744 g_em->src_y != debug_src_y)
6745 printf(" frame %d (%c): %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
6746 j, (is_backside ? 'B' : 'F'),
6747 g_em->src_x, g_em->src_y,
6748 g_em->src_x / 32, g_em->src_y / 32,
6749 debug_src_x, debug_src_y,
6750 debug_src_x / 32, debug_src_y / 32);
6752 if (g_em->src_offset_x != 0 ||
6753 g_em->src_offset_y != 0 ||
6754 g_em->dst_offset_x != 0 ||
6755 g_em->dst_offset_y != 0)
6756 printf(" %d (%d): offsets %d,%d and %d,%d should be all 0\n",
6758 g_em->src_offset_x, g_em->src_offset_y,
6759 g_em->dst_offset_x, g_em->dst_offset_y);
6761 if (g_em->width != TILEX ||
6762 g_em->height != TILEY)
6763 printf(" %d (%d): size %d,%d should be %d,%d\n",
6765 g_em->width, g_em->height, TILEX, TILEY);
6767 num_em_gfx_errors++;
6774 for (i = 0; i < TILE_MAX; i++)
6776 for (j = 0; j < 8; j++)
6778 int element = object_mapping[i].element_rnd;
6779 int action = object_mapping[i].action;
6780 int direction = object_mapping[i].direction;
6781 boolean is_backside = object_mapping[i].is_backside;
6782 int graphic_action = el_act_dir2img(element, action, direction);
6783 int graphic_default = el_act_dir2img(element, ACTION_DEFAULT, direction);
6785 if ((action == ACTION_SMASHED_BY_ROCK ||
6786 action == ACTION_SMASHED_BY_SPRING ||
6787 action == ACTION_EATING) &&
6788 graphic_action == graphic_default)
6790 int e = (action == ACTION_SMASHED_BY_ROCK ? Ystone_s :
6791 action == ACTION_SMASHED_BY_SPRING ? Yspring_s :
6792 direction == MV_LEFT ? (is_backside? Yspring_wB: Yspring_w) :
6793 direction == MV_RIGHT ? (is_backside? Yspring_eB: Yspring_e) :
6796 /* no separate animation for "smashed by rock" -- use rock instead */
6797 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
6798 struct GraphicInfo_EM *g_xx = &graphic_info_em_object[e][7 - j];
6800 g_em->bitmap = g_xx->bitmap;
6801 g_em->src_x = g_xx->src_x;
6802 g_em->src_y = g_xx->src_y;
6803 g_em->src_offset_x = g_xx->src_offset_x;
6804 g_em->src_offset_y = g_xx->src_offset_y;
6805 g_em->dst_offset_x = g_xx->dst_offset_x;
6806 g_em->dst_offset_y = g_xx->dst_offset_y;
6807 g_em->width = g_xx->width;
6808 g_em->height = g_xx->height;
6809 g_em->unique_identifier = g_xx->unique_identifier;
6812 g_em->preserve_background = TRUE;
6817 for (p = 0; p < MAX_PLAYERS; p++)
6819 for (i = 0; i < SPR_MAX; i++)
6821 int element = player_mapping[p][i].element_rnd;
6822 int action = player_mapping[p][i].action;
6823 int direction = player_mapping[p][i].direction;
6825 for (j = 0; j < 8; j++)
6827 int effective_element = element;
6828 int effective_action = action;
6829 int graphic = (direction == MV_NONE ?
6830 el_act2img(effective_element, effective_action) :
6831 el_act_dir2img(effective_element, effective_action,
6833 struct GraphicInfo *g = &graphic_info[graphic];
6834 struct GraphicInfo_EM *g_em = &graphic_info_em_player[p][i][7 - j];
6840 Bitmap *debug_bitmap = g_em->bitmap;
6841 int debug_src_x = g_em->src_x;
6842 int debug_src_y = g_em->src_y;
6845 int frame = getAnimationFrame(g->anim_frames,
6848 g->anim_start_frame,
6851 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
6853 g_em->bitmap = src_bitmap;
6854 g_em->src_x = src_x;
6855 g_em->src_y = src_y;
6856 g_em->src_offset_x = 0;
6857 g_em->src_offset_y = 0;
6858 g_em->dst_offset_x = 0;
6859 g_em->dst_offset_y = 0;
6860 g_em->width = TILEX;
6861 g_em->height = TILEY;
6865 /* skip check for EMC elements not contained in original EMC artwork */
6866 if (element == EL_PLAYER_3 ||
6867 element == EL_PLAYER_4)
6870 if (g_em->bitmap != debug_bitmap ||
6871 g_em->src_x != debug_src_x ||
6872 g_em->src_y != debug_src_y)
6874 static int last_i = -1;
6882 printf("::: EMC GFX ERROR for p/a %d/%d -> %d ('%s', '%s', %d)",
6883 p, i, element, element_info[element].token_name,
6884 element_action_info[effective_action].suffix, direction);
6886 if (element != effective_element)
6887 printf(" [%d ('%s')]",
6889 element_info[effective_element].token_name);
6893 if (g_em->bitmap != debug_bitmap)
6894 printf(" %d: different bitmap! (0x%08x != 0x%08x)\n",
6895 j, (int)(g_em->bitmap), (int)(debug_bitmap));
6897 if (g_em->src_x != debug_src_x ||
6898 g_em->src_y != debug_src_y)
6899 printf(" frame %d: %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
6901 g_em->src_x, g_em->src_y,
6902 g_em->src_x / 32, g_em->src_y / 32,
6903 debug_src_x, debug_src_y,
6904 debug_src_x / 32, debug_src_y / 32);
6906 num_em_gfx_errors++;
6916 printf("::: [%d errors found]\n", num_em_gfx_errors);
6922 void PlayMenuSoundExt(int sound)
6924 if (sound == SND_UNDEFINED)
6927 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
6928 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
6931 if (IS_LOOP_SOUND(sound))
6932 PlaySoundLoop(sound);
6937 void PlayMenuSound()
6939 PlayMenuSoundExt(menu.sound[game_status]);
6942 void PlayMenuSoundStereo(int sound, int stereo_position)
6944 if (sound == SND_UNDEFINED)
6947 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
6948 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
6951 if (IS_LOOP_SOUND(sound))
6952 PlaySoundExt(sound, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_LOOP);
6954 PlaySoundStereo(sound, stereo_position);
6957 void PlayMenuSoundIfLoopExt(int sound)
6959 if (sound == SND_UNDEFINED)
6962 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
6963 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
6966 if (IS_LOOP_SOUND(sound))
6967 PlaySoundLoop(sound);
6970 void PlayMenuSoundIfLoop()
6972 PlayMenuSoundIfLoopExt(menu.sound[game_status]);
6975 void PlayMenuMusicExt(int music)
6977 if (music == MUS_UNDEFINED)
6980 if (!setup.sound_music)
6986 void PlayMenuMusic()
6988 PlayMenuMusicExt(menu.music[game_status]);
6991 void PlaySoundActivating()
6994 PlaySound(SND_MENU_ITEM_ACTIVATING);
6998 void PlaySoundSelecting()
7001 PlaySound(SND_MENU_ITEM_SELECTING);
7005 void ToggleFullscreenIfNeeded()
7007 boolean change_fullscreen = (setup.fullscreen !=
7008 video.fullscreen_enabled);
7009 boolean change_fullscreen_mode = (video.fullscreen_enabled &&
7010 !strEqual(setup.fullscreen_mode,
7011 video.fullscreen_mode_current));
7013 if (!video.fullscreen_available)
7017 if (change_fullscreen || change_fullscreen_mode)
7019 if (setup.fullscreen != video.fullscreen_enabled ||
7020 setup.fullscreen_mode != video.fullscreen_mode_current)
7023 Bitmap *tmp_backbuffer = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
7025 /* save backbuffer content which gets lost when toggling fullscreen mode */
7026 BlitBitmap(backbuffer, tmp_backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
7029 if (change_fullscreen_mode)
7031 if (setup.fullscreen && video.fullscreen_enabled)
7034 /* keep fullscreen, but change fullscreen mode (screen resolution) */
7036 /* (this is now set in sdl.c) */
7038 video.fullscreen_mode_current = setup.fullscreen_mode;
7040 video.fullscreen_enabled = FALSE; /* force new fullscreen mode */
7043 /* toggle fullscreen */
7044 ChangeVideoModeIfNeeded(setup.fullscreen);
7046 setup.fullscreen = video.fullscreen_enabled;
7048 /* restore backbuffer content from temporary backbuffer backup bitmap */
7049 BlitBitmap(tmp_backbuffer, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
7051 FreeBitmap(tmp_backbuffer);
7054 /* update visible window/screen */
7055 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
7057 redraw_mask = REDRAW_ALL;