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 char *text_final = text;
2432 char *text_door_style = NULL;
2433 int graphic = IMG_BACKGROUND_REQUEST;
2434 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
2435 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
2436 int font_nr = FONT_REQUEST;
2437 int font_width = getFontWidth(font_nr);
2438 int font_height = getFontHeight(font_nr);
2439 int border_size = request.border_size;
2440 int line_spacing = request.line_spacing;
2441 int line_height = font_height + line_spacing;
2442 int max_text_width = request.width - 2 * border_size;
2443 int max_text_height = request.height - 2 * border_size;
2444 int line_length = max_text_width / font_width;
2445 int max_lines = max_text_height / line_height;
2446 int text_width = line_length * font_width;
2447 int width = request.width;
2448 int height = request.height;
2449 int tile_size = MAX(request.step_offset, 1);
2450 int x_steps = width / tile_size;
2451 int y_steps = height / tile_size;
2452 int sx_offset = border_size;
2453 int sy_offset = border_size;
2457 if (request.centered)
2458 sx_offset = (request.width - text_width) / 2;
2460 if (request.wrap_single_words && !request.autowrap)
2462 char *src_text_ptr, *dst_text_ptr;
2464 text_door_style = checked_malloc(2 * strlen(text) + 1);
2466 src_text_ptr = text;
2467 dst_text_ptr = text_door_style;
2469 while (*src_text_ptr)
2471 if (*src_text_ptr == ' ' ||
2472 *src_text_ptr == '?' ||
2473 *src_text_ptr == '!')
2474 *dst_text_ptr++ = '\n';
2476 if (*src_text_ptr != ' ')
2477 *dst_text_ptr++ = *src_text_ptr;
2482 *dst_text_ptr = '\0';
2484 text_final = text_door_style;
2487 setRequestPosition(&sx, &sy, FALSE);
2489 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
2491 for (y = 0; y < y_steps; y++)
2492 for (x = 0; x < x_steps; x++)
2493 DrawEnvelopeBackgroundTiles(graphic, sx, sy,
2494 x, y, x_steps, y_steps,
2495 tile_size, tile_size);
2497 /* force DOOR font inside door area */
2498 SetFontStatus(GAME_MODE_PSEUDO_DOOR);
2500 DrawTextBuffer(sx + sx_offset, sy + sy_offset, text_final, font_nr,
2501 line_length, -1, max_lines, line_spacing, mask_mode,
2502 request.autowrap, request.centered, FALSE);
2506 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
2507 RedrawGadget(tool_gadget[i]);
2509 // store readily prepared envelope request for later use when animating
2510 BlitBitmap(backbuffer, bitmap_db_cross, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2512 if (text_door_style)
2513 free(text_door_style);
2516 void AnimateEnvelopeRequest(int anim_mode, int action)
2518 int graphic = IMG_BACKGROUND_REQUEST;
2519 boolean draw_masked = graphic_info[graphic].draw_masked;
2520 int delay_value_normal = request.step_delay;
2521 int delay_value_fast = delay_value_normal / 2;
2522 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2523 boolean no_delay = (tape.warp_forward);
2524 int delay_value = (ffwd_delay ? delay_value_fast : delay_value_normal);
2525 int anim_delay_value = (no_delay ? 0 : delay_value + 500 * 0) / 2;
2526 unsigned int anim_delay = 0;
2528 int tile_size = MAX(request.step_offset, 1);
2529 int max_xsize = request.width / tile_size;
2530 int max_ysize = request.height / tile_size;
2531 int max_xsize_inner = max_xsize - 2;
2532 int max_ysize_inner = max_ysize - 2;
2534 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize_inner : 0);
2535 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize_inner : 0);
2536 int xend = max_xsize_inner;
2537 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize_inner : 0);
2538 int xstep = (xstart < xend ? 1 : 0);
2539 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
2541 int end = MAX(xend - xstart, yend - ystart);
2544 if (setup.quick_doors)
2551 for (i = start; i <= end; i++)
2553 int last_frame = end; // last frame of this "for" loop
2554 int x = xstart + i * xstep;
2555 int y = ystart + i * ystep;
2556 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
2557 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
2558 int xsize_size_left = (xsize - 1) * tile_size;
2559 int ysize_size_top = (ysize - 1) * tile_size;
2560 int max_xsize_pos = (max_xsize - 1) * tile_size;
2561 int max_ysize_pos = (max_ysize - 1) * tile_size;
2562 int width = xsize * tile_size;
2563 int height = ysize * tile_size;
2568 setRequestPosition(&src_x, &src_y, FALSE);
2569 setRequestPositionExt(&dst_x, &dst_y, width, height, FALSE);
2571 BlitBitmap(bitmap_db_store, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2573 for (yy = 0; yy < 2; yy++)
2575 for (xx = 0; xx < 2; xx++)
2577 int src_xx = src_x + xx * max_xsize_pos;
2578 int src_yy = src_y + yy * max_ysize_pos;
2579 int dst_xx = dst_x + xx * xsize_size_left;
2580 int dst_yy = dst_y + yy * ysize_size_top;
2581 int xx_size = (xx ? tile_size : xsize_size_left);
2582 int yy_size = (yy ? tile_size : ysize_size_top);
2585 BlitBitmapMasked(bitmap_db_cross, backbuffer,
2586 src_xx, src_yy, xx_size, yy_size, dst_xx, dst_yy);
2588 BlitBitmap(bitmap_db_cross, backbuffer,
2589 src_xx, src_yy, xx_size, yy_size, dst_xx, dst_yy);
2593 redraw_mask |= REDRAW_FIELD;
2598 SkipUntilDelayReached(&anim_delay, anim_delay_value, &i, last_frame);
2602 void ShowEnvelopeRequest(char *text, unsigned int req_state, int action)
2604 int graphic = IMG_BACKGROUND_REQUEST;
2605 int sound_opening = SND_REQUEST_OPENING;
2606 int sound_closing = SND_REQUEST_CLOSING;
2607 int anim_mode_1 = request.anim_mode; /* (higher priority) */
2608 int anim_mode_2 = graphic_info[graphic].anim_mode; /* (lower priority) */
2609 int anim_mode = (anim_mode_1 != ANIM_DEFAULT ? anim_mode_1 : anim_mode_2);
2610 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
2611 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
2613 if (game_status == GAME_MODE_PLAYING)
2614 BlitScreenToBitmap(backbuffer);
2616 SetDrawtoField(DRAW_BACKBUFFER);
2618 // SetDrawBackgroundMask(REDRAW_NONE);
2620 if (action == ACTION_OPENING)
2622 BlitBitmap(backbuffer, bitmap_db_store, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2624 if (req_state & REQ_ASK)
2626 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
2627 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
2629 else if (req_state & REQ_CONFIRM)
2631 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
2633 else if (req_state & REQ_PLAYER)
2635 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
2636 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
2637 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
2638 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
2641 DrawEnvelopeRequest(text);
2643 if (game_status != GAME_MODE_MAIN)
2647 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
2649 if (action == ACTION_OPENING)
2651 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
2653 if (anim_mode == ANIM_DEFAULT)
2654 AnimateEnvelopeRequest(ANIM_DEFAULT, ACTION_OPENING);
2656 AnimateEnvelopeRequest(main_anim_mode, ACTION_OPENING);
2660 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
2662 if (anim_mode != ANIM_NONE)
2663 AnimateEnvelopeRequest(main_anim_mode, ACTION_CLOSING);
2665 if (anim_mode == ANIM_DEFAULT)
2666 AnimateEnvelopeRequest(ANIM_DEFAULT, ACTION_CLOSING);
2669 game.envelope_active = FALSE;
2671 if (action == ACTION_CLOSING)
2673 if (game_status != GAME_MODE_MAIN)
2676 BlitBitmap(bitmap_db_store, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2679 // SetDrawBackgroundMask(last_draw_background_mask);
2681 redraw_mask |= REDRAW_FIELD;
2683 if (game_status == GAME_MODE_MAIN)
2688 if (action == ACTION_CLOSING &&
2689 game_status == GAME_MODE_PLAYING &&
2690 level.game_engine_type == GAME_ENGINE_TYPE_RND)
2691 SetDrawtoField(DRAW_FIELDBUFFER);
2694 void DrawPreviewElement(int dst_x, int dst_y, int element, int tilesize)
2698 int graphic = el2preimg(element);
2700 getSizedGraphicSource(graphic, 0, tilesize, &src_bitmap, &src_x, &src_y);
2701 BlitBitmap(src_bitmap, drawto, src_x, src_y, tilesize, tilesize, dst_x,dst_y);
2704 void DrawLevel(int draw_background_mask)
2708 SetMainBackgroundImage(IMG_BACKGROUND_PLAYING);
2709 SetDrawBackgroundMask(draw_background_mask);
2713 for (x = BX1; x <= BX2; x++)
2714 for (y = BY1; y <= BY2; y++)
2715 DrawScreenField(x, y);
2717 redraw_mask |= REDRAW_FIELD;
2720 void DrawSizedLevel(int size_x, int size_y, int scroll_x, int scroll_y,
2725 for (x = 0; x < size_x; x++)
2726 for (y = 0; y < size_y; y++)
2727 DrawSizedElementOrWall(x, y, scroll_x, scroll_y, tilesize);
2729 redraw_mask |= REDRAW_FIELD;
2732 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
2736 for (x = 0; x < size_x; x++)
2737 for (y = 0; y < size_y; y++)
2738 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
2740 redraw_mask |= REDRAW_FIELD;
2743 static void DrawPreviewLevelPlayfieldExt(int from_x, int from_y)
2745 boolean show_level_border = (BorderElement != EL_EMPTY);
2746 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
2747 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
2748 int tile_size = preview.tile_size;
2749 int preview_width = preview.xsize * tile_size;
2750 int preview_height = preview.ysize * tile_size;
2751 int real_preview_xsize = MIN(level_xsize, preview.xsize);
2752 int real_preview_ysize = MIN(level_ysize, preview.ysize);
2753 int real_preview_width = real_preview_xsize * tile_size;
2754 int real_preview_height = real_preview_ysize * tile_size;
2755 int dst_x = SX + ALIGNED_XPOS(preview.x, preview_width, preview.align);
2756 int dst_y = SY + ALIGNED_YPOS(preview.y, preview_height, preview.valign);
2759 if (!IN_GFX_FIELD_FULL(dst_x, dst_y + preview_height - 1))
2762 DrawBackground(dst_x, dst_y, preview_width, preview_height);
2764 dst_x += (preview_width - real_preview_width) / 2;
2765 dst_y += (preview_height - real_preview_height) / 2;
2767 for (x = 0; x < real_preview_xsize; x++)
2769 for (y = 0; y < real_preview_ysize; y++)
2771 int lx = from_x + x + (show_level_border ? -1 : 0);
2772 int ly = from_y + y + (show_level_border ? -1 : 0);
2773 int element = (IN_LEV_FIELD(lx, ly) ? level.field[lx][ly] :
2774 getBorderElement(lx, ly));
2776 DrawPreviewElement(dst_x + x * tile_size, dst_y + y * tile_size,
2777 element, tile_size);
2781 redraw_mask |= REDRAW_FIELD;
2784 #define MICROLABEL_EMPTY 0
2785 #define MICROLABEL_LEVEL_NAME 1
2786 #define MICROLABEL_LEVEL_AUTHOR_HEAD 2
2787 #define MICROLABEL_LEVEL_AUTHOR 3
2788 #define MICROLABEL_IMPORTED_FROM_HEAD 4
2789 #define MICROLABEL_IMPORTED_FROM 5
2790 #define MICROLABEL_IMPORTED_BY_HEAD 6
2791 #define MICROLABEL_IMPORTED_BY 7
2793 static int getMaxTextLength(struct TextPosInfo *pos, int font_nr)
2795 int max_text_width = SXSIZE;
2796 int font_width = getFontWidth(font_nr);
2798 if (pos->align == ALIGN_CENTER)
2799 max_text_width = (pos->x < SXSIZE / 2 ? pos->x * 2 : (SXSIZE - pos->x) * 2);
2800 else if (pos->align == ALIGN_RIGHT)
2801 max_text_width = pos->x;
2803 max_text_width = SXSIZE - pos->x;
2805 return max_text_width / font_width;
2808 static void DrawPreviewLevelLabelExt(int mode)
2810 struct TextPosInfo *pos = &menu.main.text.level_info_2;
2811 char label_text[MAX_OUTPUT_LINESIZE + 1];
2812 int max_len_label_text;
2813 int font_nr = pos->font;
2816 if (!IN_GFX_FIELD_FULL(pos->x, pos->y + getFontHeight(pos->font)))
2819 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
2820 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
2821 mode == MICROLABEL_IMPORTED_BY_HEAD)
2822 font_nr = pos->font_alt;
2824 max_len_label_text = getMaxTextLength(pos, font_nr);
2826 if (pos->size != -1)
2827 max_len_label_text = pos->size;
2829 for (i = 0; i < max_len_label_text; i++)
2830 label_text[i] = ' ';
2831 label_text[max_len_label_text] = '\0';
2833 if (strlen(label_text) > 0)
2834 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2837 (mode == MICROLABEL_LEVEL_NAME ? level.name :
2838 mode == MICROLABEL_LEVEL_AUTHOR_HEAD ? "created by" :
2839 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
2840 mode == MICROLABEL_IMPORTED_FROM_HEAD ? "imported from" :
2841 mode == MICROLABEL_IMPORTED_FROM ? leveldir_current->imported_from :
2842 mode == MICROLABEL_IMPORTED_BY_HEAD ? "imported by" :
2843 mode == MICROLABEL_IMPORTED_BY ? leveldir_current->imported_by :""),
2844 max_len_label_text);
2845 label_text[max_len_label_text] = '\0';
2847 if (strlen(label_text) > 0)
2848 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2850 redraw_mask |= REDRAW_FIELD;
2853 static void DrawPreviewLevelExt(boolean restart)
2855 static unsigned int scroll_delay = 0;
2856 static unsigned int label_delay = 0;
2857 static int from_x, from_y, scroll_direction;
2858 static int label_state, label_counter;
2859 unsigned int scroll_delay_value = preview.step_delay;
2860 boolean show_level_border = (BorderElement != EL_EMPTY);
2861 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
2862 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
2869 if (preview.anim_mode == ANIM_CENTERED)
2871 if (level_xsize > preview.xsize)
2872 from_x = (level_xsize - preview.xsize) / 2;
2873 if (level_ysize > preview.ysize)
2874 from_y = (level_ysize - preview.ysize) / 2;
2877 from_x += preview.xoffset;
2878 from_y += preview.yoffset;
2880 scroll_direction = MV_RIGHT;
2884 DrawPreviewLevelPlayfieldExt(from_x, from_y);
2885 DrawPreviewLevelLabelExt(label_state);
2887 /* initialize delay counters */
2888 DelayReached(&scroll_delay, 0);
2889 DelayReached(&label_delay, 0);
2891 if (leveldir_current->name)
2893 struct TextPosInfo *pos = &menu.main.text.level_info_1;
2894 char label_text[MAX_OUTPUT_LINESIZE + 1];
2895 int font_nr = pos->font;
2896 int max_len_label_text = getMaxTextLength(pos, font_nr);
2898 if (pos->size != -1)
2899 max_len_label_text = pos->size;
2901 strncpy(label_text, leveldir_current->name, max_len_label_text);
2902 label_text[max_len_label_text] = '\0';
2904 if (IN_GFX_FIELD_FULL(pos->x, pos->y + getFontHeight(pos->font)))
2905 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2911 /* scroll preview level, if needed */
2912 if (preview.anim_mode != ANIM_NONE &&
2913 (level_xsize > preview.xsize || level_ysize > preview.ysize) &&
2914 DelayReached(&scroll_delay, scroll_delay_value))
2916 switch (scroll_direction)
2921 from_x -= preview.step_offset;
2922 from_x = (from_x < 0 ? 0 : from_x);
2925 scroll_direction = MV_UP;
2929 if (from_x < level_xsize - preview.xsize)
2931 from_x += preview.step_offset;
2932 from_x = (from_x > level_xsize - preview.xsize ?
2933 level_xsize - preview.xsize : from_x);
2936 scroll_direction = MV_DOWN;
2942 from_y -= preview.step_offset;
2943 from_y = (from_y < 0 ? 0 : from_y);
2946 scroll_direction = MV_RIGHT;
2950 if (from_y < level_ysize - preview.ysize)
2952 from_y += preview.step_offset;
2953 from_y = (from_y > level_ysize - preview.ysize ?
2954 level_ysize - preview.ysize : from_y);
2957 scroll_direction = MV_LEFT;
2964 DrawPreviewLevelPlayfieldExt(from_x, from_y);
2967 /* !!! THIS ALL SUCKS -- SHOULD BE CLEANLY REWRITTEN !!! */
2968 /* redraw micro level label, if needed */
2969 if (!strEqual(level.name, NAMELESS_LEVEL_NAME) &&
2970 !strEqual(level.author, ANONYMOUS_NAME) &&
2971 !strEqual(level.author, leveldir_current->name) &&
2972 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
2974 int max_label_counter = 23;
2976 if (leveldir_current->imported_from != NULL &&
2977 strlen(leveldir_current->imported_from) > 0)
2978 max_label_counter += 14;
2979 if (leveldir_current->imported_by != NULL &&
2980 strlen(leveldir_current->imported_by) > 0)
2981 max_label_counter += 14;
2983 label_counter = (label_counter + 1) % max_label_counter;
2984 label_state = (label_counter >= 0 && label_counter <= 7 ?
2985 MICROLABEL_LEVEL_NAME :
2986 label_counter >= 9 && label_counter <= 12 ?
2987 MICROLABEL_LEVEL_AUTHOR_HEAD :
2988 label_counter >= 14 && label_counter <= 21 ?
2989 MICROLABEL_LEVEL_AUTHOR :
2990 label_counter >= 23 && label_counter <= 26 ?
2991 MICROLABEL_IMPORTED_FROM_HEAD :
2992 label_counter >= 28 && label_counter <= 35 ?
2993 MICROLABEL_IMPORTED_FROM :
2994 label_counter >= 37 && label_counter <= 40 ?
2995 MICROLABEL_IMPORTED_BY_HEAD :
2996 label_counter >= 42 && label_counter <= 49 ?
2997 MICROLABEL_IMPORTED_BY : MICROLABEL_EMPTY);
2999 if (leveldir_current->imported_from == NULL &&
3000 (label_state == MICROLABEL_IMPORTED_FROM_HEAD ||
3001 label_state == MICROLABEL_IMPORTED_FROM))
3002 label_state = (label_state == MICROLABEL_IMPORTED_FROM_HEAD ?
3003 MICROLABEL_IMPORTED_BY_HEAD : MICROLABEL_IMPORTED_BY);
3005 DrawPreviewLevelLabelExt(label_state);
3009 void DrawPreviewLevelInitial()
3011 DrawPreviewLevelExt(TRUE);
3014 void DrawPreviewLevelAnimation()
3016 DrawPreviewLevelExt(FALSE);
3019 inline static void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
3020 int graphic, int sync_frame,
3023 int frame = getGraphicAnimationFrame(graphic, sync_frame);
3025 if (mask_mode == USE_MASKING)
3026 DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
3028 DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
3031 void DrawFixedGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
3032 int graphic, int sync_frame, int mask_mode)
3034 int frame = getGraphicAnimationFrame(graphic, sync_frame);
3036 if (mask_mode == USE_MASKING)
3037 DrawFixedGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
3039 DrawFixedGraphicExt(dst_bitmap, x, y, graphic, frame);
3042 inline static void DrawGraphicAnimation(int x, int y, int graphic)
3044 int lx = LEVELX(x), ly = LEVELY(y);
3046 if (!IN_SCR_FIELD(x, y))
3049 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR,
3050 graphic, GfxFrame[lx][ly], NO_MASKING);
3052 MarkTileDirty(x, y);
3055 void DrawFixedGraphicAnimation(int x, int y, int graphic)
3057 int lx = LEVELX(x), ly = LEVELY(y);
3059 if (!IN_SCR_FIELD(x, y))
3062 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
3063 graphic, GfxFrame[lx][ly], NO_MASKING);
3064 MarkTileDirty(x, y);
3067 void DrawLevelGraphicAnimation(int x, int y, int graphic)
3069 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
3072 void DrawLevelElementAnimation(int x, int y, int element)
3074 int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
3076 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
3079 void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
3081 int sx = SCREENX(x), sy = SCREENY(y);
3083 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
3086 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
3089 DrawGraphicAnimation(sx, sy, graphic);
3092 if (GFX_CRUMBLED(TILE_GFX_ELEMENT(x, y)))
3093 DrawLevelFieldCrumbled(x, y);
3095 if (GFX_CRUMBLED(Feld[x][y]))
3096 DrawLevelFieldCrumbled(x, y);
3100 void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
3102 int sx = SCREENX(x), sy = SCREENY(y);
3105 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
3108 graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
3110 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
3113 DrawGraphicAnimation(sx, sy, graphic);
3115 if (GFX_CRUMBLED(element))
3116 DrawLevelFieldCrumbled(x, y);
3119 static int getPlayerGraphic(struct PlayerInfo *player, int move_dir)
3121 if (player->use_murphy)
3123 /* this works only because currently only one player can be "murphy" ... */
3124 static int last_horizontal_dir = MV_LEFT;
3125 int graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir);
3127 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3128 last_horizontal_dir = move_dir;
3130 if (graphic == IMG_SP_MURPHY) /* undefined => use special graphic */
3132 int direction = (player->is_snapping ? move_dir : last_horizontal_dir);
3134 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
3140 return el_act_dir2img(player->artwork_element, player->GfxAction,move_dir);
3143 static boolean equalGraphics(int graphic1, int graphic2)
3145 struct GraphicInfo *g1 = &graphic_info[graphic1];
3146 struct GraphicInfo *g2 = &graphic_info[graphic2];
3148 return (g1->bitmap == g2->bitmap &&
3149 g1->src_x == g2->src_x &&
3150 g1->src_y == g2->src_y &&
3151 g1->anim_frames == g2->anim_frames &&
3152 g1->anim_delay == g2->anim_delay &&
3153 g1->anim_mode == g2->anim_mode);
3156 void DrawAllPlayers()
3160 for (i = 0; i < MAX_PLAYERS; i++)
3161 if (stored_player[i].active)
3162 DrawPlayer(&stored_player[i]);
3165 void DrawPlayerField(int x, int y)
3167 if (!IS_PLAYER(x, y))
3170 DrawPlayer(PLAYERINFO(x, y));
3173 #define DRAW_PLAYER_OVER_PUSHED_ELEMENT 1
3175 void DrawPlayer(struct PlayerInfo *player)
3177 int jx = player->jx;
3178 int jy = player->jy;
3179 int move_dir = player->MovDir;
3180 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? +1 : 0);
3181 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? +1 : 0);
3182 int last_jx = (player->is_moving ? jx - dx : jx);
3183 int last_jy = (player->is_moving ? jy - dy : jy);
3184 int next_jx = jx + dx;
3185 int next_jy = jy + dy;
3186 boolean player_is_moving = (player->MovPos ? TRUE : FALSE);
3187 boolean player_is_opaque = FALSE;
3188 int sx = SCREENX(jx), sy = SCREENY(jy);
3189 int sxx = 0, syy = 0;
3190 int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
3192 int action = ACTION_DEFAULT;
3193 int last_player_graphic = getPlayerGraphic(player, move_dir);
3194 int last_player_frame = player->Frame;
3197 /* GfxElement[][] is set to the element the player is digging or collecting;
3198 remove also for off-screen player if the player is not moving anymore */
3199 if (IN_LEV_FIELD(jx, jy) && !player_is_moving)
3200 GfxElement[jx][jy] = EL_UNDEFINED;
3202 if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
3206 if (!IN_LEV_FIELD(jx, jy))
3208 printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
3209 printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
3210 printf("DrawPlayerField(): This should never happen!\n");
3215 if (element == EL_EXPLOSION)
3218 action = (player->is_pushing ? ACTION_PUSHING :
3219 player->is_digging ? ACTION_DIGGING :
3220 player->is_collecting ? ACTION_COLLECTING :
3221 player->is_moving ? ACTION_MOVING :
3222 player->is_snapping ? ACTION_SNAPPING :
3223 player->is_dropping ? ACTION_DROPPING :
3224 player->is_waiting ? player->action_waiting : ACTION_DEFAULT);
3226 if (player->is_waiting)
3227 move_dir = player->dir_waiting;
3229 InitPlayerGfxAnimation(player, action, move_dir);
3231 /* ----------------------------------------------------------------------- */
3232 /* draw things in the field the player is leaving, if needed */
3233 /* ----------------------------------------------------------------------- */
3235 if (player->is_moving)
3237 if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
3239 DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
3241 if (last_element == EL_DYNAMITE_ACTIVE ||
3242 last_element == EL_EM_DYNAMITE_ACTIVE ||
3243 last_element == EL_SP_DISK_RED_ACTIVE)
3244 DrawDynamite(last_jx, last_jy);
3246 DrawLevelFieldThruMask(last_jx, last_jy);
3248 else if (last_element == EL_DYNAMITE_ACTIVE ||
3249 last_element == EL_EM_DYNAMITE_ACTIVE ||
3250 last_element == EL_SP_DISK_RED_ACTIVE)
3251 DrawDynamite(last_jx, last_jy);
3253 /* !!! this is not enough to prevent flickering of players which are
3254 moving next to each others without a free tile between them -- this
3255 can only be solved by drawing all players layer by layer (first the
3256 background, then the foreground etc.) !!! => TODO */
3257 else if (!IS_PLAYER(last_jx, last_jy))
3258 DrawLevelField(last_jx, last_jy);
3261 DrawLevelField(last_jx, last_jy);
3264 if (player->is_pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
3265 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
3268 if (!IN_SCR_FIELD(sx, sy))
3271 /* ----------------------------------------------------------------------- */
3272 /* draw things behind the player, if needed */
3273 /* ----------------------------------------------------------------------- */
3276 DrawLevelElement(jx, jy, Back[jx][jy]);
3277 else if (IS_ACTIVE_BOMB(element))
3278 DrawLevelElement(jx, jy, EL_EMPTY);
3281 if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
3283 int old_element = GfxElement[jx][jy];
3284 int old_graphic = el_act_dir2img(old_element, action, move_dir);
3285 int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
3287 if (GFX_CRUMBLED(old_element))
3288 DrawLevelFieldCrumbledDigging(jx, jy, move_dir, player->StepFrame);
3290 DrawGraphic(sx, sy, old_graphic, frame);
3292 if (graphic_info[old_graphic].anim_mode & ANIM_OPAQUE_PLAYER)
3293 player_is_opaque = TRUE;
3297 GfxElement[jx][jy] = EL_UNDEFINED;
3299 /* make sure that pushed elements are drawn with correct frame rate */
3300 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
3302 if (player->is_pushing && player->is_moving && !IS_ANIM_MODE_CE(graphic))
3303 GfxFrame[jx][jy] = player->StepFrame;
3305 DrawLevelField(jx, jy);
3309 #if !DRAW_PLAYER_OVER_PUSHED_ELEMENT
3310 /* ----------------------------------------------------------------------- */
3311 /* draw player himself */
3312 /* ----------------------------------------------------------------------- */
3314 graphic = getPlayerGraphic(player, move_dir);
3316 /* in the case of changed player action or direction, prevent the current
3317 animation frame from being restarted for identical animations */
3318 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
3319 player->Frame = last_player_frame;
3321 frame = getGraphicAnimationFrame(graphic, player->Frame);
3325 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3326 sxx = player->GfxPos;
3328 syy = player->GfxPos;
3331 if (player_is_opaque)
3332 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
3334 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3336 if (SHIELD_ON(player))
3338 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
3339 IMG_SHIELD_NORMAL_ACTIVE);
3340 int frame = getGraphicAnimationFrame(graphic, -1);
3342 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3346 #if DRAW_PLAYER_OVER_PUSHED_ELEMENT
3349 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3350 sxx = player->GfxPos;
3352 syy = player->GfxPos;
3356 /* ----------------------------------------------------------------------- */
3357 /* draw things the player is pushing, if needed */
3358 /* ----------------------------------------------------------------------- */
3360 if (player->is_pushing && player->is_moving)
3362 int px = SCREENX(jx), py = SCREENY(jy);
3363 int pxx = (TILEX - ABS(sxx)) * dx;
3364 int pyy = (TILEY - ABS(syy)) * dy;
3365 int gfx_frame = GfxFrame[jx][jy];
3371 if (!IS_MOVING(jx, jy)) /* push movement already finished */
3373 element = Feld[next_jx][next_jy];
3374 gfx_frame = GfxFrame[next_jx][next_jy];
3377 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
3379 sync_frame = (IS_ANIM_MODE_CE(graphic) ? gfx_frame : player->StepFrame);
3380 frame = getGraphicAnimationFrame(graphic, sync_frame);
3382 /* draw background element under pushed element (like the Sokoban field) */
3383 if (game.use_masked_pushing && IS_MOVING(jx, jy))
3385 /* this allows transparent pushing animation over non-black background */
3388 DrawLevelElement(jx, jy, Back[jx][jy]);
3390 DrawLevelElement(jx, jy, EL_EMPTY);
3392 if (Back[next_jx][next_jy])
3393 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
3395 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
3397 else if (Back[next_jx][next_jy])
3398 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
3401 /* do not draw (EM style) pushing animation when pushing is finished */
3402 /* (two-tile animations usually do not contain start and end frame) */
3403 if (graphic_info[graphic].double_movement && !IS_MOVING(jx, jy))
3404 DrawLevelElement(next_jx, next_jy, Feld[next_jx][next_jy]);
3406 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
3408 /* masked drawing is needed for EMC style (double) movement graphics */
3409 /* !!! (ONLY WHEN DRAWING PUSHED ELEMENT OVER THE PLAYER) !!! */
3410 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
3414 #if DRAW_PLAYER_OVER_PUSHED_ELEMENT
3415 /* ----------------------------------------------------------------------- */
3416 /* draw player himself */
3417 /* ----------------------------------------------------------------------- */
3419 graphic = getPlayerGraphic(player, move_dir);
3421 /* in the case of changed player action or direction, prevent the current
3422 animation frame from being restarted for identical animations */
3423 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
3424 player->Frame = last_player_frame;
3426 frame = getGraphicAnimationFrame(graphic, player->Frame);
3430 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3431 sxx = player->GfxPos;
3433 syy = player->GfxPos;
3436 if (player_is_opaque)
3437 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
3439 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3441 if (SHIELD_ON(player))
3443 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
3444 IMG_SHIELD_NORMAL_ACTIVE);
3445 int frame = getGraphicAnimationFrame(graphic, -1);
3447 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3451 /* ----------------------------------------------------------------------- */
3452 /* draw things in front of player (active dynamite or dynabombs) */
3453 /* ----------------------------------------------------------------------- */
3455 if (IS_ACTIVE_BOMB(element))
3457 graphic = el2img(element);
3458 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
3460 if (game.emulation == EMU_SUPAPLEX)
3461 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
3463 DrawGraphicThruMask(sx, sy, graphic, frame);
3466 if (player_is_moving && last_element == EL_EXPLOSION)
3468 int element = (GfxElement[last_jx][last_jy] != EL_UNDEFINED ?
3469 GfxElement[last_jx][last_jy] : EL_EMPTY);
3470 int graphic = el_act2img(element, ACTION_EXPLODING);
3471 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
3472 int phase = ExplodePhase[last_jx][last_jy] - 1;
3473 int frame = getGraphicAnimationFrame(graphic, phase - delay);
3476 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
3479 /* ----------------------------------------------------------------------- */
3480 /* draw elements the player is just walking/passing through/under */
3481 /* ----------------------------------------------------------------------- */
3483 if (player_is_moving)
3485 /* handle the field the player is leaving ... */
3486 if (IS_ACCESSIBLE_INSIDE(last_element))
3487 DrawLevelField(last_jx, last_jy);
3488 else if (IS_ACCESSIBLE_UNDER(last_element))
3489 DrawLevelFieldThruMask(last_jx, last_jy);
3492 /* do not redraw accessible elements if the player is just pushing them */
3493 if (!player_is_moving || !player->is_pushing)
3495 /* ... and the field the player is entering */
3496 if (IS_ACCESSIBLE_INSIDE(element))
3497 DrawLevelField(jx, jy);
3498 else if (IS_ACCESSIBLE_UNDER(element))
3499 DrawLevelFieldThruMask(jx, jy);
3502 MarkTileDirty(sx, sy);
3505 /* ------------------------------------------------------------------------- */
3507 void WaitForEventToContinue()
3509 boolean still_wait = TRUE;
3511 /* simulate releasing mouse button over last gadget, if still pressed */
3513 HandleGadgets(-1, -1, 0);
3515 button_status = MB_RELEASED;
3529 case EVENT_BUTTONPRESS:
3530 case EVENT_KEYPRESS:
3534 case EVENT_KEYRELEASE:
3535 ClearPlayerAction();
3539 HandleOtherEvents(&event);
3543 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
3550 WaitUntilDelayReached(&sync_frame_delay, sync_frame_delay_value);
3554 #define MAX_REQUEST_LINES 13
3555 #define MAX_REQUEST_LINE_FONT1_LEN 7
3556 #define MAX_REQUEST_LINE_FONT2_LEN 10
3558 static int RequestHandleEvents(unsigned int req_state)
3560 boolean level_solved = (game_status == GAME_MODE_PLAYING &&
3561 local_player->LevelSolved_GameEnd);
3562 int width = request.width;
3563 int height = request.height;
3567 setRequestPosition(&sx, &sy, FALSE);
3569 button_status = MB_RELEASED;
3571 request_gadget_id = -1;
3578 SetDrawtoField(DRAW_FIELDBUFFER);
3580 HandleGameActions();
3582 SetDrawtoField(DRAW_BACKBUFFER);
3584 if (global.use_envelope_request)
3586 /* copy current state of request area to middle of playfield area */
3587 BlitBitmap(bitmap_db_cross, drawto, sx, sy, width, height, sx, sy);
3595 while (NextValidEvent(&event))
3599 case EVENT_BUTTONPRESS:
3600 case EVENT_BUTTONRELEASE:
3601 case EVENT_MOTIONNOTIFY:
3605 if (event.type == EVENT_MOTIONNOTIFY)
3610 motion_status = TRUE;
3611 mx = ((MotionEvent *) &event)->x;
3612 my = ((MotionEvent *) &event)->y;
3616 motion_status = FALSE;
3617 mx = ((ButtonEvent *) &event)->x;
3618 my = ((ButtonEvent *) &event)->y;
3619 if (event.type == EVENT_BUTTONPRESS)
3620 button_status = ((ButtonEvent *) &event)->button;
3622 button_status = MB_RELEASED;
3625 /* this sets 'request_gadget_id' */
3626 HandleGadgets(mx, my, button_status);
3628 switch (request_gadget_id)
3630 case TOOL_CTRL_ID_YES:
3633 case TOOL_CTRL_ID_NO:
3636 case TOOL_CTRL_ID_CONFIRM:
3637 result = TRUE | FALSE;
3640 case TOOL_CTRL_ID_PLAYER_1:
3643 case TOOL_CTRL_ID_PLAYER_2:
3646 case TOOL_CTRL_ID_PLAYER_3:
3649 case TOOL_CTRL_ID_PLAYER_4:
3660 case EVENT_KEYPRESS:
3661 switch (GetEventKey((KeyEvent *)&event, TRUE))
3664 if (req_state & REQ_CONFIRM)
3669 #if defined(TARGET_SDL2)
3676 #if defined(TARGET_SDL2)
3686 if (req_state & REQ_PLAYER)
3690 case EVENT_KEYRELEASE:
3691 ClearPlayerAction();
3695 HandleOtherEvents(&event);
3700 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
3702 int joy = AnyJoystick();
3704 if (joy & JOY_BUTTON_1)
3706 else if (joy & JOY_BUTTON_2)
3712 if (global.use_envelope_request)
3714 /* copy back current state of pressed buttons inside request area */
3715 BlitBitmap(drawto, bitmap_db_cross, sx, sy, width, height, sx, sy);
3725 WaitUntilDelayReached(&sync_frame_delay, sync_frame_delay_value);
3731 static boolean RequestDoor(char *text, unsigned int req_state)
3733 unsigned int old_door_state;
3734 int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
3735 int font_nr = FONT_TEXT_2;
3740 if (maxWordLengthInString(text) > MAX_REQUEST_LINE_FONT1_LEN)
3742 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
3743 font_nr = FONT_TEXT_1;
3746 if (game_status == GAME_MODE_PLAYING)
3747 BlitScreenToBitmap(backbuffer);
3749 /* disable deactivated drawing when quick-loading level tape recording */
3750 if (tape.playing && tape.deactivate_display)
3751 TapeDeactivateDisplayOff(TRUE);
3753 SetMouseCursor(CURSOR_DEFAULT);
3755 #if defined(NETWORK_AVALIABLE)
3756 /* pause network game while waiting for request to answer */
3757 if (options.network &&
3758 game_status == GAME_MODE_PLAYING &&
3759 req_state & REQUEST_WAIT_FOR_INPUT)
3760 SendToServer_PausePlaying();
3763 old_door_state = GetDoorState();
3765 /* simulate releasing mouse button over last gadget, if still pressed */
3767 HandleGadgets(-1, -1, 0);
3771 /* draw released gadget before proceeding */
3774 if (old_door_state & DOOR_OPEN_1)
3776 CloseDoor(DOOR_CLOSE_1);
3778 /* save old door content */
3779 BlitBitmap(bitmap_db_door_1, bitmap_db_door_1,
3780 0 * DXSIZE, 0, DXSIZE, DYSIZE, 1 * DXSIZE, 0);
3783 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
3784 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3786 /* clear door drawing field */
3787 DrawBackground(DX, DY, DXSIZE, DYSIZE);
3789 /* force DOOR font inside door area */
3790 SetFontStatus(GAME_MODE_PSEUDO_DOOR);
3792 /* write text for request */
3793 for (text_ptr = text, ty = 0; ty < MAX_REQUEST_LINES; ty++)
3795 char text_line[max_request_line_len + 1];
3801 for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
3803 tc = *(text_ptr + tx);
3804 // if (!tc || tc == ' ')
3805 if (!tc || tc == ' ' || tc == '?' || tc == '!')
3809 if ((tc == '?' || tc == '!') && tl == 0)
3819 strncpy(text_line, text_ptr, tl);
3822 DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
3823 DY + 8 + ty * (getFontHeight(font_nr) + 2),
3824 text_line, font_nr);
3826 text_ptr += tl + (tc == ' ' ? 1 : 0);
3827 // text_ptr += tl + (tc == ' ' || tc == '?' || tc == '!' ? 1 : 0);
3832 if (req_state & REQ_ASK)
3834 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
3835 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
3837 else if (req_state & REQ_CONFIRM)
3839 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
3841 else if (req_state & REQ_PLAYER)
3843 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
3844 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
3845 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
3846 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
3849 /* copy request gadgets to door backbuffer */
3850 BlitBitmap(drawto, bitmap_db_door_1, DX, DY, DXSIZE, DYSIZE, 0, 0);
3852 OpenDoor(DOOR_OPEN_1);
3854 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
3856 if (game_status == GAME_MODE_PLAYING)
3858 SetPanelBackground();
3859 SetDrawBackgroundMask(REDRAW_DOOR_1);
3863 SetDrawBackgroundMask(REDRAW_FIELD);
3869 if (game_status != GAME_MODE_MAIN)
3872 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3874 // ---------- handle request buttons ----------
3875 result = RequestHandleEvents(req_state);
3877 if (game_status != GAME_MODE_MAIN)
3882 if (!(req_state & REQ_STAY_OPEN))
3884 CloseDoor(DOOR_CLOSE_1);
3886 if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
3887 (req_state & REQ_REOPEN))
3888 OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
3893 if (game_status == GAME_MODE_PLAYING)
3895 SetPanelBackground();
3896 SetDrawBackgroundMask(REDRAW_DOOR_1);
3900 SetDrawBackgroundMask(REDRAW_FIELD);
3903 #if defined(NETWORK_AVALIABLE)
3904 /* continue network game after request */
3905 if (options.network &&
3906 game_status == GAME_MODE_PLAYING &&
3907 req_state & REQUEST_WAIT_FOR_INPUT)
3908 SendToServer_ContinuePlaying();
3911 /* restore deactivated drawing when quick-loading level tape recording */
3912 if (tape.playing && tape.deactivate_display)
3913 TapeDeactivateDisplayOn();
3918 static boolean RequestEnvelope(char *text, unsigned int req_state)
3922 if (game_status == GAME_MODE_PLAYING)
3923 BlitScreenToBitmap(backbuffer);
3925 /* disable deactivated drawing when quick-loading level tape recording */
3926 if (tape.playing && tape.deactivate_display)
3927 TapeDeactivateDisplayOff(TRUE);
3929 SetMouseCursor(CURSOR_DEFAULT);
3931 #if defined(NETWORK_AVALIABLE)
3932 /* pause network game while waiting for request to answer */
3933 if (options.network &&
3934 game_status == GAME_MODE_PLAYING &&
3935 req_state & REQUEST_WAIT_FOR_INPUT)
3936 SendToServer_PausePlaying();
3939 /* simulate releasing mouse button over last gadget, if still pressed */
3941 HandleGadgets(-1, -1, 0);
3945 // (replace with setting corresponding request background)
3946 // SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
3947 // SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3949 /* clear door drawing field */
3950 // DrawBackground(DX, DY, DXSIZE, DYSIZE);
3952 ShowEnvelopeRequest(text, req_state, ACTION_OPENING);
3954 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
3956 if (game_status == GAME_MODE_PLAYING)
3958 SetPanelBackground();
3959 SetDrawBackgroundMask(REDRAW_DOOR_1);
3963 SetDrawBackgroundMask(REDRAW_FIELD);
3969 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3971 // ---------- handle request buttons ----------
3972 result = RequestHandleEvents(req_state);
3974 if (game_status != GAME_MODE_MAIN)
3979 ShowEnvelopeRequest(text, req_state, ACTION_CLOSING);
3983 if (game_status == GAME_MODE_PLAYING)
3985 SetPanelBackground();
3986 SetDrawBackgroundMask(REDRAW_DOOR_1);
3990 SetDrawBackgroundMask(REDRAW_FIELD);
3993 #if defined(NETWORK_AVALIABLE)
3994 /* continue network game after request */
3995 if (options.network &&
3996 game_status == GAME_MODE_PLAYING &&
3997 req_state & REQUEST_WAIT_FOR_INPUT)
3998 SendToServer_ContinuePlaying();
4001 /* restore deactivated drawing when quick-loading level tape recording */
4002 if (tape.playing && tape.deactivate_display)
4003 TapeDeactivateDisplayOn();
4008 boolean Request(char *text, unsigned int req_state)
4010 if (global.use_envelope_request)
4011 return RequestEnvelope(text, req_state);
4013 return RequestDoor(text, req_state);
4016 static int compareDoorPartOrderInfo(const void *object1, const void *object2)
4018 const struct DoorPartOrderInfo *dpo1 = (struct DoorPartOrderInfo *)object1;
4019 const struct DoorPartOrderInfo *dpo2 = (struct DoorPartOrderInfo *)object2;
4022 if (dpo1->sort_priority != dpo2->sort_priority)
4023 compare_result = dpo1->sort_priority - dpo2->sort_priority;
4025 compare_result = dpo1->nr - dpo2->nr;
4027 return compare_result;
4030 void InitGraphicCompatibilityInfo_Doors()
4036 struct DoorInfo *door;
4040 { DOOR_1, IMG_DOOR_1_GFX_PART_1, IMG_DOOR_1_GFX_PART_8, &door_1 },
4041 { DOOR_2, IMG_DOOR_2_GFX_PART_1, IMG_DOOR_2_GFX_PART_8, &door_2 },
4043 { -1, -1, -1, NULL }
4045 struct Rect door_rect_list[] =
4047 { DX, DY, DXSIZE, DYSIZE },
4048 { VX, VY, VXSIZE, VYSIZE }
4052 for (i = 0; doors[i].door_token != -1; i++)
4054 int door_token = doors[i].door_token;
4055 int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
4056 int part_1 = doors[i].part_1;
4057 int part_8 = doors[i].part_8;
4058 int part_2 = part_1 + 1;
4059 int part_3 = part_1 + 2;
4060 struct DoorInfo *door = doors[i].door;
4061 struct Rect *door_rect = &door_rect_list[door_index];
4062 boolean door_gfx_redefined = FALSE;
4064 /* check if any door part graphic definitions have been redefined */
4066 for (j = 0; door_part_controls[j].door_token != -1; j++)
4068 struct DoorPartControlInfo *dpc = &door_part_controls[j];
4069 struct FileInfo *fi = getImageListEntryFromImageID(dpc->graphic);
4071 if (dpc->door_token == door_token && fi->redefined)
4072 door_gfx_redefined = TRUE;
4075 /* check for old-style door graphic/animation modifications */
4077 if (!door_gfx_redefined)
4079 if (door->anim_mode & ANIM_STATIC_PANEL)
4081 door->panel.step_xoffset = 0;
4082 door->panel.step_yoffset = 0;
4085 if (door->anim_mode & (ANIM_HORIZONTAL | ANIM_VERTICAL))
4087 struct GraphicInfo *g_part_1 = &graphic_info[part_1];
4088 struct GraphicInfo *g_part_2 = &graphic_info[part_2];
4089 int num_door_steps, num_panel_steps;
4091 /* remove door part graphics other than the two default wings */
4093 for (j = 0; door_part_controls[j].door_token != -1; j++)
4095 struct DoorPartControlInfo *dpc = &door_part_controls[j];
4096 struct GraphicInfo *g = &graphic_info[dpc->graphic];
4098 if (dpc->graphic >= part_3 &&
4099 dpc->graphic <= part_8)
4103 /* set graphics and screen positions of the default wings */
4105 g_part_1->width = door_rect->width;
4106 g_part_1->height = door_rect->height;
4107 g_part_2->width = door_rect->width;
4108 g_part_2->height = door_rect->height;
4109 g_part_2->src_x = door_rect->width;
4110 g_part_2->src_y = g_part_1->src_y;
4112 door->part_2.x = door->part_1.x;
4113 door->part_2.y = door->part_1.y;
4115 if (door->width != -1)
4117 g_part_1->width = door->width;
4118 g_part_2->width = door->width;
4120 // special treatment for graphics and screen position of right wing
4121 g_part_2->src_x += door_rect->width - door->width;
4122 door->part_2.x += door_rect->width - door->width;
4125 if (door->height != -1)
4127 g_part_1->height = door->height;
4128 g_part_2->height = door->height;
4130 // special treatment for graphics and screen position of bottom wing
4131 g_part_2->src_y += door_rect->height - door->height;
4132 door->part_2.y += door_rect->height - door->height;
4135 /* set animation delays for the default wings and panels */
4137 door->part_1.step_delay = door->step_delay;
4138 door->part_2.step_delay = door->step_delay;
4139 door->panel.step_delay = door->step_delay;
4141 /* set animation draw order for the default wings */
4143 door->part_1.sort_priority = 2; /* draw left wing over ... */
4144 door->part_2.sort_priority = 1; /* ... right wing */
4146 /* set animation draw offset for the default wings */
4148 if (door->anim_mode & ANIM_HORIZONTAL)
4150 door->part_1.step_xoffset = door->step_offset;
4151 door->part_1.step_yoffset = 0;
4152 door->part_2.step_xoffset = door->step_offset * -1;
4153 door->part_2.step_yoffset = 0;
4155 num_door_steps = g_part_1->width / door->step_offset;
4157 else // ANIM_VERTICAL
4159 door->part_1.step_xoffset = 0;
4160 door->part_1.step_yoffset = door->step_offset;
4161 door->part_2.step_xoffset = 0;
4162 door->part_2.step_yoffset = door->step_offset * -1;
4164 num_door_steps = g_part_1->height / door->step_offset;
4167 /* set animation draw offset for the default panels */
4169 if (door->step_offset > 1)
4171 num_panel_steps = 2 * door_rect->height / door->step_offset;
4172 door->panel.start_step = num_panel_steps - num_door_steps;
4173 door->panel.start_step_closing = door->panel.start_step;
4177 num_panel_steps = door_rect->height / door->step_offset;
4178 door->panel.start_step = num_panel_steps - num_door_steps / 2;
4179 door->panel.start_step_closing = door->panel.start_step;
4180 door->panel.step_delay *= 2;
4191 for (i = 0; door_part_controls[i].door_token != -1; i++)
4193 struct DoorPartControlInfo *dpc = &door_part_controls[i];
4194 struct DoorPartOrderInfo *dpo = &door_part_order[i];
4196 /* initialize "start_step_opening" and "start_step_closing", if needed */
4197 if (dpc->pos->start_step_opening == 0 &&
4198 dpc->pos->start_step_closing == 0)
4200 // dpc->pos->start_step_opening = dpc->pos->start_step;
4201 dpc->pos->start_step_closing = dpc->pos->start_step;
4204 /* fill structure for door part draw order (sorted below) */
4206 dpo->sort_priority = dpc->pos->sort_priority;
4209 /* sort door part controls according to sort_priority and graphic number */
4210 qsort(door_part_order, MAX_DOOR_PARTS,
4211 sizeof(struct DoorPartOrderInfo), compareDoorPartOrderInfo);
4214 unsigned int OpenDoor(unsigned int door_state)
4216 if (door_state & DOOR_COPY_BACK)
4218 if (door_state & DOOR_OPEN_1)
4219 BlitBitmap(bitmap_db_door_1, bitmap_db_door_1,
4220 1 * DXSIZE, 0, DXSIZE, DYSIZE, 0 * DXSIZE, 0);
4222 if (door_state & DOOR_OPEN_2)
4223 BlitBitmap(bitmap_db_door_2, bitmap_db_door_2,
4224 1 * VXSIZE, 0, VXSIZE, VYSIZE, 0 * VXSIZE, 0);
4226 door_state &= ~DOOR_COPY_BACK;
4229 return MoveDoor(door_state);
4232 unsigned int CloseDoor(unsigned int door_state)
4234 unsigned int old_door_state = GetDoorState();
4236 if (!(door_state & DOOR_NO_COPY_BACK))
4238 if (old_door_state & DOOR_OPEN_1)
4239 BlitBitmap(backbuffer, bitmap_db_door_1,
4240 DX, DY, DXSIZE, DYSIZE, 0, 0);
4242 if (old_door_state & DOOR_OPEN_2)
4243 BlitBitmap(backbuffer, bitmap_db_door_2,
4244 VX, VY, VXSIZE, VYSIZE, 0, 0);
4246 door_state &= ~DOOR_NO_COPY_BACK;
4249 return MoveDoor(door_state);
4252 unsigned int GetDoorState()
4254 return MoveDoor(DOOR_GET_STATE);
4257 unsigned int SetDoorState(unsigned int door_state)
4259 return MoveDoor(door_state | DOOR_SET_STATE);
4262 int euclid(int a, int b)
4264 return (b ? euclid(b, a % b) : a);
4267 unsigned int MoveDoor(unsigned int door_state)
4269 struct Rect door_rect_list[] =
4271 { DX, DY, DXSIZE, DYSIZE },
4272 { VX, VY, VXSIZE, VYSIZE }
4274 static int door1 = DOOR_CLOSE_1;
4275 static int door2 = DOOR_CLOSE_2;
4276 unsigned int door_delay = 0;
4277 unsigned int door_delay_value;
4280 if (door_state == DOOR_GET_STATE)
4281 return (door1 | door2);
4283 if (door_state & DOOR_SET_STATE)
4285 if (door_state & DOOR_ACTION_1)
4286 door1 = door_state & DOOR_ACTION_1;
4287 if (door_state & DOOR_ACTION_2)
4288 door2 = door_state & DOOR_ACTION_2;
4290 return (door1 | door2);
4293 if (!(door_state & DOOR_FORCE_REDRAW))
4295 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
4296 door_state &= ~DOOR_OPEN_1;
4297 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
4298 door_state &= ~DOOR_CLOSE_1;
4299 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
4300 door_state &= ~DOOR_OPEN_2;
4301 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
4302 door_state &= ~DOOR_CLOSE_2;
4305 if (global.autoplay_leveldir)
4307 door_state |= DOOR_NO_DELAY;
4308 door_state &= ~DOOR_CLOSE_ALL;
4311 if (game_status == GAME_MODE_EDITOR)
4312 door_state |= DOOR_NO_DELAY;
4314 if (door_state & DOOR_ACTION)
4316 boolean door_panel_drawn[NUM_DOORS];
4317 boolean panel_has_doors[NUM_DOORS];
4318 boolean door_part_skip[MAX_DOOR_PARTS];
4319 boolean door_part_done[MAX_DOOR_PARTS];
4320 boolean door_part_done_all;
4321 int num_steps[MAX_DOOR_PARTS];
4322 int max_move_delay = 0; // delay for complete animations of all doors
4323 int max_step_delay = 0; // delay (ms) between two animation frames
4324 int num_move_steps = 0; // number of animation steps for all doors
4325 int max_move_delay_doors_only = 0; // delay for doors only (no panel)
4326 int num_move_steps_doors_only = 0; // steps for doors only (no panel)
4327 int current_move_delay = 0;
4331 for (i = 0; i < NUM_DOORS; i++)
4332 panel_has_doors[i] = FALSE;
4334 for (i = 0; i < MAX_DOOR_PARTS; i++)
4336 struct DoorPartControlInfo *dpc = &door_part_controls[i];
4337 struct GraphicInfo *g = &graphic_info[dpc->graphic];
4338 int door_token = dpc->door_token;
4340 door_part_done[i] = FALSE;
4341 door_part_skip[i] = (!(door_state & door_token) ||
4345 for (i = 0; i < MAX_DOOR_PARTS; i++)
4347 int nr = door_part_order[i].nr;
4348 struct DoorPartControlInfo *dpc = &door_part_controls[nr];
4349 struct DoorPartPosInfo *pos = dpc->pos;
4350 struct GraphicInfo *g = &graphic_info[dpc->graphic];
4351 int door_token = dpc->door_token;
4352 int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
4353 boolean is_panel = DOOR_PART_IS_PANEL(nr);
4354 int step_xoffset = ABS(pos->step_xoffset);
4355 int step_yoffset = ABS(pos->step_yoffset);
4356 int step_delay = pos->step_delay;
4357 int current_door_state = door_state & door_token;
4358 boolean door_opening = ((current_door_state & DOOR_OPEN) != 0);
4359 boolean door_closing = ((current_door_state & DOOR_CLOSE) != 0);
4360 boolean part_opening = (is_panel ? door_closing : door_opening);
4361 int start_step = (part_opening ? pos->start_step_opening :
4362 pos->start_step_closing);
4363 float move_xsize = (step_xoffset ? g->width : 0);
4364 float move_ysize = (step_yoffset ? g->height : 0);
4365 int move_xsteps = (step_xoffset ? ceil(move_xsize / step_xoffset) : 0);
4366 int move_ysteps = (step_yoffset ? ceil(move_ysize / step_yoffset) : 0);
4367 int move_steps = (move_xsteps && move_ysteps ?
4368 MIN(move_xsteps, move_ysteps) :
4369 move_xsteps ? move_xsteps : move_ysteps) - start_step;
4370 int move_delay = move_steps * step_delay;
4372 if (door_part_skip[nr])
4375 max_move_delay = MAX(max_move_delay, move_delay);
4376 max_step_delay = (max_step_delay == 0 ? step_delay :
4377 euclid(max_step_delay, step_delay));
4378 num_steps[nr] = move_steps;
4382 max_move_delay_doors_only = MAX(max_move_delay_doors_only, move_delay);
4384 panel_has_doors[door_index] = TRUE;
4388 max_step_delay = MAX(1, max_step_delay); // prevent division by zero
4390 num_move_steps = max_move_delay / max_step_delay;
4391 num_move_steps_doors_only = max_move_delay_doors_only / max_step_delay;
4393 door_delay_value = max_step_delay;
4395 if ((door_state & DOOR_NO_DELAY) || setup.quick_doors)
4397 start = num_move_steps - 1;
4401 /* opening door sound has priority over simultaneously closing door */
4402 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
4403 PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
4404 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
4405 PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
4408 for (k = start; k < num_move_steps; k++)
4410 int last_frame = num_move_steps - 1; // last frame of this "for" loop
4412 door_part_done_all = TRUE;
4414 for (i = 0; i < NUM_DOORS; i++)
4415 door_panel_drawn[i] = FALSE;
4417 for (i = 0; i < MAX_DOOR_PARTS; i++)
4419 int nr = door_part_order[i].nr;
4420 struct DoorPartControlInfo *dpc = &door_part_controls[nr];
4421 struct DoorPartPosInfo *pos = dpc->pos;
4422 struct GraphicInfo *g = &graphic_info[dpc->graphic];
4423 int door_token = dpc->door_token;
4424 int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
4425 boolean is_panel = DOOR_PART_IS_PANEL(nr);
4426 boolean is_panel_and_door_has_closed = FALSE;
4427 struct Rect *door_rect = &door_rect_list[door_index];
4428 Bitmap *bitmap_db_door = (door_token == DOOR_1 ? bitmap_db_door_1 :
4430 Bitmap *bitmap = (is_panel ? bitmap_db_door : g->bitmap);
4431 int current_door_state = door_state & door_token;
4432 boolean door_opening = ((current_door_state & DOOR_OPEN) != 0);
4433 boolean door_closing = !door_opening;
4434 boolean part_opening = (is_panel ? door_closing : door_opening);
4435 boolean part_closing = !part_opening;
4436 int start_step = (part_opening ? pos->start_step_opening :
4437 pos->start_step_closing);
4438 int step_delay = pos->step_delay;
4439 int step_factor = step_delay / max_step_delay;
4440 int k1 = (step_factor ? k / step_factor + 1 : k);
4441 int k2 = (part_opening ? k1 + start_step : num_steps[nr] - k1);
4442 int kk = MAX(0, k2);
4445 int src_x, src_y, src_xx, src_yy;
4446 int dst_x, dst_y, dst_xx, dst_yy;
4449 if (door_part_skip[nr])
4452 if (!(door_state & door_token))
4460 int k2_door = (door_opening ? k : num_move_steps_doors_only - k - 1);
4461 int kk_door = MAX(0, k2_door);
4462 int sync_frame = kk_door * door_delay_value;
4463 int frame = getGraphicAnimationFrame(dpc->graphic, sync_frame);
4465 getGraphicSource(dpc->graphic, frame, &bitmap, &g_src_x, &g_src_y);
4470 if (!door_panel_drawn[door_index])
4472 ClearRectangle(drawto, door_rect->x, door_rect->y,
4473 door_rect->width, door_rect->height);
4475 door_panel_drawn[door_index] = TRUE;
4478 // draw opening or closing door parts
4480 if (pos->step_xoffset < 0) // door part on right side
4483 dst_xx = pos->x + ABS(kk * pos->step_xoffset);
4486 if (dst_xx + width > door_rect->width)
4487 width = door_rect->width - dst_xx;
4489 else // door part on left side
4492 dst_xx = pos->x - kk * pos->step_xoffset;
4496 src_xx = ABS(dst_xx);
4500 width = g->width - src_xx;
4502 if (width > door_rect->width)
4503 width = door_rect->width;
4505 // printf("::: k == %d [%d] \n", k, start_step);
4508 if (pos->step_yoffset < 0) // door part on bottom side
4511 dst_yy = pos->y + ABS(kk * pos->step_yoffset);
4514 if (dst_yy + height > door_rect->height)
4515 height = door_rect->height - dst_yy;
4517 else // door part on top side
4520 dst_yy = pos->y - kk * pos->step_yoffset;
4524 src_yy = ABS(dst_yy);
4528 height = g->height - src_yy;
4531 src_x = g_src_x + src_xx;
4532 src_y = g_src_y + src_yy;
4534 dst_x = door_rect->x + dst_xx;
4535 dst_y = door_rect->y + dst_yy;
4537 is_panel_and_door_has_closed =
4540 panel_has_doors[door_index] &&
4541 k >= num_move_steps_doors_only - 1);
4543 if (width >= 0 && width <= g->width &&
4544 height >= 0 && height <= g->height &&
4545 !is_panel_and_door_has_closed)
4547 if (is_panel || !pos->draw_masked)
4548 BlitBitmap(bitmap, drawto, src_x, src_y, width, height,
4551 BlitBitmapMasked(bitmap, drawto, src_x, src_y, width, height,
4555 redraw_mask |= REDRAW_DOOR_FROM_TOKEN(door_token);
4557 if ((part_opening && (width < 0 || height < 0)) ||
4558 (part_closing && (width >= g->width && height >= g->height)))
4559 door_part_done[nr] = TRUE;
4561 // continue door part animations, but not panel after door has closed
4562 if (!door_part_done[nr] && !is_panel_and_door_has_closed)
4563 door_part_done_all = FALSE;
4566 if (!(door_state & DOOR_NO_DELAY))
4570 if (game_status == GAME_MODE_MAIN)
4573 SkipUntilDelayReached(&door_delay, door_delay_value, &k, last_frame);
4575 current_move_delay += max_step_delay;
4578 if (door_part_done_all)
4583 if (door_state & DOOR_ACTION_1)
4584 door1 = door_state & DOOR_ACTION_1;
4585 if (door_state & DOOR_ACTION_2)
4586 door2 = door_state & DOOR_ACTION_2;
4588 // draw masked border over door area
4589 DrawMaskedBorder(REDRAW_DOOR_1);
4590 DrawMaskedBorder(REDRAW_DOOR_2);
4592 return (door1 | door2);
4595 static boolean useSpecialEditorDoor()
4597 int graphic = IMG_GLOBAL_BORDER_EDITOR;
4598 boolean redefined = getImageListEntryFromImageID(graphic)->redefined;
4600 // do not draw special editor door if editor border defined or redefined
4601 if (graphic_info[graphic].bitmap != NULL || redefined)
4604 // do not draw special editor door if global border defined to be empty
4605 if (graphic_info[IMG_GLOBAL_BORDER].bitmap == NULL)
4608 // do not draw special editor door if viewport definitions do not match
4612 EY + EYSIZE != VY + VYSIZE)
4618 void DrawSpecialEditorDoor()
4620 struct GraphicInfo *gfx1 = &graphic_info[IMG_DOOR_2_TOP_BORDER_CORRECTION];
4621 int top_border_width = gfx1->width;
4622 int top_border_height = gfx1->height;
4623 int outer_border = viewport.door_2[GAME_MODE_EDITOR].border_size;
4624 int ex = EX - outer_border;
4625 int ey = EY - outer_border;
4626 int vy = VY - outer_border;
4627 int exsize = EXSIZE + 2 * outer_border;
4629 if (!useSpecialEditorDoor())
4632 /* draw bigger level editor toolbox window */
4633 BlitBitmap(gfx1->bitmap, drawto, gfx1->src_x, gfx1->src_y,
4634 top_border_width, top_border_height, ex, ey - top_border_height);
4635 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto, ex, vy,
4636 exsize, EYSIZE - VYSIZE + outer_border, ex, ey);
4638 redraw_mask |= REDRAW_ALL;
4641 void UndrawSpecialEditorDoor()
4643 struct GraphicInfo *gfx1 = &graphic_info[IMG_DOOR_2_TOP_BORDER_CORRECTION];
4644 int top_border_width = gfx1->width;
4645 int top_border_height = gfx1->height;
4646 int outer_border = viewport.door_2[GAME_MODE_EDITOR].border_size;
4647 int ex = EX - outer_border;
4648 int ey = EY - outer_border;
4649 int ey_top = ey - top_border_height;
4650 int exsize = EXSIZE + 2 * outer_border;
4651 int eysize = EYSIZE + 2 * outer_border;
4653 if (!useSpecialEditorDoor())
4656 /* draw normal tape recorder window */
4657 if (graphic_info[IMG_GLOBAL_BORDER].bitmap)
4659 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
4660 ex, ey_top, top_border_width, top_border_height,
4662 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
4663 ex, ey, exsize, eysize, ex, ey);
4667 // if screen background is set to "[NONE]", clear editor toolbox window
4668 ClearRectangle(drawto, ex, ey_top, top_border_width, top_border_height);
4669 ClearRectangle(drawto, ex, ey, exsize, eysize);
4672 redraw_mask |= REDRAW_ALL;
4676 /* ---------- new tool button stuff ---------------------------------------- */
4681 struct TextPosInfo *pos;
4684 } toolbutton_info[NUM_TOOL_BUTTONS] =
4687 IMG_REQUEST_BUTTON_GFX_YES, &request.button.yes,
4688 TOOL_CTRL_ID_YES, "yes"
4691 IMG_REQUEST_BUTTON_GFX_NO, &request.button.no,
4692 TOOL_CTRL_ID_NO, "no"
4695 IMG_REQUEST_BUTTON_GFX_CONFIRM, &request.button.confirm,
4696 TOOL_CTRL_ID_CONFIRM, "confirm"
4699 IMG_REQUEST_BUTTON_GFX_PLAYER_1, &request.button.player_1,
4700 TOOL_CTRL_ID_PLAYER_1, "player 1"
4703 IMG_REQUEST_BUTTON_GFX_PLAYER_2, &request.button.player_2,
4704 TOOL_CTRL_ID_PLAYER_2, "player 2"
4707 IMG_REQUEST_BUTTON_GFX_PLAYER_3, &request.button.player_3,
4708 TOOL_CTRL_ID_PLAYER_3, "player 3"
4711 IMG_REQUEST_BUTTON_GFX_PLAYER_4, &request.button.player_4,
4712 TOOL_CTRL_ID_PLAYER_4, "player 4"
4716 void CreateToolButtons()
4720 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4722 struct GraphicInfo *gfx = &graphic_info[toolbutton_info[i].graphic];
4723 struct TextPosInfo *pos = toolbutton_info[i].pos;
4724 struct GadgetInfo *gi;
4725 Bitmap *deco_bitmap = None;
4726 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
4727 unsigned int event_mask = GD_EVENT_RELEASED;
4730 int gd_x = gfx->src_x;
4731 int gd_y = gfx->src_y;
4732 int gd_xp = gfx->src_x + gfx->pressed_xoffset;
4733 int gd_yp = gfx->src_y + gfx->pressed_yoffset;
4736 if (global.use_envelope_request)
4737 setRequestPosition(&dx, &dy, TRUE);
4739 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
4741 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
4743 getSizedGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr), 0,
4744 pos->size, &deco_bitmap, &deco_x, &deco_y);
4745 deco_xpos = (gfx->width - pos->size) / 2;
4746 deco_ypos = (gfx->height - pos->size) / 2;
4749 gi = CreateGadget(GDI_CUSTOM_ID, id,
4750 GDI_INFO_TEXT, toolbutton_info[i].infotext,
4751 GDI_X, dx + GDI_ACTIVE_POS(pos->x),
4752 GDI_Y, dy + GDI_ACTIVE_POS(pos->y),
4753 GDI_WIDTH, gfx->width,
4754 GDI_HEIGHT, gfx->height,
4755 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
4756 GDI_STATE, GD_BUTTON_UNPRESSED,
4757 GDI_DESIGN_UNPRESSED, gfx->bitmap, gd_x, gd_y,
4758 GDI_DESIGN_PRESSED, gfx->bitmap, gd_xp, gd_yp,
4759 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
4760 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
4761 GDI_DECORATION_SIZE, pos->size, pos->size,
4762 GDI_DECORATION_SHIFTING, 1, 1,
4763 GDI_DIRECT_DRAW, FALSE,
4764 GDI_EVENT_MASK, event_mask,
4765 GDI_CALLBACK_ACTION, HandleToolButtons,
4769 Error(ERR_EXIT, "cannot create gadget");
4771 tool_gadget[id] = gi;
4775 void FreeToolButtons()
4779 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4780 FreeGadget(tool_gadget[i]);
4783 static void UnmapToolButtons()
4787 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4788 UnmapGadget(tool_gadget[i]);
4791 static void HandleToolButtons(struct GadgetInfo *gi)
4793 request_gadget_id = gi->custom_id;
4796 static struct Mapping_EM_to_RND_object
4799 boolean is_rnd_to_em_mapping; /* unique mapping EM <-> RND */
4800 boolean is_backside; /* backside of moving element */
4806 em_object_mapping_list[] =
4809 Xblank, TRUE, FALSE,
4813 Yacid_splash_eB, FALSE, FALSE,
4814 EL_ACID_SPLASH_RIGHT, -1, -1
4817 Yacid_splash_wB, FALSE, FALSE,
4818 EL_ACID_SPLASH_LEFT, -1, -1
4821 #ifdef EM_ENGINE_BAD_ROLL
4823 Xstone_force_e, FALSE, FALSE,
4824 EL_ROCK, -1, MV_BIT_RIGHT
4827 Xstone_force_w, FALSE, FALSE,
4828 EL_ROCK, -1, MV_BIT_LEFT
4831 Xnut_force_e, FALSE, FALSE,
4832 EL_NUT, -1, MV_BIT_RIGHT
4835 Xnut_force_w, FALSE, FALSE,
4836 EL_NUT, -1, MV_BIT_LEFT
4839 Xspring_force_e, FALSE, FALSE,
4840 EL_SPRING, -1, MV_BIT_RIGHT
4843 Xspring_force_w, FALSE, FALSE,
4844 EL_SPRING, -1, MV_BIT_LEFT
4847 Xemerald_force_e, FALSE, FALSE,
4848 EL_EMERALD, -1, MV_BIT_RIGHT
4851 Xemerald_force_w, FALSE, FALSE,
4852 EL_EMERALD, -1, MV_BIT_LEFT
4855 Xdiamond_force_e, FALSE, FALSE,
4856 EL_DIAMOND, -1, MV_BIT_RIGHT
4859 Xdiamond_force_w, FALSE, FALSE,
4860 EL_DIAMOND, -1, MV_BIT_LEFT
4863 Xbomb_force_e, FALSE, FALSE,
4864 EL_BOMB, -1, MV_BIT_RIGHT
4867 Xbomb_force_w, FALSE, FALSE,
4868 EL_BOMB, -1, MV_BIT_LEFT
4870 #endif /* EM_ENGINE_BAD_ROLL */
4873 Xstone, TRUE, FALSE,
4877 Xstone_pause, FALSE, FALSE,
4881 Xstone_fall, FALSE, FALSE,
4885 Ystone_s, FALSE, FALSE,
4886 EL_ROCK, ACTION_FALLING, -1
4889 Ystone_sB, FALSE, TRUE,
4890 EL_ROCK, ACTION_FALLING, -1
4893 Ystone_e, FALSE, FALSE,
4894 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
4897 Ystone_eB, FALSE, TRUE,
4898 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
4901 Ystone_w, FALSE, FALSE,
4902 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
4905 Ystone_wB, FALSE, TRUE,
4906 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
4913 Xnut_pause, FALSE, FALSE,
4917 Xnut_fall, FALSE, FALSE,
4921 Ynut_s, FALSE, FALSE,
4922 EL_NUT, ACTION_FALLING, -1
4925 Ynut_sB, FALSE, TRUE,
4926 EL_NUT, ACTION_FALLING, -1
4929 Ynut_e, FALSE, FALSE,
4930 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
4933 Ynut_eB, FALSE, TRUE,
4934 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
4937 Ynut_w, FALSE, FALSE,
4938 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
4941 Ynut_wB, FALSE, TRUE,
4942 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
4945 Xbug_n, TRUE, FALSE,
4949 Xbug_e, TRUE, FALSE,
4950 EL_BUG_RIGHT, -1, -1
4953 Xbug_s, TRUE, FALSE,
4957 Xbug_w, TRUE, FALSE,
4961 Xbug_gon, FALSE, FALSE,
4965 Xbug_goe, FALSE, FALSE,
4966 EL_BUG_RIGHT, -1, -1
4969 Xbug_gos, FALSE, FALSE,
4973 Xbug_gow, FALSE, FALSE,
4977 Ybug_n, FALSE, FALSE,
4978 EL_BUG, ACTION_MOVING, MV_BIT_UP
4981 Ybug_nB, FALSE, TRUE,
4982 EL_BUG, ACTION_MOVING, MV_BIT_UP
4985 Ybug_e, FALSE, FALSE,
4986 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
4989 Ybug_eB, FALSE, TRUE,
4990 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
4993 Ybug_s, FALSE, FALSE,
4994 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
4997 Ybug_sB, FALSE, TRUE,
4998 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
5001 Ybug_w, FALSE, FALSE,
5002 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
5005 Ybug_wB, FALSE, TRUE,
5006 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
5009 Ybug_w_n, FALSE, FALSE,
5010 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
5013 Ybug_n_e, FALSE, FALSE,
5014 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
5017 Ybug_e_s, FALSE, FALSE,
5018 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
5021 Ybug_s_w, FALSE, FALSE,
5022 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
5025 Ybug_e_n, FALSE, FALSE,
5026 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
5029 Ybug_s_e, FALSE, FALSE,
5030 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
5033 Ybug_w_s, FALSE, FALSE,
5034 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
5037 Ybug_n_w, FALSE, FALSE,
5038 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
5041 Ybug_stone, FALSE, FALSE,
5042 EL_BUG, ACTION_SMASHED_BY_ROCK, -1
5045 Ybug_spring, FALSE, FALSE,
5046 EL_BUG, ACTION_SMASHED_BY_SPRING, -1
5049 Xtank_n, TRUE, FALSE,
5050 EL_SPACESHIP_UP, -1, -1
5053 Xtank_e, TRUE, FALSE,
5054 EL_SPACESHIP_RIGHT, -1, -1
5057 Xtank_s, TRUE, FALSE,
5058 EL_SPACESHIP_DOWN, -1, -1
5061 Xtank_w, TRUE, FALSE,
5062 EL_SPACESHIP_LEFT, -1, -1
5065 Xtank_gon, FALSE, FALSE,
5066 EL_SPACESHIP_UP, -1, -1
5069 Xtank_goe, FALSE, FALSE,
5070 EL_SPACESHIP_RIGHT, -1, -1
5073 Xtank_gos, FALSE, FALSE,
5074 EL_SPACESHIP_DOWN, -1, -1
5077 Xtank_gow, FALSE, FALSE,
5078 EL_SPACESHIP_LEFT, -1, -1
5081 Ytank_n, FALSE, FALSE,
5082 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
5085 Ytank_nB, FALSE, TRUE,
5086 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
5089 Ytank_e, FALSE, FALSE,
5090 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
5093 Ytank_eB, FALSE, TRUE,
5094 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
5097 Ytank_s, FALSE, FALSE,
5098 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
5101 Ytank_sB, FALSE, TRUE,
5102 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
5105 Ytank_w, FALSE, FALSE,
5106 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
5109 Ytank_wB, FALSE, TRUE,
5110 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
5113 Ytank_w_n, FALSE, FALSE,
5114 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
5117 Ytank_n_e, FALSE, FALSE,
5118 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
5121 Ytank_e_s, FALSE, FALSE,
5122 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
5125 Ytank_s_w, FALSE, FALSE,
5126 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
5129 Ytank_e_n, FALSE, FALSE,
5130 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
5133 Ytank_s_e, FALSE, FALSE,
5134 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
5137 Ytank_w_s, FALSE, FALSE,
5138 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
5141 Ytank_n_w, FALSE, FALSE,
5142 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
5145 Ytank_stone, FALSE, FALSE,
5146 EL_SPACESHIP, ACTION_SMASHED_BY_ROCK, -1
5149 Ytank_spring, FALSE, FALSE,
5150 EL_SPACESHIP, ACTION_SMASHED_BY_SPRING, -1
5153 Xandroid, TRUE, FALSE,
5154 EL_EMC_ANDROID, ACTION_ACTIVE, -1
5157 Xandroid_1_n, FALSE, FALSE,
5158 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
5161 Xandroid_2_n, FALSE, FALSE,
5162 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
5165 Xandroid_1_e, FALSE, FALSE,
5166 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
5169 Xandroid_2_e, FALSE, FALSE,
5170 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
5173 Xandroid_1_w, FALSE, FALSE,
5174 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
5177 Xandroid_2_w, FALSE, FALSE,
5178 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
5181 Xandroid_1_s, FALSE, FALSE,
5182 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
5185 Xandroid_2_s, FALSE, FALSE,
5186 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
5189 Yandroid_n, FALSE, FALSE,
5190 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
5193 Yandroid_nB, FALSE, TRUE,
5194 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
5197 Yandroid_ne, FALSE, FALSE,
5198 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPRIGHT
5201 Yandroid_neB, FALSE, TRUE,
5202 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPRIGHT
5205 Yandroid_e, FALSE, FALSE,
5206 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
5209 Yandroid_eB, FALSE, TRUE,
5210 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
5213 Yandroid_se, FALSE, FALSE,
5214 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNRIGHT
5217 Yandroid_seB, FALSE, TRUE,
5218 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNRIGHT
5221 Yandroid_s, FALSE, FALSE,
5222 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
5225 Yandroid_sB, FALSE, TRUE,
5226 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
5229 Yandroid_sw, FALSE, FALSE,
5230 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNLEFT
5233 Yandroid_swB, FALSE, TRUE,
5234 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNLEFT
5237 Yandroid_w, FALSE, FALSE,
5238 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
5241 Yandroid_wB, FALSE, TRUE,
5242 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
5245 Yandroid_nw, FALSE, FALSE,
5246 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPLEFT
5249 Yandroid_nwB, FALSE, TRUE,
5250 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPLEFT
5253 Xspring, TRUE, FALSE,
5257 Xspring_pause, FALSE, FALSE,
5261 Xspring_e, FALSE, FALSE,
5265 Xspring_w, FALSE, FALSE,
5269 Xspring_fall, FALSE, FALSE,
5273 Yspring_s, FALSE, FALSE,
5274 EL_SPRING, ACTION_FALLING, -1
5277 Yspring_sB, FALSE, TRUE,
5278 EL_SPRING, ACTION_FALLING, -1
5281 Yspring_e, FALSE, FALSE,
5282 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
5285 Yspring_eB, FALSE, TRUE,
5286 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
5289 Yspring_w, FALSE, FALSE,
5290 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
5293 Yspring_wB, FALSE, TRUE,
5294 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
5297 Yspring_kill_e, FALSE, FALSE,
5298 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
5301 Yspring_kill_eB, FALSE, TRUE,
5302 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
5305 Yspring_kill_w, FALSE, FALSE,
5306 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
5309 Yspring_kill_wB, FALSE, TRUE,
5310 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
5313 Xeater_n, TRUE, FALSE,
5314 EL_YAMYAM_UP, -1, -1
5317 Xeater_e, TRUE, FALSE,
5318 EL_YAMYAM_RIGHT, -1, -1
5321 Xeater_w, TRUE, FALSE,
5322 EL_YAMYAM_LEFT, -1, -1
5325 Xeater_s, TRUE, FALSE,
5326 EL_YAMYAM_DOWN, -1, -1
5329 Yeater_n, FALSE, FALSE,
5330 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
5333 Yeater_nB, FALSE, TRUE,
5334 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
5337 Yeater_e, FALSE, FALSE,
5338 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
5341 Yeater_eB, FALSE, TRUE,
5342 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
5345 Yeater_s, FALSE, FALSE,
5346 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
5349 Yeater_sB, FALSE, TRUE,
5350 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
5353 Yeater_w, FALSE, FALSE,
5354 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
5357 Yeater_wB, FALSE, TRUE,
5358 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
5361 Yeater_stone, FALSE, FALSE,
5362 EL_YAMYAM, ACTION_SMASHED_BY_ROCK, -1
5365 Yeater_spring, FALSE, FALSE,
5366 EL_YAMYAM, ACTION_SMASHED_BY_SPRING, -1
5369 Xalien, TRUE, FALSE,
5373 Xalien_pause, FALSE, FALSE,
5377 Yalien_n, FALSE, FALSE,
5378 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
5381 Yalien_nB, FALSE, TRUE,
5382 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
5385 Yalien_e, FALSE, FALSE,
5386 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
5389 Yalien_eB, FALSE, TRUE,
5390 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
5393 Yalien_s, FALSE, FALSE,
5394 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
5397 Yalien_sB, FALSE, TRUE,
5398 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
5401 Yalien_w, FALSE, FALSE,
5402 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
5405 Yalien_wB, FALSE, TRUE,
5406 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
5409 Yalien_stone, FALSE, FALSE,
5410 EL_ROBOT, ACTION_SMASHED_BY_ROCK, -1
5413 Yalien_spring, FALSE, FALSE,
5414 EL_ROBOT, ACTION_SMASHED_BY_SPRING, -1
5417 Xemerald, TRUE, FALSE,
5421 Xemerald_pause, FALSE, FALSE,
5425 Xemerald_fall, FALSE, FALSE,
5429 Xemerald_shine, FALSE, FALSE,
5430 EL_EMERALD, ACTION_TWINKLING, -1
5433 Yemerald_s, FALSE, FALSE,
5434 EL_EMERALD, ACTION_FALLING, -1
5437 Yemerald_sB, FALSE, TRUE,
5438 EL_EMERALD, ACTION_FALLING, -1
5441 Yemerald_e, FALSE, FALSE,
5442 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
5445 Yemerald_eB, FALSE, TRUE,
5446 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
5449 Yemerald_w, FALSE, FALSE,
5450 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
5453 Yemerald_wB, FALSE, TRUE,
5454 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
5457 Yemerald_eat, FALSE, FALSE,
5458 EL_EMERALD, ACTION_COLLECTING, -1
5461 Yemerald_stone, FALSE, FALSE,
5462 EL_NUT, ACTION_BREAKING, -1
5465 Xdiamond, TRUE, FALSE,
5469 Xdiamond_pause, FALSE, FALSE,
5473 Xdiamond_fall, FALSE, FALSE,
5477 Xdiamond_shine, FALSE, FALSE,
5478 EL_DIAMOND, ACTION_TWINKLING, -1
5481 Ydiamond_s, FALSE, FALSE,
5482 EL_DIAMOND, ACTION_FALLING, -1
5485 Ydiamond_sB, FALSE, TRUE,
5486 EL_DIAMOND, ACTION_FALLING, -1
5489 Ydiamond_e, FALSE, FALSE,
5490 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
5493 Ydiamond_eB, FALSE, TRUE,
5494 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
5497 Ydiamond_w, FALSE, FALSE,
5498 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
5501 Ydiamond_wB, FALSE, TRUE,
5502 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
5505 Ydiamond_eat, FALSE, FALSE,
5506 EL_DIAMOND, ACTION_COLLECTING, -1
5509 Ydiamond_stone, FALSE, FALSE,
5510 EL_DIAMOND, ACTION_SMASHED_BY_ROCK, -1
5513 Xdrip_fall, TRUE, FALSE,
5514 EL_AMOEBA_DROP, -1, -1
5517 Xdrip_stretch, FALSE, FALSE,
5518 EL_AMOEBA_DROP, ACTION_FALLING, -1
5521 Xdrip_stretchB, FALSE, TRUE,
5522 EL_AMOEBA_DROP, ACTION_FALLING, -1
5525 Xdrip_eat, FALSE, FALSE,
5526 EL_AMOEBA_DROP, ACTION_GROWING, -1
5529 Ydrip_s1, FALSE, FALSE,
5530 EL_AMOEBA_DROP, ACTION_FALLING, -1
5533 Ydrip_s1B, FALSE, TRUE,
5534 EL_AMOEBA_DROP, ACTION_FALLING, -1
5537 Ydrip_s2, FALSE, FALSE,
5538 EL_AMOEBA_DROP, ACTION_FALLING, -1
5541 Ydrip_s2B, FALSE, TRUE,
5542 EL_AMOEBA_DROP, ACTION_FALLING, -1
5549 Xbomb_pause, FALSE, FALSE,
5553 Xbomb_fall, FALSE, FALSE,
5557 Ybomb_s, FALSE, FALSE,
5558 EL_BOMB, ACTION_FALLING, -1
5561 Ybomb_sB, FALSE, TRUE,
5562 EL_BOMB, ACTION_FALLING, -1
5565 Ybomb_e, FALSE, FALSE,
5566 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
5569 Ybomb_eB, FALSE, TRUE,
5570 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
5573 Ybomb_w, FALSE, FALSE,
5574 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
5577 Ybomb_wB, FALSE, TRUE,
5578 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
5581 Ybomb_eat, FALSE, FALSE,
5582 EL_BOMB, ACTION_ACTIVATING, -1
5585 Xballoon, TRUE, FALSE,
5589 Yballoon_n, FALSE, FALSE,
5590 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
5593 Yballoon_nB, FALSE, TRUE,
5594 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
5597 Yballoon_e, FALSE, FALSE,
5598 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
5601 Yballoon_eB, FALSE, TRUE,
5602 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
5605 Yballoon_s, FALSE, FALSE,
5606 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
5609 Yballoon_sB, FALSE, TRUE,
5610 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
5613 Yballoon_w, FALSE, FALSE,
5614 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
5617 Yballoon_wB, FALSE, TRUE,
5618 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
5621 Xgrass, TRUE, FALSE,
5622 EL_EMC_GRASS, -1, -1
5625 Ygrass_nB, FALSE, FALSE,
5626 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_UP
5629 Ygrass_eB, FALSE, FALSE,
5630 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_RIGHT
5633 Ygrass_sB, FALSE, FALSE,
5634 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_DOWN
5637 Ygrass_wB, FALSE, FALSE,
5638 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_LEFT
5645 Ydirt_nB, FALSE, FALSE,
5646 EL_SAND, ACTION_DIGGING, MV_BIT_UP
5649 Ydirt_eB, FALSE, FALSE,
5650 EL_SAND, ACTION_DIGGING, MV_BIT_RIGHT
5653 Ydirt_sB, FALSE, FALSE,
5654 EL_SAND, ACTION_DIGGING, MV_BIT_DOWN
5657 Ydirt_wB, FALSE, FALSE,
5658 EL_SAND, ACTION_DIGGING, MV_BIT_LEFT
5661 Xacid_ne, TRUE, FALSE,
5662 EL_ACID_POOL_TOPRIGHT, -1, -1
5665 Xacid_se, TRUE, FALSE,
5666 EL_ACID_POOL_BOTTOMRIGHT, -1, -1
5669 Xacid_s, TRUE, FALSE,
5670 EL_ACID_POOL_BOTTOM, -1, -1
5673 Xacid_sw, TRUE, FALSE,
5674 EL_ACID_POOL_BOTTOMLEFT, -1, -1
5677 Xacid_nw, TRUE, FALSE,
5678 EL_ACID_POOL_TOPLEFT, -1, -1
5681 Xacid_1, TRUE, FALSE,
5685 Xacid_2, FALSE, FALSE,
5689 Xacid_3, FALSE, FALSE,
5693 Xacid_4, FALSE, FALSE,
5697 Xacid_5, FALSE, FALSE,
5701 Xacid_6, FALSE, FALSE,
5705 Xacid_7, FALSE, FALSE,
5709 Xacid_8, FALSE, FALSE,
5713 Xball_1, TRUE, FALSE,
5714 EL_EMC_MAGIC_BALL, -1, -1
5717 Xball_1B, FALSE, FALSE,
5718 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
5721 Xball_2, FALSE, FALSE,
5722 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
5725 Xball_2B, FALSE, FALSE,
5726 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
5729 Yball_eat, FALSE, FALSE,
5730 EL_EMC_MAGIC_BALL, ACTION_DROPPING, -1
5733 Ykey_1_eat, FALSE, FALSE,
5734 EL_EM_KEY_1, ACTION_COLLECTING, -1
5737 Ykey_2_eat, FALSE, FALSE,
5738 EL_EM_KEY_2, ACTION_COLLECTING, -1
5741 Ykey_3_eat, FALSE, FALSE,
5742 EL_EM_KEY_3, ACTION_COLLECTING, -1
5745 Ykey_4_eat, FALSE, FALSE,
5746 EL_EM_KEY_4, ACTION_COLLECTING, -1
5749 Ykey_5_eat, FALSE, FALSE,
5750 EL_EMC_KEY_5, ACTION_COLLECTING, -1
5753 Ykey_6_eat, FALSE, FALSE,
5754 EL_EMC_KEY_6, ACTION_COLLECTING, -1
5757 Ykey_7_eat, FALSE, FALSE,
5758 EL_EMC_KEY_7, ACTION_COLLECTING, -1
5761 Ykey_8_eat, FALSE, FALSE,
5762 EL_EMC_KEY_8, ACTION_COLLECTING, -1
5765 Ylenses_eat, FALSE, FALSE,
5766 EL_EMC_LENSES, ACTION_COLLECTING, -1
5769 Ymagnify_eat, FALSE, FALSE,
5770 EL_EMC_MAGNIFIER, ACTION_COLLECTING, -1
5773 Ygrass_eat, FALSE, FALSE,
5774 EL_EMC_GRASS, ACTION_SNAPPING, -1
5777 Ydirt_eat, FALSE, FALSE,
5778 EL_SAND, ACTION_SNAPPING, -1
5781 Xgrow_ns, TRUE, FALSE,
5782 EL_EXPANDABLE_WALL_VERTICAL, -1, -1
5785 Ygrow_ns_eat, FALSE, FALSE,
5786 EL_EXPANDABLE_WALL_VERTICAL, ACTION_GROWING, -1
5789 Xgrow_ew, TRUE, FALSE,
5790 EL_EXPANDABLE_WALL_HORIZONTAL, -1, -1
5793 Ygrow_ew_eat, FALSE, FALSE,
5794 EL_EXPANDABLE_WALL_HORIZONTAL, ACTION_GROWING, -1
5797 Xwonderwall, TRUE, FALSE,
5798 EL_MAGIC_WALL, -1, -1
5801 XwonderwallB, FALSE, FALSE,
5802 EL_MAGIC_WALL, ACTION_ACTIVE, -1
5805 Xamoeba_1, TRUE, FALSE,
5806 EL_AMOEBA_DRY, ACTION_OTHER, -1
5809 Xamoeba_2, FALSE, FALSE,
5810 EL_AMOEBA_DRY, ACTION_OTHER, -1
5813 Xamoeba_3, FALSE, FALSE,
5814 EL_AMOEBA_DRY, ACTION_OTHER, -1
5817 Xamoeba_4, FALSE, FALSE,
5818 EL_AMOEBA_DRY, ACTION_OTHER, -1
5821 Xamoeba_5, TRUE, FALSE,
5822 EL_AMOEBA_WET, ACTION_OTHER, -1
5825 Xamoeba_6, FALSE, FALSE,
5826 EL_AMOEBA_WET, ACTION_OTHER, -1
5829 Xamoeba_7, FALSE, FALSE,
5830 EL_AMOEBA_WET, ACTION_OTHER, -1
5833 Xamoeba_8, FALSE, FALSE,
5834 EL_AMOEBA_WET, ACTION_OTHER, -1
5837 Xdoor_1, TRUE, FALSE,
5838 EL_EM_GATE_1, -1, -1
5841 Xdoor_2, TRUE, FALSE,
5842 EL_EM_GATE_2, -1, -1
5845 Xdoor_3, TRUE, FALSE,
5846 EL_EM_GATE_3, -1, -1
5849 Xdoor_4, TRUE, FALSE,
5850 EL_EM_GATE_4, -1, -1
5853 Xdoor_5, TRUE, FALSE,
5854 EL_EMC_GATE_5, -1, -1
5857 Xdoor_6, TRUE, FALSE,
5858 EL_EMC_GATE_6, -1, -1
5861 Xdoor_7, TRUE, FALSE,
5862 EL_EMC_GATE_7, -1, -1
5865 Xdoor_8, TRUE, FALSE,
5866 EL_EMC_GATE_8, -1, -1
5869 Xkey_1, TRUE, FALSE,
5873 Xkey_2, TRUE, FALSE,
5877 Xkey_3, TRUE, FALSE,
5881 Xkey_4, TRUE, FALSE,
5885 Xkey_5, TRUE, FALSE,
5886 EL_EMC_KEY_5, -1, -1
5889 Xkey_6, TRUE, FALSE,
5890 EL_EMC_KEY_6, -1, -1
5893 Xkey_7, TRUE, FALSE,
5894 EL_EMC_KEY_7, -1, -1
5897 Xkey_8, TRUE, FALSE,
5898 EL_EMC_KEY_8, -1, -1
5901 Xwind_n, TRUE, FALSE,
5902 EL_BALLOON_SWITCH_UP, -1, -1
5905 Xwind_e, TRUE, FALSE,
5906 EL_BALLOON_SWITCH_RIGHT, -1, -1
5909 Xwind_s, TRUE, FALSE,
5910 EL_BALLOON_SWITCH_DOWN, -1, -1
5913 Xwind_w, TRUE, FALSE,
5914 EL_BALLOON_SWITCH_LEFT, -1, -1
5917 Xwind_nesw, TRUE, FALSE,
5918 EL_BALLOON_SWITCH_ANY, -1, -1
5921 Xwind_stop, TRUE, FALSE,
5922 EL_BALLOON_SWITCH_NONE, -1, -1
5926 EL_EM_EXIT_CLOSED, -1, -1
5929 Xexit_1, TRUE, FALSE,
5930 EL_EM_EXIT_OPEN, -1, -1
5933 Xexit_2, FALSE, FALSE,
5934 EL_EM_EXIT_OPEN, -1, -1
5937 Xexit_3, FALSE, FALSE,
5938 EL_EM_EXIT_OPEN, -1, -1
5941 Xdynamite, TRUE, FALSE,
5942 EL_EM_DYNAMITE, -1, -1
5945 Ydynamite_eat, FALSE, FALSE,
5946 EL_EM_DYNAMITE, ACTION_COLLECTING, -1
5949 Xdynamite_1, TRUE, FALSE,
5950 EL_EM_DYNAMITE_ACTIVE, -1, -1
5953 Xdynamite_2, FALSE, FALSE,
5954 EL_EM_DYNAMITE_ACTIVE, -1, -1
5957 Xdynamite_3, FALSE, FALSE,
5958 EL_EM_DYNAMITE_ACTIVE, -1, -1
5961 Xdynamite_4, FALSE, FALSE,
5962 EL_EM_DYNAMITE_ACTIVE, -1, -1
5965 Xbumper, TRUE, FALSE,
5966 EL_EMC_SPRING_BUMPER, -1, -1
5969 XbumperB, FALSE, FALSE,
5970 EL_EMC_SPRING_BUMPER, ACTION_ACTIVE, -1
5973 Xwheel, TRUE, FALSE,
5974 EL_ROBOT_WHEEL, -1, -1
5977 XwheelB, FALSE, FALSE,
5978 EL_ROBOT_WHEEL, ACTION_ACTIVE, -1
5981 Xswitch, TRUE, FALSE,
5982 EL_EMC_MAGIC_BALL_SWITCH, -1, -1
5985 XswitchB, FALSE, FALSE,
5986 EL_EMC_MAGIC_BALL_SWITCH, ACTION_ACTIVE, -1
5990 EL_QUICKSAND_EMPTY, -1, -1
5993 Xsand_stone, TRUE, FALSE,
5994 EL_QUICKSAND_FULL, -1, -1
5997 Xsand_stonein_1, FALSE, TRUE,
5998 EL_ROCK, ACTION_FILLING, -1
6001 Xsand_stonein_2, FALSE, TRUE,
6002 EL_ROCK, ACTION_FILLING, -1
6005 Xsand_stonein_3, FALSE, TRUE,
6006 EL_ROCK, ACTION_FILLING, -1
6009 Xsand_stonein_4, FALSE, TRUE,
6010 EL_ROCK, ACTION_FILLING, -1
6013 Xsand_stonesand_1, FALSE, FALSE,
6014 EL_QUICKSAND_EMPTYING, -1, -1
6017 Xsand_stonesand_2, FALSE, FALSE,
6018 EL_QUICKSAND_EMPTYING, -1, -1
6021 Xsand_stonesand_3, FALSE, FALSE,
6022 EL_QUICKSAND_EMPTYING, -1, -1
6025 Xsand_stonesand_4, FALSE, FALSE,
6026 EL_QUICKSAND_EMPTYING, -1, -1
6029 Xsand_stonesand_quickout_1, FALSE, FALSE,
6030 EL_QUICKSAND_EMPTYING, -1, -1
6033 Xsand_stonesand_quickout_2, FALSE, FALSE,
6034 EL_QUICKSAND_EMPTYING, -1, -1
6037 Xsand_stoneout_1, FALSE, FALSE,
6038 EL_ROCK, ACTION_EMPTYING, -1
6041 Xsand_stoneout_2, FALSE, FALSE,
6042 EL_ROCK, ACTION_EMPTYING, -1
6045 Xsand_sandstone_1, FALSE, FALSE,
6046 EL_QUICKSAND_FILLING, -1, -1
6049 Xsand_sandstone_2, FALSE, FALSE,
6050 EL_QUICKSAND_FILLING, -1, -1
6053 Xsand_sandstone_3, FALSE, FALSE,
6054 EL_QUICKSAND_FILLING, -1, -1
6057 Xsand_sandstone_4, FALSE, FALSE,
6058 EL_QUICKSAND_FILLING, -1, -1
6061 Xplant, TRUE, FALSE,
6062 EL_EMC_PLANT, -1, -1
6065 Yplant, FALSE, FALSE,
6066 EL_EMC_PLANT, -1, -1
6069 Xlenses, TRUE, FALSE,
6070 EL_EMC_LENSES, -1, -1
6073 Xmagnify, TRUE, FALSE,
6074 EL_EMC_MAGNIFIER, -1, -1
6077 Xdripper, TRUE, FALSE,
6078 EL_EMC_DRIPPER, -1, -1
6081 XdripperB, FALSE, FALSE,
6082 EL_EMC_DRIPPER, ACTION_ACTIVE, -1
6085 Xfake_blank, TRUE, FALSE,
6086 EL_INVISIBLE_WALL, -1, -1
6089 Xfake_blankB, FALSE, FALSE,
6090 EL_INVISIBLE_WALL, ACTION_ACTIVE, -1
6093 Xfake_grass, TRUE, FALSE,
6094 EL_EMC_FAKE_GRASS, -1, -1
6097 Xfake_grassB, FALSE, FALSE,
6098 EL_EMC_FAKE_GRASS, ACTION_ACTIVE, -1
6101 Xfake_door_1, TRUE, FALSE,
6102 EL_EM_GATE_1_GRAY, -1, -1
6105 Xfake_door_2, TRUE, FALSE,
6106 EL_EM_GATE_2_GRAY, -1, -1
6109 Xfake_door_3, TRUE, FALSE,
6110 EL_EM_GATE_3_GRAY, -1, -1
6113 Xfake_door_4, TRUE, FALSE,
6114 EL_EM_GATE_4_GRAY, -1, -1
6117 Xfake_door_5, TRUE, FALSE,
6118 EL_EMC_GATE_5_GRAY, -1, -1
6121 Xfake_door_6, TRUE, FALSE,
6122 EL_EMC_GATE_6_GRAY, -1, -1
6125 Xfake_door_7, TRUE, FALSE,
6126 EL_EMC_GATE_7_GRAY, -1, -1
6129 Xfake_door_8, TRUE, FALSE,
6130 EL_EMC_GATE_8_GRAY, -1, -1
6133 Xfake_acid_1, TRUE, FALSE,
6134 EL_EMC_FAKE_ACID, -1, -1
6137 Xfake_acid_2, FALSE, FALSE,
6138 EL_EMC_FAKE_ACID, -1, -1
6141 Xfake_acid_3, FALSE, FALSE,
6142 EL_EMC_FAKE_ACID, -1, -1
6145 Xfake_acid_4, FALSE, FALSE,
6146 EL_EMC_FAKE_ACID, -1, -1
6149 Xfake_acid_5, FALSE, FALSE,
6150 EL_EMC_FAKE_ACID, -1, -1
6153 Xfake_acid_6, FALSE, FALSE,
6154 EL_EMC_FAKE_ACID, -1, -1
6157 Xfake_acid_7, FALSE, FALSE,
6158 EL_EMC_FAKE_ACID, -1, -1
6161 Xfake_acid_8, FALSE, FALSE,
6162 EL_EMC_FAKE_ACID, -1, -1
6165 Xsteel_1, TRUE, FALSE,
6166 EL_STEELWALL, -1, -1
6169 Xsteel_2, TRUE, FALSE,
6170 EL_EMC_STEELWALL_2, -1, -1
6173 Xsteel_3, TRUE, FALSE,
6174 EL_EMC_STEELWALL_3, -1, -1
6177 Xsteel_4, TRUE, FALSE,
6178 EL_EMC_STEELWALL_4, -1, -1
6181 Xwall_1, TRUE, FALSE,
6185 Xwall_2, TRUE, FALSE,
6186 EL_EMC_WALL_14, -1, -1
6189 Xwall_3, TRUE, FALSE,
6190 EL_EMC_WALL_15, -1, -1
6193 Xwall_4, TRUE, FALSE,
6194 EL_EMC_WALL_16, -1, -1
6197 Xround_wall_1, TRUE, FALSE,
6198 EL_WALL_SLIPPERY, -1, -1
6201 Xround_wall_2, TRUE, FALSE,
6202 EL_EMC_WALL_SLIPPERY_2, -1, -1
6205 Xround_wall_3, TRUE, FALSE,
6206 EL_EMC_WALL_SLIPPERY_3, -1, -1
6209 Xround_wall_4, TRUE, FALSE,
6210 EL_EMC_WALL_SLIPPERY_4, -1, -1
6213 Xdecor_1, TRUE, FALSE,
6214 EL_EMC_WALL_8, -1, -1
6217 Xdecor_2, TRUE, FALSE,
6218 EL_EMC_WALL_6, -1, -1
6221 Xdecor_3, TRUE, FALSE,
6222 EL_EMC_WALL_4, -1, -1
6225 Xdecor_4, TRUE, FALSE,
6226 EL_EMC_WALL_7, -1, -1
6229 Xdecor_5, TRUE, FALSE,
6230 EL_EMC_WALL_5, -1, -1
6233 Xdecor_6, TRUE, FALSE,
6234 EL_EMC_WALL_9, -1, -1
6237 Xdecor_7, TRUE, FALSE,
6238 EL_EMC_WALL_10, -1, -1
6241 Xdecor_8, TRUE, FALSE,
6242 EL_EMC_WALL_1, -1, -1
6245 Xdecor_9, TRUE, FALSE,
6246 EL_EMC_WALL_2, -1, -1
6249 Xdecor_10, TRUE, FALSE,
6250 EL_EMC_WALL_3, -1, -1
6253 Xdecor_11, TRUE, FALSE,
6254 EL_EMC_WALL_11, -1, -1
6257 Xdecor_12, TRUE, FALSE,
6258 EL_EMC_WALL_12, -1, -1
6261 Xalpha_0, TRUE, FALSE,
6262 EL_CHAR('0'), -1, -1
6265 Xalpha_1, TRUE, FALSE,
6266 EL_CHAR('1'), -1, -1
6269 Xalpha_2, TRUE, FALSE,
6270 EL_CHAR('2'), -1, -1
6273 Xalpha_3, TRUE, FALSE,
6274 EL_CHAR('3'), -1, -1
6277 Xalpha_4, TRUE, FALSE,
6278 EL_CHAR('4'), -1, -1
6281 Xalpha_5, TRUE, FALSE,
6282 EL_CHAR('5'), -1, -1
6285 Xalpha_6, TRUE, FALSE,
6286 EL_CHAR('6'), -1, -1
6289 Xalpha_7, TRUE, FALSE,
6290 EL_CHAR('7'), -1, -1
6293 Xalpha_8, TRUE, FALSE,
6294 EL_CHAR('8'), -1, -1
6297 Xalpha_9, TRUE, FALSE,
6298 EL_CHAR('9'), -1, -1
6301 Xalpha_excla, TRUE, FALSE,
6302 EL_CHAR('!'), -1, -1
6305 Xalpha_quote, TRUE, FALSE,
6306 EL_CHAR('"'), -1, -1
6309 Xalpha_comma, TRUE, FALSE,
6310 EL_CHAR(','), -1, -1
6313 Xalpha_minus, TRUE, FALSE,
6314 EL_CHAR('-'), -1, -1
6317 Xalpha_perio, TRUE, FALSE,
6318 EL_CHAR('.'), -1, -1
6321 Xalpha_colon, TRUE, FALSE,
6322 EL_CHAR(':'), -1, -1
6325 Xalpha_quest, TRUE, FALSE,
6326 EL_CHAR('?'), -1, -1
6329 Xalpha_a, TRUE, FALSE,
6330 EL_CHAR('A'), -1, -1
6333 Xalpha_b, TRUE, FALSE,
6334 EL_CHAR('B'), -1, -1
6337 Xalpha_c, TRUE, FALSE,
6338 EL_CHAR('C'), -1, -1
6341 Xalpha_d, TRUE, FALSE,
6342 EL_CHAR('D'), -1, -1
6345 Xalpha_e, TRUE, FALSE,
6346 EL_CHAR('E'), -1, -1
6349 Xalpha_f, TRUE, FALSE,
6350 EL_CHAR('F'), -1, -1
6353 Xalpha_g, TRUE, FALSE,
6354 EL_CHAR('G'), -1, -1
6357 Xalpha_h, TRUE, FALSE,
6358 EL_CHAR('H'), -1, -1
6361 Xalpha_i, TRUE, FALSE,
6362 EL_CHAR('I'), -1, -1
6365 Xalpha_j, TRUE, FALSE,
6366 EL_CHAR('J'), -1, -1
6369 Xalpha_k, TRUE, FALSE,
6370 EL_CHAR('K'), -1, -1
6373 Xalpha_l, TRUE, FALSE,
6374 EL_CHAR('L'), -1, -1
6377 Xalpha_m, TRUE, FALSE,
6378 EL_CHAR('M'), -1, -1
6381 Xalpha_n, TRUE, FALSE,
6382 EL_CHAR('N'), -1, -1
6385 Xalpha_o, TRUE, FALSE,
6386 EL_CHAR('O'), -1, -1
6389 Xalpha_p, TRUE, FALSE,
6390 EL_CHAR('P'), -1, -1
6393 Xalpha_q, TRUE, FALSE,
6394 EL_CHAR('Q'), -1, -1
6397 Xalpha_r, TRUE, FALSE,
6398 EL_CHAR('R'), -1, -1
6401 Xalpha_s, TRUE, FALSE,
6402 EL_CHAR('S'), -1, -1
6405 Xalpha_t, TRUE, FALSE,
6406 EL_CHAR('T'), -1, -1
6409 Xalpha_u, TRUE, FALSE,
6410 EL_CHAR('U'), -1, -1
6413 Xalpha_v, TRUE, FALSE,
6414 EL_CHAR('V'), -1, -1
6417 Xalpha_w, TRUE, FALSE,
6418 EL_CHAR('W'), -1, -1
6421 Xalpha_x, TRUE, FALSE,
6422 EL_CHAR('X'), -1, -1
6425 Xalpha_y, TRUE, FALSE,
6426 EL_CHAR('Y'), -1, -1
6429 Xalpha_z, TRUE, FALSE,
6430 EL_CHAR('Z'), -1, -1
6433 Xalpha_arrow_e, TRUE, FALSE,
6434 EL_CHAR('>'), -1, -1
6437 Xalpha_arrow_w, TRUE, FALSE,
6438 EL_CHAR('<'), -1, -1
6441 Xalpha_copyr, TRUE, FALSE,
6442 EL_CHAR(CHAR_BYTE_COPYRIGHT), -1, -1
6446 Xboom_bug, FALSE, FALSE,
6447 EL_BUG, ACTION_EXPLODING, -1
6450 Xboom_bomb, FALSE, FALSE,
6451 EL_BOMB, ACTION_EXPLODING, -1
6454 Xboom_android, FALSE, FALSE,
6455 EL_EMC_ANDROID, ACTION_OTHER, -1
6458 Xboom_1, FALSE, FALSE,
6459 EL_DEFAULT, ACTION_EXPLODING, -1
6462 Xboom_2, FALSE, FALSE,
6463 EL_DEFAULT, ACTION_EXPLODING, -1
6466 Znormal, FALSE, FALSE,
6470 Zdynamite, FALSE, FALSE,
6474 Zplayer, FALSE, FALSE,
6478 ZBORDER, FALSE, FALSE,
6488 static struct Mapping_EM_to_RND_player
6497 em_player_mapping_list[] =
6501 EL_PLAYER_1, ACTION_MOVING, MV_BIT_UP,
6505 EL_PLAYER_1, ACTION_MOVING, MV_BIT_RIGHT,
6509 EL_PLAYER_1, ACTION_MOVING, MV_BIT_DOWN,
6513 EL_PLAYER_1, ACTION_MOVING, MV_BIT_LEFT,
6517 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_UP,
6521 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_RIGHT,
6525 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_DOWN,
6529 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_LEFT,
6533 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_UP,
6537 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_RIGHT,
6541 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_DOWN,
6545 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_LEFT,
6549 EL_PLAYER_2, ACTION_MOVING, MV_BIT_UP,
6553 EL_PLAYER_2, ACTION_MOVING, MV_BIT_RIGHT,
6557 EL_PLAYER_2, ACTION_MOVING, MV_BIT_DOWN,
6561 EL_PLAYER_2, ACTION_MOVING, MV_BIT_LEFT,
6565 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_UP,
6569 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_RIGHT,
6573 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_DOWN,
6577 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_LEFT,
6581 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_UP,
6585 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_RIGHT,
6589 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_DOWN,
6593 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_LEFT,
6597 EL_PLAYER_1, ACTION_DEFAULT, -1,
6601 EL_PLAYER_2, ACTION_DEFAULT, -1,
6605 EL_PLAYER_3, ACTION_MOVING, MV_BIT_UP,
6609 EL_PLAYER_3, ACTION_MOVING, MV_BIT_RIGHT,
6613 EL_PLAYER_3, ACTION_MOVING, MV_BIT_DOWN,
6617 EL_PLAYER_3, ACTION_MOVING, MV_BIT_LEFT,
6621 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_UP,
6625 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_RIGHT,
6629 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_DOWN,
6633 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_LEFT,
6637 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_UP,
6641 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_RIGHT,
6645 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_DOWN,
6649 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_LEFT,
6653 EL_PLAYER_4, ACTION_MOVING, MV_BIT_UP,
6657 EL_PLAYER_4, ACTION_MOVING, MV_BIT_RIGHT,
6661 EL_PLAYER_4, ACTION_MOVING, MV_BIT_DOWN,
6665 EL_PLAYER_4, ACTION_MOVING, MV_BIT_LEFT,
6669 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_UP,
6673 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_RIGHT,
6677 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_DOWN,
6681 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_LEFT,
6685 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_UP,
6689 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_RIGHT,
6693 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_DOWN,
6697 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_LEFT,
6701 EL_PLAYER_3, ACTION_DEFAULT, -1,
6705 EL_PLAYER_4, ACTION_DEFAULT, -1,
6714 int map_element_RND_to_EM(int element_rnd)
6716 static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
6717 static boolean mapping_initialized = FALSE;
6719 if (!mapping_initialized)
6723 /* return "Xalpha_quest" for all undefined elements in mapping array */
6724 for (i = 0; i < NUM_FILE_ELEMENTS; i++)
6725 mapping_RND_to_EM[i] = Xalpha_quest;
6727 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
6728 if (em_object_mapping_list[i].is_rnd_to_em_mapping)
6729 mapping_RND_to_EM[em_object_mapping_list[i].element_rnd] =
6730 em_object_mapping_list[i].element_em;
6732 mapping_initialized = TRUE;
6735 if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
6736 return mapping_RND_to_EM[element_rnd];
6738 Error(ERR_WARN, "invalid RND level element %d", element_rnd);
6743 int map_element_EM_to_RND(int element_em)
6745 static unsigned short mapping_EM_to_RND[TILE_MAX];
6746 static boolean mapping_initialized = FALSE;
6748 if (!mapping_initialized)
6752 /* return "EL_UNKNOWN" for all undefined elements in mapping array */
6753 for (i = 0; i < TILE_MAX; i++)
6754 mapping_EM_to_RND[i] = EL_UNKNOWN;
6756 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
6757 mapping_EM_to_RND[em_object_mapping_list[i].element_em] =
6758 em_object_mapping_list[i].element_rnd;
6760 mapping_initialized = TRUE;
6763 if (element_em >= 0 && element_em < TILE_MAX)
6764 return mapping_EM_to_RND[element_em];
6766 Error(ERR_WARN, "invalid EM level element %d", element_em);
6771 void map_android_clone_elements_RND_to_EM(struct LevelInfo *level)
6773 struct LevelInfo_EM *level_em = level->native_em_level;
6774 struct LEVEL *lev = level_em->lev;
6777 for (i = 0; i < TILE_MAX; i++)
6778 lev->android_array[i] = Xblank;
6780 for (i = 0; i < level->num_android_clone_elements; i++)
6782 int element_rnd = level->android_clone_element[i];
6783 int element_em = map_element_RND_to_EM(element_rnd);
6785 for (j = 0; em_object_mapping_list[j].element_em != -1; j++)
6786 if (em_object_mapping_list[j].element_rnd == element_rnd)
6787 lev->android_array[em_object_mapping_list[j].element_em] = element_em;
6791 void map_android_clone_elements_EM_to_RND(struct LevelInfo *level)
6793 struct LevelInfo_EM *level_em = level->native_em_level;
6794 struct LEVEL *lev = level_em->lev;
6797 level->num_android_clone_elements = 0;
6799 for (i = 0; i < TILE_MAX; i++)
6801 int element_em = lev->android_array[i];
6803 boolean element_found = FALSE;
6805 if (element_em == Xblank)
6808 element_rnd = map_element_EM_to_RND(element_em);
6810 for (j = 0; j < level->num_android_clone_elements; j++)
6811 if (level->android_clone_element[j] == element_rnd)
6812 element_found = TRUE;
6816 level->android_clone_element[level->num_android_clone_elements++] =
6819 if (level->num_android_clone_elements == MAX_ANDROID_ELEMENTS)
6824 if (level->num_android_clone_elements == 0)
6826 level->num_android_clone_elements = 1;
6827 level->android_clone_element[0] = EL_EMPTY;
6831 int map_direction_RND_to_EM(int direction)
6833 return (direction == MV_UP ? 0 :
6834 direction == MV_RIGHT ? 1 :
6835 direction == MV_DOWN ? 2 :
6836 direction == MV_LEFT ? 3 :
6840 int map_direction_EM_to_RND(int direction)
6842 return (direction == 0 ? MV_UP :
6843 direction == 1 ? MV_RIGHT :
6844 direction == 2 ? MV_DOWN :
6845 direction == 3 ? MV_LEFT :
6849 int map_element_RND_to_SP(int element_rnd)
6851 int element_sp = 0x20; /* map unknown elements to yellow "hardware" */
6853 if (element_rnd >= EL_SP_START &&
6854 element_rnd <= EL_SP_END)
6855 element_sp = element_rnd - EL_SP_START;
6856 else if (element_rnd == EL_EMPTY_SPACE)
6858 else if (element_rnd == EL_INVISIBLE_WALL)
6864 int map_element_SP_to_RND(int element_sp)
6866 int element_rnd = EL_UNKNOWN;
6868 if (element_sp >= 0x00 &&
6870 element_rnd = EL_SP_START + element_sp;
6871 else if (element_sp == 0x28)
6872 element_rnd = EL_INVISIBLE_WALL;
6877 int map_action_SP_to_RND(int action_sp)
6881 case actActive: return ACTION_ACTIVE;
6882 case actImpact: return ACTION_IMPACT;
6883 case actExploding: return ACTION_EXPLODING;
6884 case actDigging: return ACTION_DIGGING;
6885 case actSnapping: return ACTION_SNAPPING;
6886 case actCollecting: return ACTION_COLLECTING;
6887 case actPassing: return ACTION_PASSING;
6888 case actPushing: return ACTION_PUSHING;
6889 case actDropping: return ACTION_DROPPING;
6891 default: return ACTION_DEFAULT;
6895 int get_next_element(int element)
6899 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
6900 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
6901 case EL_QUICKSAND_FAST_FILLING: return EL_QUICKSAND_FAST_FULL;
6902 case EL_QUICKSAND_FAST_EMPTYING: return EL_QUICKSAND_FAST_EMPTY;
6903 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
6904 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
6905 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
6906 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
6907 case EL_DC_MAGIC_WALL_FILLING: return EL_DC_MAGIC_WALL_FULL;
6908 case EL_DC_MAGIC_WALL_EMPTYING: return EL_DC_MAGIC_WALL_ACTIVE;
6909 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
6911 default: return element;
6915 int el_act_dir2img(int element, int action, int direction)
6917 element = GFX_ELEMENT(element);
6918 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
6920 /* direction_graphic[][] == graphic[] for undefined direction graphics */
6921 return element_info[element].direction_graphic[action][direction];
6924 static int el_act_dir2crm(int element, int action, int direction)
6926 element = GFX_ELEMENT(element);
6927 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
6929 /* direction_graphic[][] == graphic[] for undefined direction graphics */
6930 return element_info[element].direction_crumbled[action][direction];
6933 int el_act2img(int element, int action)
6935 element = GFX_ELEMENT(element);
6937 return element_info[element].graphic[action];
6940 int el_act2crm(int element, int action)
6942 element = GFX_ELEMENT(element);
6944 return element_info[element].crumbled[action];
6947 int el_dir2img(int element, int direction)
6949 element = GFX_ELEMENT(element);
6951 return el_act_dir2img(element, ACTION_DEFAULT, direction);
6954 int el2baseimg(int element)
6956 return element_info[element].graphic[ACTION_DEFAULT];
6959 int el2img(int element)
6961 element = GFX_ELEMENT(element);
6963 return element_info[element].graphic[ACTION_DEFAULT];
6966 int el2edimg(int element)
6968 element = GFX_ELEMENT(element);
6970 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
6973 int el2preimg(int element)
6975 element = GFX_ELEMENT(element);
6977 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
6980 int el2panelimg(int element)
6982 element = GFX_ELEMENT(element);
6984 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PANEL];
6987 int font2baseimg(int font_nr)
6989 return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
6992 int getBeltNrFromBeltElement(int element)
6994 return (element < EL_CONVEYOR_BELT_2_LEFT ? 0 :
6995 element < EL_CONVEYOR_BELT_3_LEFT ? 1 :
6996 element < EL_CONVEYOR_BELT_4_LEFT ? 2 : 3);
6999 int getBeltNrFromBeltActiveElement(int element)
7001 return (element < EL_CONVEYOR_BELT_2_LEFT_ACTIVE ? 0 :
7002 element < EL_CONVEYOR_BELT_3_LEFT_ACTIVE ? 1 :
7003 element < EL_CONVEYOR_BELT_4_LEFT_ACTIVE ? 2 : 3);
7006 int getBeltNrFromBeltSwitchElement(int element)
7008 return (element < EL_CONVEYOR_BELT_2_SWITCH_LEFT ? 0 :
7009 element < EL_CONVEYOR_BELT_3_SWITCH_LEFT ? 1 :
7010 element < EL_CONVEYOR_BELT_4_SWITCH_LEFT ? 2 : 3);
7013 int getBeltDirNrFromBeltElement(int element)
7015 static int belt_base_element[4] =
7017 EL_CONVEYOR_BELT_1_LEFT,
7018 EL_CONVEYOR_BELT_2_LEFT,
7019 EL_CONVEYOR_BELT_3_LEFT,
7020 EL_CONVEYOR_BELT_4_LEFT
7023 int belt_nr = getBeltNrFromBeltElement(element);
7024 int belt_dir_nr = element - belt_base_element[belt_nr];
7026 return (belt_dir_nr % 3);
7029 int getBeltDirNrFromBeltSwitchElement(int element)
7031 static int belt_base_element[4] =
7033 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
7034 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
7035 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
7036 EL_CONVEYOR_BELT_4_SWITCH_LEFT
7039 int belt_nr = getBeltNrFromBeltSwitchElement(element);
7040 int belt_dir_nr = element - belt_base_element[belt_nr];
7042 return (belt_dir_nr % 3);
7045 int getBeltDirFromBeltElement(int element)
7047 static int belt_move_dir[3] =
7054 int belt_dir_nr = getBeltDirNrFromBeltElement(element);
7056 return belt_move_dir[belt_dir_nr];
7059 int getBeltDirFromBeltSwitchElement(int element)
7061 static int belt_move_dir[3] =
7068 int belt_dir_nr = getBeltDirNrFromBeltSwitchElement(element);
7070 return belt_move_dir[belt_dir_nr];
7073 int getBeltElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
7075 static int belt_base_element[4] =
7077 EL_CONVEYOR_BELT_1_LEFT,
7078 EL_CONVEYOR_BELT_2_LEFT,
7079 EL_CONVEYOR_BELT_3_LEFT,
7080 EL_CONVEYOR_BELT_4_LEFT
7083 return belt_base_element[belt_nr] + belt_dir_nr;
7086 int getBeltElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
7088 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
7090 return getBeltElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
7093 int getBeltSwitchElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
7095 static int belt_base_element[4] =
7097 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
7098 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
7099 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
7100 EL_CONVEYOR_BELT_4_SWITCH_LEFT
7103 return belt_base_element[belt_nr] + belt_dir_nr;
7106 int getBeltSwitchElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
7108 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
7110 return getBeltSwitchElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
7113 boolean getTeamMode_EM()
7115 return game.team_mode;
7118 int getGameFrameDelay_EM(int native_em_game_frame_delay)
7120 int game_frame_delay_value;
7122 game_frame_delay_value =
7123 (tape.playing && tape.fast_forward ? FfwdFrameDelay :
7124 GameFrameDelay == GAME_FRAME_DELAY ? native_em_game_frame_delay :
7127 if (tape.playing && tape.warp_forward && !tape.pausing)
7128 game_frame_delay_value = 0;
7130 return game_frame_delay_value;
7133 unsigned int InitRND(int seed)
7135 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
7136 return InitEngineRandom_EM(seed);
7137 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
7138 return InitEngineRandom_SP(seed);
7140 return InitEngineRandom_RND(seed);
7143 static struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
7144 static struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
7146 inline static int get_effective_element_EM(int tile, int frame_em)
7148 int element = object_mapping[tile].element_rnd;
7149 int action = object_mapping[tile].action;
7150 boolean is_backside = object_mapping[tile].is_backside;
7151 boolean action_removing = (action == ACTION_DIGGING ||
7152 action == ACTION_SNAPPING ||
7153 action == ACTION_COLLECTING);
7159 case Yacid_splash_eB:
7160 case Yacid_splash_wB:
7161 return (frame_em > 5 ? EL_EMPTY : element);
7167 else /* frame_em == 7 */
7171 case Yacid_splash_eB:
7172 case Yacid_splash_wB:
7175 case Yemerald_stone:
7178 case Ydiamond_stone:
7182 case Xdrip_stretchB:
7201 case Xsand_stonein_1:
7202 case Xsand_stonein_2:
7203 case Xsand_stonein_3:
7204 case Xsand_stonein_4:
7208 return (is_backside || action_removing ? EL_EMPTY : element);
7213 inline static boolean check_linear_animation_EM(int tile)
7217 case Xsand_stonesand_1:
7218 case Xsand_stonesand_quickout_1:
7219 case Xsand_sandstone_1:
7220 case Xsand_stonein_1:
7221 case Xsand_stoneout_1:
7240 case Yacid_splash_eB:
7241 case Yacid_splash_wB:
7242 case Yemerald_stone:
7249 inline static void set_crumbled_graphics_EM(struct GraphicInfo_EM *g_em,
7250 boolean has_crumbled_graphics,
7251 int crumbled, int sync_frame)
7253 /* if element can be crumbled, but certain action graphics are just empty
7254 space (like instantly snapping sand to empty space in 1 frame), do not
7255 treat these empty space graphics as crumbled graphics in EMC engine */
7256 if (crumbled == IMG_EMPTY_SPACE)
7257 has_crumbled_graphics = FALSE;
7259 if (has_crumbled_graphics)
7261 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
7262 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
7263 g_crumbled->anim_delay,
7264 g_crumbled->anim_mode,
7265 g_crumbled->anim_start_frame,
7268 getGraphicSource(crumbled, frame_crumbled, &g_em->crumbled_bitmap,
7269 &g_em->crumbled_src_x, &g_em->crumbled_src_y);
7271 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
7273 g_em->has_crumbled_graphics = TRUE;
7277 g_em->crumbled_bitmap = NULL;
7278 g_em->crumbled_src_x = 0;
7279 g_em->crumbled_src_y = 0;
7280 g_em->crumbled_border_size = 0;
7282 g_em->has_crumbled_graphics = FALSE;
7286 void ResetGfxAnimation_EM(int x, int y, int tile)
7291 void SetGfxAnimation_EM(struct GraphicInfo_EM *g_em,
7292 int tile, int frame_em, int x, int y)
7294 int action = object_mapping[tile].action;
7295 int direction = object_mapping[tile].direction;
7296 int effective_element = get_effective_element_EM(tile, frame_em);
7297 int graphic = (direction == MV_NONE ?
7298 el_act2img(effective_element, action) :
7299 el_act_dir2img(effective_element, action, direction));
7300 struct GraphicInfo *g = &graphic_info[graphic];
7302 boolean action_removing = (action == ACTION_DIGGING ||
7303 action == ACTION_SNAPPING ||
7304 action == ACTION_COLLECTING);
7305 boolean action_moving = (action == ACTION_FALLING ||
7306 action == ACTION_MOVING ||
7307 action == ACTION_PUSHING ||
7308 action == ACTION_EATING ||
7309 action == ACTION_FILLING ||
7310 action == ACTION_EMPTYING);
7311 boolean action_falling = (action == ACTION_FALLING ||
7312 action == ACTION_FILLING ||
7313 action == ACTION_EMPTYING);
7315 /* special case: graphic uses "2nd movement tile" and has defined
7316 7 frames for movement animation (or less) => use default graphic
7317 for last (8th) frame which ends the movement animation */
7318 if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
7320 action = ACTION_DEFAULT; /* (keep action_* unchanged for now) */
7321 graphic = (direction == MV_NONE ?
7322 el_act2img(effective_element, action) :
7323 el_act_dir2img(effective_element, action, direction));
7325 g = &graphic_info[graphic];
7328 if ((action_removing || check_linear_animation_EM(tile)) && frame_em == 0)
7332 else if (action_moving)
7334 boolean is_backside = object_mapping[tile].is_backside;
7338 int direction = object_mapping[tile].direction;
7339 int move_dir = (action_falling ? MV_DOWN : direction);
7344 /* !!! TEST !!! NEW !!! DOES NOT WORK RIGHT YET !!! */
7345 if (g->double_movement && frame_em == 0)
7349 if (move_dir == MV_LEFT)
7350 GfxFrame[x - 1][y] = GfxFrame[x][y];
7351 else if (move_dir == MV_RIGHT)
7352 GfxFrame[x + 1][y] = GfxFrame[x][y];
7353 else if (move_dir == MV_UP)
7354 GfxFrame[x][y - 1] = GfxFrame[x][y];
7355 else if (move_dir == MV_DOWN)
7356 GfxFrame[x][y + 1] = GfxFrame[x][y];
7363 /* special case: animation for Xsand_stonesand_quickout_1/2 twice as fast */
7364 if (tile == Xsand_stonesand_quickout_1 ||
7365 tile == Xsand_stonesand_quickout_2)
7369 if (graphic_info[graphic].anim_global_sync)
7370 sync_frame = FrameCounter;
7371 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
7372 sync_frame = GfxFrame[x][y];
7374 sync_frame = 0; /* playfield border (pseudo steel) */
7376 SetRandomAnimationValue(x, y);
7378 int frame = getAnimationFrame(g->anim_frames,
7381 g->anim_start_frame,
7384 g_em->unique_identifier =
7385 (graphic << 16) | ((frame % 8) << 12) | (g_em->width << 6) | g_em->height;
7388 void getGraphicSourceObjectExt_EM(struct GraphicInfo_EM *g_em,
7389 int tile, int frame_em, int x, int y)
7391 int action = object_mapping[tile].action;
7392 int direction = object_mapping[tile].direction;
7393 boolean is_backside = object_mapping[tile].is_backside;
7394 int effective_element = get_effective_element_EM(tile, frame_em);
7395 int effective_action = action;
7396 int graphic = (direction == MV_NONE ?
7397 el_act2img(effective_element, effective_action) :
7398 el_act_dir2img(effective_element, effective_action,
7400 int crumbled = (direction == MV_NONE ?
7401 el_act2crm(effective_element, effective_action) :
7402 el_act_dir2crm(effective_element, effective_action,
7404 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
7405 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
7406 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
7407 struct GraphicInfo *g = &graphic_info[graphic];
7410 /* special case: graphic uses "2nd movement tile" and has defined
7411 7 frames for movement animation (or less) => use default graphic
7412 for last (8th) frame which ends the movement animation */
7413 if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
7415 effective_action = ACTION_DEFAULT;
7416 graphic = (direction == MV_NONE ?
7417 el_act2img(effective_element, effective_action) :
7418 el_act_dir2img(effective_element, effective_action,
7420 crumbled = (direction == MV_NONE ?
7421 el_act2crm(effective_element, effective_action) :
7422 el_act_dir2crm(effective_element, effective_action,
7425 g = &graphic_info[graphic];
7428 if (graphic_info[graphic].anim_global_sync)
7429 sync_frame = FrameCounter;
7430 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
7431 sync_frame = GfxFrame[x][y];
7433 sync_frame = 0; /* playfield border (pseudo steel) */
7435 SetRandomAnimationValue(x, y);
7437 int frame = getAnimationFrame(g->anim_frames,
7440 g->anim_start_frame,
7443 getGraphicSourceExt(graphic, frame, &g_em->bitmap, &g_em->src_x, &g_em->src_y,
7444 g->double_movement && is_backside);
7446 /* (updating the "crumbled" graphic definitions is probably not really needed,
7447 as animations for crumbled graphics can't be longer than one EMC cycle) */
7448 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
7452 void getGraphicSourcePlayerExt_EM(struct GraphicInfo_EM *g_em,
7453 int player_nr, int anim, int frame_em)
7455 int element = player_mapping[player_nr][anim].element_rnd;
7456 int action = player_mapping[player_nr][anim].action;
7457 int direction = player_mapping[player_nr][anim].direction;
7458 int graphic = (direction == MV_NONE ?
7459 el_act2img(element, action) :
7460 el_act_dir2img(element, action, direction));
7461 struct GraphicInfo *g = &graphic_info[graphic];
7464 InitPlayerGfxAnimation(&stored_player[player_nr], action, direction);
7466 stored_player[player_nr].StepFrame = frame_em;
7468 sync_frame = stored_player[player_nr].Frame;
7470 int frame = getAnimationFrame(g->anim_frames,
7473 g->anim_start_frame,
7476 getGraphicSourceExt(graphic, frame, &g_em->bitmap,
7477 &g_em->src_x, &g_em->src_y, FALSE);
7480 void InitGraphicInfo_EM(void)
7485 int num_em_gfx_errors = 0;
7487 if (graphic_info_em_object[0][0].bitmap == NULL)
7489 /* EM graphics not yet initialized in em_open_all() */
7494 printf("::: [4 errors can be ignored (1 x 'bomb', 3 x 'em_dynamite']\n");
7497 /* always start with reliable default values */
7498 for (i = 0; i < TILE_MAX; i++)
7500 object_mapping[i].element_rnd = EL_UNKNOWN;
7501 object_mapping[i].is_backside = FALSE;
7502 object_mapping[i].action = ACTION_DEFAULT;
7503 object_mapping[i].direction = MV_NONE;
7506 /* always start with reliable default values */
7507 for (p = 0; p < MAX_PLAYERS; p++)
7509 for (i = 0; i < SPR_MAX; i++)
7511 player_mapping[p][i].element_rnd = EL_UNKNOWN;
7512 player_mapping[p][i].action = ACTION_DEFAULT;
7513 player_mapping[p][i].direction = MV_NONE;
7517 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
7519 int e = em_object_mapping_list[i].element_em;
7521 object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd;
7522 object_mapping[e].is_backside = em_object_mapping_list[i].is_backside;
7524 if (em_object_mapping_list[i].action != -1)
7525 object_mapping[e].action = em_object_mapping_list[i].action;
7527 if (em_object_mapping_list[i].direction != -1)
7528 object_mapping[e].direction =
7529 MV_DIR_FROM_BIT(em_object_mapping_list[i].direction);
7532 for (i = 0; em_player_mapping_list[i].action_em != -1; i++)
7534 int a = em_player_mapping_list[i].action_em;
7535 int p = em_player_mapping_list[i].player_nr;
7537 player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd;
7539 if (em_player_mapping_list[i].action != -1)
7540 player_mapping[p][a].action = em_player_mapping_list[i].action;
7542 if (em_player_mapping_list[i].direction != -1)
7543 player_mapping[p][a].direction =
7544 MV_DIR_FROM_BIT(em_player_mapping_list[i].direction);
7547 for (i = 0; i < TILE_MAX; i++)
7549 int element = object_mapping[i].element_rnd;
7550 int action = object_mapping[i].action;
7551 int direction = object_mapping[i].direction;
7552 boolean is_backside = object_mapping[i].is_backside;
7553 boolean action_exploding = ((action == ACTION_EXPLODING ||
7554 action == ACTION_SMASHED_BY_ROCK ||
7555 action == ACTION_SMASHED_BY_SPRING) &&
7556 element != EL_DIAMOND);
7557 boolean action_active = (action == ACTION_ACTIVE);
7558 boolean action_other = (action == ACTION_OTHER);
7560 for (j = 0; j < 8; j++)
7562 int effective_element = get_effective_element_EM(i, j);
7563 int effective_action = (j < 7 ? action :
7564 i == Xdrip_stretch ? action :
7565 i == Xdrip_stretchB ? action :
7566 i == Ydrip_s1 ? action :
7567 i == Ydrip_s1B ? action :
7568 i == Xball_1B ? action :
7569 i == Xball_2 ? action :
7570 i == Xball_2B ? action :
7571 i == Yball_eat ? action :
7572 i == Ykey_1_eat ? action :
7573 i == Ykey_2_eat ? action :
7574 i == Ykey_3_eat ? action :
7575 i == Ykey_4_eat ? action :
7576 i == Ykey_5_eat ? action :
7577 i == Ykey_6_eat ? action :
7578 i == Ykey_7_eat ? action :
7579 i == Ykey_8_eat ? action :
7580 i == Ylenses_eat ? action :
7581 i == Ymagnify_eat ? action :
7582 i == Ygrass_eat ? action :
7583 i == Ydirt_eat ? action :
7584 i == Xsand_stonein_1 ? action :
7585 i == Xsand_stonein_2 ? action :
7586 i == Xsand_stonein_3 ? action :
7587 i == Xsand_stonein_4 ? action :
7588 i == Xsand_stoneout_1 ? action :
7589 i == Xsand_stoneout_2 ? action :
7590 i == Xboom_android ? ACTION_EXPLODING :
7591 action_exploding ? ACTION_EXPLODING :
7592 action_active ? action :
7593 action_other ? action :
7595 int graphic = (el_act_dir2img(effective_element, effective_action,
7597 int crumbled = (el_act_dir2crm(effective_element, effective_action,
7599 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
7600 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
7601 boolean has_action_graphics = (graphic != base_graphic);
7602 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
7603 struct GraphicInfo *g = &graphic_info[graphic];
7604 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
7607 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
7608 boolean special_animation = (action != ACTION_DEFAULT &&
7609 g->anim_frames == 3 &&
7610 g->anim_delay == 2 &&
7611 g->anim_mode & ANIM_LINEAR);
7612 int sync_frame = (i == Xdrip_stretch ? 7 :
7613 i == Xdrip_stretchB ? 7 :
7614 i == Ydrip_s2 ? j + 8 :
7615 i == Ydrip_s2B ? j + 8 :
7624 i == Xfake_acid_1 ? 0 :
7625 i == Xfake_acid_2 ? 10 :
7626 i == Xfake_acid_3 ? 20 :
7627 i == Xfake_acid_4 ? 30 :
7628 i == Xfake_acid_5 ? 40 :
7629 i == Xfake_acid_6 ? 50 :
7630 i == Xfake_acid_7 ? 60 :
7631 i == Xfake_acid_8 ? 70 :
7633 i == Xball_2B ? j + 8 :
7634 i == Yball_eat ? j + 1 :
7635 i == Ykey_1_eat ? j + 1 :
7636 i == Ykey_2_eat ? j + 1 :
7637 i == Ykey_3_eat ? j + 1 :
7638 i == Ykey_4_eat ? j + 1 :
7639 i == Ykey_5_eat ? j + 1 :
7640 i == Ykey_6_eat ? j + 1 :
7641 i == Ykey_7_eat ? j + 1 :
7642 i == Ykey_8_eat ? j + 1 :
7643 i == Ylenses_eat ? j + 1 :
7644 i == Ymagnify_eat ? j + 1 :
7645 i == Ygrass_eat ? j + 1 :
7646 i == Ydirt_eat ? j + 1 :
7647 i == Xamoeba_1 ? 0 :
7648 i == Xamoeba_2 ? 1 :
7649 i == Xamoeba_3 ? 2 :
7650 i == Xamoeba_4 ? 3 :
7651 i == Xamoeba_5 ? 0 :
7652 i == Xamoeba_6 ? 1 :
7653 i == Xamoeba_7 ? 2 :
7654 i == Xamoeba_8 ? 3 :
7655 i == Xexit_2 ? j + 8 :
7656 i == Xexit_3 ? j + 16 :
7657 i == Xdynamite_1 ? 0 :
7658 i == Xdynamite_2 ? 8 :
7659 i == Xdynamite_3 ? 16 :
7660 i == Xdynamite_4 ? 24 :
7661 i == Xsand_stonein_1 ? j + 1 :
7662 i == Xsand_stonein_2 ? j + 9 :
7663 i == Xsand_stonein_3 ? j + 17 :
7664 i == Xsand_stonein_4 ? j + 25 :
7665 i == Xsand_stoneout_1 && j == 0 ? 0 :
7666 i == Xsand_stoneout_1 && j == 1 ? 0 :
7667 i == Xsand_stoneout_1 && j == 2 ? 1 :
7668 i == Xsand_stoneout_1 && j == 3 ? 2 :
7669 i == Xsand_stoneout_1 && j == 4 ? 2 :
7670 i == Xsand_stoneout_1 && j == 5 ? 3 :
7671 i == Xsand_stoneout_1 && j == 6 ? 4 :
7672 i == Xsand_stoneout_1 && j == 7 ? 4 :
7673 i == Xsand_stoneout_2 && j == 0 ? 5 :
7674 i == Xsand_stoneout_2 && j == 1 ? 6 :
7675 i == Xsand_stoneout_2 && j == 2 ? 7 :
7676 i == Xsand_stoneout_2 && j == 3 ? 8 :
7677 i == Xsand_stoneout_2 && j == 4 ? 9 :
7678 i == Xsand_stoneout_2 && j == 5 ? 11 :
7679 i == Xsand_stoneout_2 && j == 6 ? 13 :
7680 i == Xsand_stoneout_2 && j == 7 ? 15 :
7681 i == Xboom_bug && j == 1 ? 2 :
7682 i == Xboom_bug && j == 2 ? 2 :
7683 i == Xboom_bug && j == 3 ? 4 :
7684 i == Xboom_bug && j == 4 ? 4 :
7685 i == Xboom_bug && j == 5 ? 2 :
7686 i == Xboom_bug && j == 6 ? 2 :
7687 i == Xboom_bug && j == 7 ? 0 :
7688 i == Xboom_bomb && j == 1 ? 2 :
7689 i == Xboom_bomb && j == 2 ? 2 :
7690 i == Xboom_bomb && j == 3 ? 4 :
7691 i == Xboom_bomb && j == 4 ? 4 :
7692 i == Xboom_bomb && j == 5 ? 2 :
7693 i == Xboom_bomb && j == 6 ? 2 :
7694 i == Xboom_bomb && j == 7 ? 0 :
7695 i == Xboom_android && j == 7 ? 6 :
7696 i == Xboom_1 && j == 1 ? 2 :
7697 i == Xboom_1 && j == 2 ? 2 :
7698 i == Xboom_1 && j == 3 ? 4 :
7699 i == Xboom_1 && j == 4 ? 4 :
7700 i == Xboom_1 && j == 5 ? 6 :
7701 i == Xboom_1 && j == 6 ? 6 :
7702 i == Xboom_1 && j == 7 ? 8 :
7703 i == Xboom_2 && j == 0 ? 8 :
7704 i == Xboom_2 && j == 1 ? 8 :
7705 i == Xboom_2 && j == 2 ? 10 :
7706 i == Xboom_2 && j == 3 ? 10 :
7707 i == Xboom_2 && j == 4 ? 10 :
7708 i == Xboom_2 && j == 5 ? 12 :
7709 i == Xboom_2 && j == 6 ? 12 :
7710 i == Xboom_2 && j == 7 ? 12 :
7711 special_animation && j == 4 ? 3 :
7712 effective_action != action ? 0 :
7716 Bitmap *debug_bitmap = g_em->bitmap;
7717 int debug_src_x = g_em->src_x;
7718 int debug_src_y = g_em->src_y;
7721 int frame = getAnimationFrame(g->anim_frames,
7724 g->anim_start_frame,
7727 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y,
7728 g->double_movement && is_backside);
7730 g_em->bitmap = src_bitmap;
7731 g_em->src_x = src_x;
7732 g_em->src_y = src_y;
7733 g_em->src_offset_x = 0;
7734 g_em->src_offset_y = 0;
7735 g_em->dst_offset_x = 0;
7736 g_em->dst_offset_y = 0;
7737 g_em->width = TILEX;
7738 g_em->height = TILEY;
7740 g_em->preserve_background = FALSE;
7742 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
7745 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
7746 effective_action == ACTION_MOVING ||
7747 effective_action == ACTION_PUSHING ||
7748 effective_action == ACTION_EATING)) ||
7749 (!has_action_graphics && (effective_action == ACTION_FILLING ||
7750 effective_action == ACTION_EMPTYING)))
7753 (effective_action == ACTION_FALLING ||
7754 effective_action == ACTION_FILLING ||
7755 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
7756 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
7757 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
7758 int num_steps = (i == Ydrip_s1 ? 16 :
7759 i == Ydrip_s1B ? 16 :
7760 i == Ydrip_s2 ? 16 :
7761 i == Ydrip_s2B ? 16 :
7762 i == Xsand_stonein_1 ? 32 :
7763 i == Xsand_stonein_2 ? 32 :
7764 i == Xsand_stonein_3 ? 32 :
7765 i == Xsand_stonein_4 ? 32 :
7766 i == Xsand_stoneout_1 ? 16 :
7767 i == Xsand_stoneout_2 ? 16 : 8);
7768 int cx = ABS(dx) * (TILEX / num_steps);
7769 int cy = ABS(dy) * (TILEY / num_steps);
7770 int step_frame = (i == Ydrip_s2 ? j + 8 :
7771 i == Ydrip_s2B ? j + 8 :
7772 i == Xsand_stonein_2 ? j + 8 :
7773 i == Xsand_stonein_3 ? j + 16 :
7774 i == Xsand_stonein_4 ? j + 24 :
7775 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
7776 int step = (is_backside ? step_frame : num_steps - step_frame);
7778 if (is_backside) /* tile where movement starts */
7780 if (dx < 0 || dy < 0)
7782 g_em->src_offset_x = cx * step;
7783 g_em->src_offset_y = cy * step;
7787 g_em->dst_offset_x = cx * step;
7788 g_em->dst_offset_y = cy * step;
7791 else /* tile where movement ends */
7793 if (dx < 0 || dy < 0)
7795 g_em->dst_offset_x = cx * step;
7796 g_em->dst_offset_y = cy * step;
7800 g_em->src_offset_x = cx * step;
7801 g_em->src_offset_y = cy * step;
7805 g_em->width = TILEX - cx * step;
7806 g_em->height = TILEY - cy * step;
7809 /* create unique graphic identifier to decide if tile must be redrawn */
7810 /* bit 31 - 16 (16 bit): EM style graphic
7811 bit 15 - 12 ( 4 bit): EM style frame
7812 bit 11 - 6 ( 6 bit): graphic width
7813 bit 5 - 0 ( 6 bit): graphic height */
7814 g_em->unique_identifier =
7815 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
7819 /* skip check for EMC elements not contained in original EMC artwork */
7820 if (element == EL_EMC_FAKE_ACID)
7823 if (g_em->bitmap != debug_bitmap ||
7824 g_em->src_x != debug_src_x ||
7825 g_em->src_y != debug_src_y ||
7826 g_em->src_offset_x != 0 ||
7827 g_em->src_offset_y != 0 ||
7828 g_em->dst_offset_x != 0 ||
7829 g_em->dst_offset_y != 0 ||
7830 g_em->width != TILEX ||
7831 g_em->height != TILEY)
7833 static int last_i = -1;
7841 printf("::: EMC GFX ERROR for element %d -> %d ('%s', '%s', %d)",
7842 i, element, element_info[element].token_name,
7843 element_action_info[effective_action].suffix, direction);
7845 if (element != effective_element)
7846 printf(" [%d ('%s')]",
7848 element_info[effective_element].token_name);
7852 if (g_em->bitmap != debug_bitmap)
7853 printf(" %d (%d): different bitmap! (0x%08x != 0x%08x)\n",
7854 j, is_backside, (int)(g_em->bitmap), (int)(debug_bitmap));
7856 if (g_em->src_x != debug_src_x ||
7857 g_em->src_y != debug_src_y)
7858 printf(" frame %d (%c): %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
7859 j, (is_backside ? 'B' : 'F'),
7860 g_em->src_x, g_em->src_y,
7861 g_em->src_x / 32, g_em->src_y / 32,
7862 debug_src_x, debug_src_y,
7863 debug_src_x / 32, debug_src_y / 32);
7865 if (g_em->src_offset_x != 0 ||
7866 g_em->src_offset_y != 0 ||
7867 g_em->dst_offset_x != 0 ||
7868 g_em->dst_offset_y != 0)
7869 printf(" %d (%d): offsets %d,%d and %d,%d should be all 0\n",
7871 g_em->src_offset_x, g_em->src_offset_y,
7872 g_em->dst_offset_x, g_em->dst_offset_y);
7874 if (g_em->width != TILEX ||
7875 g_em->height != TILEY)
7876 printf(" %d (%d): size %d,%d should be %d,%d\n",
7878 g_em->width, g_em->height, TILEX, TILEY);
7880 num_em_gfx_errors++;
7887 for (i = 0; i < TILE_MAX; i++)
7889 for (j = 0; j < 8; j++)
7891 int element = object_mapping[i].element_rnd;
7892 int action = object_mapping[i].action;
7893 int direction = object_mapping[i].direction;
7894 boolean is_backside = object_mapping[i].is_backside;
7895 int graphic_action = el_act_dir2img(element, action, direction);
7896 int graphic_default = el_act_dir2img(element, ACTION_DEFAULT, direction);
7898 if ((action == ACTION_SMASHED_BY_ROCK ||
7899 action == ACTION_SMASHED_BY_SPRING ||
7900 action == ACTION_EATING) &&
7901 graphic_action == graphic_default)
7903 int e = (action == ACTION_SMASHED_BY_ROCK ? Ystone_s :
7904 action == ACTION_SMASHED_BY_SPRING ? Yspring_s :
7905 direction == MV_LEFT ? (is_backside? Yspring_wB: Yspring_w) :
7906 direction == MV_RIGHT ? (is_backside? Yspring_eB: Yspring_e) :
7909 /* no separate animation for "smashed by rock" -- use rock instead */
7910 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
7911 struct GraphicInfo_EM *g_xx = &graphic_info_em_object[e][7 - j];
7913 g_em->bitmap = g_xx->bitmap;
7914 g_em->src_x = g_xx->src_x;
7915 g_em->src_y = g_xx->src_y;
7916 g_em->src_offset_x = g_xx->src_offset_x;
7917 g_em->src_offset_y = g_xx->src_offset_y;
7918 g_em->dst_offset_x = g_xx->dst_offset_x;
7919 g_em->dst_offset_y = g_xx->dst_offset_y;
7920 g_em->width = g_xx->width;
7921 g_em->height = g_xx->height;
7922 g_em->unique_identifier = g_xx->unique_identifier;
7925 g_em->preserve_background = TRUE;
7930 for (p = 0; p < MAX_PLAYERS; p++)
7932 for (i = 0; i < SPR_MAX; i++)
7934 int element = player_mapping[p][i].element_rnd;
7935 int action = player_mapping[p][i].action;
7936 int direction = player_mapping[p][i].direction;
7938 for (j = 0; j < 8; j++)
7940 int effective_element = element;
7941 int effective_action = action;
7942 int graphic = (direction == MV_NONE ?
7943 el_act2img(effective_element, effective_action) :
7944 el_act_dir2img(effective_element, effective_action,
7946 struct GraphicInfo *g = &graphic_info[graphic];
7947 struct GraphicInfo_EM *g_em = &graphic_info_em_player[p][i][7 - j];
7953 Bitmap *debug_bitmap = g_em->bitmap;
7954 int debug_src_x = g_em->src_x;
7955 int debug_src_y = g_em->src_y;
7958 int frame = getAnimationFrame(g->anim_frames,
7961 g->anim_start_frame,
7964 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
7966 g_em->bitmap = src_bitmap;
7967 g_em->src_x = src_x;
7968 g_em->src_y = src_y;
7969 g_em->src_offset_x = 0;
7970 g_em->src_offset_y = 0;
7971 g_em->dst_offset_x = 0;
7972 g_em->dst_offset_y = 0;
7973 g_em->width = TILEX;
7974 g_em->height = TILEY;
7978 /* skip check for EMC elements not contained in original EMC artwork */
7979 if (element == EL_PLAYER_3 ||
7980 element == EL_PLAYER_4)
7983 if (g_em->bitmap != debug_bitmap ||
7984 g_em->src_x != debug_src_x ||
7985 g_em->src_y != debug_src_y)
7987 static int last_i = -1;
7995 printf("::: EMC GFX ERROR for p/a %d/%d -> %d ('%s', '%s', %d)",
7996 p, i, element, element_info[element].token_name,
7997 element_action_info[effective_action].suffix, direction);
7999 if (element != effective_element)
8000 printf(" [%d ('%s')]",
8002 element_info[effective_element].token_name);
8006 if (g_em->bitmap != debug_bitmap)
8007 printf(" %d: different bitmap! (0x%08x != 0x%08x)\n",
8008 j, (int)(g_em->bitmap), (int)(debug_bitmap));
8010 if (g_em->src_x != debug_src_x ||
8011 g_em->src_y != debug_src_y)
8012 printf(" frame %d: %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
8014 g_em->src_x, g_em->src_y,
8015 g_em->src_x / 32, g_em->src_y / 32,
8016 debug_src_x, debug_src_y,
8017 debug_src_x / 32, debug_src_y / 32);
8019 num_em_gfx_errors++;
8029 printf("::: [%d errors found]\n", num_em_gfx_errors);
8035 void CheckSaveEngineSnapshot_EM(byte action[MAX_PLAYERS], int frame,
8036 boolean any_player_moving,
8037 boolean any_player_snapping,
8038 boolean any_player_dropping)
8040 static boolean player_was_waiting = TRUE;
8042 if (frame == 0 && !any_player_dropping)
8044 if (!player_was_waiting)
8046 if (!SaveEngineSnapshotToList())
8049 player_was_waiting = TRUE;
8052 else if (any_player_moving || any_player_snapping || any_player_dropping)
8054 player_was_waiting = FALSE;
8058 void CheckSaveEngineSnapshot_SP(boolean murphy_is_waiting,
8059 boolean murphy_is_dropping)
8061 static boolean player_was_waiting = TRUE;
8063 if (murphy_is_waiting)
8065 if (!player_was_waiting)
8067 if (!SaveEngineSnapshotToList())
8070 player_was_waiting = TRUE;
8075 player_was_waiting = FALSE;
8079 void CheckSingleStepMode_EM(byte action[MAX_PLAYERS], int frame,
8080 boolean any_player_moving,
8081 boolean any_player_snapping,
8082 boolean any_player_dropping)
8084 if (tape.single_step && tape.recording && !tape.pausing)
8085 if (frame == 0 && !any_player_dropping)
8086 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
8088 CheckSaveEngineSnapshot_EM(action, frame, any_player_moving,
8089 any_player_snapping, any_player_dropping);
8092 void CheckSingleStepMode_SP(boolean murphy_is_waiting,
8093 boolean murphy_is_dropping)
8095 if (tape.single_step && tape.recording && !tape.pausing)
8096 if (murphy_is_waiting)
8097 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
8099 CheckSaveEngineSnapshot_SP(murphy_is_waiting, murphy_is_dropping);
8102 void getGraphicSource_SP(struct GraphicInfo_SP *g_sp,
8103 int graphic, int sync_frame, int x, int y)
8105 int frame = getGraphicAnimationFrame(graphic, sync_frame);
8107 getGraphicSource(graphic, frame, &g_sp->bitmap, &g_sp->src_x, &g_sp->src_y);
8110 boolean isNextAnimationFrame_SP(int graphic, int sync_frame)
8112 return (IS_NEXT_FRAME(sync_frame, graphic));
8115 int getGraphicInfo_Delay(int graphic)
8117 return graphic_info[graphic].anim_delay;
8120 void PlayMenuSoundExt(int sound)
8122 if (sound == SND_UNDEFINED)
8125 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
8126 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
8129 if (IS_LOOP_SOUND(sound))
8130 PlaySoundLoop(sound);
8135 void PlayMenuSound()
8137 PlayMenuSoundExt(menu.sound[game_status]);
8140 void PlayMenuSoundStereo(int sound, int stereo_position)
8142 if (sound == SND_UNDEFINED)
8145 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
8146 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
8149 if (IS_LOOP_SOUND(sound))
8150 PlaySoundExt(sound, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_LOOP);
8152 PlaySoundStereo(sound, stereo_position);
8155 void PlayMenuSoundIfLoopExt(int sound)
8157 if (sound == SND_UNDEFINED)
8160 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
8161 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
8164 if (IS_LOOP_SOUND(sound))
8165 PlaySoundLoop(sound);
8168 void PlayMenuSoundIfLoop()
8170 PlayMenuSoundIfLoopExt(menu.sound[game_status]);
8173 void PlayMenuMusicExt(int music)
8175 if (music == MUS_UNDEFINED)
8178 if (!setup.sound_music)
8184 void PlayMenuMusic()
8186 PlayMenuMusicExt(menu.music[game_status]);
8189 void PlaySoundActivating()
8192 PlaySound(SND_MENU_ITEM_ACTIVATING);
8196 void PlaySoundSelecting()
8199 PlaySound(SND_MENU_ITEM_SELECTING);
8203 void ToggleFullscreenOrChangeWindowScalingIfNeeded()
8205 boolean change_fullscreen = (setup.fullscreen !=
8206 video.fullscreen_enabled);
8207 boolean change_window_scaling_percent = (!video.fullscreen_enabled &&
8208 setup.window_scaling_percent !=
8209 video.window_scaling_percent);
8211 if (change_window_scaling_percent && video.fullscreen_enabled)
8214 if (!change_window_scaling_percent && !video.fullscreen_available)
8217 #if defined(TARGET_SDL2)
8218 if (change_window_scaling_percent)
8220 SDLSetWindowScaling(setup.window_scaling_percent);
8224 else if (change_fullscreen)
8226 SDLSetWindowFullscreen(setup.fullscreen);
8228 /* set setup value according to successfully changed fullscreen mode */
8229 setup.fullscreen = video.fullscreen_enabled;
8235 if (change_fullscreen ||
8236 change_window_scaling_percent)
8238 Bitmap *tmp_backbuffer = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
8240 /* save backbuffer content which gets lost when toggling fullscreen mode */
8241 BlitBitmap(backbuffer, tmp_backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
8243 if (change_window_scaling_percent)
8245 /* keep window mode, but change window scaling */
8246 video.fullscreen_enabled = TRUE; /* force new window scaling */
8249 /* toggle fullscreen */
8250 ChangeVideoModeIfNeeded(setup.fullscreen);
8252 /* set setup value according to successfully changed fullscreen mode */
8253 setup.fullscreen = video.fullscreen_enabled;
8255 /* restore backbuffer content from temporary backbuffer backup bitmap */
8256 BlitBitmap(tmp_backbuffer, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
8258 FreeBitmap(tmp_backbuffer);
8260 /* update visible window/screen */
8261 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
8265 void JoinRectangles(int *x, int *y, int *width, int *height,
8266 int x2, int y2, int width2, int height2)
8268 // do not join with "off-screen" rectangle
8269 if (x2 == -1 || y2 == -1)
8274 *width = MAX(*width, width2);
8275 *height = MAX(*height, height2);
8278 void SetAnimStatus(int anim_status_new)
8280 if (anim_status_new == GAME_MODE_MAIN)
8281 anim_status_new = GAME_MODE_PSEUDO_MAINONLY;
8283 global.anim_status_next = anim_status_new;
8285 // directly set screen modes that are entered without fading
8286 if ((global.anim_status == GAME_MODE_PSEUDO_MAINONLY &&
8287 global.anim_status_next == GAME_MODE_PSEUDO_TYPENAME) ||
8288 (global.anim_status == GAME_MODE_PSEUDO_TYPENAME &&
8289 global.anim_status_next == GAME_MODE_PSEUDO_MAINONLY))
8290 global.anim_status = global.anim_status_next;
8293 void SetGameStatus(int game_status_new)
8295 game_status = game_status_new;
8297 SetAnimStatus(game_status_new);
8300 void SetFontStatus(int game_status_new)
8302 static int last_game_status = -1;
8304 if (game_status_new != -1)
8306 // set game status for font use after storing last game status
8307 last_game_status = game_status;
8308 game_status = game_status_new;
8312 // reset game status after font use from last stored game status
8313 game_status = last_game_status;
8317 void ResetFontStatus()
8322 void ChangeViewportPropertiesIfNeeded()
8324 int gfx_game_mode = game_status;
8325 int gfx_game_mode2 = (game_status == GAME_MODE_EDITOR ? GAME_MODE_DEFAULT :
8327 struct RectWithBorder *vp_window = &viewport.window[gfx_game_mode];
8328 struct RectWithBorder *vp_playfield = &viewport.playfield[gfx_game_mode];
8329 struct RectWithBorder *vp_door_1 = &viewport.door_1[gfx_game_mode];
8330 struct RectWithBorder *vp_door_2 = &viewport.door_2[gfx_game_mode2];
8331 struct RectWithBorder *vp_door_3 = &viewport.door_2[GAME_MODE_EDITOR];
8332 int new_win_xsize = vp_window->width;
8333 int new_win_ysize = vp_window->height;
8334 int border_size = vp_playfield->border_size;
8335 int new_sx = vp_playfield->x + border_size;
8336 int new_sy = vp_playfield->y + border_size;
8337 int new_sxsize = vp_playfield->width - 2 * border_size;
8338 int new_sysize = vp_playfield->height - 2 * border_size;
8339 int new_real_sx = vp_playfield->x;
8340 int new_real_sy = vp_playfield->y;
8341 int new_full_sxsize = vp_playfield->width;
8342 int new_full_sysize = vp_playfield->height;
8343 int new_dx = vp_door_1->x;
8344 int new_dy = vp_door_1->y;
8345 int new_dxsize = vp_door_1->width;
8346 int new_dysize = vp_door_1->height;
8347 int new_vx = vp_door_2->x;
8348 int new_vy = vp_door_2->y;
8349 int new_vxsize = vp_door_2->width;
8350 int new_vysize = vp_door_2->height;
8351 int new_ex = vp_door_3->x;
8352 int new_ey = vp_door_3->y;
8353 int new_exsize = vp_door_3->width;
8354 int new_eysize = vp_door_3->height;
8355 int new_tilesize_var =
8356 (setup.small_game_graphics ? MINI_TILESIZE : game.tile_size);
8358 int tilesize = (gfx_game_mode == GAME_MODE_PLAYING ? new_tilesize_var :
8359 gfx_game_mode == GAME_MODE_EDITOR ? MINI_TILESIZE : TILESIZE);
8360 int new_scr_fieldx = new_sxsize / tilesize;
8361 int new_scr_fieldy = new_sysize / tilesize;
8362 int new_scr_fieldx_buffers = new_sxsize / new_tilesize_var;
8363 int new_scr_fieldy_buffers = new_sysize / new_tilesize_var;
8364 boolean init_gfx_buffers = FALSE;
8365 boolean init_video_buffer = FALSE;
8366 boolean init_gadgets_and_toons = FALSE;
8367 boolean init_em_graphics = FALSE;
8369 if (new_win_xsize != WIN_XSIZE ||
8370 new_win_ysize != WIN_YSIZE)
8372 WIN_XSIZE = new_win_xsize;
8373 WIN_YSIZE = new_win_ysize;
8375 init_video_buffer = TRUE;
8376 init_gfx_buffers = TRUE;
8377 init_gadgets_and_toons = TRUE;
8379 // printf("::: video: init_video_buffer, init_gfx_buffers\n");
8382 if (new_scr_fieldx != SCR_FIELDX ||
8383 new_scr_fieldy != SCR_FIELDY)
8385 /* this always toggles between MAIN and GAME when using small tile size */
8387 SCR_FIELDX = new_scr_fieldx;
8388 SCR_FIELDY = new_scr_fieldy;
8390 // printf("::: new_scr_fieldx != SCR_FIELDX ...\n");
8401 new_sxsize != SXSIZE ||
8402 new_sysize != SYSIZE ||
8403 new_dxsize != DXSIZE ||
8404 new_dysize != DYSIZE ||
8405 new_vxsize != VXSIZE ||
8406 new_vysize != VYSIZE ||
8407 new_exsize != EXSIZE ||
8408 new_eysize != EYSIZE ||
8409 new_real_sx != REAL_SX ||
8410 new_real_sy != REAL_SY ||
8411 new_full_sxsize != FULL_SXSIZE ||
8412 new_full_sysize != FULL_SYSIZE ||
8413 new_tilesize_var != TILESIZE_VAR
8416 // ------------------------------------------------------------------------
8417 // determine next fading area for changed viewport definitions
8418 // ------------------------------------------------------------------------
8420 // start with current playfield area (default fading area)
8423 FADE_SXSIZE = FULL_SXSIZE;
8424 FADE_SYSIZE = FULL_SYSIZE;
8426 // add new playfield area if position or size has changed
8427 if (new_real_sx != REAL_SX || new_real_sy != REAL_SY ||
8428 new_full_sxsize != FULL_SXSIZE || new_full_sysize != FULL_SYSIZE)
8430 JoinRectangles(&FADE_SX, &FADE_SY, &FADE_SXSIZE, &FADE_SYSIZE,
8431 new_real_sx, new_real_sy, new_full_sxsize,new_full_sysize);
8434 // add current and new door 1 area if position or size has changed
8435 if (new_dx != DX || new_dy != DY ||
8436 new_dxsize != DXSIZE || new_dysize != DYSIZE)
8438 JoinRectangles(&FADE_SX, &FADE_SY, &FADE_SXSIZE, &FADE_SYSIZE,
8439 DX, DY, DXSIZE, DYSIZE);
8440 JoinRectangles(&FADE_SX, &FADE_SY, &FADE_SXSIZE, &FADE_SYSIZE,
8441 new_dx, new_dy, new_dxsize, new_dysize);
8444 // add current and new door 2 area if position or size has changed
8445 if (new_dx != VX || new_dy != VY ||
8446 new_dxsize != VXSIZE || new_dysize != VYSIZE)
8448 JoinRectangles(&FADE_SX, &FADE_SY, &FADE_SXSIZE, &FADE_SYSIZE,
8449 VX, VY, VXSIZE, VYSIZE);
8450 JoinRectangles(&FADE_SX, &FADE_SY, &FADE_SXSIZE, &FADE_SYSIZE,
8451 new_vx, new_vy, new_vxsize, new_vysize);
8454 // ------------------------------------------------------------------------
8455 // handle changed tile size
8456 // ------------------------------------------------------------------------
8458 if (new_tilesize_var != TILESIZE_VAR)
8460 // printf("::: new_tilesize_var != TILESIZE_VAR\n");
8462 // changing tile size invalidates scroll values of engine snapshots
8463 FreeEngineSnapshotSingle();
8465 // changing tile size requires update of graphic mapping for EM engine
8466 init_em_graphics = TRUE;
8477 SXSIZE = new_sxsize;
8478 SYSIZE = new_sysize;
8479 DXSIZE = new_dxsize;
8480 DYSIZE = new_dysize;
8481 VXSIZE = new_vxsize;
8482 VYSIZE = new_vysize;
8483 EXSIZE = new_exsize;
8484 EYSIZE = new_eysize;
8485 REAL_SX = new_real_sx;
8486 REAL_SY = new_real_sy;
8487 FULL_SXSIZE = new_full_sxsize;
8488 FULL_SYSIZE = new_full_sysize;
8489 TILESIZE_VAR = new_tilesize_var;
8491 init_gfx_buffers = TRUE;
8492 init_gadgets_and_toons = TRUE;
8494 // printf("::: viewports: init_gfx_buffers\n");
8495 // printf("::: viewports: init_gadgets_and_toons\n");
8498 if (init_gfx_buffers)
8500 // printf("::: init_gfx_buffers\n");
8502 SCR_FIELDX = new_scr_fieldx_buffers;
8503 SCR_FIELDY = new_scr_fieldy_buffers;
8507 SCR_FIELDX = new_scr_fieldx;
8508 SCR_FIELDY = new_scr_fieldy;
8510 SetDrawDeactivationMask(REDRAW_NONE);
8511 SetDrawBackgroundMask(REDRAW_FIELD);
8514 if (init_video_buffer)
8516 // printf("::: init_video_buffer\n");
8518 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
8519 InitImageTextures();
8522 if (init_gadgets_and_toons)
8524 // printf("::: init_gadgets_and_toons\n");
8528 InitGlobalAnimations();
8531 if (init_em_graphics)
8533 InitGraphicInfo_EM();