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
4800 Xsand_stonesand_1, FALSE, FALSE,
4801 EL_QUICKSAND_FULL, -1, -1
4804 Xsand_stonesand_2, FALSE, FALSE,
4805 EL_QUICKSAND_FULL, -1, -1
4808 Xsand_stonesand_3, FALSE, FALSE,
4809 EL_QUICKSAND_FULL, -1, -1
4812 Xsand_stonesand_4, FALSE, FALSE,
4813 EL_QUICKSAND_FULL, -1, -1
4816 Xsand_stoneout_1, FALSE, FALSE,
4817 EL_ROCK, ACTION_EMPTYING, -1
4820 Xsand_stoneout_2, FALSE, FALSE,
4821 EL_ROCK, ACTION_EMPTYING, -1
4824 Xsand_sandstone_1, FALSE, FALSE,
4825 EL_QUICKSAND_FULL, -1, -1
4828 Xsand_sandstone_2, FALSE, FALSE,
4829 EL_QUICKSAND_FULL, -1, -1
4832 Xsand_sandstone_3, FALSE, FALSE,
4833 EL_QUICKSAND_FULL, -1, -1
4836 Xsand_sandstone_4, FALSE, FALSE,
4837 EL_QUICKSAND_FULL, -1, -1
4840 Xplant, TRUE, FALSE,
4841 EL_EMC_PLANT, -1, -1
4844 Yplant, FALSE, FALSE,
4845 EL_EMC_PLANT, -1, -1
4848 Xlenses, TRUE, FALSE,
4849 EL_EMC_LENSES, -1, -1
4852 Xmagnify, TRUE, FALSE,
4853 EL_EMC_MAGNIFIER, -1, -1
4856 Xdripper, TRUE, FALSE,
4857 EL_EMC_DRIPPER, -1, -1
4860 XdripperB, FALSE, FALSE,
4861 EL_EMC_DRIPPER, ACTION_ACTIVE, -1
4864 Xfake_blank, TRUE, FALSE,
4865 EL_INVISIBLE_WALL, -1, -1
4868 Xfake_blankB, FALSE, FALSE,
4869 EL_INVISIBLE_WALL, ACTION_ACTIVE, -1
4872 Xfake_grass, TRUE, FALSE,
4873 EL_EMC_FAKE_GRASS, -1, -1
4876 Xfake_grassB, FALSE, FALSE,
4877 EL_EMC_FAKE_GRASS, ACTION_ACTIVE, -1
4880 Xfake_door_1, TRUE, FALSE,
4881 EL_EM_GATE_1_GRAY, -1, -1
4884 Xfake_door_2, TRUE, FALSE,
4885 EL_EM_GATE_2_GRAY, -1, -1
4888 Xfake_door_3, TRUE, FALSE,
4889 EL_EM_GATE_3_GRAY, -1, -1
4892 Xfake_door_4, TRUE, FALSE,
4893 EL_EM_GATE_4_GRAY, -1, -1
4896 Xfake_door_5, TRUE, FALSE,
4897 EL_EMC_GATE_5_GRAY, -1, -1
4900 Xfake_door_6, TRUE, FALSE,
4901 EL_EMC_GATE_6_GRAY, -1, -1
4904 Xfake_door_7, TRUE, FALSE,
4905 EL_EMC_GATE_7_GRAY, -1, -1
4908 Xfake_door_8, TRUE, FALSE,
4909 EL_EMC_GATE_8_GRAY, -1, -1
4912 Xfake_acid_1, TRUE, FALSE,
4913 EL_EMC_FAKE_ACID, -1, -1
4916 Xfake_acid_2, FALSE, FALSE,
4917 EL_EMC_FAKE_ACID, -1, -1
4920 Xfake_acid_3, FALSE, FALSE,
4921 EL_EMC_FAKE_ACID, -1, -1
4924 Xfake_acid_4, FALSE, FALSE,
4925 EL_EMC_FAKE_ACID, -1, -1
4928 Xfake_acid_5, FALSE, FALSE,
4929 EL_EMC_FAKE_ACID, -1, -1
4932 Xfake_acid_6, FALSE, FALSE,
4933 EL_EMC_FAKE_ACID, -1, -1
4936 Xfake_acid_7, FALSE, FALSE,
4937 EL_EMC_FAKE_ACID, -1, -1
4940 Xfake_acid_8, FALSE, FALSE,
4941 EL_EMC_FAKE_ACID, -1, -1
4944 Xsteel_1, TRUE, FALSE,
4945 EL_STEELWALL, -1, -1
4948 Xsteel_2, TRUE, FALSE,
4949 EL_EMC_STEELWALL_2, -1, -1
4952 Xsteel_3, TRUE, FALSE,
4953 EL_EMC_STEELWALL_3, -1, -1
4956 Xsteel_4, TRUE, FALSE,
4957 EL_EMC_STEELWALL_4, -1, -1
4960 Xwall_1, TRUE, FALSE,
4964 Xwall_2, TRUE, FALSE,
4965 EL_EMC_WALL_14, -1, -1
4968 Xwall_3, TRUE, FALSE,
4969 EL_EMC_WALL_15, -1, -1
4972 Xwall_4, TRUE, FALSE,
4973 EL_EMC_WALL_16, -1, -1
4976 Xround_wall_1, TRUE, FALSE,
4977 EL_WALL_SLIPPERY, -1, -1
4980 Xround_wall_2, TRUE, FALSE,
4981 EL_EMC_WALL_SLIPPERY_2, -1, -1
4984 Xround_wall_3, TRUE, FALSE,
4985 EL_EMC_WALL_SLIPPERY_3, -1, -1
4988 Xround_wall_4, TRUE, FALSE,
4989 EL_EMC_WALL_SLIPPERY_4, -1, -1
4992 Xdecor_1, TRUE, FALSE,
4993 EL_EMC_WALL_8, -1, -1
4996 Xdecor_2, TRUE, FALSE,
4997 EL_EMC_WALL_6, -1, -1
5000 Xdecor_3, TRUE, FALSE,
5001 EL_EMC_WALL_4, -1, -1
5004 Xdecor_4, TRUE, FALSE,
5005 EL_EMC_WALL_7, -1, -1
5008 Xdecor_5, TRUE, FALSE,
5009 EL_EMC_WALL_5, -1, -1
5012 Xdecor_6, TRUE, FALSE,
5013 EL_EMC_WALL_9, -1, -1
5016 Xdecor_7, TRUE, FALSE,
5017 EL_EMC_WALL_10, -1, -1
5020 Xdecor_8, TRUE, FALSE,
5021 EL_EMC_WALL_1, -1, -1
5024 Xdecor_9, TRUE, FALSE,
5025 EL_EMC_WALL_2, -1, -1
5028 Xdecor_10, TRUE, FALSE,
5029 EL_EMC_WALL_3, -1, -1
5032 Xdecor_11, TRUE, FALSE,
5033 EL_EMC_WALL_11, -1, -1
5036 Xdecor_12, TRUE, FALSE,
5037 EL_EMC_WALL_12, -1, -1
5040 Xalpha_0, TRUE, FALSE,
5041 EL_CHAR('0'), -1, -1
5044 Xalpha_1, TRUE, FALSE,
5045 EL_CHAR('1'), -1, -1
5048 Xalpha_2, TRUE, FALSE,
5049 EL_CHAR('2'), -1, -1
5052 Xalpha_3, TRUE, FALSE,
5053 EL_CHAR('3'), -1, -1
5056 Xalpha_4, TRUE, FALSE,
5057 EL_CHAR('4'), -1, -1
5060 Xalpha_5, TRUE, FALSE,
5061 EL_CHAR('5'), -1, -1
5064 Xalpha_6, TRUE, FALSE,
5065 EL_CHAR('6'), -1, -1
5068 Xalpha_7, TRUE, FALSE,
5069 EL_CHAR('7'), -1, -1
5072 Xalpha_8, TRUE, FALSE,
5073 EL_CHAR('8'), -1, -1
5076 Xalpha_9, TRUE, FALSE,
5077 EL_CHAR('9'), -1, -1
5080 Xalpha_excla, TRUE, FALSE,
5081 EL_CHAR('!'), -1, -1
5084 Xalpha_quote, TRUE, FALSE,
5085 EL_CHAR('"'), -1, -1
5088 Xalpha_comma, TRUE, FALSE,
5089 EL_CHAR(','), -1, -1
5092 Xalpha_minus, TRUE, FALSE,
5093 EL_CHAR('-'), -1, -1
5096 Xalpha_perio, TRUE, FALSE,
5097 EL_CHAR('.'), -1, -1
5100 Xalpha_colon, TRUE, FALSE,
5101 EL_CHAR(':'), -1, -1
5104 Xalpha_quest, TRUE, FALSE,
5105 EL_CHAR('?'), -1, -1
5108 Xalpha_a, TRUE, FALSE,
5109 EL_CHAR('A'), -1, -1
5112 Xalpha_b, TRUE, FALSE,
5113 EL_CHAR('B'), -1, -1
5116 Xalpha_c, TRUE, FALSE,
5117 EL_CHAR('C'), -1, -1
5120 Xalpha_d, TRUE, FALSE,
5121 EL_CHAR('D'), -1, -1
5124 Xalpha_e, TRUE, FALSE,
5125 EL_CHAR('E'), -1, -1
5128 Xalpha_f, TRUE, FALSE,
5129 EL_CHAR('F'), -1, -1
5132 Xalpha_g, TRUE, FALSE,
5133 EL_CHAR('G'), -1, -1
5136 Xalpha_h, TRUE, FALSE,
5137 EL_CHAR('H'), -1, -1
5140 Xalpha_i, TRUE, FALSE,
5141 EL_CHAR('I'), -1, -1
5144 Xalpha_j, TRUE, FALSE,
5145 EL_CHAR('J'), -1, -1
5148 Xalpha_k, TRUE, FALSE,
5149 EL_CHAR('K'), -1, -1
5152 Xalpha_l, TRUE, FALSE,
5153 EL_CHAR('L'), -1, -1
5156 Xalpha_m, TRUE, FALSE,
5157 EL_CHAR('M'), -1, -1
5160 Xalpha_n, TRUE, FALSE,
5161 EL_CHAR('N'), -1, -1
5164 Xalpha_o, TRUE, FALSE,
5165 EL_CHAR('O'), -1, -1
5168 Xalpha_p, TRUE, FALSE,
5169 EL_CHAR('P'), -1, -1
5172 Xalpha_q, TRUE, FALSE,
5173 EL_CHAR('Q'), -1, -1
5176 Xalpha_r, TRUE, FALSE,
5177 EL_CHAR('R'), -1, -1
5180 Xalpha_s, TRUE, FALSE,
5181 EL_CHAR('S'), -1, -1
5184 Xalpha_t, TRUE, FALSE,
5185 EL_CHAR('T'), -1, -1
5188 Xalpha_u, TRUE, FALSE,
5189 EL_CHAR('U'), -1, -1
5192 Xalpha_v, TRUE, FALSE,
5193 EL_CHAR('V'), -1, -1
5196 Xalpha_w, TRUE, FALSE,
5197 EL_CHAR('W'), -1, -1
5200 Xalpha_x, TRUE, FALSE,
5201 EL_CHAR('X'), -1, -1
5204 Xalpha_y, TRUE, FALSE,
5205 EL_CHAR('Y'), -1, -1
5208 Xalpha_z, TRUE, FALSE,
5209 EL_CHAR('Z'), -1, -1
5212 Xalpha_arrow_e, TRUE, FALSE,
5213 EL_CHAR('>'), -1, -1
5216 Xalpha_arrow_w, TRUE, FALSE,
5217 EL_CHAR('<'), -1, -1
5220 Xalpha_copyr, TRUE, FALSE,
5221 EL_CHAR('©'), -1, -1
5225 Xboom_bug, FALSE, FALSE,
5226 EL_BUG, ACTION_EXPLODING, -1
5229 Xboom_bomb, FALSE, FALSE,
5230 EL_BOMB, ACTION_EXPLODING, -1
5233 Xboom_android, FALSE, FALSE,
5234 EL_EMC_ANDROID, ACTION_OTHER, -1
5237 Xboom_1, FALSE, FALSE,
5238 EL_DEFAULT, ACTION_EXPLODING, -1
5241 Xboom_2, FALSE, FALSE,
5242 EL_DEFAULT, ACTION_EXPLODING, -1
5245 Znormal, FALSE, FALSE,
5249 Zdynamite, FALSE, FALSE,
5253 Zplayer, FALSE, FALSE,
5257 ZBORDER, FALSE, FALSE,
5267 static struct Mapping_EM_to_RND_player
5276 em_player_mapping_list[] =
5280 EL_PLAYER_1, ACTION_MOVING, MV_BIT_UP,
5284 EL_PLAYER_1, ACTION_MOVING, MV_BIT_RIGHT,
5288 EL_PLAYER_1, ACTION_MOVING, MV_BIT_DOWN,
5292 EL_PLAYER_1, ACTION_MOVING, MV_BIT_LEFT,
5296 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_UP,
5300 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_RIGHT,
5304 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_DOWN,
5308 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_LEFT,
5312 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_UP,
5316 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_RIGHT,
5320 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_DOWN,
5324 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_LEFT,
5328 EL_PLAYER_2, ACTION_MOVING, MV_BIT_UP,
5332 EL_PLAYER_2, ACTION_MOVING, MV_BIT_RIGHT,
5336 EL_PLAYER_2, ACTION_MOVING, MV_BIT_DOWN,
5340 EL_PLAYER_2, ACTION_MOVING, MV_BIT_LEFT,
5344 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_UP,
5348 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_RIGHT,
5352 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_DOWN,
5356 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_LEFT,
5360 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_UP,
5364 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_RIGHT,
5368 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_DOWN,
5372 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_LEFT,
5376 EL_PLAYER_1, ACTION_DEFAULT, -1,
5380 EL_PLAYER_2, ACTION_DEFAULT, -1,
5384 EL_PLAYER_3, ACTION_MOVING, MV_BIT_UP,
5388 EL_PLAYER_3, ACTION_MOVING, MV_BIT_RIGHT,
5392 EL_PLAYER_3, ACTION_MOVING, MV_BIT_DOWN,
5396 EL_PLAYER_3, ACTION_MOVING, MV_BIT_LEFT,
5400 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_UP,
5404 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_RIGHT,
5408 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_DOWN,
5412 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_LEFT,
5416 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_UP,
5420 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_RIGHT,
5424 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_DOWN,
5428 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_LEFT,
5432 EL_PLAYER_4, ACTION_MOVING, MV_BIT_UP,
5436 EL_PLAYER_4, ACTION_MOVING, MV_BIT_RIGHT,
5440 EL_PLAYER_4, ACTION_MOVING, MV_BIT_DOWN,
5444 EL_PLAYER_4, ACTION_MOVING, MV_BIT_LEFT,
5448 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_UP,
5452 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_RIGHT,
5456 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_DOWN,
5460 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_LEFT,
5464 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_UP,
5468 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_RIGHT,
5472 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_DOWN,
5476 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_LEFT,
5480 EL_PLAYER_3, ACTION_DEFAULT, -1,
5484 EL_PLAYER_4, ACTION_DEFAULT, -1,
5493 int map_element_RND_to_EM(int element_rnd)
5495 static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
5496 static boolean mapping_initialized = FALSE;
5498 if (!mapping_initialized)
5502 /* return "Xalpha_quest" for all undefined elements in mapping array */
5503 for (i = 0; i < NUM_FILE_ELEMENTS; i++)
5504 mapping_RND_to_EM[i] = Xalpha_quest;
5506 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5507 if (em_object_mapping_list[i].is_rnd_to_em_mapping)
5508 mapping_RND_to_EM[em_object_mapping_list[i].element_rnd] =
5509 em_object_mapping_list[i].element_em;
5511 mapping_initialized = TRUE;
5514 if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
5515 return mapping_RND_to_EM[element_rnd];
5517 Error(ERR_WARN, "invalid RND level element %d", element_rnd);
5522 int map_element_EM_to_RND(int element_em)
5524 static unsigned short mapping_EM_to_RND[TILE_MAX];
5525 static boolean mapping_initialized = FALSE;
5527 if (!mapping_initialized)
5531 /* return "EL_UNKNOWN" for all undefined elements in mapping array */
5532 for (i = 0; i < TILE_MAX; i++)
5533 mapping_EM_to_RND[i] = EL_UNKNOWN;
5535 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5536 mapping_EM_to_RND[em_object_mapping_list[i].element_em] =
5537 em_object_mapping_list[i].element_rnd;
5539 mapping_initialized = TRUE;
5542 if (element_em >= 0 && element_em < TILE_MAX)
5543 return mapping_EM_to_RND[element_em];
5545 Error(ERR_WARN, "invalid EM level element %d", element_em);
5550 void map_android_clone_elements_RND_to_EM(struct LevelInfo *level)
5552 struct LevelInfo_EM *level_em = level->native_em_level;
5553 struct LEVEL *lev = level_em->lev;
5556 for (i = 0; i < TILE_MAX; i++)
5557 lev->android_array[i] = Xblank;
5559 for (i = 0; i < level->num_android_clone_elements; i++)
5561 int element_rnd = level->android_clone_element[i];
5562 int element_em = map_element_RND_to_EM(element_rnd);
5564 for (j = 0; em_object_mapping_list[j].element_em != -1; j++)
5565 if (em_object_mapping_list[j].element_rnd == element_rnd)
5566 lev->android_array[em_object_mapping_list[j].element_em] = element_em;
5570 void map_android_clone_elements_EM_to_RND(struct LevelInfo *level)
5572 struct LevelInfo_EM *level_em = level->native_em_level;
5573 struct LEVEL *lev = level_em->lev;
5576 level->num_android_clone_elements = 0;
5578 for (i = 0; i < TILE_MAX; i++)
5580 int element_em = lev->android_array[i];
5582 boolean element_found = FALSE;
5584 if (element_em == Xblank)
5587 element_rnd = map_element_EM_to_RND(element_em);
5589 for (j = 0; j < level->num_android_clone_elements; j++)
5590 if (level->android_clone_element[j] == element_rnd)
5591 element_found = TRUE;
5595 level->android_clone_element[level->num_android_clone_elements++] =
5598 if (level->num_android_clone_elements == MAX_ANDROID_ELEMENTS)
5603 if (level->num_android_clone_elements == 0)
5605 level->num_android_clone_elements = 1;
5606 level->android_clone_element[0] = EL_EMPTY;
5610 int map_direction_RND_to_EM(int direction)
5612 return (direction == MV_UP ? 0 :
5613 direction == MV_RIGHT ? 1 :
5614 direction == MV_DOWN ? 2 :
5615 direction == MV_LEFT ? 3 :
5619 int map_direction_EM_to_RND(int direction)
5621 return (direction == 0 ? MV_UP :
5622 direction == 1 ? MV_RIGHT :
5623 direction == 2 ? MV_DOWN :
5624 direction == 3 ? MV_LEFT :
5628 int get_next_element(int element)
5632 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
5633 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
5634 case EL_QUICKSAND_FAST_FILLING: return EL_QUICKSAND_FAST_FULL;
5635 case EL_QUICKSAND_FAST_EMPTYING: return EL_QUICKSAND_FAST_EMPTY;
5636 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
5637 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
5638 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
5639 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
5640 case EL_DC_MAGIC_WALL_FILLING: return EL_DC_MAGIC_WALL_FULL;
5641 case EL_DC_MAGIC_WALL_EMPTYING: return EL_DC_MAGIC_WALL_ACTIVE;
5642 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
5644 default: return element;
5649 int el_act_dir2img(int element, int action, int direction)
5651 element = GFX_ELEMENT(element);
5653 if (direction == MV_NONE)
5654 return element_info[element].graphic[action];
5656 direction = MV_DIR_TO_BIT(direction);
5658 return element_info[element].direction_graphic[action][direction];
5661 int el_act_dir2img(int element, int action, int direction)
5663 element = GFX_ELEMENT(element);
5664 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
5666 /* direction_graphic[][] == graphic[] for undefined direction graphics */
5667 return element_info[element].direction_graphic[action][direction];
5672 static int el_act_dir2crm(int element, int action, int direction)
5674 element = GFX_ELEMENT(element);
5676 if (direction == MV_NONE)
5677 return element_info[element].crumbled[action];
5679 direction = MV_DIR_TO_BIT(direction);
5681 return element_info[element].direction_crumbled[action][direction];
5684 static int el_act_dir2crm(int element, int action, int direction)
5686 element = GFX_ELEMENT(element);
5687 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
5689 /* direction_graphic[][] == graphic[] for undefined direction graphics */
5690 return element_info[element].direction_crumbled[action][direction];
5694 int el_act2img(int element, int action)
5696 element = GFX_ELEMENT(element);
5698 return element_info[element].graphic[action];
5701 int el_act2crm(int element, int action)
5703 element = GFX_ELEMENT(element);
5705 return element_info[element].crumbled[action];
5708 int el_dir2img(int element, int direction)
5710 element = GFX_ELEMENT(element);
5712 return el_act_dir2img(element, ACTION_DEFAULT, direction);
5715 int el2baseimg(int element)
5717 return element_info[element].graphic[ACTION_DEFAULT];
5720 int el2img(int element)
5722 element = GFX_ELEMENT(element);
5724 return element_info[element].graphic[ACTION_DEFAULT];
5727 int el2edimg(int element)
5729 element = GFX_ELEMENT(element);
5731 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
5734 int el2preimg(int element)
5736 element = GFX_ELEMENT(element);
5738 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
5741 int el2panelimg(int element)
5743 element = GFX_ELEMENT(element);
5745 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PANEL];
5748 int font2baseimg(int font_nr)
5750 return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
5753 int getBeltNrFromBeltElement(int element)
5755 return (element < EL_CONVEYOR_BELT_2_LEFT ? 0 :
5756 element < EL_CONVEYOR_BELT_3_LEFT ? 1 :
5757 element < EL_CONVEYOR_BELT_4_LEFT ? 2 : 3);
5760 int getBeltNrFromBeltActiveElement(int element)
5762 return (element < EL_CONVEYOR_BELT_2_LEFT_ACTIVE ? 0 :
5763 element < EL_CONVEYOR_BELT_3_LEFT_ACTIVE ? 1 :
5764 element < EL_CONVEYOR_BELT_4_LEFT_ACTIVE ? 2 : 3);
5767 int getBeltNrFromBeltSwitchElement(int element)
5769 return (element < EL_CONVEYOR_BELT_2_SWITCH_LEFT ? 0 :
5770 element < EL_CONVEYOR_BELT_3_SWITCH_LEFT ? 1 :
5771 element < EL_CONVEYOR_BELT_4_SWITCH_LEFT ? 2 : 3);
5774 int getBeltDirNrFromBeltElement(int element)
5776 static int belt_base_element[4] =
5778 EL_CONVEYOR_BELT_1_LEFT,
5779 EL_CONVEYOR_BELT_2_LEFT,
5780 EL_CONVEYOR_BELT_3_LEFT,
5781 EL_CONVEYOR_BELT_4_LEFT
5784 int belt_nr = getBeltNrFromBeltElement(element);
5785 int belt_dir_nr = element - belt_base_element[belt_nr];
5787 return (belt_dir_nr % 3);
5790 int getBeltDirNrFromBeltSwitchElement(int element)
5792 static int belt_base_element[4] =
5794 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
5795 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
5796 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
5797 EL_CONVEYOR_BELT_4_SWITCH_LEFT
5800 int belt_nr = getBeltNrFromBeltSwitchElement(element);
5801 int belt_dir_nr = element - belt_base_element[belt_nr];
5803 return (belt_dir_nr % 3);
5806 int getBeltDirFromBeltElement(int element)
5808 static int belt_move_dir[3] =
5815 int belt_dir_nr = getBeltDirNrFromBeltElement(element);
5817 return belt_move_dir[belt_dir_nr];
5820 int getBeltDirFromBeltSwitchElement(int element)
5822 static int belt_move_dir[3] =
5829 int belt_dir_nr = getBeltDirNrFromBeltSwitchElement(element);
5831 return belt_move_dir[belt_dir_nr];
5834 int getBeltElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
5836 static int belt_base_element[4] =
5838 EL_CONVEYOR_BELT_1_LEFT,
5839 EL_CONVEYOR_BELT_2_LEFT,
5840 EL_CONVEYOR_BELT_3_LEFT,
5841 EL_CONVEYOR_BELT_4_LEFT
5844 return belt_base_element[belt_nr] + belt_dir_nr;
5847 int getBeltElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
5849 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
5851 return getBeltElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
5854 int getBeltSwitchElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
5856 static int belt_base_element[4] =
5858 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
5859 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
5860 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
5861 EL_CONVEYOR_BELT_4_SWITCH_LEFT
5864 return belt_base_element[belt_nr] + belt_dir_nr;
5867 int getBeltSwitchElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
5869 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
5871 return getBeltSwitchElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
5874 int getNumActivePlayers_EM()
5876 int num_players = 0;
5882 for (i = 0; i < MAX_PLAYERS; i++)
5883 if (tape.player_participates[i])
5889 int getGameFrameDelay_EM(int native_em_game_frame_delay)
5891 int game_frame_delay_value;
5893 game_frame_delay_value =
5894 (tape.playing && tape.fast_forward ? FfwdFrameDelay :
5895 GameFrameDelay == GAME_FRAME_DELAY ? native_em_game_frame_delay :
5898 if (tape.playing && tape.warp_forward && !tape.pausing)
5899 game_frame_delay_value = 0;
5901 return game_frame_delay_value;
5904 unsigned int InitRND(long seed)
5906 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
5907 return InitEngineRandom_EM(seed);
5909 return InitEngineRandom_RND(seed);
5913 static struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
5914 static struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
5917 void ResetGfxAnimation_EM(int x, int y, int tile)
5922 void SetGfxAnimation_EM(int tile, int frame_em, int x, int y)
5925 int element = object_mapping[tile].element_rnd;
5927 int action = object_mapping[tile].action;
5928 int direction = object_mapping[tile].direction;
5929 boolean is_backside = object_mapping[tile].is_backside;
5930 boolean action_removing = (action == ACTION_DIGGING ||
5931 action == ACTION_SNAPPING ||
5932 action == ACTION_COLLECTING);
5935 printf("::: SET: %d, %d: '%s'\n", x, y, EL_NAME(element));
5939 if (action_removing)
5942 printf("::: %d, %d: action_removing [%s]\n", x, y, EL_NAME(element));
5945 GfxFrame[x][y] = 7 - frame_em;
5947 else if (action == ACTION_FALLING ||
5948 action == ACTION_MOVING ||
5949 action == ACTION_PUSHING ||
5950 action == ACTION_EATING ||
5951 action == ACTION_FILLING ||
5952 action == ACTION_EMPTYING)
5955 (action == ACTION_FALLING ||
5956 action == ACTION_FILLING ||
5957 action == ACTION_EMPTYING ? MV_DOWN : direction);
5963 if (move_dir == MV_LEFT)
5964 GfxFrame[x - 1][y] = GfxFrame[x][y];
5965 else if (move_dir == MV_RIGHT)
5966 GfxFrame[x + 1][y] = GfxFrame[x][y];
5967 else if (move_dir == MV_UP)
5968 GfxFrame[x][y - 1] = GfxFrame[x][y];
5969 else if (move_dir == MV_DOWN)
5970 GfxFrame[x][y + 1] = GfxFrame[x][y];
5974 printf("::: %d, %d: %s, %d, %d [%d]\n", x, y, EL_NAME(element), is_backside,
5975 move_dir, GfxFrame[x][y]);
5981 GfxFrame[x][y] = 7 - frame_em;
5985 void getGraphicSourceObjectExt_EM(int tile, int frame_em,
5986 Bitmap **src_bitmap, int *src_x, int *src_y,
5987 Bitmap **crumbled_src_bitmap,
5988 int *crumbled_src_x, int *crumbled_src_y,
5991 int element = object_mapping[tile].element_rnd;
5992 int action = object_mapping[tile].action;
5993 int direction = object_mapping[tile].direction;
5994 boolean is_backside = object_mapping[tile].is_backside;
5995 boolean action_removing = (action == ACTION_DIGGING ||
5996 action == ACTION_SNAPPING ||
5997 action == ACTION_COLLECTING);
5998 int effective_element = (frame_em > 0 ? element :
5999 is_backside ? EL_EMPTY :
6000 action_removing ? EL_EMPTY :
6002 int graphic = (direction == MV_NONE ?
6003 el_act2img(effective_element, action) :
6004 el_act_dir2img(effective_element, action, direction));
6005 int crumbled = (direction == MV_NONE ?
6006 el_act2crm(effective_element, action) :
6007 el_act_dir2crm(effective_element, action, direction));
6008 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
6009 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
6010 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
6011 struct GraphicInfo *g = &graphic_info[graphic];
6012 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
6016 printf("::: GET: %d, %d: '%s'\n", x, y, EL_NAME(element));
6020 if (GfxFrame[x][y] < 8)
6021 printf("::: %d, %d: %d [%s]\n", x, y, GfxFrame[x][y], EL_NAME(element));
6025 if (graphic_info[graphic].anim_global_sync)
6026 sync_frame = FrameCounter;
6027 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
6028 sync_frame = GfxFrame[x][y];
6030 sync_frame = 0; /* steel border */
6032 if (graphic_info[graphic].anim_global_sync)
6033 sync_frame = FrameCounter;
6035 sync_frame = 7 - frame_em;
6038 SetRandomAnimationValue(x, y);
6040 int frame = getAnimationFrame(g->anim_frames,
6043 g->anim_start_frame,
6046 getGraphicSourceExt(graphic, frame, src_bitmap, src_x, src_y, FALSE);
6049 if (x == 1 && y == 1 && frame == 0)
6050 printf("--> %d, %d, %d\n", *crumbled_src_x, *crumbled_src_y, tile);
6054 getGraphicSource(crumbled, frame, crumbled_src_bitmap,
6055 crumbled_src_x, crumbled_src_y);
6059 /* (updating the "crumbled" graphic definitions is probably not really needed,
6060 as animations for crumbled graphics can't be longer than one EMC cycle) */
6062 *crumbled_src_bitmap = NULL;
6063 *crumbled_src_x = 0;
6064 *crumbled_src_y = 0;
6066 if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
6068 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
6069 g_crumbled->anim_delay,
6070 g_crumbled->anim_mode,
6071 g_crumbled->anim_start_frame,
6074 getGraphicSource(crumbled, frame_crumbled, crumbled_src_bitmap,
6075 crumbled_src_x, crumbled_src_y);
6080 void getGraphicSourcePlayerExt_EM(int player_nr, int anim, int frame_em,
6081 Bitmap **src_bitmap, int *src_x, int *src_y)
6083 int element = player_mapping[player_nr][anim].element_rnd;
6084 int action = player_mapping[player_nr][anim].action;
6085 int direction = player_mapping[player_nr][anim].direction;
6086 int graphic = (direction == MV_NONE ?
6087 el_act2img(element, action) :
6088 el_act_dir2img(element, action, direction));
6089 struct GraphicInfo *g = &graphic_info[graphic];
6092 InitPlayerGfxAnimation(&stored_player[player_nr], action, direction);
6094 stored_player[player_nr].StepFrame = 7 - frame_em;
6096 sync_frame = stored_player[player_nr].Frame;
6099 printf("::: %d: %d, %d [%d]\n",
6101 stored_player[player_nr].Frame,
6102 stored_player[player_nr].StepFrame,
6106 int frame = getAnimationFrame(g->anim_frames,
6109 g->anim_start_frame,
6112 getGraphicSourceExt(graphic, frame, src_bitmap, src_x, src_y, FALSE);
6115 void InitGraphicInfo_EM(void)
6118 struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
6119 struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
6124 int num_em_gfx_errors = 0;
6126 if (graphic_info_em_object[0][0].bitmap == NULL)
6128 /* EM graphics not yet initialized in em_open_all() */
6133 printf("::: [4 errors can be ignored (1 x 'bomb', 3 x 'em_dynamite']\n");
6136 /* always start with reliable default values */
6137 for (i = 0; i < TILE_MAX; i++)
6139 object_mapping[i].element_rnd = EL_UNKNOWN;
6140 object_mapping[i].is_backside = FALSE;
6141 object_mapping[i].action = ACTION_DEFAULT;
6142 object_mapping[i].direction = MV_NONE;
6145 /* always start with reliable default values */
6146 for (p = 0; p < MAX_PLAYERS; p++)
6148 for (i = 0; i < SPR_MAX; i++)
6150 player_mapping[p][i].element_rnd = EL_UNKNOWN;
6151 player_mapping[p][i].action = ACTION_DEFAULT;
6152 player_mapping[p][i].direction = MV_NONE;
6156 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
6158 int e = em_object_mapping_list[i].element_em;
6160 object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd;
6161 object_mapping[e].is_backside = em_object_mapping_list[i].is_backside;
6163 if (em_object_mapping_list[i].action != -1)
6164 object_mapping[e].action = em_object_mapping_list[i].action;
6166 if (em_object_mapping_list[i].direction != -1)
6167 object_mapping[e].direction =
6168 MV_DIR_FROM_BIT(em_object_mapping_list[i].direction);
6171 for (i = 0; em_player_mapping_list[i].action_em != -1; i++)
6173 int a = em_player_mapping_list[i].action_em;
6174 int p = em_player_mapping_list[i].player_nr;
6176 player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd;
6178 if (em_player_mapping_list[i].action != -1)
6179 player_mapping[p][a].action = em_player_mapping_list[i].action;
6181 if (em_player_mapping_list[i].direction != -1)
6182 player_mapping[p][a].direction =
6183 MV_DIR_FROM_BIT(em_player_mapping_list[i].direction);
6186 for (i = 0; i < TILE_MAX; i++)
6188 int element = object_mapping[i].element_rnd;
6189 int action = object_mapping[i].action;
6190 int direction = object_mapping[i].direction;
6191 boolean is_backside = object_mapping[i].is_backside;
6192 boolean action_removing = (action == ACTION_DIGGING ||
6193 action == ACTION_SNAPPING ||
6194 action == ACTION_COLLECTING);
6195 boolean action_exploding = ((action == ACTION_EXPLODING ||
6196 action == ACTION_SMASHED_BY_ROCK ||
6197 action == ACTION_SMASHED_BY_SPRING) &&
6198 element != EL_DIAMOND);
6199 boolean action_active = (action == ACTION_ACTIVE);
6200 boolean action_other = (action == ACTION_OTHER);
6202 for (j = 0; j < 8; j++)
6204 int effective_element = (j > 5 && i == Yacid_splash_eB ? EL_EMPTY :
6205 j > 5 && i == Yacid_splash_wB ? EL_EMPTY :
6207 i == Xdrip_stretch ? element :
6208 i == Xdrip_stretchB ? element :
6209 i == Ydrip_s1 ? element :
6210 i == Ydrip_s1B ? element :
6211 i == Xball_1B ? element :
6212 i == Xball_2 ? element :
6213 i == Xball_2B ? element :
6214 i == Yball_eat ? element :
6215 i == Ykey_1_eat ? element :
6216 i == Ykey_2_eat ? element :
6217 i == Ykey_3_eat ? element :
6218 i == Ykey_4_eat ? element :
6219 i == Ykey_5_eat ? element :
6220 i == Ykey_6_eat ? element :
6221 i == Ykey_7_eat ? element :
6222 i == Ykey_8_eat ? element :
6223 i == Ylenses_eat ? element :
6224 i == Ymagnify_eat ? element :
6225 i == Ygrass_eat ? element :
6226 i == Ydirt_eat ? element :
6227 i == Yemerald_stone ? EL_EMERALD :
6228 i == Ydiamond_stone ? EL_ROCK :
6229 i == Xsand_stonein_1 ? element :
6230 i == Xsand_stonein_2 ? element :
6231 i == Xsand_stonein_3 ? element :
6232 i == Xsand_stonein_4 ? element :
6233 is_backside ? EL_EMPTY :
6234 action_removing ? EL_EMPTY :
6236 int effective_action = (j < 7 ? action :
6237 i == Xdrip_stretch ? action :
6238 i == Xdrip_stretchB ? action :
6239 i == Ydrip_s1 ? action :
6240 i == Ydrip_s1B ? action :
6241 i == Xball_1B ? action :
6242 i == Xball_2 ? action :
6243 i == Xball_2B ? action :
6244 i == Yball_eat ? action :
6245 i == Ykey_1_eat ? action :
6246 i == Ykey_2_eat ? action :
6247 i == Ykey_3_eat ? action :
6248 i == Ykey_4_eat ? action :
6249 i == Ykey_5_eat ? action :
6250 i == Ykey_6_eat ? action :
6251 i == Ykey_7_eat ? action :
6252 i == Ykey_8_eat ? action :
6253 i == Ylenses_eat ? action :
6254 i == Ymagnify_eat ? action :
6255 i == Ygrass_eat ? action :
6256 i == Ydirt_eat ? action :
6257 i == Xsand_stonein_1 ? action :
6258 i == Xsand_stonein_2 ? action :
6259 i == Xsand_stonein_3 ? action :
6260 i == Xsand_stonein_4 ? action :
6261 i == Xsand_stoneout_1 ? action :
6262 i == Xsand_stoneout_2 ? action :
6263 i == Xboom_android ? ACTION_EXPLODING :
6264 action_exploding ? ACTION_EXPLODING :
6265 action_active ? action :
6266 action_other ? action :
6268 int graphic = (el_act_dir2img(effective_element, effective_action,
6270 int crumbled = (el_act_dir2crm(effective_element, effective_action,
6272 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
6273 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
6274 boolean has_action_graphics = (graphic != base_graphic);
6275 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
6276 struct GraphicInfo *g = &graphic_info[graphic];
6277 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
6278 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
6281 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
6282 boolean special_animation = (action != ACTION_DEFAULT &&
6283 g->anim_frames == 3 &&
6284 g->anim_delay == 2 &&
6285 g->anim_mode & ANIM_LINEAR);
6286 int sync_frame = (i == Xdrip_stretch ? 7 :
6287 i == Xdrip_stretchB ? 7 :
6288 i == Ydrip_s2 ? j + 8 :
6289 i == Ydrip_s2B ? j + 8 :
6298 i == Xfake_acid_1 ? 0 :
6299 i == Xfake_acid_2 ? 10 :
6300 i == Xfake_acid_3 ? 20 :
6301 i == Xfake_acid_4 ? 30 :
6302 i == Xfake_acid_5 ? 40 :
6303 i == Xfake_acid_6 ? 50 :
6304 i == Xfake_acid_7 ? 60 :
6305 i == Xfake_acid_8 ? 70 :
6307 i == Xball_2B ? j + 8 :
6308 i == Yball_eat ? j + 1 :
6309 i == Ykey_1_eat ? j + 1 :
6310 i == Ykey_2_eat ? j + 1 :
6311 i == Ykey_3_eat ? j + 1 :
6312 i == Ykey_4_eat ? j + 1 :
6313 i == Ykey_5_eat ? j + 1 :
6314 i == Ykey_6_eat ? j + 1 :
6315 i == Ykey_7_eat ? j + 1 :
6316 i == Ykey_8_eat ? j + 1 :
6317 i == Ylenses_eat ? j + 1 :
6318 i == Ymagnify_eat ? j + 1 :
6319 i == Ygrass_eat ? j + 1 :
6320 i == Ydirt_eat ? j + 1 :
6321 i == Xamoeba_1 ? 0 :
6322 i == Xamoeba_2 ? 1 :
6323 i == Xamoeba_3 ? 2 :
6324 i == Xamoeba_4 ? 3 :
6325 i == Xamoeba_5 ? 0 :
6326 i == Xamoeba_6 ? 1 :
6327 i == Xamoeba_7 ? 2 :
6328 i == Xamoeba_8 ? 3 :
6329 i == Xexit_2 ? j + 8 :
6330 i == Xexit_3 ? j + 16 :
6331 i == Xdynamite_1 ? 0 :
6332 i == Xdynamite_2 ? 8 :
6333 i == Xdynamite_3 ? 16 :
6334 i == Xdynamite_4 ? 24 :
6335 i == Xsand_stonein_1 ? j + 1 :
6336 i == Xsand_stonein_2 ? j + 9 :
6337 i == Xsand_stonein_3 ? j + 17 :
6338 i == Xsand_stonein_4 ? j + 25 :
6339 i == Xsand_stoneout_1 && j == 0 ? 0 :
6340 i == Xsand_stoneout_1 && j == 1 ? 0 :
6341 i == Xsand_stoneout_1 && j == 2 ? 1 :
6342 i == Xsand_stoneout_1 && j == 3 ? 2 :
6343 i == Xsand_stoneout_1 && j == 4 ? 2 :
6344 i == Xsand_stoneout_1 && j == 5 ? 3 :
6345 i == Xsand_stoneout_1 && j == 6 ? 4 :
6346 i == Xsand_stoneout_1 && j == 7 ? 4 :
6347 i == Xsand_stoneout_2 && j == 0 ? 5 :
6348 i == Xsand_stoneout_2 && j == 1 ? 6 :
6349 i == Xsand_stoneout_2 && j == 2 ? 7 :
6350 i == Xsand_stoneout_2 && j == 3 ? 8 :
6351 i == Xsand_stoneout_2 && j == 4 ? 9 :
6352 i == Xsand_stoneout_2 && j == 5 ? 11 :
6353 i == Xsand_stoneout_2 && j == 6 ? 13 :
6354 i == Xsand_stoneout_2 && j == 7 ? 15 :
6355 i == Xboom_bug && j == 1 ? 2 :
6356 i == Xboom_bug && j == 2 ? 2 :
6357 i == Xboom_bug && j == 3 ? 4 :
6358 i == Xboom_bug && j == 4 ? 4 :
6359 i == Xboom_bug && j == 5 ? 2 :
6360 i == Xboom_bug && j == 6 ? 2 :
6361 i == Xboom_bug && j == 7 ? 0 :
6362 i == Xboom_bomb && j == 1 ? 2 :
6363 i == Xboom_bomb && j == 2 ? 2 :
6364 i == Xboom_bomb && j == 3 ? 4 :
6365 i == Xboom_bomb && j == 4 ? 4 :
6366 i == Xboom_bomb && j == 5 ? 2 :
6367 i == Xboom_bomb && j == 6 ? 2 :
6368 i == Xboom_bomb && j == 7 ? 0 :
6369 i == Xboom_android && j == 7 ? 6 :
6370 i == Xboom_1 && j == 1 ? 2 :
6371 i == Xboom_1 && j == 2 ? 2 :
6372 i == Xboom_1 && j == 3 ? 4 :
6373 i == Xboom_1 && j == 4 ? 4 :
6374 i == Xboom_1 && j == 5 ? 6 :
6375 i == Xboom_1 && j == 6 ? 6 :
6376 i == Xboom_1 && j == 7 ? 8 :
6377 i == Xboom_2 && j == 0 ? 8 :
6378 i == Xboom_2 && j == 1 ? 8 :
6379 i == Xboom_2 && j == 2 ? 10 :
6380 i == Xboom_2 && j == 3 ? 10 :
6381 i == Xboom_2 && j == 4 ? 10 :
6382 i == Xboom_2 && j == 5 ? 12 :
6383 i == Xboom_2 && j == 6 ? 12 :
6384 i == Xboom_2 && j == 7 ? 12 :
6385 special_animation && j == 4 ? 3 :
6386 effective_action != action ? 0 :
6390 Bitmap *debug_bitmap = g_em->bitmap;
6391 int debug_src_x = g_em->src_x;
6392 int debug_src_y = g_em->src_y;
6395 int frame = getAnimationFrame(g->anim_frames,
6398 g->anim_start_frame,
6401 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y,
6402 g->double_movement && is_backside);
6404 g_em->bitmap = src_bitmap;
6405 g_em->src_x = src_x;
6406 g_em->src_y = src_y;
6407 g_em->src_offset_x = 0;
6408 g_em->src_offset_y = 0;
6409 g_em->dst_offset_x = 0;
6410 g_em->dst_offset_y = 0;
6411 g_em->width = TILEX;
6412 g_em->height = TILEY;
6414 g_em->crumbled_bitmap = NULL;
6415 g_em->crumbled_src_x = 0;
6416 g_em->crumbled_src_y = 0;
6417 g_em->crumbled_border_size = 0;
6419 g_em->has_crumbled_graphics = FALSE;
6420 g_em->preserve_background = FALSE;
6423 if (has_crumbled_graphics && crumbled == IMG_EMPTY_SPACE)
6424 printf("::: empty crumbled: %d [%s], %d, %d\n",
6425 effective_element, element_info[effective_element].token_name,
6426 effective_action, direction);
6429 /* if element can be crumbled, but certain action graphics are just empty
6430 space (like instantly snapping sand to empty space in 1 frame), do not
6431 treat these empty space graphics as crumbled graphics in EMC engine */
6432 if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
6434 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
6435 g_crumbled->anim_delay,
6436 g_crumbled->anim_mode,
6437 g_crumbled->anim_start_frame,
6440 getGraphicSource(crumbled, frame_crumbled, &src_bitmap, &src_x, &src_y);
6442 g_em->has_crumbled_graphics = TRUE;
6443 g_em->crumbled_bitmap = src_bitmap;
6444 g_em->crumbled_src_x = src_x;
6445 g_em->crumbled_src_y = src_y;
6446 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
6450 if (g_em == &graphic_info_em_object[207][0])
6451 printf("... %d, %d [%d, %d, %d, %d] [%d, %d, %d, %d, %d, %d => %d]\n",
6452 graphic_info_em_object[207][0].crumbled_src_x,
6453 graphic_info_em_object[207][0].crumbled_src_y,
6455 crumbled, frame, src_x, src_y,
6460 g->anim_start_frame,
6462 gfx.anim_random_frame,
6470 if (element == EL_ROCK &&
6471 effective_action == ACTION_FILLING)
6472 printf("::: has_action_graphics == %d\n", has_action_graphics);
6475 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
6476 effective_action == ACTION_MOVING ||
6477 effective_action == ACTION_PUSHING ||
6478 effective_action == ACTION_EATING)) ||
6479 (!has_action_graphics && (effective_action == ACTION_FILLING ||
6480 effective_action == ACTION_EMPTYING)))
6483 (effective_action == ACTION_FALLING ||
6484 effective_action == ACTION_FILLING ||
6485 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
6486 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
6487 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
6488 int num_steps = (i == Ydrip_s1 ? 16 :
6489 i == Ydrip_s1B ? 16 :
6490 i == Ydrip_s2 ? 16 :
6491 i == Ydrip_s2B ? 16 :
6492 i == Xsand_stonein_1 ? 32 :
6493 i == Xsand_stonein_2 ? 32 :
6494 i == Xsand_stonein_3 ? 32 :
6495 i == Xsand_stonein_4 ? 32 :
6496 i == Xsand_stoneout_1 ? 16 :
6497 i == Xsand_stoneout_2 ? 16 : 8);
6498 int cx = ABS(dx) * (TILEX / num_steps);
6499 int cy = ABS(dy) * (TILEY / num_steps);
6500 int step_frame = (i == Ydrip_s2 ? j + 8 :
6501 i == Ydrip_s2B ? j + 8 :
6502 i == Xsand_stonein_2 ? j + 8 :
6503 i == Xsand_stonein_3 ? j + 16 :
6504 i == Xsand_stonein_4 ? j + 24 :
6505 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
6506 int step = (is_backside ? step_frame : num_steps - step_frame);
6508 if (is_backside) /* tile where movement starts */
6510 if (dx < 0 || dy < 0)
6512 g_em->src_offset_x = cx * step;
6513 g_em->src_offset_y = cy * step;
6517 g_em->dst_offset_x = cx * step;
6518 g_em->dst_offset_y = cy * step;
6521 else /* tile where movement ends */
6523 if (dx < 0 || dy < 0)
6525 g_em->dst_offset_x = cx * step;
6526 g_em->dst_offset_y = cy * step;
6530 g_em->src_offset_x = cx * step;
6531 g_em->src_offset_y = cy * step;
6535 g_em->width = TILEX - cx * step;
6536 g_em->height = TILEY - cy * step;
6539 /* create unique graphic identifier to decide if tile must be redrawn */
6540 /* bit 31 - 16 (16 bit): EM style graphic
6541 bit 15 - 12 ( 4 bit): EM style frame
6542 bit 11 - 6 ( 6 bit): graphic width
6543 bit 5 - 0 ( 6 bit): graphic height */
6544 g_em->unique_identifier =
6545 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
6549 /* skip check for EMC elements not contained in original EMC artwork */
6550 if (element == EL_EMC_FAKE_ACID)
6553 if (g_em->bitmap != debug_bitmap ||
6554 g_em->src_x != debug_src_x ||
6555 g_em->src_y != debug_src_y ||
6556 g_em->src_offset_x != 0 ||
6557 g_em->src_offset_y != 0 ||
6558 g_em->dst_offset_x != 0 ||
6559 g_em->dst_offset_y != 0 ||
6560 g_em->width != TILEX ||
6561 g_em->height != TILEY)
6563 static int last_i = -1;
6571 printf("::: EMC GFX ERROR for element %d -> %d ('%s', '%s', %d)",
6572 i, element, element_info[element].token_name,
6573 element_action_info[effective_action].suffix, direction);
6575 if (element != effective_element)
6576 printf(" [%d ('%s')]",
6578 element_info[effective_element].token_name);
6582 if (g_em->bitmap != debug_bitmap)
6583 printf(" %d (%d): different bitmap! (0x%08x != 0x%08x)\n",
6584 j, is_backside, (int)(g_em->bitmap), (int)(debug_bitmap));
6586 if (g_em->src_x != debug_src_x ||
6587 g_em->src_y != debug_src_y)
6588 printf(" frame %d (%c): %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
6589 j, (is_backside ? 'B' : 'F'),
6590 g_em->src_x, g_em->src_y,
6591 g_em->src_x / 32, g_em->src_y / 32,
6592 debug_src_x, debug_src_y,
6593 debug_src_x / 32, debug_src_y / 32);
6595 if (g_em->src_offset_x != 0 ||
6596 g_em->src_offset_y != 0 ||
6597 g_em->dst_offset_x != 0 ||
6598 g_em->dst_offset_y != 0)
6599 printf(" %d (%d): offsets %d,%d and %d,%d should be all 0\n",
6601 g_em->src_offset_x, g_em->src_offset_y,
6602 g_em->dst_offset_x, g_em->dst_offset_y);
6604 if (g_em->width != TILEX ||
6605 g_em->height != TILEY)
6606 printf(" %d (%d): size %d,%d should be %d,%d\n",
6608 g_em->width, g_em->height, TILEX, TILEY);
6610 num_em_gfx_errors++;
6617 for (i = 0; i < TILE_MAX; i++)
6619 for (j = 0; j < 8; j++)
6621 int element = object_mapping[i].element_rnd;
6622 int action = object_mapping[i].action;
6623 int direction = object_mapping[i].direction;
6624 boolean is_backside = object_mapping[i].is_backside;
6625 int graphic_action = el_act_dir2img(element, action, direction);
6626 int graphic_default = el_act_dir2img(element, ACTION_DEFAULT, direction);
6628 if ((action == ACTION_SMASHED_BY_ROCK ||
6629 action == ACTION_SMASHED_BY_SPRING ||
6630 action == ACTION_EATING) &&
6631 graphic_action == graphic_default)
6633 int e = (action == ACTION_SMASHED_BY_ROCK ? Ystone_s :
6634 action == ACTION_SMASHED_BY_SPRING ? Yspring_s :
6635 direction == MV_LEFT ? (is_backside? Yspring_wB: Yspring_w) :
6636 direction == MV_RIGHT ? (is_backside? Yspring_eB: Yspring_e) :
6639 /* no separate animation for "smashed by rock" -- use rock instead */
6640 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
6641 struct GraphicInfo_EM *g_xx = &graphic_info_em_object[e][7 - j];
6643 g_em->bitmap = g_xx->bitmap;
6644 g_em->src_x = g_xx->src_x;
6645 g_em->src_y = g_xx->src_y;
6646 g_em->src_offset_x = g_xx->src_offset_x;
6647 g_em->src_offset_y = g_xx->src_offset_y;
6648 g_em->dst_offset_x = g_xx->dst_offset_x;
6649 g_em->dst_offset_y = g_xx->dst_offset_y;
6650 g_em->width = g_xx->width;
6651 g_em->height = g_xx->height;
6652 g_em->unique_identifier = g_xx->unique_identifier;
6655 g_em->preserve_background = TRUE;
6660 for (p = 0; p < MAX_PLAYERS; p++)
6662 for (i = 0; i < SPR_MAX; i++)
6664 int element = player_mapping[p][i].element_rnd;
6665 int action = player_mapping[p][i].action;
6666 int direction = player_mapping[p][i].direction;
6668 for (j = 0; j < 8; j++)
6670 int effective_element = element;
6671 int effective_action = action;
6672 int graphic = (direction == MV_NONE ?
6673 el_act2img(effective_element, effective_action) :
6674 el_act_dir2img(effective_element, effective_action,
6676 struct GraphicInfo *g = &graphic_info[graphic];
6677 struct GraphicInfo_EM *g_em = &graphic_info_em_player[p][i][7 - j];
6683 Bitmap *debug_bitmap = g_em->bitmap;
6684 int debug_src_x = g_em->src_x;
6685 int debug_src_y = g_em->src_y;
6688 int frame = getAnimationFrame(g->anim_frames,
6691 g->anim_start_frame,
6694 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
6696 g_em->bitmap = src_bitmap;
6697 g_em->src_x = src_x;
6698 g_em->src_y = src_y;
6699 g_em->src_offset_x = 0;
6700 g_em->src_offset_y = 0;
6701 g_em->dst_offset_x = 0;
6702 g_em->dst_offset_y = 0;
6703 g_em->width = TILEX;
6704 g_em->height = TILEY;
6708 /* skip check for EMC elements not contained in original EMC artwork */
6709 if (element == EL_PLAYER_3 ||
6710 element == EL_PLAYER_4)
6713 if (g_em->bitmap != debug_bitmap ||
6714 g_em->src_x != debug_src_x ||
6715 g_em->src_y != debug_src_y)
6717 static int last_i = -1;
6725 printf("::: EMC GFX ERROR for p/a %d/%d -> %d ('%s', '%s', %d)",
6726 p, i, element, element_info[element].token_name,
6727 element_action_info[effective_action].suffix, direction);
6729 if (element != effective_element)
6730 printf(" [%d ('%s')]",
6732 element_info[effective_element].token_name);
6736 if (g_em->bitmap != debug_bitmap)
6737 printf(" %d: different bitmap! (0x%08x != 0x%08x)\n",
6738 j, (int)(g_em->bitmap), (int)(debug_bitmap));
6740 if (g_em->src_x != debug_src_x ||
6741 g_em->src_y != debug_src_y)
6742 printf(" frame %d: %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
6744 g_em->src_x, g_em->src_y,
6745 g_em->src_x / 32, g_em->src_y / 32,
6746 debug_src_x, debug_src_y,
6747 debug_src_x / 32, debug_src_y / 32);
6749 num_em_gfx_errors++;
6759 printf("::: [%d errors found]\n", num_em_gfx_errors);
6765 void PlayMenuSoundExt(int sound)
6767 if (sound == SND_UNDEFINED)
6770 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
6771 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
6774 if (IS_LOOP_SOUND(sound))
6775 PlaySoundLoop(sound);
6780 void PlayMenuSound()
6782 PlayMenuSoundExt(menu.sound[game_status]);
6785 void PlayMenuSoundStereo(int sound, int stereo_position)
6787 if (sound == SND_UNDEFINED)
6790 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
6791 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
6794 if (IS_LOOP_SOUND(sound))
6795 PlaySoundExt(sound, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_LOOP);
6797 PlaySoundStereo(sound, stereo_position);
6800 void PlayMenuSoundIfLoopExt(int sound)
6802 if (sound == SND_UNDEFINED)
6805 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
6806 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
6809 if (IS_LOOP_SOUND(sound))
6810 PlaySoundLoop(sound);
6813 void PlayMenuSoundIfLoop()
6815 PlayMenuSoundIfLoopExt(menu.sound[game_status]);
6818 void PlayMenuMusicExt(int music)
6820 if (music == MUS_UNDEFINED)
6823 if (!setup.sound_music)
6829 void PlayMenuMusic()
6831 PlayMenuMusicExt(menu.music[game_status]);
6834 void PlaySoundActivating()
6837 PlaySound(SND_MENU_ITEM_ACTIVATING);
6841 void PlaySoundSelecting()
6844 PlaySound(SND_MENU_ITEM_SELECTING);
6848 void ToggleFullscreenIfNeeded()
6850 boolean change_fullscreen = (setup.fullscreen !=
6851 video.fullscreen_enabled);
6852 boolean change_fullscreen_mode = (video.fullscreen_enabled &&
6853 !strEqual(setup.fullscreen_mode,
6854 video.fullscreen_mode_current));
6856 if (!video.fullscreen_available)
6860 if (change_fullscreen || change_fullscreen_mode)
6862 if (setup.fullscreen != video.fullscreen_enabled ||
6863 setup.fullscreen_mode != video.fullscreen_mode_current)
6866 Bitmap *tmp_backbuffer = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
6868 /* save backbuffer content which gets lost when toggling fullscreen mode */
6869 BlitBitmap(backbuffer, tmp_backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
6872 if (change_fullscreen_mode)
6874 if (setup.fullscreen && video.fullscreen_enabled)
6877 /* keep fullscreen, but change fullscreen mode (screen resolution) */
6879 /* (this is now set in sdl.c) */
6881 video.fullscreen_mode_current = setup.fullscreen_mode;
6883 video.fullscreen_enabled = FALSE; /* force new fullscreen mode */
6886 /* toggle fullscreen */
6887 ChangeVideoModeIfNeeded(setup.fullscreen);
6889 setup.fullscreen = video.fullscreen_enabled;
6891 /* restore backbuffer content from temporary backbuffer backup bitmap */
6892 BlitBitmap(tmp_backbuffer, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
6894 FreeBitmap(tmp_backbuffer);
6897 /* update visible window/screen */
6898 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
6900 redraw_mask = REDRAW_ALL;