1 // ============================================================================
2 // Rocks'n'Diamonds - McDuffin Strikes Back!
3 // ----------------------------------------------------------------------------
4 // (c) 1995-2014 by Artsoft Entertainment
7 // http://www.artsoft.org/
8 // ----------------------------------------------------------------------------
10 // ============================================================================
14 #include "libgame/libgame.h"
26 /* select level set with EMC X11 graphics before activating EM GFX debugging */
27 #define DEBUG_EM_GFX FALSE
28 #define DEBUG_FRAME_TIME FALSE
30 /* tool button identifiers */
31 #define TOOL_CTRL_ID_YES 0
32 #define TOOL_CTRL_ID_NO 1
33 #define TOOL_CTRL_ID_CONFIRM 2
34 #define TOOL_CTRL_ID_PLAYER_1 3
35 #define TOOL_CTRL_ID_PLAYER_2 4
36 #define TOOL_CTRL_ID_PLAYER_3 5
37 #define TOOL_CTRL_ID_PLAYER_4 6
39 #define NUM_TOOL_BUTTONS 7
41 /* constants for number of doors and door parts */
43 #define NUM_PANELS NUM_DOORS
44 // #define NUM_PANELS 0
45 #define MAX_PARTS_PER_DOOR 8
46 #define MAX_DOOR_PARTS (NUM_DOORS * MAX_PARTS_PER_DOOR + NUM_PANELS)
47 #define DOOR_PART_IS_PANEL(i) ((i) >= NUM_DOORS * MAX_PARTS_PER_DOOR)
50 struct DoorPartOrderInfo
56 static struct DoorPartOrderInfo door_part_order[MAX_DOOR_PARTS];
58 struct DoorPartControlInfo
62 struct DoorPartPosInfo *pos;
65 static struct DoorPartControlInfo door_part_controls[] =
69 IMG_DOOR_1_GFX_PART_1,
74 IMG_DOOR_1_GFX_PART_2,
79 IMG_DOOR_1_GFX_PART_3,
84 IMG_DOOR_1_GFX_PART_4,
89 IMG_DOOR_1_GFX_PART_5,
94 IMG_DOOR_1_GFX_PART_6,
99 IMG_DOOR_1_GFX_PART_7,
104 IMG_DOOR_1_GFX_PART_8,
110 IMG_DOOR_2_GFX_PART_1,
115 IMG_DOOR_2_GFX_PART_2,
120 IMG_DOOR_2_GFX_PART_3,
125 IMG_DOOR_2_GFX_PART_4,
130 IMG_DOOR_2_GFX_PART_5,
135 IMG_DOOR_2_GFX_PART_6,
140 IMG_DOOR_2_GFX_PART_7,
145 IMG_DOOR_2_GFX_PART_8,
151 IMG_BACKGROUND_PANEL,
168 /* forward declaration for internal use */
169 static void UnmapToolButtons();
170 static void HandleToolButtons(struct GadgetInfo *);
171 static int el_act_dir2crm(int, int, int);
172 static int el_act2crm(int, int);
174 static struct GadgetInfo *tool_gadget[NUM_TOOL_BUTTONS];
175 static int request_gadget_id = -1;
177 static unsigned int sync_frame_delay = 0;
178 static unsigned int sync_frame_delay_value = GAME_FRAME_DELAY;
180 static char *print_if_not_empty(int element)
182 static char *s = NULL;
183 char *token_name = element_info[element].token_name;
188 s = checked_malloc(strlen(token_name) + 10 + 1);
190 if (element != EL_EMPTY)
191 sprintf(s, "%d\t['%s']", element, token_name);
193 sprintf(s, "%d", element);
198 void DumpTile(int x, int y)
203 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
209 printf_line("-", 79);
210 printf("Field Info: SCREEN(%d, %d), LEVEL(%d, %d)\n", sx, sy, x, y);
211 printf_line("-", 79);
213 if (!IN_LEV_FIELD(x, y))
215 printf("(not in level field)\n");
221 printf(" Feld: %d\t['%s']\n", Feld[x][y],
222 element_info[Feld[x][y]].token_name);
223 printf(" Back: %s\n", print_if_not_empty(Back[x][y]));
224 printf(" Store: %s\n", print_if_not_empty(Store[x][y]));
225 printf(" Store2: %s\n", print_if_not_empty(Store2[x][y]));
226 printf(" StorePlayer: %s\n", print_if_not_empty(StorePlayer[x][y]));
227 printf(" MovPos: %d\n", MovPos[x][y]);
228 printf(" MovDir: %d\n", MovDir[x][y]);
229 printf(" MovDelay: %d\n", MovDelay[x][y]);
230 printf(" ChangeDelay: %d\n", ChangeDelay[x][y]);
231 printf(" CustomValue: %d\n", CustomValue[x][y]);
232 printf(" GfxElement: %d\n", GfxElement[x][y]);
233 printf(" GfxAction: %d\n", GfxAction[x][y]);
234 printf(" GfxFrame: %d [%d]\n", GfxFrame[x][y], FrameCounter);
238 void SetDrawtoField(int mode)
240 if (mode == DRAW_FIELDBUFFER)
246 BX2 = SCR_FIELDX + 1;
247 BY2 = SCR_FIELDY + 1;
249 drawto_field = fieldbuffer;
251 else /* DRAW_BACKBUFFER */
257 BX2 = SCR_FIELDX - 1;
258 BY2 = SCR_FIELDY - 1;
260 drawto_field = backbuffer;
264 static void RedrawPlayfield_RND()
266 if (game.envelope_active)
269 DrawLevel(REDRAW_ALL);
273 void RedrawPlayfield()
275 if (game_status != GAME_MODE_PLAYING)
278 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
279 RedrawPlayfield_EM(TRUE);
280 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
281 RedrawPlayfield_SP(TRUE);
282 else if (level.game_engine_type == GAME_ENGINE_TYPE_RND)
283 RedrawPlayfield_RND();
285 BlitScreenToBitmap(backbuffer);
287 BlitBitmap(drawto, window, gfx.sx, gfx.sy, gfx.sxsize, gfx.sysize,
291 static void DrawMaskedBorderExt_Rect(int x, int y, int width, int height,
294 Bitmap *src_bitmap = getGlobalBorderBitmapFromStatus(global.border_status);
295 Bitmap *dst_bitmap = gfx.masked_border_bitmap_ptr;
297 if (x == -1 && y == -1)
300 if (draw_target == DRAW_BORDER_TO_SCREEN)
301 BlitToScreenMasked(src_bitmap, x, y, width, height, x, y);
303 BlitBitmapMasked(src_bitmap, dst_bitmap, x, y, width, height, x, y);
306 static void DrawMaskedBorderExt_FIELD(int draw_target)
308 if (global.border_status >= GAME_MODE_MAIN &&
309 global.border_status <= GAME_MODE_PLAYING &&
310 border.draw_masked[global.border_status])
311 DrawMaskedBorderExt_Rect(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
315 static void DrawMaskedBorderExt_DOOR_1(int draw_target)
317 // when drawing to backbuffer, never draw border over open doors
318 if (draw_target == DRAW_BORDER_TO_BACKBUFFER &&
319 (GetDoorState() & DOOR_OPEN_1))
322 if (border.draw_masked[GFX_SPECIAL_ARG_DOOR] &&
323 (global.border_status != GAME_MODE_EDITOR ||
324 border.draw_masked[GFX_SPECIAL_ARG_EDITOR]))
325 DrawMaskedBorderExt_Rect(DX, DY, DXSIZE, DYSIZE, draw_target);
328 static void DrawMaskedBorderExt_DOOR_2(int draw_target)
330 // when drawing to backbuffer, never draw border over open doors
331 if (draw_target == DRAW_BORDER_TO_BACKBUFFER &&
332 (GetDoorState() & DOOR_OPEN_2))
335 if (border.draw_masked[GFX_SPECIAL_ARG_DOOR] &&
336 global.border_status != GAME_MODE_EDITOR)
337 DrawMaskedBorderExt_Rect(VX, VY, VXSIZE, VYSIZE, draw_target);
340 static void DrawMaskedBorderExt_DOOR_3(int draw_target)
342 /* currently not available */
345 static void DrawMaskedBorderExt_ALL(int draw_target)
347 DrawMaskedBorderExt_FIELD(draw_target);
348 DrawMaskedBorderExt_DOOR_1(draw_target);
349 DrawMaskedBorderExt_DOOR_2(draw_target);
350 DrawMaskedBorderExt_DOOR_3(draw_target);
353 static void DrawMaskedBorderExt(int redraw_mask, int draw_target)
355 /* never draw masked screen borders on borderless screens */
356 if (global.border_status == GAME_MODE_LOADING ||
357 global.border_status == GAME_MODE_TITLE)
360 if (redraw_mask & REDRAW_ALL)
361 DrawMaskedBorderExt_ALL(draw_target);
364 if (redraw_mask & REDRAW_FIELD)
365 DrawMaskedBorderExt_FIELD(draw_target);
366 if (redraw_mask & REDRAW_DOOR_1)
367 DrawMaskedBorderExt_DOOR_1(draw_target);
368 if (redraw_mask & REDRAW_DOOR_2)
369 DrawMaskedBorderExt_DOOR_2(draw_target);
370 if (redraw_mask & REDRAW_DOOR_3)
371 DrawMaskedBorderExt_DOOR_3(draw_target);
375 void DrawMaskedBorder_FIELD()
377 DrawMaskedBorderExt_FIELD(DRAW_BORDER_TO_BACKBUFFER);
380 void DrawMaskedBorder(int redraw_mask)
382 DrawMaskedBorderExt(redraw_mask, DRAW_BORDER_TO_BACKBUFFER);
385 void DrawMaskedBorderToTarget(int draw_target)
387 if (draw_target == DRAW_BORDER_TO_BACKBUFFER ||
388 draw_target == DRAW_BORDER_TO_SCREEN)
390 DrawMaskedBorderExt(REDRAW_ALL, draw_target);
394 int last_border_status = global.border_status;
396 if (draw_target == DRAW_BORDER_TO_FADE_SOURCE)
398 global.border_status = gfx.fade_border_source_status;
399 gfx.masked_border_bitmap_ptr = gfx.fade_bitmap_source;
401 else if (draw_target == DRAW_BORDER_TO_FADE_TARGET)
403 global.border_status = gfx.fade_border_target_status;
404 gfx.masked_border_bitmap_ptr = gfx.fade_bitmap_target;
407 DrawMaskedBorderExt(REDRAW_ALL, draw_target);
409 global.border_status = last_border_status;
410 gfx.masked_border_bitmap_ptr = backbuffer;
414 void BlitScreenToBitmap_RND(Bitmap *target_bitmap)
416 int fx = FX, fy = FY;
417 int full_lev_fieldx = lev_fieldx + (BorderElement != EL_EMPTY ? 2 : 0);
418 int full_lev_fieldy = lev_fieldy + (BorderElement != EL_EMPTY ? 2 : 0);
420 int dx = (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
421 int dy = (ScreenMovDir & (MV_UP | MV_DOWN) ? ScreenGfxPos : 0);
422 int dx_var = dx * TILESIZE_VAR / TILESIZE;
423 int dy_var = dy * TILESIZE_VAR / TILESIZE;
426 ffx = (scroll_x - SBX_Left) * TILEX_VAR + dx_var;
427 ffy = (scroll_y - SBY_Upper) * TILEY_VAR + dy_var;
429 if (EVEN(SCR_FIELDX))
431 if (ffx < SBX_Right * TILEX_VAR + TILEX_VAR / 2 + TILEX_VAR)
432 fx += dx_var - MIN(ffx, TILEX_VAR / 2) + TILEX_VAR;
434 fx += (dx_var > 0 ? TILEX_VAR : 0);
441 if (EVEN(SCR_FIELDY))
443 if (ffy < SBY_Lower * TILEY_VAR + TILEY_VAR / 2 + TILEY_VAR)
444 fy += dy_var - MIN(ffy, TILEY_VAR / 2) + TILEY_VAR;
446 fy += (dy_var > 0 ? TILEY_VAR : 0);
453 if (full_lev_fieldx <= SCR_FIELDX)
455 if (EVEN(SCR_FIELDX))
456 fx = 2 * TILEX_VAR - (ODD(lev_fieldx) ? TILEX_VAR / 2 : 0);
458 fx = 2 * TILEX_VAR - (EVEN(lev_fieldx) ? TILEX_VAR / 2 : 0);
461 if (full_lev_fieldy <= SCR_FIELDY)
463 if (EVEN(SCR_FIELDY))
464 fy = 2 * TILEY_VAR - (ODD(lev_fieldy) ? TILEY_VAR / 2 : 0);
466 fy = 2 * TILEY_VAR - (EVEN(lev_fieldy) ? TILEY_VAR / 2 : 0);
469 BlitBitmap(drawto_field, target_bitmap, fx, fy, SXSIZE, SYSIZE, SX, SY);
472 void BlitScreenToBitmap(Bitmap *target_bitmap)
474 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
475 BlitScreenToBitmap_EM(target_bitmap);
476 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
477 BlitScreenToBitmap_SP(target_bitmap);
478 else if (level.game_engine_type == GAME_ENGINE_TYPE_RND)
479 BlitScreenToBitmap_RND(target_bitmap);
481 redraw_mask |= REDRAW_FIELD;
484 void DrawFramesPerSecond()
487 int font_nr = FONT_TEXT_2;
488 int font_width = getFontWidth(font_nr);
490 sprintf(text, "%04.1f fps", global.frames_per_second);
492 DrawTextExt(backbuffer, WIN_XSIZE - font_width * strlen(text), 0, text,
493 font_nr, BLIT_OPAQUE);
497 static void PrintFrameTimeDebugging()
499 static unsigned int last_counter = 0;
500 unsigned int counter = Counter();
501 int diff_1 = counter - last_counter;
502 int diff_2 = diff_1 - GAME_FRAME_DELAY;
504 int diff_2_cut = MIN(ABS(diff_2), diff_2_max);
505 char diff_bar[2 * diff_2_max + 5];
509 diff_bar[pos++] = (diff_2 < -diff_2_max ? '<' : ' ');
511 for (i = 0; i < diff_2_max; i++)
512 diff_bar[pos++] = (diff_2 >= 0 ? ' ' :
513 i >= diff_2_max - diff_2_cut ? '-' : ' ');
515 diff_bar[pos++] = '|';
517 for (i = 0; i < diff_2_max; i++)
518 diff_bar[pos++] = (diff_2 <= 0 ? ' ' : i < diff_2_cut ? '+' : ' ');
520 diff_bar[pos++] = (diff_2 > diff_2_max ? '>' : ' ');
522 diff_bar[pos++] = '\0';
524 Error(ERR_INFO, "%06d [%02d] [%c%02d] %s",
527 (diff_2 < 0 ? '-' : diff_2 > 0 ? '+' : ' '), ABS(diff_2),
530 last_counter = counter;
536 static int last_redraw_mask = REDRAW_NONE;
538 // force screen redraw in every frame to continue drawing global animations
539 // (but always use the last redraw mask to prevent unwanted side effects)
540 if (redraw_mask == REDRAW_NONE)
541 redraw_mask = last_redraw_mask;
543 last_redraw_mask = redraw_mask;
546 // masked border now drawn immediately when blitting backbuffer to window
548 // draw masked border to all viewports, if defined
549 DrawMaskedBorder(redraw_mask);
552 // draw frames per second (only if debug mode is enabled)
553 if (redraw_mask & REDRAW_FPS)
554 DrawFramesPerSecond();
556 // redraw complete window if both playfield and (some) doors need redraw
557 if (redraw_mask & REDRAW_FIELD && redraw_mask & REDRAW_DOORS)
558 redraw_mask = REDRAW_ALL;
560 /* although redrawing the whole window would be fine for normal gameplay,
561 being able to only redraw the playfield is required for deactivating
562 certain drawing areas (mainly playfield) to work, which is needed for
563 warp-forward to be fast enough (by skipping redraw of most frames) */
565 if (redraw_mask & REDRAW_ALL)
567 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
569 else if (redraw_mask & REDRAW_FIELD)
571 BlitBitmap(backbuffer, window,
572 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE, REAL_SX, REAL_SY);
574 else if (redraw_mask & REDRAW_DOORS)
576 if (redraw_mask & REDRAW_DOOR_1)
577 BlitBitmap(backbuffer, window, DX, DY, DXSIZE, DYSIZE, DX, DY);
579 if (redraw_mask & REDRAW_DOOR_2)
580 BlitBitmap(backbuffer, window, VX, VY, VXSIZE, VYSIZE, VX, VY);
582 if (redraw_mask & REDRAW_DOOR_3)
583 BlitBitmap(backbuffer, window, EX, EY, EXSIZE, EYSIZE, EX, EY);
586 redraw_mask = REDRAW_NONE;
589 PrintFrameTimeDebugging();
593 static void FadeCrossSaveBackbuffer()
595 BlitBitmap(backbuffer, bitmap_db_cross, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
598 static void FadeCrossRestoreBackbuffer()
600 int redraw_mask_last = redraw_mask;
602 BlitBitmap(bitmap_db_cross, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
604 // do not change redraw mask when restoring backbuffer after cross-fading
605 redraw_mask = redraw_mask_last;
608 static void FadeExt(int fade_mask, int fade_mode, int fade_type)
610 static int fade_type_skip = FADE_TYPE_NONE;
611 void (*draw_border_function)(void) = NULL;
612 Bitmap *bitmap = (fade_mode & FADE_TYPE_TRANSFORM ? bitmap_db_cross : NULL);
613 int x, y, width, height;
614 int fade_delay, post_delay;
616 if (fade_type == FADE_TYPE_FADE_OUT)
618 if (fade_type_skip != FADE_TYPE_NONE)
620 /* skip all fade operations until specified fade operation */
621 if (fade_type & fade_type_skip)
622 fade_type_skip = FADE_TYPE_NONE;
628 FadeCrossSaveBackbuffer();
631 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
634 FadeCrossSaveBackbuffer();
641 redraw_mask |= fade_mask;
643 if (fade_type == FADE_TYPE_SKIP)
645 fade_type_skip = fade_mode;
650 fade_delay = fading.fade_delay;
651 post_delay = (fade_mode == FADE_MODE_FADE_OUT ? fading.post_delay : 0);
653 if (fade_type_skip != FADE_TYPE_NONE)
655 /* skip all fade operations until specified fade operation */
656 if (fade_type & fade_type_skip)
657 fade_type_skip = FADE_TYPE_NONE;
662 if (global.autoplay_leveldir)
667 if (fade_mask == REDRAW_FIELD)
672 height = FADE_SYSIZE;
674 if (border.draw_masked_when_fading)
675 draw_border_function = DrawMaskedBorder_FIELD; /* update when fading */
677 DrawMaskedBorder_FIELD(); /* draw once */
679 else /* REDRAW_ALL */
687 if (!setup.fade_screens ||
689 fading.fade_mode == FADE_MODE_NONE)
691 if (fade_mode == FADE_MODE_FADE_OUT)
694 BlitBitmap(backbuffer, window, x, y, width, height, x, y);
696 redraw_mask &= ~fade_mask;
701 FadeRectangle(bitmap, x, y, width, height, fade_mode, fade_delay, post_delay,
702 draw_border_function);
704 if (fade_type == FADE_TYPE_FADE_OUT)
705 FadeCrossRestoreBackbuffer();
707 redraw_mask &= ~fade_mask;
710 static void SetScreenStates_BeforeFadingIn()
714 static void SetScreenStates_AfterFadingIn()
716 // store new source screen (to use correct masked border for fading)
717 gfx.fade_border_source_status = global.border_status;
719 global.anim_status = global.anim_status_next;
721 // force update of global animation status in case of rapid screen changes
722 redraw_mask = REDRAW_ALL;
726 static void SetScreenStates_BeforeFadingOut()
728 // store new target screen (to use correct masked border for fading)
729 gfx.fade_border_target_status = game_status;
731 global.anim_status = GAME_MODE_PSEUDO_FADING;
734 static void SetScreenStates_AfterFadingOut()
736 global.border_status = game_status;
739 void FadeIn(int fade_mask)
741 SetScreenStates_BeforeFadingIn();
744 DrawMaskedBorder(REDRAW_ALL);
747 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
748 FadeExt(fade_mask, fading.fade_mode, FADE_TYPE_FADE_IN);
750 FadeExt(fade_mask, FADE_MODE_FADE_IN, FADE_TYPE_FADE_IN);
754 FADE_SXSIZE = FULL_SXSIZE;
755 FADE_SYSIZE = FULL_SYSIZE;
757 SetScreenStates_AfterFadingIn();
760 void FadeOut(int fade_mask)
762 SetScreenStates_BeforeFadingOut();
765 DrawMaskedBorder(REDRAW_ALL);
768 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
769 FadeExt(fade_mask, fading.fade_mode, FADE_TYPE_FADE_OUT);
771 FadeExt(fade_mask, FADE_MODE_FADE_OUT, FADE_TYPE_FADE_OUT);
773 SetScreenStates_AfterFadingOut();
776 static void FadeSetLeaveNext(struct TitleFadingInfo fading_leave, boolean set)
778 static struct TitleFadingInfo fading_leave_stored;
781 fading_leave_stored = fading_leave;
783 fading = fading_leave_stored;
786 void FadeSetEnterMenu()
788 fading = menu.enter_menu;
790 FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
793 void FadeSetLeaveMenu()
795 fading = menu.leave_menu;
797 FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
800 void FadeSetEnterScreen()
802 fading = menu.enter_screen[game_status];
804 FadeSetLeaveNext(menu.leave_screen[game_status], TRUE); /* store */
807 void FadeSetNextScreen()
809 fading = menu.next_screen[game_status];
811 // (do not overwrite fade mode set by FadeSetEnterScreen)
812 // FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
815 void FadeSetLeaveScreen()
817 FadeSetLeaveNext(menu.leave_screen[game_status], FALSE); /* recall */
820 void FadeSetFromType(int type)
822 if (type & TYPE_ENTER_SCREEN)
823 FadeSetEnterScreen();
824 else if (type & TYPE_ENTER)
826 else if (type & TYPE_LEAVE)
830 void FadeSetDisabled()
832 static struct TitleFadingInfo fading_none = { FADE_MODE_NONE, -1, -1, -1 };
834 fading = fading_none;
837 void FadeSkipNextFadeIn()
839 FadeExt(0, FADE_MODE_SKIP_FADE_IN, FADE_TYPE_SKIP);
842 void FadeSkipNextFadeOut()
844 FadeExt(0, FADE_MODE_SKIP_FADE_OUT, FADE_TYPE_SKIP);
847 Bitmap *getBitmapFromGraphicOrDefault(int graphic, int default_graphic)
849 boolean redefined = getImageListEntryFromImageID(graphic)->redefined;
851 return (graphic == IMG_UNDEFINED ? NULL :
852 graphic_info[graphic].bitmap != NULL || redefined ?
853 graphic_info[graphic].bitmap :
854 graphic_info[default_graphic].bitmap);
857 Bitmap *getBackgroundBitmap(int graphic)
859 return getBitmapFromGraphicOrDefault(graphic, IMG_BACKGROUND);
862 Bitmap *getGlobalBorderBitmap(int graphic)
864 return getBitmapFromGraphicOrDefault(graphic, IMG_GLOBAL_BORDER);
867 Bitmap *getGlobalBorderBitmapFromStatus(int status)
870 (status == GAME_MODE_MAIN ||
871 status == GAME_MODE_PSEUDO_TYPENAME ? IMG_GLOBAL_BORDER_MAIN :
872 status == GAME_MODE_SCORES ? IMG_GLOBAL_BORDER_SCORES :
873 status == GAME_MODE_EDITOR ? IMG_GLOBAL_BORDER_EDITOR :
874 status == GAME_MODE_PLAYING ? IMG_GLOBAL_BORDER_PLAYING :
877 return getGlobalBorderBitmap(graphic);
880 void SetWindowBackgroundImageIfDefined(int graphic)
882 if (graphic_info[graphic].bitmap)
883 SetWindowBackgroundBitmap(graphic_info[graphic].bitmap);
886 void SetMainBackgroundImageIfDefined(int graphic)
888 if (graphic_info[graphic].bitmap)
889 SetMainBackgroundBitmap(graphic_info[graphic].bitmap);
892 void SetDoorBackgroundImageIfDefined(int graphic)
894 if (graphic_info[graphic].bitmap)
895 SetDoorBackgroundBitmap(graphic_info[graphic].bitmap);
898 void SetWindowBackgroundImage(int graphic)
900 SetWindowBackgroundBitmap(getBackgroundBitmap(graphic));
903 void SetMainBackgroundImage(int graphic)
905 SetMainBackgroundBitmap(getBackgroundBitmap(graphic));
908 void SetDoorBackgroundImage(int graphic)
910 SetDoorBackgroundBitmap(getBackgroundBitmap(graphic));
913 void SetPanelBackground()
915 struct GraphicInfo *gfx = &graphic_info[IMG_BACKGROUND_PANEL];
917 BlitBitmapTiled(gfx->bitmap, bitmap_db_panel, gfx->src_x, gfx->src_y,
918 gfx->width, gfx->height, 0, 0, DXSIZE, DYSIZE);
920 SetDoorBackgroundBitmap(bitmap_db_panel);
923 void DrawBackground(int x, int y, int width, int height)
925 /* "drawto" might still point to playfield buffer here (hall of fame) */
926 ClearRectangleOnBackground(backbuffer, x, y, width, height);
928 if (IN_GFX_FIELD_FULL(x, y))
929 redraw_mask |= REDRAW_FIELD;
930 else if (IN_GFX_DOOR_1(x, y))
931 redraw_mask |= REDRAW_DOOR_1;
932 else if (IN_GFX_DOOR_2(x, y))
933 redraw_mask |= REDRAW_DOOR_2;
934 else if (IN_GFX_DOOR_3(x, y))
935 redraw_mask |= REDRAW_DOOR_3;
938 void DrawBackgroundForFont(int x, int y, int width, int height, int font_nr)
940 struct FontBitmapInfo *font = getFontBitmapInfo(font_nr);
942 if (font->bitmap == NULL)
945 DrawBackground(x, y, width, height);
948 void DrawBackgroundForGraphic(int x, int y, int width, int height, int graphic)
950 struct GraphicInfo *g = &graphic_info[graphic];
952 if (g->bitmap == NULL)
955 DrawBackground(x, y, width, height);
958 static int game_status_last = -1;
959 static Bitmap *global_border_bitmap_last = NULL;
960 static Bitmap *global_border_bitmap = NULL;
961 static int real_sx_last = -1, real_sy_last = -1;
962 static int full_sxsize_last = -1, full_sysize_last = -1;
963 static int dx_last = -1, dy_last = -1;
964 static int dxsize_last = -1, dysize_last = -1;
965 static int vx_last = -1, vy_last = -1;
966 static int vxsize_last = -1, vysize_last = -1;
968 boolean CheckIfGlobalBorderHasChanged()
970 // if game status has not changed, global border has not changed either
971 if (game_status == game_status_last)
974 // determine and store new global border bitmap for current game status
975 global_border_bitmap = getGlobalBorderBitmapFromStatus(game_status);
977 return (global_border_bitmap_last != global_border_bitmap);
980 boolean CheckIfGlobalBorderRedrawIsNeeded()
982 // if game status has not changed, nothing has to be redrawn
983 if (game_status == game_status_last)
986 // redraw if last screen was title screen
987 if (game_status_last == GAME_MODE_TITLE)
990 // redraw if global screen border has changed
991 if (CheckIfGlobalBorderHasChanged())
994 // redraw if position or size of playfield area has changed
995 if (real_sx_last != REAL_SX || real_sy_last != REAL_SY ||
996 full_sxsize_last != FULL_SXSIZE || full_sysize_last != FULL_SYSIZE)
999 // redraw if position or size of door area has changed
1000 if (dx_last != DX || dy_last != DY ||
1001 dxsize_last != DXSIZE || dysize_last != DYSIZE)
1004 // redraw if position or size of tape area has changed
1005 if (vx_last != VX || vy_last != VY ||
1006 vxsize_last != VXSIZE || vysize_last != VYSIZE)
1012 void RedrawGlobalBorderFromBitmap(Bitmap *bitmap)
1015 BlitBitmap(bitmap, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
1017 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
1020 void RedrawGlobalBorder()
1022 Bitmap *bitmap = getGlobalBorderBitmapFromStatus(game_status);
1024 RedrawGlobalBorderFromBitmap(bitmap);
1026 redraw_mask = REDRAW_ALL;
1029 static void RedrawGlobalBorderIfNeeded()
1031 if (game_status == game_status_last)
1034 // copy current draw buffer to later copy back areas that have not changed
1035 if (game_status_last != GAME_MODE_TITLE)
1036 BlitBitmap(backbuffer, bitmap_db_store, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
1038 if (CheckIfGlobalBorderRedrawIsNeeded())
1040 // redraw global screen border (or clear, if defined to be empty)
1041 RedrawGlobalBorderFromBitmap(global_border_bitmap);
1043 // copy previous playfield and door areas, if they are defined on both
1044 // previous and current screen and if they still have the same size
1046 if (real_sx_last != -1 && real_sy_last != -1 &&
1047 REAL_SX != -1 && REAL_SY != -1 &&
1048 full_sxsize_last == FULL_SXSIZE && full_sysize_last == FULL_SYSIZE)
1049 BlitBitmap(bitmap_db_store, backbuffer,
1050 real_sx_last, real_sy_last, FULL_SXSIZE, FULL_SYSIZE,
1053 if (dx_last != -1 && dy_last != -1 &&
1054 DX != -1 && DY != -1 &&
1055 dxsize_last == DXSIZE && dysize_last == DYSIZE)
1056 BlitBitmap(bitmap_db_store, backbuffer,
1057 dx_last, dy_last, DXSIZE, DYSIZE, DX, DY);
1059 if (vx_last != -1 && vy_last != -1 &&
1060 VX != -1 && VY != -1 &&
1061 vxsize_last == VXSIZE && vysize_last == VYSIZE)
1062 BlitBitmap(bitmap_db_store, backbuffer,
1063 vx_last, vy_last, VXSIZE, VYSIZE, VX, VY);
1065 redraw_mask = REDRAW_ALL;
1068 game_status_last = game_status;
1070 global_border_bitmap_last = global_border_bitmap;
1072 real_sx_last = REAL_SX;
1073 real_sy_last = REAL_SY;
1074 full_sxsize_last = FULL_SXSIZE;
1075 full_sysize_last = FULL_SYSIZE;
1078 dxsize_last = DXSIZE;
1079 dysize_last = DYSIZE;
1082 vxsize_last = VXSIZE;
1083 vysize_last = VYSIZE;
1088 RedrawGlobalBorderIfNeeded();
1090 /* !!! "drawto" might still point to playfield buffer here (see above) !!! */
1091 /* (when entering hall of fame after playing) */
1092 DrawBackground(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
1094 /* !!! maybe this should be done before clearing the background !!! */
1095 if (game_status == GAME_MODE_PLAYING)
1097 ClearRectangle(fieldbuffer, 0, 0, FXSIZE, FYSIZE);
1098 SetDrawtoField(DRAW_FIELDBUFFER);
1102 SetDrawtoField(DRAW_BACKBUFFER);
1106 void MarkTileDirty(int x, int y)
1108 redraw_mask |= REDRAW_FIELD;
1111 void SetBorderElement()
1115 BorderElement = EL_EMPTY;
1117 for (y = 0; y < lev_fieldy && BorderElement == EL_EMPTY; y++)
1119 for (x = 0; x < lev_fieldx; x++)
1121 if (!IS_INDESTRUCTIBLE(Feld[x][y]))
1122 BorderElement = EL_STEELWALL;
1124 if (y != 0 && y != lev_fieldy - 1 && x != lev_fieldx - 1)
1130 void FloodFillLevel(int from_x, int from_y, int fill_element,
1131 short field[MAX_LEV_FIELDX][MAX_LEV_FIELDY],
1132 int max_fieldx, int max_fieldy)
1136 static int check[4][2] = { { -1, 0 }, { 0, -1 }, { 1, 0 }, { 0, 1 } };
1137 static int safety = 0;
1139 /* check if starting field still has the desired content */
1140 if (field[from_x][from_y] == fill_element)
1145 if (safety > max_fieldx * max_fieldy)
1146 Error(ERR_EXIT, "Something went wrong in 'FloodFill()'. Please debug.");
1148 old_element = field[from_x][from_y];
1149 field[from_x][from_y] = fill_element;
1151 for (i = 0; i < 4; i++)
1153 x = from_x + check[i][0];
1154 y = from_y + check[i][1];
1156 if (IN_FIELD(x, y, max_fieldx, max_fieldy) && field[x][y] == old_element)
1157 FloodFillLevel(x, y, fill_element, field, max_fieldx, max_fieldy);
1163 void SetRandomAnimationValue(int x, int y)
1165 gfx.anim_random_frame = GfxRandom[x][y];
1168 int getGraphicAnimationFrame(int graphic, int sync_frame)
1170 /* animation synchronized with global frame counter, not move position */
1171 if (graphic_info[graphic].anim_global_sync || sync_frame < 0)
1172 sync_frame = FrameCounter;
1174 return getAnimationFrame(graphic_info[graphic].anim_frames,
1175 graphic_info[graphic].anim_delay,
1176 graphic_info[graphic].anim_mode,
1177 graphic_info[graphic].anim_start_frame,
1181 void getSizedGraphicSourceExt(int graphic, int frame, int tilesize,
1182 Bitmap **bitmap, int *x, int *y,
1183 boolean get_backside)
1185 struct GraphicInfo *g = &graphic_info[graphic];
1186 Bitmap *src_bitmap = g->bitmap;
1187 int src_x = g->src_x + (get_backside ? g->offset2_x : 0);
1188 int src_y = g->src_y + (get_backside ? g->offset2_y : 0);
1189 int tilesize_capped = MIN(MAX(1, tilesize), TILESIZE);
1191 // if no in-game graphics defined, always use standard graphic size
1192 if (g->bitmaps[IMG_BITMAP_GAME] == NULL)
1193 tilesize = TILESIZE;
1195 if (tilesize == gfx.standard_tile_size)
1196 src_bitmap = g->bitmaps[IMG_BITMAP_STANDARD];
1197 else if (tilesize == game.tile_size)
1198 src_bitmap = g->bitmaps[IMG_BITMAP_GAME];
1200 src_bitmap = g->bitmaps[IMG_BITMAP_1x1 - log_2(tilesize_capped)];
1202 if (g->offset_y == 0) /* frames are ordered horizontally */
1204 int max_width = g->anim_frames_per_line * g->width;
1205 int pos = (src_y / g->height) * max_width + src_x + frame * g->offset_x;
1207 src_x = pos % max_width;
1208 src_y = src_y % g->height + pos / max_width * g->height;
1210 else if (g->offset_x == 0) /* frames are ordered vertically */
1212 int max_height = g->anim_frames_per_line * g->height;
1213 int pos = (src_x / g->width) * max_height + src_y + frame * g->offset_y;
1215 src_x = src_x % g->width + pos / max_height * g->width;
1216 src_y = pos % max_height;
1218 else /* frames are ordered diagonally */
1220 src_x = src_x + frame * g->offset_x;
1221 src_y = src_y + frame * g->offset_y;
1224 *bitmap = src_bitmap;
1225 *x = src_x * tilesize / g->tile_size;
1226 *y = src_y * tilesize / g->tile_size;
1229 void getFixedGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
1230 int *x, int *y, boolean get_backside)
1232 getSizedGraphicSourceExt(graphic, frame, TILESIZE, bitmap, x, y,
1236 void getSizedGraphicSource(int graphic, int frame, int tilesize,
1237 Bitmap **bitmap, int *x, int *y)
1239 getSizedGraphicSourceExt(graphic, frame, tilesize, bitmap, x, y, FALSE);
1242 void getFixedGraphicSource(int graphic, int frame,
1243 Bitmap **bitmap, int *x, int *y)
1245 getSizedGraphicSourceExt(graphic, frame, TILESIZE, bitmap, x, y, FALSE);
1248 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
1250 getSizedGraphicSource(graphic, 0, MINI_TILESIZE, bitmap, x, y);
1253 inline static void getGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
1254 int *x, int *y, boolean get_backside)
1256 struct GraphicInfo *g = &graphic_info[graphic];
1257 int src_x = g->src_x + (get_backside ? g->offset2_x : 0);
1258 int src_y = g->src_y + (get_backside ? g->offset2_y : 0);
1260 if (TILESIZE_VAR != TILESIZE)
1261 return getSizedGraphicSourceExt(graphic, frame, TILESIZE_VAR, bitmap, x, y,
1264 *bitmap = g->bitmap;
1266 if (g->offset_y == 0) /* frames are ordered horizontally */
1268 int max_width = g->anim_frames_per_line * g->width;
1269 int pos = (src_y / g->height) * max_width + src_x + frame * g->offset_x;
1271 *x = pos % max_width;
1272 *y = src_y % g->height + pos / max_width * g->height;
1274 else if (g->offset_x == 0) /* frames are ordered vertically */
1276 int max_height = g->anim_frames_per_line * g->height;
1277 int pos = (src_x / g->width) * max_height + src_y + frame * g->offset_y;
1279 *x = src_x % g->width + pos / max_height * g->width;
1280 *y = pos % max_height;
1282 else /* frames are ordered diagonally */
1284 *x = src_x + frame * g->offset_x;
1285 *y = src_y + frame * g->offset_y;
1288 *x = *x * TILESIZE_VAR / g->tile_size;
1289 *y = *y * TILESIZE_VAR / g->tile_size;
1292 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
1294 getGraphicSourceExt(graphic, frame, bitmap, x, y, FALSE);
1297 void DrawGraphic(int x, int y, int graphic, int frame)
1300 if (!IN_SCR_FIELD(x, y))
1302 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
1303 printf("DrawGraphic(): This should never happen!\n");
1308 DrawGraphicExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR, graphic,
1311 MarkTileDirty(x, y);
1314 void DrawFixedGraphic(int x, int y, int graphic, int frame)
1317 if (!IN_SCR_FIELD(x, y))
1319 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
1320 printf("DrawGraphic(): This should never happen!\n");
1325 DrawFixedGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic,
1327 MarkTileDirty(x, y);
1330 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
1336 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1338 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX_VAR, TILEY_VAR, x, y);
1341 void DrawFixedGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
1347 getFixedGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1348 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
1351 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
1354 if (!IN_SCR_FIELD(x, y))
1356 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
1357 printf("DrawGraphicThruMask(): This should never happen!\n");
1362 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR,
1365 MarkTileDirty(x, y);
1368 void DrawFixedGraphicThruMask(int x, int y, int graphic, int frame)
1371 if (!IN_SCR_FIELD(x, y))
1373 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
1374 printf("DrawGraphicThruMask(): This should never happen!\n");
1379 DrawFixedGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
1381 MarkTileDirty(x, y);
1384 void DrawGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y, int graphic,
1390 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1392 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX_VAR, TILEY_VAR,
1396 void DrawFixedGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y,
1397 int graphic, int frame)
1402 getFixedGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1404 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY,
1408 void DrawSizedGraphic(int x, int y, int graphic, int frame, int tilesize)
1410 DrawSizedGraphicExt(drawto, SX + x * tilesize, SY + y * tilesize, graphic,
1412 MarkTileDirty(x / tilesize, y / tilesize);
1415 void DrawSizedGraphicExt(DrawBuffer *d, int x, int y, int graphic, int frame,
1421 getSizedGraphicSource(graphic, frame, tilesize, &src_bitmap, &src_x, &src_y);
1422 BlitBitmap(src_bitmap, d, src_x, src_y, tilesize, tilesize, x, y);
1425 void DrawMiniGraphic(int x, int y, int graphic)
1427 DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
1428 MarkTileDirty(x / 2, y / 2);
1431 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
1436 getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1437 BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
1440 inline static void DrawGraphicShiftedNormal(int x, int y, int dx, int dy,
1441 int graphic, int frame,
1442 int cut_mode, int mask_mode)
1447 int width = TILEX, height = TILEY;
1450 if (dx || dy) /* shifted graphic */
1452 if (x < BX1) /* object enters playfield from the left */
1459 else if (x > BX2) /* object enters playfield from the right */
1465 else if (x == BX1 && dx < 0) /* object leaves playfield to the left */
1471 else if (x == BX2 && dx > 0) /* object leaves playfield to the right */
1473 else if (dx) /* general horizontal movement */
1474 MarkTileDirty(x + SIGN(dx), y);
1476 if (y < BY1) /* object enters playfield from the top */
1478 if (cut_mode == CUT_BELOW) /* object completely above top border */
1486 else if (y > BY2) /* object enters playfield from the bottom */
1492 else if (y == BY1 && dy < 0) /* object leaves playfield to the top */
1498 else if (dy > 0 && cut_mode == CUT_ABOVE)
1500 if (y == BY2) /* object completely above bottom border */
1506 MarkTileDirty(x, y + 1);
1507 } /* object leaves playfield to the bottom */
1508 else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
1510 else if (dy) /* general vertical movement */
1511 MarkTileDirty(x, y + SIGN(dy));
1515 if (!IN_SCR_FIELD(x, y))
1517 printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
1518 printf("DrawGraphicShifted(): This should never happen!\n");
1523 width = width * TILESIZE_VAR / TILESIZE;
1524 height = height * TILESIZE_VAR / TILESIZE;
1525 cx = cx * TILESIZE_VAR / TILESIZE;
1526 cy = cy * TILESIZE_VAR / TILESIZE;
1527 dx = dx * TILESIZE_VAR / TILESIZE;
1528 dy = dy * TILESIZE_VAR / TILESIZE;
1530 if (width > 0 && height > 0)
1532 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1537 dst_x = FX + x * TILEX_VAR + dx;
1538 dst_y = FY + y * TILEY_VAR + dy;
1540 if (mask_mode == USE_MASKING)
1541 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1544 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1547 MarkTileDirty(x, y);
1551 inline static void DrawGraphicShiftedDouble(int x, int y, int dx, int dy,
1552 int graphic, int frame,
1553 int cut_mode, int mask_mode)
1558 int width = TILEX_VAR, height = TILEY_VAR;
1561 int x2 = x + SIGN(dx);
1562 int y2 = y + SIGN(dy);
1564 /* movement with two-tile animations must be sync'ed with movement position,
1565 not with current GfxFrame (which can be higher when using slow movement) */
1566 int anim_pos = (dx ? ABS(dx) : ABS(dy));
1567 int anim_frames = graphic_info[graphic].anim_frames;
1569 /* (we also need anim_delay here for movement animations with less frames) */
1570 int anim_delay = graphic_info[graphic].anim_delay;
1571 int sync_frame = anim_pos * anim_frames * anim_delay / TILESIZE;
1573 boolean draw_start_tile = (cut_mode != CUT_ABOVE); /* only for falling! */
1574 boolean draw_end_tile = (cut_mode != CUT_BELOW); /* only for falling! */
1576 /* re-calculate animation frame for two-tile movement animation */
1577 frame = getGraphicAnimationFrame(graphic, sync_frame);
1579 /* check if movement start graphic inside screen area and should be drawn */
1580 if (draw_start_tile && IN_SCR_FIELD(x1, y1))
1582 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, TRUE);
1584 dst_x = FX + x1 * TILEX_VAR;
1585 dst_y = FY + y1 * TILEY_VAR;
1587 if (mask_mode == USE_MASKING)
1588 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1591 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1594 MarkTileDirty(x1, y1);
1597 /* check if movement end graphic inside screen area and should be drawn */
1598 if (draw_end_tile && IN_SCR_FIELD(x2, y2))
1600 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
1602 dst_x = FX + x2 * TILEX_VAR;
1603 dst_y = FY + y2 * TILEY_VAR;
1605 if (mask_mode == USE_MASKING)
1606 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1609 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1612 MarkTileDirty(x2, y2);
1616 static void DrawGraphicShifted(int x, int y, int dx, int dy,
1617 int graphic, int frame,
1618 int cut_mode, int mask_mode)
1622 DrawGraphic(x, y, graphic, frame);
1627 if (graphic_info[graphic].double_movement) /* EM style movement images */
1628 DrawGraphicShiftedDouble(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1630 DrawGraphicShiftedNormal(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1633 void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
1634 int frame, int cut_mode)
1636 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, USE_MASKING);
1639 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
1640 int cut_mode, int mask_mode)
1642 int lx = LEVELX(x), ly = LEVELY(y);
1646 if (IN_LEV_FIELD(lx, ly))
1648 SetRandomAnimationValue(lx, ly);
1650 graphic = el_act_dir2img(element, GfxAction[lx][ly], GfxDir[lx][ly]);
1651 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1653 /* do not use double (EM style) movement graphic when not moving */
1654 if (graphic_info[graphic].double_movement && !dx && !dy)
1656 graphic = el_act_dir2img(element, ACTION_DEFAULT, GfxDir[lx][ly]);
1657 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1660 else /* border element */
1662 graphic = el2img(element);
1663 frame = getGraphicAnimationFrame(graphic, -1);
1666 if (element == EL_EXPANDABLE_WALL)
1668 boolean left_stopped = FALSE, right_stopped = FALSE;
1670 if (!IN_LEV_FIELD(lx - 1, ly) || IS_WALL(Feld[lx - 1][ly]))
1671 left_stopped = TRUE;
1672 if (!IN_LEV_FIELD(lx + 1, ly) || IS_WALL(Feld[lx + 1][ly]))
1673 right_stopped = TRUE;
1675 if (left_stopped && right_stopped)
1677 else if (left_stopped)
1679 graphic = IMG_EXPANDABLE_WALL_GROWING_RIGHT;
1680 frame = graphic_info[graphic].anim_frames - 1;
1682 else if (right_stopped)
1684 graphic = IMG_EXPANDABLE_WALL_GROWING_LEFT;
1685 frame = graphic_info[graphic].anim_frames - 1;
1690 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
1691 else if (mask_mode == USE_MASKING)
1692 DrawGraphicThruMask(x, y, graphic, frame);
1694 DrawGraphic(x, y, graphic, frame);
1697 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
1698 int cut_mode, int mask_mode)
1700 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1701 DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
1702 cut_mode, mask_mode);
1705 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
1708 DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1711 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
1714 DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1717 void DrawLevelElementThruMask(int x, int y, int element)
1719 DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1722 void DrawLevelFieldThruMask(int x, int y)
1724 DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
1727 /* !!! implementation of quicksand is totally broken !!! */
1728 #define IS_CRUMBLED_TILE(x, y, e) \
1729 (GFX_CRUMBLED(e) && (!IN_LEV_FIELD(x, y) || \
1730 !IS_MOVING(x, y) || \
1731 (e) == EL_QUICKSAND_EMPTYING || \
1732 (e) == EL_QUICKSAND_FAST_EMPTYING))
1734 static void DrawLevelFieldCrumbledInnerCorners(int x, int y, int dx, int dy,
1739 int width, height, cx, cy;
1740 int sx = SCREENX(x), sy = SCREENY(y);
1741 int crumbled_border_size = graphic_info[graphic].border_size;
1744 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1746 for (i = 1; i < 4; i++)
1748 int dxx = (i & 1 ? dx : 0);
1749 int dyy = (i & 2 ? dy : 0);
1752 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1755 /* check if neighbour field is of same crumble type */
1756 boolean same = (IS_CRUMBLED_TILE(xx, yy, element) &&
1757 graphic_info[graphic].class ==
1758 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class);
1760 /* return if check prevents inner corner */
1761 if (same == (dxx == dx && dyy == dy))
1765 /* if we reach this point, we have an inner corner */
1767 getGraphicSource(graphic, 1, &src_bitmap, &src_x, &src_y);
1769 width = crumbled_border_size * TILESIZE_VAR / TILESIZE;
1770 height = crumbled_border_size * TILESIZE_VAR / TILESIZE;
1771 cx = (dx > 0 ? TILESIZE_VAR - width : 0);
1772 cy = (dy > 0 ? TILESIZE_VAR - height : 0);
1774 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1775 width, height, FX + sx * TILEX_VAR + cx, FY + sy * TILEY_VAR + cy);
1778 static void DrawLevelFieldCrumbledBorders(int x, int y, int graphic, int frame,
1783 int width, height, bx, by, cx, cy;
1784 int sx = SCREENX(x), sy = SCREENY(y);
1785 int crumbled_border_size = graphic_info[graphic].border_size;
1786 int crumbled_border_size_var = crumbled_border_size * TILESIZE_VAR / TILESIZE;
1787 int crumbled_border_pos_var = TILESIZE_VAR - crumbled_border_size_var;
1790 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1792 /* draw simple, sloppy, non-corner-accurate crumbled border */
1794 width = (dir == 1 || dir == 2 ? crumbled_border_size_var : TILESIZE_VAR);
1795 height = (dir == 0 || dir == 3 ? crumbled_border_size_var : TILESIZE_VAR);
1796 cx = (dir == 2 ? crumbled_border_pos_var : 0);
1797 cy = (dir == 3 ? crumbled_border_pos_var : 0);
1799 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy, width, height,
1800 FX + sx * TILEX_VAR + cx,
1801 FY + sy * TILEY_VAR + cy);
1803 /* (remaining middle border part must be at least as big as corner part) */
1804 if (!(graphic_info[graphic].style & STYLE_ACCURATE_BORDERS) ||
1805 crumbled_border_size >= TILESIZE / 3)
1808 /* correct corners of crumbled border, if needed */
1810 for (i = -1; i <= 1; i += 2)
1812 int xx = x + (dir == 0 || dir == 3 ? i : 0);
1813 int yy = y + (dir == 1 || dir == 2 ? i : 0);
1814 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1817 /* check if neighbour field is of same crumble type */
1818 if (IS_CRUMBLED_TILE(xx, yy, element) &&
1819 graphic_info[graphic].class ==
1820 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
1822 /* no crumbled corner, but continued crumbled border */
1824 int c1 = (dir == 2 || dir == 3 ? crumbled_border_pos_var : 0);
1825 int c2 = (i == 1 ? crumbled_border_pos_var : 0);
1826 int b1 = (i == 1 ? crumbled_border_size_var :
1827 TILESIZE_VAR - 2 * crumbled_border_size_var);
1829 width = crumbled_border_size_var;
1830 height = crumbled_border_size_var;
1832 if (dir == 1 || dir == 2)
1847 BlitBitmap(src_bitmap, drawto_field, src_x + bx, src_y + by,
1849 FX + sx * TILEX_VAR + cx,
1850 FY + sy * TILEY_VAR + cy);
1855 static void DrawLevelFieldCrumbledExt(int x, int y, int graphic, int frame)
1857 int sx = SCREENX(x), sy = SCREENY(y);
1860 static int xy[4][2] =
1868 if (!IN_LEV_FIELD(x, y))
1871 element = TILE_GFX_ELEMENT(x, y);
1873 /* crumble field itself */
1874 if (IS_CRUMBLED_TILE(x, y, element))
1876 if (!IN_SCR_FIELD(sx, sy))
1879 for (i = 0; i < 4; i++)
1881 int xx = x + xy[i][0];
1882 int yy = y + xy[i][1];
1884 element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1887 /* check if neighbour field is of same crumble type */
1888 if (IS_CRUMBLED_TILE(xx, yy, element) &&
1889 graphic_info[graphic].class ==
1890 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
1893 DrawLevelFieldCrumbledBorders(x, y, graphic, frame, i);
1896 if ((graphic_info[graphic].style & STYLE_INNER_CORNERS) &&
1897 graphic_info[graphic].anim_frames == 2)
1899 for (i = 0; i < 4; i++)
1901 int dx = (i & 1 ? +1 : -1);
1902 int dy = (i & 2 ? +1 : -1);
1904 DrawLevelFieldCrumbledInnerCorners(x, y, dx, dy, graphic);
1908 MarkTileDirty(sx, sy);
1910 else /* center field not crumbled -- crumble neighbour fields */
1912 for (i = 0; i < 4; i++)
1914 int xx = x + xy[i][0];
1915 int yy = y + xy[i][1];
1916 int sxx = sx + xy[i][0];
1917 int syy = sy + xy[i][1];
1919 if (!IN_LEV_FIELD(xx, yy) ||
1920 !IN_SCR_FIELD(sxx, syy))
1923 if (Feld[xx][yy] == EL_ELEMENT_SNAPPING)
1926 element = TILE_GFX_ELEMENT(xx, yy);
1928 if (!IS_CRUMBLED_TILE(xx, yy, element))
1931 graphic = el_act2crm(element, ACTION_DEFAULT);
1933 DrawLevelFieldCrumbledBorders(xx, yy, graphic, 0, 3 - i);
1935 MarkTileDirty(sxx, syy);
1940 void DrawLevelFieldCrumbled(int x, int y)
1944 if (!IN_LEV_FIELD(x, y))
1947 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
1948 GfxElement[x][y] != EL_UNDEFINED &&
1949 GFX_CRUMBLED(GfxElement[x][y]))
1951 DrawLevelFieldCrumbledDigging(x, y, GfxDir[x][y], GfxFrame[x][y]);
1956 graphic = el_act2crm(TILE_GFX_ELEMENT(x, y), ACTION_DEFAULT);
1958 DrawLevelFieldCrumbledExt(x, y, graphic, 0);
1961 void DrawLevelFieldCrumbledDigging(int x, int y, int direction,
1964 int graphic1 = el_act_dir2img(GfxElement[x][y], ACTION_DIGGING, direction);
1965 int graphic2 = el_act_dir2crm(GfxElement[x][y], ACTION_DIGGING, direction);
1966 int frame1 = getGraphicAnimationFrame(graphic1, step_frame);
1967 int frame2 = getGraphicAnimationFrame(graphic2, step_frame);
1968 int sx = SCREENX(x), sy = SCREENY(y);
1970 DrawGraphic(sx, sy, graphic1, frame1);
1971 DrawLevelFieldCrumbledExt(x, y, graphic2, frame2);
1974 void DrawLevelFieldCrumbledNeighbours(int x, int y)
1976 int sx = SCREENX(x), sy = SCREENY(y);
1977 static int xy[4][2] =
1986 for (i = 0; i < 4; i++)
1988 int xx = x + xy[i][0];
1989 int yy = y + xy[i][1];
1990 int sxx = sx + xy[i][0];
1991 int syy = sy + xy[i][1];
1993 if (!IN_LEV_FIELD(xx, yy) ||
1994 !IN_SCR_FIELD(sxx, syy) ||
1995 !GFX_CRUMBLED(Feld[xx][yy]) ||
1999 DrawLevelField(xx, yy);
2003 static int getBorderElement(int x, int y)
2007 { EL_STEELWALL_TOPLEFT, EL_INVISIBLE_STEELWALL_TOPLEFT },
2008 { EL_STEELWALL_TOPRIGHT, EL_INVISIBLE_STEELWALL_TOPRIGHT },
2009 { EL_STEELWALL_BOTTOMLEFT, EL_INVISIBLE_STEELWALL_BOTTOMLEFT },
2010 { EL_STEELWALL_BOTTOMRIGHT, EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
2011 { EL_STEELWALL_VERTICAL, EL_INVISIBLE_STEELWALL_VERTICAL },
2012 { EL_STEELWALL_HORIZONTAL, EL_INVISIBLE_STEELWALL_HORIZONTAL },
2013 { EL_STEELWALL, EL_INVISIBLE_STEELWALL }
2015 int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
2016 int steel_position = (x == -1 && y == -1 ? 0 :
2017 x == lev_fieldx && y == -1 ? 1 :
2018 x == -1 && y == lev_fieldy ? 2 :
2019 x == lev_fieldx && y == lev_fieldy ? 3 :
2020 x == -1 || x == lev_fieldx ? 4 :
2021 y == -1 || y == lev_fieldy ? 5 : 6);
2023 return border[steel_position][steel_type];
2026 void DrawScreenElement(int x, int y, int element)
2028 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
2029 DrawLevelFieldCrumbled(LEVELX(x), LEVELY(y));
2032 void DrawLevelElement(int x, int y, int element)
2034 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
2035 DrawScreenElement(SCREENX(x), SCREENY(y), element);
2038 void DrawScreenField(int x, int y)
2040 int lx = LEVELX(x), ly = LEVELY(y);
2041 int element, content;
2043 if (!IN_LEV_FIELD(lx, ly))
2045 if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
2048 element = getBorderElement(lx, ly);
2050 DrawScreenElement(x, y, element);
2055 element = Feld[lx][ly];
2056 content = Store[lx][ly];
2058 if (IS_MOVING(lx, ly))
2060 int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
2061 boolean cut_mode = NO_CUTTING;
2063 if (element == EL_QUICKSAND_EMPTYING ||
2064 element == EL_QUICKSAND_FAST_EMPTYING ||
2065 element == EL_MAGIC_WALL_EMPTYING ||
2066 element == EL_BD_MAGIC_WALL_EMPTYING ||
2067 element == EL_DC_MAGIC_WALL_EMPTYING ||
2068 element == EL_AMOEBA_DROPPING)
2069 cut_mode = CUT_ABOVE;
2070 else if (element == EL_QUICKSAND_FILLING ||
2071 element == EL_QUICKSAND_FAST_FILLING ||
2072 element == EL_MAGIC_WALL_FILLING ||
2073 element == EL_BD_MAGIC_WALL_FILLING ||
2074 element == EL_DC_MAGIC_WALL_FILLING)
2075 cut_mode = CUT_BELOW;
2077 if (cut_mode == CUT_ABOVE)
2078 DrawScreenElement(x, y, element);
2080 DrawScreenElement(x, y, EL_EMPTY);
2083 DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
2084 else if (cut_mode == NO_CUTTING)
2085 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
2088 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
2090 if (cut_mode == CUT_BELOW &&
2091 IN_LEV_FIELD(lx, ly + 1) && IN_SCR_FIELD(x, y + 1))
2092 DrawLevelElement(lx, ly + 1, element);
2095 if (content == EL_ACID)
2097 int dir = MovDir[lx][ly];
2098 int newlx = lx + (dir == MV_LEFT ? -1 : dir == MV_RIGHT ? +1 : 0);
2099 int newly = ly + (dir == MV_UP ? -1 : dir == MV_DOWN ? +1 : 0);
2101 DrawLevelElementThruMask(newlx, newly, EL_ACID);
2104 else if (IS_BLOCKED(lx, ly))
2109 boolean cut_mode = NO_CUTTING;
2110 int element_old, content_old;
2112 Blocked2Moving(lx, ly, &oldx, &oldy);
2115 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
2116 MovDir[oldx][oldy] == MV_RIGHT);
2118 element_old = Feld[oldx][oldy];
2119 content_old = Store[oldx][oldy];
2121 if (element_old == EL_QUICKSAND_EMPTYING ||
2122 element_old == EL_QUICKSAND_FAST_EMPTYING ||
2123 element_old == EL_MAGIC_WALL_EMPTYING ||
2124 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
2125 element_old == EL_DC_MAGIC_WALL_EMPTYING ||
2126 element_old == EL_AMOEBA_DROPPING)
2127 cut_mode = CUT_ABOVE;
2129 DrawScreenElement(x, y, EL_EMPTY);
2132 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
2134 else if (cut_mode == NO_CUTTING)
2135 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
2138 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
2141 else if (IS_DRAWABLE(element))
2142 DrawScreenElement(x, y, element);
2144 DrawScreenElement(x, y, EL_EMPTY);
2147 void DrawLevelField(int x, int y)
2149 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
2150 DrawScreenField(SCREENX(x), SCREENY(y));
2151 else if (IS_MOVING(x, y))
2155 Moving2Blocked(x, y, &newx, &newy);
2156 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
2157 DrawScreenField(SCREENX(newx), SCREENY(newy));
2159 else if (IS_BLOCKED(x, y))
2163 Blocked2Moving(x, y, &oldx, &oldy);
2164 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
2165 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
2169 void DrawSizedElement(int x, int y, int element, int tilesize)
2173 graphic = el2edimg(element);
2174 DrawSizedGraphic(x, y, graphic, 0, tilesize);
2177 void DrawMiniElement(int x, int y, int element)
2181 graphic = el2edimg(element);
2182 DrawMiniGraphic(x, y, graphic);
2185 void DrawSizedElementOrWall(int sx, int sy, int scroll_x, int scroll_y,
2188 int x = sx + scroll_x, y = sy + scroll_y;
2190 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
2191 DrawSizedElement(sx, sy, EL_EMPTY, tilesize);
2192 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
2193 DrawSizedElement(sx, sy, Feld[x][y], tilesize);
2195 DrawSizedGraphic(sx, sy, el2edimg(getBorderElement(x, y)), 0, tilesize);
2198 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
2200 int x = sx + scroll_x, y = sy + scroll_y;
2202 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
2203 DrawMiniElement(sx, sy, EL_EMPTY);
2204 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
2205 DrawMiniElement(sx, sy, Feld[x][y]);
2207 DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
2210 void DrawEnvelopeBackgroundTiles(int graphic, int startx, int starty,
2211 int x, int y, int xsize, int ysize,
2212 int tile_width, int tile_height)
2216 int dst_x = startx + x * tile_width;
2217 int dst_y = starty + y * tile_height;
2218 int width = graphic_info[graphic].width;
2219 int height = graphic_info[graphic].height;
2220 int inner_width_raw = MAX(width - 2 * tile_width, tile_width);
2221 int inner_height_raw = MAX(height - 2 * tile_height, tile_height);
2222 int inner_width = inner_width_raw - (inner_width_raw % tile_width);
2223 int inner_height = inner_height_raw - (inner_height_raw % tile_height);
2224 int inner_sx = (width >= 3 * tile_width ? tile_width : 0);
2225 int inner_sy = (height >= 3 * tile_height ? tile_height : 0);
2226 boolean draw_masked = graphic_info[graphic].draw_masked;
2228 getFixedGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
2230 if (src_bitmap == NULL || width < tile_width || height < tile_height)
2232 ClearRectangle(drawto, dst_x, dst_y, tile_width, tile_height);
2236 src_x += (x == 0 ? 0 : x == xsize - 1 ? width - tile_width :
2237 inner_sx + (x - 1) * tile_width % inner_width);
2238 src_y += (y == 0 ? 0 : y == ysize - 1 ? height - tile_height :
2239 inner_sy + (y - 1) * tile_height % inner_height);
2242 BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, tile_width, tile_height,
2245 BlitBitmap(src_bitmap, drawto, src_x, src_y, tile_width, tile_height,
2249 void DrawEnvelopeBackground(int graphic, int startx, int starty,
2250 int x, int y, int xsize, int ysize, int font_nr)
2252 int font_width = getFontWidth(font_nr);
2253 int font_height = getFontHeight(font_nr);
2255 DrawEnvelopeBackgroundTiles(graphic, startx, starty, x, y, xsize, ysize,
2256 font_width, font_height);
2259 void AnimateEnvelope(int envelope_nr, int anim_mode, int action)
2261 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2262 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
2263 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
2264 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2265 boolean no_delay = (tape.warp_forward);
2266 unsigned int anim_delay = 0;
2267 int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
2268 int anim_delay_value = (no_delay ? 0 : frame_delay_value) / 2;
2269 int font_nr = FONT_ENVELOPE_1 + envelope_nr;
2270 int font_width = getFontWidth(font_nr);
2271 int font_height = getFontHeight(font_nr);
2272 int max_xsize = level.envelope[envelope_nr].xsize;
2273 int max_ysize = level.envelope[envelope_nr].ysize;
2274 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
2275 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
2276 int xend = max_xsize;
2277 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
2278 int xstep = (xstart < xend ? 1 : 0);
2279 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
2281 int end = MAX(xend - xstart, yend - ystart);
2284 for (i = start; i <= end; i++)
2286 int last_frame = end; // last frame of this "for" loop
2287 int x = xstart + i * xstep;
2288 int y = ystart + i * ystep;
2289 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
2290 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
2291 int sx = SX + (SXSIZE - xsize * font_width) / 2;
2292 int sy = SY + (SYSIZE - ysize * font_height) / 2;
2295 SetDrawtoField(DRAW_FIELDBUFFER);
2297 BlitScreenToBitmap(backbuffer);
2299 SetDrawtoField(DRAW_BACKBUFFER);
2301 for (yy = 0; yy < ysize; yy++)
2302 for (xx = 0; xx < xsize; xx++)
2303 DrawEnvelopeBackground(graphic, sx, sy, xx, yy, xsize, ysize, font_nr);
2305 DrawTextBuffer(sx + font_width, sy + font_height,
2306 level.envelope[envelope_nr].text, font_nr, max_xsize,
2307 xsize - 2, ysize - 2, 0, mask_mode,
2308 level.envelope[envelope_nr].autowrap,
2309 level.envelope[envelope_nr].centered, FALSE);
2311 redraw_mask |= REDRAW_FIELD;
2314 SkipUntilDelayReached(&anim_delay, anim_delay_value, &i, last_frame);
2318 void ShowEnvelope(int envelope_nr)
2320 int element = EL_ENVELOPE_1 + envelope_nr;
2321 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2322 int sound_opening = element_info[element].sound[ACTION_OPENING];
2323 int sound_closing = element_info[element].sound[ACTION_CLOSING];
2324 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2325 boolean no_delay = (tape.warp_forward);
2326 int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
2327 int wait_delay_value = (no_delay ? 0 : normal_delay_value);
2328 int anim_mode = graphic_info[graphic].anim_mode;
2329 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
2330 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
2332 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
2334 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
2336 if (anim_mode == ANIM_DEFAULT)
2337 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_OPENING);
2339 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_OPENING);
2342 Delay(wait_delay_value);
2344 WaitForEventToContinue();
2346 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
2348 if (anim_mode != ANIM_NONE)
2349 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_CLOSING);
2351 if (anim_mode == ANIM_DEFAULT)
2352 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_CLOSING);
2354 game.envelope_active = FALSE;
2356 SetDrawtoField(DRAW_FIELDBUFFER);
2358 redraw_mask |= REDRAW_FIELD;
2362 static void setRequestBasePosition(int *x, int *y)
2364 int sx_base, sy_base;
2366 if (request.x != -1)
2367 sx_base = request.x;
2368 else if (request.align == ALIGN_LEFT)
2370 else if (request.align == ALIGN_RIGHT)
2371 sx_base = SX + SXSIZE;
2373 sx_base = SX + SXSIZE / 2;
2375 if (request.y != -1)
2376 sy_base = request.y;
2377 else if (request.valign == VALIGN_TOP)
2379 else if (request.valign == VALIGN_BOTTOM)
2380 sy_base = SY + SYSIZE;
2382 sy_base = SY + SYSIZE / 2;
2388 static void setRequestPositionExt(int *x, int *y, int width, int height,
2389 boolean add_border_size)
2391 int border_size = request.border_size;
2392 int sx_base, sy_base;
2395 setRequestBasePosition(&sx_base, &sy_base);
2397 if (request.align == ALIGN_LEFT)
2399 else if (request.align == ALIGN_RIGHT)
2400 sx = sx_base - width;
2402 sx = sx_base - width / 2;
2404 if (request.valign == VALIGN_TOP)
2406 else if (request.valign == VALIGN_BOTTOM)
2407 sy = sy_base - height;
2409 sy = sy_base - height / 2;
2411 sx = MAX(0, MIN(sx, WIN_XSIZE - width));
2412 sy = MAX(0, MIN(sy, WIN_YSIZE - height));
2414 if (add_border_size)
2424 static void setRequestPosition(int *x, int *y, boolean add_border_size)
2426 setRequestPositionExt(x, y, request.width, request.height, add_border_size);
2429 void DrawEnvelopeRequest(char *text)
2431 int last_game_status = game_status; /* save current game status */
2432 char *text_final = text;
2433 char *text_door_style = NULL;
2434 int graphic = IMG_BACKGROUND_REQUEST;
2435 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
2436 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
2437 int font_nr = FONT_REQUEST;
2438 int font_width = getFontWidth(font_nr);
2439 int font_height = getFontHeight(font_nr);
2440 int border_size = request.border_size;
2441 int line_spacing = request.line_spacing;
2442 int line_height = font_height + line_spacing;
2443 int max_text_width = request.width - 2 * border_size;
2444 int max_text_height = request.height - 2 * border_size;
2445 int line_length = max_text_width / font_width;
2446 int max_lines = max_text_height / line_height;
2447 int text_width = line_length * font_width;
2448 int width = request.width;
2449 int height = request.height;
2450 int tile_size = MAX(request.step_offset, 1);
2451 int x_steps = width / tile_size;
2452 int y_steps = height / tile_size;
2453 int sx_offset = border_size;
2454 int sy_offset = border_size;
2458 if (request.centered)
2459 sx_offset = (request.width - text_width) / 2;
2461 if (request.wrap_single_words && !request.autowrap)
2463 char *src_text_ptr, *dst_text_ptr;
2465 text_door_style = checked_malloc(2 * strlen(text) + 1);
2467 src_text_ptr = text;
2468 dst_text_ptr = text_door_style;
2470 while (*src_text_ptr)
2472 if (*src_text_ptr == ' ' ||
2473 *src_text_ptr == '?' ||
2474 *src_text_ptr == '!')
2475 *dst_text_ptr++ = '\n';
2477 if (*src_text_ptr != ' ')
2478 *dst_text_ptr++ = *src_text_ptr;
2483 *dst_text_ptr = '\0';
2485 text_final = text_door_style;
2488 setRequestPosition(&sx, &sy, FALSE);
2490 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
2492 for (y = 0; y < y_steps; y++)
2493 for (x = 0; x < x_steps; x++)
2494 DrawEnvelopeBackgroundTiles(graphic, sx, sy,
2495 x, y, x_steps, y_steps,
2496 tile_size, tile_size);
2498 /* force DOOR font inside door area */
2499 SetGameStatus(GAME_MODE_PSEUDO_DOOR);
2501 DrawTextBuffer(sx + sx_offset, sy + sy_offset, text_final, font_nr,
2502 line_length, -1, max_lines, line_spacing, mask_mode,
2503 request.autowrap, request.centered, FALSE);
2505 SetGameStatus(last_game_status); /* restore current game status */
2507 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
2508 RedrawGadget(tool_gadget[i]);
2510 // store readily prepared envelope request for later use when animating
2511 BlitBitmap(backbuffer, bitmap_db_cross, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2513 if (text_door_style)
2514 free(text_door_style);
2517 void AnimateEnvelopeRequest(int anim_mode, int action)
2519 int graphic = IMG_BACKGROUND_REQUEST;
2520 boolean draw_masked = graphic_info[graphic].draw_masked;
2521 int delay_value_normal = request.step_delay;
2522 int delay_value_fast = delay_value_normal / 2;
2523 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2524 boolean no_delay = (tape.warp_forward);
2525 int delay_value = (ffwd_delay ? delay_value_fast : delay_value_normal);
2526 int anim_delay_value = (no_delay ? 0 : delay_value + 500 * 0) / 2;
2527 unsigned int anim_delay = 0;
2529 int tile_size = MAX(request.step_offset, 1);
2530 int max_xsize = request.width / tile_size;
2531 int max_ysize = request.height / tile_size;
2532 int max_xsize_inner = max_xsize - 2;
2533 int max_ysize_inner = max_ysize - 2;
2535 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize_inner : 0);
2536 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize_inner : 0);
2537 int xend = max_xsize_inner;
2538 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize_inner : 0);
2539 int xstep = (xstart < xend ? 1 : 0);
2540 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
2542 int end = MAX(xend - xstart, yend - ystart);
2545 if (setup.quick_doors)
2552 for (i = start; i <= end; i++)
2554 int last_frame = end; // last frame of this "for" loop
2555 int x = xstart + i * xstep;
2556 int y = ystart + i * ystep;
2557 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
2558 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
2559 int xsize_size_left = (xsize - 1) * tile_size;
2560 int ysize_size_top = (ysize - 1) * tile_size;
2561 int max_xsize_pos = (max_xsize - 1) * tile_size;
2562 int max_ysize_pos = (max_ysize - 1) * tile_size;
2563 int width = xsize * tile_size;
2564 int height = ysize * tile_size;
2569 setRequestPosition(&src_x, &src_y, FALSE);
2570 setRequestPositionExt(&dst_x, &dst_y, width, height, FALSE);
2572 BlitBitmap(bitmap_db_store, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2574 for (yy = 0; yy < 2; yy++)
2576 for (xx = 0; xx < 2; xx++)
2578 int src_xx = src_x + xx * max_xsize_pos;
2579 int src_yy = src_y + yy * max_ysize_pos;
2580 int dst_xx = dst_x + xx * xsize_size_left;
2581 int dst_yy = dst_y + yy * ysize_size_top;
2582 int xx_size = (xx ? tile_size : xsize_size_left);
2583 int yy_size = (yy ? tile_size : ysize_size_top);
2586 BlitBitmapMasked(bitmap_db_cross, backbuffer,
2587 src_xx, src_yy, xx_size, yy_size, dst_xx, dst_yy);
2589 BlitBitmap(bitmap_db_cross, backbuffer,
2590 src_xx, src_yy, xx_size, yy_size, dst_xx, dst_yy);
2594 redraw_mask |= REDRAW_FIELD;
2599 SkipUntilDelayReached(&anim_delay, anim_delay_value, &i, last_frame);
2603 void ShowEnvelopeRequest(char *text, unsigned int req_state, int action)
2605 int graphic = IMG_BACKGROUND_REQUEST;
2606 int sound_opening = SND_REQUEST_OPENING;
2607 int sound_closing = SND_REQUEST_CLOSING;
2608 int anim_mode_1 = request.anim_mode; /* (higher priority) */
2609 int anim_mode_2 = graphic_info[graphic].anim_mode; /* (lower priority) */
2610 int anim_mode = (anim_mode_1 != ANIM_DEFAULT ? anim_mode_1 : anim_mode_2);
2611 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
2612 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
2614 if (game_status == GAME_MODE_PLAYING)
2615 BlitScreenToBitmap(backbuffer);
2617 SetDrawtoField(DRAW_BACKBUFFER);
2619 // SetDrawBackgroundMask(REDRAW_NONE);
2621 if (action == ACTION_OPENING)
2623 BlitBitmap(backbuffer, bitmap_db_store, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2625 if (req_state & REQ_ASK)
2627 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
2628 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
2630 else if (req_state & REQ_CONFIRM)
2632 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
2634 else if (req_state & REQ_PLAYER)
2636 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
2637 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
2638 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
2639 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
2642 DrawEnvelopeRequest(text);
2644 if (game_status != GAME_MODE_MAIN)
2648 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
2650 if (action == ACTION_OPENING)
2652 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
2654 if (anim_mode == ANIM_DEFAULT)
2655 AnimateEnvelopeRequest(ANIM_DEFAULT, ACTION_OPENING);
2657 AnimateEnvelopeRequest(main_anim_mode, ACTION_OPENING);
2661 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
2663 if (anim_mode != ANIM_NONE)
2664 AnimateEnvelopeRequest(main_anim_mode, ACTION_CLOSING);
2666 if (anim_mode == ANIM_DEFAULT)
2667 AnimateEnvelopeRequest(ANIM_DEFAULT, ACTION_CLOSING);
2670 game.envelope_active = FALSE;
2672 if (action == ACTION_CLOSING)
2674 if (game_status != GAME_MODE_MAIN)
2677 BlitBitmap(bitmap_db_store, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2680 // SetDrawBackgroundMask(last_draw_background_mask);
2682 redraw_mask |= REDRAW_FIELD;
2684 if (game_status == GAME_MODE_MAIN)
2689 if (action == ACTION_CLOSING &&
2690 game_status == GAME_MODE_PLAYING &&
2691 level.game_engine_type == GAME_ENGINE_TYPE_RND)
2692 SetDrawtoField(DRAW_FIELDBUFFER);
2695 void DrawPreviewElement(int dst_x, int dst_y, int element, int tilesize)
2699 int graphic = el2preimg(element);
2701 getSizedGraphicSource(graphic, 0, tilesize, &src_bitmap, &src_x, &src_y);
2702 BlitBitmap(src_bitmap, drawto, src_x, src_y, tilesize, tilesize, dst_x,dst_y);
2705 void DrawLevel(int draw_background_mask)
2709 SetMainBackgroundImage(IMG_BACKGROUND_PLAYING);
2710 SetDrawBackgroundMask(draw_background_mask);
2714 for (x = BX1; x <= BX2; x++)
2715 for (y = BY1; y <= BY2; y++)
2716 DrawScreenField(x, y);
2718 redraw_mask |= REDRAW_FIELD;
2721 void DrawSizedLevel(int size_x, int size_y, int scroll_x, int scroll_y,
2726 for (x = 0; x < size_x; x++)
2727 for (y = 0; y < size_y; y++)
2728 DrawSizedElementOrWall(x, y, scroll_x, scroll_y, tilesize);
2730 redraw_mask |= REDRAW_FIELD;
2733 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
2737 for (x = 0; x < size_x; x++)
2738 for (y = 0; y < size_y; y++)
2739 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
2741 redraw_mask |= REDRAW_FIELD;
2744 static void DrawPreviewLevelPlayfieldExt(int from_x, int from_y)
2746 boolean show_level_border = (BorderElement != EL_EMPTY);
2747 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
2748 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
2749 int tile_size = preview.tile_size;
2750 int preview_width = preview.xsize * tile_size;
2751 int preview_height = preview.ysize * tile_size;
2752 int real_preview_xsize = MIN(level_xsize, preview.xsize);
2753 int real_preview_ysize = MIN(level_ysize, preview.ysize);
2754 int real_preview_width = real_preview_xsize * tile_size;
2755 int real_preview_height = real_preview_ysize * tile_size;
2756 int dst_x = SX + ALIGNED_XPOS(preview.x, preview_width, preview.align);
2757 int dst_y = SY + ALIGNED_YPOS(preview.y, preview_height, preview.valign);
2760 if (!IN_GFX_FIELD_FULL(dst_x, dst_y + preview_height - 1))
2763 DrawBackground(dst_x, dst_y, preview_width, preview_height);
2765 dst_x += (preview_width - real_preview_width) / 2;
2766 dst_y += (preview_height - real_preview_height) / 2;
2768 for (x = 0; x < real_preview_xsize; x++)
2770 for (y = 0; y < real_preview_ysize; y++)
2772 int lx = from_x + x + (show_level_border ? -1 : 0);
2773 int ly = from_y + y + (show_level_border ? -1 : 0);
2774 int element = (IN_LEV_FIELD(lx, ly) ? level.field[lx][ly] :
2775 getBorderElement(lx, ly));
2777 DrawPreviewElement(dst_x + x * tile_size, dst_y + y * tile_size,
2778 element, tile_size);
2782 redraw_mask |= REDRAW_FIELD;
2785 #define MICROLABEL_EMPTY 0
2786 #define MICROLABEL_LEVEL_NAME 1
2787 #define MICROLABEL_LEVEL_AUTHOR_HEAD 2
2788 #define MICROLABEL_LEVEL_AUTHOR 3
2789 #define MICROLABEL_IMPORTED_FROM_HEAD 4
2790 #define MICROLABEL_IMPORTED_FROM 5
2791 #define MICROLABEL_IMPORTED_BY_HEAD 6
2792 #define MICROLABEL_IMPORTED_BY 7
2794 static int getMaxTextLength(struct TextPosInfo *pos, int font_nr)
2796 int max_text_width = SXSIZE;
2797 int font_width = getFontWidth(font_nr);
2799 if (pos->align == ALIGN_CENTER)
2800 max_text_width = (pos->x < SXSIZE / 2 ? pos->x * 2 : (SXSIZE - pos->x) * 2);
2801 else if (pos->align == ALIGN_RIGHT)
2802 max_text_width = pos->x;
2804 max_text_width = SXSIZE - pos->x;
2806 return max_text_width / font_width;
2809 static void DrawPreviewLevelLabelExt(int mode)
2811 struct TextPosInfo *pos = &menu.main.text.level_info_2;
2812 char label_text[MAX_OUTPUT_LINESIZE + 1];
2813 int max_len_label_text;
2814 int font_nr = pos->font;
2817 if (!IN_GFX_FIELD_FULL(pos->x, pos->y + getFontHeight(pos->font)))
2820 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
2821 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
2822 mode == MICROLABEL_IMPORTED_BY_HEAD)
2823 font_nr = pos->font_alt;
2825 max_len_label_text = getMaxTextLength(pos, font_nr);
2827 if (pos->size != -1)
2828 max_len_label_text = pos->size;
2830 for (i = 0; i < max_len_label_text; i++)
2831 label_text[i] = ' ';
2832 label_text[max_len_label_text] = '\0';
2834 if (strlen(label_text) > 0)
2835 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2838 (mode == MICROLABEL_LEVEL_NAME ? level.name :
2839 mode == MICROLABEL_LEVEL_AUTHOR_HEAD ? "created by" :
2840 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
2841 mode == MICROLABEL_IMPORTED_FROM_HEAD ? "imported from" :
2842 mode == MICROLABEL_IMPORTED_FROM ? leveldir_current->imported_from :
2843 mode == MICROLABEL_IMPORTED_BY_HEAD ? "imported by" :
2844 mode == MICROLABEL_IMPORTED_BY ? leveldir_current->imported_by :""),
2845 max_len_label_text);
2846 label_text[max_len_label_text] = '\0';
2848 if (strlen(label_text) > 0)
2849 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2851 redraw_mask |= REDRAW_FIELD;
2854 static void DrawPreviewLevelExt(boolean restart)
2856 static unsigned int scroll_delay = 0;
2857 static unsigned int label_delay = 0;
2858 static int from_x, from_y, scroll_direction;
2859 static int label_state, label_counter;
2860 unsigned int scroll_delay_value = preview.step_delay;
2861 boolean show_level_border = (BorderElement != EL_EMPTY);
2862 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
2863 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
2864 int last_game_status = game_status; /* save current game status */
2871 if (preview.anim_mode == ANIM_CENTERED)
2873 if (level_xsize > preview.xsize)
2874 from_x = (level_xsize - preview.xsize) / 2;
2875 if (level_ysize > preview.ysize)
2876 from_y = (level_ysize - preview.ysize) / 2;
2879 from_x += preview.xoffset;
2880 from_y += preview.yoffset;
2882 scroll_direction = MV_RIGHT;
2886 DrawPreviewLevelPlayfieldExt(from_x, from_y);
2887 DrawPreviewLevelLabelExt(label_state);
2889 /* initialize delay counters */
2890 DelayReached(&scroll_delay, 0);
2891 DelayReached(&label_delay, 0);
2893 if (leveldir_current->name)
2895 struct TextPosInfo *pos = &menu.main.text.level_info_1;
2896 char label_text[MAX_OUTPUT_LINESIZE + 1];
2897 int font_nr = pos->font;
2898 int max_len_label_text = getMaxTextLength(pos, font_nr);
2900 if (pos->size != -1)
2901 max_len_label_text = pos->size;
2903 strncpy(label_text, leveldir_current->name, max_len_label_text);
2904 label_text[max_len_label_text] = '\0';
2906 if (IN_GFX_FIELD_FULL(pos->x, pos->y + getFontHeight(pos->font)))
2907 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2910 SetGameStatus(last_game_status); /* restore current game status */
2915 /* scroll preview level, if needed */
2916 if (preview.anim_mode != ANIM_NONE &&
2917 (level_xsize > preview.xsize || level_ysize > preview.ysize) &&
2918 DelayReached(&scroll_delay, scroll_delay_value))
2920 switch (scroll_direction)
2925 from_x -= preview.step_offset;
2926 from_x = (from_x < 0 ? 0 : from_x);
2929 scroll_direction = MV_UP;
2933 if (from_x < level_xsize - preview.xsize)
2935 from_x += preview.step_offset;
2936 from_x = (from_x > level_xsize - preview.xsize ?
2937 level_xsize - preview.xsize : from_x);
2940 scroll_direction = MV_DOWN;
2946 from_y -= preview.step_offset;
2947 from_y = (from_y < 0 ? 0 : from_y);
2950 scroll_direction = MV_RIGHT;
2954 if (from_y < level_ysize - preview.ysize)
2956 from_y += preview.step_offset;
2957 from_y = (from_y > level_ysize - preview.ysize ?
2958 level_ysize - preview.ysize : from_y);
2961 scroll_direction = MV_LEFT;
2968 DrawPreviewLevelPlayfieldExt(from_x, from_y);
2971 /* !!! THIS ALL SUCKS -- SHOULD BE CLEANLY REWRITTEN !!! */
2972 /* redraw micro level label, if needed */
2973 if (!strEqual(level.name, NAMELESS_LEVEL_NAME) &&
2974 !strEqual(level.author, ANONYMOUS_NAME) &&
2975 !strEqual(level.author, leveldir_current->name) &&
2976 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
2978 int max_label_counter = 23;
2980 if (leveldir_current->imported_from != NULL &&
2981 strlen(leveldir_current->imported_from) > 0)
2982 max_label_counter += 14;
2983 if (leveldir_current->imported_by != NULL &&
2984 strlen(leveldir_current->imported_by) > 0)
2985 max_label_counter += 14;
2987 label_counter = (label_counter + 1) % max_label_counter;
2988 label_state = (label_counter >= 0 && label_counter <= 7 ?
2989 MICROLABEL_LEVEL_NAME :
2990 label_counter >= 9 && label_counter <= 12 ?
2991 MICROLABEL_LEVEL_AUTHOR_HEAD :
2992 label_counter >= 14 && label_counter <= 21 ?
2993 MICROLABEL_LEVEL_AUTHOR :
2994 label_counter >= 23 && label_counter <= 26 ?
2995 MICROLABEL_IMPORTED_FROM_HEAD :
2996 label_counter >= 28 && label_counter <= 35 ?
2997 MICROLABEL_IMPORTED_FROM :
2998 label_counter >= 37 && label_counter <= 40 ?
2999 MICROLABEL_IMPORTED_BY_HEAD :
3000 label_counter >= 42 && label_counter <= 49 ?
3001 MICROLABEL_IMPORTED_BY : MICROLABEL_EMPTY);
3003 if (leveldir_current->imported_from == NULL &&
3004 (label_state == MICROLABEL_IMPORTED_FROM_HEAD ||
3005 label_state == MICROLABEL_IMPORTED_FROM))
3006 label_state = (label_state == MICROLABEL_IMPORTED_FROM_HEAD ?
3007 MICROLABEL_IMPORTED_BY_HEAD : MICROLABEL_IMPORTED_BY);
3009 DrawPreviewLevelLabelExt(label_state);
3012 SetGameStatus(last_game_status); /* restore current game status */
3015 void DrawPreviewLevelInitial()
3017 DrawPreviewLevelExt(TRUE);
3020 void DrawPreviewLevelAnimation()
3022 DrawPreviewLevelExt(FALSE);
3025 inline static void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
3026 int graphic, int sync_frame,
3029 int frame = getGraphicAnimationFrame(graphic, sync_frame);
3031 if (mask_mode == USE_MASKING)
3032 DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
3034 DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
3037 void DrawFixedGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
3038 int graphic, int sync_frame, int mask_mode)
3040 int frame = getGraphicAnimationFrame(graphic, sync_frame);
3042 if (mask_mode == USE_MASKING)
3043 DrawFixedGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
3045 DrawFixedGraphicExt(dst_bitmap, x, y, graphic, frame);
3048 inline static void DrawGraphicAnimation(int x, int y, int graphic)
3050 int lx = LEVELX(x), ly = LEVELY(y);
3052 if (!IN_SCR_FIELD(x, y))
3055 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR,
3056 graphic, GfxFrame[lx][ly], NO_MASKING);
3058 MarkTileDirty(x, y);
3061 void DrawFixedGraphicAnimation(int x, int y, int graphic)
3063 int lx = LEVELX(x), ly = LEVELY(y);
3065 if (!IN_SCR_FIELD(x, y))
3068 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
3069 graphic, GfxFrame[lx][ly], NO_MASKING);
3070 MarkTileDirty(x, y);
3073 void DrawLevelGraphicAnimation(int x, int y, int graphic)
3075 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
3078 void DrawLevelElementAnimation(int x, int y, int element)
3080 int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
3082 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
3085 void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
3087 int sx = SCREENX(x), sy = SCREENY(y);
3089 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
3092 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
3095 DrawGraphicAnimation(sx, sy, graphic);
3098 if (GFX_CRUMBLED(TILE_GFX_ELEMENT(x, y)))
3099 DrawLevelFieldCrumbled(x, y);
3101 if (GFX_CRUMBLED(Feld[x][y]))
3102 DrawLevelFieldCrumbled(x, y);
3106 void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
3108 int sx = SCREENX(x), sy = SCREENY(y);
3111 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
3114 graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
3116 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
3119 DrawGraphicAnimation(sx, sy, graphic);
3121 if (GFX_CRUMBLED(element))
3122 DrawLevelFieldCrumbled(x, y);
3125 static int getPlayerGraphic(struct PlayerInfo *player, int move_dir)
3127 if (player->use_murphy)
3129 /* this works only because currently only one player can be "murphy" ... */
3130 static int last_horizontal_dir = MV_LEFT;
3131 int graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir);
3133 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3134 last_horizontal_dir = move_dir;
3136 if (graphic == IMG_SP_MURPHY) /* undefined => use special graphic */
3138 int direction = (player->is_snapping ? move_dir : last_horizontal_dir);
3140 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
3146 return el_act_dir2img(player->artwork_element, player->GfxAction,move_dir);
3149 static boolean equalGraphics(int graphic1, int graphic2)
3151 struct GraphicInfo *g1 = &graphic_info[graphic1];
3152 struct GraphicInfo *g2 = &graphic_info[graphic2];
3154 return (g1->bitmap == g2->bitmap &&
3155 g1->src_x == g2->src_x &&
3156 g1->src_y == g2->src_y &&
3157 g1->anim_frames == g2->anim_frames &&
3158 g1->anim_delay == g2->anim_delay &&
3159 g1->anim_mode == g2->anim_mode);
3162 void DrawAllPlayers()
3166 for (i = 0; i < MAX_PLAYERS; i++)
3167 if (stored_player[i].active)
3168 DrawPlayer(&stored_player[i]);
3171 void DrawPlayerField(int x, int y)
3173 if (!IS_PLAYER(x, y))
3176 DrawPlayer(PLAYERINFO(x, y));
3179 #define DRAW_PLAYER_OVER_PUSHED_ELEMENT 1
3181 void DrawPlayer(struct PlayerInfo *player)
3183 int jx = player->jx;
3184 int jy = player->jy;
3185 int move_dir = player->MovDir;
3186 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? +1 : 0);
3187 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? +1 : 0);
3188 int last_jx = (player->is_moving ? jx - dx : jx);
3189 int last_jy = (player->is_moving ? jy - dy : jy);
3190 int next_jx = jx + dx;
3191 int next_jy = jy + dy;
3192 boolean player_is_moving = (player->MovPos ? TRUE : FALSE);
3193 boolean player_is_opaque = FALSE;
3194 int sx = SCREENX(jx), sy = SCREENY(jy);
3195 int sxx = 0, syy = 0;
3196 int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
3198 int action = ACTION_DEFAULT;
3199 int last_player_graphic = getPlayerGraphic(player, move_dir);
3200 int last_player_frame = player->Frame;
3203 /* GfxElement[][] is set to the element the player is digging or collecting;
3204 remove also for off-screen player if the player is not moving anymore */
3205 if (IN_LEV_FIELD(jx, jy) && !player_is_moving)
3206 GfxElement[jx][jy] = EL_UNDEFINED;
3208 if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
3212 if (!IN_LEV_FIELD(jx, jy))
3214 printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
3215 printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
3216 printf("DrawPlayerField(): This should never happen!\n");
3221 if (element == EL_EXPLOSION)
3224 action = (player->is_pushing ? ACTION_PUSHING :
3225 player->is_digging ? ACTION_DIGGING :
3226 player->is_collecting ? ACTION_COLLECTING :
3227 player->is_moving ? ACTION_MOVING :
3228 player->is_snapping ? ACTION_SNAPPING :
3229 player->is_dropping ? ACTION_DROPPING :
3230 player->is_waiting ? player->action_waiting : ACTION_DEFAULT);
3232 if (player->is_waiting)
3233 move_dir = player->dir_waiting;
3235 InitPlayerGfxAnimation(player, action, move_dir);
3237 /* ----------------------------------------------------------------------- */
3238 /* draw things in the field the player is leaving, if needed */
3239 /* ----------------------------------------------------------------------- */
3241 if (player->is_moving)
3243 if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
3245 DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
3247 if (last_element == EL_DYNAMITE_ACTIVE ||
3248 last_element == EL_EM_DYNAMITE_ACTIVE ||
3249 last_element == EL_SP_DISK_RED_ACTIVE)
3250 DrawDynamite(last_jx, last_jy);
3252 DrawLevelFieldThruMask(last_jx, last_jy);
3254 else if (last_element == EL_DYNAMITE_ACTIVE ||
3255 last_element == EL_EM_DYNAMITE_ACTIVE ||
3256 last_element == EL_SP_DISK_RED_ACTIVE)
3257 DrawDynamite(last_jx, last_jy);
3259 /* !!! this is not enough to prevent flickering of players which are
3260 moving next to each others without a free tile between them -- this
3261 can only be solved by drawing all players layer by layer (first the
3262 background, then the foreground etc.) !!! => TODO */
3263 else if (!IS_PLAYER(last_jx, last_jy))
3264 DrawLevelField(last_jx, last_jy);
3267 DrawLevelField(last_jx, last_jy);
3270 if (player->is_pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
3271 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
3274 if (!IN_SCR_FIELD(sx, sy))
3277 /* ----------------------------------------------------------------------- */
3278 /* draw things behind the player, if needed */
3279 /* ----------------------------------------------------------------------- */
3282 DrawLevelElement(jx, jy, Back[jx][jy]);
3283 else if (IS_ACTIVE_BOMB(element))
3284 DrawLevelElement(jx, jy, EL_EMPTY);
3287 if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
3289 int old_element = GfxElement[jx][jy];
3290 int old_graphic = el_act_dir2img(old_element, action, move_dir);
3291 int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
3293 if (GFX_CRUMBLED(old_element))
3294 DrawLevelFieldCrumbledDigging(jx, jy, move_dir, player->StepFrame);
3296 DrawGraphic(sx, sy, old_graphic, frame);
3298 if (graphic_info[old_graphic].anim_mode & ANIM_OPAQUE_PLAYER)
3299 player_is_opaque = TRUE;
3303 GfxElement[jx][jy] = EL_UNDEFINED;
3305 /* make sure that pushed elements are drawn with correct frame rate */
3306 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
3308 if (player->is_pushing && player->is_moving && !IS_ANIM_MODE_CE(graphic))
3309 GfxFrame[jx][jy] = player->StepFrame;
3311 DrawLevelField(jx, jy);
3315 #if !DRAW_PLAYER_OVER_PUSHED_ELEMENT
3316 /* ----------------------------------------------------------------------- */
3317 /* draw player himself */
3318 /* ----------------------------------------------------------------------- */
3320 graphic = getPlayerGraphic(player, move_dir);
3322 /* in the case of changed player action or direction, prevent the current
3323 animation frame from being restarted for identical animations */
3324 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
3325 player->Frame = last_player_frame;
3327 frame = getGraphicAnimationFrame(graphic, player->Frame);
3331 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3332 sxx = player->GfxPos;
3334 syy = player->GfxPos;
3337 if (player_is_opaque)
3338 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
3340 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3342 if (SHIELD_ON(player))
3344 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
3345 IMG_SHIELD_NORMAL_ACTIVE);
3346 int frame = getGraphicAnimationFrame(graphic, -1);
3348 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3352 #if DRAW_PLAYER_OVER_PUSHED_ELEMENT
3355 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3356 sxx = player->GfxPos;
3358 syy = player->GfxPos;
3362 /* ----------------------------------------------------------------------- */
3363 /* draw things the player is pushing, if needed */
3364 /* ----------------------------------------------------------------------- */
3366 if (player->is_pushing && player->is_moving)
3368 int px = SCREENX(jx), py = SCREENY(jy);
3369 int pxx = (TILEX - ABS(sxx)) * dx;
3370 int pyy = (TILEY - ABS(syy)) * dy;
3371 int gfx_frame = GfxFrame[jx][jy];
3377 if (!IS_MOVING(jx, jy)) /* push movement already finished */
3379 element = Feld[next_jx][next_jy];
3380 gfx_frame = GfxFrame[next_jx][next_jy];
3383 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
3385 sync_frame = (IS_ANIM_MODE_CE(graphic) ? gfx_frame : player->StepFrame);
3386 frame = getGraphicAnimationFrame(graphic, sync_frame);
3388 /* draw background element under pushed element (like the Sokoban field) */
3389 if (game.use_masked_pushing && IS_MOVING(jx, jy))
3391 /* this allows transparent pushing animation over non-black background */
3394 DrawLevelElement(jx, jy, Back[jx][jy]);
3396 DrawLevelElement(jx, jy, EL_EMPTY);
3398 if (Back[next_jx][next_jy])
3399 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
3401 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
3403 else if (Back[next_jx][next_jy])
3404 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
3407 /* do not draw (EM style) pushing animation when pushing is finished */
3408 /* (two-tile animations usually do not contain start and end frame) */
3409 if (graphic_info[graphic].double_movement && !IS_MOVING(jx, jy))
3410 DrawLevelElement(next_jx, next_jy, Feld[next_jx][next_jy]);
3412 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
3414 /* masked drawing is needed for EMC style (double) movement graphics */
3415 /* !!! (ONLY WHEN DRAWING PUSHED ELEMENT OVER THE PLAYER) !!! */
3416 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
3420 #if DRAW_PLAYER_OVER_PUSHED_ELEMENT
3421 /* ----------------------------------------------------------------------- */
3422 /* draw player himself */
3423 /* ----------------------------------------------------------------------- */
3425 graphic = getPlayerGraphic(player, move_dir);
3427 /* in the case of changed player action or direction, prevent the current
3428 animation frame from being restarted for identical animations */
3429 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
3430 player->Frame = last_player_frame;
3432 frame = getGraphicAnimationFrame(graphic, player->Frame);
3436 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3437 sxx = player->GfxPos;
3439 syy = player->GfxPos;
3442 if (player_is_opaque)
3443 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
3445 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3447 if (SHIELD_ON(player))
3449 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
3450 IMG_SHIELD_NORMAL_ACTIVE);
3451 int frame = getGraphicAnimationFrame(graphic, -1);
3453 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3457 /* ----------------------------------------------------------------------- */
3458 /* draw things in front of player (active dynamite or dynabombs) */
3459 /* ----------------------------------------------------------------------- */
3461 if (IS_ACTIVE_BOMB(element))
3463 graphic = el2img(element);
3464 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
3466 if (game.emulation == EMU_SUPAPLEX)
3467 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
3469 DrawGraphicThruMask(sx, sy, graphic, frame);
3472 if (player_is_moving && last_element == EL_EXPLOSION)
3474 int element = (GfxElement[last_jx][last_jy] != EL_UNDEFINED ?
3475 GfxElement[last_jx][last_jy] : EL_EMPTY);
3476 int graphic = el_act2img(element, ACTION_EXPLODING);
3477 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
3478 int phase = ExplodePhase[last_jx][last_jy] - 1;
3479 int frame = getGraphicAnimationFrame(graphic, phase - delay);
3482 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
3485 /* ----------------------------------------------------------------------- */
3486 /* draw elements the player is just walking/passing through/under */
3487 /* ----------------------------------------------------------------------- */
3489 if (player_is_moving)
3491 /* handle the field the player is leaving ... */
3492 if (IS_ACCESSIBLE_INSIDE(last_element))
3493 DrawLevelField(last_jx, last_jy);
3494 else if (IS_ACCESSIBLE_UNDER(last_element))
3495 DrawLevelFieldThruMask(last_jx, last_jy);
3498 /* do not redraw accessible elements if the player is just pushing them */
3499 if (!player_is_moving || !player->is_pushing)
3501 /* ... and the field the player is entering */
3502 if (IS_ACCESSIBLE_INSIDE(element))
3503 DrawLevelField(jx, jy);
3504 else if (IS_ACCESSIBLE_UNDER(element))
3505 DrawLevelFieldThruMask(jx, jy);
3508 MarkTileDirty(sx, sy);
3511 /* ------------------------------------------------------------------------- */
3513 void WaitForEventToContinue()
3515 boolean still_wait = TRUE;
3517 /* simulate releasing mouse button over last gadget, if still pressed */
3519 HandleGadgets(-1, -1, 0);
3521 button_status = MB_RELEASED;
3535 case EVENT_BUTTONPRESS:
3536 case EVENT_KEYPRESS:
3540 case EVENT_KEYRELEASE:
3541 ClearPlayerAction();
3545 HandleOtherEvents(&event);
3549 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
3556 WaitUntilDelayReached(&sync_frame_delay, sync_frame_delay_value);
3560 #define MAX_REQUEST_LINES 13
3561 #define MAX_REQUEST_LINE_FONT1_LEN 7
3562 #define MAX_REQUEST_LINE_FONT2_LEN 10
3564 static int RequestHandleEvents(unsigned int req_state)
3566 boolean level_solved = (game_status == GAME_MODE_PLAYING &&
3567 local_player->LevelSolved_GameEnd);
3568 int width = request.width;
3569 int height = request.height;
3573 setRequestPosition(&sx, &sy, FALSE);
3575 button_status = MB_RELEASED;
3577 request_gadget_id = -1;
3584 SetDrawtoField(DRAW_FIELDBUFFER);
3586 HandleGameActions();
3588 SetDrawtoField(DRAW_BACKBUFFER);
3590 if (global.use_envelope_request)
3592 /* copy current state of request area to middle of playfield area */
3593 BlitBitmap(bitmap_db_cross, drawto, sx, sy, width, height, sx, sy);
3601 while (NextValidEvent(&event))
3605 case EVENT_BUTTONPRESS:
3606 case EVENT_BUTTONRELEASE:
3607 case EVENT_MOTIONNOTIFY:
3611 if (event.type == EVENT_MOTIONNOTIFY)
3616 motion_status = TRUE;
3617 mx = ((MotionEvent *) &event)->x;
3618 my = ((MotionEvent *) &event)->y;
3622 motion_status = FALSE;
3623 mx = ((ButtonEvent *) &event)->x;
3624 my = ((ButtonEvent *) &event)->y;
3625 if (event.type == EVENT_BUTTONPRESS)
3626 button_status = ((ButtonEvent *) &event)->button;
3628 button_status = MB_RELEASED;
3631 /* this sets 'request_gadget_id' */
3632 HandleGadgets(mx, my, button_status);
3634 switch (request_gadget_id)
3636 case TOOL_CTRL_ID_YES:
3639 case TOOL_CTRL_ID_NO:
3642 case TOOL_CTRL_ID_CONFIRM:
3643 result = TRUE | FALSE;
3646 case TOOL_CTRL_ID_PLAYER_1:
3649 case TOOL_CTRL_ID_PLAYER_2:
3652 case TOOL_CTRL_ID_PLAYER_3:
3655 case TOOL_CTRL_ID_PLAYER_4:
3666 case EVENT_KEYPRESS:
3667 switch (GetEventKey((KeyEvent *)&event, TRUE))
3670 if (req_state & REQ_CONFIRM)
3675 #if defined(TARGET_SDL2)
3682 #if defined(TARGET_SDL2)
3692 if (req_state & REQ_PLAYER)
3696 case EVENT_KEYRELEASE:
3697 ClearPlayerAction();
3701 HandleOtherEvents(&event);
3706 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
3708 int joy = AnyJoystick();
3710 if (joy & JOY_BUTTON_1)
3712 else if (joy & JOY_BUTTON_2)
3718 if (global.use_envelope_request)
3720 /* copy back current state of pressed buttons inside request area */
3721 BlitBitmap(drawto, bitmap_db_cross, sx, sy, width, height, sx, sy);
3731 WaitUntilDelayReached(&sync_frame_delay, sync_frame_delay_value);
3737 static boolean RequestDoor(char *text, unsigned int req_state)
3739 unsigned int old_door_state;
3740 int last_game_status = game_status; /* save current game status */
3741 int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
3742 int font_nr = FONT_TEXT_2;
3747 if (maxWordLengthInString(text) > MAX_REQUEST_LINE_FONT1_LEN)
3749 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
3750 font_nr = FONT_TEXT_1;
3753 if (game_status == GAME_MODE_PLAYING)
3754 BlitScreenToBitmap(backbuffer);
3756 /* disable deactivated drawing when quick-loading level tape recording */
3757 if (tape.playing && tape.deactivate_display)
3758 TapeDeactivateDisplayOff(TRUE);
3760 SetMouseCursor(CURSOR_DEFAULT);
3762 #if defined(NETWORK_AVALIABLE)
3763 /* pause network game while waiting for request to answer */
3764 if (options.network &&
3765 game_status == GAME_MODE_PLAYING &&
3766 req_state & REQUEST_WAIT_FOR_INPUT)
3767 SendToServer_PausePlaying();
3770 old_door_state = GetDoorState();
3772 /* simulate releasing mouse button over last gadget, if still pressed */
3774 HandleGadgets(-1, -1, 0);
3778 /* draw released gadget before proceeding */
3781 if (old_door_state & DOOR_OPEN_1)
3783 CloseDoor(DOOR_CLOSE_1);
3785 /* save old door content */
3786 BlitBitmap(bitmap_db_door_1, bitmap_db_door_1,
3787 0 * DXSIZE, 0, DXSIZE, DYSIZE, 1 * DXSIZE, 0);
3790 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
3791 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3793 /* clear door drawing field */
3794 DrawBackground(DX, DY, DXSIZE, DYSIZE);
3796 /* force DOOR font inside door area */
3797 SetGameStatus(GAME_MODE_PSEUDO_DOOR);
3799 /* write text for request */
3800 for (text_ptr = text, ty = 0; ty < MAX_REQUEST_LINES; ty++)
3802 char text_line[max_request_line_len + 1];
3808 for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
3810 tc = *(text_ptr + tx);
3811 // if (!tc || tc == ' ')
3812 if (!tc || tc == ' ' || tc == '?' || tc == '!')
3816 if ((tc == '?' || tc == '!') && tl == 0)
3826 strncpy(text_line, text_ptr, tl);
3829 DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
3830 DY + 8 + ty * (getFontHeight(font_nr) + 2),
3831 text_line, font_nr);
3833 text_ptr += tl + (tc == ' ' ? 1 : 0);
3834 // text_ptr += tl + (tc == ' ' || tc == '?' || tc == '!' ? 1 : 0);
3837 SetGameStatus(last_game_status); /* restore current game status */
3839 if (req_state & REQ_ASK)
3841 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
3842 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
3844 else if (req_state & REQ_CONFIRM)
3846 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
3848 else if (req_state & REQ_PLAYER)
3850 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
3851 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
3852 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
3853 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
3856 /* copy request gadgets to door backbuffer */
3857 BlitBitmap(drawto, bitmap_db_door_1, DX, DY, DXSIZE, DYSIZE, 0, 0);
3859 OpenDoor(DOOR_OPEN_1);
3861 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
3863 if (game_status == GAME_MODE_PLAYING)
3865 SetPanelBackground();
3866 SetDrawBackgroundMask(REDRAW_DOOR_1);
3870 SetDrawBackgroundMask(REDRAW_FIELD);
3876 if (game_status != GAME_MODE_MAIN)
3879 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3881 // ---------- handle request buttons ----------
3882 result = RequestHandleEvents(req_state);
3884 if (game_status != GAME_MODE_MAIN)
3889 if (!(req_state & REQ_STAY_OPEN))
3891 CloseDoor(DOOR_CLOSE_1);
3893 if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
3894 (req_state & REQ_REOPEN))
3895 OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
3900 if (game_status == GAME_MODE_PLAYING)
3902 SetPanelBackground();
3903 SetDrawBackgroundMask(REDRAW_DOOR_1);
3907 SetDrawBackgroundMask(REDRAW_FIELD);
3910 #if defined(NETWORK_AVALIABLE)
3911 /* continue network game after request */
3912 if (options.network &&
3913 game_status == GAME_MODE_PLAYING &&
3914 req_state & REQUEST_WAIT_FOR_INPUT)
3915 SendToServer_ContinuePlaying();
3918 /* restore deactivated drawing when quick-loading level tape recording */
3919 if (tape.playing && tape.deactivate_display)
3920 TapeDeactivateDisplayOn();
3925 static boolean RequestEnvelope(char *text, unsigned int req_state)
3929 if (game_status == GAME_MODE_PLAYING)
3930 BlitScreenToBitmap(backbuffer);
3932 /* disable deactivated drawing when quick-loading level tape recording */
3933 if (tape.playing && tape.deactivate_display)
3934 TapeDeactivateDisplayOff(TRUE);
3936 SetMouseCursor(CURSOR_DEFAULT);
3938 #if defined(NETWORK_AVALIABLE)
3939 /* pause network game while waiting for request to answer */
3940 if (options.network &&
3941 game_status == GAME_MODE_PLAYING &&
3942 req_state & REQUEST_WAIT_FOR_INPUT)
3943 SendToServer_PausePlaying();
3946 /* simulate releasing mouse button over last gadget, if still pressed */
3948 HandleGadgets(-1, -1, 0);
3952 // (replace with setting corresponding request background)
3953 // SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
3954 // SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3956 /* clear door drawing field */
3957 // DrawBackground(DX, DY, DXSIZE, DYSIZE);
3959 ShowEnvelopeRequest(text, req_state, ACTION_OPENING);
3961 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
3963 if (game_status == GAME_MODE_PLAYING)
3965 SetPanelBackground();
3966 SetDrawBackgroundMask(REDRAW_DOOR_1);
3970 SetDrawBackgroundMask(REDRAW_FIELD);
3976 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3978 // ---------- handle request buttons ----------
3979 result = RequestHandleEvents(req_state);
3981 if (game_status != GAME_MODE_MAIN)
3986 ShowEnvelopeRequest(text, req_state, ACTION_CLOSING);
3990 if (game_status == GAME_MODE_PLAYING)
3992 SetPanelBackground();
3993 SetDrawBackgroundMask(REDRAW_DOOR_1);
3997 SetDrawBackgroundMask(REDRAW_FIELD);
4000 #if defined(NETWORK_AVALIABLE)
4001 /* continue network game after request */
4002 if (options.network &&
4003 game_status == GAME_MODE_PLAYING &&
4004 req_state & REQUEST_WAIT_FOR_INPUT)
4005 SendToServer_ContinuePlaying();
4008 /* restore deactivated drawing when quick-loading level tape recording */
4009 if (tape.playing && tape.deactivate_display)
4010 TapeDeactivateDisplayOn();
4015 boolean Request(char *text, unsigned int req_state)
4017 if (global.use_envelope_request)
4018 return RequestEnvelope(text, req_state);
4020 return RequestDoor(text, req_state);
4023 static int compareDoorPartOrderInfo(const void *object1, const void *object2)
4025 const struct DoorPartOrderInfo *dpo1 = (struct DoorPartOrderInfo *)object1;
4026 const struct DoorPartOrderInfo *dpo2 = (struct DoorPartOrderInfo *)object2;
4029 if (dpo1->sort_priority != dpo2->sort_priority)
4030 compare_result = dpo1->sort_priority - dpo2->sort_priority;
4032 compare_result = dpo1->nr - dpo2->nr;
4034 return compare_result;
4037 void InitGraphicCompatibilityInfo_Doors()
4043 struct DoorInfo *door;
4047 { DOOR_1, IMG_DOOR_1_GFX_PART_1, IMG_DOOR_1_GFX_PART_8, &door_1 },
4048 { DOOR_2, IMG_DOOR_2_GFX_PART_1, IMG_DOOR_2_GFX_PART_8, &door_2 },
4050 { -1, -1, -1, NULL }
4052 struct Rect door_rect_list[] =
4054 { DX, DY, DXSIZE, DYSIZE },
4055 { VX, VY, VXSIZE, VYSIZE }
4059 for (i = 0; doors[i].door_token != -1; i++)
4061 int door_token = doors[i].door_token;
4062 int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
4063 int part_1 = doors[i].part_1;
4064 int part_8 = doors[i].part_8;
4065 int part_2 = part_1 + 1;
4066 int part_3 = part_1 + 2;
4067 struct DoorInfo *door = doors[i].door;
4068 struct Rect *door_rect = &door_rect_list[door_index];
4069 boolean door_gfx_redefined = FALSE;
4071 /* check if any door part graphic definitions have been redefined */
4073 for (j = 0; door_part_controls[j].door_token != -1; j++)
4075 struct DoorPartControlInfo *dpc = &door_part_controls[j];
4076 struct FileInfo *fi = getImageListEntryFromImageID(dpc->graphic);
4078 if (dpc->door_token == door_token && fi->redefined)
4079 door_gfx_redefined = TRUE;
4082 /* check for old-style door graphic/animation modifications */
4084 if (!door_gfx_redefined)
4086 if (door->anim_mode & ANIM_STATIC_PANEL)
4088 door->panel.step_xoffset = 0;
4089 door->panel.step_yoffset = 0;
4092 if (door->anim_mode & (ANIM_HORIZONTAL | ANIM_VERTICAL))
4094 struct GraphicInfo *g_part_1 = &graphic_info[part_1];
4095 struct GraphicInfo *g_part_2 = &graphic_info[part_2];
4096 int num_door_steps, num_panel_steps;
4098 /* remove door part graphics other than the two default wings */
4100 for (j = 0; door_part_controls[j].door_token != -1; j++)
4102 struct DoorPartControlInfo *dpc = &door_part_controls[j];
4103 struct GraphicInfo *g = &graphic_info[dpc->graphic];
4105 if (dpc->graphic >= part_3 &&
4106 dpc->graphic <= part_8)
4110 /* set graphics and screen positions of the default wings */
4112 g_part_1->width = door_rect->width;
4113 g_part_1->height = door_rect->height;
4114 g_part_2->width = door_rect->width;
4115 g_part_2->height = door_rect->height;
4116 g_part_2->src_x = door_rect->width;
4117 g_part_2->src_y = g_part_1->src_y;
4119 door->part_2.x = door->part_1.x;
4120 door->part_2.y = door->part_1.y;
4122 if (door->width != -1)
4124 g_part_1->width = door->width;
4125 g_part_2->width = door->width;
4127 // special treatment for graphics and screen position of right wing
4128 g_part_2->src_x += door_rect->width - door->width;
4129 door->part_2.x += door_rect->width - door->width;
4132 if (door->height != -1)
4134 g_part_1->height = door->height;
4135 g_part_2->height = door->height;
4137 // special treatment for graphics and screen position of bottom wing
4138 g_part_2->src_y += door_rect->height - door->height;
4139 door->part_2.y += door_rect->height - door->height;
4142 /* set animation delays for the default wings and panels */
4144 door->part_1.step_delay = door->step_delay;
4145 door->part_2.step_delay = door->step_delay;
4146 door->panel.step_delay = door->step_delay;
4148 /* set animation draw order for the default wings */
4150 door->part_1.sort_priority = 2; /* draw left wing over ... */
4151 door->part_2.sort_priority = 1; /* ... right wing */
4153 /* set animation draw offset for the default wings */
4155 if (door->anim_mode & ANIM_HORIZONTAL)
4157 door->part_1.step_xoffset = door->step_offset;
4158 door->part_1.step_yoffset = 0;
4159 door->part_2.step_xoffset = door->step_offset * -1;
4160 door->part_2.step_yoffset = 0;
4162 num_door_steps = g_part_1->width / door->step_offset;
4164 else // ANIM_VERTICAL
4166 door->part_1.step_xoffset = 0;
4167 door->part_1.step_yoffset = door->step_offset;
4168 door->part_2.step_xoffset = 0;
4169 door->part_2.step_yoffset = door->step_offset * -1;
4171 num_door_steps = g_part_1->height / door->step_offset;
4174 /* set animation draw offset for the default panels */
4176 if (door->step_offset > 1)
4178 num_panel_steps = 2 * door_rect->height / door->step_offset;
4179 door->panel.start_step = num_panel_steps - num_door_steps;
4180 door->panel.start_step_closing = door->panel.start_step;
4184 num_panel_steps = door_rect->height / door->step_offset;
4185 door->panel.start_step = num_panel_steps - num_door_steps / 2;
4186 door->panel.start_step_closing = door->panel.start_step;
4187 door->panel.step_delay *= 2;
4198 for (i = 0; door_part_controls[i].door_token != -1; i++)
4200 struct DoorPartControlInfo *dpc = &door_part_controls[i];
4201 struct DoorPartOrderInfo *dpo = &door_part_order[i];
4203 /* initialize "start_step_opening" and "start_step_closing", if needed */
4204 if (dpc->pos->start_step_opening == 0 &&
4205 dpc->pos->start_step_closing == 0)
4207 // dpc->pos->start_step_opening = dpc->pos->start_step;
4208 dpc->pos->start_step_closing = dpc->pos->start_step;
4211 /* fill structure for door part draw order (sorted below) */
4213 dpo->sort_priority = dpc->pos->sort_priority;
4216 /* sort door part controls according to sort_priority and graphic number */
4217 qsort(door_part_order, MAX_DOOR_PARTS,
4218 sizeof(struct DoorPartOrderInfo), compareDoorPartOrderInfo);
4221 unsigned int OpenDoor(unsigned int door_state)
4223 if (door_state & DOOR_COPY_BACK)
4225 if (door_state & DOOR_OPEN_1)
4226 BlitBitmap(bitmap_db_door_1, bitmap_db_door_1,
4227 1 * DXSIZE, 0, DXSIZE, DYSIZE, 0 * DXSIZE, 0);
4229 if (door_state & DOOR_OPEN_2)
4230 BlitBitmap(bitmap_db_door_2, bitmap_db_door_2,
4231 1 * VXSIZE, 0, VXSIZE, VYSIZE, 0 * VXSIZE, 0);
4233 door_state &= ~DOOR_COPY_BACK;
4236 return MoveDoor(door_state);
4239 unsigned int CloseDoor(unsigned int door_state)
4241 unsigned int old_door_state = GetDoorState();
4243 if (!(door_state & DOOR_NO_COPY_BACK))
4245 if (old_door_state & DOOR_OPEN_1)
4246 BlitBitmap(backbuffer, bitmap_db_door_1,
4247 DX, DY, DXSIZE, DYSIZE, 0, 0);
4249 if (old_door_state & DOOR_OPEN_2)
4250 BlitBitmap(backbuffer, bitmap_db_door_2,
4251 VX, VY, VXSIZE, VYSIZE, 0, 0);
4253 door_state &= ~DOOR_NO_COPY_BACK;
4256 return MoveDoor(door_state);
4259 unsigned int GetDoorState()
4261 return MoveDoor(DOOR_GET_STATE);
4264 unsigned int SetDoorState(unsigned int door_state)
4266 return MoveDoor(door_state | DOOR_SET_STATE);
4269 int euclid(int a, int b)
4271 return (b ? euclid(b, a % b) : a);
4274 unsigned int MoveDoor(unsigned int door_state)
4276 struct Rect door_rect_list[] =
4278 { DX, DY, DXSIZE, DYSIZE },
4279 { VX, VY, VXSIZE, VYSIZE }
4281 static int door1 = DOOR_CLOSE_1;
4282 static int door2 = DOOR_CLOSE_2;
4283 unsigned int door_delay = 0;
4284 unsigned int door_delay_value;
4287 if (door_state == DOOR_GET_STATE)
4288 return (door1 | door2);
4290 if (door_state & DOOR_SET_STATE)
4292 if (door_state & DOOR_ACTION_1)
4293 door1 = door_state & DOOR_ACTION_1;
4294 if (door_state & DOOR_ACTION_2)
4295 door2 = door_state & DOOR_ACTION_2;
4297 return (door1 | door2);
4300 if (!(door_state & DOOR_FORCE_REDRAW))
4302 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
4303 door_state &= ~DOOR_OPEN_1;
4304 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
4305 door_state &= ~DOOR_CLOSE_1;
4306 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
4307 door_state &= ~DOOR_OPEN_2;
4308 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
4309 door_state &= ~DOOR_CLOSE_2;
4312 if (global.autoplay_leveldir)
4314 door_state |= DOOR_NO_DELAY;
4315 door_state &= ~DOOR_CLOSE_ALL;
4318 if (game_status == GAME_MODE_EDITOR)
4319 door_state |= DOOR_NO_DELAY;
4321 if (door_state & DOOR_ACTION)
4323 boolean door_panel_drawn[NUM_DOORS];
4324 boolean panel_has_doors[NUM_DOORS];
4325 boolean door_part_skip[MAX_DOOR_PARTS];
4326 boolean door_part_done[MAX_DOOR_PARTS];
4327 boolean door_part_done_all;
4328 int num_steps[MAX_DOOR_PARTS];
4329 int max_move_delay = 0; // delay for complete animations of all doors
4330 int max_step_delay = 0; // delay (ms) between two animation frames
4331 int num_move_steps = 0; // number of animation steps for all doors
4332 int max_move_delay_doors_only = 0; // delay for doors only (no panel)
4333 int num_move_steps_doors_only = 0; // steps for doors only (no panel)
4334 int current_move_delay = 0;
4338 for (i = 0; i < NUM_DOORS; i++)
4339 panel_has_doors[i] = FALSE;
4341 for (i = 0; i < MAX_DOOR_PARTS; i++)
4343 struct DoorPartControlInfo *dpc = &door_part_controls[i];
4344 struct GraphicInfo *g = &graphic_info[dpc->graphic];
4345 int door_token = dpc->door_token;
4347 door_part_done[i] = FALSE;
4348 door_part_skip[i] = (!(door_state & door_token) ||
4352 for (i = 0; i < MAX_DOOR_PARTS; i++)
4354 int nr = door_part_order[i].nr;
4355 struct DoorPartControlInfo *dpc = &door_part_controls[nr];
4356 struct DoorPartPosInfo *pos = dpc->pos;
4357 struct GraphicInfo *g = &graphic_info[dpc->graphic];
4358 int door_token = dpc->door_token;
4359 int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
4360 boolean is_panel = DOOR_PART_IS_PANEL(nr);
4361 int step_xoffset = ABS(pos->step_xoffset);
4362 int step_yoffset = ABS(pos->step_yoffset);
4363 int step_delay = pos->step_delay;
4364 int current_door_state = door_state & door_token;
4365 boolean door_opening = ((current_door_state & DOOR_OPEN) != 0);
4366 boolean door_closing = ((current_door_state & DOOR_CLOSE) != 0);
4367 boolean part_opening = (is_panel ? door_closing : door_opening);
4368 int start_step = (part_opening ? pos->start_step_opening :
4369 pos->start_step_closing);
4370 float move_xsize = (step_xoffset ? g->width : 0);
4371 float move_ysize = (step_yoffset ? g->height : 0);
4372 int move_xsteps = (step_xoffset ? ceil(move_xsize / step_xoffset) : 0);
4373 int move_ysteps = (step_yoffset ? ceil(move_ysize / step_yoffset) : 0);
4374 int move_steps = (move_xsteps && move_ysteps ?
4375 MIN(move_xsteps, move_ysteps) :
4376 move_xsteps ? move_xsteps : move_ysteps) - start_step;
4377 int move_delay = move_steps * step_delay;
4379 if (door_part_skip[nr])
4382 max_move_delay = MAX(max_move_delay, move_delay);
4383 max_step_delay = (max_step_delay == 0 ? step_delay :
4384 euclid(max_step_delay, step_delay));
4385 num_steps[nr] = move_steps;
4389 max_move_delay_doors_only = MAX(max_move_delay_doors_only, move_delay);
4391 panel_has_doors[door_index] = TRUE;
4395 max_step_delay = MAX(1, max_step_delay); // prevent division by zero
4397 num_move_steps = max_move_delay / max_step_delay;
4398 num_move_steps_doors_only = max_move_delay_doors_only / max_step_delay;
4400 door_delay_value = max_step_delay;
4402 if ((door_state & DOOR_NO_DELAY) || setup.quick_doors)
4404 start = num_move_steps - 1;
4408 /* opening door sound has priority over simultaneously closing door */
4409 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
4410 PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
4411 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
4412 PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
4415 for (k = start; k < num_move_steps; k++)
4417 int last_frame = num_move_steps - 1; // last frame of this "for" loop
4419 door_part_done_all = TRUE;
4421 for (i = 0; i < NUM_DOORS; i++)
4422 door_panel_drawn[i] = FALSE;
4424 for (i = 0; i < MAX_DOOR_PARTS; i++)
4426 int nr = door_part_order[i].nr;
4427 struct DoorPartControlInfo *dpc = &door_part_controls[nr];
4428 struct DoorPartPosInfo *pos = dpc->pos;
4429 struct GraphicInfo *g = &graphic_info[dpc->graphic];
4430 int door_token = dpc->door_token;
4431 int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
4432 boolean is_panel = DOOR_PART_IS_PANEL(nr);
4433 boolean is_panel_and_door_has_closed = FALSE;
4434 struct Rect *door_rect = &door_rect_list[door_index];
4435 Bitmap *bitmap_db_door = (door_token == DOOR_1 ? bitmap_db_door_1 :
4437 Bitmap *bitmap = (is_panel ? bitmap_db_door : g->bitmap);
4438 int current_door_state = door_state & door_token;
4439 boolean door_opening = ((current_door_state & DOOR_OPEN) != 0);
4440 boolean door_closing = !door_opening;
4441 boolean part_opening = (is_panel ? door_closing : door_opening);
4442 boolean part_closing = !part_opening;
4443 int start_step = (part_opening ? pos->start_step_opening :
4444 pos->start_step_closing);
4445 int step_delay = pos->step_delay;
4446 int step_factor = step_delay / max_step_delay;
4447 int k1 = (step_factor ? k / step_factor + 1 : k);
4448 int k2 = (part_opening ? k1 + start_step : num_steps[nr] - k1);
4449 int kk = MAX(0, k2);
4452 int src_x, src_y, src_xx, src_yy;
4453 int dst_x, dst_y, dst_xx, dst_yy;
4456 if (door_part_skip[nr])
4459 if (!(door_state & door_token))
4467 int k2_door = (door_opening ? k : num_move_steps_doors_only - k - 1);
4468 int kk_door = MAX(0, k2_door);
4469 int sync_frame = kk_door * door_delay_value;
4470 int frame = getGraphicAnimationFrame(dpc->graphic, sync_frame);
4472 getGraphicSource(dpc->graphic, frame, &bitmap, &g_src_x, &g_src_y);
4477 if (!door_panel_drawn[door_index])
4479 ClearRectangle(drawto, door_rect->x, door_rect->y,
4480 door_rect->width, door_rect->height);
4482 door_panel_drawn[door_index] = TRUE;
4485 // draw opening or closing door parts
4487 if (pos->step_xoffset < 0) // door part on right side
4490 dst_xx = pos->x + ABS(kk * pos->step_xoffset);
4493 if (dst_xx + width > door_rect->width)
4494 width = door_rect->width - dst_xx;
4496 else // door part on left side
4499 dst_xx = pos->x - kk * pos->step_xoffset;
4503 src_xx = ABS(dst_xx);
4507 width = g->width - src_xx;
4509 if (width > door_rect->width)
4510 width = door_rect->width;
4512 // printf("::: k == %d [%d] \n", k, start_step);
4515 if (pos->step_yoffset < 0) // door part on bottom side
4518 dst_yy = pos->y + ABS(kk * pos->step_yoffset);
4521 if (dst_yy + height > door_rect->height)
4522 height = door_rect->height - dst_yy;
4524 else // door part on top side
4527 dst_yy = pos->y - kk * pos->step_yoffset;
4531 src_yy = ABS(dst_yy);
4535 height = g->height - src_yy;
4538 src_x = g_src_x + src_xx;
4539 src_y = g_src_y + src_yy;
4541 dst_x = door_rect->x + dst_xx;
4542 dst_y = door_rect->y + dst_yy;
4544 is_panel_and_door_has_closed =
4547 panel_has_doors[door_index] &&
4548 k >= num_move_steps_doors_only - 1);
4550 if (width >= 0 && width <= g->width &&
4551 height >= 0 && height <= g->height &&
4552 !is_panel_and_door_has_closed)
4554 if (is_panel || !pos->draw_masked)
4555 BlitBitmap(bitmap, drawto, src_x, src_y, width, height,
4558 BlitBitmapMasked(bitmap, drawto, src_x, src_y, width, height,
4562 redraw_mask |= REDRAW_DOOR_FROM_TOKEN(door_token);
4564 if ((part_opening && (width < 0 || height < 0)) ||
4565 (part_closing && (width >= g->width && height >= g->height)))
4566 door_part_done[nr] = TRUE;
4568 // continue door part animations, but not panel after door has closed
4569 if (!door_part_done[nr] && !is_panel_and_door_has_closed)
4570 door_part_done_all = FALSE;
4573 if (!(door_state & DOOR_NO_DELAY))
4577 if (game_status == GAME_MODE_MAIN)
4580 SkipUntilDelayReached(&door_delay, door_delay_value, &k, last_frame);
4582 current_move_delay += max_step_delay;
4585 if (door_part_done_all)
4590 if (door_state & DOOR_ACTION_1)
4591 door1 = door_state & DOOR_ACTION_1;
4592 if (door_state & DOOR_ACTION_2)
4593 door2 = door_state & DOOR_ACTION_2;
4595 // draw masked border over door area
4596 DrawMaskedBorder(REDRAW_DOOR_1);
4597 DrawMaskedBorder(REDRAW_DOOR_2);
4599 return (door1 | door2);
4602 static boolean useSpecialEditorDoor()
4604 int graphic = IMG_GLOBAL_BORDER_EDITOR;
4605 boolean redefined = getImageListEntryFromImageID(graphic)->redefined;
4607 // do not draw special editor door if editor border defined or redefined
4608 if (graphic_info[graphic].bitmap != NULL || redefined)
4611 // do not draw special editor door if global border defined to be empty
4612 if (graphic_info[IMG_GLOBAL_BORDER].bitmap == NULL)
4615 // do not draw special editor door if viewport definitions do not match
4619 EY + EYSIZE != VY + VYSIZE)
4625 void DrawSpecialEditorDoor()
4627 struct GraphicInfo *gfx1 = &graphic_info[IMG_DOOR_2_TOP_BORDER_CORRECTION];
4628 int top_border_width = gfx1->width;
4629 int top_border_height = gfx1->height;
4630 int outer_border = viewport.door_2[GAME_MODE_EDITOR].border_size;
4631 int ex = EX - outer_border;
4632 int ey = EY - outer_border;
4633 int vy = VY - outer_border;
4634 int exsize = EXSIZE + 2 * outer_border;
4636 if (!useSpecialEditorDoor())
4639 /* draw bigger level editor toolbox window */
4640 BlitBitmap(gfx1->bitmap, drawto, gfx1->src_x, gfx1->src_y,
4641 top_border_width, top_border_height, ex, ey - top_border_height);
4642 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto, ex, vy,
4643 exsize, EYSIZE - VYSIZE + outer_border, ex, ey);
4645 redraw_mask |= REDRAW_ALL;
4648 void UndrawSpecialEditorDoor()
4650 struct GraphicInfo *gfx1 = &graphic_info[IMG_DOOR_2_TOP_BORDER_CORRECTION];
4651 int top_border_width = gfx1->width;
4652 int top_border_height = gfx1->height;
4653 int outer_border = viewport.door_2[GAME_MODE_EDITOR].border_size;
4654 int ex = EX - outer_border;
4655 int ey = EY - outer_border;
4656 int ey_top = ey - top_border_height;
4657 int exsize = EXSIZE + 2 * outer_border;
4658 int eysize = EYSIZE + 2 * outer_border;
4660 if (!useSpecialEditorDoor())
4663 /* draw normal tape recorder window */
4664 if (graphic_info[IMG_GLOBAL_BORDER].bitmap)
4666 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
4667 ex, ey_top, top_border_width, top_border_height,
4669 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
4670 ex, ey, exsize, eysize, ex, ey);
4674 // if screen background is set to "[NONE]", clear editor toolbox window
4675 ClearRectangle(drawto, ex, ey_top, top_border_width, top_border_height);
4676 ClearRectangle(drawto, ex, ey, exsize, eysize);
4679 redraw_mask |= REDRAW_ALL;
4683 /* ---------- new tool button stuff ---------------------------------------- */
4688 struct TextPosInfo *pos;
4691 } toolbutton_info[NUM_TOOL_BUTTONS] =
4694 IMG_REQUEST_BUTTON_GFX_YES, &request.button.yes,
4695 TOOL_CTRL_ID_YES, "yes"
4698 IMG_REQUEST_BUTTON_GFX_NO, &request.button.no,
4699 TOOL_CTRL_ID_NO, "no"
4702 IMG_REQUEST_BUTTON_GFX_CONFIRM, &request.button.confirm,
4703 TOOL_CTRL_ID_CONFIRM, "confirm"
4706 IMG_REQUEST_BUTTON_GFX_PLAYER_1, &request.button.player_1,
4707 TOOL_CTRL_ID_PLAYER_1, "player 1"
4710 IMG_REQUEST_BUTTON_GFX_PLAYER_2, &request.button.player_2,
4711 TOOL_CTRL_ID_PLAYER_2, "player 2"
4714 IMG_REQUEST_BUTTON_GFX_PLAYER_3, &request.button.player_3,
4715 TOOL_CTRL_ID_PLAYER_3, "player 3"
4718 IMG_REQUEST_BUTTON_GFX_PLAYER_4, &request.button.player_4,
4719 TOOL_CTRL_ID_PLAYER_4, "player 4"
4723 void CreateToolButtons()
4727 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4729 struct GraphicInfo *gfx = &graphic_info[toolbutton_info[i].graphic];
4730 struct TextPosInfo *pos = toolbutton_info[i].pos;
4731 struct GadgetInfo *gi;
4732 Bitmap *deco_bitmap = None;
4733 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
4734 unsigned int event_mask = GD_EVENT_RELEASED;
4737 int gd_x = gfx->src_x;
4738 int gd_y = gfx->src_y;
4739 int gd_xp = gfx->src_x + gfx->pressed_xoffset;
4740 int gd_yp = gfx->src_y + gfx->pressed_yoffset;
4743 if (global.use_envelope_request)
4744 setRequestPosition(&dx, &dy, TRUE);
4746 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
4748 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
4750 getSizedGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr), 0,
4751 pos->size, &deco_bitmap, &deco_x, &deco_y);
4752 deco_xpos = (gfx->width - pos->size) / 2;
4753 deco_ypos = (gfx->height - pos->size) / 2;
4756 gi = CreateGadget(GDI_CUSTOM_ID, id,
4757 GDI_INFO_TEXT, toolbutton_info[i].infotext,
4758 GDI_X, dx + GDI_ACTIVE_POS(pos->x),
4759 GDI_Y, dy + GDI_ACTIVE_POS(pos->y),
4760 GDI_WIDTH, gfx->width,
4761 GDI_HEIGHT, gfx->height,
4762 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
4763 GDI_STATE, GD_BUTTON_UNPRESSED,
4764 GDI_DESIGN_UNPRESSED, gfx->bitmap, gd_x, gd_y,
4765 GDI_DESIGN_PRESSED, gfx->bitmap, gd_xp, gd_yp,
4766 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
4767 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
4768 GDI_DECORATION_SIZE, pos->size, pos->size,
4769 GDI_DECORATION_SHIFTING, 1, 1,
4770 GDI_DIRECT_DRAW, FALSE,
4771 GDI_EVENT_MASK, event_mask,
4772 GDI_CALLBACK_ACTION, HandleToolButtons,
4776 Error(ERR_EXIT, "cannot create gadget");
4778 tool_gadget[id] = gi;
4782 void FreeToolButtons()
4786 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4787 FreeGadget(tool_gadget[i]);
4790 static void UnmapToolButtons()
4794 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4795 UnmapGadget(tool_gadget[i]);
4798 static void HandleToolButtons(struct GadgetInfo *gi)
4800 request_gadget_id = gi->custom_id;
4803 static struct Mapping_EM_to_RND_object
4806 boolean is_rnd_to_em_mapping; /* unique mapping EM <-> RND */
4807 boolean is_backside; /* backside of moving element */
4813 em_object_mapping_list[] =
4816 Xblank, TRUE, FALSE,
4820 Yacid_splash_eB, FALSE, FALSE,
4821 EL_ACID_SPLASH_RIGHT, -1, -1
4824 Yacid_splash_wB, FALSE, FALSE,
4825 EL_ACID_SPLASH_LEFT, -1, -1
4828 #ifdef EM_ENGINE_BAD_ROLL
4830 Xstone_force_e, FALSE, FALSE,
4831 EL_ROCK, -1, MV_BIT_RIGHT
4834 Xstone_force_w, FALSE, FALSE,
4835 EL_ROCK, -1, MV_BIT_LEFT
4838 Xnut_force_e, FALSE, FALSE,
4839 EL_NUT, -1, MV_BIT_RIGHT
4842 Xnut_force_w, FALSE, FALSE,
4843 EL_NUT, -1, MV_BIT_LEFT
4846 Xspring_force_e, FALSE, FALSE,
4847 EL_SPRING, -1, MV_BIT_RIGHT
4850 Xspring_force_w, FALSE, FALSE,
4851 EL_SPRING, -1, MV_BIT_LEFT
4854 Xemerald_force_e, FALSE, FALSE,
4855 EL_EMERALD, -1, MV_BIT_RIGHT
4858 Xemerald_force_w, FALSE, FALSE,
4859 EL_EMERALD, -1, MV_BIT_LEFT
4862 Xdiamond_force_e, FALSE, FALSE,
4863 EL_DIAMOND, -1, MV_BIT_RIGHT
4866 Xdiamond_force_w, FALSE, FALSE,
4867 EL_DIAMOND, -1, MV_BIT_LEFT
4870 Xbomb_force_e, FALSE, FALSE,
4871 EL_BOMB, -1, MV_BIT_RIGHT
4874 Xbomb_force_w, FALSE, FALSE,
4875 EL_BOMB, -1, MV_BIT_LEFT
4877 #endif /* EM_ENGINE_BAD_ROLL */
4880 Xstone, TRUE, FALSE,
4884 Xstone_pause, FALSE, FALSE,
4888 Xstone_fall, FALSE, FALSE,
4892 Ystone_s, FALSE, FALSE,
4893 EL_ROCK, ACTION_FALLING, -1
4896 Ystone_sB, FALSE, TRUE,
4897 EL_ROCK, ACTION_FALLING, -1
4900 Ystone_e, FALSE, FALSE,
4901 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
4904 Ystone_eB, FALSE, TRUE,
4905 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
4908 Ystone_w, FALSE, FALSE,
4909 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
4912 Ystone_wB, FALSE, TRUE,
4913 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
4920 Xnut_pause, FALSE, FALSE,
4924 Xnut_fall, FALSE, FALSE,
4928 Ynut_s, FALSE, FALSE,
4929 EL_NUT, ACTION_FALLING, -1
4932 Ynut_sB, FALSE, TRUE,
4933 EL_NUT, ACTION_FALLING, -1
4936 Ynut_e, FALSE, FALSE,
4937 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
4940 Ynut_eB, FALSE, TRUE,
4941 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
4944 Ynut_w, FALSE, FALSE,
4945 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
4948 Ynut_wB, FALSE, TRUE,
4949 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
4952 Xbug_n, TRUE, FALSE,
4956 Xbug_e, TRUE, FALSE,
4957 EL_BUG_RIGHT, -1, -1
4960 Xbug_s, TRUE, FALSE,
4964 Xbug_w, TRUE, FALSE,
4968 Xbug_gon, FALSE, FALSE,
4972 Xbug_goe, FALSE, FALSE,
4973 EL_BUG_RIGHT, -1, -1
4976 Xbug_gos, FALSE, FALSE,
4980 Xbug_gow, FALSE, FALSE,
4984 Ybug_n, FALSE, FALSE,
4985 EL_BUG, ACTION_MOVING, MV_BIT_UP
4988 Ybug_nB, FALSE, TRUE,
4989 EL_BUG, ACTION_MOVING, MV_BIT_UP
4992 Ybug_e, FALSE, FALSE,
4993 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
4996 Ybug_eB, FALSE, TRUE,
4997 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
5000 Ybug_s, FALSE, FALSE,
5001 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
5004 Ybug_sB, FALSE, TRUE,
5005 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
5008 Ybug_w, FALSE, FALSE,
5009 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
5012 Ybug_wB, FALSE, TRUE,
5013 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
5016 Ybug_w_n, FALSE, FALSE,
5017 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
5020 Ybug_n_e, FALSE, FALSE,
5021 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
5024 Ybug_e_s, FALSE, FALSE,
5025 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
5028 Ybug_s_w, FALSE, FALSE,
5029 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
5032 Ybug_e_n, FALSE, FALSE,
5033 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
5036 Ybug_s_e, FALSE, FALSE,
5037 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
5040 Ybug_w_s, FALSE, FALSE,
5041 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
5044 Ybug_n_w, FALSE, FALSE,
5045 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
5048 Ybug_stone, FALSE, FALSE,
5049 EL_BUG, ACTION_SMASHED_BY_ROCK, -1
5052 Ybug_spring, FALSE, FALSE,
5053 EL_BUG, ACTION_SMASHED_BY_SPRING, -1
5056 Xtank_n, TRUE, FALSE,
5057 EL_SPACESHIP_UP, -1, -1
5060 Xtank_e, TRUE, FALSE,
5061 EL_SPACESHIP_RIGHT, -1, -1
5064 Xtank_s, TRUE, FALSE,
5065 EL_SPACESHIP_DOWN, -1, -1
5068 Xtank_w, TRUE, FALSE,
5069 EL_SPACESHIP_LEFT, -1, -1
5072 Xtank_gon, FALSE, FALSE,
5073 EL_SPACESHIP_UP, -1, -1
5076 Xtank_goe, FALSE, FALSE,
5077 EL_SPACESHIP_RIGHT, -1, -1
5080 Xtank_gos, FALSE, FALSE,
5081 EL_SPACESHIP_DOWN, -1, -1
5084 Xtank_gow, FALSE, FALSE,
5085 EL_SPACESHIP_LEFT, -1, -1
5088 Ytank_n, FALSE, FALSE,
5089 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
5092 Ytank_nB, FALSE, TRUE,
5093 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
5096 Ytank_e, FALSE, FALSE,
5097 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
5100 Ytank_eB, FALSE, TRUE,
5101 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
5104 Ytank_s, FALSE, FALSE,
5105 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
5108 Ytank_sB, FALSE, TRUE,
5109 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
5112 Ytank_w, FALSE, FALSE,
5113 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
5116 Ytank_wB, FALSE, TRUE,
5117 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
5120 Ytank_w_n, FALSE, FALSE,
5121 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
5124 Ytank_n_e, FALSE, FALSE,
5125 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
5128 Ytank_e_s, FALSE, FALSE,
5129 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
5132 Ytank_s_w, FALSE, FALSE,
5133 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
5136 Ytank_e_n, FALSE, FALSE,
5137 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
5140 Ytank_s_e, FALSE, FALSE,
5141 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
5144 Ytank_w_s, FALSE, FALSE,
5145 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
5148 Ytank_n_w, FALSE, FALSE,
5149 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
5152 Ytank_stone, FALSE, FALSE,
5153 EL_SPACESHIP, ACTION_SMASHED_BY_ROCK, -1
5156 Ytank_spring, FALSE, FALSE,
5157 EL_SPACESHIP, ACTION_SMASHED_BY_SPRING, -1
5160 Xandroid, TRUE, FALSE,
5161 EL_EMC_ANDROID, ACTION_ACTIVE, -1
5164 Xandroid_1_n, FALSE, FALSE,
5165 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
5168 Xandroid_2_n, FALSE, FALSE,
5169 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
5172 Xandroid_1_e, FALSE, FALSE,
5173 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
5176 Xandroid_2_e, FALSE, FALSE,
5177 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
5180 Xandroid_1_w, FALSE, FALSE,
5181 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
5184 Xandroid_2_w, FALSE, FALSE,
5185 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
5188 Xandroid_1_s, FALSE, FALSE,
5189 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
5192 Xandroid_2_s, FALSE, FALSE,
5193 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
5196 Yandroid_n, FALSE, FALSE,
5197 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
5200 Yandroid_nB, FALSE, TRUE,
5201 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
5204 Yandroid_ne, FALSE, FALSE,
5205 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPRIGHT
5208 Yandroid_neB, FALSE, TRUE,
5209 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPRIGHT
5212 Yandroid_e, FALSE, FALSE,
5213 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
5216 Yandroid_eB, FALSE, TRUE,
5217 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
5220 Yandroid_se, FALSE, FALSE,
5221 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNRIGHT
5224 Yandroid_seB, FALSE, TRUE,
5225 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNRIGHT
5228 Yandroid_s, FALSE, FALSE,
5229 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
5232 Yandroid_sB, FALSE, TRUE,
5233 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
5236 Yandroid_sw, FALSE, FALSE,
5237 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNLEFT
5240 Yandroid_swB, FALSE, TRUE,
5241 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNLEFT
5244 Yandroid_w, FALSE, FALSE,
5245 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
5248 Yandroid_wB, FALSE, TRUE,
5249 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
5252 Yandroid_nw, FALSE, FALSE,
5253 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPLEFT
5256 Yandroid_nwB, FALSE, TRUE,
5257 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPLEFT
5260 Xspring, TRUE, FALSE,
5264 Xspring_pause, FALSE, FALSE,
5268 Xspring_e, FALSE, FALSE,
5272 Xspring_w, FALSE, FALSE,
5276 Xspring_fall, FALSE, FALSE,
5280 Yspring_s, FALSE, FALSE,
5281 EL_SPRING, ACTION_FALLING, -1
5284 Yspring_sB, FALSE, TRUE,
5285 EL_SPRING, ACTION_FALLING, -1
5288 Yspring_e, FALSE, FALSE,
5289 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
5292 Yspring_eB, FALSE, TRUE,
5293 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
5296 Yspring_w, FALSE, FALSE,
5297 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
5300 Yspring_wB, FALSE, TRUE,
5301 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
5304 Yspring_kill_e, FALSE, FALSE,
5305 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
5308 Yspring_kill_eB, FALSE, TRUE,
5309 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
5312 Yspring_kill_w, FALSE, FALSE,
5313 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
5316 Yspring_kill_wB, FALSE, TRUE,
5317 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
5320 Xeater_n, TRUE, FALSE,
5321 EL_YAMYAM_UP, -1, -1
5324 Xeater_e, TRUE, FALSE,
5325 EL_YAMYAM_RIGHT, -1, -1
5328 Xeater_w, TRUE, FALSE,
5329 EL_YAMYAM_LEFT, -1, -1
5332 Xeater_s, TRUE, FALSE,
5333 EL_YAMYAM_DOWN, -1, -1
5336 Yeater_n, FALSE, FALSE,
5337 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
5340 Yeater_nB, FALSE, TRUE,
5341 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
5344 Yeater_e, FALSE, FALSE,
5345 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
5348 Yeater_eB, FALSE, TRUE,
5349 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
5352 Yeater_s, FALSE, FALSE,
5353 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
5356 Yeater_sB, FALSE, TRUE,
5357 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
5360 Yeater_w, FALSE, FALSE,
5361 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
5364 Yeater_wB, FALSE, TRUE,
5365 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
5368 Yeater_stone, FALSE, FALSE,
5369 EL_YAMYAM, ACTION_SMASHED_BY_ROCK, -1
5372 Yeater_spring, FALSE, FALSE,
5373 EL_YAMYAM, ACTION_SMASHED_BY_SPRING, -1
5376 Xalien, TRUE, FALSE,
5380 Xalien_pause, FALSE, FALSE,
5384 Yalien_n, FALSE, FALSE,
5385 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
5388 Yalien_nB, FALSE, TRUE,
5389 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
5392 Yalien_e, FALSE, FALSE,
5393 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
5396 Yalien_eB, FALSE, TRUE,
5397 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
5400 Yalien_s, FALSE, FALSE,
5401 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
5404 Yalien_sB, FALSE, TRUE,
5405 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
5408 Yalien_w, FALSE, FALSE,
5409 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
5412 Yalien_wB, FALSE, TRUE,
5413 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
5416 Yalien_stone, FALSE, FALSE,
5417 EL_ROBOT, ACTION_SMASHED_BY_ROCK, -1
5420 Yalien_spring, FALSE, FALSE,
5421 EL_ROBOT, ACTION_SMASHED_BY_SPRING, -1
5424 Xemerald, TRUE, FALSE,
5428 Xemerald_pause, FALSE, FALSE,
5432 Xemerald_fall, FALSE, FALSE,
5436 Xemerald_shine, FALSE, FALSE,
5437 EL_EMERALD, ACTION_TWINKLING, -1
5440 Yemerald_s, FALSE, FALSE,
5441 EL_EMERALD, ACTION_FALLING, -1
5444 Yemerald_sB, FALSE, TRUE,
5445 EL_EMERALD, ACTION_FALLING, -1
5448 Yemerald_e, FALSE, FALSE,
5449 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
5452 Yemerald_eB, FALSE, TRUE,
5453 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
5456 Yemerald_w, FALSE, FALSE,
5457 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
5460 Yemerald_wB, FALSE, TRUE,
5461 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
5464 Yemerald_eat, FALSE, FALSE,
5465 EL_EMERALD, ACTION_COLLECTING, -1
5468 Yemerald_stone, FALSE, FALSE,
5469 EL_NUT, ACTION_BREAKING, -1
5472 Xdiamond, TRUE, FALSE,
5476 Xdiamond_pause, FALSE, FALSE,
5480 Xdiamond_fall, FALSE, FALSE,
5484 Xdiamond_shine, FALSE, FALSE,
5485 EL_DIAMOND, ACTION_TWINKLING, -1
5488 Ydiamond_s, FALSE, FALSE,
5489 EL_DIAMOND, ACTION_FALLING, -1
5492 Ydiamond_sB, FALSE, TRUE,
5493 EL_DIAMOND, ACTION_FALLING, -1
5496 Ydiamond_e, FALSE, FALSE,
5497 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
5500 Ydiamond_eB, FALSE, TRUE,
5501 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
5504 Ydiamond_w, FALSE, FALSE,
5505 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
5508 Ydiamond_wB, FALSE, TRUE,
5509 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
5512 Ydiamond_eat, FALSE, FALSE,
5513 EL_DIAMOND, ACTION_COLLECTING, -1
5516 Ydiamond_stone, FALSE, FALSE,
5517 EL_DIAMOND, ACTION_SMASHED_BY_ROCK, -1
5520 Xdrip_fall, TRUE, FALSE,
5521 EL_AMOEBA_DROP, -1, -1
5524 Xdrip_stretch, FALSE, FALSE,
5525 EL_AMOEBA_DROP, ACTION_FALLING, -1
5528 Xdrip_stretchB, FALSE, TRUE,
5529 EL_AMOEBA_DROP, ACTION_FALLING, -1
5532 Xdrip_eat, FALSE, FALSE,
5533 EL_AMOEBA_DROP, ACTION_GROWING, -1
5536 Ydrip_s1, FALSE, FALSE,
5537 EL_AMOEBA_DROP, ACTION_FALLING, -1
5540 Ydrip_s1B, FALSE, TRUE,
5541 EL_AMOEBA_DROP, ACTION_FALLING, -1
5544 Ydrip_s2, FALSE, FALSE,
5545 EL_AMOEBA_DROP, ACTION_FALLING, -1
5548 Ydrip_s2B, FALSE, TRUE,
5549 EL_AMOEBA_DROP, ACTION_FALLING, -1
5556 Xbomb_pause, FALSE, FALSE,
5560 Xbomb_fall, FALSE, FALSE,
5564 Ybomb_s, FALSE, FALSE,
5565 EL_BOMB, ACTION_FALLING, -1
5568 Ybomb_sB, FALSE, TRUE,
5569 EL_BOMB, ACTION_FALLING, -1
5572 Ybomb_e, FALSE, FALSE,
5573 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
5576 Ybomb_eB, FALSE, TRUE,
5577 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
5580 Ybomb_w, FALSE, FALSE,
5581 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
5584 Ybomb_wB, FALSE, TRUE,
5585 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
5588 Ybomb_eat, FALSE, FALSE,
5589 EL_BOMB, ACTION_ACTIVATING, -1
5592 Xballoon, TRUE, FALSE,
5596 Yballoon_n, FALSE, FALSE,
5597 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
5600 Yballoon_nB, FALSE, TRUE,
5601 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
5604 Yballoon_e, FALSE, FALSE,
5605 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
5608 Yballoon_eB, FALSE, TRUE,
5609 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
5612 Yballoon_s, FALSE, FALSE,
5613 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
5616 Yballoon_sB, FALSE, TRUE,
5617 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
5620 Yballoon_w, FALSE, FALSE,
5621 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
5624 Yballoon_wB, FALSE, TRUE,
5625 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
5628 Xgrass, TRUE, FALSE,
5629 EL_EMC_GRASS, -1, -1
5632 Ygrass_nB, FALSE, FALSE,
5633 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_UP
5636 Ygrass_eB, FALSE, FALSE,
5637 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_RIGHT
5640 Ygrass_sB, FALSE, FALSE,
5641 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_DOWN
5644 Ygrass_wB, FALSE, FALSE,
5645 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_LEFT
5652 Ydirt_nB, FALSE, FALSE,
5653 EL_SAND, ACTION_DIGGING, MV_BIT_UP
5656 Ydirt_eB, FALSE, FALSE,
5657 EL_SAND, ACTION_DIGGING, MV_BIT_RIGHT
5660 Ydirt_sB, FALSE, FALSE,
5661 EL_SAND, ACTION_DIGGING, MV_BIT_DOWN
5664 Ydirt_wB, FALSE, FALSE,
5665 EL_SAND, ACTION_DIGGING, MV_BIT_LEFT
5668 Xacid_ne, TRUE, FALSE,
5669 EL_ACID_POOL_TOPRIGHT, -1, -1
5672 Xacid_se, TRUE, FALSE,
5673 EL_ACID_POOL_BOTTOMRIGHT, -1, -1
5676 Xacid_s, TRUE, FALSE,
5677 EL_ACID_POOL_BOTTOM, -1, -1
5680 Xacid_sw, TRUE, FALSE,
5681 EL_ACID_POOL_BOTTOMLEFT, -1, -1
5684 Xacid_nw, TRUE, FALSE,
5685 EL_ACID_POOL_TOPLEFT, -1, -1
5688 Xacid_1, TRUE, FALSE,
5692 Xacid_2, FALSE, FALSE,
5696 Xacid_3, FALSE, FALSE,
5700 Xacid_4, FALSE, FALSE,
5704 Xacid_5, FALSE, FALSE,
5708 Xacid_6, FALSE, FALSE,
5712 Xacid_7, FALSE, FALSE,
5716 Xacid_8, FALSE, FALSE,
5720 Xball_1, TRUE, FALSE,
5721 EL_EMC_MAGIC_BALL, -1, -1
5724 Xball_1B, FALSE, FALSE,
5725 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
5728 Xball_2, FALSE, FALSE,
5729 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
5732 Xball_2B, FALSE, FALSE,
5733 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
5736 Yball_eat, FALSE, FALSE,
5737 EL_EMC_MAGIC_BALL, ACTION_DROPPING, -1
5740 Ykey_1_eat, FALSE, FALSE,
5741 EL_EM_KEY_1, ACTION_COLLECTING, -1
5744 Ykey_2_eat, FALSE, FALSE,
5745 EL_EM_KEY_2, ACTION_COLLECTING, -1
5748 Ykey_3_eat, FALSE, FALSE,
5749 EL_EM_KEY_3, ACTION_COLLECTING, -1
5752 Ykey_4_eat, FALSE, FALSE,
5753 EL_EM_KEY_4, ACTION_COLLECTING, -1
5756 Ykey_5_eat, FALSE, FALSE,
5757 EL_EMC_KEY_5, ACTION_COLLECTING, -1
5760 Ykey_6_eat, FALSE, FALSE,
5761 EL_EMC_KEY_6, ACTION_COLLECTING, -1
5764 Ykey_7_eat, FALSE, FALSE,
5765 EL_EMC_KEY_7, ACTION_COLLECTING, -1
5768 Ykey_8_eat, FALSE, FALSE,
5769 EL_EMC_KEY_8, ACTION_COLLECTING, -1
5772 Ylenses_eat, FALSE, FALSE,
5773 EL_EMC_LENSES, ACTION_COLLECTING, -1
5776 Ymagnify_eat, FALSE, FALSE,
5777 EL_EMC_MAGNIFIER, ACTION_COLLECTING, -1
5780 Ygrass_eat, FALSE, FALSE,
5781 EL_EMC_GRASS, ACTION_SNAPPING, -1
5784 Ydirt_eat, FALSE, FALSE,
5785 EL_SAND, ACTION_SNAPPING, -1
5788 Xgrow_ns, TRUE, FALSE,
5789 EL_EXPANDABLE_WALL_VERTICAL, -1, -1
5792 Ygrow_ns_eat, FALSE, FALSE,
5793 EL_EXPANDABLE_WALL_VERTICAL, ACTION_GROWING, -1
5796 Xgrow_ew, TRUE, FALSE,
5797 EL_EXPANDABLE_WALL_HORIZONTAL, -1, -1
5800 Ygrow_ew_eat, FALSE, FALSE,
5801 EL_EXPANDABLE_WALL_HORIZONTAL, ACTION_GROWING, -1
5804 Xwonderwall, TRUE, FALSE,
5805 EL_MAGIC_WALL, -1, -1
5808 XwonderwallB, FALSE, FALSE,
5809 EL_MAGIC_WALL, ACTION_ACTIVE, -1
5812 Xamoeba_1, TRUE, FALSE,
5813 EL_AMOEBA_DRY, ACTION_OTHER, -1
5816 Xamoeba_2, FALSE, FALSE,
5817 EL_AMOEBA_DRY, ACTION_OTHER, -1
5820 Xamoeba_3, FALSE, FALSE,
5821 EL_AMOEBA_DRY, ACTION_OTHER, -1
5824 Xamoeba_4, FALSE, FALSE,
5825 EL_AMOEBA_DRY, ACTION_OTHER, -1
5828 Xamoeba_5, TRUE, FALSE,
5829 EL_AMOEBA_WET, ACTION_OTHER, -1
5832 Xamoeba_6, FALSE, FALSE,
5833 EL_AMOEBA_WET, ACTION_OTHER, -1
5836 Xamoeba_7, FALSE, FALSE,
5837 EL_AMOEBA_WET, ACTION_OTHER, -1
5840 Xamoeba_8, FALSE, FALSE,
5841 EL_AMOEBA_WET, ACTION_OTHER, -1
5844 Xdoor_1, TRUE, FALSE,
5845 EL_EM_GATE_1, -1, -1
5848 Xdoor_2, TRUE, FALSE,
5849 EL_EM_GATE_2, -1, -1
5852 Xdoor_3, TRUE, FALSE,
5853 EL_EM_GATE_3, -1, -1
5856 Xdoor_4, TRUE, FALSE,
5857 EL_EM_GATE_4, -1, -1
5860 Xdoor_5, TRUE, FALSE,
5861 EL_EMC_GATE_5, -1, -1
5864 Xdoor_6, TRUE, FALSE,
5865 EL_EMC_GATE_6, -1, -1
5868 Xdoor_7, TRUE, FALSE,
5869 EL_EMC_GATE_7, -1, -1
5872 Xdoor_8, TRUE, FALSE,
5873 EL_EMC_GATE_8, -1, -1
5876 Xkey_1, TRUE, FALSE,
5880 Xkey_2, TRUE, FALSE,
5884 Xkey_3, TRUE, FALSE,
5888 Xkey_4, TRUE, FALSE,
5892 Xkey_5, TRUE, FALSE,
5893 EL_EMC_KEY_5, -1, -1
5896 Xkey_6, TRUE, FALSE,
5897 EL_EMC_KEY_6, -1, -1
5900 Xkey_7, TRUE, FALSE,
5901 EL_EMC_KEY_7, -1, -1
5904 Xkey_8, TRUE, FALSE,
5905 EL_EMC_KEY_8, -1, -1
5908 Xwind_n, TRUE, FALSE,
5909 EL_BALLOON_SWITCH_UP, -1, -1
5912 Xwind_e, TRUE, FALSE,
5913 EL_BALLOON_SWITCH_RIGHT, -1, -1
5916 Xwind_s, TRUE, FALSE,
5917 EL_BALLOON_SWITCH_DOWN, -1, -1
5920 Xwind_w, TRUE, FALSE,
5921 EL_BALLOON_SWITCH_LEFT, -1, -1
5924 Xwind_nesw, TRUE, FALSE,
5925 EL_BALLOON_SWITCH_ANY, -1, -1
5928 Xwind_stop, TRUE, FALSE,
5929 EL_BALLOON_SWITCH_NONE, -1, -1
5933 EL_EM_EXIT_CLOSED, -1, -1
5936 Xexit_1, TRUE, FALSE,
5937 EL_EM_EXIT_OPEN, -1, -1
5940 Xexit_2, FALSE, FALSE,
5941 EL_EM_EXIT_OPEN, -1, -1
5944 Xexit_3, FALSE, FALSE,
5945 EL_EM_EXIT_OPEN, -1, -1
5948 Xdynamite, TRUE, FALSE,
5949 EL_EM_DYNAMITE, -1, -1
5952 Ydynamite_eat, FALSE, FALSE,
5953 EL_EM_DYNAMITE, ACTION_COLLECTING, -1
5956 Xdynamite_1, TRUE, FALSE,
5957 EL_EM_DYNAMITE_ACTIVE, -1, -1
5960 Xdynamite_2, FALSE, FALSE,
5961 EL_EM_DYNAMITE_ACTIVE, -1, -1
5964 Xdynamite_3, FALSE, FALSE,
5965 EL_EM_DYNAMITE_ACTIVE, -1, -1
5968 Xdynamite_4, FALSE, FALSE,
5969 EL_EM_DYNAMITE_ACTIVE, -1, -1
5972 Xbumper, TRUE, FALSE,
5973 EL_EMC_SPRING_BUMPER, -1, -1
5976 XbumperB, FALSE, FALSE,
5977 EL_EMC_SPRING_BUMPER, ACTION_ACTIVE, -1
5980 Xwheel, TRUE, FALSE,
5981 EL_ROBOT_WHEEL, -1, -1
5984 XwheelB, FALSE, FALSE,
5985 EL_ROBOT_WHEEL, ACTION_ACTIVE, -1
5988 Xswitch, TRUE, FALSE,
5989 EL_EMC_MAGIC_BALL_SWITCH, -1, -1
5992 XswitchB, FALSE, FALSE,
5993 EL_EMC_MAGIC_BALL_SWITCH, ACTION_ACTIVE, -1
5997 EL_QUICKSAND_EMPTY, -1, -1
6000 Xsand_stone, TRUE, FALSE,
6001 EL_QUICKSAND_FULL, -1, -1
6004 Xsand_stonein_1, FALSE, TRUE,
6005 EL_ROCK, ACTION_FILLING, -1
6008 Xsand_stonein_2, FALSE, TRUE,
6009 EL_ROCK, ACTION_FILLING, -1
6012 Xsand_stonein_3, FALSE, TRUE,
6013 EL_ROCK, ACTION_FILLING, -1
6016 Xsand_stonein_4, FALSE, TRUE,
6017 EL_ROCK, ACTION_FILLING, -1
6020 Xsand_stonesand_1, FALSE, FALSE,
6021 EL_QUICKSAND_EMPTYING, -1, -1
6024 Xsand_stonesand_2, FALSE, FALSE,
6025 EL_QUICKSAND_EMPTYING, -1, -1
6028 Xsand_stonesand_3, FALSE, FALSE,
6029 EL_QUICKSAND_EMPTYING, -1, -1
6032 Xsand_stonesand_4, FALSE, FALSE,
6033 EL_QUICKSAND_EMPTYING, -1, -1
6036 Xsand_stonesand_quickout_1, FALSE, FALSE,
6037 EL_QUICKSAND_EMPTYING, -1, -1
6040 Xsand_stonesand_quickout_2, FALSE, FALSE,
6041 EL_QUICKSAND_EMPTYING, -1, -1
6044 Xsand_stoneout_1, FALSE, FALSE,
6045 EL_ROCK, ACTION_EMPTYING, -1
6048 Xsand_stoneout_2, FALSE, FALSE,
6049 EL_ROCK, ACTION_EMPTYING, -1
6052 Xsand_sandstone_1, FALSE, FALSE,
6053 EL_QUICKSAND_FILLING, -1, -1
6056 Xsand_sandstone_2, FALSE, FALSE,
6057 EL_QUICKSAND_FILLING, -1, -1
6060 Xsand_sandstone_3, FALSE, FALSE,
6061 EL_QUICKSAND_FILLING, -1, -1
6064 Xsand_sandstone_4, FALSE, FALSE,
6065 EL_QUICKSAND_FILLING, -1, -1
6068 Xplant, TRUE, FALSE,
6069 EL_EMC_PLANT, -1, -1
6072 Yplant, FALSE, FALSE,
6073 EL_EMC_PLANT, -1, -1
6076 Xlenses, TRUE, FALSE,
6077 EL_EMC_LENSES, -1, -1
6080 Xmagnify, TRUE, FALSE,
6081 EL_EMC_MAGNIFIER, -1, -1
6084 Xdripper, TRUE, FALSE,
6085 EL_EMC_DRIPPER, -1, -1
6088 XdripperB, FALSE, FALSE,
6089 EL_EMC_DRIPPER, ACTION_ACTIVE, -1
6092 Xfake_blank, TRUE, FALSE,
6093 EL_INVISIBLE_WALL, -1, -1
6096 Xfake_blankB, FALSE, FALSE,
6097 EL_INVISIBLE_WALL, ACTION_ACTIVE, -1
6100 Xfake_grass, TRUE, FALSE,
6101 EL_EMC_FAKE_GRASS, -1, -1
6104 Xfake_grassB, FALSE, FALSE,
6105 EL_EMC_FAKE_GRASS, ACTION_ACTIVE, -1
6108 Xfake_door_1, TRUE, FALSE,
6109 EL_EM_GATE_1_GRAY, -1, -1
6112 Xfake_door_2, TRUE, FALSE,
6113 EL_EM_GATE_2_GRAY, -1, -1
6116 Xfake_door_3, TRUE, FALSE,
6117 EL_EM_GATE_3_GRAY, -1, -1
6120 Xfake_door_4, TRUE, FALSE,
6121 EL_EM_GATE_4_GRAY, -1, -1
6124 Xfake_door_5, TRUE, FALSE,
6125 EL_EMC_GATE_5_GRAY, -1, -1
6128 Xfake_door_6, TRUE, FALSE,
6129 EL_EMC_GATE_6_GRAY, -1, -1
6132 Xfake_door_7, TRUE, FALSE,
6133 EL_EMC_GATE_7_GRAY, -1, -1
6136 Xfake_door_8, TRUE, FALSE,
6137 EL_EMC_GATE_8_GRAY, -1, -1
6140 Xfake_acid_1, TRUE, FALSE,
6141 EL_EMC_FAKE_ACID, -1, -1
6144 Xfake_acid_2, FALSE, FALSE,
6145 EL_EMC_FAKE_ACID, -1, -1
6148 Xfake_acid_3, FALSE, FALSE,
6149 EL_EMC_FAKE_ACID, -1, -1
6152 Xfake_acid_4, FALSE, FALSE,
6153 EL_EMC_FAKE_ACID, -1, -1
6156 Xfake_acid_5, FALSE, FALSE,
6157 EL_EMC_FAKE_ACID, -1, -1
6160 Xfake_acid_6, FALSE, FALSE,
6161 EL_EMC_FAKE_ACID, -1, -1
6164 Xfake_acid_7, FALSE, FALSE,
6165 EL_EMC_FAKE_ACID, -1, -1
6168 Xfake_acid_8, FALSE, FALSE,
6169 EL_EMC_FAKE_ACID, -1, -1
6172 Xsteel_1, TRUE, FALSE,
6173 EL_STEELWALL, -1, -1
6176 Xsteel_2, TRUE, FALSE,
6177 EL_EMC_STEELWALL_2, -1, -1
6180 Xsteel_3, TRUE, FALSE,
6181 EL_EMC_STEELWALL_3, -1, -1
6184 Xsteel_4, TRUE, FALSE,
6185 EL_EMC_STEELWALL_4, -1, -1
6188 Xwall_1, TRUE, FALSE,
6192 Xwall_2, TRUE, FALSE,
6193 EL_EMC_WALL_14, -1, -1
6196 Xwall_3, TRUE, FALSE,
6197 EL_EMC_WALL_15, -1, -1
6200 Xwall_4, TRUE, FALSE,
6201 EL_EMC_WALL_16, -1, -1
6204 Xround_wall_1, TRUE, FALSE,
6205 EL_WALL_SLIPPERY, -1, -1
6208 Xround_wall_2, TRUE, FALSE,
6209 EL_EMC_WALL_SLIPPERY_2, -1, -1
6212 Xround_wall_3, TRUE, FALSE,
6213 EL_EMC_WALL_SLIPPERY_3, -1, -1
6216 Xround_wall_4, TRUE, FALSE,
6217 EL_EMC_WALL_SLIPPERY_4, -1, -1
6220 Xdecor_1, TRUE, FALSE,
6221 EL_EMC_WALL_8, -1, -1
6224 Xdecor_2, TRUE, FALSE,
6225 EL_EMC_WALL_6, -1, -1
6228 Xdecor_3, TRUE, FALSE,
6229 EL_EMC_WALL_4, -1, -1
6232 Xdecor_4, TRUE, FALSE,
6233 EL_EMC_WALL_7, -1, -1
6236 Xdecor_5, TRUE, FALSE,
6237 EL_EMC_WALL_5, -1, -1
6240 Xdecor_6, TRUE, FALSE,
6241 EL_EMC_WALL_9, -1, -1
6244 Xdecor_7, TRUE, FALSE,
6245 EL_EMC_WALL_10, -1, -1
6248 Xdecor_8, TRUE, FALSE,
6249 EL_EMC_WALL_1, -1, -1
6252 Xdecor_9, TRUE, FALSE,
6253 EL_EMC_WALL_2, -1, -1
6256 Xdecor_10, TRUE, FALSE,
6257 EL_EMC_WALL_3, -1, -1
6260 Xdecor_11, TRUE, FALSE,
6261 EL_EMC_WALL_11, -1, -1
6264 Xdecor_12, TRUE, FALSE,
6265 EL_EMC_WALL_12, -1, -1
6268 Xalpha_0, TRUE, FALSE,
6269 EL_CHAR('0'), -1, -1
6272 Xalpha_1, TRUE, FALSE,
6273 EL_CHAR('1'), -1, -1
6276 Xalpha_2, TRUE, FALSE,
6277 EL_CHAR('2'), -1, -1
6280 Xalpha_3, TRUE, FALSE,
6281 EL_CHAR('3'), -1, -1
6284 Xalpha_4, TRUE, FALSE,
6285 EL_CHAR('4'), -1, -1
6288 Xalpha_5, TRUE, FALSE,
6289 EL_CHAR('5'), -1, -1
6292 Xalpha_6, TRUE, FALSE,
6293 EL_CHAR('6'), -1, -1
6296 Xalpha_7, TRUE, FALSE,
6297 EL_CHAR('7'), -1, -1
6300 Xalpha_8, TRUE, FALSE,
6301 EL_CHAR('8'), -1, -1
6304 Xalpha_9, TRUE, FALSE,
6305 EL_CHAR('9'), -1, -1
6308 Xalpha_excla, TRUE, FALSE,
6309 EL_CHAR('!'), -1, -1
6312 Xalpha_quote, TRUE, FALSE,
6313 EL_CHAR('"'), -1, -1
6316 Xalpha_comma, TRUE, FALSE,
6317 EL_CHAR(','), -1, -1
6320 Xalpha_minus, TRUE, FALSE,
6321 EL_CHAR('-'), -1, -1
6324 Xalpha_perio, TRUE, FALSE,
6325 EL_CHAR('.'), -1, -1
6328 Xalpha_colon, TRUE, FALSE,
6329 EL_CHAR(':'), -1, -1
6332 Xalpha_quest, TRUE, FALSE,
6333 EL_CHAR('?'), -1, -1
6336 Xalpha_a, TRUE, FALSE,
6337 EL_CHAR('A'), -1, -1
6340 Xalpha_b, TRUE, FALSE,
6341 EL_CHAR('B'), -1, -1
6344 Xalpha_c, TRUE, FALSE,
6345 EL_CHAR('C'), -1, -1
6348 Xalpha_d, TRUE, FALSE,
6349 EL_CHAR('D'), -1, -1
6352 Xalpha_e, TRUE, FALSE,
6353 EL_CHAR('E'), -1, -1
6356 Xalpha_f, TRUE, FALSE,
6357 EL_CHAR('F'), -1, -1
6360 Xalpha_g, TRUE, FALSE,
6361 EL_CHAR('G'), -1, -1
6364 Xalpha_h, TRUE, FALSE,
6365 EL_CHAR('H'), -1, -1
6368 Xalpha_i, TRUE, FALSE,
6369 EL_CHAR('I'), -1, -1
6372 Xalpha_j, TRUE, FALSE,
6373 EL_CHAR('J'), -1, -1
6376 Xalpha_k, TRUE, FALSE,
6377 EL_CHAR('K'), -1, -1
6380 Xalpha_l, TRUE, FALSE,
6381 EL_CHAR('L'), -1, -1
6384 Xalpha_m, TRUE, FALSE,
6385 EL_CHAR('M'), -1, -1
6388 Xalpha_n, TRUE, FALSE,
6389 EL_CHAR('N'), -1, -1
6392 Xalpha_o, TRUE, FALSE,
6393 EL_CHAR('O'), -1, -1
6396 Xalpha_p, TRUE, FALSE,
6397 EL_CHAR('P'), -1, -1
6400 Xalpha_q, TRUE, FALSE,
6401 EL_CHAR('Q'), -1, -1
6404 Xalpha_r, TRUE, FALSE,
6405 EL_CHAR('R'), -1, -1
6408 Xalpha_s, TRUE, FALSE,
6409 EL_CHAR('S'), -1, -1
6412 Xalpha_t, TRUE, FALSE,
6413 EL_CHAR('T'), -1, -1
6416 Xalpha_u, TRUE, FALSE,
6417 EL_CHAR('U'), -1, -1
6420 Xalpha_v, TRUE, FALSE,
6421 EL_CHAR('V'), -1, -1
6424 Xalpha_w, TRUE, FALSE,
6425 EL_CHAR('W'), -1, -1
6428 Xalpha_x, TRUE, FALSE,
6429 EL_CHAR('X'), -1, -1
6432 Xalpha_y, TRUE, FALSE,
6433 EL_CHAR('Y'), -1, -1
6436 Xalpha_z, TRUE, FALSE,
6437 EL_CHAR('Z'), -1, -1
6440 Xalpha_arrow_e, TRUE, FALSE,
6441 EL_CHAR('>'), -1, -1
6444 Xalpha_arrow_w, TRUE, FALSE,
6445 EL_CHAR('<'), -1, -1
6448 Xalpha_copyr, TRUE, FALSE,
6449 EL_CHAR(CHAR_BYTE_COPYRIGHT), -1, -1
6453 Xboom_bug, FALSE, FALSE,
6454 EL_BUG, ACTION_EXPLODING, -1
6457 Xboom_bomb, FALSE, FALSE,
6458 EL_BOMB, ACTION_EXPLODING, -1
6461 Xboom_android, FALSE, FALSE,
6462 EL_EMC_ANDROID, ACTION_OTHER, -1
6465 Xboom_1, FALSE, FALSE,
6466 EL_DEFAULT, ACTION_EXPLODING, -1
6469 Xboom_2, FALSE, FALSE,
6470 EL_DEFAULT, ACTION_EXPLODING, -1
6473 Znormal, FALSE, FALSE,
6477 Zdynamite, FALSE, FALSE,
6481 Zplayer, FALSE, FALSE,
6485 ZBORDER, FALSE, FALSE,
6495 static struct Mapping_EM_to_RND_player
6504 em_player_mapping_list[] =
6508 EL_PLAYER_1, ACTION_MOVING, MV_BIT_UP,
6512 EL_PLAYER_1, ACTION_MOVING, MV_BIT_RIGHT,
6516 EL_PLAYER_1, ACTION_MOVING, MV_BIT_DOWN,
6520 EL_PLAYER_1, ACTION_MOVING, MV_BIT_LEFT,
6524 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_UP,
6528 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_RIGHT,
6532 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_DOWN,
6536 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_LEFT,
6540 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_UP,
6544 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_RIGHT,
6548 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_DOWN,
6552 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_LEFT,
6556 EL_PLAYER_2, ACTION_MOVING, MV_BIT_UP,
6560 EL_PLAYER_2, ACTION_MOVING, MV_BIT_RIGHT,
6564 EL_PLAYER_2, ACTION_MOVING, MV_BIT_DOWN,
6568 EL_PLAYER_2, ACTION_MOVING, MV_BIT_LEFT,
6572 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_UP,
6576 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_RIGHT,
6580 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_DOWN,
6584 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_LEFT,
6588 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_UP,
6592 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_RIGHT,
6596 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_DOWN,
6600 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_LEFT,
6604 EL_PLAYER_1, ACTION_DEFAULT, -1,
6608 EL_PLAYER_2, ACTION_DEFAULT, -1,
6612 EL_PLAYER_3, ACTION_MOVING, MV_BIT_UP,
6616 EL_PLAYER_3, ACTION_MOVING, MV_BIT_RIGHT,
6620 EL_PLAYER_3, ACTION_MOVING, MV_BIT_DOWN,
6624 EL_PLAYER_3, ACTION_MOVING, MV_BIT_LEFT,
6628 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_UP,
6632 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_RIGHT,
6636 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_DOWN,
6640 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_LEFT,
6644 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_UP,
6648 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_RIGHT,
6652 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_DOWN,
6656 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_LEFT,
6660 EL_PLAYER_4, ACTION_MOVING, MV_BIT_UP,
6664 EL_PLAYER_4, ACTION_MOVING, MV_BIT_RIGHT,
6668 EL_PLAYER_4, ACTION_MOVING, MV_BIT_DOWN,
6672 EL_PLAYER_4, ACTION_MOVING, MV_BIT_LEFT,
6676 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_UP,
6680 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_RIGHT,
6684 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_DOWN,
6688 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_LEFT,
6692 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_UP,
6696 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_RIGHT,
6700 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_DOWN,
6704 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_LEFT,
6708 EL_PLAYER_3, ACTION_DEFAULT, -1,
6712 EL_PLAYER_4, ACTION_DEFAULT, -1,
6721 int map_element_RND_to_EM(int element_rnd)
6723 static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
6724 static boolean mapping_initialized = FALSE;
6726 if (!mapping_initialized)
6730 /* return "Xalpha_quest" for all undefined elements in mapping array */
6731 for (i = 0; i < NUM_FILE_ELEMENTS; i++)
6732 mapping_RND_to_EM[i] = Xalpha_quest;
6734 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
6735 if (em_object_mapping_list[i].is_rnd_to_em_mapping)
6736 mapping_RND_to_EM[em_object_mapping_list[i].element_rnd] =
6737 em_object_mapping_list[i].element_em;
6739 mapping_initialized = TRUE;
6742 if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
6743 return mapping_RND_to_EM[element_rnd];
6745 Error(ERR_WARN, "invalid RND level element %d", element_rnd);
6750 int map_element_EM_to_RND(int element_em)
6752 static unsigned short mapping_EM_to_RND[TILE_MAX];
6753 static boolean mapping_initialized = FALSE;
6755 if (!mapping_initialized)
6759 /* return "EL_UNKNOWN" for all undefined elements in mapping array */
6760 for (i = 0; i < TILE_MAX; i++)
6761 mapping_EM_to_RND[i] = EL_UNKNOWN;
6763 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
6764 mapping_EM_to_RND[em_object_mapping_list[i].element_em] =
6765 em_object_mapping_list[i].element_rnd;
6767 mapping_initialized = TRUE;
6770 if (element_em >= 0 && element_em < TILE_MAX)
6771 return mapping_EM_to_RND[element_em];
6773 Error(ERR_WARN, "invalid EM level element %d", element_em);
6778 void map_android_clone_elements_RND_to_EM(struct LevelInfo *level)
6780 struct LevelInfo_EM *level_em = level->native_em_level;
6781 struct LEVEL *lev = level_em->lev;
6784 for (i = 0; i < TILE_MAX; i++)
6785 lev->android_array[i] = Xblank;
6787 for (i = 0; i < level->num_android_clone_elements; i++)
6789 int element_rnd = level->android_clone_element[i];
6790 int element_em = map_element_RND_to_EM(element_rnd);
6792 for (j = 0; em_object_mapping_list[j].element_em != -1; j++)
6793 if (em_object_mapping_list[j].element_rnd == element_rnd)
6794 lev->android_array[em_object_mapping_list[j].element_em] = element_em;
6798 void map_android_clone_elements_EM_to_RND(struct LevelInfo *level)
6800 struct LevelInfo_EM *level_em = level->native_em_level;
6801 struct LEVEL *lev = level_em->lev;
6804 level->num_android_clone_elements = 0;
6806 for (i = 0; i < TILE_MAX; i++)
6808 int element_em = lev->android_array[i];
6810 boolean element_found = FALSE;
6812 if (element_em == Xblank)
6815 element_rnd = map_element_EM_to_RND(element_em);
6817 for (j = 0; j < level->num_android_clone_elements; j++)
6818 if (level->android_clone_element[j] == element_rnd)
6819 element_found = TRUE;
6823 level->android_clone_element[level->num_android_clone_elements++] =
6826 if (level->num_android_clone_elements == MAX_ANDROID_ELEMENTS)
6831 if (level->num_android_clone_elements == 0)
6833 level->num_android_clone_elements = 1;
6834 level->android_clone_element[0] = EL_EMPTY;
6838 int map_direction_RND_to_EM(int direction)
6840 return (direction == MV_UP ? 0 :
6841 direction == MV_RIGHT ? 1 :
6842 direction == MV_DOWN ? 2 :
6843 direction == MV_LEFT ? 3 :
6847 int map_direction_EM_to_RND(int direction)
6849 return (direction == 0 ? MV_UP :
6850 direction == 1 ? MV_RIGHT :
6851 direction == 2 ? MV_DOWN :
6852 direction == 3 ? MV_LEFT :
6856 int map_element_RND_to_SP(int element_rnd)
6858 int element_sp = 0x20; /* map unknown elements to yellow "hardware" */
6860 if (element_rnd >= EL_SP_START &&
6861 element_rnd <= EL_SP_END)
6862 element_sp = element_rnd - EL_SP_START;
6863 else if (element_rnd == EL_EMPTY_SPACE)
6865 else if (element_rnd == EL_INVISIBLE_WALL)
6871 int map_element_SP_to_RND(int element_sp)
6873 int element_rnd = EL_UNKNOWN;
6875 if (element_sp >= 0x00 &&
6877 element_rnd = EL_SP_START + element_sp;
6878 else if (element_sp == 0x28)
6879 element_rnd = EL_INVISIBLE_WALL;
6884 int map_action_SP_to_RND(int action_sp)
6888 case actActive: return ACTION_ACTIVE;
6889 case actImpact: return ACTION_IMPACT;
6890 case actExploding: return ACTION_EXPLODING;
6891 case actDigging: return ACTION_DIGGING;
6892 case actSnapping: return ACTION_SNAPPING;
6893 case actCollecting: return ACTION_COLLECTING;
6894 case actPassing: return ACTION_PASSING;
6895 case actPushing: return ACTION_PUSHING;
6896 case actDropping: return ACTION_DROPPING;
6898 default: return ACTION_DEFAULT;
6902 int get_next_element(int element)
6906 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
6907 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
6908 case EL_QUICKSAND_FAST_FILLING: return EL_QUICKSAND_FAST_FULL;
6909 case EL_QUICKSAND_FAST_EMPTYING: return EL_QUICKSAND_FAST_EMPTY;
6910 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
6911 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
6912 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
6913 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
6914 case EL_DC_MAGIC_WALL_FILLING: return EL_DC_MAGIC_WALL_FULL;
6915 case EL_DC_MAGIC_WALL_EMPTYING: return EL_DC_MAGIC_WALL_ACTIVE;
6916 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
6918 default: return element;
6922 int el_act_dir2img(int element, int action, int direction)
6924 element = GFX_ELEMENT(element);
6925 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
6927 /* direction_graphic[][] == graphic[] for undefined direction graphics */
6928 return element_info[element].direction_graphic[action][direction];
6931 static int el_act_dir2crm(int element, int action, int direction)
6933 element = GFX_ELEMENT(element);
6934 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
6936 /* direction_graphic[][] == graphic[] for undefined direction graphics */
6937 return element_info[element].direction_crumbled[action][direction];
6940 int el_act2img(int element, int action)
6942 element = GFX_ELEMENT(element);
6944 return element_info[element].graphic[action];
6947 int el_act2crm(int element, int action)
6949 element = GFX_ELEMENT(element);
6951 return element_info[element].crumbled[action];
6954 int el_dir2img(int element, int direction)
6956 element = GFX_ELEMENT(element);
6958 return el_act_dir2img(element, ACTION_DEFAULT, direction);
6961 int el2baseimg(int element)
6963 return element_info[element].graphic[ACTION_DEFAULT];
6966 int el2img(int element)
6968 element = GFX_ELEMENT(element);
6970 return element_info[element].graphic[ACTION_DEFAULT];
6973 int el2edimg(int element)
6975 element = GFX_ELEMENT(element);
6977 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
6980 int el2preimg(int element)
6982 element = GFX_ELEMENT(element);
6984 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
6987 int el2panelimg(int element)
6989 element = GFX_ELEMENT(element);
6991 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PANEL];
6994 int font2baseimg(int font_nr)
6996 return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
6999 int getBeltNrFromBeltElement(int element)
7001 return (element < EL_CONVEYOR_BELT_2_LEFT ? 0 :
7002 element < EL_CONVEYOR_BELT_3_LEFT ? 1 :
7003 element < EL_CONVEYOR_BELT_4_LEFT ? 2 : 3);
7006 int getBeltNrFromBeltActiveElement(int element)
7008 return (element < EL_CONVEYOR_BELT_2_LEFT_ACTIVE ? 0 :
7009 element < EL_CONVEYOR_BELT_3_LEFT_ACTIVE ? 1 :
7010 element < EL_CONVEYOR_BELT_4_LEFT_ACTIVE ? 2 : 3);
7013 int getBeltNrFromBeltSwitchElement(int element)
7015 return (element < EL_CONVEYOR_BELT_2_SWITCH_LEFT ? 0 :
7016 element < EL_CONVEYOR_BELT_3_SWITCH_LEFT ? 1 :
7017 element < EL_CONVEYOR_BELT_4_SWITCH_LEFT ? 2 : 3);
7020 int getBeltDirNrFromBeltElement(int element)
7022 static int belt_base_element[4] =
7024 EL_CONVEYOR_BELT_1_LEFT,
7025 EL_CONVEYOR_BELT_2_LEFT,
7026 EL_CONVEYOR_BELT_3_LEFT,
7027 EL_CONVEYOR_BELT_4_LEFT
7030 int belt_nr = getBeltNrFromBeltElement(element);
7031 int belt_dir_nr = element - belt_base_element[belt_nr];
7033 return (belt_dir_nr % 3);
7036 int getBeltDirNrFromBeltSwitchElement(int element)
7038 static int belt_base_element[4] =
7040 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
7041 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
7042 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
7043 EL_CONVEYOR_BELT_4_SWITCH_LEFT
7046 int belt_nr = getBeltNrFromBeltSwitchElement(element);
7047 int belt_dir_nr = element - belt_base_element[belt_nr];
7049 return (belt_dir_nr % 3);
7052 int getBeltDirFromBeltElement(int element)
7054 static int belt_move_dir[3] =
7061 int belt_dir_nr = getBeltDirNrFromBeltElement(element);
7063 return belt_move_dir[belt_dir_nr];
7066 int getBeltDirFromBeltSwitchElement(int element)
7068 static int belt_move_dir[3] =
7075 int belt_dir_nr = getBeltDirNrFromBeltSwitchElement(element);
7077 return belt_move_dir[belt_dir_nr];
7080 int getBeltElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
7082 static int belt_base_element[4] =
7084 EL_CONVEYOR_BELT_1_LEFT,
7085 EL_CONVEYOR_BELT_2_LEFT,
7086 EL_CONVEYOR_BELT_3_LEFT,
7087 EL_CONVEYOR_BELT_4_LEFT
7090 return belt_base_element[belt_nr] + belt_dir_nr;
7093 int getBeltElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
7095 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
7097 return getBeltElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
7100 int getBeltSwitchElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
7102 static int belt_base_element[4] =
7104 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
7105 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
7106 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
7107 EL_CONVEYOR_BELT_4_SWITCH_LEFT
7110 return belt_base_element[belt_nr] + belt_dir_nr;
7113 int getBeltSwitchElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
7115 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
7117 return getBeltSwitchElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
7120 boolean getTeamMode_EM()
7122 return game.team_mode;
7125 int getGameFrameDelay_EM(int native_em_game_frame_delay)
7127 int game_frame_delay_value;
7129 game_frame_delay_value =
7130 (tape.playing && tape.fast_forward ? FfwdFrameDelay :
7131 GameFrameDelay == GAME_FRAME_DELAY ? native_em_game_frame_delay :
7134 if (tape.playing && tape.warp_forward && !tape.pausing)
7135 game_frame_delay_value = 0;
7137 return game_frame_delay_value;
7140 unsigned int InitRND(int seed)
7142 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
7143 return InitEngineRandom_EM(seed);
7144 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
7145 return InitEngineRandom_SP(seed);
7147 return InitEngineRandom_RND(seed);
7150 static struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
7151 static struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
7153 inline static int get_effective_element_EM(int tile, int frame_em)
7155 int element = object_mapping[tile].element_rnd;
7156 int action = object_mapping[tile].action;
7157 boolean is_backside = object_mapping[tile].is_backside;
7158 boolean action_removing = (action == ACTION_DIGGING ||
7159 action == ACTION_SNAPPING ||
7160 action == ACTION_COLLECTING);
7166 case Yacid_splash_eB:
7167 case Yacid_splash_wB:
7168 return (frame_em > 5 ? EL_EMPTY : element);
7174 else /* frame_em == 7 */
7178 case Yacid_splash_eB:
7179 case Yacid_splash_wB:
7182 case Yemerald_stone:
7185 case Ydiamond_stone:
7189 case Xdrip_stretchB:
7208 case Xsand_stonein_1:
7209 case Xsand_stonein_2:
7210 case Xsand_stonein_3:
7211 case Xsand_stonein_4:
7215 return (is_backside || action_removing ? EL_EMPTY : element);
7220 inline static boolean check_linear_animation_EM(int tile)
7224 case Xsand_stonesand_1:
7225 case Xsand_stonesand_quickout_1:
7226 case Xsand_sandstone_1:
7227 case Xsand_stonein_1:
7228 case Xsand_stoneout_1:
7247 case Yacid_splash_eB:
7248 case Yacid_splash_wB:
7249 case Yemerald_stone:
7256 inline static void set_crumbled_graphics_EM(struct GraphicInfo_EM *g_em,
7257 boolean has_crumbled_graphics,
7258 int crumbled, int sync_frame)
7260 /* if element can be crumbled, but certain action graphics are just empty
7261 space (like instantly snapping sand to empty space in 1 frame), do not
7262 treat these empty space graphics as crumbled graphics in EMC engine */
7263 if (crumbled == IMG_EMPTY_SPACE)
7264 has_crumbled_graphics = FALSE;
7266 if (has_crumbled_graphics)
7268 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
7269 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
7270 g_crumbled->anim_delay,
7271 g_crumbled->anim_mode,
7272 g_crumbled->anim_start_frame,
7275 getGraphicSource(crumbled, frame_crumbled, &g_em->crumbled_bitmap,
7276 &g_em->crumbled_src_x, &g_em->crumbled_src_y);
7278 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
7280 g_em->has_crumbled_graphics = TRUE;
7284 g_em->crumbled_bitmap = NULL;
7285 g_em->crumbled_src_x = 0;
7286 g_em->crumbled_src_y = 0;
7287 g_em->crumbled_border_size = 0;
7289 g_em->has_crumbled_graphics = FALSE;
7293 void ResetGfxAnimation_EM(int x, int y, int tile)
7298 void SetGfxAnimation_EM(struct GraphicInfo_EM *g_em,
7299 int tile, int frame_em, int x, int y)
7301 int action = object_mapping[tile].action;
7302 int direction = object_mapping[tile].direction;
7303 int effective_element = get_effective_element_EM(tile, frame_em);
7304 int graphic = (direction == MV_NONE ?
7305 el_act2img(effective_element, action) :
7306 el_act_dir2img(effective_element, action, direction));
7307 struct GraphicInfo *g = &graphic_info[graphic];
7309 boolean action_removing = (action == ACTION_DIGGING ||
7310 action == ACTION_SNAPPING ||
7311 action == ACTION_COLLECTING);
7312 boolean action_moving = (action == ACTION_FALLING ||
7313 action == ACTION_MOVING ||
7314 action == ACTION_PUSHING ||
7315 action == ACTION_EATING ||
7316 action == ACTION_FILLING ||
7317 action == ACTION_EMPTYING);
7318 boolean action_falling = (action == ACTION_FALLING ||
7319 action == ACTION_FILLING ||
7320 action == ACTION_EMPTYING);
7322 /* special case: graphic uses "2nd movement tile" and has defined
7323 7 frames for movement animation (or less) => use default graphic
7324 for last (8th) frame which ends the movement animation */
7325 if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
7327 action = ACTION_DEFAULT; /* (keep action_* unchanged for now) */
7328 graphic = (direction == MV_NONE ?
7329 el_act2img(effective_element, action) :
7330 el_act_dir2img(effective_element, action, direction));
7332 g = &graphic_info[graphic];
7335 if ((action_removing || check_linear_animation_EM(tile)) && frame_em == 0)
7339 else if (action_moving)
7341 boolean is_backside = object_mapping[tile].is_backside;
7345 int direction = object_mapping[tile].direction;
7346 int move_dir = (action_falling ? MV_DOWN : direction);
7351 /* !!! TEST !!! NEW !!! DOES NOT WORK RIGHT YET !!! */
7352 if (g->double_movement && frame_em == 0)
7356 if (move_dir == MV_LEFT)
7357 GfxFrame[x - 1][y] = GfxFrame[x][y];
7358 else if (move_dir == MV_RIGHT)
7359 GfxFrame[x + 1][y] = GfxFrame[x][y];
7360 else if (move_dir == MV_UP)
7361 GfxFrame[x][y - 1] = GfxFrame[x][y];
7362 else if (move_dir == MV_DOWN)
7363 GfxFrame[x][y + 1] = GfxFrame[x][y];
7370 /* special case: animation for Xsand_stonesand_quickout_1/2 twice as fast */
7371 if (tile == Xsand_stonesand_quickout_1 ||
7372 tile == Xsand_stonesand_quickout_2)
7376 if (graphic_info[graphic].anim_global_sync)
7377 sync_frame = FrameCounter;
7378 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
7379 sync_frame = GfxFrame[x][y];
7381 sync_frame = 0; /* playfield border (pseudo steel) */
7383 SetRandomAnimationValue(x, y);
7385 int frame = getAnimationFrame(g->anim_frames,
7388 g->anim_start_frame,
7391 g_em->unique_identifier =
7392 (graphic << 16) | ((frame % 8) << 12) | (g_em->width << 6) | g_em->height;
7395 void getGraphicSourceObjectExt_EM(struct GraphicInfo_EM *g_em,
7396 int tile, int frame_em, int x, int y)
7398 int action = object_mapping[tile].action;
7399 int direction = object_mapping[tile].direction;
7400 boolean is_backside = object_mapping[tile].is_backside;
7401 int effective_element = get_effective_element_EM(tile, frame_em);
7402 int effective_action = action;
7403 int graphic = (direction == MV_NONE ?
7404 el_act2img(effective_element, effective_action) :
7405 el_act_dir2img(effective_element, effective_action,
7407 int crumbled = (direction == MV_NONE ?
7408 el_act2crm(effective_element, effective_action) :
7409 el_act_dir2crm(effective_element, effective_action,
7411 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
7412 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
7413 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
7414 struct GraphicInfo *g = &graphic_info[graphic];
7417 /* special case: graphic uses "2nd movement tile" and has defined
7418 7 frames for movement animation (or less) => use default graphic
7419 for last (8th) frame which ends the movement animation */
7420 if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
7422 effective_action = ACTION_DEFAULT;
7423 graphic = (direction == MV_NONE ?
7424 el_act2img(effective_element, effective_action) :
7425 el_act_dir2img(effective_element, effective_action,
7427 crumbled = (direction == MV_NONE ?
7428 el_act2crm(effective_element, effective_action) :
7429 el_act_dir2crm(effective_element, effective_action,
7432 g = &graphic_info[graphic];
7435 if (graphic_info[graphic].anim_global_sync)
7436 sync_frame = FrameCounter;
7437 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
7438 sync_frame = GfxFrame[x][y];
7440 sync_frame = 0; /* playfield border (pseudo steel) */
7442 SetRandomAnimationValue(x, y);
7444 int frame = getAnimationFrame(g->anim_frames,
7447 g->anim_start_frame,
7450 getGraphicSourceExt(graphic, frame, &g_em->bitmap, &g_em->src_x, &g_em->src_y,
7451 g->double_movement && is_backside);
7453 /* (updating the "crumbled" graphic definitions is probably not really needed,
7454 as animations for crumbled graphics can't be longer than one EMC cycle) */
7455 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
7459 void getGraphicSourcePlayerExt_EM(struct GraphicInfo_EM *g_em,
7460 int player_nr, int anim, int frame_em)
7462 int element = player_mapping[player_nr][anim].element_rnd;
7463 int action = player_mapping[player_nr][anim].action;
7464 int direction = player_mapping[player_nr][anim].direction;
7465 int graphic = (direction == MV_NONE ?
7466 el_act2img(element, action) :
7467 el_act_dir2img(element, action, direction));
7468 struct GraphicInfo *g = &graphic_info[graphic];
7471 InitPlayerGfxAnimation(&stored_player[player_nr], action, direction);
7473 stored_player[player_nr].StepFrame = frame_em;
7475 sync_frame = stored_player[player_nr].Frame;
7477 int frame = getAnimationFrame(g->anim_frames,
7480 g->anim_start_frame,
7483 getGraphicSourceExt(graphic, frame, &g_em->bitmap,
7484 &g_em->src_x, &g_em->src_y, FALSE);
7487 void InitGraphicInfo_EM(void)
7492 int num_em_gfx_errors = 0;
7494 if (graphic_info_em_object[0][0].bitmap == NULL)
7496 /* EM graphics not yet initialized in em_open_all() */
7501 printf("::: [4 errors can be ignored (1 x 'bomb', 3 x 'em_dynamite']\n");
7504 /* always start with reliable default values */
7505 for (i = 0; i < TILE_MAX; i++)
7507 object_mapping[i].element_rnd = EL_UNKNOWN;
7508 object_mapping[i].is_backside = FALSE;
7509 object_mapping[i].action = ACTION_DEFAULT;
7510 object_mapping[i].direction = MV_NONE;
7513 /* always start with reliable default values */
7514 for (p = 0; p < MAX_PLAYERS; p++)
7516 for (i = 0; i < SPR_MAX; i++)
7518 player_mapping[p][i].element_rnd = EL_UNKNOWN;
7519 player_mapping[p][i].action = ACTION_DEFAULT;
7520 player_mapping[p][i].direction = MV_NONE;
7524 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
7526 int e = em_object_mapping_list[i].element_em;
7528 object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd;
7529 object_mapping[e].is_backside = em_object_mapping_list[i].is_backside;
7531 if (em_object_mapping_list[i].action != -1)
7532 object_mapping[e].action = em_object_mapping_list[i].action;
7534 if (em_object_mapping_list[i].direction != -1)
7535 object_mapping[e].direction =
7536 MV_DIR_FROM_BIT(em_object_mapping_list[i].direction);
7539 for (i = 0; em_player_mapping_list[i].action_em != -1; i++)
7541 int a = em_player_mapping_list[i].action_em;
7542 int p = em_player_mapping_list[i].player_nr;
7544 player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd;
7546 if (em_player_mapping_list[i].action != -1)
7547 player_mapping[p][a].action = em_player_mapping_list[i].action;
7549 if (em_player_mapping_list[i].direction != -1)
7550 player_mapping[p][a].direction =
7551 MV_DIR_FROM_BIT(em_player_mapping_list[i].direction);
7554 for (i = 0; i < TILE_MAX; i++)
7556 int element = object_mapping[i].element_rnd;
7557 int action = object_mapping[i].action;
7558 int direction = object_mapping[i].direction;
7559 boolean is_backside = object_mapping[i].is_backside;
7560 boolean action_exploding = ((action == ACTION_EXPLODING ||
7561 action == ACTION_SMASHED_BY_ROCK ||
7562 action == ACTION_SMASHED_BY_SPRING) &&
7563 element != EL_DIAMOND);
7564 boolean action_active = (action == ACTION_ACTIVE);
7565 boolean action_other = (action == ACTION_OTHER);
7567 for (j = 0; j < 8; j++)
7569 int effective_element = get_effective_element_EM(i, j);
7570 int effective_action = (j < 7 ? action :
7571 i == Xdrip_stretch ? action :
7572 i == Xdrip_stretchB ? action :
7573 i == Ydrip_s1 ? action :
7574 i == Ydrip_s1B ? action :
7575 i == Xball_1B ? action :
7576 i == Xball_2 ? action :
7577 i == Xball_2B ? action :
7578 i == Yball_eat ? action :
7579 i == Ykey_1_eat ? action :
7580 i == Ykey_2_eat ? action :
7581 i == Ykey_3_eat ? action :
7582 i == Ykey_4_eat ? action :
7583 i == Ykey_5_eat ? action :
7584 i == Ykey_6_eat ? action :
7585 i == Ykey_7_eat ? action :
7586 i == Ykey_8_eat ? action :
7587 i == Ylenses_eat ? action :
7588 i == Ymagnify_eat ? action :
7589 i == Ygrass_eat ? action :
7590 i == Ydirt_eat ? action :
7591 i == Xsand_stonein_1 ? action :
7592 i == Xsand_stonein_2 ? action :
7593 i == Xsand_stonein_3 ? action :
7594 i == Xsand_stonein_4 ? action :
7595 i == Xsand_stoneout_1 ? action :
7596 i == Xsand_stoneout_2 ? action :
7597 i == Xboom_android ? ACTION_EXPLODING :
7598 action_exploding ? ACTION_EXPLODING :
7599 action_active ? action :
7600 action_other ? action :
7602 int graphic = (el_act_dir2img(effective_element, effective_action,
7604 int crumbled = (el_act_dir2crm(effective_element, effective_action,
7606 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
7607 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
7608 boolean has_action_graphics = (graphic != base_graphic);
7609 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
7610 struct GraphicInfo *g = &graphic_info[graphic];
7611 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
7614 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
7615 boolean special_animation = (action != ACTION_DEFAULT &&
7616 g->anim_frames == 3 &&
7617 g->anim_delay == 2 &&
7618 g->anim_mode & ANIM_LINEAR);
7619 int sync_frame = (i == Xdrip_stretch ? 7 :
7620 i == Xdrip_stretchB ? 7 :
7621 i == Ydrip_s2 ? j + 8 :
7622 i == Ydrip_s2B ? j + 8 :
7631 i == Xfake_acid_1 ? 0 :
7632 i == Xfake_acid_2 ? 10 :
7633 i == Xfake_acid_3 ? 20 :
7634 i == Xfake_acid_4 ? 30 :
7635 i == Xfake_acid_5 ? 40 :
7636 i == Xfake_acid_6 ? 50 :
7637 i == Xfake_acid_7 ? 60 :
7638 i == Xfake_acid_8 ? 70 :
7640 i == Xball_2B ? j + 8 :
7641 i == Yball_eat ? j + 1 :
7642 i == Ykey_1_eat ? j + 1 :
7643 i == Ykey_2_eat ? j + 1 :
7644 i == Ykey_3_eat ? j + 1 :
7645 i == Ykey_4_eat ? j + 1 :
7646 i == Ykey_5_eat ? j + 1 :
7647 i == Ykey_6_eat ? j + 1 :
7648 i == Ykey_7_eat ? j + 1 :
7649 i == Ykey_8_eat ? j + 1 :
7650 i == Ylenses_eat ? j + 1 :
7651 i == Ymagnify_eat ? j + 1 :
7652 i == Ygrass_eat ? j + 1 :
7653 i == Ydirt_eat ? j + 1 :
7654 i == Xamoeba_1 ? 0 :
7655 i == Xamoeba_2 ? 1 :
7656 i == Xamoeba_3 ? 2 :
7657 i == Xamoeba_4 ? 3 :
7658 i == Xamoeba_5 ? 0 :
7659 i == Xamoeba_6 ? 1 :
7660 i == Xamoeba_7 ? 2 :
7661 i == Xamoeba_8 ? 3 :
7662 i == Xexit_2 ? j + 8 :
7663 i == Xexit_3 ? j + 16 :
7664 i == Xdynamite_1 ? 0 :
7665 i == Xdynamite_2 ? 8 :
7666 i == Xdynamite_3 ? 16 :
7667 i == Xdynamite_4 ? 24 :
7668 i == Xsand_stonein_1 ? j + 1 :
7669 i == Xsand_stonein_2 ? j + 9 :
7670 i == Xsand_stonein_3 ? j + 17 :
7671 i == Xsand_stonein_4 ? j + 25 :
7672 i == Xsand_stoneout_1 && j == 0 ? 0 :
7673 i == Xsand_stoneout_1 && j == 1 ? 0 :
7674 i == Xsand_stoneout_1 && j == 2 ? 1 :
7675 i == Xsand_stoneout_1 && j == 3 ? 2 :
7676 i == Xsand_stoneout_1 && j == 4 ? 2 :
7677 i == Xsand_stoneout_1 && j == 5 ? 3 :
7678 i == Xsand_stoneout_1 && j == 6 ? 4 :
7679 i == Xsand_stoneout_1 && j == 7 ? 4 :
7680 i == Xsand_stoneout_2 && j == 0 ? 5 :
7681 i == Xsand_stoneout_2 && j == 1 ? 6 :
7682 i == Xsand_stoneout_2 && j == 2 ? 7 :
7683 i == Xsand_stoneout_2 && j == 3 ? 8 :
7684 i == Xsand_stoneout_2 && j == 4 ? 9 :
7685 i == Xsand_stoneout_2 && j == 5 ? 11 :
7686 i == Xsand_stoneout_2 && j == 6 ? 13 :
7687 i == Xsand_stoneout_2 && j == 7 ? 15 :
7688 i == Xboom_bug && j == 1 ? 2 :
7689 i == Xboom_bug && j == 2 ? 2 :
7690 i == Xboom_bug && j == 3 ? 4 :
7691 i == Xboom_bug && j == 4 ? 4 :
7692 i == Xboom_bug && j == 5 ? 2 :
7693 i == Xboom_bug && j == 6 ? 2 :
7694 i == Xboom_bug && j == 7 ? 0 :
7695 i == Xboom_bomb && j == 1 ? 2 :
7696 i == Xboom_bomb && j == 2 ? 2 :
7697 i == Xboom_bomb && j == 3 ? 4 :
7698 i == Xboom_bomb && j == 4 ? 4 :
7699 i == Xboom_bomb && j == 5 ? 2 :
7700 i == Xboom_bomb && j == 6 ? 2 :
7701 i == Xboom_bomb && j == 7 ? 0 :
7702 i == Xboom_android && j == 7 ? 6 :
7703 i == Xboom_1 && j == 1 ? 2 :
7704 i == Xboom_1 && j == 2 ? 2 :
7705 i == Xboom_1 && j == 3 ? 4 :
7706 i == Xboom_1 && j == 4 ? 4 :
7707 i == Xboom_1 && j == 5 ? 6 :
7708 i == Xboom_1 && j == 6 ? 6 :
7709 i == Xboom_1 && j == 7 ? 8 :
7710 i == Xboom_2 && j == 0 ? 8 :
7711 i == Xboom_2 && j == 1 ? 8 :
7712 i == Xboom_2 && j == 2 ? 10 :
7713 i == Xboom_2 && j == 3 ? 10 :
7714 i == Xboom_2 && j == 4 ? 10 :
7715 i == Xboom_2 && j == 5 ? 12 :
7716 i == Xboom_2 && j == 6 ? 12 :
7717 i == Xboom_2 && j == 7 ? 12 :
7718 special_animation && j == 4 ? 3 :
7719 effective_action != action ? 0 :
7723 Bitmap *debug_bitmap = g_em->bitmap;
7724 int debug_src_x = g_em->src_x;
7725 int debug_src_y = g_em->src_y;
7728 int frame = getAnimationFrame(g->anim_frames,
7731 g->anim_start_frame,
7734 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y,
7735 g->double_movement && is_backside);
7737 g_em->bitmap = src_bitmap;
7738 g_em->src_x = src_x;
7739 g_em->src_y = src_y;
7740 g_em->src_offset_x = 0;
7741 g_em->src_offset_y = 0;
7742 g_em->dst_offset_x = 0;
7743 g_em->dst_offset_y = 0;
7744 g_em->width = TILEX;
7745 g_em->height = TILEY;
7747 g_em->preserve_background = FALSE;
7749 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
7752 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
7753 effective_action == ACTION_MOVING ||
7754 effective_action == ACTION_PUSHING ||
7755 effective_action == ACTION_EATING)) ||
7756 (!has_action_graphics && (effective_action == ACTION_FILLING ||
7757 effective_action == ACTION_EMPTYING)))
7760 (effective_action == ACTION_FALLING ||
7761 effective_action == ACTION_FILLING ||
7762 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
7763 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
7764 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
7765 int num_steps = (i == Ydrip_s1 ? 16 :
7766 i == Ydrip_s1B ? 16 :
7767 i == Ydrip_s2 ? 16 :
7768 i == Ydrip_s2B ? 16 :
7769 i == Xsand_stonein_1 ? 32 :
7770 i == Xsand_stonein_2 ? 32 :
7771 i == Xsand_stonein_3 ? 32 :
7772 i == Xsand_stonein_4 ? 32 :
7773 i == Xsand_stoneout_1 ? 16 :
7774 i == Xsand_stoneout_2 ? 16 : 8);
7775 int cx = ABS(dx) * (TILEX / num_steps);
7776 int cy = ABS(dy) * (TILEY / num_steps);
7777 int step_frame = (i == Ydrip_s2 ? j + 8 :
7778 i == Ydrip_s2B ? j + 8 :
7779 i == Xsand_stonein_2 ? j + 8 :
7780 i == Xsand_stonein_3 ? j + 16 :
7781 i == Xsand_stonein_4 ? j + 24 :
7782 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
7783 int step = (is_backside ? step_frame : num_steps - step_frame);
7785 if (is_backside) /* tile where movement starts */
7787 if (dx < 0 || dy < 0)
7789 g_em->src_offset_x = cx * step;
7790 g_em->src_offset_y = cy * step;
7794 g_em->dst_offset_x = cx * step;
7795 g_em->dst_offset_y = cy * step;
7798 else /* tile where movement ends */
7800 if (dx < 0 || dy < 0)
7802 g_em->dst_offset_x = cx * step;
7803 g_em->dst_offset_y = cy * step;
7807 g_em->src_offset_x = cx * step;
7808 g_em->src_offset_y = cy * step;
7812 g_em->width = TILEX - cx * step;
7813 g_em->height = TILEY - cy * step;
7816 /* create unique graphic identifier to decide if tile must be redrawn */
7817 /* bit 31 - 16 (16 bit): EM style graphic
7818 bit 15 - 12 ( 4 bit): EM style frame
7819 bit 11 - 6 ( 6 bit): graphic width
7820 bit 5 - 0 ( 6 bit): graphic height */
7821 g_em->unique_identifier =
7822 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
7826 /* skip check for EMC elements not contained in original EMC artwork */
7827 if (element == EL_EMC_FAKE_ACID)
7830 if (g_em->bitmap != debug_bitmap ||
7831 g_em->src_x != debug_src_x ||
7832 g_em->src_y != debug_src_y ||
7833 g_em->src_offset_x != 0 ||
7834 g_em->src_offset_y != 0 ||
7835 g_em->dst_offset_x != 0 ||
7836 g_em->dst_offset_y != 0 ||
7837 g_em->width != TILEX ||
7838 g_em->height != TILEY)
7840 static int last_i = -1;
7848 printf("::: EMC GFX ERROR for element %d -> %d ('%s', '%s', %d)",
7849 i, element, element_info[element].token_name,
7850 element_action_info[effective_action].suffix, direction);
7852 if (element != effective_element)
7853 printf(" [%d ('%s')]",
7855 element_info[effective_element].token_name);
7859 if (g_em->bitmap != debug_bitmap)
7860 printf(" %d (%d): different bitmap! (0x%08x != 0x%08x)\n",
7861 j, is_backside, (int)(g_em->bitmap), (int)(debug_bitmap));
7863 if (g_em->src_x != debug_src_x ||
7864 g_em->src_y != debug_src_y)
7865 printf(" frame %d (%c): %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
7866 j, (is_backside ? 'B' : 'F'),
7867 g_em->src_x, g_em->src_y,
7868 g_em->src_x / 32, g_em->src_y / 32,
7869 debug_src_x, debug_src_y,
7870 debug_src_x / 32, debug_src_y / 32);
7872 if (g_em->src_offset_x != 0 ||
7873 g_em->src_offset_y != 0 ||
7874 g_em->dst_offset_x != 0 ||
7875 g_em->dst_offset_y != 0)
7876 printf(" %d (%d): offsets %d,%d and %d,%d should be all 0\n",
7878 g_em->src_offset_x, g_em->src_offset_y,
7879 g_em->dst_offset_x, g_em->dst_offset_y);
7881 if (g_em->width != TILEX ||
7882 g_em->height != TILEY)
7883 printf(" %d (%d): size %d,%d should be %d,%d\n",
7885 g_em->width, g_em->height, TILEX, TILEY);
7887 num_em_gfx_errors++;
7894 for (i = 0; i < TILE_MAX; i++)
7896 for (j = 0; j < 8; j++)
7898 int element = object_mapping[i].element_rnd;
7899 int action = object_mapping[i].action;
7900 int direction = object_mapping[i].direction;
7901 boolean is_backside = object_mapping[i].is_backside;
7902 int graphic_action = el_act_dir2img(element, action, direction);
7903 int graphic_default = el_act_dir2img(element, ACTION_DEFAULT, direction);
7905 if ((action == ACTION_SMASHED_BY_ROCK ||
7906 action == ACTION_SMASHED_BY_SPRING ||
7907 action == ACTION_EATING) &&
7908 graphic_action == graphic_default)
7910 int e = (action == ACTION_SMASHED_BY_ROCK ? Ystone_s :
7911 action == ACTION_SMASHED_BY_SPRING ? Yspring_s :
7912 direction == MV_LEFT ? (is_backside? Yspring_wB: Yspring_w) :
7913 direction == MV_RIGHT ? (is_backside? Yspring_eB: Yspring_e) :
7916 /* no separate animation for "smashed by rock" -- use rock instead */
7917 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
7918 struct GraphicInfo_EM *g_xx = &graphic_info_em_object[e][7 - j];
7920 g_em->bitmap = g_xx->bitmap;
7921 g_em->src_x = g_xx->src_x;
7922 g_em->src_y = g_xx->src_y;
7923 g_em->src_offset_x = g_xx->src_offset_x;
7924 g_em->src_offset_y = g_xx->src_offset_y;
7925 g_em->dst_offset_x = g_xx->dst_offset_x;
7926 g_em->dst_offset_y = g_xx->dst_offset_y;
7927 g_em->width = g_xx->width;
7928 g_em->height = g_xx->height;
7929 g_em->unique_identifier = g_xx->unique_identifier;
7932 g_em->preserve_background = TRUE;
7937 for (p = 0; p < MAX_PLAYERS; p++)
7939 for (i = 0; i < SPR_MAX; i++)
7941 int element = player_mapping[p][i].element_rnd;
7942 int action = player_mapping[p][i].action;
7943 int direction = player_mapping[p][i].direction;
7945 for (j = 0; j < 8; j++)
7947 int effective_element = element;
7948 int effective_action = action;
7949 int graphic = (direction == MV_NONE ?
7950 el_act2img(effective_element, effective_action) :
7951 el_act_dir2img(effective_element, effective_action,
7953 struct GraphicInfo *g = &graphic_info[graphic];
7954 struct GraphicInfo_EM *g_em = &graphic_info_em_player[p][i][7 - j];
7960 Bitmap *debug_bitmap = g_em->bitmap;
7961 int debug_src_x = g_em->src_x;
7962 int debug_src_y = g_em->src_y;
7965 int frame = getAnimationFrame(g->anim_frames,
7968 g->anim_start_frame,
7971 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
7973 g_em->bitmap = src_bitmap;
7974 g_em->src_x = src_x;
7975 g_em->src_y = src_y;
7976 g_em->src_offset_x = 0;
7977 g_em->src_offset_y = 0;
7978 g_em->dst_offset_x = 0;
7979 g_em->dst_offset_y = 0;
7980 g_em->width = TILEX;
7981 g_em->height = TILEY;
7985 /* skip check for EMC elements not contained in original EMC artwork */
7986 if (element == EL_PLAYER_3 ||
7987 element == EL_PLAYER_4)
7990 if (g_em->bitmap != debug_bitmap ||
7991 g_em->src_x != debug_src_x ||
7992 g_em->src_y != debug_src_y)
7994 static int last_i = -1;
8002 printf("::: EMC GFX ERROR for p/a %d/%d -> %d ('%s', '%s', %d)",
8003 p, i, element, element_info[element].token_name,
8004 element_action_info[effective_action].suffix, direction);
8006 if (element != effective_element)
8007 printf(" [%d ('%s')]",
8009 element_info[effective_element].token_name);
8013 if (g_em->bitmap != debug_bitmap)
8014 printf(" %d: different bitmap! (0x%08x != 0x%08x)\n",
8015 j, (int)(g_em->bitmap), (int)(debug_bitmap));
8017 if (g_em->src_x != debug_src_x ||
8018 g_em->src_y != debug_src_y)
8019 printf(" frame %d: %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
8021 g_em->src_x, g_em->src_y,
8022 g_em->src_x / 32, g_em->src_y / 32,
8023 debug_src_x, debug_src_y,
8024 debug_src_x / 32, debug_src_y / 32);
8026 num_em_gfx_errors++;
8036 printf("::: [%d errors found]\n", num_em_gfx_errors);
8042 void CheckSaveEngineSnapshot_EM(byte action[MAX_PLAYERS], int frame,
8043 boolean any_player_moving,
8044 boolean any_player_snapping,
8045 boolean any_player_dropping)
8047 static boolean player_was_waiting = TRUE;
8049 if (frame == 0 && !any_player_dropping)
8051 if (!player_was_waiting)
8053 if (!SaveEngineSnapshotToList())
8056 player_was_waiting = TRUE;
8059 else if (any_player_moving || any_player_snapping || any_player_dropping)
8061 player_was_waiting = FALSE;
8065 void CheckSaveEngineSnapshot_SP(boolean murphy_is_waiting,
8066 boolean murphy_is_dropping)
8068 static boolean player_was_waiting = TRUE;
8070 if (murphy_is_waiting)
8072 if (!player_was_waiting)
8074 if (!SaveEngineSnapshotToList())
8077 player_was_waiting = TRUE;
8082 player_was_waiting = FALSE;
8086 void CheckSingleStepMode_EM(byte action[MAX_PLAYERS], int frame,
8087 boolean any_player_moving,
8088 boolean any_player_snapping,
8089 boolean any_player_dropping)
8091 if (tape.single_step && tape.recording && !tape.pausing)
8092 if (frame == 0 && !any_player_dropping)
8093 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
8095 CheckSaveEngineSnapshot_EM(action, frame, any_player_moving,
8096 any_player_snapping, any_player_dropping);
8099 void CheckSingleStepMode_SP(boolean murphy_is_waiting,
8100 boolean murphy_is_dropping)
8102 if (tape.single_step && tape.recording && !tape.pausing)
8103 if (murphy_is_waiting)
8104 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
8106 CheckSaveEngineSnapshot_SP(murphy_is_waiting, murphy_is_dropping);
8109 void getGraphicSource_SP(struct GraphicInfo_SP *g_sp,
8110 int graphic, int sync_frame, int x, int y)
8112 int frame = getGraphicAnimationFrame(graphic, sync_frame);
8114 getGraphicSource(graphic, frame, &g_sp->bitmap, &g_sp->src_x, &g_sp->src_y);
8117 boolean isNextAnimationFrame_SP(int graphic, int sync_frame)
8119 return (IS_NEXT_FRAME(sync_frame, graphic));
8122 int getGraphicInfo_Delay(int graphic)
8124 return graphic_info[graphic].anim_delay;
8127 void PlayMenuSoundExt(int sound)
8129 if (sound == SND_UNDEFINED)
8132 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
8133 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
8136 if (IS_LOOP_SOUND(sound))
8137 PlaySoundLoop(sound);
8142 void PlayMenuSound()
8144 PlayMenuSoundExt(menu.sound[game_status]);
8147 void PlayMenuSoundStereo(int sound, int stereo_position)
8149 if (sound == SND_UNDEFINED)
8152 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
8153 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
8156 if (IS_LOOP_SOUND(sound))
8157 PlaySoundExt(sound, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_LOOP);
8159 PlaySoundStereo(sound, stereo_position);
8162 void PlayMenuSoundIfLoopExt(int sound)
8164 if (sound == SND_UNDEFINED)
8167 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
8168 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
8171 if (IS_LOOP_SOUND(sound))
8172 PlaySoundLoop(sound);
8175 void PlayMenuSoundIfLoop()
8177 PlayMenuSoundIfLoopExt(menu.sound[game_status]);
8180 void PlayMenuMusicExt(int music)
8182 if (music == MUS_UNDEFINED)
8185 if (!setup.sound_music)
8191 void PlayMenuMusic()
8193 PlayMenuMusicExt(menu.music[game_status]);
8196 void PlaySoundActivating()
8199 PlaySound(SND_MENU_ITEM_ACTIVATING);
8203 void PlaySoundSelecting()
8206 PlaySound(SND_MENU_ITEM_SELECTING);
8210 void ToggleFullscreenOrChangeWindowScalingIfNeeded()
8212 boolean change_fullscreen = (setup.fullscreen !=
8213 video.fullscreen_enabled);
8214 boolean change_fullscreen_mode = (video.fullscreen_enabled &&
8215 !strEqual(setup.fullscreen_mode,
8216 video.fullscreen_mode_current));
8217 boolean change_window_scaling_percent = (!video.fullscreen_enabled &&
8218 setup.window_scaling_percent !=
8219 video.window_scaling_percent);
8221 if (change_window_scaling_percent && video.fullscreen_enabled)
8224 if (!change_window_scaling_percent && !video.fullscreen_available)
8227 #if defined(TARGET_SDL2)
8228 if (change_window_scaling_percent)
8230 SDLSetWindowScaling(setup.window_scaling_percent);
8234 else if (change_fullscreen)
8236 SDLSetWindowFullscreen(setup.fullscreen);
8238 /* set setup value according to successfully changed fullscreen mode */
8239 setup.fullscreen = video.fullscreen_enabled;
8245 if (change_fullscreen ||
8246 change_fullscreen_mode ||
8247 change_window_scaling_percent)
8249 Bitmap *tmp_backbuffer = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
8251 /* save backbuffer content which gets lost when toggling fullscreen mode */
8252 BlitBitmap(backbuffer, tmp_backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
8254 if (change_fullscreen_mode)
8256 /* keep fullscreen, but change fullscreen mode (screen resolution) */
8257 video.fullscreen_enabled = FALSE; /* force new fullscreen mode */
8260 if (change_window_scaling_percent)
8262 /* keep window mode, but change window scaling */
8263 video.fullscreen_enabled = TRUE; /* force new window scaling */
8266 /* toggle fullscreen */
8267 ChangeVideoModeIfNeeded(setup.fullscreen);
8269 /* set setup value according to successfully changed fullscreen mode */
8270 setup.fullscreen = video.fullscreen_enabled;
8272 /* restore backbuffer content from temporary backbuffer backup bitmap */
8273 BlitBitmap(tmp_backbuffer, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
8275 FreeBitmap(tmp_backbuffer);
8277 /* update visible window/screen */
8278 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
8282 void JoinRectangles(int *x, int *y, int *width, int *height,
8283 int x2, int y2, int width2, int height2)
8285 // do not join with "off-screen" rectangle
8286 if (x2 == -1 || y2 == -1)
8291 *width = MAX(*width, width2);
8292 *height = MAX(*height, height2);
8295 void SetGameStatus(int game_status_new)
8297 game_status = game_status_new;
8299 global.anim_status_next = game_status;
8302 void ChangeViewportPropertiesIfNeeded()
8304 int gfx_game_mode = game_status;
8305 int gfx_game_mode2 = (game_status == GAME_MODE_EDITOR ? GAME_MODE_DEFAULT :
8307 struct RectWithBorder *vp_window = &viewport.window[gfx_game_mode];
8308 struct RectWithBorder *vp_playfield = &viewport.playfield[gfx_game_mode];
8309 struct RectWithBorder *vp_door_1 = &viewport.door_1[gfx_game_mode];
8310 struct RectWithBorder *vp_door_2 = &viewport.door_2[gfx_game_mode2];
8311 struct RectWithBorder *vp_door_3 = &viewport.door_2[GAME_MODE_EDITOR];
8312 int new_win_xsize = vp_window->width;
8313 int new_win_ysize = vp_window->height;
8314 int border_size = vp_playfield->border_size;
8315 int new_sx = vp_playfield->x + border_size;
8316 int new_sy = vp_playfield->y + border_size;
8317 int new_sxsize = vp_playfield->width - 2 * border_size;
8318 int new_sysize = vp_playfield->height - 2 * border_size;
8319 int new_real_sx = vp_playfield->x;
8320 int new_real_sy = vp_playfield->y;
8321 int new_full_sxsize = vp_playfield->width;
8322 int new_full_sysize = vp_playfield->height;
8323 int new_dx = vp_door_1->x;
8324 int new_dy = vp_door_1->y;
8325 int new_dxsize = vp_door_1->width;
8326 int new_dysize = vp_door_1->height;
8327 int new_vx = vp_door_2->x;
8328 int new_vy = vp_door_2->y;
8329 int new_vxsize = vp_door_2->width;
8330 int new_vysize = vp_door_2->height;
8331 int new_ex = vp_door_3->x;
8332 int new_ey = vp_door_3->y;
8333 int new_exsize = vp_door_3->width;
8334 int new_eysize = vp_door_3->height;
8335 int new_tilesize_var =
8336 (setup.small_game_graphics ? MINI_TILESIZE : game.tile_size);
8338 int tilesize = (gfx_game_mode == GAME_MODE_PLAYING ? new_tilesize_var :
8339 gfx_game_mode == GAME_MODE_EDITOR ? MINI_TILESIZE : TILESIZE);
8340 int new_scr_fieldx = new_sxsize / tilesize;
8341 int new_scr_fieldy = new_sysize / tilesize;
8342 int new_scr_fieldx_buffers = new_sxsize / new_tilesize_var;
8343 int new_scr_fieldy_buffers = new_sysize / new_tilesize_var;
8344 boolean init_gfx_buffers = FALSE;
8345 boolean init_video_buffer = FALSE;
8346 boolean init_gadgets_and_toons = FALSE;
8347 boolean init_em_graphics = FALSE;
8349 if (new_win_xsize != WIN_XSIZE ||
8350 new_win_ysize != WIN_YSIZE)
8352 WIN_XSIZE = new_win_xsize;
8353 WIN_YSIZE = new_win_ysize;
8355 init_video_buffer = TRUE;
8356 init_gfx_buffers = TRUE;
8357 init_gadgets_and_toons = TRUE;
8359 // printf("::: video: init_video_buffer, init_gfx_buffers\n");
8362 if (new_scr_fieldx != SCR_FIELDX ||
8363 new_scr_fieldy != SCR_FIELDY)
8365 /* this always toggles between MAIN and GAME when using small tile size */
8367 SCR_FIELDX = new_scr_fieldx;
8368 SCR_FIELDY = new_scr_fieldy;
8370 // printf("::: new_scr_fieldx != SCR_FIELDX ...\n");
8381 new_sxsize != SXSIZE ||
8382 new_sysize != SYSIZE ||
8383 new_dxsize != DXSIZE ||
8384 new_dysize != DYSIZE ||
8385 new_vxsize != VXSIZE ||
8386 new_vysize != VYSIZE ||
8387 new_exsize != EXSIZE ||
8388 new_eysize != EYSIZE ||
8389 new_real_sx != REAL_SX ||
8390 new_real_sy != REAL_SY ||
8391 new_full_sxsize != FULL_SXSIZE ||
8392 new_full_sysize != FULL_SYSIZE ||
8393 new_tilesize_var != TILESIZE_VAR
8396 // ------------------------------------------------------------------------
8397 // determine next fading area for changed viewport definitions
8398 // ------------------------------------------------------------------------
8400 // start with current playfield area (default fading area)
8403 FADE_SXSIZE = FULL_SXSIZE;
8404 FADE_SYSIZE = FULL_SYSIZE;
8406 // add new playfield area if position or size has changed
8407 if (new_real_sx != REAL_SX || new_real_sy != REAL_SY ||
8408 new_full_sxsize != FULL_SXSIZE || new_full_sysize != FULL_SYSIZE)
8410 JoinRectangles(&FADE_SX, &FADE_SY, &FADE_SXSIZE, &FADE_SYSIZE,
8411 new_real_sx, new_real_sy, new_full_sxsize,new_full_sysize);
8414 // add current and new door 1 area if position or size has changed
8415 if (new_dx != DX || new_dy != DY ||
8416 new_dxsize != DXSIZE || new_dysize != DYSIZE)
8418 JoinRectangles(&FADE_SX, &FADE_SY, &FADE_SXSIZE, &FADE_SYSIZE,
8419 DX, DY, DXSIZE, DYSIZE);
8420 JoinRectangles(&FADE_SX, &FADE_SY, &FADE_SXSIZE, &FADE_SYSIZE,
8421 new_dx, new_dy, new_dxsize, new_dysize);
8424 // add current and new door 2 area if position or size has changed
8425 if (new_dx != VX || new_dy != VY ||
8426 new_dxsize != VXSIZE || new_dysize != VYSIZE)
8428 JoinRectangles(&FADE_SX, &FADE_SY, &FADE_SXSIZE, &FADE_SYSIZE,
8429 VX, VY, VXSIZE, VYSIZE);
8430 JoinRectangles(&FADE_SX, &FADE_SY, &FADE_SXSIZE, &FADE_SYSIZE,
8431 new_vx, new_vy, new_vxsize, new_vysize);
8434 // ------------------------------------------------------------------------
8435 // handle changed tile size
8436 // ------------------------------------------------------------------------
8438 if (new_tilesize_var != TILESIZE_VAR)
8440 // printf("::: new_tilesize_var != TILESIZE_VAR\n");
8442 // changing tile size invalidates scroll values of engine snapshots
8443 FreeEngineSnapshotSingle();
8445 // changing tile size requires update of graphic mapping for EM engine
8446 init_em_graphics = TRUE;
8457 SXSIZE = new_sxsize;
8458 SYSIZE = new_sysize;
8459 DXSIZE = new_dxsize;
8460 DYSIZE = new_dysize;
8461 VXSIZE = new_vxsize;
8462 VYSIZE = new_vysize;
8463 EXSIZE = new_exsize;
8464 EYSIZE = new_eysize;
8465 REAL_SX = new_real_sx;
8466 REAL_SY = new_real_sy;
8467 FULL_SXSIZE = new_full_sxsize;
8468 FULL_SYSIZE = new_full_sysize;
8469 TILESIZE_VAR = new_tilesize_var;
8471 init_gfx_buffers = TRUE;
8472 init_gadgets_and_toons = TRUE;
8474 // printf("::: viewports: init_gfx_buffers\n");
8475 // printf("::: viewports: init_gadgets_and_toons\n");
8478 if (init_gfx_buffers)
8480 // printf("::: init_gfx_buffers\n");
8482 SCR_FIELDX = new_scr_fieldx_buffers;
8483 SCR_FIELDY = new_scr_fieldy_buffers;
8487 SCR_FIELDX = new_scr_fieldx;
8488 SCR_FIELDY = new_scr_fieldy;
8490 SetDrawDeactivationMask(REDRAW_NONE);
8491 SetDrawBackgroundMask(REDRAW_FIELD);
8494 if (init_video_buffer)
8496 // printf("::: init_video_buffer\n");
8498 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
8499 InitImageTextures();
8502 if (init_gadgets_and_toons)
8504 // printf("::: init_gadgets_and_toons\n");
8508 InitGlobalAnimations();
8511 if (init_em_graphics)
8513 InitGraphicInfo_EM();