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 0
29 /* tool button identifiers */
30 #define TOOL_CTRL_ID_YES 0
31 #define TOOL_CTRL_ID_NO 1
32 #define TOOL_CTRL_ID_CONFIRM 2
33 #define TOOL_CTRL_ID_PLAYER_1 3
34 #define TOOL_CTRL_ID_PLAYER_2 4
35 #define TOOL_CTRL_ID_PLAYER_3 5
36 #define TOOL_CTRL_ID_PLAYER_4 6
38 #define NUM_TOOL_BUTTONS 7
40 /* constants for number of doors and door parts */
42 #define NUM_PANELS NUM_DOORS
43 // #define NUM_PANELS 0
44 #define MAX_PARTS_PER_DOOR 8
45 #define MAX_DOOR_PARTS (NUM_DOORS * MAX_PARTS_PER_DOOR + NUM_PANELS)
46 #define DOOR_PART_IS_PANEL(i) ((i) >= NUM_DOORS * MAX_PARTS_PER_DOOR)
49 struct DoorPartOrderInfo
55 static struct DoorPartOrderInfo door_part_order[MAX_DOOR_PARTS];
57 struct DoorPartControlInfo
61 struct DoorPartPosInfo *pos;
64 static struct DoorPartControlInfo door_part_controls[] =
68 IMG_DOOR_1_GFX_PART_1,
73 IMG_DOOR_1_GFX_PART_2,
78 IMG_DOOR_1_GFX_PART_3,
83 IMG_DOOR_1_GFX_PART_4,
88 IMG_DOOR_1_GFX_PART_5,
93 IMG_DOOR_1_GFX_PART_6,
98 IMG_DOOR_1_GFX_PART_7,
103 IMG_DOOR_1_GFX_PART_8,
109 IMG_DOOR_2_GFX_PART_1,
114 IMG_DOOR_2_GFX_PART_2,
119 IMG_DOOR_2_GFX_PART_3,
124 IMG_DOOR_2_GFX_PART_4,
129 IMG_DOOR_2_GFX_PART_5,
134 IMG_DOOR_2_GFX_PART_6,
139 IMG_DOOR_2_GFX_PART_7,
144 IMG_DOOR_2_GFX_PART_8,
150 IMG_BACKGROUND_PANEL,
167 /* forward declaration for internal use */
168 static void UnmapToolButtons();
169 static void HandleToolButtons(struct GadgetInfo *);
170 static int el_act_dir2crm(int, int, int);
171 static int el_act2crm(int, int);
173 static struct GadgetInfo *tool_gadget[NUM_TOOL_BUTTONS];
174 static int request_gadget_id = -1;
176 static char *print_if_not_empty(int element)
178 static char *s = NULL;
179 char *token_name = element_info[element].token_name;
184 s = checked_malloc(strlen(token_name) + 10 + 1);
186 if (element != EL_EMPTY)
187 sprintf(s, "%d\t['%s']", element, token_name);
189 sprintf(s, "%d", element);
194 void DumpTile(int x, int y)
199 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
205 printf_line("-", 79);
206 printf("Field Info: SCREEN(%d, %d), LEVEL(%d, %d)\n", sx, sy, x, y);
207 printf_line("-", 79);
209 if (!IN_LEV_FIELD(x, y))
211 printf("(not in level field)\n");
217 printf(" Feld: %d\t['%s']\n", Feld[x][y],
218 element_info[Feld[x][y]].token_name);
219 printf(" Back: %s\n", print_if_not_empty(Back[x][y]));
220 printf(" Store: %s\n", print_if_not_empty(Store[x][y]));
221 printf(" Store2: %s\n", print_if_not_empty(Store2[x][y]));
222 printf(" StorePlayer: %s\n", print_if_not_empty(StorePlayer[x][y]));
223 printf(" MovPos: %d\n", MovPos[x][y]);
224 printf(" MovDir: %d\n", MovDir[x][y]);
225 printf(" MovDelay: %d\n", MovDelay[x][y]);
226 printf(" ChangeDelay: %d\n", ChangeDelay[x][y]);
227 printf(" CustomValue: %d\n", CustomValue[x][y]);
228 printf(" GfxElement: %d\n", GfxElement[x][y]);
229 printf(" GfxAction: %d\n", GfxAction[x][y]);
230 printf(" GfxFrame: %d\n", GfxFrame[x][y]);
234 void SetDrawtoField(int mode)
236 if (mode == DRAW_BUFFERED && setup.soft_scrolling)
242 BX2 = SCR_FIELDX + 1;
243 BY2 = SCR_FIELDY + 1;
247 drawto_field = fieldbuffer;
249 else /* DRAW_BACKBUFFER */
255 BX2 = SCR_FIELDX - 1;
256 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 void DrawMaskedBorder_Rect(int x, int y, int width, int height)
293 Bitmap *bitmap = graphic_info[IMG_GLOBAL_BORDER].bitmap;
295 SetClipOrigin(bitmap, bitmap->stored_clip_gc, 0, 0);
296 BlitBitmapMasked(bitmap, backbuffer, x, y, width, height, x, y);
299 void DrawMaskedBorder_FIELD()
301 if (global.border_status >= GAME_MODE_TITLE &&
302 global.border_status <= GAME_MODE_PLAYING &&
303 border.draw_masked[global.border_status])
304 DrawMaskedBorder_Rect(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
307 void DrawMaskedBorder_DOOR_1()
309 if (border.draw_masked[GFX_SPECIAL_ARG_DOOR] &&
310 (global.border_status != GAME_MODE_EDITOR ||
311 border.draw_masked[GFX_SPECIAL_ARG_EDITOR]))
312 DrawMaskedBorder_Rect(DX, DY, DXSIZE, DYSIZE);
315 void DrawMaskedBorder_DOOR_2()
317 if (border.draw_masked[GFX_SPECIAL_ARG_DOOR] &&
318 global.border_status != GAME_MODE_EDITOR)
319 DrawMaskedBorder_Rect(VX, VY, VXSIZE, VYSIZE);
322 void DrawMaskedBorder_DOOR_3()
324 /* currently not available */
327 void DrawMaskedBorder_ALL()
329 DrawMaskedBorder_FIELD();
330 DrawMaskedBorder_DOOR_1();
331 DrawMaskedBorder_DOOR_2();
332 DrawMaskedBorder_DOOR_3();
335 void DrawMaskedBorder(int redraw_mask)
337 /* never draw masked screen borders on borderless screens */
338 if (effectiveGameStatus() == GAME_MODE_LOADING ||
339 effectiveGameStatus() == GAME_MODE_TITLE)
342 /* never draw masked screen borders when displaying request outside door */
343 if (effectiveGameStatus() == GAME_MODE_PSEUDO_DOOR &&
344 global.use_envelope_request)
347 if (redraw_mask & REDRAW_ALL)
348 DrawMaskedBorder_ALL();
351 if (redraw_mask & REDRAW_FIELD)
352 DrawMaskedBorder_FIELD();
353 if (redraw_mask & REDRAW_DOOR_1)
354 DrawMaskedBorder_DOOR_1();
355 if (redraw_mask & REDRAW_DOOR_2)
356 DrawMaskedBorder_DOOR_2();
357 if (redraw_mask & REDRAW_DOOR_3)
358 DrawMaskedBorder_DOOR_3();
362 static void BlitScreenToBitmap_RND(Bitmap *target_bitmap)
364 DrawBuffer *buffer = (drawto_field == window ? backbuffer : drawto_field);
365 int fx = FX, fy = FY;
366 int full_lev_fieldx = lev_fieldx + (BorderElement != EL_EMPTY ? 2 : 0);
367 int full_lev_fieldy = lev_fieldy + (BorderElement != EL_EMPTY ? 2 : 0);
369 int dx = (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
370 int dy = (ScreenMovDir & (MV_UP | MV_DOWN) ? ScreenGfxPos : 0);
371 int dx_var = dx * TILESIZE_VAR / TILESIZE;
372 int dy_var = dy * TILESIZE_VAR / TILESIZE;
375 ffx = (scroll_x - SBX_Left) * TILEX_VAR + dx_var;
376 ffy = (scroll_y - SBY_Upper) * TILEY_VAR + dy_var;
378 if (EVEN(SCR_FIELDX))
380 if (ffx < SBX_Right * TILEX_VAR + TILEX_VAR / 2 + TILEX_VAR)
381 fx += dx_var - MIN(ffx, TILEX_VAR / 2) + TILEX_VAR;
383 fx += (dx_var > 0 ? TILEX_VAR : 0);
390 if (EVEN(SCR_FIELDY))
392 if (ffy < SBY_Lower * TILEY_VAR + TILEY_VAR / 2 + TILEY_VAR)
393 fy += dy_var - MIN(ffy, TILEY_VAR / 2) + TILEY_VAR;
395 fy += (dy_var > 0 ? TILEY_VAR : 0);
402 if (full_lev_fieldx <= SCR_FIELDX)
404 if (EVEN(SCR_FIELDX))
405 fx = 2 * TILEX_VAR - (ODD(lev_fieldx) ? TILEX_VAR / 2 : 0);
407 fx = 2 * TILEX_VAR - (EVEN(lev_fieldx) ? TILEX_VAR / 2 : 0);
410 if (full_lev_fieldy <= SCR_FIELDY)
412 if (EVEN(SCR_FIELDY))
413 fy = 2 * TILEY_VAR - (ODD(lev_fieldy) ? TILEY_VAR / 2 : 0);
415 fy = 2 * TILEY_VAR - (EVEN(lev_fieldy) ? TILEY_VAR / 2 : 0);
418 if (border.draw_masked[GAME_MODE_PLAYING])
420 if (buffer != backbuffer)
422 /* copy playfield buffer to backbuffer to add masked border */
423 BlitBitmap(buffer, backbuffer, fx, fy, SXSIZE, SYSIZE, SX, SY);
424 DrawMaskedBorder(REDRAW_FIELD);
427 BlitBitmap(backbuffer, target_bitmap,
428 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
433 BlitBitmap(buffer, target_bitmap, fx, fy, SXSIZE, SYSIZE, SX, SY);
437 void BlitScreenToBitmap(Bitmap *target_bitmap)
439 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
440 BlitScreenToBitmap_EM(target_bitmap);
441 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
442 BlitScreenToBitmap_SP(target_bitmap);
443 else if (level.game_engine_type == GAME_ENGINE_TYPE_RND)
444 BlitScreenToBitmap_RND(target_bitmap);
450 DrawBuffer *buffer = (drawto_field == window ? backbuffer : drawto_field);
452 if (redraw_mask & REDRAW_TILES && redraw_tiles > REDRAWTILES_THRESHOLD)
453 redraw_mask |= REDRAW_FIELD;
456 // never redraw single tiles, always redraw the whole field
457 // (redrawing single tiles up to a certain threshold was faster on old,
458 // now legacy graphics, but slows things down on modern graphics now)
459 // UPDATE: this is now globally defined by value of REDRAWTILES_THRESHOLD
460 if (redraw_mask & REDRAW_TILES)
461 redraw_mask |= REDRAW_FIELD;
465 /* !!! TEST ONLY !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */
466 /* (force full redraw) */
467 if (game_status == GAME_MODE_PLAYING)
468 redraw_mask |= REDRAW_FIELD;
471 if (redraw_mask & REDRAW_FIELD)
472 redraw_mask &= ~REDRAW_TILES;
474 if (redraw_mask == REDRAW_NONE)
479 if (redraw_mask & REDRAW_ALL)
480 printf("[REDRAW_ALL]");
481 if (redraw_mask & REDRAW_FIELD)
482 printf("[REDRAW_FIELD]");
483 if (redraw_mask & REDRAW_TILES)
484 printf("[REDRAW_TILES]");
485 if (redraw_mask & REDRAW_DOOR_1)
486 printf("[REDRAW_DOOR_1]");
487 if (redraw_mask & REDRAW_DOOR_2)
488 printf("[REDRAW_DOOR_2]");
489 if (redraw_mask & REDRAW_FROM_BACKBUFFER)
490 printf("[REDRAW_FROM_BACKBUFFER]");
491 printf(" [%d]\n", FrameCounter);
494 if (redraw_mask & REDRAW_TILES &&
495 game_status == GAME_MODE_PLAYING &&
496 border.draw_masked[GAME_MODE_PLAYING])
497 redraw_mask |= REDRAW_FIELD;
499 if (global.fps_slowdown && game_status == GAME_MODE_PLAYING)
501 static boolean last_frame_skipped = FALSE;
502 boolean skip_even_when_not_scrolling = TRUE;
503 boolean just_scrolling = (ScreenMovDir != 0);
504 boolean verbose = FALSE;
506 if (global.fps_slowdown_factor > 1 &&
507 (FrameCounter % global.fps_slowdown_factor) &&
508 (just_scrolling || skip_even_when_not_scrolling))
510 redraw_mask &= ~REDRAW_MAIN;
512 last_frame_skipped = TRUE;
515 printf("FRAME SKIPPED\n");
519 if (last_frame_skipped)
520 redraw_mask |= REDRAW_FIELD;
522 last_frame_skipped = FALSE;
525 printf("frame not skipped\n");
529 /* synchronize X11 graphics at this point; if we would synchronize the
530 display immediately after the buffer switching (after the XFlush),
531 this could mean that we have to wait for the graphics to complete,
532 although we could go on doing calculations for the next frame */
536 /* never draw masked border to backbuffer when using playfield buffer */
537 if (game_status != GAME_MODE_PLAYING ||
538 redraw_mask & REDRAW_FROM_BACKBUFFER ||
539 buffer == backbuffer)
540 DrawMaskedBorder(redraw_mask);
542 DrawMaskedBorder(redraw_mask & REDRAW_DOORS);
544 if (redraw_mask & REDRAW_ALL)
546 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
548 redraw_mask = REDRAW_NONE;
551 if (redraw_mask & REDRAW_FIELD)
553 if (game_status != GAME_MODE_PLAYING ||
554 redraw_mask & REDRAW_FROM_BACKBUFFER)
556 BlitBitmap(backbuffer, window,
557 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE, REAL_SX, REAL_SY);
561 BlitScreenToBitmap_RND(window);
564 redraw_mask &= ~REDRAW_MAIN;
567 if (redraw_mask & REDRAW_DOORS)
569 if (redraw_mask & REDRAW_DOOR_1)
570 BlitBitmap(backbuffer, window, DX, DY, DXSIZE, DYSIZE, DX, DY);
572 if (redraw_mask & REDRAW_DOOR_2)
573 BlitBitmap(backbuffer, window, VX, VY, VXSIZE, VYSIZE, VX, VY);
575 if (redraw_mask & REDRAW_DOOR_3)
576 BlitBitmap(backbuffer, window, EX, EY, EXSIZE, EYSIZE, EX, EY);
578 redraw_mask &= ~REDRAW_DOORS;
581 if (redraw_mask & REDRAW_MICROLEVEL)
583 BlitBitmap(backbuffer, window, SX, SY + 10 * TILEY, SXSIZE, 7 * TILEY,
584 SX, SY + 10 * TILEY);
586 redraw_mask &= ~REDRAW_MICROLEVEL;
589 if (redraw_mask & REDRAW_TILES)
595 int dx_var = dx * TILESIZE_VAR / TILESIZE;
596 int dy_var = dy * TILESIZE_VAR / TILESIZE;
598 int fx = FX, fy = FY;
600 int scr_fieldx = SCR_FIELDX + (EVEN(SCR_FIELDX) ? 2 : 0);
601 int scr_fieldy = SCR_FIELDY + (EVEN(SCR_FIELDY) ? 2 : 0);
603 InitGfxClipRegion(TRUE, SX, SY, SXSIZE, SYSIZE);
605 ffx = (scroll_x - SBX_Left) * TILEX_VAR + dx_var;
606 ffy = (scroll_y - SBY_Upper) * TILEY_VAR + dy_var;
608 if (EVEN(SCR_FIELDX))
610 if (ffx < SBX_Right * TILEX_VAR + TILEX_VAR / 2 + TILEX_VAR)
612 fx += dx_var - MIN(ffx, TILEX_VAR / 2) + TILEX_VAR;
621 fx += (dx_var > 0 ? TILEX_VAR : 0);
625 if (EVEN(SCR_FIELDY))
627 if (ffy < SBY_Lower * TILEY_VAR + TILEY_VAR / 2 + TILEY_VAR)
629 fy += dy_var - MIN(ffy, TILEY_VAR / 2) + TILEY_VAR;
638 fy += (dy_var > 0 ? TILEY_VAR : 0);
642 for (x = 0; x < scr_fieldx; x++)
643 for (y = 0 ; y < scr_fieldy; y++)
644 if (redraw[redraw_x1 + x][redraw_y1 + y])
645 BlitBitmap(buffer, window,
646 FX + x * TILEX_VAR, FY + y * TILEY_VAR,
647 TILEX_VAR, TILEY_VAR,
648 sx + x * TILEX_VAR, sy + y * TILEY_VAR);
650 InitGfxClipRegion(FALSE, -1, -1, -1, -1);
653 if (redraw_mask & REDRAW_FPS) /* display frames per second */
658 sprintf(info1, " (only every %d. frame)", global.fps_slowdown_factor);
659 if (!global.fps_slowdown)
662 sprintf(text, "%04.1f fps%s", global.frames_per_second, info1);
664 DrawTextExt(window, SX + SXSIZE + SX, 0, text, FONT_TEXT_2, BLIT_OPAQUE);
669 for (x = 0; x < MAX_BUF_XSIZE; x++)
670 for (y = 0; y < MAX_BUF_YSIZE; y++)
673 redraw_mask = REDRAW_NONE;
676 static void FadeCrossSaveBackbuffer()
678 BlitBitmap(backbuffer, bitmap_db_cross, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
681 static void FadeExt(int fade_mask, int fade_mode, int fade_type)
683 static int fade_type_skip = FADE_TYPE_NONE;
684 void (*draw_border_function)(void) = NULL;
685 Bitmap *bitmap = (fade_mode & FADE_TYPE_TRANSFORM ? bitmap_db_cross : NULL);
686 int x, y, width, height;
687 int fade_delay, post_delay;
689 if (fade_type == FADE_TYPE_FADE_OUT)
691 if (fade_type_skip != FADE_TYPE_NONE)
693 /* skip all fade operations until specified fade operation */
694 if (fade_type & fade_type_skip)
695 fade_type_skip = FADE_TYPE_NONE;
700 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
702 FadeCrossSaveBackbuffer();
708 redraw_mask |= fade_mask;
710 if (fade_type == FADE_TYPE_SKIP)
712 fade_type_skip = fade_mode;
717 fade_delay = fading.fade_delay;
718 post_delay = (fade_mode == FADE_MODE_FADE_OUT ? fading.post_delay : 0);
720 if (fade_type_skip != FADE_TYPE_NONE)
722 /* skip all fade operations until specified fade operation */
723 if (fade_type & fade_type_skip)
724 fade_type_skip = FADE_TYPE_NONE;
729 if (global.autoplay_leveldir)
734 if (fade_mask == REDRAW_FIELD)
739 height = FULL_SYSIZE;
741 if (border.draw_masked_when_fading)
742 draw_border_function = DrawMaskedBorder_FIELD; /* update when fading */
744 DrawMaskedBorder_FIELD(); /* draw once */
746 else /* REDRAW_ALL */
754 if (!setup.fade_screens ||
756 fading.fade_mode == FADE_MODE_NONE)
758 if (fade_mode == FADE_MODE_FADE_OUT)
761 BlitBitmap(backbuffer, window, x, y, width, height, x, y);
763 redraw_mask &= ~fade_mask;
768 FadeRectangle(bitmap, x, y, width, height, fade_mode, fade_delay, post_delay,
769 draw_border_function);
771 redraw_mask &= ~fade_mask;
774 void FadeIn(int fade_mask)
776 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
777 FadeExt(fade_mask, fading.fade_mode, FADE_TYPE_FADE_IN);
779 FadeExt(fade_mask, FADE_MODE_FADE_IN, FADE_TYPE_FADE_IN);
782 void FadeOut(int fade_mask)
784 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
785 FadeExt(fade_mask, fading.fade_mode, FADE_TYPE_FADE_OUT);
787 FadeExt(fade_mask, FADE_MODE_FADE_OUT, FADE_TYPE_FADE_OUT);
789 global.border_status = game_status;
792 static void FadeSetLeaveNext(struct TitleFadingInfo fading_leave, boolean set)
794 static struct TitleFadingInfo fading_leave_stored;
797 fading_leave_stored = fading_leave;
799 fading = fading_leave_stored;
802 void FadeSetEnterMenu()
804 fading = menu.enter_menu;
806 FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
809 void FadeSetLeaveMenu()
811 fading = menu.leave_menu;
813 FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
816 void FadeSetEnterScreen()
818 fading = menu.enter_screen[game_status];
820 FadeSetLeaveNext(menu.leave_screen[game_status], TRUE); /* store */
823 void FadeSetNextScreen()
825 fading = menu.next_screen;
827 // (do not overwrite fade mode set by FadeSetEnterScreen)
828 // FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
831 void FadeSetLeaveScreen()
833 FadeSetLeaveNext(menu.leave_screen[game_status], FALSE); /* recall */
836 void FadeSetFromType(int type)
838 if (type & TYPE_ENTER_SCREEN)
839 FadeSetEnterScreen();
840 else if (type & TYPE_ENTER)
842 else if (type & TYPE_LEAVE)
846 void FadeSetDisabled()
848 static struct TitleFadingInfo fading_none = { FADE_MODE_NONE, -1, -1, -1 };
850 fading = fading_none;
853 void FadeSkipNextFadeIn()
855 FadeExt(0, FADE_MODE_SKIP_FADE_IN, FADE_TYPE_SKIP);
858 void FadeSkipNextFadeOut()
860 FadeExt(0, FADE_MODE_SKIP_FADE_OUT, FADE_TYPE_SKIP);
863 void SetWindowBackgroundImageIfDefined(int graphic)
865 if (graphic_info[graphic].bitmap)
866 SetWindowBackgroundBitmap(graphic_info[graphic].bitmap);
869 void SetMainBackgroundImageIfDefined(int graphic)
871 if (graphic_info[graphic].bitmap)
872 SetMainBackgroundBitmap(graphic_info[graphic].bitmap);
875 void SetDoorBackgroundImageIfDefined(int graphic)
877 if (graphic_info[graphic].bitmap)
878 SetDoorBackgroundBitmap(graphic_info[graphic].bitmap);
881 void SetWindowBackgroundImage(int graphic)
883 SetWindowBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
884 graphic_info[graphic].bitmap ?
885 graphic_info[graphic].bitmap :
886 graphic_info[IMG_BACKGROUND].bitmap);
889 void SetMainBackgroundImage(int graphic)
891 SetMainBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
892 graphic_info[graphic].bitmap ?
893 graphic_info[graphic].bitmap :
894 graphic_info[IMG_BACKGROUND].bitmap);
897 void SetDoorBackgroundImage(int graphic)
899 SetDoorBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
900 graphic_info[graphic].bitmap ?
901 graphic_info[graphic].bitmap :
902 graphic_info[IMG_BACKGROUND].bitmap);
905 void SetPanelBackground()
907 struct GraphicInfo *gfx = &graphic_info[IMG_BACKGROUND_PANEL];
909 BlitBitmapTiled(gfx->bitmap, bitmap_db_panel, gfx->src_x, gfx->src_y,
910 gfx->width, gfx->height, 0, 0, DXSIZE, DYSIZE);
912 SetDoorBackgroundBitmap(bitmap_db_panel);
915 void DrawBackground(int x, int y, int width, int height)
917 /* "drawto" might still point to playfield buffer here (hall of fame) */
918 ClearRectangleOnBackground(backbuffer, x, y, width, height);
920 if (IN_GFX_FIELD_FULL(x, y))
921 redraw_mask |= REDRAW_FIELD;
922 else if (IN_GFX_DOOR_1(x, y))
923 redraw_mask |= REDRAW_DOOR_1;
924 else if (IN_GFX_DOOR_2(x, y))
925 redraw_mask |= REDRAW_DOOR_2;
926 else if (IN_GFX_DOOR_3(x, y))
927 redraw_mask |= REDRAW_DOOR_3;
930 void DrawBackgroundForFont(int x, int y, int width, int height, int font_nr)
932 struct FontBitmapInfo *font = getFontBitmapInfo(font_nr);
934 if (font->bitmap == NULL)
937 DrawBackground(x, y, width, height);
940 void DrawBackgroundForGraphic(int x, int y, int width, int height, int graphic)
942 struct GraphicInfo *g = &graphic_info[graphic];
944 if (g->bitmap == NULL)
947 DrawBackground(x, y, width, height);
952 /* !!! "drawto" might still point to playfield buffer here (see above) !!! */
953 /* (when entering hall of fame after playing) */
954 DrawBackground(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
956 /* !!! maybe this should be done before clearing the background !!! */
957 if (setup.soft_scrolling && game_status == GAME_MODE_PLAYING)
959 ClearRectangle(fieldbuffer, 0, 0, FXSIZE, FYSIZE);
960 SetDrawtoField(DRAW_BUFFERED);
963 SetDrawtoField(DRAW_BACKBUFFER);
966 void MarkTileDirty(int x, int y)
968 int xx = redraw_x1 + x;
969 int yy = redraw_y1 + y;
974 redraw[xx][yy] = TRUE;
975 redraw_mask |= REDRAW_TILES;
978 void SetBorderElement()
982 BorderElement = EL_EMPTY;
984 for (y = 0; y < lev_fieldy && BorderElement == EL_EMPTY; y++)
986 for (x = 0; x < lev_fieldx; x++)
988 if (!IS_INDESTRUCTIBLE(Feld[x][y]))
989 BorderElement = EL_STEELWALL;
991 if (y != 0 && y != lev_fieldy - 1 && x != lev_fieldx - 1)
997 void FloodFillLevel(int from_x, int from_y, int fill_element,
998 short field[MAX_LEV_FIELDX][MAX_LEV_FIELDY],
999 int max_fieldx, int max_fieldy)
1003 static int check[4][2] = { { -1, 0 }, { 0, -1 }, { 1, 0 }, { 0, 1 } };
1004 static int safety = 0;
1006 /* check if starting field still has the desired content */
1007 if (field[from_x][from_y] == fill_element)
1012 if (safety > max_fieldx * max_fieldy)
1013 Error(ERR_EXIT, "Something went wrong in 'FloodFill()'. Please debug.");
1015 old_element = field[from_x][from_y];
1016 field[from_x][from_y] = fill_element;
1018 for (i = 0; i < 4; i++)
1020 x = from_x + check[i][0];
1021 y = from_y + check[i][1];
1023 if (IN_FIELD(x, y, max_fieldx, max_fieldy) && field[x][y] == old_element)
1024 FloodFillLevel(x, y, fill_element, field, max_fieldx, max_fieldy);
1030 void SetRandomAnimationValue(int x, int y)
1032 gfx.anim_random_frame = GfxRandom[x][y];
1035 inline int getGraphicAnimationFrame(int graphic, int sync_frame)
1037 /* animation synchronized with global frame counter, not move position */
1038 if (graphic_info[graphic].anim_global_sync || sync_frame < 0)
1039 sync_frame = FrameCounter;
1041 return getAnimationFrame(graphic_info[graphic].anim_frames,
1042 graphic_info[graphic].anim_delay,
1043 graphic_info[graphic].anim_mode,
1044 graphic_info[graphic].anim_start_frame,
1048 void getSizedGraphicSourceExt(int graphic, int frame, int tilesize_raw,
1049 Bitmap **bitmap, int *x, int *y,
1050 boolean get_backside)
1052 struct GraphicInfo *g = &graphic_info[graphic];
1053 Bitmap *src_bitmap = g->bitmap;
1054 int tilesize = MIN(MAX(1, tilesize_raw), TILESIZE);
1055 int offset_x = g->offset_x * tilesize_raw / TILESIZE;
1056 int offset_y = g->offset_y * tilesize_raw / TILESIZE;
1057 int offset2_x = (get_backside ? g->offset2_x : 0);
1058 int offset2_y = (get_backside ? g->offset2_y : 0);
1059 int src_x = (g->src_x + offset2_x) * tilesize_raw / TILESIZE;
1060 int src_y = (g->src_y + offset2_y) * tilesize_raw / TILESIZE;
1061 int width = g->width * tilesize_raw / TILESIZE;
1062 int height = g->height * tilesize_raw / TILESIZE;
1064 if (tilesize_raw == gfx.standard_tile_size)
1065 src_bitmap = g->bitmaps[IMG_BITMAP_STANDARD];
1066 else if (tilesize_raw == game.tile_size)
1067 src_bitmap = g->bitmaps[IMG_BITMAP_GAME];
1069 src_bitmap = g->bitmaps[IMG_BITMAP_1x1 - log_2(tilesize)];
1071 if (g->offset_y == 0) /* frames are ordered horizontally */
1073 int max_width = g->anim_frames_per_line * width;
1074 int pos = (src_y / height) * max_width + src_x + frame * offset_x;
1076 src_x = pos % max_width;
1077 src_y = src_y % height + pos / max_width * height;
1079 else if (g->offset_x == 0) /* frames are ordered vertically */
1081 int max_height = g->anim_frames_per_line * height;
1082 int pos = (src_x / width) * max_height + src_y + frame * offset_y;
1084 src_x = src_x % width + pos / max_height * width;
1085 src_y = pos % max_height;
1087 else /* frames are ordered diagonally */
1089 src_x = src_x + frame * offset_x;
1090 src_y = src_y + frame * offset_y;
1093 *bitmap = src_bitmap;
1098 void getFixedGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
1099 int *x, int *y, boolean get_backside)
1101 getSizedGraphicSourceExt(graphic, frame, TILESIZE, bitmap, x, y,
1105 void getSizedGraphicSource(int graphic, int frame, int tilesize_raw,
1106 Bitmap **bitmap, int *x, int *y)
1108 getSizedGraphicSourceExt(graphic, frame, tilesize_raw, bitmap, x, y, FALSE);
1111 void getFixedGraphicSource(int graphic, int frame,
1112 Bitmap **bitmap, int *x, int *y)
1114 getSizedGraphicSourceExt(graphic, frame, TILESIZE, bitmap, x, y, FALSE);
1117 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
1119 getSizedGraphicSource(graphic, 0, MINI_TILESIZE, bitmap, x, y);
1122 inline void getGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
1123 int *x, int *y, boolean get_backside)
1125 struct GraphicInfo *g = &graphic_info[graphic];
1126 int src_x = g->src_x + (get_backside ? g->offset2_x : 0);
1127 int src_y = g->src_y + (get_backside ? g->offset2_y : 0);
1129 if (TILESIZE_VAR != TILESIZE)
1130 return getSizedGraphicSourceExt(graphic, frame, TILESIZE_VAR, bitmap, x, y,
1133 *bitmap = g->bitmap;
1135 if (g->offset_y == 0) /* frames are ordered horizontally */
1137 int max_width = g->anim_frames_per_line * g->width;
1138 int pos = (src_y / g->height) * max_width + src_x + frame * g->offset_x;
1140 *x = pos % max_width;
1141 *y = src_y % g->height + pos / max_width * g->height;
1143 else if (g->offset_x == 0) /* frames are ordered vertically */
1145 int max_height = g->anim_frames_per_line * g->height;
1146 int pos = (src_x / g->width) * max_height + src_y + frame * g->offset_y;
1148 *x = src_x % g->width + pos / max_height * g->width;
1149 *y = pos % max_height;
1151 else /* frames are ordered diagonally */
1153 *x = src_x + frame * g->offset_x;
1154 *y = src_y + frame * g->offset_y;
1158 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
1160 getGraphicSourceExt(graphic, frame, bitmap, x, y, FALSE);
1163 void DrawGraphic(int x, int y, int graphic, int frame)
1166 if (!IN_SCR_FIELD(x, y))
1168 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
1169 printf("DrawGraphic(): This should never happen!\n");
1174 DrawGraphicExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR, graphic,
1177 MarkTileDirty(x, y);
1180 void DrawFixedGraphic(int x, int y, int graphic, int frame)
1183 if (!IN_SCR_FIELD(x, y))
1185 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
1186 printf("DrawGraphic(): This should never happen!\n");
1191 DrawFixedGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic,
1193 MarkTileDirty(x, y);
1196 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
1202 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1204 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX_VAR, TILEY_VAR, x, y);
1207 void DrawFixedGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
1213 getFixedGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1214 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
1217 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
1220 if (!IN_SCR_FIELD(x, y))
1222 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
1223 printf("DrawGraphicThruMask(): This should never happen!\n");
1228 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR,
1231 MarkTileDirty(x, y);
1234 void DrawFixedGraphicThruMask(int x, int y, int graphic, int frame)
1237 if (!IN_SCR_FIELD(x, y))
1239 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
1240 printf("DrawGraphicThruMask(): This should never happen!\n");
1245 DrawFixedGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
1247 MarkTileDirty(x, y);
1250 void DrawGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y, int graphic,
1256 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1258 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1259 dst_x - src_x, dst_y - src_y);
1261 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX_VAR, TILEY_VAR,
1265 void DrawFixedGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y,
1266 int graphic, int frame)
1271 getFixedGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1273 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1274 dst_x - src_x, dst_y - src_y);
1275 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dst_x, dst_y);
1278 void DrawSizedGraphic(int x, int y, int graphic, int frame, int tilesize)
1280 DrawSizedGraphicExt(drawto, SX + x * tilesize, SY + y * tilesize, graphic,
1282 MarkTileDirty(x / tilesize, y / tilesize);
1285 void DrawSizedGraphicExt(DrawBuffer *d, int x, int y, int graphic, int frame,
1291 getSizedGraphicSource(graphic, frame, tilesize, &src_bitmap, &src_x, &src_y);
1292 BlitBitmap(src_bitmap, d, src_x, src_y, tilesize, tilesize, x, y);
1295 void DrawMiniGraphic(int x, int y, int graphic)
1297 DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
1298 MarkTileDirty(x / 2, y / 2);
1301 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
1306 getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1307 BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
1310 inline static void DrawGraphicShiftedNormal(int x, int y, int dx, int dy,
1311 int graphic, int frame,
1312 int cut_mode, int mask_mode)
1317 int width = TILEX, height = TILEY;
1320 if (dx || dy) /* shifted graphic */
1322 if (x < BX1) /* object enters playfield from the left */
1329 else if (x > BX2) /* object enters playfield from the right */
1335 else if (x==BX1 && dx < 0) /* object leaves playfield to the left */
1341 else if (x==BX2 && dx > 0) /* object leaves playfield to the right */
1343 else if (dx) /* general horizontal movement */
1344 MarkTileDirty(x + SIGN(dx), y);
1346 if (y < BY1) /* object enters playfield from the top */
1348 if (cut_mode==CUT_BELOW) /* object completely above top border */
1356 else if (y > BY2) /* object enters playfield from the bottom */
1362 else if (y==BY1 && dy < 0) /* object leaves playfield to the top */
1368 else if (dy > 0 && cut_mode == CUT_ABOVE)
1370 if (y == BY2) /* object completely above bottom border */
1376 MarkTileDirty(x, y + 1);
1377 } /* object leaves playfield to the bottom */
1378 else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
1380 else if (dy) /* general vertical movement */
1381 MarkTileDirty(x, y + SIGN(dy));
1385 if (!IN_SCR_FIELD(x, y))
1387 printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
1388 printf("DrawGraphicShifted(): This should never happen!\n");
1393 width = width * TILESIZE_VAR / TILESIZE;
1394 height = height * TILESIZE_VAR / TILESIZE;
1395 cx = cx * TILESIZE_VAR / TILESIZE;
1396 cy = cy * TILESIZE_VAR / TILESIZE;
1397 dx = dx * TILESIZE_VAR / TILESIZE;
1398 dy = dy * TILESIZE_VAR / TILESIZE;
1400 if (width > 0 && height > 0)
1402 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1407 dst_x = FX + x * TILEX_VAR + dx;
1408 dst_y = FY + y * TILEY_VAR + dy;
1410 if (mask_mode == USE_MASKING)
1412 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1413 dst_x - src_x, dst_y - src_y);
1414 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1418 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1421 MarkTileDirty(x, y);
1425 inline static void DrawGraphicShiftedDouble(int x, int y, int dx, int dy,
1426 int graphic, int frame,
1427 int cut_mode, int mask_mode)
1432 int width = TILEX_VAR, height = TILEY_VAR;
1435 int x2 = x + SIGN(dx);
1436 int y2 = y + SIGN(dy);
1438 /* movement with two-tile animations must be sync'ed with movement position,
1439 not with current GfxFrame (which can be higher when using slow movement) */
1440 int anim_pos = (dx ? ABS(dx) : ABS(dy));
1441 int anim_frames = graphic_info[graphic].anim_frames;
1443 /* (we also need anim_delay here for movement animations with less frames) */
1444 int anim_delay = graphic_info[graphic].anim_delay;
1445 int sync_frame = anim_pos * anim_frames * anim_delay / TILESIZE;
1447 boolean draw_start_tile = (cut_mode != CUT_ABOVE); /* only for falling! */
1448 boolean draw_end_tile = (cut_mode != CUT_BELOW); /* only for falling! */
1450 /* re-calculate animation frame for two-tile movement animation */
1451 frame = getGraphicAnimationFrame(graphic, sync_frame);
1453 /* check if movement start graphic inside screen area and should be drawn */
1454 if (draw_start_tile && IN_SCR_FIELD(x1, y1))
1456 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, TRUE);
1458 dst_x = FX + x1 * TILEX_VAR;
1459 dst_y = FY + y1 * TILEY_VAR;
1461 if (mask_mode == USE_MASKING)
1463 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1464 dst_x - src_x, dst_y - src_y);
1465 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1469 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1472 MarkTileDirty(x1, y1);
1475 /* check if movement end graphic inside screen area and should be drawn */
1476 if (draw_end_tile && IN_SCR_FIELD(x2, y2))
1478 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
1480 dst_x = FX + x2 * TILEX_VAR;
1481 dst_y = FY + y2 * TILEY_VAR;
1483 if (mask_mode == USE_MASKING)
1485 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1486 dst_x - src_x, dst_y - src_y);
1487 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1491 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1494 MarkTileDirty(x2, y2);
1498 static void DrawGraphicShifted(int x, int y, int dx, int dy,
1499 int graphic, int frame,
1500 int cut_mode, int mask_mode)
1504 DrawGraphic(x, y, graphic, frame);
1509 if (graphic_info[graphic].double_movement) /* EM style movement images */
1510 DrawGraphicShiftedDouble(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1512 DrawGraphicShiftedNormal(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1515 void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
1516 int frame, int cut_mode)
1518 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, USE_MASKING);
1521 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
1522 int cut_mode, int mask_mode)
1524 int lx = LEVELX(x), ly = LEVELY(y);
1528 if (IN_LEV_FIELD(lx, ly))
1530 SetRandomAnimationValue(lx, ly);
1532 graphic = el_act_dir2img(element, GfxAction[lx][ly], GfxDir[lx][ly]);
1533 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1535 /* do not use double (EM style) movement graphic when not moving */
1536 if (graphic_info[graphic].double_movement && !dx && !dy)
1538 graphic = el_act_dir2img(element, ACTION_DEFAULT, GfxDir[lx][ly]);
1539 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1542 else /* border element */
1544 graphic = el2img(element);
1545 frame = getGraphicAnimationFrame(graphic, -1);
1548 if (element == EL_EXPANDABLE_WALL)
1550 boolean left_stopped = FALSE, right_stopped = FALSE;
1552 if (!IN_LEV_FIELD(lx - 1, ly) || IS_WALL(Feld[lx - 1][ly]))
1553 left_stopped = TRUE;
1554 if (!IN_LEV_FIELD(lx + 1, ly) || IS_WALL(Feld[lx + 1][ly]))
1555 right_stopped = TRUE;
1557 if (left_stopped && right_stopped)
1559 else if (left_stopped)
1561 graphic = IMG_EXPANDABLE_WALL_GROWING_RIGHT;
1562 frame = graphic_info[graphic].anim_frames - 1;
1564 else if (right_stopped)
1566 graphic = IMG_EXPANDABLE_WALL_GROWING_LEFT;
1567 frame = graphic_info[graphic].anim_frames - 1;
1572 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
1573 else if (mask_mode == USE_MASKING)
1574 DrawGraphicThruMask(x, y, graphic, frame);
1576 DrawGraphic(x, y, graphic, frame);
1579 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
1580 int cut_mode, int mask_mode)
1582 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1583 DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
1584 cut_mode, mask_mode);
1587 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
1590 DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1593 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
1596 DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1599 void DrawLevelElementThruMask(int x, int y, int element)
1601 DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1604 void DrawLevelFieldThruMask(int x, int y)
1606 DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
1609 /* !!! implementation of quicksand is totally broken !!! */
1610 #define IS_CRUMBLED_TILE(x, y, e) \
1611 (GFX_CRUMBLED(e) && (!IN_LEV_FIELD(x, y) || \
1612 !IS_MOVING(x, y) || \
1613 (e) == EL_QUICKSAND_EMPTYING || \
1614 (e) == EL_QUICKSAND_FAST_EMPTYING))
1616 static void DrawLevelFieldCrumbledInnerCorners(int x, int y, int dx, int dy,
1621 int width, height, cx, cy;
1622 int sx = SCREENX(x), sy = SCREENY(y);
1623 int crumbled_border_size = graphic_info[graphic].border_size;
1626 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1628 for (i = 1; i < 4; i++)
1630 int dxx = (i & 1 ? dx : 0);
1631 int dyy = (i & 2 ? dy : 0);
1634 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1637 /* check if neighbour field is of same crumble type */
1638 boolean same = (IS_CRUMBLED_TILE(xx, yy, element) &&
1639 graphic_info[graphic].class ==
1640 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class);
1642 /* return if check prevents inner corner */
1643 if (same == (dxx == dx && dyy == dy))
1647 /* if we reach this point, we have an inner corner */
1649 getGraphicSource(graphic, 1, &src_bitmap, &src_x, &src_y);
1651 width = crumbled_border_size * TILESIZE_VAR / TILESIZE;
1652 height = crumbled_border_size * TILESIZE_VAR / TILESIZE;
1653 cx = (dx > 0 ? TILESIZE_VAR - width : 0);
1654 cy = (dy > 0 ? TILESIZE_VAR - height : 0);
1656 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1657 width, height, FX + sx * TILEX_VAR + cx, FY + sy * TILEY_VAR + cy);
1660 static void DrawLevelFieldCrumbledBorders(int x, int y, int graphic, int frame,
1665 int width, height, bx, by, cx, cy;
1666 int sx = SCREENX(x), sy = SCREENY(y);
1667 int crumbled_border_size = graphic_info[graphic].border_size;
1668 int crumbled_border_size_var = crumbled_border_size * TILESIZE_VAR / TILESIZE;
1669 int crumbled_border_pos_var = TILESIZE_VAR - crumbled_border_size_var;
1672 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1674 /* draw simple, sloppy, non-corner-accurate crumbled border */
1676 width = (dir == 1 || dir == 2 ? crumbled_border_size_var : TILESIZE_VAR);
1677 height = (dir == 0 || dir == 3 ? crumbled_border_size_var : TILESIZE_VAR);
1678 cx = (dir == 2 ? crumbled_border_pos_var : 0);
1679 cy = (dir == 3 ? crumbled_border_pos_var : 0);
1681 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy, width, height,
1682 FX + sx * TILEX_VAR + cx,
1683 FY + sy * TILEY_VAR + cy);
1685 /* (remaining middle border part must be at least as big as corner part) */
1686 if (!(graphic_info[graphic].style & STYLE_ACCURATE_BORDERS) ||
1687 crumbled_border_size >= TILESIZE / 3)
1690 /* correct corners of crumbled border, if needed */
1692 for (i = -1; i <= 1; i += 2)
1694 int xx = x + (dir == 0 || dir == 3 ? i : 0);
1695 int yy = y + (dir == 1 || dir == 2 ? i : 0);
1696 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1699 /* check if neighbour field is of same crumble type */
1700 if (IS_CRUMBLED_TILE(xx, yy, element) &&
1701 graphic_info[graphic].class ==
1702 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
1704 /* no crumbled corner, but continued crumbled border */
1706 int c1 = (dir == 2 || dir == 3 ? crumbled_border_pos_var : 0);
1707 int c2 = (i == 1 ? crumbled_border_pos_var : 0);
1708 int b1 = (i == 1 ? crumbled_border_size_var :
1709 TILESIZE_VAR - 2 * crumbled_border_size_var);
1711 width = crumbled_border_size_var;
1712 height = crumbled_border_size_var;
1714 if (dir == 1 || dir == 2)
1729 BlitBitmap(src_bitmap, drawto_field, src_x + bx, src_y + by,
1731 FX + sx * TILEX_VAR + cx,
1732 FY + sy * TILEY_VAR + cy);
1737 static void DrawLevelFieldCrumbledExt(int x, int y, int graphic, int frame)
1739 int sx = SCREENX(x), sy = SCREENY(y);
1742 static int xy[4][2] =
1750 if (!IN_LEV_FIELD(x, y))
1753 element = TILE_GFX_ELEMENT(x, y);
1755 /* crumble field itself */
1756 if (IS_CRUMBLED_TILE(x, y, element))
1758 if (!IN_SCR_FIELD(sx, sy))
1761 for (i = 0; i < 4; i++)
1763 int xx = x + xy[i][0];
1764 int yy = y + xy[i][1];
1766 element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1769 /* check if neighbour field is of same crumble type */
1770 if (IS_CRUMBLED_TILE(xx, yy, element) &&
1771 graphic_info[graphic].class ==
1772 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
1775 DrawLevelFieldCrumbledBorders(x, y, graphic, frame, i);
1778 if ((graphic_info[graphic].style & STYLE_INNER_CORNERS) &&
1779 graphic_info[graphic].anim_frames == 2)
1781 for (i = 0; i < 4; i++)
1783 int dx = (i & 1 ? +1 : -1);
1784 int dy = (i & 2 ? +1 : -1);
1786 DrawLevelFieldCrumbledInnerCorners(x, y, dx, dy, graphic);
1790 MarkTileDirty(sx, sy);
1792 else /* center field not crumbled -- crumble neighbour fields */
1794 for (i = 0; i < 4; i++)
1796 int xx = x + xy[i][0];
1797 int yy = y + xy[i][1];
1798 int sxx = sx + xy[i][0];
1799 int syy = sy + xy[i][1];
1801 if (!IN_LEV_FIELD(xx, yy) ||
1802 !IN_SCR_FIELD(sxx, syy))
1805 if (Feld[xx][yy] == EL_ELEMENT_SNAPPING)
1808 element = TILE_GFX_ELEMENT(xx, yy);
1810 if (!IS_CRUMBLED_TILE(xx, yy, element))
1813 graphic = el_act2crm(element, ACTION_DEFAULT);
1815 DrawLevelFieldCrumbledBorders(xx, yy, graphic, 0, 3 - i);
1817 MarkTileDirty(sxx, syy);
1822 void DrawLevelFieldCrumbled(int x, int y)
1826 if (!IN_LEV_FIELD(x, y))
1829 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
1830 GfxElement[x][y] != EL_UNDEFINED &&
1831 GFX_CRUMBLED(GfxElement[x][y]))
1833 DrawLevelFieldCrumbledDigging(x, y, GfxDir[x][y], GfxFrame[x][y]);
1838 graphic = el_act2crm(TILE_GFX_ELEMENT(x, y), ACTION_DEFAULT);
1840 DrawLevelFieldCrumbledExt(x, y, graphic, 0);
1843 void DrawLevelFieldCrumbledDigging(int x, int y, int direction,
1846 int graphic1 = el_act_dir2img(GfxElement[x][y], ACTION_DIGGING, direction);
1847 int graphic2 = el_act_dir2crm(GfxElement[x][y], ACTION_DIGGING, direction);
1848 int frame1 = getGraphicAnimationFrame(graphic1, step_frame);
1849 int frame2 = getGraphicAnimationFrame(graphic2, step_frame);
1850 int sx = SCREENX(x), sy = SCREENY(y);
1852 DrawGraphic(sx, sy, graphic1, frame1);
1853 DrawLevelFieldCrumbledExt(x, y, graphic2, frame2);
1856 void DrawLevelFieldCrumbledNeighbours(int x, int y)
1858 int sx = SCREENX(x), sy = SCREENY(y);
1859 static int xy[4][2] =
1868 for (i = 0; i < 4; i++)
1870 int xx = x + xy[i][0];
1871 int yy = y + xy[i][1];
1872 int sxx = sx + xy[i][0];
1873 int syy = sy + xy[i][1];
1875 if (!IN_LEV_FIELD(xx, yy) ||
1876 !IN_SCR_FIELD(sxx, syy) ||
1877 !GFX_CRUMBLED(Feld[xx][yy]) ||
1881 DrawLevelField(xx, yy);
1885 static int getBorderElement(int x, int y)
1889 { EL_STEELWALL_TOPLEFT, EL_INVISIBLE_STEELWALL_TOPLEFT },
1890 { EL_STEELWALL_TOPRIGHT, EL_INVISIBLE_STEELWALL_TOPRIGHT },
1891 { EL_STEELWALL_BOTTOMLEFT, EL_INVISIBLE_STEELWALL_BOTTOMLEFT },
1892 { EL_STEELWALL_BOTTOMRIGHT, EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
1893 { EL_STEELWALL_VERTICAL, EL_INVISIBLE_STEELWALL_VERTICAL },
1894 { EL_STEELWALL_HORIZONTAL, EL_INVISIBLE_STEELWALL_HORIZONTAL },
1895 { EL_STEELWALL, EL_INVISIBLE_STEELWALL }
1897 int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
1898 int steel_position = (x == -1 && y == -1 ? 0 :
1899 x == lev_fieldx && y == -1 ? 1 :
1900 x == -1 && y == lev_fieldy ? 2 :
1901 x == lev_fieldx && y == lev_fieldy ? 3 :
1902 x == -1 || x == lev_fieldx ? 4 :
1903 y == -1 || y == lev_fieldy ? 5 : 6);
1905 return border[steel_position][steel_type];
1908 void DrawScreenElement(int x, int y, int element)
1910 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
1911 DrawLevelFieldCrumbled(LEVELX(x), LEVELY(y));
1914 void DrawLevelElement(int x, int y, int element)
1916 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1917 DrawScreenElement(SCREENX(x), SCREENY(y), element);
1920 void DrawScreenField(int x, int y)
1922 int lx = LEVELX(x), ly = LEVELY(y);
1923 int element, content;
1925 if (!IN_LEV_FIELD(lx, ly))
1927 if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
1930 element = getBorderElement(lx, ly);
1932 DrawScreenElement(x, y, element);
1937 element = Feld[lx][ly];
1938 content = Store[lx][ly];
1940 if (IS_MOVING(lx, ly))
1942 int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
1943 boolean cut_mode = NO_CUTTING;
1945 if (element == EL_QUICKSAND_EMPTYING ||
1946 element == EL_QUICKSAND_FAST_EMPTYING ||
1947 element == EL_MAGIC_WALL_EMPTYING ||
1948 element == EL_BD_MAGIC_WALL_EMPTYING ||
1949 element == EL_DC_MAGIC_WALL_EMPTYING ||
1950 element == EL_AMOEBA_DROPPING)
1951 cut_mode = CUT_ABOVE;
1952 else if (element == EL_QUICKSAND_FILLING ||
1953 element == EL_QUICKSAND_FAST_FILLING ||
1954 element == EL_MAGIC_WALL_FILLING ||
1955 element == EL_BD_MAGIC_WALL_FILLING ||
1956 element == EL_DC_MAGIC_WALL_FILLING)
1957 cut_mode = CUT_BELOW;
1959 if (cut_mode == CUT_ABOVE)
1960 DrawScreenElement(x, y, element);
1962 DrawScreenElement(x, y, EL_EMPTY);
1965 DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
1966 else if (cut_mode == NO_CUTTING)
1967 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
1970 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
1972 if (cut_mode == CUT_BELOW &&
1973 IN_LEV_FIELD(lx, ly + 1) && IN_SCR_FIELD(x, y + 1))
1974 DrawLevelElement(lx, ly + 1, element);
1977 if (content == EL_ACID)
1979 int dir = MovDir[lx][ly];
1980 int newlx = lx + (dir == MV_LEFT ? -1 : dir == MV_RIGHT ? +1 : 0);
1981 int newly = ly + (dir == MV_UP ? -1 : dir == MV_DOWN ? +1 : 0);
1983 DrawLevelElementThruMask(newlx, newly, EL_ACID);
1986 else if (IS_BLOCKED(lx, ly))
1991 boolean cut_mode = NO_CUTTING;
1992 int element_old, content_old;
1994 Blocked2Moving(lx, ly, &oldx, &oldy);
1997 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
1998 MovDir[oldx][oldy] == MV_RIGHT);
2000 element_old = Feld[oldx][oldy];
2001 content_old = Store[oldx][oldy];
2003 if (element_old == EL_QUICKSAND_EMPTYING ||
2004 element_old == EL_QUICKSAND_FAST_EMPTYING ||
2005 element_old == EL_MAGIC_WALL_EMPTYING ||
2006 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
2007 element_old == EL_DC_MAGIC_WALL_EMPTYING ||
2008 element_old == EL_AMOEBA_DROPPING)
2009 cut_mode = CUT_ABOVE;
2011 DrawScreenElement(x, y, EL_EMPTY);
2014 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
2016 else if (cut_mode == NO_CUTTING)
2017 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
2020 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
2023 else if (IS_DRAWABLE(element))
2024 DrawScreenElement(x, y, element);
2026 DrawScreenElement(x, y, EL_EMPTY);
2029 void DrawLevelField(int x, int y)
2031 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
2032 DrawScreenField(SCREENX(x), SCREENY(y));
2033 else if (IS_MOVING(x, y))
2037 Moving2Blocked(x, y, &newx, &newy);
2038 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
2039 DrawScreenField(SCREENX(newx), SCREENY(newy));
2041 else if (IS_BLOCKED(x, y))
2045 Blocked2Moving(x, y, &oldx, &oldy);
2046 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
2047 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
2051 void DrawMiniElement(int x, int y, int element)
2055 graphic = el2edimg(element);
2056 DrawMiniGraphic(x, y, graphic);
2059 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
2061 int x = sx + scroll_x, y = sy + scroll_y;
2063 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
2064 DrawMiniElement(sx, sy, EL_EMPTY);
2065 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
2066 DrawMiniElement(sx, sy, Feld[x][y]);
2068 DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
2071 void DrawEnvelopeBackgroundTiles(int graphic, int startx, int starty,
2072 int x, int y, int xsize, int ysize,
2073 int tile_width, int tile_height)
2077 int dst_x = startx + x * tile_width;
2078 int dst_y = starty + y * tile_height;
2079 int width = graphic_info[graphic].width;
2080 int height = graphic_info[graphic].height;
2081 int inner_width_raw = MAX(width - 2 * tile_width, tile_width);
2082 int inner_height_raw = MAX(height - 2 * tile_height, tile_height);
2083 int inner_width = inner_width_raw - (inner_width_raw % tile_width);
2084 int inner_height = inner_height_raw - (inner_height_raw % tile_height);
2085 int inner_sx = (width >= 3 * tile_width ? tile_width : 0);
2086 int inner_sy = (height >= 3 * tile_height ? tile_height : 0);
2087 boolean draw_masked = graphic_info[graphic].draw_masked;
2089 getFixedGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
2091 if (src_bitmap == NULL || width < tile_width || height < tile_height)
2093 ClearRectangle(drawto, dst_x, dst_y, tile_width, tile_height);
2097 src_x += (x == 0 ? 0 : x == xsize - 1 ? width - tile_width :
2098 inner_sx + (x - 1) * tile_width % inner_width);
2099 src_y += (y == 0 ? 0 : y == ysize - 1 ? height - tile_height :
2100 inner_sy + (y - 1) * tile_height % inner_height);
2104 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
2105 dst_x - src_x, dst_y - src_y);
2106 BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, tile_width, tile_height,
2110 BlitBitmap(src_bitmap, drawto, src_x, src_y, tile_width, tile_height,
2114 void DrawEnvelopeBackground(int graphic, int startx, int starty,
2115 int x, int y, int xsize, int ysize, int font_nr)
2117 int font_width = getFontWidth(font_nr);
2118 int font_height = getFontHeight(font_nr);
2120 DrawEnvelopeBackgroundTiles(graphic, startx, starty, x, y, xsize, ysize,
2121 font_width, font_height);
2124 void AnimateEnvelope(int envelope_nr, int anim_mode, int action)
2126 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2127 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
2128 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
2129 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2130 boolean no_delay = (tape.warp_forward);
2131 unsigned int anim_delay = 0;
2132 int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
2133 int anim_delay_value = (no_delay ? 0 : frame_delay_value);
2134 int font_nr = FONT_ENVELOPE_1 + envelope_nr;
2135 int font_width = getFontWidth(font_nr);
2136 int font_height = getFontHeight(font_nr);
2137 int max_xsize = level.envelope[envelope_nr].xsize;
2138 int max_ysize = level.envelope[envelope_nr].ysize;
2139 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
2140 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
2141 int xend = max_xsize;
2142 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
2143 int xstep = (xstart < xend ? 1 : 0);
2144 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
2147 for (x = xstart, y = ystart; x <= xend && y <= yend; x += xstep, y += ystep)
2149 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
2150 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
2151 int sx = SX + (SXSIZE - xsize * font_width) / 2;
2152 int sy = SY + (SYSIZE - ysize * font_height) / 2;
2155 SetDrawtoField(DRAW_BUFFERED);
2157 BlitScreenToBitmap(backbuffer);
2159 SetDrawtoField(DRAW_BACKBUFFER);
2161 for (yy = 0; yy < ysize; yy++)
2162 for (xx = 0; xx < xsize; xx++)
2163 DrawEnvelopeBackground(graphic, sx, sy, xx, yy, xsize, ysize, font_nr);
2165 DrawTextBuffer(sx + font_width, sy + font_height,
2166 level.envelope[envelope_nr].text, font_nr, max_xsize,
2167 xsize - 2, ysize - 2, 0, mask_mode,
2168 level.envelope[envelope_nr].autowrap,
2169 level.envelope[envelope_nr].centered, FALSE);
2171 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
2174 WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
2178 void ShowEnvelope(int envelope_nr)
2180 int element = EL_ENVELOPE_1 + envelope_nr;
2181 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2182 int sound_opening = element_info[element].sound[ACTION_OPENING];
2183 int sound_closing = element_info[element].sound[ACTION_CLOSING];
2184 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2185 boolean no_delay = (tape.warp_forward);
2186 int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
2187 int wait_delay_value = (no_delay ? 0 : normal_delay_value);
2188 int anim_mode = graphic_info[graphic].anim_mode;
2189 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
2190 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
2192 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
2194 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
2196 if (anim_mode == ANIM_DEFAULT)
2197 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_OPENING);
2199 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_OPENING);
2202 Delay(wait_delay_value);
2204 WaitForEventToContinue();
2206 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
2208 if (anim_mode != ANIM_NONE)
2209 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_CLOSING);
2211 if (anim_mode == ANIM_DEFAULT)
2212 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_CLOSING);
2214 game.envelope_active = FALSE;
2216 SetDrawtoField(DRAW_BUFFERED);
2218 redraw_mask |= REDRAW_FIELD;
2222 static void setRequestPosition(int *x, int *y, boolean add_border_size)
2224 int border_size = request.border_size;
2225 int sx_center = (request.x != -1 ? request.x : SX + SXSIZE / 2);
2226 int sy_center = (request.y != -1 ? request.y : SY + SYSIZE / 2);
2227 int sx = sx_center - request.width / 2;
2228 int sy = sy_center - request.height / 2;
2230 if (add_border_size)
2240 void DrawEnvelopeRequest(char *text)
2242 char *text_final = text;
2243 char *text_door_style = NULL;
2244 int graphic = IMG_BACKGROUND_REQUEST;
2245 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
2246 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
2247 int font_nr = FONT_REQUEST;
2248 int font_width = getFontWidth(font_nr);
2249 int font_height = getFontHeight(font_nr);
2250 int border_size = request.border_size;
2251 int line_spacing = request.line_spacing;
2252 int line_height = font_height + line_spacing;
2253 int text_width = request.width - 2 * border_size;
2254 int text_height = request.height - 2 * border_size;
2255 int line_length = text_width / font_width;
2256 int max_lines = text_height / line_height;
2257 int width = request.width;
2258 int height = request.height;
2259 int tile_size = request.step_offset;
2260 int x_steps = width / tile_size;
2261 int y_steps = height / tile_size;
2265 if (request.wrap_single_words)
2267 char *src_text_ptr, *dst_text_ptr;
2269 text_door_style = checked_malloc(2 * strlen(text) + 1);
2271 src_text_ptr = text;
2272 dst_text_ptr = text_door_style;
2274 while (*src_text_ptr)
2276 if (*src_text_ptr == ' ' ||
2277 *src_text_ptr == '?' ||
2278 *src_text_ptr == '!')
2279 *dst_text_ptr++ = '\n';
2281 if (*src_text_ptr != ' ')
2282 *dst_text_ptr++ = *src_text_ptr;
2287 *dst_text_ptr = '\0';
2289 text_final = text_door_style;
2292 setRequestPosition(&sx, &sy, FALSE);
2294 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
2296 for (y = 0; y < y_steps; y++)
2297 for (x = 0; x < x_steps; x++)
2298 DrawEnvelopeBackgroundTiles(graphic, sx, sy,
2299 x, y, x_steps, y_steps,
2300 tile_size, tile_size);
2302 DrawTextBuffer(sx + border_size, sy + border_size, text_final, font_nr,
2303 line_length, -1, max_lines, line_spacing, mask_mode,
2304 request.autowrap, request.centered, FALSE);
2306 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
2307 RedrawGadget(tool_gadget[i]);
2309 // store readily prepared envelope request for later use when animating
2310 BlitBitmap(backbuffer, bitmap_db_cross, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2312 if (text_door_style)
2313 free(text_door_style);
2316 void AnimateEnvelopeRequest(int anim_mode, int action)
2318 int graphic = IMG_BACKGROUND_REQUEST;
2319 boolean draw_masked = graphic_info[graphic].draw_masked;
2320 int delay_value_normal = request.step_delay;
2321 int delay_value_fast = delay_value_normal / 2;
2322 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2323 boolean no_delay = (tape.warp_forward);
2324 int delay_value = (ffwd_delay ? delay_value_fast : delay_value_normal);
2325 int anim_delay_value = (no_delay ? 0 : delay_value + 500 * 0);
2326 unsigned int anim_delay = 0;
2328 int width = request.width;
2329 int height = request.height;
2330 int tile_size = request.step_offset;
2331 int max_xsize = width / tile_size;
2332 int max_ysize = height / tile_size;
2333 int max_xsize_inner = max_xsize - 2;
2334 int max_ysize_inner = max_ysize - 2;
2336 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize_inner : 0);
2337 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize_inner : 0);
2338 int xend = max_xsize_inner;
2339 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize_inner : 0);
2340 int xstep = (xstart < xend ? 1 : 0);
2341 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
2344 if (setup.quick_doors)
2351 if (action == ACTION_OPENING)
2352 PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
2353 else if (action == ACTION_CLOSING)
2354 PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
2357 for (x = xstart, y = ystart; x <= xend && y <= yend; x += xstep, y += ystep)
2359 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
2360 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
2361 int sx_center = (request.x != -1 ? request.x : SX + SXSIZE / 2);
2362 int sy_center = (request.y != -1 ? request.y : SY + SYSIZE / 2);
2363 int src_x = sx_center - width / 2;
2364 int src_y = sy_center - height / 2;
2365 int dst_x = sx_center - xsize * tile_size / 2;
2366 int dst_y = sy_center - ysize * tile_size / 2;
2367 int xsize_size_left = (xsize - 1) * tile_size;
2368 int ysize_size_top = (ysize - 1) * tile_size;
2369 int max_xsize_pos = (max_xsize - 1) * tile_size;
2370 int max_ysize_pos = (max_ysize - 1) * tile_size;
2373 BlitBitmap(bitmap_db_store, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2375 for (yy = 0; yy < 2; yy++)
2377 for (xx = 0; xx < 2; xx++)
2379 int src_xx = src_x + xx * max_xsize_pos;
2380 int src_yy = src_y + yy * max_ysize_pos;
2381 int dst_xx = dst_x + xx * xsize_size_left;
2382 int dst_yy = dst_y + yy * ysize_size_top;
2383 int xx_size = (xx ? tile_size : xsize_size_left);
2384 int yy_size = (yy ? tile_size : ysize_size_top);
2387 BlitBitmapMasked(bitmap_db_cross, backbuffer,
2388 src_xx, src_yy, xx_size, yy_size, dst_xx, dst_yy);
2390 BlitBitmap(bitmap_db_cross, backbuffer,
2391 src_xx, src_yy, xx_size, yy_size, dst_xx, dst_yy);
2395 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
2400 WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
2405 void ShowEnvelopeRequest(char *text, unsigned int req_state, int action)
2407 int last_game_status = game_status; /* save current game status */
2408 int graphic = IMG_BACKGROUND_REQUEST;
2409 int sound_opening = SND_REQUEST_OPENING;
2410 int sound_closing = SND_REQUEST_CLOSING;
2411 int anim_mode = graphic_info[graphic].anim_mode;
2412 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
2413 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
2415 if (game_status == GAME_MODE_PLAYING)
2416 BlitScreenToBitmap(backbuffer);
2418 SetDrawtoField(DRAW_BACKBUFFER);
2420 // SetDrawBackgroundMask(REDRAW_NONE);
2422 if (action == ACTION_OPENING)
2424 BlitBitmap(backbuffer, bitmap_db_store, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2426 if (req_state & REQ_ASK)
2428 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
2429 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
2431 else if (req_state & REQ_CONFIRM)
2433 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
2435 else if (req_state & REQ_PLAYER)
2437 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
2438 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
2439 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
2440 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
2443 DrawEnvelopeRequest(text);
2445 if (game_status != GAME_MODE_MAIN)
2449 /* force DOOR font inside door area */
2450 game_status = GAME_MODE_PSEUDO_DOOR;
2452 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
2454 if (action == ACTION_OPENING)
2456 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
2458 if (anim_mode == ANIM_DEFAULT)
2459 AnimateEnvelopeRequest(ANIM_DEFAULT, ACTION_OPENING);
2461 AnimateEnvelopeRequest(main_anim_mode, ACTION_OPENING);
2466 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
2468 if (anim_mode != ANIM_NONE)
2469 AnimateEnvelopeRequest(main_anim_mode, ACTION_CLOSING);
2471 if (anim_mode == ANIM_DEFAULT)
2472 AnimateEnvelopeRequest(ANIM_DEFAULT, ACTION_CLOSING);
2475 game.envelope_active = FALSE;
2477 game_status = last_game_status; /* restore current game status */
2479 if (action == ACTION_CLOSING)
2481 if (game_status != GAME_MODE_MAIN)
2484 BlitBitmap(bitmap_db_store, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2487 // SetDrawBackgroundMask(last_draw_background_mask);
2489 redraw_mask |= REDRAW_FIELD;
2491 if (game_status == GAME_MODE_MAIN)
2496 if (action == ACTION_CLOSING &&
2497 game_status == GAME_MODE_PLAYING &&
2498 level.game_engine_type == GAME_ENGINE_TYPE_RND)
2499 SetDrawtoField(DRAW_BUFFERED);
2502 void DrawPreviewElement(int dst_x, int dst_y, int element, int tilesize)
2506 int graphic = el2preimg(element);
2508 getSizedGraphicSource(graphic, 0, tilesize, &src_bitmap, &src_x, &src_y);
2509 BlitBitmap(src_bitmap, drawto, src_x, src_y, tilesize, tilesize, dst_x,dst_y);
2512 void DrawLevel(int draw_background_mask)
2516 SetMainBackgroundImage(IMG_BACKGROUND_PLAYING);
2517 SetDrawBackgroundMask(draw_background_mask);
2521 for (x = BX1; x <= BX2; x++)
2522 for (y = BY1; y <= BY2; y++)
2523 DrawScreenField(x, y);
2525 redraw_mask |= REDRAW_FIELD;
2528 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
2532 for (x = 0; x < size_x; x++)
2533 for (y = 0; y < size_y; y++)
2534 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
2536 redraw_mask |= REDRAW_FIELD;
2539 static void DrawPreviewLevelPlayfieldExt(int from_x, int from_y)
2541 boolean show_level_border = (BorderElement != EL_EMPTY);
2542 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
2543 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
2544 int tile_size = preview.tile_size;
2545 int preview_width = preview.xsize * tile_size;
2546 int preview_height = preview.ysize * tile_size;
2547 int real_preview_xsize = MIN(level_xsize, preview.xsize);
2548 int real_preview_ysize = MIN(level_ysize, preview.ysize);
2549 int real_preview_width = real_preview_xsize * tile_size;
2550 int real_preview_height = real_preview_ysize * tile_size;
2551 int dst_x = SX + ALIGNED_XPOS(preview.x, preview_width, preview.align);
2552 int dst_y = SY + ALIGNED_YPOS(preview.y, preview_height, preview.valign);
2555 if (!IN_GFX_FIELD_FULL(dst_x, dst_y + preview_height - 1))
2558 DrawBackground(dst_x, dst_y, preview_width, preview_height);
2560 dst_x += (preview_width - real_preview_width) / 2;
2561 dst_y += (preview_height - real_preview_height) / 2;
2563 for (x = 0; x < real_preview_xsize; x++)
2565 for (y = 0; y < real_preview_ysize; y++)
2567 int lx = from_x + x + (show_level_border ? -1 : 0);
2568 int ly = from_y + y + (show_level_border ? -1 : 0);
2569 int element = (IN_LEV_FIELD(lx, ly) ? level.field[lx][ly] :
2570 getBorderElement(lx, ly));
2572 DrawPreviewElement(dst_x + x * tile_size, dst_y + y * tile_size,
2573 element, tile_size);
2577 redraw_mask |= REDRAW_MICROLEVEL;
2580 #define MICROLABEL_EMPTY 0
2581 #define MICROLABEL_LEVEL_NAME 1
2582 #define MICROLABEL_LEVEL_AUTHOR_HEAD 2
2583 #define MICROLABEL_LEVEL_AUTHOR 3
2584 #define MICROLABEL_IMPORTED_FROM_HEAD 4
2585 #define MICROLABEL_IMPORTED_FROM 5
2586 #define MICROLABEL_IMPORTED_BY_HEAD 6
2587 #define MICROLABEL_IMPORTED_BY 7
2589 static int getMaxTextLength(struct TextPosInfo *pos, int font_nr)
2591 int max_text_width = SXSIZE;
2592 int font_width = getFontWidth(font_nr);
2594 if (pos->align == ALIGN_CENTER)
2595 max_text_width = (pos->x < SXSIZE / 2 ? pos->x * 2 : (SXSIZE - pos->x) * 2);
2596 else if (pos->align == ALIGN_RIGHT)
2597 max_text_width = pos->x;
2599 max_text_width = SXSIZE - pos->x;
2601 return max_text_width / font_width;
2604 static void DrawPreviewLevelLabelExt(int mode)
2606 struct TextPosInfo *pos = &menu.main.text.level_info_2;
2607 char label_text[MAX_OUTPUT_LINESIZE + 1];
2608 int max_len_label_text;
2609 int font_nr = pos->font;
2612 if (!IN_GFX_FIELD_FULL(pos->x, pos->y + getFontHeight(pos->font)))
2615 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
2616 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
2617 mode == MICROLABEL_IMPORTED_BY_HEAD)
2618 font_nr = pos->font_alt;
2620 max_len_label_text = getMaxTextLength(pos, font_nr);
2622 if (pos->size != -1)
2623 max_len_label_text = pos->size;
2625 for (i = 0; i < max_len_label_text; i++)
2626 label_text[i] = ' ';
2627 label_text[max_len_label_text] = '\0';
2629 if (strlen(label_text) > 0)
2630 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2633 (mode == MICROLABEL_LEVEL_NAME ? level.name :
2634 mode == MICROLABEL_LEVEL_AUTHOR_HEAD ? "created by" :
2635 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
2636 mode == MICROLABEL_IMPORTED_FROM_HEAD ? "imported from" :
2637 mode == MICROLABEL_IMPORTED_FROM ? leveldir_current->imported_from :
2638 mode == MICROLABEL_IMPORTED_BY_HEAD ? "imported by" :
2639 mode == MICROLABEL_IMPORTED_BY ? leveldir_current->imported_by :""),
2640 max_len_label_text);
2641 label_text[max_len_label_text] = '\0';
2643 if (strlen(label_text) > 0)
2644 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2646 redraw_mask |= REDRAW_MICROLEVEL;
2649 static void DrawPreviewLevelExt(boolean restart)
2651 static unsigned int scroll_delay = 0;
2652 static unsigned int label_delay = 0;
2653 static int from_x, from_y, scroll_direction;
2654 static int label_state, label_counter;
2655 unsigned int scroll_delay_value = preview.step_delay;
2656 boolean show_level_border = (BorderElement != EL_EMPTY);
2657 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
2658 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
2659 int last_game_status = game_status; /* save current game status */
2666 if (preview.anim_mode == ANIM_CENTERED)
2668 if (level_xsize > preview.xsize)
2669 from_x = (level_xsize - preview.xsize) / 2;
2670 if (level_ysize > preview.ysize)
2671 from_y = (level_ysize - preview.ysize) / 2;
2674 from_x += preview.xoffset;
2675 from_y += preview.yoffset;
2677 scroll_direction = MV_RIGHT;
2681 DrawPreviewLevelPlayfieldExt(from_x, from_y);
2682 DrawPreviewLevelLabelExt(label_state);
2684 /* initialize delay counters */
2685 DelayReached(&scroll_delay, 0);
2686 DelayReached(&label_delay, 0);
2688 if (leveldir_current->name)
2690 struct TextPosInfo *pos = &menu.main.text.level_info_1;
2691 char label_text[MAX_OUTPUT_LINESIZE + 1];
2692 int font_nr = pos->font;
2693 int max_len_label_text = getMaxTextLength(pos, font_nr);
2695 if (pos->size != -1)
2696 max_len_label_text = pos->size;
2698 strncpy(label_text, leveldir_current->name, max_len_label_text);
2699 label_text[max_len_label_text] = '\0';
2701 if (IN_GFX_FIELD_FULL(pos->x, pos->y + getFontHeight(pos->font)))
2702 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2705 game_status = last_game_status; /* restore current game status */
2710 /* scroll preview level, if needed */
2711 if (preview.anim_mode != ANIM_NONE &&
2712 (level_xsize > preview.xsize || level_ysize > preview.ysize) &&
2713 DelayReached(&scroll_delay, scroll_delay_value))
2715 switch (scroll_direction)
2720 from_x -= preview.step_offset;
2721 from_x = (from_x < 0 ? 0 : from_x);
2724 scroll_direction = MV_UP;
2728 if (from_x < level_xsize - preview.xsize)
2730 from_x += preview.step_offset;
2731 from_x = (from_x > level_xsize - preview.xsize ?
2732 level_xsize - preview.xsize : from_x);
2735 scroll_direction = MV_DOWN;
2741 from_y -= preview.step_offset;
2742 from_y = (from_y < 0 ? 0 : from_y);
2745 scroll_direction = MV_RIGHT;
2749 if (from_y < level_ysize - preview.ysize)
2751 from_y += preview.step_offset;
2752 from_y = (from_y > level_ysize - preview.ysize ?
2753 level_ysize - preview.ysize : from_y);
2756 scroll_direction = MV_LEFT;
2763 DrawPreviewLevelPlayfieldExt(from_x, from_y);
2766 /* !!! THIS ALL SUCKS -- SHOULD BE CLEANLY REWRITTEN !!! */
2767 /* redraw micro level label, if needed */
2768 if (!strEqual(level.name, NAMELESS_LEVEL_NAME) &&
2769 !strEqual(level.author, ANONYMOUS_NAME) &&
2770 !strEqual(level.author, leveldir_current->name) &&
2771 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
2773 int max_label_counter = 23;
2775 if (leveldir_current->imported_from != NULL &&
2776 strlen(leveldir_current->imported_from) > 0)
2777 max_label_counter += 14;
2778 if (leveldir_current->imported_by != NULL &&
2779 strlen(leveldir_current->imported_by) > 0)
2780 max_label_counter += 14;
2782 label_counter = (label_counter + 1) % max_label_counter;
2783 label_state = (label_counter >= 0 && label_counter <= 7 ?
2784 MICROLABEL_LEVEL_NAME :
2785 label_counter >= 9 && label_counter <= 12 ?
2786 MICROLABEL_LEVEL_AUTHOR_HEAD :
2787 label_counter >= 14 && label_counter <= 21 ?
2788 MICROLABEL_LEVEL_AUTHOR :
2789 label_counter >= 23 && label_counter <= 26 ?
2790 MICROLABEL_IMPORTED_FROM_HEAD :
2791 label_counter >= 28 && label_counter <= 35 ?
2792 MICROLABEL_IMPORTED_FROM :
2793 label_counter >= 37 && label_counter <= 40 ?
2794 MICROLABEL_IMPORTED_BY_HEAD :
2795 label_counter >= 42 && label_counter <= 49 ?
2796 MICROLABEL_IMPORTED_BY : MICROLABEL_EMPTY);
2798 if (leveldir_current->imported_from == NULL &&
2799 (label_state == MICROLABEL_IMPORTED_FROM_HEAD ||
2800 label_state == MICROLABEL_IMPORTED_FROM))
2801 label_state = (label_state == MICROLABEL_IMPORTED_FROM_HEAD ?
2802 MICROLABEL_IMPORTED_BY_HEAD : MICROLABEL_IMPORTED_BY);
2804 DrawPreviewLevelLabelExt(label_state);
2807 game_status = last_game_status; /* restore current game status */
2810 void DrawPreviewLevelInitial()
2812 DrawPreviewLevelExt(TRUE);
2815 void DrawPreviewLevelAnimation()
2817 DrawPreviewLevelExt(FALSE);
2820 inline void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
2821 int graphic, int sync_frame, int mask_mode)
2823 int frame = getGraphicAnimationFrame(graphic, sync_frame);
2825 if (mask_mode == USE_MASKING)
2826 DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
2828 DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
2831 inline void DrawFixedGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
2832 int graphic, int sync_frame,
2835 int frame = getGraphicAnimationFrame(graphic, sync_frame);
2837 if (mask_mode == USE_MASKING)
2838 DrawFixedGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
2840 DrawFixedGraphicExt(dst_bitmap, x, y, graphic, frame);
2843 inline void DrawGraphicAnimation(int x, int y, int graphic)
2845 int lx = LEVELX(x), ly = LEVELY(y);
2847 if (!IN_SCR_FIELD(x, y))
2850 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR,
2851 graphic, GfxFrame[lx][ly], NO_MASKING);
2853 MarkTileDirty(x, y);
2856 inline void DrawFixedGraphicAnimation(int x, int y, int graphic)
2858 int lx = LEVELX(x), ly = LEVELY(y);
2860 if (!IN_SCR_FIELD(x, y))
2863 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
2864 graphic, GfxFrame[lx][ly], NO_MASKING);
2865 MarkTileDirty(x, y);
2868 void DrawLevelGraphicAnimation(int x, int y, int graphic)
2870 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
2873 void DrawLevelElementAnimation(int x, int y, int element)
2875 int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
2877 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
2880 inline void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
2882 int sx = SCREENX(x), sy = SCREENY(y);
2884 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
2887 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
2890 DrawGraphicAnimation(sx, sy, graphic);
2893 if (GFX_CRUMBLED(TILE_GFX_ELEMENT(x, y)))
2894 DrawLevelFieldCrumbled(x, y);
2896 if (GFX_CRUMBLED(Feld[x][y]))
2897 DrawLevelFieldCrumbled(x, y);
2901 void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
2903 int sx = SCREENX(x), sy = SCREENY(y);
2906 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
2909 graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
2911 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
2914 DrawGraphicAnimation(sx, sy, graphic);
2916 if (GFX_CRUMBLED(element))
2917 DrawLevelFieldCrumbled(x, y);
2920 static int getPlayerGraphic(struct PlayerInfo *player, int move_dir)
2922 if (player->use_murphy)
2924 /* this works only because currently only one player can be "murphy" ... */
2925 static int last_horizontal_dir = MV_LEFT;
2926 int graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir);
2928 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
2929 last_horizontal_dir = move_dir;
2931 if (graphic == IMG_SP_MURPHY) /* undefined => use special graphic */
2933 int direction = (player->is_snapping ? move_dir : last_horizontal_dir);
2935 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
2941 return el_act_dir2img(player->artwork_element, player->GfxAction,move_dir);
2944 static boolean equalGraphics(int graphic1, int graphic2)
2946 struct GraphicInfo *g1 = &graphic_info[graphic1];
2947 struct GraphicInfo *g2 = &graphic_info[graphic2];
2949 return (g1->bitmap == g2->bitmap &&
2950 g1->src_x == g2->src_x &&
2951 g1->src_y == g2->src_y &&
2952 g1->anim_frames == g2->anim_frames &&
2953 g1->anim_delay == g2->anim_delay &&
2954 g1->anim_mode == g2->anim_mode);
2957 void DrawAllPlayers()
2961 for (i = 0; i < MAX_PLAYERS; i++)
2962 if (stored_player[i].active)
2963 DrawPlayer(&stored_player[i]);
2966 void DrawPlayerField(int x, int y)
2968 if (!IS_PLAYER(x, y))
2971 DrawPlayer(PLAYERINFO(x, y));
2974 #define DRAW_PLAYER_OVER_PUSHED_ELEMENT 1
2976 void DrawPlayer(struct PlayerInfo *player)
2978 int jx = player->jx;
2979 int jy = player->jy;
2980 int move_dir = player->MovDir;
2981 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? +1 : 0);
2982 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? +1 : 0);
2983 int last_jx = (player->is_moving ? jx - dx : jx);
2984 int last_jy = (player->is_moving ? jy - dy : jy);
2985 int next_jx = jx + dx;
2986 int next_jy = jy + dy;
2987 boolean player_is_moving = (player->MovPos ? TRUE : FALSE);
2988 boolean player_is_opaque = FALSE;
2989 int sx = SCREENX(jx), sy = SCREENY(jy);
2990 int sxx = 0, syy = 0;
2991 int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
2993 int action = ACTION_DEFAULT;
2994 int last_player_graphic = getPlayerGraphic(player, move_dir);
2995 int last_player_frame = player->Frame;
2998 /* GfxElement[][] is set to the element the player is digging or collecting;
2999 remove also for off-screen player if the player is not moving anymore */
3000 if (IN_LEV_FIELD(jx, jy) && !player_is_moving)
3001 GfxElement[jx][jy] = EL_UNDEFINED;
3003 if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
3007 if (!IN_LEV_FIELD(jx, jy))
3009 printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
3010 printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
3011 printf("DrawPlayerField(): This should never happen!\n");
3016 if (element == EL_EXPLOSION)
3019 action = (player->is_pushing ? ACTION_PUSHING :
3020 player->is_digging ? ACTION_DIGGING :
3021 player->is_collecting ? ACTION_COLLECTING :
3022 player->is_moving ? ACTION_MOVING :
3023 player->is_snapping ? ACTION_SNAPPING :
3024 player->is_dropping ? ACTION_DROPPING :
3025 player->is_waiting ? player->action_waiting : ACTION_DEFAULT);
3027 if (player->is_waiting)
3028 move_dir = player->dir_waiting;
3030 InitPlayerGfxAnimation(player, action, move_dir);
3032 /* ----------------------------------------------------------------------- */
3033 /* draw things in the field the player is leaving, if needed */
3034 /* ----------------------------------------------------------------------- */
3036 if (player->is_moving)
3038 if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
3040 DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
3042 if (last_element == EL_DYNAMITE_ACTIVE ||
3043 last_element == EL_EM_DYNAMITE_ACTIVE ||
3044 last_element == EL_SP_DISK_RED_ACTIVE)
3045 DrawDynamite(last_jx, last_jy);
3047 DrawLevelFieldThruMask(last_jx, last_jy);
3049 else if (last_element == EL_DYNAMITE_ACTIVE ||
3050 last_element == EL_EM_DYNAMITE_ACTIVE ||
3051 last_element == EL_SP_DISK_RED_ACTIVE)
3052 DrawDynamite(last_jx, last_jy);
3054 /* !!! this is not enough to prevent flickering of players which are
3055 moving next to each others without a free tile between them -- this
3056 can only be solved by drawing all players layer by layer (first the
3057 background, then the foreground etc.) !!! => TODO */
3058 else if (!IS_PLAYER(last_jx, last_jy))
3059 DrawLevelField(last_jx, last_jy);
3062 DrawLevelField(last_jx, last_jy);
3065 if (player->is_pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
3066 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
3069 if (!IN_SCR_FIELD(sx, sy))
3072 /* ----------------------------------------------------------------------- */
3073 /* draw things behind the player, if needed */
3074 /* ----------------------------------------------------------------------- */
3077 DrawLevelElement(jx, jy, Back[jx][jy]);
3078 else if (IS_ACTIVE_BOMB(element))
3079 DrawLevelElement(jx, jy, EL_EMPTY);
3082 if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
3084 int old_element = GfxElement[jx][jy];
3085 int old_graphic = el_act_dir2img(old_element, action, move_dir);
3086 int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
3088 if (GFX_CRUMBLED(old_element))
3089 DrawLevelFieldCrumbledDigging(jx, jy, move_dir, player->StepFrame);
3091 DrawGraphic(sx, sy, old_graphic, frame);
3093 if (graphic_info[old_graphic].anim_mode & ANIM_OPAQUE_PLAYER)
3094 player_is_opaque = TRUE;
3098 GfxElement[jx][jy] = EL_UNDEFINED;
3100 /* make sure that pushed elements are drawn with correct frame rate */
3101 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
3103 if (player->is_pushing && player->is_moving && !IS_ANIM_MODE_CE(graphic))
3104 GfxFrame[jx][jy] = player->StepFrame;
3106 DrawLevelField(jx, jy);
3110 #if !DRAW_PLAYER_OVER_PUSHED_ELEMENT
3111 /* ----------------------------------------------------------------------- */
3112 /* draw player himself */
3113 /* ----------------------------------------------------------------------- */
3115 graphic = getPlayerGraphic(player, move_dir);
3117 /* in the case of changed player action or direction, prevent the current
3118 animation frame from being restarted for identical animations */
3119 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
3120 player->Frame = last_player_frame;
3122 frame = getGraphicAnimationFrame(graphic, player->Frame);
3126 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3127 sxx = player->GfxPos;
3129 syy = player->GfxPos;
3132 if (!setup.soft_scrolling && ScreenMovPos)
3135 if (player_is_opaque)
3136 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
3138 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3140 if (SHIELD_ON(player))
3142 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
3143 IMG_SHIELD_NORMAL_ACTIVE);
3144 int frame = getGraphicAnimationFrame(graphic, -1);
3146 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3150 #if DRAW_PLAYER_OVER_PUSHED_ELEMENT
3153 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3154 sxx = player->GfxPos;
3156 syy = player->GfxPos;
3160 /* ----------------------------------------------------------------------- */
3161 /* draw things the player is pushing, if needed */
3162 /* ----------------------------------------------------------------------- */
3164 if (player->is_pushing && player->is_moving)
3166 int px = SCREENX(jx), py = SCREENY(jy);
3167 int pxx = (TILEX - ABS(sxx)) * dx;
3168 int pyy = (TILEY - ABS(syy)) * dy;
3169 int gfx_frame = GfxFrame[jx][jy];
3175 if (!IS_MOVING(jx, jy)) /* push movement already finished */
3177 element = Feld[next_jx][next_jy];
3178 gfx_frame = GfxFrame[next_jx][next_jy];
3181 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
3183 sync_frame = (IS_ANIM_MODE_CE(graphic) ? gfx_frame : player->StepFrame);
3184 frame = getGraphicAnimationFrame(graphic, sync_frame);
3186 /* draw background element under pushed element (like the Sokoban field) */
3187 if (game.use_masked_pushing && IS_MOVING(jx, jy))
3189 /* this allows transparent pushing animation over non-black background */
3192 DrawLevelElement(jx, jy, Back[jx][jy]);
3194 DrawLevelElement(jx, jy, EL_EMPTY);
3196 if (Back[next_jx][next_jy])
3197 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
3199 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
3201 else if (Back[next_jx][next_jy])
3202 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
3205 /* do not draw (EM style) pushing animation when pushing is finished */
3206 /* (two-tile animations usually do not contain start and end frame) */
3207 if (graphic_info[graphic].double_movement && !IS_MOVING(jx, jy))
3208 DrawLevelElement(next_jx, next_jy, Feld[next_jx][next_jy]);
3210 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
3212 /* masked drawing is needed for EMC style (double) movement graphics */
3213 /* !!! (ONLY WHEN DRAWING PUSHED ELEMENT OVER THE PLAYER) !!! */
3214 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
3218 #if DRAW_PLAYER_OVER_PUSHED_ELEMENT
3219 /* ----------------------------------------------------------------------- */
3220 /* draw player himself */
3221 /* ----------------------------------------------------------------------- */
3223 graphic = getPlayerGraphic(player, move_dir);
3225 /* in the case of changed player action or direction, prevent the current
3226 animation frame from being restarted for identical animations */
3227 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
3228 player->Frame = last_player_frame;
3230 frame = getGraphicAnimationFrame(graphic, player->Frame);
3234 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3235 sxx = player->GfxPos;
3237 syy = player->GfxPos;
3240 if (!setup.soft_scrolling && ScreenMovPos)
3243 if (player_is_opaque)
3244 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
3246 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3248 if (SHIELD_ON(player))
3250 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
3251 IMG_SHIELD_NORMAL_ACTIVE);
3252 int frame = getGraphicAnimationFrame(graphic, -1);
3254 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3258 /* ----------------------------------------------------------------------- */
3259 /* draw things in front of player (active dynamite or dynabombs) */
3260 /* ----------------------------------------------------------------------- */
3262 if (IS_ACTIVE_BOMB(element))
3264 graphic = el2img(element);
3265 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
3267 if (game.emulation == EMU_SUPAPLEX)
3268 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
3270 DrawGraphicThruMask(sx, sy, graphic, frame);
3273 if (player_is_moving && last_element == EL_EXPLOSION)
3275 int element = (GfxElement[last_jx][last_jy] != EL_UNDEFINED ?
3276 GfxElement[last_jx][last_jy] : EL_EMPTY);
3277 int graphic = el_act2img(element, ACTION_EXPLODING);
3278 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
3279 int phase = ExplodePhase[last_jx][last_jy] - 1;
3280 int frame = getGraphicAnimationFrame(graphic, phase - delay);
3283 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
3286 /* ----------------------------------------------------------------------- */
3287 /* draw elements the player is just walking/passing through/under */
3288 /* ----------------------------------------------------------------------- */
3290 if (player_is_moving)
3292 /* handle the field the player is leaving ... */
3293 if (IS_ACCESSIBLE_INSIDE(last_element))
3294 DrawLevelField(last_jx, last_jy);
3295 else if (IS_ACCESSIBLE_UNDER(last_element))
3296 DrawLevelFieldThruMask(last_jx, last_jy);
3299 /* do not redraw accessible elements if the player is just pushing them */
3300 if (!player_is_moving || !player->is_pushing)
3302 /* ... and the field the player is entering */
3303 if (IS_ACCESSIBLE_INSIDE(element))
3304 DrawLevelField(jx, jy);
3305 else if (IS_ACCESSIBLE_UNDER(element))
3306 DrawLevelFieldThruMask(jx, jy);
3309 MarkTileDirty(sx, sy);
3312 /* ------------------------------------------------------------------------- */
3314 void WaitForEventToContinue()
3316 boolean still_wait = TRUE;
3318 /* simulate releasing mouse button over last gadget, if still pressed */
3320 HandleGadgets(-1, -1, 0);
3322 button_status = MB_RELEASED;
3336 case EVENT_BUTTONPRESS:
3337 case EVENT_KEYPRESS:
3341 case EVENT_KEYRELEASE:
3342 ClearPlayerAction();
3346 HandleOtherEvents(&event);
3350 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
3357 /* don't eat all CPU time */
3362 #define MAX_REQUEST_LINES 13
3363 #define MAX_REQUEST_LINE_FONT1_LEN 7
3364 #define MAX_REQUEST_LINE_FONT2_LEN 10
3366 static int RequestHandleEvents(unsigned int req_state)
3368 int last_game_status = game_status; /* save current game status */
3372 button_status = MB_RELEASED;
3374 request_gadget_id = -1;
3387 case EVENT_BUTTONPRESS:
3388 case EVENT_BUTTONRELEASE:
3389 case EVENT_MOTIONNOTIFY:
3391 if (event.type == EVENT_MOTIONNOTIFY)
3393 if (!PointerInWindow(window))
3394 continue; /* window and pointer are on different screens */
3399 motion_status = TRUE;
3400 mx = ((MotionEvent *) &event)->x;
3401 my = ((MotionEvent *) &event)->y;
3405 motion_status = FALSE;
3406 mx = ((ButtonEvent *) &event)->x;
3407 my = ((ButtonEvent *) &event)->y;
3408 if (event.type == EVENT_BUTTONPRESS)
3409 button_status = ((ButtonEvent *) &event)->button;
3411 button_status = MB_RELEASED;
3414 /* this sets 'request_gadget_id' */
3415 HandleGadgets(mx, my, button_status);
3417 switch (request_gadget_id)
3419 case TOOL_CTRL_ID_YES:
3422 case TOOL_CTRL_ID_NO:
3425 case TOOL_CTRL_ID_CONFIRM:
3426 result = TRUE | FALSE;
3429 case TOOL_CTRL_ID_PLAYER_1:
3432 case TOOL_CTRL_ID_PLAYER_2:
3435 case TOOL_CTRL_ID_PLAYER_3:
3438 case TOOL_CTRL_ID_PLAYER_4:
3449 case EVENT_KEYPRESS:
3450 switch (GetEventKey((KeyEvent *)&event, TRUE))
3453 if (req_state & REQ_CONFIRM)
3458 #if defined(TARGET_SDL2)
3465 #if defined(TARGET_SDL2)
3475 if (req_state & REQ_PLAYER)
3479 case EVENT_KEYRELEASE:
3480 ClearPlayerAction();
3484 HandleOtherEvents(&event);
3488 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
3490 int joy = AnyJoystick();
3492 if (joy & JOY_BUTTON_1)
3494 else if (joy & JOY_BUTTON_2)
3498 if (game_status == GAME_MODE_PLAYING && local_player->LevelSolved_GameEnd)
3500 HandleGameActions();
3506 if (!PendingEvent()) /* delay only if no pending events */
3510 game_status = GAME_MODE_PSEUDO_DOOR;
3514 game_status = last_game_status; /* restore current game status */
3520 static boolean RequestDoor(char *text, unsigned int req_state)
3522 unsigned int old_door_state;
3523 int last_game_status = game_status; /* save current game status */
3524 int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
3525 int font_nr = FONT_TEXT_2;
3530 if (maxWordLengthInString(text) > MAX_REQUEST_LINE_FONT1_LEN)
3532 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
3533 font_nr = FONT_TEXT_1;
3536 if (game_status == GAME_MODE_PLAYING)
3537 BlitScreenToBitmap(backbuffer);
3539 /* disable deactivated drawing when quick-loading level tape recording */
3540 if (tape.playing && tape.deactivate_display)
3541 TapeDeactivateDisplayOff(TRUE);
3543 SetMouseCursor(CURSOR_DEFAULT);
3545 #if defined(NETWORK_AVALIABLE)
3546 /* pause network game while waiting for request to answer */
3547 if (options.network &&
3548 game_status == GAME_MODE_PLAYING &&
3549 req_state & REQUEST_WAIT_FOR_INPUT)
3550 SendToServer_PausePlaying();
3553 old_door_state = GetDoorState();
3555 /* simulate releasing mouse button over last gadget, if still pressed */
3557 HandleGadgets(-1, -1, 0);
3561 /* draw released gadget before proceeding */
3564 if (old_door_state & DOOR_OPEN_1)
3566 CloseDoor(DOOR_CLOSE_1);
3568 /* save old door content */
3569 BlitBitmap(bitmap_db_door_1, bitmap_db_door_1,
3570 0 * DXSIZE, 0, DXSIZE, DYSIZE, 1 * DXSIZE, 0);
3573 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
3574 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3576 /* clear door drawing field */
3577 DrawBackground(DX, DY, DXSIZE, DYSIZE);
3579 /* force DOOR font inside door area */
3580 game_status = GAME_MODE_PSEUDO_DOOR;
3582 /* write text for request */
3583 for (text_ptr = text, ty = 0; ty < MAX_REQUEST_LINES; ty++)
3585 char text_line[max_request_line_len + 1];
3591 for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
3593 tc = *(text_ptr + tx);
3594 // if (!tc || tc == ' ')
3595 if (!tc || tc == ' ' || tc == '?' || tc == '!')
3599 if ((tc == '?' || tc == '!') && tl == 0)
3609 strncpy(text_line, text_ptr, tl);
3612 DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
3613 DY + 8 + ty * (getFontHeight(font_nr) + 2),
3614 text_line, font_nr);
3616 text_ptr += tl + (tc == ' ' ? 1 : 0);
3617 // text_ptr += tl + (tc == ' ' || tc == '?' || tc == '!' ? 1 : 0);
3620 game_status = last_game_status; /* restore current game status */
3622 if (req_state & REQ_ASK)
3624 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
3625 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
3627 else if (req_state & REQ_CONFIRM)
3629 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
3631 else if (req_state & REQ_PLAYER)
3633 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
3634 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
3635 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
3636 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
3639 /* copy request gadgets to door backbuffer */
3640 BlitBitmap(drawto, bitmap_db_door_1, DX, DY, DXSIZE, DYSIZE, 0, 0);
3642 OpenDoor(DOOR_OPEN_1);
3644 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
3646 if (game_status == GAME_MODE_PLAYING)
3648 SetPanelBackground();
3649 SetDrawBackgroundMask(REDRAW_DOOR_1);
3653 SetDrawBackgroundMask(REDRAW_FIELD);
3659 if (game_status != GAME_MODE_MAIN)
3662 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3664 // ---------- handle request buttons ----------
3665 result = RequestHandleEvents(req_state);
3667 if (game_status != GAME_MODE_MAIN)
3672 if (!(req_state & REQ_STAY_OPEN))
3674 CloseDoor(DOOR_CLOSE_1);
3676 if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
3677 (req_state & REQ_REOPEN))
3678 OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
3683 if (game_status == GAME_MODE_PLAYING)
3685 SetPanelBackground();
3686 SetDrawBackgroundMask(REDRAW_DOOR_1);
3690 SetDrawBackgroundMask(REDRAW_FIELD);
3693 #if defined(NETWORK_AVALIABLE)
3694 /* continue network game after request */
3695 if (options.network &&
3696 game_status == GAME_MODE_PLAYING &&
3697 req_state & REQUEST_WAIT_FOR_INPUT)
3698 SendToServer_ContinuePlaying();
3701 /* restore deactivated drawing when quick-loading level tape recording */
3702 if (tape.playing && tape.deactivate_display)
3703 TapeDeactivateDisplayOn();
3708 static boolean RequestEnvelope(char *text, unsigned int req_state)
3712 if (game_status == GAME_MODE_PLAYING)
3713 BlitScreenToBitmap(backbuffer);
3715 /* disable deactivated drawing when quick-loading level tape recording */
3716 if (tape.playing && tape.deactivate_display)
3717 TapeDeactivateDisplayOff(TRUE);
3719 SetMouseCursor(CURSOR_DEFAULT);
3721 #if defined(NETWORK_AVALIABLE)
3722 /* pause network game while waiting for request to answer */
3723 if (options.network &&
3724 game_status == GAME_MODE_PLAYING &&
3725 req_state & REQUEST_WAIT_FOR_INPUT)
3726 SendToServer_PausePlaying();
3729 /* simulate releasing mouse button over last gadget, if still pressed */
3731 HandleGadgets(-1, -1, 0);
3735 // (replace with setting corresponding request background)
3736 // SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
3737 // SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3739 /* clear door drawing field */
3740 // DrawBackground(DX, DY, DXSIZE, DYSIZE);
3742 ShowEnvelopeRequest(text, req_state, ACTION_OPENING);
3744 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
3746 if (game_status == GAME_MODE_PLAYING)
3748 SetPanelBackground();
3749 SetDrawBackgroundMask(REDRAW_DOOR_1);
3753 SetDrawBackgroundMask(REDRAW_FIELD);
3759 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3761 // ---------- handle request buttons ----------
3762 result = RequestHandleEvents(req_state);
3764 if (game_status != GAME_MODE_MAIN)
3769 ShowEnvelopeRequest(text, req_state, ACTION_CLOSING);
3773 if (game_status == GAME_MODE_PLAYING)
3775 SetPanelBackground();
3776 SetDrawBackgroundMask(REDRAW_DOOR_1);
3780 SetDrawBackgroundMask(REDRAW_FIELD);
3783 #if defined(NETWORK_AVALIABLE)
3784 /* continue network game after request */
3785 if (options.network &&
3786 game_status == GAME_MODE_PLAYING &&
3787 req_state & REQUEST_WAIT_FOR_INPUT)
3788 SendToServer_ContinuePlaying();
3791 /* restore deactivated drawing when quick-loading level tape recording */
3792 if (tape.playing && tape.deactivate_display)
3793 TapeDeactivateDisplayOn();
3798 boolean Request(char *text, unsigned int req_state)
3800 if (global.use_envelope_request)
3801 return RequestEnvelope(text, req_state);
3803 return RequestDoor(text, req_state);
3806 static int compareDoorPartOrderInfo(const void *object1, const void *object2)
3808 const struct DoorPartOrderInfo *dpo1 = (struct DoorPartOrderInfo *)object1;
3809 const struct DoorPartOrderInfo *dpo2 = (struct DoorPartOrderInfo *)object2;
3812 if (dpo1->sort_priority != dpo2->sort_priority)
3813 compare_result = dpo1->sort_priority - dpo2->sort_priority;
3815 compare_result = dpo1->nr - dpo2->nr;
3817 return compare_result;
3820 void InitGraphicCompatibilityInfo_Doors()
3826 struct DoorInfo *door;
3830 { DOOR_1, IMG_DOOR_1_GFX_PART_1, IMG_DOOR_1_GFX_PART_8, &door_1 },
3831 { DOOR_2, IMG_DOOR_2_GFX_PART_1, IMG_DOOR_2_GFX_PART_8, &door_2 },
3833 { -1, -1, -1, NULL }
3835 struct Rect door_rect_list[] =
3837 { DX, DY, DXSIZE, DYSIZE },
3838 { VX, VY, VXSIZE, VYSIZE }
3842 for (i = 0; doors[i].door_token != -1; i++)
3844 int door_token = doors[i].door_token;
3845 int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
3846 int part_1 = doors[i].part_1;
3847 int part_8 = doors[i].part_8;
3848 int part_2 = part_1 + 1;
3849 int part_3 = part_1 + 2;
3850 struct DoorInfo *door = doors[i].door;
3851 struct Rect *door_rect = &door_rect_list[door_index];
3852 boolean door_gfx_redefined = FALSE;
3854 /* check if any door part graphic definitions have been redefined */
3856 for (j = 0; door_part_controls[j].door_token != -1; j++)
3858 struct DoorPartControlInfo *dpc = &door_part_controls[j];
3859 struct FileInfo *fi = getImageListEntryFromImageID(dpc->graphic);
3861 if (dpc->door_token == door_token && fi->redefined)
3862 door_gfx_redefined = TRUE;
3865 /* check for old-style door graphic/animation modifications */
3867 if (!door_gfx_redefined)
3869 if (door->anim_mode & ANIM_STATIC_PANEL)
3871 door->panel.step_xoffset = 0;
3872 door->panel.step_yoffset = 0;
3875 if (door->anim_mode & (ANIM_HORIZONTAL | ANIM_VERTICAL))
3877 struct GraphicInfo *g_part_1 = &graphic_info[part_1];
3878 struct GraphicInfo *g_part_2 = &graphic_info[part_2];
3879 int num_door_steps, num_panel_steps;
3881 /* remove door part graphics other than the two default wings */
3883 for (j = 0; door_part_controls[j].door_token != -1; j++)
3885 struct DoorPartControlInfo *dpc = &door_part_controls[j];
3886 struct GraphicInfo *g = &graphic_info[dpc->graphic];
3888 if (dpc->graphic >= part_3 &&
3889 dpc->graphic <= part_8)
3893 /* set graphics and screen positions of the default wings */
3895 g_part_1->width = door_rect->width;
3896 g_part_1->height = door_rect->height;
3897 g_part_2->width = door_rect->width;
3898 g_part_2->height = door_rect->height;
3899 g_part_2->src_x = door_rect->width;
3900 g_part_2->src_y = g_part_1->src_y;
3902 door->part_2.x = door->part_1.x;
3903 door->part_2.y = door->part_1.y;
3905 if (door->width != -1)
3907 g_part_1->width = door->width;
3908 g_part_2->width = door->width;
3910 // special treatment for graphics and screen position of right wing
3911 g_part_2->src_x += door_rect->width - door->width;
3912 door->part_2.x += door_rect->width - door->width;
3915 if (door->height != -1)
3917 g_part_1->height = door->height;
3918 g_part_2->height = door->height;
3920 // special treatment for graphics and screen position of bottom wing
3921 g_part_2->src_y += door_rect->height - door->height;
3922 door->part_2.y += door_rect->height - door->height;
3925 /* set animation delays for the default wings and panels */
3927 door->part_1.step_delay = door->step_delay;
3928 door->part_2.step_delay = door->step_delay;
3929 door->panel.step_delay = door->step_delay;
3931 /* set animation draw order for the default wings */
3933 door->part_1.sort_priority = 2; /* draw left wing over ... */
3934 door->part_2.sort_priority = 1; /* ... right wing */
3936 /* set animation draw offset for the default wings */
3938 if (door->anim_mode & ANIM_HORIZONTAL)
3940 door->part_1.step_xoffset = door->step_offset;
3941 door->part_1.step_yoffset = 0;
3942 door->part_2.step_xoffset = door->step_offset * -1;
3943 door->part_2.step_yoffset = 0;
3945 num_door_steps = g_part_1->width / door->step_offset;
3947 else // ANIM_VERTICAL
3949 door->part_1.step_xoffset = 0;
3950 door->part_1.step_yoffset = door->step_offset;
3951 door->part_2.step_xoffset = 0;
3952 door->part_2.step_yoffset = door->step_offset * -1;
3954 num_door_steps = g_part_1->height / door->step_offset;
3957 /* set animation draw offset for the default panels */
3959 if (door->step_offset > 1)
3961 num_panel_steps = 2 * door_rect->height / door->step_offset;
3962 door->panel.start_step = num_panel_steps - num_door_steps;
3966 num_panel_steps = door_rect->height / door->step_offset;
3967 door->panel.start_step = num_panel_steps - num_door_steps / 2;
3968 door->panel.step_delay *= 2;
3979 for (i = 0; door_part_controls[i].door_token != -1; i++)
3981 struct DoorPartControlInfo *dpc = &door_part_controls[i];
3982 struct DoorPartOrderInfo *dpo = &door_part_order[i];
3984 /* initialize "start_step_opening" and "start_step_closing", if needed */
3985 if (dpc->pos->start_step_opening == 0 &&
3986 dpc->pos->start_step_closing == 0)
3988 // dpc->pos->start_step_opening = dpc->pos->start_step;
3989 dpc->pos->start_step_closing = dpc->pos->start_step;
3992 /* fill structure for door part draw order (sorted below) */
3994 dpo->sort_priority = dpc->pos->sort_priority;
3997 /* sort door part controls according to sort_priority and graphic number */
3998 qsort(door_part_order, MAX_DOOR_PARTS,
3999 sizeof(struct DoorPartOrderInfo), compareDoorPartOrderInfo);
4002 unsigned int OpenDoor(unsigned int door_state)
4004 if (door_state & DOOR_COPY_BACK)
4006 if (door_state & DOOR_OPEN_1)
4007 BlitBitmap(bitmap_db_door_1, bitmap_db_door_1,
4008 1 * DXSIZE, 0, DXSIZE, DYSIZE, 0 * DXSIZE, 0);
4010 if (door_state & DOOR_OPEN_2)
4011 BlitBitmap(bitmap_db_door_2, bitmap_db_door_2,
4012 1 * VXSIZE, 0, VXSIZE, VYSIZE, 0 * VXSIZE, 0);
4014 door_state &= ~DOOR_COPY_BACK;
4017 return MoveDoor(door_state);
4020 unsigned int CloseDoor(unsigned int door_state)
4022 unsigned int old_door_state = GetDoorState();
4024 if (!(door_state & DOOR_NO_COPY_BACK))
4026 if (old_door_state & DOOR_OPEN_1)
4027 BlitBitmap(backbuffer, bitmap_db_door_1,
4028 DX, DY, DXSIZE, DYSIZE, 0, 0);
4030 if (old_door_state & DOOR_OPEN_2)
4031 BlitBitmap(backbuffer, bitmap_db_door_2,
4032 VX, VY, VXSIZE, VYSIZE, 0, 0);
4034 door_state &= ~DOOR_NO_COPY_BACK;
4037 return MoveDoor(door_state);
4040 unsigned int GetDoorState()
4042 return MoveDoor(DOOR_GET_STATE);
4045 unsigned int SetDoorState(unsigned int door_state)
4047 return MoveDoor(door_state | DOOR_SET_STATE);
4050 int euclid(int a, int b)
4052 return (b ? euclid(b, a % b) : a);
4055 unsigned int MoveDoor(unsigned int door_state)
4057 struct Rect door_rect_list[] =
4059 { DX, DY, DXSIZE, DYSIZE },
4060 { VX, VY, VXSIZE, VYSIZE }
4062 static int door1 = DOOR_OPEN_1;
4063 static int door2 = DOOR_CLOSE_2;
4064 unsigned int door_delay = 0;
4065 unsigned int door_delay_value;
4068 if (door_1.width < 0 || door_1.width > DXSIZE)
4069 door_1.width = DXSIZE;
4070 if (door_1.height < 0 || door_1.height > DYSIZE)
4071 door_1.height = DYSIZE;
4072 if (door_2.width < 0 || door_2.width > VXSIZE)
4073 door_2.width = VXSIZE;
4074 if (door_2.height < 0 || door_2.height > VYSIZE)
4075 door_2.height = VYSIZE;
4077 if (door_state == DOOR_GET_STATE)
4078 return (door1 | door2);
4080 if (door_state & DOOR_SET_STATE)
4082 if (door_state & DOOR_ACTION_1)
4083 door1 = door_state & DOOR_ACTION_1;
4084 if (door_state & DOOR_ACTION_2)
4085 door2 = door_state & DOOR_ACTION_2;
4087 return (door1 | door2);
4090 if (!(door_state & DOOR_FORCE_REDRAW))
4092 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
4093 door_state &= ~DOOR_OPEN_1;
4094 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
4095 door_state &= ~DOOR_CLOSE_1;
4096 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
4097 door_state &= ~DOOR_OPEN_2;
4098 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
4099 door_state &= ~DOOR_CLOSE_2;
4102 if (global.autoplay_leveldir)
4104 door_state |= DOOR_NO_DELAY;
4105 door_state &= ~DOOR_CLOSE_ALL;
4108 if (game_status == GAME_MODE_EDITOR)
4109 door_state |= DOOR_NO_DELAY;
4111 if (door_state & DOOR_ACTION)
4113 boolean door_panel_drawn[NUM_DOORS];
4114 boolean panel_has_doors[NUM_DOORS];
4115 boolean door_part_skip[MAX_DOOR_PARTS];
4116 boolean door_part_done[MAX_DOOR_PARTS];
4117 boolean door_part_done_all;
4118 int num_steps[MAX_DOOR_PARTS];
4119 int max_move_delay = 0; // delay for complete animations of all doors
4120 int max_step_delay = 0; // delay (ms) between two animation frames
4121 int num_move_steps = 0; // number of animation steps for all doors
4122 int current_move_delay = 0;
4126 for (i = 0; i < NUM_DOORS; i++)
4127 panel_has_doors[i] = FALSE;
4129 for (i = 0; i < MAX_DOOR_PARTS; i++)
4131 struct DoorPartControlInfo *dpc = &door_part_controls[i];
4132 struct GraphicInfo *g = &graphic_info[dpc->graphic];
4133 int door_token = dpc->door_token;
4135 door_part_done[i] = FALSE;
4136 door_part_skip[i] = (!(door_state & door_token) ||
4140 for (i = 0; i < MAX_DOOR_PARTS; i++)
4142 int nr = door_part_order[i].nr;
4143 struct DoorPartControlInfo *dpc = &door_part_controls[nr];
4144 struct DoorPartPosInfo *pos = dpc->pos;
4145 struct GraphicInfo *g = &graphic_info[dpc->graphic];
4146 int door_token = dpc->door_token;
4147 int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
4148 boolean is_panel = DOOR_PART_IS_PANEL(nr);
4149 int step_xoffset = ABS(pos->step_xoffset);
4150 int step_yoffset = ABS(pos->step_yoffset);
4151 int step_delay = pos->step_delay;
4152 int current_door_state = door_state & door_token;
4153 boolean door_opening = ((current_door_state & DOOR_OPEN) != 0);
4154 boolean door_closing = ((current_door_state & DOOR_CLOSE) != 0);
4155 boolean part_opening = (is_panel ? door_closing : door_opening);
4156 int start_step = (part_opening ? pos->start_step_opening :
4157 pos->start_step_closing);
4158 float move_xsize = (step_xoffset ? g->width : 0);
4159 float move_ysize = (step_yoffset ? g->height : 0);
4160 int move_xsteps = (step_xoffset ? ceil(move_xsize / step_xoffset) : 0);
4161 int move_ysteps = (step_yoffset ? ceil(move_ysize / step_yoffset) : 0);
4162 int move_steps = (move_xsteps && move_ysteps ?
4163 MIN(move_xsteps, move_ysteps) :
4164 move_xsteps ? move_xsteps : move_ysteps) - start_step;
4165 int move_delay = move_steps * step_delay;
4167 if (door_part_skip[nr])
4171 panel_has_doors[door_index] = TRUE;
4173 max_move_delay = MAX(max_move_delay, move_delay);
4174 max_step_delay = (max_step_delay == 0 ? step_delay :
4175 euclid(max_step_delay, step_delay));
4176 num_steps[nr] = move_steps;
4179 num_move_steps = max_move_delay / max_step_delay;
4181 door_delay_value = max_step_delay;
4183 if ((door_state & DOOR_NO_DELAY) || setup.quick_doors)
4185 start = num_move_steps - 1;
4189 /* opening door sound has priority over simultaneously closing door */
4190 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
4191 PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
4192 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
4193 PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
4196 for (k = start; k < num_move_steps; k++)
4198 door_part_done_all = TRUE;
4200 for (i = 0; i < NUM_DOORS; i++)
4201 door_panel_drawn[i] = FALSE;
4203 for (i = 0; i < MAX_DOOR_PARTS; i++)
4205 int nr = door_part_order[i].nr;
4206 struct DoorPartControlInfo *dpc = &door_part_controls[nr];
4207 struct DoorPartPosInfo *pos = dpc->pos;
4208 struct GraphicInfo *g = &graphic_info[dpc->graphic];
4209 int door_token = dpc->door_token;
4210 int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
4211 boolean is_panel = DOOR_PART_IS_PANEL(nr);
4212 struct Rect *door_rect = &door_rect_list[door_index];
4213 Bitmap *bitmap_db_door = (door_token == DOOR_1 ? bitmap_db_door_1 :
4215 Bitmap *bitmap = (is_panel ? bitmap_db_door : g->bitmap);
4216 int current_door_state = door_state & door_token;
4217 boolean door_opening = ((current_door_state & DOOR_OPEN) != 0);
4218 boolean door_closing = !door_opening;
4219 boolean part_opening = (is_panel ? door_closing : door_opening);
4220 boolean part_closing = !part_opening;
4221 int start_step = (part_opening ? pos->start_step_opening :
4222 pos->start_step_closing);
4223 int step_delay = pos->step_delay;
4224 int step_factor = step_delay / max_step_delay;
4225 int k1 = (step_factor ? k / step_factor + 1 : k);
4226 int k2 = (part_opening ? k1 + start_step : num_steps[nr] - k1);
4227 int kk = (k2 < 0 ? 0 : k2);
4228 int src_x, src_y, src_xx, src_yy;
4229 int dst_x, dst_y, dst_xx, dst_yy;
4232 if (door_part_skip[nr])
4235 if (!(door_state & door_token))
4243 if (!door_panel_drawn[door_index])
4245 ClearRectangle(drawto, door_rect->x, door_rect->y,
4246 door_rect->width, door_rect->height);
4248 door_panel_drawn[door_index] = TRUE;
4251 // draw opening or closing door parts
4253 if (pos->step_xoffset < 0) // door part on right side
4256 dst_xx = pos->x + ABS(kk * pos->step_xoffset);
4259 if (dst_xx + width > door_rect->width)
4260 width = door_rect->width - dst_xx;
4262 else // door part on left side
4265 dst_xx = pos->x - kk * pos->step_xoffset;
4269 src_xx = ABS(dst_xx);
4273 width = g->width - src_xx;
4275 // printf("::: k == %d [%d] \n", k, start_step);
4278 if (pos->step_yoffset < 0) // door part on bottom side
4281 dst_yy = pos->y + ABS(kk * pos->step_yoffset);
4284 if (dst_yy + height > door_rect->height)
4285 height = door_rect->height - dst_yy;
4287 else // door part on top side
4290 dst_yy = pos->y - kk * pos->step_yoffset;
4294 src_yy = ABS(dst_yy);
4298 height = g->height - src_yy;
4308 src_x = g->src_x + src_xx;
4309 src_y = g->src_y + src_yy;
4312 dst_x = door_rect->x + dst_xx;
4313 dst_y = door_rect->y + dst_yy;
4315 if (width >= 0 && width <= g->width &&
4316 height >= 0 && height <= g->height)
4318 if (is_panel || !pos->draw_masked)
4319 BlitBitmap(bitmap, drawto, src_x, src_y, width, height,
4322 BlitBitmapMasked(bitmap, drawto, src_x, src_y, width, height,
4326 redraw_mask |= REDRAW_DOOR_FROM_TOKEN(door_token);
4328 if ((part_opening && (width < 0 || height < 0)) ||
4329 (part_closing && (width >= g->width && height >= g->height)))
4330 door_part_done[nr] = TRUE;
4332 // continue door part animations, but not panel after door has closed
4333 if (!door_part_done[nr] &&
4334 !(is_panel && door_closing && panel_has_doors[door_index]))
4335 door_part_done_all = FALSE;
4338 if (!(door_state & DOOR_NO_DELAY))
4342 if (game_status == GAME_MODE_MAIN)
4345 WaitUntilDelayReached(&door_delay, door_delay_value);
4347 current_move_delay += max_step_delay;
4350 if (door_part_done_all)
4355 if (door_state & DOOR_ACTION_1)
4356 door1 = door_state & DOOR_ACTION_1;
4357 if (door_state & DOOR_ACTION_2)
4358 door2 = door_state & DOOR_ACTION_2;
4360 return (door1 | door2);
4363 void DrawSpecialEditorDoor()
4365 struct GraphicInfo *gfx1 = &graphic_info[IMG_DOOR_2_TOP_BORDER_CORRECTION];
4366 int top_border_width = gfx1->width;
4367 int top_border_height = gfx1->height;
4368 int outer_border = viewport.door_2[GAME_MODE_EDITOR].border_size;
4369 int ex = EX - outer_border;
4370 int ey = EY - outer_border;
4371 int vy = VY - outer_border;
4372 int exsize = EXSIZE + 2 * outer_border;
4374 CloseDoor(DOOR_CLOSE_2);
4376 /* draw bigger level editor toolbox window */
4377 BlitBitmap(gfx1->bitmap, drawto, gfx1->src_x, gfx1->src_y,
4378 top_border_width, top_border_height, ex, ey - top_border_height);
4379 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto, ex, vy,
4380 exsize, EYSIZE - VYSIZE + outer_border, ex, ey);
4382 redraw_mask |= REDRAW_ALL;
4385 void UndrawSpecialEditorDoor()
4387 struct GraphicInfo *gfx1 = &graphic_info[IMG_DOOR_2_TOP_BORDER_CORRECTION];
4388 int top_border_width = gfx1->width;
4389 int top_border_height = gfx1->height;
4390 int outer_border = viewport.door_2[GAME_MODE_EDITOR].border_size;
4391 int ex = EX - outer_border;
4392 int ey = EY - outer_border;
4393 int ey_top = ey - top_border_height;
4394 int exsize = EXSIZE + 2 * outer_border;
4395 int eysize = EYSIZE + 2 * outer_border;
4397 /* draw normal tape recorder window */
4398 if (graphic_info[IMG_GLOBAL_BORDER].bitmap)
4400 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
4401 ex, ey_top, top_border_width, top_border_height,
4403 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
4404 ex, ey, exsize, eysize, ex, ey);
4408 // if screen background is set to "[NONE]", clear editor toolbox window
4409 ClearRectangle(drawto, ex, ey_top, top_border_width, top_border_height);
4410 ClearRectangle(drawto, ex, ey, exsize, eysize);
4413 redraw_mask |= REDRAW_ALL;
4417 /* ---------- new tool button stuff ---------------------------------------- */
4422 struct TextPosInfo *pos;
4425 } toolbutton_info[NUM_TOOL_BUTTONS] =
4428 IMG_REQUEST_BUTTON_GFX_YES, &request.button.yes,
4429 TOOL_CTRL_ID_YES, "yes"
4432 IMG_REQUEST_BUTTON_GFX_NO, &request.button.no,
4433 TOOL_CTRL_ID_NO, "no"
4436 IMG_REQUEST_BUTTON_GFX_CONFIRM, &request.button.confirm,
4437 TOOL_CTRL_ID_CONFIRM, "confirm"
4440 IMG_REQUEST_BUTTON_GFX_PLAYER_1, &request.button.player_1,
4441 TOOL_CTRL_ID_PLAYER_1, "player 1"
4444 IMG_REQUEST_BUTTON_GFX_PLAYER_2, &request.button.player_2,
4445 TOOL_CTRL_ID_PLAYER_2, "player 2"
4448 IMG_REQUEST_BUTTON_GFX_PLAYER_3, &request.button.player_3,
4449 TOOL_CTRL_ID_PLAYER_3, "player 3"
4452 IMG_REQUEST_BUTTON_GFX_PLAYER_4, &request.button.player_4,
4453 TOOL_CTRL_ID_PLAYER_4, "player 4"
4457 void CreateToolButtons()
4461 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4463 struct GraphicInfo *gfx = &graphic_info[toolbutton_info[i].graphic];
4464 struct TextPosInfo *pos = toolbutton_info[i].pos;
4465 struct GadgetInfo *gi;
4466 Bitmap *deco_bitmap = None;
4467 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
4468 unsigned int event_mask = GD_EVENT_RELEASED;
4471 int gd_x = gfx->src_x;
4472 int gd_y = gfx->src_y;
4473 int gd_xp = gfx->src_x + gfx->pressed_xoffset;
4474 int gd_yp = gfx->src_y + gfx->pressed_yoffset;
4477 if (global.use_envelope_request)
4478 setRequestPosition(&dx, &dy, TRUE);
4480 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
4482 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
4484 getSizedGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr), 0,
4485 pos->size, &deco_bitmap, &deco_x, &deco_y);
4486 deco_xpos = (gfx->width - pos->size) / 2;
4487 deco_ypos = (gfx->height - pos->size) / 2;
4490 gi = CreateGadget(GDI_CUSTOM_ID, id,
4491 GDI_INFO_TEXT, toolbutton_info[i].infotext,
4492 GDI_X, dx + GDI_ACTIVE_POS(pos->x),
4493 GDI_Y, dy + GDI_ACTIVE_POS(pos->y),
4494 GDI_WIDTH, gfx->width,
4495 GDI_HEIGHT, gfx->height,
4496 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
4497 GDI_STATE, GD_BUTTON_UNPRESSED,
4498 GDI_DESIGN_UNPRESSED, gfx->bitmap, gd_x, gd_y,
4499 GDI_DESIGN_PRESSED, gfx->bitmap, gd_xp, gd_yp,
4500 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
4501 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
4502 GDI_DECORATION_SIZE, pos->size, pos->size,
4503 GDI_DECORATION_SHIFTING, 1, 1,
4504 GDI_DIRECT_DRAW, FALSE,
4505 GDI_EVENT_MASK, event_mask,
4506 GDI_CALLBACK_ACTION, HandleToolButtons,
4510 Error(ERR_EXIT, "cannot create gadget");
4512 tool_gadget[id] = gi;
4516 void FreeToolButtons()
4520 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4521 FreeGadget(tool_gadget[i]);
4524 static void UnmapToolButtons()
4528 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4529 UnmapGadget(tool_gadget[i]);
4532 static void HandleToolButtons(struct GadgetInfo *gi)
4534 request_gadget_id = gi->custom_id;
4537 static struct Mapping_EM_to_RND_object
4540 boolean is_rnd_to_em_mapping; /* unique mapping EM <-> RND */
4541 boolean is_backside; /* backside of moving element */
4547 em_object_mapping_list[] =
4550 Xblank, TRUE, FALSE,
4554 Yacid_splash_eB, FALSE, FALSE,
4555 EL_ACID_SPLASH_RIGHT, -1, -1
4558 Yacid_splash_wB, FALSE, FALSE,
4559 EL_ACID_SPLASH_LEFT, -1, -1
4562 #ifdef EM_ENGINE_BAD_ROLL
4564 Xstone_force_e, FALSE, FALSE,
4565 EL_ROCK, -1, MV_BIT_RIGHT
4568 Xstone_force_w, FALSE, FALSE,
4569 EL_ROCK, -1, MV_BIT_LEFT
4572 Xnut_force_e, FALSE, FALSE,
4573 EL_NUT, -1, MV_BIT_RIGHT
4576 Xnut_force_w, FALSE, FALSE,
4577 EL_NUT, -1, MV_BIT_LEFT
4580 Xspring_force_e, FALSE, FALSE,
4581 EL_SPRING, -1, MV_BIT_RIGHT
4584 Xspring_force_w, FALSE, FALSE,
4585 EL_SPRING, -1, MV_BIT_LEFT
4588 Xemerald_force_e, FALSE, FALSE,
4589 EL_EMERALD, -1, MV_BIT_RIGHT
4592 Xemerald_force_w, FALSE, FALSE,
4593 EL_EMERALD, -1, MV_BIT_LEFT
4596 Xdiamond_force_e, FALSE, FALSE,
4597 EL_DIAMOND, -1, MV_BIT_RIGHT
4600 Xdiamond_force_w, FALSE, FALSE,
4601 EL_DIAMOND, -1, MV_BIT_LEFT
4604 Xbomb_force_e, FALSE, FALSE,
4605 EL_BOMB, -1, MV_BIT_RIGHT
4608 Xbomb_force_w, FALSE, FALSE,
4609 EL_BOMB, -1, MV_BIT_LEFT
4611 #endif /* EM_ENGINE_BAD_ROLL */
4614 Xstone, TRUE, FALSE,
4618 Xstone_pause, FALSE, FALSE,
4622 Xstone_fall, FALSE, FALSE,
4626 Ystone_s, FALSE, FALSE,
4627 EL_ROCK, ACTION_FALLING, -1
4630 Ystone_sB, FALSE, TRUE,
4631 EL_ROCK, ACTION_FALLING, -1
4634 Ystone_e, FALSE, FALSE,
4635 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
4638 Ystone_eB, FALSE, TRUE,
4639 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
4642 Ystone_w, FALSE, FALSE,
4643 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
4646 Ystone_wB, FALSE, TRUE,
4647 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
4654 Xnut_pause, FALSE, FALSE,
4658 Xnut_fall, FALSE, FALSE,
4662 Ynut_s, FALSE, FALSE,
4663 EL_NUT, ACTION_FALLING, -1
4666 Ynut_sB, FALSE, TRUE,
4667 EL_NUT, ACTION_FALLING, -1
4670 Ynut_e, FALSE, FALSE,
4671 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
4674 Ynut_eB, FALSE, TRUE,
4675 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
4678 Ynut_w, FALSE, FALSE,
4679 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
4682 Ynut_wB, FALSE, TRUE,
4683 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
4686 Xbug_n, TRUE, FALSE,
4690 Xbug_e, TRUE, FALSE,
4691 EL_BUG_RIGHT, -1, -1
4694 Xbug_s, TRUE, FALSE,
4698 Xbug_w, TRUE, FALSE,
4702 Xbug_gon, FALSE, FALSE,
4706 Xbug_goe, FALSE, FALSE,
4707 EL_BUG_RIGHT, -1, -1
4710 Xbug_gos, FALSE, FALSE,
4714 Xbug_gow, FALSE, FALSE,
4718 Ybug_n, FALSE, FALSE,
4719 EL_BUG, ACTION_MOVING, MV_BIT_UP
4722 Ybug_nB, FALSE, TRUE,
4723 EL_BUG, ACTION_MOVING, MV_BIT_UP
4726 Ybug_e, FALSE, FALSE,
4727 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
4730 Ybug_eB, FALSE, TRUE,
4731 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
4734 Ybug_s, FALSE, FALSE,
4735 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
4738 Ybug_sB, FALSE, TRUE,
4739 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
4742 Ybug_w, FALSE, FALSE,
4743 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
4746 Ybug_wB, FALSE, TRUE,
4747 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
4750 Ybug_w_n, FALSE, FALSE,
4751 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
4754 Ybug_n_e, FALSE, FALSE,
4755 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
4758 Ybug_e_s, FALSE, FALSE,
4759 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
4762 Ybug_s_w, FALSE, FALSE,
4763 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
4766 Ybug_e_n, FALSE, FALSE,
4767 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
4770 Ybug_s_e, FALSE, FALSE,
4771 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
4774 Ybug_w_s, FALSE, FALSE,
4775 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
4778 Ybug_n_w, FALSE, FALSE,
4779 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
4782 Ybug_stone, FALSE, FALSE,
4783 EL_BUG, ACTION_SMASHED_BY_ROCK, -1
4786 Ybug_spring, FALSE, FALSE,
4787 EL_BUG, ACTION_SMASHED_BY_SPRING, -1
4790 Xtank_n, TRUE, FALSE,
4791 EL_SPACESHIP_UP, -1, -1
4794 Xtank_e, TRUE, FALSE,
4795 EL_SPACESHIP_RIGHT, -1, -1
4798 Xtank_s, TRUE, FALSE,
4799 EL_SPACESHIP_DOWN, -1, -1
4802 Xtank_w, TRUE, FALSE,
4803 EL_SPACESHIP_LEFT, -1, -1
4806 Xtank_gon, FALSE, FALSE,
4807 EL_SPACESHIP_UP, -1, -1
4810 Xtank_goe, FALSE, FALSE,
4811 EL_SPACESHIP_RIGHT, -1, -1
4814 Xtank_gos, FALSE, FALSE,
4815 EL_SPACESHIP_DOWN, -1, -1
4818 Xtank_gow, FALSE, FALSE,
4819 EL_SPACESHIP_LEFT, -1, -1
4822 Ytank_n, FALSE, FALSE,
4823 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
4826 Ytank_nB, FALSE, TRUE,
4827 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
4830 Ytank_e, FALSE, FALSE,
4831 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
4834 Ytank_eB, FALSE, TRUE,
4835 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
4838 Ytank_s, FALSE, FALSE,
4839 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
4842 Ytank_sB, FALSE, TRUE,
4843 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
4846 Ytank_w, FALSE, FALSE,
4847 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
4850 Ytank_wB, FALSE, TRUE,
4851 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
4854 Ytank_w_n, FALSE, FALSE,
4855 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
4858 Ytank_n_e, FALSE, FALSE,
4859 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
4862 Ytank_e_s, FALSE, FALSE,
4863 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
4866 Ytank_s_w, FALSE, FALSE,
4867 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
4870 Ytank_e_n, FALSE, FALSE,
4871 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
4874 Ytank_s_e, FALSE, FALSE,
4875 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
4878 Ytank_w_s, FALSE, FALSE,
4879 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
4882 Ytank_n_w, FALSE, FALSE,
4883 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
4886 Ytank_stone, FALSE, FALSE,
4887 EL_SPACESHIP, ACTION_SMASHED_BY_ROCK, -1
4890 Ytank_spring, FALSE, FALSE,
4891 EL_SPACESHIP, ACTION_SMASHED_BY_SPRING, -1
4894 Xandroid, TRUE, FALSE,
4895 EL_EMC_ANDROID, ACTION_ACTIVE, -1
4898 Xandroid_1_n, FALSE, FALSE,
4899 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
4902 Xandroid_2_n, FALSE, FALSE,
4903 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
4906 Xandroid_1_e, FALSE, FALSE,
4907 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
4910 Xandroid_2_e, FALSE, FALSE,
4911 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
4914 Xandroid_1_w, FALSE, FALSE,
4915 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
4918 Xandroid_2_w, FALSE, FALSE,
4919 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
4922 Xandroid_1_s, FALSE, FALSE,
4923 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
4926 Xandroid_2_s, FALSE, FALSE,
4927 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
4930 Yandroid_n, FALSE, FALSE,
4931 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
4934 Yandroid_nB, FALSE, TRUE,
4935 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
4938 Yandroid_ne, FALSE, FALSE,
4939 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPRIGHT
4942 Yandroid_neB, FALSE, TRUE,
4943 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPRIGHT
4946 Yandroid_e, FALSE, FALSE,
4947 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
4950 Yandroid_eB, FALSE, TRUE,
4951 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
4954 Yandroid_se, FALSE, FALSE,
4955 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNRIGHT
4958 Yandroid_seB, FALSE, TRUE,
4959 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNRIGHT
4962 Yandroid_s, FALSE, FALSE,
4963 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
4966 Yandroid_sB, FALSE, TRUE,
4967 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
4970 Yandroid_sw, FALSE, FALSE,
4971 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNLEFT
4974 Yandroid_swB, FALSE, TRUE,
4975 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNLEFT
4978 Yandroid_w, FALSE, FALSE,
4979 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
4982 Yandroid_wB, FALSE, TRUE,
4983 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
4986 Yandroid_nw, FALSE, FALSE,
4987 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPLEFT
4990 Yandroid_nwB, FALSE, TRUE,
4991 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPLEFT
4994 Xspring, TRUE, FALSE,
4998 Xspring_pause, FALSE, FALSE,
5002 Xspring_e, FALSE, FALSE,
5006 Xspring_w, FALSE, FALSE,
5010 Xspring_fall, FALSE, FALSE,
5014 Yspring_s, FALSE, FALSE,
5015 EL_SPRING, ACTION_FALLING, -1
5018 Yspring_sB, FALSE, TRUE,
5019 EL_SPRING, ACTION_FALLING, -1
5022 Yspring_e, FALSE, FALSE,
5023 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
5026 Yspring_eB, FALSE, TRUE,
5027 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
5030 Yspring_w, FALSE, FALSE,
5031 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
5034 Yspring_wB, FALSE, TRUE,
5035 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
5038 Yspring_kill_e, FALSE, FALSE,
5039 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
5042 Yspring_kill_eB, FALSE, TRUE,
5043 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
5046 Yspring_kill_w, FALSE, FALSE,
5047 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
5050 Yspring_kill_wB, FALSE, TRUE,
5051 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
5054 Xeater_n, TRUE, FALSE,
5055 EL_YAMYAM_UP, -1, -1
5058 Xeater_e, TRUE, FALSE,
5059 EL_YAMYAM_RIGHT, -1, -1
5062 Xeater_w, TRUE, FALSE,
5063 EL_YAMYAM_LEFT, -1, -1
5066 Xeater_s, TRUE, FALSE,
5067 EL_YAMYAM_DOWN, -1, -1
5070 Yeater_n, FALSE, FALSE,
5071 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
5074 Yeater_nB, FALSE, TRUE,
5075 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
5078 Yeater_e, FALSE, FALSE,
5079 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
5082 Yeater_eB, FALSE, TRUE,
5083 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
5086 Yeater_s, FALSE, FALSE,
5087 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
5090 Yeater_sB, FALSE, TRUE,
5091 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
5094 Yeater_w, FALSE, FALSE,
5095 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
5098 Yeater_wB, FALSE, TRUE,
5099 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
5102 Yeater_stone, FALSE, FALSE,
5103 EL_YAMYAM, ACTION_SMASHED_BY_ROCK, -1
5106 Yeater_spring, FALSE, FALSE,
5107 EL_YAMYAM, ACTION_SMASHED_BY_SPRING, -1
5110 Xalien, TRUE, FALSE,
5114 Xalien_pause, FALSE, FALSE,
5118 Yalien_n, FALSE, FALSE,
5119 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
5122 Yalien_nB, FALSE, TRUE,
5123 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
5126 Yalien_e, FALSE, FALSE,
5127 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
5130 Yalien_eB, FALSE, TRUE,
5131 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
5134 Yalien_s, FALSE, FALSE,
5135 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
5138 Yalien_sB, FALSE, TRUE,
5139 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
5142 Yalien_w, FALSE, FALSE,
5143 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
5146 Yalien_wB, FALSE, TRUE,
5147 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
5150 Yalien_stone, FALSE, FALSE,
5151 EL_ROBOT, ACTION_SMASHED_BY_ROCK, -1
5154 Yalien_spring, FALSE, FALSE,
5155 EL_ROBOT, ACTION_SMASHED_BY_SPRING, -1
5158 Xemerald, TRUE, FALSE,
5162 Xemerald_pause, FALSE, FALSE,
5166 Xemerald_fall, FALSE, FALSE,
5170 Xemerald_shine, FALSE, FALSE,
5171 EL_EMERALD, ACTION_TWINKLING, -1
5174 Yemerald_s, FALSE, FALSE,
5175 EL_EMERALD, ACTION_FALLING, -1
5178 Yemerald_sB, FALSE, TRUE,
5179 EL_EMERALD, ACTION_FALLING, -1
5182 Yemerald_e, FALSE, FALSE,
5183 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
5186 Yemerald_eB, FALSE, TRUE,
5187 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
5190 Yemerald_w, FALSE, FALSE,
5191 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
5194 Yemerald_wB, FALSE, TRUE,
5195 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
5198 Yemerald_eat, FALSE, FALSE,
5199 EL_EMERALD, ACTION_COLLECTING, -1
5202 Yemerald_stone, FALSE, FALSE,
5203 EL_NUT, ACTION_BREAKING, -1
5206 Xdiamond, TRUE, FALSE,
5210 Xdiamond_pause, FALSE, FALSE,
5214 Xdiamond_fall, FALSE, FALSE,
5218 Xdiamond_shine, FALSE, FALSE,
5219 EL_DIAMOND, ACTION_TWINKLING, -1
5222 Ydiamond_s, FALSE, FALSE,
5223 EL_DIAMOND, ACTION_FALLING, -1
5226 Ydiamond_sB, FALSE, TRUE,
5227 EL_DIAMOND, ACTION_FALLING, -1
5230 Ydiamond_e, FALSE, FALSE,
5231 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
5234 Ydiamond_eB, FALSE, TRUE,
5235 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
5238 Ydiamond_w, FALSE, FALSE,
5239 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
5242 Ydiamond_wB, FALSE, TRUE,
5243 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
5246 Ydiamond_eat, FALSE, FALSE,
5247 EL_DIAMOND, ACTION_COLLECTING, -1
5250 Ydiamond_stone, FALSE, FALSE,
5251 EL_DIAMOND, ACTION_SMASHED_BY_ROCK, -1
5254 Xdrip_fall, TRUE, FALSE,
5255 EL_AMOEBA_DROP, -1, -1
5258 Xdrip_stretch, FALSE, FALSE,
5259 EL_AMOEBA_DROP, ACTION_FALLING, -1
5262 Xdrip_stretchB, FALSE, TRUE,
5263 EL_AMOEBA_DROP, ACTION_FALLING, -1
5266 Xdrip_eat, FALSE, FALSE,
5267 EL_AMOEBA_DROP, ACTION_GROWING, -1
5270 Ydrip_s1, FALSE, FALSE,
5271 EL_AMOEBA_DROP, ACTION_FALLING, -1
5274 Ydrip_s1B, FALSE, TRUE,
5275 EL_AMOEBA_DROP, ACTION_FALLING, -1
5278 Ydrip_s2, FALSE, FALSE,
5279 EL_AMOEBA_DROP, ACTION_FALLING, -1
5282 Ydrip_s2B, FALSE, TRUE,
5283 EL_AMOEBA_DROP, ACTION_FALLING, -1
5290 Xbomb_pause, FALSE, FALSE,
5294 Xbomb_fall, FALSE, FALSE,
5298 Ybomb_s, FALSE, FALSE,
5299 EL_BOMB, ACTION_FALLING, -1
5302 Ybomb_sB, FALSE, TRUE,
5303 EL_BOMB, ACTION_FALLING, -1
5306 Ybomb_e, FALSE, FALSE,
5307 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
5310 Ybomb_eB, FALSE, TRUE,
5311 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
5314 Ybomb_w, FALSE, FALSE,
5315 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
5318 Ybomb_wB, FALSE, TRUE,
5319 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
5322 Ybomb_eat, FALSE, FALSE,
5323 EL_BOMB, ACTION_ACTIVATING, -1
5326 Xballoon, TRUE, FALSE,
5330 Yballoon_n, FALSE, FALSE,
5331 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
5334 Yballoon_nB, FALSE, TRUE,
5335 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
5338 Yballoon_e, FALSE, FALSE,
5339 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
5342 Yballoon_eB, FALSE, TRUE,
5343 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
5346 Yballoon_s, FALSE, FALSE,
5347 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
5350 Yballoon_sB, FALSE, TRUE,
5351 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
5354 Yballoon_w, FALSE, FALSE,
5355 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
5358 Yballoon_wB, FALSE, TRUE,
5359 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
5362 Xgrass, TRUE, FALSE,
5363 EL_EMC_GRASS, -1, -1
5366 Ygrass_nB, FALSE, FALSE,
5367 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_UP
5370 Ygrass_eB, FALSE, FALSE,
5371 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_RIGHT
5374 Ygrass_sB, FALSE, FALSE,
5375 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_DOWN
5378 Ygrass_wB, FALSE, FALSE,
5379 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_LEFT
5386 Ydirt_nB, FALSE, FALSE,
5387 EL_SAND, ACTION_DIGGING, MV_BIT_UP
5390 Ydirt_eB, FALSE, FALSE,
5391 EL_SAND, ACTION_DIGGING, MV_BIT_RIGHT
5394 Ydirt_sB, FALSE, FALSE,
5395 EL_SAND, ACTION_DIGGING, MV_BIT_DOWN
5398 Ydirt_wB, FALSE, FALSE,
5399 EL_SAND, ACTION_DIGGING, MV_BIT_LEFT
5402 Xacid_ne, TRUE, FALSE,
5403 EL_ACID_POOL_TOPRIGHT, -1, -1
5406 Xacid_se, TRUE, FALSE,
5407 EL_ACID_POOL_BOTTOMRIGHT, -1, -1
5410 Xacid_s, TRUE, FALSE,
5411 EL_ACID_POOL_BOTTOM, -1, -1
5414 Xacid_sw, TRUE, FALSE,
5415 EL_ACID_POOL_BOTTOMLEFT, -1, -1
5418 Xacid_nw, TRUE, FALSE,
5419 EL_ACID_POOL_TOPLEFT, -1, -1
5422 Xacid_1, TRUE, FALSE,
5426 Xacid_2, FALSE, FALSE,
5430 Xacid_3, FALSE, FALSE,
5434 Xacid_4, FALSE, FALSE,
5438 Xacid_5, FALSE, FALSE,
5442 Xacid_6, FALSE, FALSE,
5446 Xacid_7, FALSE, FALSE,
5450 Xacid_8, FALSE, FALSE,
5454 Xball_1, TRUE, FALSE,
5455 EL_EMC_MAGIC_BALL, -1, -1
5458 Xball_1B, FALSE, FALSE,
5459 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
5462 Xball_2, FALSE, FALSE,
5463 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
5466 Xball_2B, FALSE, FALSE,
5467 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
5470 Yball_eat, FALSE, FALSE,
5471 EL_EMC_MAGIC_BALL, ACTION_DROPPING, -1
5474 Ykey_1_eat, FALSE, FALSE,
5475 EL_EM_KEY_1, ACTION_COLLECTING, -1
5478 Ykey_2_eat, FALSE, FALSE,
5479 EL_EM_KEY_2, ACTION_COLLECTING, -1
5482 Ykey_3_eat, FALSE, FALSE,
5483 EL_EM_KEY_3, ACTION_COLLECTING, -1
5486 Ykey_4_eat, FALSE, FALSE,
5487 EL_EM_KEY_4, ACTION_COLLECTING, -1
5490 Ykey_5_eat, FALSE, FALSE,
5491 EL_EMC_KEY_5, ACTION_COLLECTING, -1
5494 Ykey_6_eat, FALSE, FALSE,
5495 EL_EMC_KEY_6, ACTION_COLLECTING, -1
5498 Ykey_7_eat, FALSE, FALSE,
5499 EL_EMC_KEY_7, ACTION_COLLECTING, -1
5502 Ykey_8_eat, FALSE, FALSE,
5503 EL_EMC_KEY_8, ACTION_COLLECTING, -1
5506 Ylenses_eat, FALSE, FALSE,
5507 EL_EMC_LENSES, ACTION_COLLECTING, -1
5510 Ymagnify_eat, FALSE, FALSE,
5511 EL_EMC_MAGNIFIER, ACTION_COLLECTING, -1
5514 Ygrass_eat, FALSE, FALSE,
5515 EL_EMC_GRASS, ACTION_SNAPPING, -1
5518 Ydirt_eat, FALSE, FALSE,
5519 EL_SAND, ACTION_SNAPPING, -1
5522 Xgrow_ns, TRUE, FALSE,
5523 EL_EXPANDABLE_WALL_VERTICAL, -1, -1
5526 Ygrow_ns_eat, FALSE, FALSE,
5527 EL_EXPANDABLE_WALL_VERTICAL, ACTION_GROWING, -1
5530 Xgrow_ew, TRUE, FALSE,
5531 EL_EXPANDABLE_WALL_HORIZONTAL, -1, -1
5534 Ygrow_ew_eat, FALSE, FALSE,
5535 EL_EXPANDABLE_WALL_HORIZONTAL, ACTION_GROWING, -1
5538 Xwonderwall, TRUE, FALSE,
5539 EL_MAGIC_WALL, -1, -1
5542 XwonderwallB, FALSE, FALSE,
5543 EL_MAGIC_WALL, ACTION_ACTIVE, -1
5546 Xamoeba_1, TRUE, FALSE,
5547 EL_AMOEBA_DRY, ACTION_OTHER, -1
5550 Xamoeba_2, FALSE, FALSE,
5551 EL_AMOEBA_DRY, ACTION_OTHER, -1
5554 Xamoeba_3, FALSE, FALSE,
5555 EL_AMOEBA_DRY, ACTION_OTHER, -1
5558 Xamoeba_4, FALSE, FALSE,
5559 EL_AMOEBA_DRY, ACTION_OTHER, -1
5562 Xamoeba_5, TRUE, FALSE,
5563 EL_AMOEBA_WET, ACTION_OTHER, -1
5566 Xamoeba_6, FALSE, FALSE,
5567 EL_AMOEBA_WET, ACTION_OTHER, -1
5570 Xamoeba_7, FALSE, FALSE,
5571 EL_AMOEBA_WET, ACTION_OTHER, -1
5574 Xamoeba_8, FALSE, FALSE,
5575 EL_AMOEBA_WET, ACTION_OTHER, -1
5578 Xdoor_1, TRUE, FALSE,
5579 EL_EM_GATE_1, -1, -1
5582 Xdoor_2, TRUE, FALSE,
5583 EL_EM_GATE_2, -1, -1
5586 Xdoor_3, TRUE, FALSE,
5587 EL_EM_GATE_3, -1, -1
5590 Xdoor_4, TRUE, FALSE,
5591 EL_EM_GATE_4, -1, -1
5594 Xdoor_5, TRUE, FALSE,
5595 EL_EMC_GATE_5, -1, -1
5598 Xdoor_6, TRUE, FALSE,
5599 EL_EMC_GATE_6, -1, -1
5602 Xdoor_7, TRUE, FALSE,
5603 EL_EMC_GATE_7, -1, -1
5606 Xdoor_8, TRUE, FALSE,
5607 EL_EMC_GATE_8, -1, -1
5610 Xkey_1, TRUE, FALSE,
5614 Xkey_2, TRUE, FALSE,
5618 Xkey_3, TRUE, FALSE,
5622 Xkey_4, TRUE, FALSE,
5626 Xkey_5, TRUE, FALSE,
5627 EL_EMC_KEY_5, -1, -1
5630 Xkey_6, TRUE, FALSE,
5631 EL_EMC_KEY_6, -1, -1
5634 Xkey_7, TRUE, FALSE,
5635 EL_EMC_KEY_7, -1, -1
5638 Xkey_8, TRUE, FALSE,
5639 EL_EMC_KEY_8, -1, -1
5642 Xwind_n, TRUE, FALSE,
5643 EL_BALLOON_SWITCH_UP, -1, -1
5646 Xwind_e, TRUE, FALSE,
5647 EL_BALLOON_SWITCH_RIGHT, -1, -1
5650 Xwind_s, TRUE, FALSE,
5651 EL_BALLOON_SWITCH_DOWN, -1, -1
5654 Xwind_w, TRUE, FALSE,
5655 EL_BALLOON_SWITCH_LEFT, -1, -1
5658 Xwind_nesw, TRUE, FALSE,
5659 EL_BALLOON_SWITCH_ANY, -1, -1
5662 Xwind_stop, TRUE, FALSE,
5663 EL_BALLOON_SWITCH_NONE, -1, -1
5667 EL_EM_EXIT_CLOSED, -1, -1
5670 Xexit_1, TRUE, FALSE,
5671 EL_EM_EXIT_OPEN, -1, -1
5674 Xexit_2, FALSE, FALSE,
5675 EL_EM_EXIT_OPEN, -1, -1
5678 Xexit_3, FALSE, FALSE,
5679 EL_EM_EXIT_OPEN, -1, -1
5682 Xdynamite, TRUE, FALSE,
5683 EL_EM_DYNAMITE, -1, -1
5686 Ydynamite_eat, FALSE, FALSE,
5687 EL_EM_DYNAMITE, ACTION_COLLECTING, -1
5690 Xdynamite_1, TRUE, FALSE,
5691 EL_EM_DYNAMITE_ACTIVE, -1, -1
5694 Xdynamite_2, FALSE, FALSE,
5695 EL_EM_DYNAMITE_ACTIVE, -1, -1
5698 Xdynamite_3, FALSE, FALSE,
5699 EL_EM_DYNAMITE_ACTIVE, -1, -1
5702 Xdynamite_4, FALSE, FALSE,
5703 EL_EM_DYNAMITE_ACTIVE, -1, -1
5706 Xbumper, TRUE, FALSE,
5707 EL_EMC_SPRING_BUMPER, -1, -1
5710 XbumperB, FALSE, FALSE,
5711 EL_EMC_SPRING_BUMPER, ACTION_ACTIVE, -1
5714 Xwheel, TRUE, FALSE,
5715 EL_ROBOT_WHEEL, -1, -1
5718 XwheelB, FALSE, FALSE,
5719 EL_ROBOT_WHEEL, ACTION_ACTIVE, -1
5722 Xswitch, TRUE, FALSE,
5723 EL_EMC_MAGIC_BALL_SWITCH, -1, -1
5726 XswitchB, FALSE, FALSE,
5727 EL_EMC_MAGIC_BALL_SWITCH, ACTION_ACTIVE, -1
5731 EL_QUICKSAND_EMPTY, -1, -1
5734 Xsand_stone, TRUE, FALSE,
5735 EL_QUICKSAND_FULL, -1, -1
5738 Xsand_stonein_1, FALSE, TRUE,
5739 EL_ROCK, ACTION_FILLING, -1
5742 Xsand_stonein_2, FALSE, TRUE,
5743 EL_ROCK, ACTION_FILLING, -1
5746 Xsand_stonein_3, FALSE, TRUE,
5747 EL_ROCK, ACTION_FILLING, -1
5750 Xsand_stonein_4, FALSE, TRUE,
5751 EL_ROCK, ACTION_FILLING, -1
5754 Xsand_stonesand_1, FALSE, FALSE,
5755 EL_QUICKSAND_EMPTYING, -1, -1
5758 Xsand_stonesand_2, FALSE, FALSE,
5759 EL_QUICKSAND_EMPTYING, -1, -1
5762 Xsand_stonesand_3, FALSE, FALSE,
5763 EL_QUICKSAND_EMPTYING, -1, -1
5766 Xsand_stonesand_4, FALSE, FALSE,
5767 EL_QUICKSAND_EMPTYING, -1, -1
5770 Xsand_stonesand_quickout_1, FALSE, FALSE,
5771 EL_QUICKSAND_EMPTYING, -1, -1
5774 Xsand_stonesand_quickout_2, FALSE, FALSE,
5775 EL_QUICKSAND_EMPTYING, -1, -1
5778 Xsand_stoneout_1, FALSE, FALSE,
5779 EL_ROCK, ACTION_EMPTYING, -1
5782 Xsand_stoneout_2, FALSE, FALSE,
5783 EL_ROCK, ACTION_EMPTYING, -1
5786 Xsand_sandstone_1, FALSE, FALSE,
5787 EL_QUICKSAND_FILLING, -1, -1
5790 Xsand_sandstone_2, FALSE, FALSE,
5791 EL_QUICKSAND_FILLING, -1, -1
5794 Xsand_sandstone_3, FALSE, FALSE,
5795 EL_QUICKSAND_FILLING, -1, -1
5798 Xsand_sandstone_4, FALSE, FALSE,
5799 EL_QUICKSAND_FILLING, -1, -1
5802 Xplant, TRUE, FALSE,
5803 EL_EMC_PLANT, -1, -1
5806 Yplant, FALSE, FALSE,
5807 EL_EMC_PLANT, -1, -1
5810 Xlenses, TRUE, FALSE,
5811 EL_EMC_LENSES, -1, -1
5814 Xmagnify, TRUE, FALSE,
5815 EL_EMC_MAGNIFIER, -1, -1
5818 Xdripper, TRUE, FALSE,
5819 EL_EMC_DRIPPER, -1, -1
5822 XdripperB, FALSE, FALSE,
5823 EL_EMC_DRIPPER, ACTION_ACTIVE, -1
5826 Xfake_blank, TRUE, FALSE,
5827 EL_INVISIBLE_WALL, -1, -1
5830 Xfake_blankB, FALSE, FALSE,
5831 EL_INVISIBLE_WALL, ACTION_ACTIVE, -1
5834 Xfake_grass, TRUE, FALSE,
5835 EL_EMC_FAKE_GRASS, -1, -1
5838 Xfake_grassB, FALSE, FALSE,
5839 EL_EMC_FAKE_GRASS, ACTION_ACTIVE, -1
5842 Xfake_door_1, TRUE, FALSE,
5843 EL_EM_GATE_1_GRAY, -1, -1
5846 Xfake_door_2, TRUE, FALSE,
5847 EL_EM_GATE_2_GRAY, -1, -1
5850 Xfake_door_3, TRUE, FALSE,
5851 EL_EM_GATE_3_GRAY, -1, -1
5854 Xfake_door_4, TRUE, FALSE,
5855 EL_EM_GATE_4_GRAY, -1, -1
5858 Xfake_door_5, TRUE, FALSE,
5859 EL_EMC_GATE_5_GRAY, -1, -1
5862 Xfake_door_6, TRUE, FALSE,
5863 EL_EMC_GATE_6_GRAY, -1, -1
5866 Xfake_door_7, TRUE, FALSE,
5867 EL_EMC_GATE_7_GRAY, -1, -1
5870 Xfake_door_8, TRUE, FALSE,
5871 EL_EMC_GATE_8_GRAY, -1, -1
5874 Xfake_acid_1, TRUE, FALSE,
5875 EL_EMC_FAKE_ACID, -1, -1
5878 Xfake_acid_2, FALSE, FALSE,
5879 EL_EMC_FAKE_ACID, -1, -1
5882 Xfake_acid_3, FALSE, FALSE,
5883 EL_EMC_FAKE_ACID, -1, -1
5886 Xfake_acid_4, FALSE, FALSE,
5887 EL_EMC_FAKE_ACID, -1, -1
5890 Xfake_acid_5, FALSE, FALSE,
5891 EL_EMC_FAKE_ACID, -1, -1
5894 Xfake_acid_6, FALSE, FALSE,
5895 EL_EMC_FAKE_ACID, -1, -1
5898 Xfake_acid_7, FALSE, FALSE,
5899 EL_EMC_FAKE_ACID, -1, -1
5902 Xfake_acid_8, FALSE, FALSE,
5903 EL_EMC_FAKE_ACID, -1, -1
5906 Xsteel_1, TRUE, FALSE,
5907 EL_STEELWALL, -1, -1
5910 Xsteel_2, TRUE, FALSE,
5911 EL_EMC_STEELWALL_2, -1, -1
5914 Xsteel_3, TRUE, FALSE,
5915 EL_EMC_STEELWALL_3, -1, -1
5918 Xsteel_4, TRUE, FALSE,
5919 EL_EMC_STEELWALL_4, -1, -1
5922 Xwall_1, TRUE, FALSE,
5926 Xwall_2, TRUE, FALSE,
5927 EL_EMC_WALL_14, -1, -1
5930 Xwall_3, TRUE, FALSE,
5931 EL_EMC_WALL_15, -1, -1
5934 Xwall_4, TRUE, FALSE,
5935 EL_EMC_WALL_16, -1, -1
5938 Xround_wall_1, TRUE, FALSE,
5939 EL_WALL_SLIPPERY, -1, -1
5942 Xround_wall_2, TRUE, FALSE,
5943 EL_EMC_WALL_SLIPPERY_2, -1, -1
5946 Xround_wall_3, TRUE, FALSE,
5947 EL_EMC_WALL_SLIPPERY_3, -1, -1
5950 Xround_wall_4, TRUE, FALSE,
5951 EL_EMC_WALL_SLIPPERY_4, -1, -1
5954 Xdecor_1, TRUE, FALSE,
5955 EL_EMC_WALL_8, -1, -1
5958 Xdecor_2, TRUE, FALSE,
5959 EL_EMC_WALL_6, -1, -1
5962 Xdecor_3, TRUE, FALSE,
5963 EL_EMC_WALL_4, -1, -1
5966 Xdecor_4, TRUE, FALSE,
5967 EL_EMC_WALL_7, -1, -1
5970 Xdecor_5, TRUE, FALSE,
5971 EL_EMC_WALL_5, -1, -1
5974 Xdecor_6, TRUE, FALSE,
5975 EL_EMC_WALL_9, -1, -1
5978 Xdecor_7, TRUE, FALSE,
5979 EL_EMC_WALL_10, -1, -1
5982 Xdecor_8, TRUE, FALSE,
5983 EL_EMC_WALL_1, -1, -1
5986 Xdecor_9, TRUE, FALSE,
5987 EL_EMC_WALL_2, -1, -1
5990 Xdecor_10, TRUE, FALSE,
5991 EL_EMC_WALL_3, -1, -1
5994 Xdecor_11, TRUE, FALSE,
5995 EL_EMC_WALL_11, -1, -1
5998 Xdecor_12, TRUE, FALSE,
5999 EL_EMC_WALL_12, -1, -1
6002 Xalpha_0, TRUE, FALSE,
6003 EL_CHAR('0'), -1, -1
6006 Xalpha_1, TRUE, FALSE,
6007 EL_CHAR('1'), -1, -1
6010 Xalpha_2, TRUE, FALSE,
6011 EL_CHAR('2'), -1, -1
6014 Xalpha_3, TRUE, FALSE,
6015 EL_CHAR('3'), -1, -1
6018 Xalpha_4, TRUE, FALSE,
6019 EL_CHAR('4'), -1, -1
6022 Xalpha_5, TRUE, FALSE,
6023 EL_CHAR('5'), -1, -1
6026 Xalpha_6, TRUE, FALSE,
6027 EL_CHAR('6'), -1, -1
6030 Xalpha_7, TRUE, FALSE,
6031 EL_CHAR('7'), -1, -1
6034 Xalpha_8, TRUE, FALSE,
6035 EL_CHAR('8'), -1, -1
6038 Xalpha_9, TRUE, FALSE,
6039 EL_CHAR('9'), -1, -1
6042 Xalpha_excla, TRUE, FALSE,
6043 EL_CHAR('!'), -1, -1
6046 Xalpha_quote, TRUE, FALSE,
6047 EL_CHAR('"'), -1, -1
6050 Xalpha_comma, TRUE, FALSE,
6051 EL_CHAR(','), -1, -1
6054 Xalpha_minus, TRUE, FALSE,
6055 EL_CHAR('-'), -1, -1
6058 Xalpha_perio, TRUE, FALSE,
6059 EL_CHAR('.'), -1, -1
6062 Xalpha_colon, TRUE, FALSE,
6063 EL_CHAR(':'), -1, -1
6066 Xalpha_quest, TRUE, FALSE,
6067 EL_CHAR('?'), -1, -1
6070 Xalpha_a, TRUE, FALSE,
6071 EL_CHAR('A'), -1, -1
6074 Xalpha_b, TRUE, FALSE,
6075 EL_CHAR('B'), -1, -1
6078 Xalpha_c, TRUE, FALSE,
6079 EL_CHAR('C'), -1, -1
6082 Xalpha_d, TRUE, FALSE,
6083 EL_CHAR('D'), -1, -1
6086 Xalpha_e, TRUE, FALSE,
6087 EL_CHAR('E'), -1, -1
6090 Xalpha_f, TRUE, FALSE,
6091 EL_CHAR('F'), -1, -1
6094 Xalpha_g, TRUE, FALSE,
6095 EL_CHAR('G'), -1, -1
6098 Xalpha_h, TRUE, FALSE,
6099 EL_CHAR('H'), -1, -1
6102 Xalpha_i, TRUE, FALSE,
6103 EL_CHAR('I'), -1, -1
6106 Xalpha_j, TRUE, FALSE,
6107 EL_CHAR('J'), -1, -1
6110 Xalpha_k, TRUE, FALSE,
6111 EL_CHAR('K'), -1, -1
6114 Xalpha_l, TRUE, FALSE,
6115 EL_CHAR('L'), -1, -1
6118 Xalpha_m, TRUE, FALSE,
6119 EL_CHAR('M'), -1, -1
6122 Xalpha_n, TRUE, FALSE,
6123 EL_CHAR('N'), -1, -1
6126 Xalpha_o, TRUE, FALSE,
6127 EL_CHAR('O'), -1, -1
6130 Xalpha_p, TRUE, FALSE,
6131 EL_CHAR('P'), -1, -1
6134 Xalpha_q, TRUE, FALSE,
6135 EL_CHAR('Q'), -1, -1
6138 Xalpha_r, TRUE, FALSE,
6139 EL_CHAR('R'), -1, -1
6142 Xalpha_s, TRUE, FALSE,
6143 EL_CHAR('S'), -1, -1
6146 Xalpha_t, TRUE, FALSE,
6147 EL_CHAR('T'), -1, -1
6150 Xalpha_u, TRUE, FALSE,
6151 EL_CHAR('U'), -1, -1
6154 Xalpha_v, TRUE, FALSE,
6155 EL_CHAR('V'), -1, -1
6158 Xalpha_w, TRUE, FALSE,
6159 EL_CHAR('W'), -1, -1
6162 Xalpha_x, TRUE, FALSE,
6163 EL_CHAR('X'), -1, -1
6166 Xalpha_y, TRUE, FALSE,
6167 EL_CHAR('Y'), -1, -1
6170 Xalpha_z, TRUE, FALSE,
6171 EL_CHAR('Z'), -1, -1
6174 Xalpha_arrow_e, TRUE, FALSE,
6175 EL_CHAR('>'), -1, -1
6178 Xalpha_arrow_w, TRUE, FALSE,
6179 EL_CHAR('<'), -1, -1
6182 Xalpha_copyr, TRUE, FALSE,
6183 EL_CHAR('©'), -1, -1
6187 Xboom_bug, FALSE, FALSE,
6188 EL_BUG, ACTION_EXPLODING, -1
6191 Xboom_bomb, FALSE, FALSE,
6192 EL_BOMB, ACTION_EXPLODING, -1
6195 Xboom_android, FALSE, FALSE,
6196 EL_EMC_ANDROID, ACTION_OTHER, -1
6199 Xboom_1, FALSE, FALSE,
6200 EL_DEFAULT, ACTION_EXPLODING, -1
6203 Xboom_2, FALSE, FALSE,
6204 EL_DEFAULT, ACTION_EXPLODING, -1
6207 Znormal, FALSE, FALSE,
6211 Zdynamite, FALSE, FALSE,
6215 Zplayer, FALSE, FALSE,
6219 ZBORDER, FALSE, FALSE,
6229 static struct Mapping_EM_to_RND_player
6238 em_player_mapping_list[] =
6242 EL_PLAYER_1, ACTION_MOVING, MV_BIT_UP,
6246 EL_PLAYER_1, ACTION_MOVING, MV_BIT_RIGHT,
6250 EL_PLAYER_1, ACTION_MOVING, MV_BIT_DOWN,
6254 EL_PLAYER_1, ACTION_MOVING, MV_BIT_LEFT,
6258 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_UP,
6262 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_RIGHT,
6266 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_DOWN,
6270 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_LEFT,
6274 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_UP,
6278 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_RIGHT,
6282 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_DOWN,
6286 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_LEFT,
6290 EL_PLAYER_2, ACTION_MOVING, MV_BIT_UP,
6294 EL_PLAYER_2, ACTION_MOVING, MV_BIT_RIGHT,
6298 EL_PLAYER_2, ACTION_MOVING, MV_BIT_DOWN,
6302 EL_PLAYER_2, ACTION_MOVING, MV_BIT_LEFT,
6306 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_UP,
6310 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_RIGHT,
6314 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_DOWN,
6318 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_LEFT,
6322 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_UP,
6326 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_RIGHT,
6330 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_DOWN,
6334 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_LEFT,
6338 EL_PLAYER_1, ACTION_DEFAULT, -1,
6342 EL_PLAYER_2, ACTION_DEFAULT, -1,
6346 EL_PLAYER_3, ACTION_MOVING, MV_BIT_UP,
6350 EL_PLAYER_3, ACTION_MOVING, MV_BIT_RIGHT,
6354 EL_PLAYER_3, ACTION_MOVING, MV_BIT_DOWN,
6358 EL_PLAYER_3, ACTION_MOVING, MV_BIT_LEFT,
6362 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_UP,
6366 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_RIGHT,
6370 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_DOWN,
6374 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_LEFT,
6378 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_UP,
6382 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_RIGHT,
6386 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_DOWN,
6390 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_LEFT,
6394 EL_PLAYER_4, ACTION_MOVING, MV_BIT_UP,
6398 EL_PLAYER_4, ACTION_MOVING, MV_BIT_RIGHT,
6402 EL_PLAYER_4, ACTION_MOVING, MV_BIT_DOWN,
6406 EL_PLAYER_4, ACTION_MOVING, MV_BIT_LEFT,
6410 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_UP,
6414 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_RIGHT,
6418 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_DOWN,
6422 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_LEFT,
6426 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_UP,
6430 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_RIGHT,
6434 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_DOWN,
6438 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_LEFT,
6442 EL_PLAYER_3, ACTION_DEFAULT, -1,
6446 EL_PLAYER_4, ACTION_DEFAULT, -1,
6455 int map_element_RND_to_EM(int element_rnd)
6457 static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
6458 static boolean mapping_initialized = FALSE;
6460 if (!mapping_initialized)
6464 /* return "Xalpha_quest" for all undefined elements in mapping array */
6465 for (i = 0; i < NUM_FILE_ELEMENTS; i++)
6466 mapping_RND_to_EM[i] = Xalpha_quest;
6468 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
6469 if (em_object_mapping_list[i].is_rnd_to_em_mapping)
6470 mapping_RND_to_EM[em_object_mapping_list[i].element_rnd] =
6471 em_object_mapping_list[i].element_em;
6473 mapping_initialized = TRUE;
6476 if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
6477 return mapping_RND_to_EM[element_rnd];
6479 Error(ERR_WARN, "invalid RND level element %d", element_rnd);
6484 int map_element_EM_to_RND(int element_em)
6486 static unsigned short mapping_EM_to_RND[TILE_MAX];
6487 static boolean mapping_initialized = FALSE;
6489 if (!mapping_initialized)
6493 /* return "EL_UNKNOWN" for all undefined elements in mapping array */
6494 for (i = 0; i < TILE_MAX; i++)
6495 mapping_EM_to_RND[i] = EL_UNKNOWN;
6497 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
6498 mapping_EM_to_RND[em_object_mapping_list[i].element_em] =
6499 em_object_mapping_list[i].element_rnd;
6501 mapping_initialized = TRUE;
6504 if (element_em >= 0 && element_em < TILE_MAX)
6505 return mapping_EM_to_RND[element_em];
6507 Error(ERR_WARN, "invalid EM level element %d", element_em);
6512 void map_android_clone_elements_RND_to_EM(struct LevelInfo *level)
6514 struct LevelInfo_EM *level_em = level->native_em_level;
6515 struct LEVEL *lev = level_em->lev;
6518 for (i = 0; i < TILE_MAX; i++)
6519 lev->android_array[i] = Xblank;
6521 for (i = 0; i < level->num_android_clone_elements; i++)
6523 int element_rnd = level->android_clone_element[i];
6524 int element_em = map_element_RND_to_EM(element_rnd);
6526 for (j = 0; em_object_mapping_list[j].element_em != -1; j++)
6527 if (em_object_mapping_list[j].element_rnd == element_rnd)
6528 lev->android_array[em_object_mapping_list[j].element_em] = element_em;
6532 void map_android_clone_elements_EM_to_RND(struct LevelInfo *level)
6534 struct LevelInfo_EM *level_em = level->native_em_level;
6535 struct LEVEL *lev = level_em->lev;
6538 level->num_android_clone_elements = 0;
6540 for (i = 0; i < TILE_MAX; i++)
6542 int element_em = lev->android_array[i];
6544 boolean element_found = FALSE;
6546 if (element_em == Xblank)
6549 element_rnd = map_element_EM_to_RND(element_em);
6551 for (j = 0; j < level->num_android_clone_elements; j++)
6552 if (level->android_clone_element[j] == element_rnd)
6553 element_found = TRUE;
6557 level->android_clone_element[level->num_android_clone_elements++] =
6560 if (level->num_android_clone_elements == MAX_ANDROID_ELEMENTS)
6565 if (level->num_android_clone_elements == 0)
6567 level->num_android_clone_elements = 1;
6568 level->android_clone_element[0] = EL_EMPTY;
6572 int map_direction_RND_to_EM(int direction)
6574 return (direction == MV_UP ? 0 :
6575 direction == MV_RIGHT ? 1 :
6576 direction == MV_DOWN ? 2 :
6577 direction == MV_LEFT ? 3 :
6581 int map_direction_EM_to_RND(int direction)
6583 return (direction == 0 ? MV_UP :
6584 direction == 1 ? MV_RIGHT :
6585 direction == 2 ? MV_DOWN :
6586 direction == 3 ? MV_LEFT :
6590 int map_element_RND_to_SP(int element_rnd)
6592 int element_sp = 0x20; /* map unknown elements to yellow "hardware" */
6594 if (element_rnd >= EL_SP_START &&
6595 element_rnd <= EL_SP_END)
6596 element_sp = element_rnd - EL_SP_START;
6597 else if (element_rnd == EL_EMPTY_SPACE)
6599 else if (element_rnd == EL_INVISIBLE_WALL)
6605 int map_element_SP_to_RND(int element_sp)
6607 int element_rnd = EL_UNKNOWN;
6609 if (element_sp >= 0x00 &&
6611 element_rnd = EL_SP_START + element_sp;
6612 else if (element_sp == 0x28)
6613 element_rnd = EL_INVISIBLE_WALL;
6618 int map_action_SP_to_RND(int action_sp)
6622 case actActive: return ACTION_ACTIVE;
6623 case actImpact: return ACTION_IMPACT;
6624 case actExploding: return ACTION_EXPLODING;
6625 case actDigging: return ACTION_DIGGING;
6626 case actSnapping: return ACTION_SNAPPING;
6627 case actCollecting: return ACTION_COLLECTING;
6628 case actPassing: return ACTION_PASSING;
6629 case actPushing: return ACTION_PUSHING;
6630 case actDropping: return ACTION_DROPPING;
6632 default: return ACTION_DEFAULT;
6636 int get_next_element(int element)
6640 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
6641 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
6642 case EL_QUICKSAND_FAST_FILLING: return EL_QUICKSAND_FAST_FULL;
6643 case EL_QUICKSAND_FAST_EMPTYING: return EL_QUICKSAND_FAST_EMPTY;
6644 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
6645 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
6646 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
6647 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
6648 case EL_DC_MAGIC_WALL_FILLING: return EL_DC_MAGIC_WALL_FULL;
6649 case EL_DC_MAGIC_WALL_EMPTYING: return EL_DC_MAGIC_WALL_ACTIVE;
6650 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
6652 default: return element;
6656 int el_act_dir2img(int element, int action, int direction)
6658 element = GFX_ELEMENT(element);
6659 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
6661 /* direction_graphic[][] == graphic[] for undefined direction graphics */
6662 return element_info[element].direction_graphic[action][direction];
6665 static int el_act_dir2crm(int element, int action, int direction)
6667 element = GFX_ELEMENT(element);
6668 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
6670 /* direction_graphic[][] == graphic[] for undefined direction graphics */
6671 return element_info[element].direction_crumbled[action][direction];
6674 int el_act2img(int element, int action)
6676 element = GFX_ELEMENT(element);
6678 return element_info[element].graphic[action];
6681 int el_act2crm(int element, int action)
6683 element = GFX_ELEMENT(element);
6685 return element_info[element].crumbled[action];
6688 int el_dir2img(int element, int direction)
6690 element = GFX_ELEMENT(element);
6692 return el_act_dir2img(element, ACTION_DEFAULT, direction);
6695 int el2baseimg(int element)
6697 return element_info[element].graphic[ACTION_DEFAULT];
6700 int el2img(int element)
6702 element = GFX_ELEMENT(element);
6704 return element_info[element].graphic[ACTION_DEFAULT];
6707 int el2edimg(int element)
6709 element = GFX_ELEMENT(element);
6711 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
6714 int el2preimg(int element)
6716 element = GFX_ELEMENT(element);
6718 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
6721 int el2panelimg(int element)
6723 element = GFX_ELEMENT(element);
6725 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PANEL];
6728 int font2baseimg(int font_nr)
6730 return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
6733 int getBeltNrFromBeltElement(int element)
6735 return (element < EL_CONVEYOR_BELT_2_LEFT ? 0 :
6736 element < EL_CONVEYOR_BELT_3_LEFT ? 1 :
6737 element < EL_CONVEYOR_BELT_4_LEFT ? 2 : 3);
6740 int getBeltNrFromBeltActiveElement(int element)
6742 return (element < EL_CONVEYOR_BELT_2_LEFT_ACTIVE ? 0 :
6743 element < EL_CONVEYOR_BELT_3_LEFT_ACTIVE ? 1 :
6744 element < EL_CONVEYOR_BELT_4_LEFT_ACTIVE ? 2 : 3);
6747 int getBeltNrFromBeltSwitchElement(int element)
6749 return (element < EL_CONVEYOR_BELT_2_SWITCH_LEFT ? 0 :
6750 element < EL_CONVEYOR_BELT_3_SWITCH_LEFT ? 1 :
6751 element < EL_CONVEYOR_BELT_4_SWITCH_LEFT ? 2 : 3);
6754 int getBeltDirNrFromBeltElement(int element)
6756 static int belt_base_element[4] =
6758 EL_CONVEYOR_BELT_1_LEFT,
6759 EL_CONVEYOR_BELT_2_LEFT,
6760 EL_CONVEYOR_BELT_3_LEFT,
6761 EL_CONVEYOR_BELT_4_LEFT
6764 int belt_nr = getBeltNrFromBeltElement(element);
6765 int belt_dir_nr = element - belt_base_element[belt_nr];
6767 return (belt_dir_nr % 3);
6770 int getBeltDirNrFromBeltSwitchElement(int element)
6772 static int belt_base_element[4] =
6774 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
6775 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
6776 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
6777 EL_CONVEYOR_BELT_4_SWITCH_LEFT
6780 int belt_nr = getBeltNrFromBeltSwitchElement(element);
6781 int belt_dir_nr = element - belt_base_element[belt_nr];
6783 return (belt_dir_nr % 3);
6786 int getBeltDirFromBeltElement(int element)
6788 static int belt_move_dir[3] =
6795 int belt_dir_nr = getBeltDirNrFromBeltElement(element);
6797 return belt_move_dir[belt_dir_nr];
6800 int getBeltDirFromBeltSwitchElement(int element)
6802 static int belt_move_dir[3] =
6809 int belt_dir_nr = getBeltDirNrFromBeltSwitchElement(element);
6811 return belt_move_dir[belt_dir_nr];
6814 int getBeltElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
6816 static int belt_base_element[4] =
6818 EL_CONVEYOR_BELT_1_LEFT,
6819 EL_CONVEYOR_BELT_2_LEFT,
6820 EL_CONVEYOR_BELT_3_LEFT,
6821 EL_CONVEYOR_BELT_4_LEFT
6824 return belt_base_element[belt_nr] + belt_dir_nr;
6827 int getBeltElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
6829 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
6831 return getBeltElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
6834 int getBeltSwitchElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
6836 static int belt_base_element[4] =
6838 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
6839 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
6840 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
6841 EL_CONVEYOR_BELT_4_SWITCH_LEFT
6844 return belt_base_element[belt_nr] + belt_dir_nr;
6847 int getBeltSwitchElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
6849 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
6851 return getBeltSwitchElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
6854 boolean getTeamMode_EM()
6856 return game.team_mode;
6859 int getGameFrameDelay_EM(int native_em_game_frame_delay)
6861 int game_frame_delay_value;
6863 game_frame_delay_value =
6864 (tape.playing && tape.fast_forward ? FfwdFrameDelay :
6865 GameFrameDelay == GAME_FRAME_DELAY ? native_em_game_frame_delay :
6868 if (tape.playing && tape.warp_forward && !tape.pausing)
6869 game_frame_delay_value = 0;
6871 return game_frame_delay_value;
6874 unsigned int InitRND(int seed)
6876 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
6877 return InitEngineRandom_EM(seed);
6878 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
6879 return InitEngineRandom_SP(seed);
6881 return InitEngineRandom_RND(seed);
6884 static struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
6885 static struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
6887 inline static int get_effective_element_EM(int tile, int frame_em)
6889 int element = object_mapping[tile].element_rnd;
6890 int action = object_mapping[tile].action;
6891 boolean is_backside = object_mapping[tile].is_backside;
6892 boolean action_removing = (action == ACTION_DIGGING ||
6893 action == ACTION_SNAPPING ||
6894 action == ACTION_COLLECTING);
6900 case Yacid_splash_eB:
6901 case Yacid_splash_wB:
6902 return (frame_em > 5 ? EL_EMPTY : element);
6908 else /* frame_em == 7 */
6912 case Yacid_splash_eB:
6913 case Yacid_splash_wB:
6916 case Yemerald_stone:
6919 case Ydiamond_stone:
6923 case Xdrip_stretchB:
6942 case Xsand_stonein_1:
6943 case Xsand_stonein_2:
6944 case Xsand_stonein_3:
6945 case Xsand_stonein_4:
6949 return (is_backside || action_removing ? EL_EMPTY : element);
6954 inline static boolean check_linear_animation_EM(int tile)
6958 case Xsand_stonesand_1:
6959 case Xsand_stonesand_quickout_1:
6960 case Xsand_sandstone_1:
6961 case Xsand_stonein_1:
6962 case Xsand_stoneout_1:
6981 case Yacid_splash_eB:
6982 case Yacid_splash_wB:
6983 case Yemerald_stone:
6990 inline static void set_crumbled_graphics_EM(struct GraphicInfo_EM *g_em,
6991 boolean has_crumbled_graphics,
6992 int crumbled, int sync_frame)
6994 /* if element can be crumbled, but certain action graphics are just empty
6995 space (like instantly snapping sand to empty space in 1 frame), do not
6996 treat these empty space graphics as crumbled graphics in EMC engine */
6997 if (crumbled == IMG_EMPTY_SPACE)
6998 has_crumbled_graphics = FALSE;
7000 if (has_crumbled_graphics)
7002 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
7003 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
7004 g_crumbled->anim_delay,
7005 g_crumbled->anim_mode,
7006 g_crumbled->anim_start_frame,
7009 getGraphicSource(crumbled, frame_crumbled, &g_em->crumbled_bitmap,
7010 &g_em->crumbled_src_x, &g_em->crumbled_src_y);
7012 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
7014 g_em->has_crumbled_graphics = TRUE;
7018 g_em->crumbled_bitmap = NULL;
7019 g_em->crumbled_src_x = 0;
7020 g_em->crumbled_src_y = 0;
7021 g_em->crumbled_border_size = 0;
7023 g_em->has_crumbled_graphics = FALSE;
7027 void ResetGfxAnimation_EM(int x, int y, int tile)
7032 void SetGfxAnimation_EM(struct GraphicInfo_EM *g_em,
7033 int tile, int frame_em, int x, int y)
7035 int action = object_mapping[tile].action;
7036 int direction = object_mapping[tile].direction;
7037 int effective_element = get_effective_element_EM(tile, frame_em);
7038 int graphic = (direction == MV_NONE ?
7039 el_act2img(effective_element, action) :
7040 el_act_dir2img(effective_element, action, direction));
7041 struct GraphicInfo *g = &graphic_info[graphic];
7043 boolean action_removing = (action == ACTION_DIGGING ||
7044 action == ACTION_SNAPPING ||
7045 action == ACTION_COLLECTING);
7046 boolean action_moving = (action == ACTION_FALLING ||
7047 action == ACTION_MOVING ||
7048 action == ACTION_PUSHING ||
7049 action == ACTION_EATING ||
7050 action == ACTION_FILLING ||
7051 action == ACTION_EMPTYING);
7052 boolean action_falling = (action == ACTION_FALLING ||
7053 action == ACTION_FILLING ||
7054 action == ACTION_EMPTYING);
7056 /* special case: graphic uses "2nd movement tile" and has defined
7057 7 frames for movement animation (or less) => use default graphic
7058 for last (8th) frame which ends the movement animation */
7059 if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
7061 action = ACTION_DEFAULT; /* (keep action_* unchanged for now) */
7062 graphic = (direction == MV_NONE ?
7063 el_act2img(effective_element, action) :
7064 el_act_dir2img(effective_element, action, direction));
7066 g = &graphic_info[graphic];
7069 if ((action_removing || check_linear_animation_EM(tile)) && frame_em == 0)
7073 else if (action_moving)
7075 boolean is_backside = object_mapping[tile].is_backside;
7079 int direction = object_mapping[tile].direction;
7080 int move_dir = (action_falling ? MV_DOWN : direction);
7085 /* !!! TEST !!! NEW !!! DOES NOT WORK RIGHT YET !!! */
7086 if (g->double_movement && frame_em == 0)
7090 if (move_dir == MV_LEFT)
7091 GfxFrame[x - 1][y] = GfxFrame[x][y];
7092 else if (move_dir == MV_RIGHT)
7093 GfxFrame[x + 1][y] = GfxFrame[x][y];
7094 else if (move_dir == MV_UP)
7095 GfxFrame[x][y - 1] = GfxFrame[x][y];
7096 else if (move_dir == MV_DOWN)
7097 GfxFrame[x][y + 1] = GfxFrame[x][y];
7104 /* special case: animation for Xsand_stonesand_quickout_1/2 twice as fast */
7105 if (tile == Xsand_stonesand_quickout_1 ||
7106 tile == Xsand_stonesand_quickout_2)
7110 if (graphic_info[graphic].anim_global_sync)
7111 sync_frame = FrameCounter;
7112 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
7113 sync_frame = GfxFrame[x][y];
7115 sync_frame = 0; /* playfield border (pseudo steel) */
7117 SetRandomAnimationValue(x, y);
7119 int frame = getAnimationFrame(g->anim_frames,
7122 g->anim_start_frame,
7125 g_em->unique_identifier =
7126 (graphic << 16) | ((frame % 8) << 12) | (g_em->width << 6) | g_em->height;
7129 void getGraphicSourceObjectExt_EM(struct GraphicInfo_EM *g_em,
7130 int tile, int frame_em, int x, int y)
7132 int action = object_mapping[tile].action;
7133 int direction = object_mapping[tile].direction;
7134 boolean is_backside = object_mapping[tile].is_backside;
7135 int effective_element = get_effective_element_EM(tile, frame_em);
7136 int effective_action = action;
7137 int graphic = (direction == MV_NONE ?
7138 el_act2img(effective_element, effective_action) :
7139 el_act_dir2img(effective_element, effective_action,
7141 int crumbled = (direction == MV_NONE ?
7142 el_act2crm(effective_element, effective_action) :
7143 el_act_dir2crm(effective_element, effective_action,
7145 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
7146 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
7147 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
7148 struct GraphicInfo *g = &graphic_info[graphic];
7151 /* special case: graphic uses "2nd movement tile" and has defined
7152 7 frames for movement animation (or less) => use default graphic
7153 for last (8th) frame which ends the movement animation */
7154 if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
7156 effective_action = ACTION_DEFAULT;
7157 graphic = (direction == MV_NONE ?
7158 el_act2img(effective_element, effective_action) :
7159 el_act_dir2img(effective_element, effective_action,
7161 crumbled = (direction == MV_NONE ?
7162 el_act2crm(effective_element, effective_action) :
7163 el_act_dir2crm(effective_element, effective_action,
7166 g = &graphic_info[graphic];
7169 if (graphic_info[graphic].anim_global_sync)
7170 sync_frame = FrameCounter;
7171 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
7172 sync_frame = GfxFrame[x][y];
7174 sync_frame = 0; /* playfield border (pseudo steel) */
7176 SetRandomAnimationValue(x, y);
7178 int frame = getAnimationFrame(g->anim_frames,
7181 g->anim_start_frame,
7184 getGraphicSourceExt(graphic, frame, &g_em->bitmap, &g_em->src_x, &g_em->src_y,
7185 g->double_movement && is_backside);
7187 /* (updating the "crumbled" graphic definitions is probably not really needed,
7188 as animations for crumbled graphics can't be longer than one EMC cycle) */
7189 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
7193 void getGraphicSourcePlayerExt_EM(struct GraphicInfo_EM *g_em,
7194 int player_nr, int anim, int frame_em)
7196 int element = player_mapping[player_nr][anim].element_rnd;
7197 int action = player_mapping[player_nr][anim].action;
7198 int direction = player_mapping[player_nr][anim].direction;
7199 int graphic = (direction == MV_NONE ?
7200 el_act2img(element, action) :
7201 el_act_dir2img(element, action, direction));
7202 struct GraphicInfo *g = &graphic_info[graphic];
7205 InitPlayerGfxAnimation(&stored_player[player_nr], action, direction);
7207 stored_player[player_nr].StepFrame = frame_em;
7209 sync_frame = stored_player[player_nr].Frame;
7211 int frame = getAnimationFrame(g->anim_frames,
7214 g->anim_start_frame,
7217 getGraphicSourceExt(graphic, frame, &g_em->bitmap,
7218 &g_em->src_x, &g_em->src_y, FALSE);
7221 void InitGraphicInfo_EM(void)
7226 int num_em_gfx_errors = 0;
7228 if (graphic_info_em_object[0][0].bitmap == NULL)
7230 /* EM graphics not yet initialized in em_open_all() */
7235 printf("::: [4 errors can be ignored (1 x 'bomb', 3 x 'em_dynamite']\n");
7238 /* always start with reliable default values */
7239 for (i = 0; i < TILE_MAX; i++)
7241 object_mapping[i].element_rnd = EL_UNKNOWN;
7242 object_mapping[i].is_backside = FALSE;
7243 object_mapping[i].action = ACTION_DEFAULT;
7244 object_mapping[i].direction = MV_NONE;
7247 /* always start with reliable default values */
7248 for (p = 0; p < MAX_PLAYERS; p++)
7250 for (i = 0; i < SPR_MAX; i++)
7252 player_mapping[p][i].element_rnd = EL_UNKNOWN;
7253 player_mapping[p][i].action = ACTION_DEFAULT;
7254 player_mapping[p][i].direction = MV_NONE;
7258 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
7260 int e = em_object_mapping_list[i].element_em;
7262 object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd;
7263 object_mapping[e].is_backside = em_object_mapping_list[i].is_backside;
7265 if (em_object_mapping_list[i].action != -1)
7266 object_mapping[e].action = em_object_mapping_list[i].action;
7268 if (em_object_mapping_list[i].direction != -1)
7269 object_mapping[e].direction =
7270 MV_DIR_FROM_BIT(em_object_mapping_list[i].direction);
7273 for (i = 0; em_player_mapping_list[i].action_em != -1; i++)
7275 int a = em_player_mapping_list[i].action_em;
7276 int p = em_player_mapping_list[i].player_nr;
7278 player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd;
7280 if (em_player_mapping_list[i].action != -1)
7281 player_mapping[p][a].action = em_player_mapping_list[i].action;
7283 if (em_player_mapping_list[i].direction != -1)
7284 player_mapping[p][a].direction =
7285 MV_DIR_FROM_BIT(em_player_mapping_list[i].direction);
7288 for (i = 0; i < TILE_MAX; i++)
7290 int element = object_mapping[i].element_rnd;
7291 int action = object_mapping[i].action;
7292 int direction = object_mapping[i].direction;
7293 boolean is_backside = object_mapping[i].is_backside;
7294 boolean action_exploding = ((action == ACTION_EXPLODING ||
7295 action == ACTION_SMASHED_BY_ROCK ||
7296 action == ACTION_SMASHED_BY_SPRING) &&
7297 element != EL_DIAMOND);
7298 boolean action_active = (action == ACTION_ACTIVE);
7299 boolean action_other = (action == ACTION_OTHER);
7301 for (j = 0; j < 8; j++)
7303 int effective_element = get_effective_element_EM(i, j);
7304 int effective_action = (j < 7 ? action :
7305 i == Xdrip_stretch ? action :
7306 i == Xdrip_stretchB ? action :
7307 i == Ydrip_s1 ? action :
7308 i == Ydrip_s1B ? action :
7309 i == Xball_1B ? action :
7310 i == Xball_2 ? action :
7311 i == Xball_2B ? action :
7312 i == Yball_eat ? action :
7313 i == Ykey_1_eat ? action :
7314 i == Ykey_2_eat ? action :
7315 i == Ykey_3_eat ? action :
7316 i == Ykey_4_eat ? action :
7317 i == Ykey_5_eat ? action :
7318 i == Ykey_6_eat ? action :
7319 i == Ykey_7_eat ? action :
7320 i == Ykey_8_eat ? action :
7321 i == Ylenses_eat ? action :
7322 i == Ymagnify_eat ? action :
7323 i == Ygrass_eat ? action :
7324 i == Ydirt_eat ? action :
7325 i == Xsand_stonein_1 ? action :
7326 i == Xsand_stonein_2 ? action :
7327 i == Xsand_stonein_3 ? action :
7328 i == Xsand_stonein_4 ? action :
7329 i == Xsand_stoneout_1 ? action :
7330 i == Xsand_stoneout_2 ? action :
7331 i == Xboom_android ? ACTION_EXPLODING :
7332 action_exploding ? ACTION_EXPLODING :
7333 action_active ? action :
7334 action_other ? action :
7336 int graphic = (el_act_dir2img(effective_element, effective_action,
7338 int crumbled = (el_act_dir2crm(effective_element, effective_action,
7340 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
7341 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
7342 boolean has_action_graphics = (graphic != base_graphic);
7343 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
7344 struct GraphicInfo *g = &graphic_info[graphic];
7345 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
7348 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
7349 boolean special_animation = (action != ACTION_DEFAULT &&
7350 g->anim_frames == 3 &&
7351 g->anim_delay == 2 &&
7352 g->anim_mode & ANIM_LINEAR);
7353 int sync_frame = (i == Xdrip_stretch ? 7 :
7354 i == Xdrip_stretchB ? 7 :
7355 i == Ydrip_s2 ? j + 8 :
7356 i == Ydrip_s2B ? j + 8 :
7365 i == Xfake_acid_1 ? 0 :
7366 i == Xfake_acid_2 ? 10 :
7367 i == Xfake_acid_3 ? 20 :
7368 i == Xfake_acid_4 ? 30 :
7369 i == Xfake_acid_5 ? 40 :
7370 i == Xfake_acid_6 ? 50 :
7371 i == Xfake_acid_7 ? 60 :
7372 i == Xfake_acid_8 ? 70 :
7374 i == Xball_2B ? j + 8 :
7375 i == Yball_eat ? j + 1 :
7376 i == Ykey_1_eat ? j + 1 :
7377 i == Ykey_2_eat ? j + 1 :
7378 i == Ykey_3_eat ? j + 1 :
7379 i == Ykey_4_eat ? j + 1 :
7380 i == Ykey_5_eat ? j + 1 :
7381 i == Ykey_6_eat ? j + 1 :
7382 i == Ykey_7_eat ? j + 1 :
7383 i == Ykey_8_eat ? j + 1 :
7384 i == Ylenses_eat ? j + 1 :
7385 i == Ymagnify_eat ? j + 1 :
7386 i == Ygrass_eat ? j + 1 :
7387 i == Ydirt_eat ? j + 1 :
7388 i == Xamoeba_1 ? 0 :
7389 i == Xamoeba_2 ? 1 :
7390 i == Xamoeba_3 ? 2 :
7391 i == Xamoeba_4 ? 3 :
7392 i == Xamoeba_5 ? 0 :
7393 i == Xamoeba_6 ? 1 :
7394 i == Xamoeba_7 ? 2 :
7395 i == Xamoeba_8 ? 3 :
7396 i == Xexit_2 ? j + 8 :
7397 i == Xexit_3 ? j + 16 :
7398 i == Xdynamite_1 ? 0 :
7399 i == Xdynamite_2 ? 8 :
7400 i == Xdynamite_3 ? 16 :
7401 i == Xdynamite_4 ? 24 :
7402 i == Xsand_stonein_1 ? j + 1 :
7403 i == Xsand_stonein_2 ? j + 9 :
7404 i == Xsand_stonein_3 ? j + 17 :
7405 i == Xsand_stonein_4 ? j + 25 :
7406 i == Xsand_stoneout_1 && j == 0 ? 0 :
7407 i == Xsand_stoneout_1 && j == 1 ? 0 :
7408 i == Xsand_stoneout_1 && j == 2 ? 1 :
7409 i == Xsand_stoneout_1 && j == 3 ? 2 :
7410 i == Xsand_stoneout_1 && j == 4 ? 2 :
7411 i == Xsand_stoneout_1 && j == 5 ? 3 :
7412 i == Xsand_stoneout_1 && j == 6 ? 4 :
7413 i == Xsand_stoneout_1 && j == 7 ? 4 :
7414 i == Xsand_stoneout_2 && j == 0 ? 5 :
7415 i == Xsand_stoneout_2 && j == 1 ? 6 :
7416 i == Xsand_stoneout_2 && j == 2 ? 7 :
7417 i == Xsand_stoneout_2 && j == 3 ? 8 :
7418 i == Xsand_stoneout_2 && j == 4 ? 9 :
7419 i == Xsand_stoneout_2 && j == 5 ? 11 :
7420 i == Xsand_stoneout_2 && j == 6 ? 13 :
7421 i == Xsand_stoneout_2 && j == 7 ? 15 :
7422 i == Xboom_bug && j == 1 ? 2 :
7423 i == Xboom_bug && j == 2 ? 2 :
7424 i == Xboom_bug && j == 3 ? 4 :
7425 i == Xboom_bug && j == 4 ? 4 :
7426 i == Xboom_bug && j == 5 ? 2 :
7427 i == Xboom_bug && j == 6 ? 2 :
7428 i == Xboom_bug && j == 7 ? 0 :
7429 i == Xboom_bomb && j == 1 ? 2 :
7430 i == Xboom_bomb && j == 2 ? 2 :
7431 i == Xboom_bomb && j == 3 ? 4 :
7432 i == Xboom_bomb && j == 4 ? 4 :
7433 i == Xboom_bomb && j == 5 ? 2 :
7434 i == Xboom_bomb && j == 6 ? 2 :
7435 i == Xboom_bomb && j == 7 ? 0 :
7436 i == Xboom_android && j == 7 ? 6 :
7437 i == Xboom_1 && j == 1 ? 2 :
7438 i == Xboom_1 && j == 2 ? 2 :
7439 i == Xboom_1 && j == 3 ? 4 :
7440 i == Xboom_1 && j == 4 ? 4 :
7441 i == Xboom_1 && j == 5 ? 6 :
7442 i == Xboom_1 && j == 6 ? 6 :
7443 i == Xboom_1 && j == 7 ? 8 :
7444 i == Xboom_2 && j == 0 ? 8 :
7445 i == Xboom_2 && j == 1 ? 8 :
7446 i == Xboom_2 && j == 2 ? 10 :
7447 i == Xboom_2 && j == 3 ? 10 :
7448 i == Xboom_2 && j == 4 ? 10 :
7449 i == Xboom_2 && j == 5 ? 12 :
7450 i == Xboom_2 && j == 6 ? 12 :
7451 i == Xboom_2 && j == 7 ? 12 :
7452 special_animation && j == 4 ? 3 :
7453 effective_action != action ? 0 :
7457 Bitmap *debug_bitmap = g_em->bitmap;
7458 int debug_src_x = g_em->src_x;
7459 int debug_src_y = g_em->src_y;
7462 int frame = getAnimationFrame(g->anim_frames,
7465 g->anim_start_frame,
7468 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y,
7469 g->double_movement && is_backside);
7471 g_em->bitmap = src_bitmap;
7472 g_em->src_x = src_x;
7473 g_em->src_y = src_y;
7474 g_em->src_offset_x = 0;
7475 g_em->src_offset_y = 0;
7476 g_em->dst_offset_x = 0;
7477 g_em->dst_offset_y = 0;
7478 g_em->width = TILEX;
7479 g_em->height = TILEY;
7481 g_em->preserve_background = FALSE;
7483 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
7486 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
7487 effective_action == ACTION_MOVING ||
7488 effective_action == ACTION_PUSHING ||
7489 effective_action == ACTION_EATING)) ||
7490 (!has_action_graphics && (effective_action == ACTION_FILLING ||
7491 effective_action == ACTION_EMPTYING)))
7494 (effective_action == ACTION_FALLING ||
7495 effective_action == ACTION_FILLING ||
7496 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
7497 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
7498 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
7499 int num_steps = (i == Ydrip_s1 ? 16 :
7500 i == Ydrip_s1B ? 16 :
7501 i == Ydrip_s2 ? 16 :
7502 i == Ydrip_s2B ? 16 :
7503 i == Xsand_stonein_1 ? 32 :
7504 i == Xsand_stonein_2 ? 32 :
7505 i == Xsand_stonein_3 ? 32 :
7506 i == Xsand_stonein_4 ? 32 :
7507 i == Xsand_stoneout_1 ? 16 :
7508 i == Xsand_stoneout_2 ? 16 : 8);
7509 int cx = ABS(dx) * (TILEX / num_steps);
7510 int cy = ABS(dy) * (TILEY / num_steps);
7511 int step_frame = (i == Ydrip_s2 ? j + 8 :
7512 i == Ydrip_s2B ? j + 8 :
7513 i == Xsand_stonein_2 ? j + 8 :
7514 i == Xsand_stonein_3 ? j + 16 :
7515 i == Xsand_stonein_4 ? j + 24 :
7516 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
7517 int step = (is_backside ? step_frame : num_steps - step_frame);
7519 if (is_backside) /* tile where movement starts */
7521 if (dx < 0 || dy < 0)
7523 g_em->src_offset_x = cx * step;
7524 g_em->src_offset_y = cy * step;
7528 g_em->dst_offset_x = cx * step;
7529 g_em->dst_offset_y = cy * step;
7532 else /* tile where movement ends */
7534 if (dx < 0 || dy < 0)
7536 g_em->dst_offset_x = cx * step;
7537 g_em->dst_offset_y = cy * step;
7541 g_em->src_offset_x = cx * step;
7542 g_em->src_offset_y = cy * step;
7546 g_em->width = TILEX - cx * step;
7547 g_em->height = TILEY - cy * step;
7550 /* create unique graphic identifier to decide if tile must be redrawn */
7551 /* bit 31 - 16 (16 bit): EM style graphic
7552 bit 15 - 12 ( 4 bit): EM style frame
7553 bit 11 - 6 ( 6 bit): graphic width
7554 bit 5 - 0 ( 6 bit): graphic height */
7555 g_em->unique_identifier =
7556 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
7560 /* skip check for EMC elements not contained in original EMC artwork */
7561 if (element == EL_EMC_FAKE_ACID)
7564 if (g_em->bitmap != debug_bitmap ||
7565 g_em->src_x != debug_src_x ||
7566 g_em->src_y != debug_src_y ||
7567 g_em->src_offset_x != 0 ||
7568 g_em->src_offset_y != 0 ||
7569 g_em->dst_offset_x != 0 ||
7570 g_em->dst_offset_y != 0 ||
7571 g_em->width != TILEX ||
7572 g_em->height != TILEY)
7574 static int last_i = -1;
7582 printf("::: EMC GFX ERROR for element %d -> %d ('%s', '%s', %d)",
7583 i, element, element_info[element].token_name,
7584 element_action_info[effective_action].suffix, direction);
7586 if (element != effective_element)
7587 printf(" [%d ('%s')]",
7589 element_info[effective_element].token_name);
7593 if (g_em->bitmap != debug_bitmap)
7594 printf(" %d (%d): different bitmap! (0x%08x != 0x%08x)\n",
7595 j, is_backside, (int)(g_em->bitmap), (int)(debug_bitmap));
7597 if (g_em->src_x != debug_src_x ||
7598 g_em->src_y != debug_src_y)
7599 printf(" frame %d (%c): %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
7600 j, (is_backside ? 'B' : 'F'),
7601 g_em->src_x, g_em->src_y,
7602 g_em->src_x / 32, g_em->src_y / 32,
7603 debug_src_x, debug_src_y,
7604 debug_src_x / 32, debug_src_y / 32);
7606 if (g_em->src_offset_x != 0 ||
7607 g_em->src_offset_y != 0 ||
7608 g_em->dst_offset_x != 0 ||
7609 g_em->dst_offset_y != 0)
7610 printf(" %d (%d): offsets %d,%d and %d,%d should be all 0\n",
7612 g_em->src_offset_x, g_em->src_offset_y,
7613 g_em->dst_offset_x, g_em->dst_offset_y);
7615 if (g_em->width != TILEX ||
7616 g_em->height != TILEY)
7617 printf(" %d (%d): size %d,%d should be %d,%d\n",
7619 g_em->width, g_em->height, TILEX, TILEY);
7621 num_em_gfx_errors++;
7628 for (i = 0; i < TILE_MAX; i++)
7630 for (j = 0; j < 8; j++)
7632 int element = object_mapping[i].element_rnd;
7633 int action = object_mapping[i].action;
7634 int direction = object_mapping[i].direction;
7635 boolean is_backside = object_mapping[i].is_backside;
7636 int graphic_action = el_act_dir2img(element, action, direction);
7637 int graphic_default = el_act_dir2img(element, ACTION_DEFAULT, direction);
7639 if ((action == ACTION_SMASHED_BY_ROCK ||
7640 action == ACTION_SMASHED_BY_SPRING ||
7641 action == ACTION_EATING) &&
7642 graphic_action == graphic_default)
7644 int e = (action == ACTION_SMASHED_BY_ROCK ? Ystone_s :
7645 action == ACTION_SMASHED_BY_SPRING ? Yspring_s :
7646 direction == MV_LEFT ? (is_backside? Yspring_wB: Yspring_w) :
7647 direction == MV_RIGHT ? (is_backside? Yspring_eB: Yspring_e) :
7650 /* no separate animation for "smashed by rock" -- use rock instead */
7651 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
7652 struct GraphicInfo_EM *g_xx = &graphic_info_em_object[e][7 - j];
7654 g_em->bitmap = g_xx->bitmap;
7655 g_em->src_x = g_xx->src_x;
7656 g_em->src_y = g_xx->src_y;
7657 g_em->src_offset_x = g_xx->src_offset_x;
7658 g_em->src_offset_y = g_xx->src_offset_y;
7659 g_em->dst_offset_x = g_xx->dst_offset_x;
7660 g_em->dst_offset_y = g_xx->dst_offset_y;
7661 g_em->width = g_xx->width;
7662 g_em->height = g_xx->height;
7663 g_em->unique_identifier = g_xx->unique_identifier;
7666 g_em->preserve_background = TRUE;
7671 for (p = 0; p < MAX_PLAYERS; p++)
7673 for (i = 0; i < SPR_MAX; i++)
7675 int element = player_mapping[p][i].element_rnd;
7676 int action = player_mapping[p][i].action;
7677 int direction = player_mapping[p][i].direction;
7679 for (j = 0; j < 8; j++)
7681 int effective_element = element;
7682 int effective_action = action;
7683 int graphic = (direction == MV_NONE ?
7684 el_act2img(effective_element, effective_action) :
7685 el_act_dir2img(effective_element, effective_action,
7687 struct GraphicInfo *g = &graphic_info[graphic];
7688 struct GraphicInfo_EM *g_em = &graphic_info_em_player[p][i][7 - j];
7694 Bitmap *debug_bitmap = g_em->bitmap;
7695 int debug_src_x = g_em->src_x;
7696 int debug_src_y = g_em->src_y;
7699 int frame = getAnimationFrame(g->anim_frames,
7702 g->anim_start_frame,
7705 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
7707 g_em->bitmap = src_bitmap;
7708 g_em->src_x = src_x;
7709 g_em->src_y = src_y;
7710 g_em->src_offset_x = 0;
7711 g_em->src_offset_y = 0;
7712 g_em->dst_offset_x = 0;
7713 g_em->dst_offset_y = 0;
7714 g_em->width = TILEX;
7715 g_em->height = TILEY;
7719 /* skip check for EMC elements not contained in original EMC artwork */
7720 if (element == EL_PLAYER_3 ||
7721 element == EL_PLAYER_4)
7724 if (g_em->bitmap != debug_bitmap ||
7725 g_em->src_x != debug_src_x ||
7726 g_em->src_y != debug_src_y)
7728 static int last_i = -1;
7736 printf("::: EMC GFX ERROR for p/a %d/%d -> %d ('%s', '%s', %d)",
7737 p, i, element, element_info[element].token_name,
7738 element_action_info[effective_action].suffix, direction);
7740 if (element != effective_element)
7741 printf(" [%d ('%s')]",
7743 element_info[effective_element].token_name);
7747 if (g_em->bitmap != debug_bitmap)
7748 printf(" %d: different bitmap! (0x%08x != 0x%08x)\n",
7749 j, (int)(g_em->bitmap), (int)(debug_bitmap));
7751 if (g_em->src_x != debug_src_x ||
7752 g_em->src_y != debug_src_y)
7753 printf(" frame %d: %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
7755 g_em->src_x, g_em->src_y,
7756 g_em->src_x / 32, g_em->src_y / 32,
7757 debug_src_x, debug_src_y,
7758 debug_src_x / 32, debug_src_y / 32);
7760 num_em_gfx_errors++;
7770 printf("::: [%d errors found]\n", num_em_gfx_errors);
7776 void CheckSingleStepMode_EM(byte action[MAX_PLAYERS], int frame,
7777 boolean any_player_moving,
7778 boolean player_is_dropping)
7780 if (tape.single_step && tape.recording && !tape.pausing)
7781 if (frame == 0 && !player_is_dropping)
7782 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
7785 void CheckSingleStepMode_SP(boolean murphy_is_waiting,
7786 boolean murphy_is_dropping)
7788 if (tape.single_step && tape.recording && !tape.pausing)
7789 if (murphy_is_waiting)
7790 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
7793 void getGraphicSource_SP(struct GraphicInfo_SP *g_sp,
7794 int graphic, int sync_frame, int x, int y)
7796 int frame = getGraphicAnimationFrame(graphic, sync_frame);
7798 getGraphicSource(graphic, frame, &g_sp->bitmap, &g_sp->src_x, &g_sp->src_y);
7801 boolean isNextAnimationFrame_SP(int graphic, int sync_frame)
7803 return (IS_NEXT_FRAME(sync_frame, graphic));
7806 int getGraphicInfo_Delay(int graphic)
7808 return graphic_info[graphic].anim_delay;
7811 void PlayMenuSoundExt(int sound)
7813 if (sound == SND_UNDEFINED)
7816 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
7817 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
7820 if (IS_LOOP_SOUND(sound))
7821 PlaySoundLoop(sound);
7826 void PlayMenuSound()
7828 PlayMenuSoundExt(menu.sound[game_status]);
7831 void PlayMenuSoundStereo(int sound, int stereo_position)
7833 if (sound == SND_UNDEFINED)
7836 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
7837 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
7840 if (IS_LOOP_SOUND(sound))
7841 PlaySoundExt(sound, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_LOOP);
7843 PlaySoundStereo(sound, stereo_position);
7846 void PlayMenuSoundIfLoopExt(int sound)
7848 if (sound == SND_UNDEFINED)
7851 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
7852 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
7855 if (IS_LOOP_SOUND(sound))
7856 PlaySoundLoop(sound);
7859 void PlayMenuSoundIfLoop()
7861 PlayMenuSoundIfLoopExt(menu.sound[game_status]);
7864 void PlayMenuMusicExt(int music)
7866 if (music == MUS_UNDEFINED)
7869 if (!setup.sound_music)
7875 void PlayMenuMusic()
7877 PlayMenuMusicExt(menu.music[game_status]);
7880 void PlaySoundActivating()
7883 PlaySound(SND_MENU_ITEM_ACTIVATING);
7887 void PlaySoundSelecting()
7890 PlaySound(SND_MENU_ITEM_SELECTING);
7894 void ToggleFullscreenOrChangeWindowScalingIfNeeded()
7896 boolean change_fullscreen = (setup.fullscreen !=
7897 video.fullscreen_enabled);
7898 boolean change_fullscreen_mode = (video.fullscreen_enabled &&
7899 !strEqual(setup.fullscreen_mode,
7900 video.fullscreen_mode_current));
7901 boolean change_window_scaling_percent = (!video.fullscreen_enabled &&
7902 setup.window_scaling_percent !=
7903 video.window_scaling_percent);
7905 if (change_window_scaling_percent && video.fullscreen_enabled)
7908 if (!change_window_scaling_percent && !video.fullscreen_available)
7911 #if defined(TARGET_SDL2)
7912 if (change_window_scaling_percent)
7914 SDLSetWindowScaling(setup.window_scaling_percent);
7918 else if (change_fullscreen)
7920 SDLSetWindowFullscreen(setup.fullscreen);
7922 /* set setup value according to successfully changed fullscreen mode */
7923 setup.fullscreen = video.fullscreen_enabled;
7929 if (change_fullscreen ||
7930 change_fullscreen_mode ||
7931 change_window_scaling_percent)
7933 Bitmap *tmp_backbuffer = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
7935 /* save backbuffer content which gets lost when toggling fullscreen mode */
7936 BlitBitmap(backbuffer, tmp_backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
7938 if (change_fullscreen_mode)
7940 /* keep fullscreen, but change fullscreen mode (screen resolution) */
7941 video.fullscreen_enabled = FALSE; /* force new fullscreen mode */
7944 if (change_window_scaling_percent)
7946 /* keep window mode, but change window scaling */
7947 video.fullscreen_enabled = TRUE; /* force new window scaling */
7950 /* toggle fullscreen */
7951 ChangeVideoModeIfNeeded(setup.fullscreen);
7953 /* set setup value according to successfully changed fullscreen mode */
7954 setup.fullscreen = video.fullscreen_enabled;
7956 /* restore backbuffer content from temporary backbuffer backup bitmap */
7957 BlitBitmap(tmp_backbuffer, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
7959 FreeBitmap(tmp_backbuffer);
7961 /* update visible window/screen */
7962 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
7966 void ChangeViewportPropertiesIfNeeded()
7968 int gfx_game_mode = game_status;
7969 int gfx_game_mode2 = (game_status == GAME_MODE_EDITOR ? GAME_MODE_DEFAULT :
7971 struct RectWithBorder *vp_playfield = &viewport.playfield[gfx_game_mode];
7972 struct RectWithBorder *vp_door_1 = &viewport.door_1[gfx_game_mode];
7973 struct RectWithBorder *vp_door_2 = &viewport.door_2[gfx_game_mode2];
7974 struct RectWithBorder *vp_door_3 = &viewport.door_2[GAME_MODE_EDITOR];
7975 int border_size = vp_playfield->border_size;
7976 int new_sx = vp_playfield->x + border_size;
7977 int new_sy = vp_playfield->y + border_size;
7978 int new_sxsize = vp_playfield->width - 2 * border_size;
7979 int new_sysize = vp_playfield->height - 2 * border_size;
7980 int new_real_sx = vp_playfield->x;
7981 int new_real_sy = vp_playfield->y;
7982 int new_full_sxsize = vp_playfield->width;
7983 int new_full_sysize = vp_playfield->height;
7984 int new_dx = vp_door_1->x;
7985 int new_dy = vp_door_1->y;
7986 int new_dxsize = vp_door_1->width;
7987 int new_dysize = vp_door_1->height;
7988 int new_vx = vp_door_2->x;
7989 int new_vy = vp_door_2->y;
7990 int new_vxsize = vp_door_2->width;
7991 int new_vysize = vp_door_2->height;
7992 int new_ex = vp_door_3->x;
7993 int new_ey = vp_door_3->y;
7994 int new_exsize = vp_door_3->width;
7995 int new_eysize = vp_door_3->height;
7996 int new_tilesize_var =
7997 (setup.small_game_graphics ? MINI_TILESIZE : game.tile_size);
7999 int tilesize = (gfx_game_mode == GAME_MODE_PLAYING ? new_tilesize_var :
8000 gfx_game_mode == GAME_MODE_EDITOR ? MINI_TILESIZE : TILESIZE);
8001 int new_scr_fieldx = new_sxsize / tilesize;
8002 int new_scr_fieldy = new_sysize / tilesize;
8003 int new_scr_fieldx_buffers = new_sxsize / new_tilesize_var;
8004 int new_scr_fieldy_buffers = new_sysize / new_tilesize_var;
8005 boolean init_gfx_buffers = FALSE;
8006 boolean init_video_buffer = FALSE;
8007 boolean init_gadgets_and_toons = FALSE;
8008 boolean init_em_graphics = FALSE;
8010 if (viewport.window.width != WIN_XSIZE ||
8011 viewport.window.height != WIN_YSIZE)
8013 WIN_XSIZE = viewport.window.width;
8014 WIN_YSIZE = viewport.window.height;
8016 init_video_buffer = TRUE;
8017 init_gfx_buffers = TRUE;
8019 // printf("::: video: init_video_buffer, init_gfx_buffers\n");
8022 if (new_scr_fieldx != SCR_FIELDX ||
8023 new_scr_fieldy != SCR_FIELDY)
8025 /* this always toggles between MAIN and GAME when using small tile size */
8027 SCR_FIELDX = new_scr_fieldx;
8028 SCR_FIELDY = new_scr_fieldy;
8030 // printf("::: new_scr_fieldx != SCR_FIELDX ...\n");
8041 new_sxsize != SXSIZE ||
8042 new_sysize != SYSIZE ||
8043 new_dxsize != DXSIZE ||
8044 new_dysize != DYSIZE ||
8045 new_vxsize != VXSIZE ||
8046 new_vysize != VYSIZE ||
8047 new_exsize != EXSIZE ||
8048 new_eysize != EYSIZE ||
8049 new_real_sx != REAL_SX ||
8050 new_real_sy != REAL_SY ||
8051 new_full_sxsize != FULL_SXSIZE ||
8052 new_full_sysize != FULL_SYSIZE ||
8053 new_tilesize_var != TILESIZE_VAR
8056 if (new_tilesize_var != TILESIZE_VAR)
8058 // printf("::: new_tilesize_var != TILESIZE_VAR\n");
8060 // changing tile size invalidates scroll values of engine snapshots
8061 FreeEngineSnapshot();
8063 // changing tile size requires update of graphic mapping for EM engine
8064 init_em_graphics = TRUE;
8075 SXSIZE = new_sxsize;
8076 SYSIZE = new_sysize;
8077 DXSIZE = new_dxsize;
8078 DYSIZE = new_dysize;
8079 VXSIZE = new_vxsize;
8080 VYSIZE = new_vysize;
8081 EXSIZE = new_exsize;
8082 EYSIZE = new_eysize;
8083 REAL_SX = new_real_sx;
8084 REAL_SY = new_real_sy;
8085 FULL_SXSIZE = new_full_sxsize;
8086 FULL_SYSIZE = new_full_sysize;
8087 TILESIZE_VAR = new_tilesize_var;
8089 init_gfx_buffers = TRUE;
8090 init_gadgets_and_toons = TRUE;
8092 // printf("::: viewports: init_gfx_buffers\n");
8093 // printf("::: viewports: init_gadgets_and_toons\n");
8096 if (init_gfx_buffers)
8098 // printf("::: init_gfx_buffers\n");
8100 SCR_FIELDX = new_scr_fieldx_buffers;
8101 SCR_FIELDY = new_scr_fieldy_buffers;
8105 SCR_FIELDX = new_scr_fieldx;
8106 SCR_FIELDY = new_scr_fieldy;
8109 if (init_video_buffer)
8111 // printf("::: init_video_buffer\n");
8113 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
8115 SetDrawDeactivationMask(REDRAW_NONE);
8116 SetDrawBackgroundMask(REDRAW_FIELD);
8119 if (init_gadgets_and_toons)
8121 // printf("::: init_gadgets_and_toons\n");
8127 if (init_em_graphics)
8129 InitGraphicInfo_EM();