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,
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 src_x = g->src_x + (get_backside ? g->offset2_x : 0);
1055 int src_y = g->src_y + (get_backside ? g->offset2_y : 0);
1056 int tilesize_capped = MIN(MAX(1, tilesize), TILESIZE);
1058 if (tilesize == gfx.standard_tile_size)
1059 src_bitmap = g->bitmaps[IMG_BITMAP_STANDARD];
1060 else if (tilesize == game.tile_size)
1061 src_bitmap = g->bitmaps[IMG_BITMAP_GAME];
1063 src_bitmap = g->bitmaps[IMG_BITMAP_1x1 - log_2(tilesize_capped)];
1065 if (g->offset_y == 0) /* frames are ordered horizontally */
1067 int max_width = g->anim_frames_per_line * g->width;
1068 int pos = (src_y / g->height) * max_width + src_x + frame * g->offset_x;
1070 src_x = pos % max_width;
1071 src_y = src_y % g->height + pos / max_width * g->height;
1073 else if (g->offset_x == 0) /* frames are ordered vertically */
1075 int max_height = g->anim_frames_per_line * g->height;
1076 int pos = (src_x / g->width) * max_height + src_y + frame * g->offset_y;
1078 src_x = src_x % g->width + pos / max_height * g->width;
1079 src_y = pos % max_height;
1081 else /* frames are ordered diagonally */
1083 src_x = src_x + frame * g->offset_x;
1084 src_y = src_y + frame * g->offset_y;
1087 *bitmap = src_bitmap;
1088 *x = src_x * tilesize / TILESIZE;
1089 *y = src_y * tilesize / TILESIZE;
1092 void getFixedGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
1093 int *x, int *y, boolean get_backside)
1095 getSizedGraphicSourceExt(graphic, frame, TILESIZE, bitmap, x, y,
1099 void getSizedGraphicSource(int graphic, int frame, int tilesize,
1100 Bitmap **bitmap, int *x, int *y)
1102 getSizedGraphicSourceExt(graphic, frame, tilesize, bitmap, x, y, FALSE);
1105 void getFixedGraphicSource(int graphic, int frame,
1106 Bitmap **bitmap, int *x, int *y)
1108 getSizedGraphicSourceExt(graphic, frame, TILESIZE, bitmap, x, y, FALSE);
1111 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
1113 getSizedGraphicSource(graphic, 0, MINI_TILESIZE, bitmap, x, y);
1116 inline void getGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
1117 int *x, int *y, boolean get_backside)
1119 struct GraphicInfo *g = &graphic_info[graphic];
1120 int src_x = g->src_x + (get_backside ? g->offset2_x : 0);
1121 int src_y = g->src_y + (get_backside ? g->offset2_y : 0);
1123 if (TILESIZE_VAR != TILESIZE)
1124 return getSizedGraphicSourceExt(graphic, frame, TILESIZE_VAR, bitmap, x, y,
1127 *bitmap = g->bitmap;
1129 if (g->offset_y == 0) /* frames are ordered horizontally */
1131 int max_width = g->anim_frames_per_line * g->width;
1132 int pos = (src_y / g->height) * max_width + src_x + frame * g->offset_x;
1134 *x = pos % max_width;
1135 *y = src_y % g->height + pos / max_width * g->height;
1137 else if (g->offset_x == 0) /* frames are ordered vertically */
1139 int max_height = g->anim_frames_per_line * g->height;
1140 int pos = (src_x / g->width) * max_height + src_y + frame * g->offset_y;
1142 *x = src_x % g->width + pos / max_height * g->width;
1143 *y = pos % max_height;
1145 else /* frames are ordered diagonally */
1147 *x = src_x + frame * g->offset_x;
1148 *y = src_y + frame * g->offset_y;
1152 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
1154 getGraphicSourceExt(graphic, frame, bitmap, x, y, FALSE);
1157 void DrawGraphic(int x, int y, int graphic, int frame)
1160 if (!IN_SCR_FIELD(x, y))
1162 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
1163 printf("DrawGraphic(): This should never happen!\n");
1168 DrawGraphicExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR, graphic,
1171 MarkTileDirty(x, y);
1174 void DrawFixedGraphic(int x, int y, int graphic, int frame)
1177 if (!IN_SCR_FIELD(x, y))
1179 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
1180 printf("DrawGraphic(): This should never happen!\n");
1185 DrawFixedGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic,
1187 MarkTileDirty(x, y);
1190 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
1196 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1198 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX_VAR, TILEY_VAR, x, y);
1201 void DrawFixedGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
1207 getFixedGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1208 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
1211 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
1214 if (!IN_SCR_FIELD(x, y))
1216 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
1217 printf("DrawGraphicThruMask(): This should never happen!\n");
1222 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR,
1225 MarkTileDirty(x, y);
1228 void DrawFixedGraphicThruMask(int x, int y, int graphic, int frame)
1231 if (!IN_SCR_FIELD(x, y))
1233 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
1234 printf("DrawGraphicThruMask(): This should never happen!\n");
1239 DrawFixedGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
1241 MarkTileDirty(x, y);
1244 void DrawGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y, int graphic,
1250 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1252 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1253 dst_x - src_x, dst_y - src_y);
1255 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX_VAR, TILEY_VAR,
1259 void DrawFixedGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y,
1260 int graphic, int frame)
1265 getFixedGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1267 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1268 dst_x - src_x, dst_y - src_y);
1269 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dst_x, dst_y);
1272 void DrawSizedGraphic(int x, int y, int graphic, int frame, int tilesize)
1274 DrawSizedGraphicExt(drawto, SX + x * tilesize, SY + y * tilesize, graphic,
1276 MarkTileDirty(x / tilesize, y / tilesize);
1279 void DrawSizedGraphicExt(DrawBuffer *d, int x, int y, int graphic, int frame,
1285 getSizedGraphicSource(graphic, frame, tilesize, &src_bitmap, &src_x, &src_y);
1286 BlitBitmap(src_bitmap, d, src_x, src_y, tilesize, tilesize, x, y);
1289 void DrawMiniGraphic(int x, int y, int graphic)
1291 DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
1292 MarkTileDirty(x / 2, y / 2);
1295 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
1300 getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1301 BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
1304 inline static void DrawGraphicShiftedNormal(int x, int y, int dx, int dy,
1305 int graphic, int frame,
1306 int cut_mode, int mask_mode)
1311 int width = TILEX, height = TILEY;
1314 if (dx || dy) /* shifted graphic */
1316 if (x < BX1) /* object enters playfield from the left */
1323 else if (x > BX2) /* object enters playfield from the right */
1329 else if (x==BX1 && dx < 0) /* object leaves playfield to the left */
1335 else if (x==BX2 && dx > 0) /* object leaves playfield to the right */
1337 else if (dx) /* general horizontal movement */
1338 MarkTileDirty(x + SIGN(dx), y);
1340 if (y < BY1) /* object enters playfield from the top */
1342 if (cut_mode==CUT_BELOW) /* object completely above top border */
1350 else if (y > BY2) /* object enters playfield from the bottom */
1356 else if (y==BY1 && dy < 0) /* object leaves playfield to the top */
1362 else if (dy > 0 && cut_mode == CUT_ABOVE)
1364 if (y == BY2) /* object completely above bottom border */
1370 MarkTileDirty(x, y + 1);
1371 } /* object leaves playfield to the bottom */
1372 else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
1374 else if (dy) /* general vertical movement */
1375 MarkTileDirty(x, y + SIGN(dy));
1379 if (!IN_SCR_FIELD(x, y))
1381 printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
1382 printf("DrawGraphicShifted(): This should never happen!\n");
1387 width = width * TILESIZE_VAR / TILESIZE;
1388 height = height * TILESIZE_VAR / TILESIZE;
1389 cx = cx * TILESIZE_VAR / TILESIZE;
1390 cy = cy * TILESIZE_VAR / TILESIZE;
1391 dx = dx * TILESIZE_VAR / TILESIZE;
1392 dy = dy * TILESIZE_VAR / TILESIZE;
1394 if (width > 0 && height > 0)
1396 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1401 dst_x = FX + x * TILEX_VAR + dx;
1402 dst_y = FY + y * TILEY_VAR + dy;
1404 if (mask_mode == USE_MASKING)
1406 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1407 dst_x - src_x, dst_y - src_y);
1408 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1412 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1415 MarkTileDirty(x, y);
1419 inline static void DrawGraphicShiftedDouble(int x, int y, int dx, int dy,
1420 int graphic, int frame,
1421 int cut_mode, int mask_mode)
1426 int width = TILEX_VAR, height = TILEY_VAR;
1429 int x2 = x + SIGN(dx);
1430 int y2 = y + SIGN(dy);
1432 /* movement with two-tile animations must be sync'ed with movement position,
1433 not with current GfxFrame (which can be higher when using slow movement) */
1434 int anim_pos = (dx ? ABS(dx) : ABS(dy));
1435 int anim_frames = graphic_info[graphic].anim_frames;
1437 /* (we also need anim_delay here for movement animations with less frames) */
1438 int anim_delay = graphic_info[graphic].anim_delay;
1439 int sync_frame = anim_pos * anim_frames * anim_delay / TILESIZE;
1441 boolean draw_start_tile = (cut_mode != CUT_ABOVE); /* only for falling! */
1442 boolean draw_end_tile = (cut_mode != CUT_BELOW); /* only for falling! */
1444 /* re-calculate animation frame for two-tile movement animation */
1445 frame = getGraphicAnimationFrame(graphic, sync_frame);
1447 /* check if movement start graphic inside screen area and should be drawn */
1448 if (draw_start_tile && IN_SCR_FIELD(x1, y1))
1450 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, TRUE);
1452 dst_x = FX + x1 * TILEX_VAR;
1453 dst_y = FY + y1 * TILEY_VAR;
1455 if (mask_mode == USE_MASKING)
1457 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1458 dst_x - src_x, dst_y - src_y);
1459 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1463 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1466 MarkTileDirty(x1, y1);
1469 /* check if movement end graphic inside screen area and should be drawn */
1470 if (draw_end_tile && IN_SCR_FIELD(x2, y2))
1472 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
1474 dst_x = FX + x2 * TILEX_VAR;
1475 dst_y = FY + y2 * TILEY_VAR;
1477 if (mask_mode == USE_MASKING)
1479 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1480 dst_x - src_x, dst_y - src_y);
1481 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1485 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1488 MarkTileDirty(x2, y2);
1492 static void DrawGraphicShifted(int x, int y, int dx, int dy,
1493 int graphic, int frame,
1494 int cut_mode, int mask_mode)
1498 DrawGraphic(x, y, graphic, frame);
1503 if (graphic_info[graphic].double_movement) /* EM style movement images */
1504 DrawGraphicShiftedDouble(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1506 DrawGraphicShiftedNormal(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1509 void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
1510 int frame, int cut_mode)
1512 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, USE_MASKING);
1515 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
1516 int cut_mode, int mask_mode)
1518 int lx = LEVELX(x), ly = LEVELY(y);
1522 if (IN_LEV_FIELD(lx, ly))
1524 SetRandomAnimationValue(lx, ly);
1526 graphic = el_act_dir2img(element, GfxAction[lx][ly], GfxDir[lx][ly]);
1527 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1529 /* do not use double (EM style) movement graphic when not moving */
1530 if (graphic_info[graphic].double_movement && !dx && !dy)
1532 graphic = el_act_dir2img(element, ACTION_DEFAULT, GfxDir[lx][ly]);
1533 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1536 else /* border element */
1538 graphic = el2img(element);
1539 frame = getGraphicAnimationFrame(graphic, -1);
1542 if (element == EL_EXPANDABLE_WALL)
1544 boolean left_stopped = FALSE, right_stopped = FALSE;
1546 if (!IN_LEV_FIELD(lx - 1, ly) || IS_WALL(Feld[lx - 1][ly]))
1547 left_stopped = TRUE;
1548 if (!IN_LEV_FIELD(lx + 1, ly) || IS_WALL(Feld[lx + 1][ly]))
1549 right_stopped = TRUE;
1551 if (left_stopped && right_stopped)
1553 else if (left_stopped)
1555 graphic = IMG_EXPANDABLE_WALL_GROWING_RIGHT;
1556 frame = graphic_info[graphic].anim_frames - 1;
1558 else if (right_stopped)
1560 graphic = IMG_EXPANDABLE_WALL_GROWING_LEFT;
1561 frame = graphic_info[graphic].anim_frames - 1;
1566 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
1567 else if (mask_mode == USE_MASKING)
1568 DrawGraphicThruMask(x, y, graphic, frame);
1570 DrawGraphic(x, y, graphic, frame);
1573 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
1574 int cut_mode, int mask_mode)
1576 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1577 DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
1578 cut_mode, mask_mode);
1581 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
1584 DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1587 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
1590 DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1593 void DrawLevelElementThruMask(int x, int y, int element)
1595 DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1598 void DrawLevelFieldThruMask(int x, int y)
1600 DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
1603 /* !!! implementation of quicksand is totally broken !!! */
1604 #define IS_CRUMBLED_TILE(x, y, e) \
1605 (GFX_CRUMBLED(e) && (!IN_LEV_FIELD(x, y) || \
1606 !IS_MOVING(x, y) || \
1607 (e) == EL_QUICKSAND_EMPTYING || \
1608 (e) == EL_QUICKSAND_FAST_EMPTYING))
1610 static void DrawLevelFieldCrumbledInnerCorners(int x, int y, int dx, int dy,
1615 int width, height, cx, cy;
1616 int sx = SCREENX(x), sy = SCREENY(y);
1617 int crumbled_border_size = graphic_info[graphic].border_size;
1620 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1622 for (i = 1; i < 4; i++)
1624 int dxx = (i & 1 ? dx : 0);
1625 int dyy = (i & 2 ? dy : 0);
1628 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1631 /* check if neighbour field is of same crumble type */
1632 boolean same = (IS_CRUMBLED_TILE(xx, yy, element) &&
1633 graphic_info[graphic].class ==
1634 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class);
1636 /* return if check prevents inner corner */
1637 if (same == (dxx == dx && dyy == dy))
1641 /* if we reach this point, we have an inner corner */
1643 getGraphicSource(graphic, 1, &src_bitmap, &src_x, &src_y);
1645 width = crumbled_border_size * TILESIZE_VAR / TILESIZE;
1646 height = crumbled_border_size * TILESIZE_VAR / TILESIZE;
1647 cx = (dx > 0 ? TILESIZE_VAR - width : 0);
1648 cy = (dy > 0 ? TILESIZE_VAR - height : 0);
1650 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1651 width, height, FX + sx * TILEX_VAR + cx, FY + sy * TILEY_VAR + cy);
1654 static void DrawLevelFieldCrumbledBorders(int x, int y, int graphic, int frame,
1659 int width, height, bx, by, cx, cy;
1660 int sx = SCREENX(x), sy = SCREENY(y);
1661 int crumbled_border_size = graphic_info[graphic].border_size;
1662 int crumbled_border_size_var = crumbled_border_size * TILESIZE_VAR / TILESIZE;
1663 int crumbled_border_pos_var = TILESIZE_VAR - crumbled_border_size_var;
1666 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1668 /* draw simple, sloppy, non-corner-accurate crumbled border */
1670 width = (dir == 1 || dir == 2 ? crumbled_border_size_var : TILESIZE_VAR);
1671 height = (dir == 0 || dir == 3 ? crumbled_border_size_var : TILESIZE_VAR);
1672 cx = (dir == 2 ? crumbled_border_pos_var : 0);
1673 cy = (dir == 3 ? crumbled_border_pos_var : 0);
1675 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy, width, height,
1676 FX + sx * TILEX_VAR + cx,
1677 FY + sy * TILEY_VAR + cy);
1679 /* (remaining middle border part must be at least as big as corner part) */
1680 if (!(graphic_info[graphic].style & STYLE_ACCURATE_BORDERS) ||
1681 crumbled_border_size >= TILESIZE / 3)
1684 /* correct corners of crumbled border, if needed */
1686 for (i = -1; i <= 1; i += 2)
1688 int xx = x + (dir == 0 || dir == 3 ? i : 0);
1689 int yy = y + (dir == 1 || dir == 2 ? i : 0);
1690 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1693 /* check if neighbour field is of same crumble type */
1694 if (IS_CRUMBLED_TILE(xx, yy, element) &&
1695 graphic_info[graphic].class ==
1696 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
1698 /* no crumbled corner, but continued crumbled border */
1700 int c1 = (dir == 2 || dir == 3 ? crumbled_border_pos_var : 0);
1701 int c2 = (i == 1 ? crumbled_border_pos_var : 0);
1702 int b1 = (i == 1 ? crumbled_border_size_var :
1703 TILESIZE_VAR - 2 * crumbled_border_size_var);
1705 width = crumbled_border_size_var;
1706 height = crumbled_border_size_var;
1708 if (dir == 1 || dir == 2)
1723 BlitBitmap(src_bitmap, drawto_field, src_x + bx, src_y + by,
1725 FX + sx * TILEX_VAR + cx,
1726 FY + sy * TILEY_VAR + cy);
1731 static void DrawLevelFieldCrumbledExt(int x, int y, int graphic, int frame)
1733 int sx = SCREENX(x), sy = SCREENY(y);
1736 static int xy[4][2] =
1744 if (!IN_LEV_FIELD(x, y))
1747 element = TILE_GFX_ELEMENT(x, y);
1749 /* crumble field itself */
1750 if (IS_CRUMBLED_TILE(x, y, element))
1752 if (!IN_SCR_FIELD(sx, sy))
1755 for (i = 0; i < 4; i++)
1757 int xx = x + xy[i][0];
1758 int yy = y + xy[i][1];
1760 element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1763 /* check if neighbour field is of same crumble type */
1764 if (IS_CRUMBLED_TILE(xx, yy, element) &&
1765 graphic_info[graphic].class ==
1766 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
1769 DrawLevelFieldCrumbledBorders(x, y, graphic, frame, i);
1772 if ((graphic_info[graphic].style & STYLE_INNER_CORNERS) &&
1773 graphic_info[graphic].anim_frames == 2)
1775 for (i = 0; i < 4; i++)
1777 int dx = (i & 1 ? +1 : -1);
1778 int dy = (i & 2 ? +1 : -1);
1780 DrawLevelFieldCrumbledInnerCorners(x, y, dx, dy, graphic);
1784 MarkTileDirty(sx, sy);
1786 else /* center field not crumbled -- crumble neighbour fields */
1788 for (i = 0; i < 4; i++)
1790 int xx = x + xy[i][0];
1791 int yy = y + xy[i][1];
1792 int sxx = sx + xy[i][0];
1793 int syy = sy + xy[i][1];
1795 if (!IN_LEV_FIELD(xx, yy) ||
1796 !IN_SCR_FIELD(sxx, syy))
1799 if (Feld[xx][yy] == EL_ELEMENT_SNAPPING)
1802 element = TILE_GFX_ELEMENT(xx, yy);
1804 if (!IS_CRUMBLED_TILE(xx, yy, element))
1807 graphic = el_act2crm(element, ACTION_DEFAULT);
1809 DrawLevelFieldCrumbledBorders(xx, yy, graphic, 0, 3 - i);
1811 MarkTileDirty(sxx, syy);
1816 void DrawLevelFieldCrumbled(int x, int y)
1820 if (!IN_LEV_FIELD(x, y))
1823 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
1824 GfxElement[x][y] != EL_UNDEFINED &&
1825 GFX_CRUMBLED(GfxElement[x][y]))
1827 DrawLevelFieldCrumbledDigging(x, y, GfxDir[x][y], GfxFrame[x][y]);
1832 graphic = el_act2crm(TILE_GFX_ELEMENT(x, y), ACTION_DEFAULT);
1834 DrawLevelFieldCrumbledExt(x, y, graphic, 0);
1837 void DrawLevelFieldCrumbledDigging(int x, int y, int direction,
1840 int graphic1 = el_act_dir2img(GfxElement[x][y], ACTION_DIGGING, direction);
1841 int graphic2 = el_act_dir2crm(GfxElement[x][y], ACTION_DIGGING, direction);
1842 int frame1 = getGraphicAnimationFrame(graphic1, step_frame);
1843 int frame2 = getGraphicAnimationFrame(graphic2, step_frame);
1844 int sx = SCREENX(x), sy = SCREENY(y);
1846 DrawGraphic(sx, sy, graphic1, frame1);
1847 DrawLevelFieldCrumbledExt(x, y, graphic2, frame2);
1850 void DrawLevelFieldCrumbledNeighbours(int x, int y)
1852 int sx = SCREENX(x), sy = SCREENY(y);
1853 static int xy[4][2] =
1862 for (i = 0; i < 4; i++)
1864 int xx = x + xy[i][0];
1865 int yy = y + xy[i][1];
1866 int sxx = sx + xy[i][0];
1867 int syy = sy + xy[i][1];
1869 if (!IN_LEV_FIELD(xx, yy) ||
1870 !IN_SCR_FIELD(sxx, syy) ||
1871 !GFX_CRUMBLED(Feld[xx][yy]) ||
1875 DrawLevelField(xx, yy);
1879 static int getBorderElement(int x, int y)
1883 { EL_STEELWALL_TOPLEFT, EL_INVISIBLE_STEELWALL_TOPLEFT },
1884 { EL_STEELWALL_TOPRIGHT, EL_INVISIBLE_STEELWALL_TOPRIGHT },
1885 { EL_STEELWALL_BOTTOMLEFT, EL_INVISIBLE_STEELWALL_BOTTOMLEFT },
1886 { EL_STEELWALL_BOTTOMRIGHT, EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
1887 { EL_STEELWALL_VERTICAL, EL_INVISIBLE_STEELWALL_VERTICAL },
1888 { EL_STEELWALL_HORIZONTAL, EL_INVISIBLE_STEELWALL_HORIZONTAL },
1889 { EL_STEELWALL, EL_INVISIBLE_STEELWALL }
1891 int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
1892 int steel_position = (x == -1 && y == -1 ? 0 :
1893 x == lev_fieldx && y == -1 ? 1 :
1894 x == -1 && y == lev_fieldy ? 2 :
1895 x == lev_fieldx && y == lev_fieldy ? 3 :
1896 x == -1 || x == lev_fieldx ? 4 :
1897 y == -1 || y == lev_fieldy ? 5 : 6);
1899 return border[steel_position][steel_type];
1902 void DrawScreenElement(int x, int y, int element)
1904 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
1905 DrawLevelFieldCrumbled(LEVELX(x), LEVELY(y));
1908 void DrawLevelElement(int x, int y, int element)
1910 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1911 DrawScreenElement(SCREENX(x), SCREENY(y), element);
1914 void DrawScreenField(int x, int y)
1916 int lx = LEVELX(x), ly = LEVELY(y);
1917 int element, content;
1919 if (!IN_LEV_FIELD(lx, ly))
1921 if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
1924 element = getBorderElement(lx, ly);
1926 DrawScreenElement(x, y, element);
1931 element = Feld[lx][ly];
1932 content = Store[lx][ly];
1934 if (IS_MOVING(lx, ly))
1936 int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
1937 boolean cut_mode = NO_CUTTING;
1939 if (element == EL_QUICKSAND_EMPTYING ||
1940 element == EL_QUICKSAND_FAST_EMPTYING ||
1941 element == EL_MAGIC_WALL_EMPTYING ||
1942 element == EL_BD_MAGIC_WALL_EMPTYING ||
1943 element == EL_DC_MAGIC_WALL_EMPTYING ||
1944 element == EL_AMOEBA_DROPPING)
1945 cut_mode = CUT_ABOVE;
1946 else if (element == EL_QUICKSAND_FILLING ||
1947 element == EL_QUICKSAND_FAST_FILLING ||
1948 element == EL_MAGIC_WALL_FILLING ||
1949 element == EL_BD_MAGIC_WALL_FILLING ||
1950 element == EL_DC_MAGIC_WALL_FILLING)
1951 cut_mode = CUT_BELOW;
1953 if (cut_mode == CUT_ABOVE)
1954 DrawScreenElement(x, y, element);
1956 DrawScreenElement(x, y, EL_EMPTY);
1959 DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
1960 else if (cut_mode == NO_CUTTING)
1961 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
1964 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
1966 if (cut_mode == CUT_BELOW &&
1967 IN_LEV_FIELD(lx, ly + 1) && IN_SCR_FIELD(x, y + 1))
1968 DrawLevelElement(lx, ly + 1, element);
1971 if (content == EL_ACID)
1973 int dir = MovDir[lx][ly];
1974 int newlx = lx + (dir == MV_LEFT ? -1 : dir == MV_RIGHT ? +1 : 0);
1975 int newly = ly + (dir == MV_UP ? -1 : dir == MV_DOWN ? +1 : 0);
1977 DrawLevelElementThruMask(newlx, newly, EL_ACID);
1980 else if (IS_BLOCKED(lx, ly))
1985 boolean cut_mode = NO_CUTTING;
1986 int element_old, content_old;
1988 Blocked2Moving(lx, ly, &oldx, &oldy);
1991 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
1992 MovDir[oldx][oldy] == MV_RIGHT);
1994 element_old = Feld[oldx][oldy];
1995 content_old = Store[oldx][oldy];
1997 if (element_old == EL_QUICKSAND_EMPTYING ||
1998 element_old == EL_QUICKSAND_FAST_EMPTYING ||
1999 element_old == EL_MAGIC_WALL_EMPTYING ||
2000 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
2001 element_old == EL_DC_MAGIC_WALL_EMPTYING ||
2002 element_old == EL_AMOEBA_DROPPING)
2003 cut_mode = CUT_ABOVE;
2005 DrawScreenElement(x, y, EL_EMPTY);
2008 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
2010 else if (cut_mode == NO_CUTTING)
2011 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
2014 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
2017 else if (IS_DRAWABLE(element))
2018 DrawScreenElement(x, y, element);
2020 DrawScreenElement(x, y, EL_EMPTY);
2023 void DrawLevelField(int x, int y)
2025 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
2026 DrawScreenField(SCREENX(x), SCREENY(y));
2027 else if (IS_MOVING(x, y))
2031 Moving2Blocked(x, y, &newx, &newy);
2032 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
2033 DrawScreenField(SCREENX(newx), SCREENY(newy));
2035 else if (IS_BLOCKED(x, y))
2039 Blocked2Moving(x, y, &oldx, &oldy);
2040 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
2041 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
2045 void DrawMiniElement(int x, int y, int element)
2049 graphic = el2edimg(element);
2050 DrawMiniGraphic(x, y, graphic);
2053 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
2055 int x = sx + scroll_x, y = sy + scroll_y;
2057 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
2058 DrawMiniElement(sx, sy, EL_EMPTY);
2059 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
2060 DrawMiniElement(sx, sy, Feld[x][y]);
2062 DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
2065 void DrawEnvelopeBackgroundTiles(int graphic, int startx, int starty,
2066 int x, int y, int xsize, int ysize,
2067 int tile_width, int tile_height)
2071 int dst_x = startx + x * tile_width;
2072 int dst_y = starty + y * tile_height;
2073 int width = graphic_info[graphic].width;
2074 int height = graphic_info[graphic].height;
2075 int inner_width_raw = MAX(width - 2 * tile_width, tile_width);
2076 int inner_height_raw = MAX(height - 2 * tile_height, tile_height);
2077 int inner_width = inner_width_raw - (inner_width_raw % tile_width);
2078 int inner_height = inner_height_raw - (inner_height_raw % tile_height);
2079 int inner_sx = (width >= 3 * tile_width ? tile_width : 0);
2080 int inner_sy = (height >= 3 * tile_height ? tile_height : 0);
2081 boolean draw_masked = graphic_info[graphic].draw_masked;
2083 getFixedGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
2085 if (src_bitmap == NULL || width < tile_width || height < tile_height)
2087 ClearRectangle(drawto, dst_x, dst_y, tile_width, tile_height);
2091 src_x += (x == 0 ? 0 : x == xsize - 1 ? width - tile_width :
2092 inner_sx + (x - 1) * tile_width % inner_width);
2093 src_y += (y == 0 ? 0 : y == ysize - 1 ? height - tile_height :
2094 inner_sy + (y - 1) * tile_height % inner_height);
2098 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
2099 dst_x - src_x, dst_y - src_y);
2100 BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, tile_width, tile_height,
2104 BlitBitmap(src_bitmap, drawto, src_x, src_y, tile_width, tile_height,
2108 void DrawEnvelopeBackground(int graphic, int startx, int starty,
2109 int x, int y, int xsize, int ysize, int font_nr)
2111 int font_width = getFontWidth(font_nr);
2112 int font_height = getFontHeight(font_nr);
2114 DrawEnvelopeBackgroundTiles(graphic, startx, starty, x, y, xsize, ysize,
2115 font_width, font_height);
2118 void AnimateEnvelope(int envelope_nr, int anim_mode, int action)
2120 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2121 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
2122 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
2123 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2124 boolean no_delay = (tape.warp_forward);
2125 unsigned int anim_delay = 0;
2126 int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
2127 int anim_delay_value = (no_delay ? 0 : frame_delay_value);
2128 int font_nr = FONT_ENVELOPE_1 + envelope_nr;
2129 int font_width = getFontWidth(font_nr);
2130 int font_height = getFontHeight(font_nr);
2131 int max_xsize = level.envelope[envelope_nr].xsize;
2132 int max_ysize = level.envelope[envelope_nr].ysize;
2133 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
2134 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
2135 int xend = max_xsize;
2136 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
2137 int xstep = (xstart < xend ? 1 : 0);
2138 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
2141 for (x = xstart, y = ystart; x <= xend && y <= yend; x += xstep, y += ystep)
2143 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
2144 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
2145 int sx = SX + (SXSIZE - xsize * font_width) / 2;
2146 int sy = SY + (SYSIZE - ysize * font_height) / 2;
2149 SetDrawtoField(DRAW_BUFFERED);
2151 BlitScreenToBitmap(backbuffer);
2153 SetDrawtoField(DRAW_BACKBUFFER);
2155 for (yy = 0; yy < ysize; yy++)
2156 for (xx = 0; xx < xsize; xx++)
2157 DrawEnvelopeBackground(graphic, sx, sy, xx, yy, xsize, ysize, font_nr);
2159 DrawTextBuffer(sx + font_width, sy + font_height,
2160 level.envelope[envelope_nr].text, font_nr, max_xsize,
2161 xsize - 2, ysize - 2, 0, mask_mode,
2162 level.envelope[envelope_nr].autowrap,
2163 level.envelope[envelope_nr].centered, FALSE);
2165 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
2168 WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
2172 void ShowEnvelope(int envelope_nr)
2174 int element = EL_ENVELOPE_1 + envelope_nr;
2175 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2176 int sound_opening = element_info[element].sound[ACTION_OPENING];
2177 int sound_closing = element_info[element].sound[ACTION_CLOSING];
2178 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2179 boolean no_delay = (tape.warp_forward);
2180 int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
2181 int wait_delay_value = (no_delay ? 0 : normal_delay_value);
2182 int anim_mode = graphic_info[graphic].anim_mode;
2183 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
2184 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
2186 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
2188 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
2190 if (anim_mode == ANIM_DEFAULT)
2191 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_OPENING);
2193 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_OPENING);
2196 Delay(wait_delay_value);
2198 WaitForEventToContinue();
2200 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
2202 if (anim_mode != ANIM_NONE)
2203 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_CLOSING);
2205 if (anim_mode == ANIM_DEFAULT)
2206 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_CLOSING);
2208 game.envelope_active = FALSE;
2210 SetDrawtoField(DRAW_BUFFERED);
2212 redraw_mask |= REDRAW_FIELD;
2216 static void setRequestPosition(int *x, int *y, boolean add_border_size)
2218 int border_size = request.border_size;
2219 int sx_center = (request.x != -1 ? request.x : SX + SXSIZE / 2);
2220 int sy_center = (request.y != -1 ? request.y : SY + SYSIZE / 2);
2221 int sx = sx_center - request.width / 2;
2222 int sy = sy_center - request.height / 2;
2224 if (add_border_size)
2234 void DrawEnvelopeRequest(char *text)
2236 char *text_final = text;
2237 char *text_door_style = NULL;
2238 int graphic = IMG_BACKGROUND_REQUEST;
2239 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
2240 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
2241 int font_nr = FONT_REQUEST;
2242 int font_width = getFontWidth(font_nr);
2243 int font_height = getFontHeight(font_nr);
2244 int border_size = request.border_size;
2245 int line_spacing = request.line_spacing;
2246 int line_height = font_height + line_spacing;
2247 int text_width = request.width - 2 * border_size;
2248 int text_height = request.height - 2 * border_size;
2249 int line_length = text_width / font_width;
2250 int max_lines = text_height / line_height;
2251 int width = request.width;
2252 int height = request.height;
2253 int tile_size = request.step_offset;
2254 int x_steps = width / tile_size;
2255 int y_steps = height / tile_size;
2259 if (request.wrap_single_words)
2261 char *src_text_ptr, *dst_text_ptr;
2263 text_door_style = checked_malloc(2 * strlen(text) + 1);
2265 src_text_ptr = text;
2266 dst_text_ptr = text_door_style;
2268 while (*src_text_ptr)
2270 if (*src_text_ptr == ' ' ||
2271 *src_text_ptr == '?' ||
2272 *src_text_ptr == '!')
2273 *dst_text_ptr++ = '\n';
2275 if (*src_text_ptr != ' ')
2276 *dst_text_ptr++ = *src_text_ptr;
2281 *dst_text_ptr = '\0';
2283 text_final = text_door_style;
2286 setRequestPosition(&sx, &sy, FALSE);
2288 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
2290 for (y = 0; y < y_steps; y++)
2291 for (x = 0; x < x_steps; x++)
2292 DrawEnvelopeBackgroundTiles(graphic, sx, sy,
2293 x, y, x_steps, y_steps,
2294 tile_size, tile_size);
2296 DrawTextBuffer(sx + border_size, sy + border_size, text_final, font_nr,
2297 line_length, -1, max_lines, line_spacing, mask_mode,
2298 request.autowrap, request.centered, FALSE);
2300 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
2301 RedrawGadget(tool_gadget[i]);
2303 // store readily prepared envelope request for later use when animating
2304 BlitBitmap(backbuffer, bitmap_db_cross, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2306 if (text_door_style)
2307 free(text_door_style);
2310 void AnimateEnvelopeRequest(int anim_mode, int action)
2312 int graphic = IMG_BACKGROUND_REQUEST;
2313 boolean draw_masked = graphic_info[graphic].draw_masked;
2314 int delay_value_normal = request.step_delay;
2315 int delay_value_fast = delay_value_normal / 2;
2316 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2317 boolean no_delay = (tape.warp_forward);
2318 int delay_value = (ffwd_delay ? delay_value_fast : delay_value_normal);
2319 int anim_delay_value = (no_delay ? 0 : delay_value + 500 * 0);
2320 unsigned int anim_delay = 0;
2322 int width = request.width;
2323 int height = request.height;
2324 int tile_size = request.step_offset;
2325 int max_xsize = width / tile_size;
2326 int max_ysize = height / tile_size;
2327 int max_xsize_inner = max_xsize - 2;
2328 int max_ysize_inner = max_ysize - 2;
2330 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize_inner : 0);
2331 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize_inner : 0);
2332 int xend = max_xsize_inner;
2333 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize_inner : 0);
2334 int xstep = (xstart < xend ? 1 : 0);
2335 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
2338 if (setup.quick_doors)
2345 if (action == ACTION_OPENING)
2346 PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
2347 else if (action == ACTION_CLOSING)
2348 PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
2351 for (x = xstart, y = ystart; x <= xend && y <= yend; x += xstep, y += ystep)
2353 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
2354 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
2355 int sx_center = (request.x != -1 ? request.x : SX + SXSIZE / 2);
2356 int sy_center = (request.y != -1 ? request.y : SY + SYSIZE / 2);
2357 int src_x = sx_center - width / 2;
2358 int src_y = sy_center - height / 2;
2359 int dst_x = sx_center - xsize * tile_size / 2;
2360 int dst_y = sy_center - ysize * tile_size / 2;
2361 int xsize_size_left = (xsize - 1) * tile_size;
2362 int ysize_size_top = (ysize - 1) * tile_size;
2363 int max_xsize_pos = (max_xsize - 1) * tile_size;
2364 int max_ysize_pos = (max_ysize - 1) * tile_size;
2367 BlitBitmap(bitmap_db_store, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2369 for (yy = 0; yy < 2; yy++)
2371 for (xx = 0; xx < 2; xx++)
2373 int src_xx = src_x + xx * max_xsize_pos;
2374 int src_yy = src_y + yy * max_ysize_pos;
2375 int dst_xx = dst_x + xx * xsize_size_left;
2376 int dst_yy = dst_y + yy * ysize_size_top;
2377 int xx_size = (xx ? tile_size : xsize_size_left);
2378 int yy_size = (yy ? tile_size : ysize_size_top);
2381 BlitBitmapMasked(bitmap_db_cross, backbuffer,
2382 src_xx, src_yy, xx_size, yy_size, dst_xx, dst_yy);
2384 BlitBitmap(bitmap_db_cross, backbuffer,
2385 src_xx, src_yy, xx_size, yy_size, dst_xx, dst_yy);
2389 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
2394 WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
2399 void ShowEnvelopeRequest(char *text, unsigned int req_state, int action)
2401 int last_game_status = game_status; /* save current game status */
2402 int graphic = IMG_BACKGROUND_REQUEST;
2403 int sound_opening = SND_REQUEST_OPENING;
2404 int sound_closing = SND_REQUEST_CLOSING;
2405 int anim_mode = graphic_info[graphic].anim_mode;
2406 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
2407 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
2409 if (game_status == GAME_MODE_PLAYING)
2410 BlitScreenToBitmap(backbuffer);
2412 SetDrawtoField(DRAW_BACKBUFFER);
2414 // SetDrawBackgroundMask(REDRAW_NONE);
2416 if (action == ACTION_OPENING)
2418 BlitBitmap(backbuffer, bitmap_db_store, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2420 if (req_state & REQ_ASK)
2422 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
2423 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
2425 else if (req_state & REQ_CONFIRM)
2427 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
2429 else if (req_state & REQ_PLAYER)
2431 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
2432 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
2433 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
2434 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
2437 DrawEnvelopeRequest(text);
2439 if (game_status != GAME_MODE_MAIN)
2443 /* force DOOR font inside door area */
2444 game_status = GAME_MODE_PSEUDO_DOOR;
2446 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
2448 if (action == ACTION_OPENING)
2450 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
2452 if (anim_mode == ANIM_DEFAULT)
2453 AnimateEnvelopeRequest(ANIM_DEFAULT, ACTION_OPENING);
2455 AnimateEnvelopeRequest(main_anim_mode, ACTION_OPENING);
2460 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
2462 if (anim_mode != ANIM_NONE)
2463 AnimateEnvelopeRequest(main_anim_mode, ACTION_CLOSING);
2465 if (anim_mode == ANIM_DEFAULT)
2466 AnimateEnvelopeRequest(ANIM_DEFAULT, ACTION_CLOSING);
2469 game.envelope_active = FALSE;
2471 game_status = last_game_status; /* restore current game status */
2473 if (action == ACTION_CLOSING)
2475 if (game_status != GAME_MODE_MAIN)
2478 BlitBitmap(bitmap_db_store, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2481 // SetDrawBackgroundMask(last_draw_background_mask);
2483 redraw_mask |= REDRAW_FIELD;
2485 if (game_status == GAME_MODE_MAIN)
2490 if (action == ACTION_CLOSING &&
2491 game_status == GAME_MODE_PLAYING &&
2492 level.game_engine_type == GAME_ENGINE_TYPE_RND)
2493 SetDrawtoField(DRAW_BUFFERED);
2496 void DrawPreviewElement(int dst_x, int dst_y, int element, int tilesize)
2500 int graphic = el2preimg(element);
2502 getSizedGraphicSource(graphic, 0, tilesize, &src_bitmap, &src_x, &src_y);
2503 BlitBitmap(src_bitmap, drawto, src_x, src_y, tilesize, tilesize, dst_x,dst_y);
2506 void DrawLevel(int draw_background_mask)
2510 SetMainBackgroundImage(IMG_BACKGROUND_PLAYING);
2511 SetDrawBackgroundMask(draw_background_mask);
2515 for (x = BX1; x <= BX2; x++)
2516 for (y = BY1; y <= BY2; y++)
2517 DrawScreenField(x, y);
2519 redraw_mask |= REDRAW_FIELD;
2522 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
2526 for (x = 0; x < size_x; x++)
2527 for (y = 0; y < size_y; y++)
2528 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
2530 redraw_mask |= REDRAW_FIELD;
2533 static void DrawPreviewLevelPlayfieldExt(int from_x, int from_y)
2535 boolean show_level_border = (BorderElement != EL_EMPTY);
2536 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
2537 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
2538 int tile_size = preview.tile_size;
2539 int preview_width = preview.xsize * tile_size;
2540 int preview_height = preview.ysize * tile_size;
2541 int real_preview_xsize = MIN(level_xsize, preview.xsize);
2542 int real_preview_ysize = MIN(level_ysize, preview.ysize);
2543 int real_preview_width = real_preview_xsize * tile_size;
2544 int real_preview_height = real_preview_ysize * tile_size;
2545 int dst_x = SX + ALIGNED_XPOS(preview.x, preview_width, preview.align);
2546 int dst_y = SY + ALIGNED_YPOS(preview.y, preview_height, preview.valign);
2549 if (!IN_GFX_FIELD_FULL(dst_x, dst_y + preview_height - 1))
2552 DrawBackground(dst_x, dst_y, preview_width, preview_height);
2554 dst_x += (preview_width - real_preview_width) / 2;
2555 dst_y += (preview_height - real_preview_height) / 2;
2557 for (x = 0; x < real_preview_xsize; x++)
2559 for (y = 0; y < real_preview_ysize; y++)
2561 int lx = from_x + x + (show_level_border ? -1 : 0);
2562 int ly = from_y + y + (show_level_border ? -1 : 0);
2563 int element = (IN_LEV_FIELD(lx, ly) ? level.field[lx][ly] :
2564 getBorderElement(lx, ly));
2566 DrawPreviewElement(dst_x + x * tile_size, dst_y + y * tile_size,
2567 element, tile_size);
2571 redraw_mask |= REDRAW_MICROLEVEL;
2574 #define MICROLABEL_EMPTY 0
2575 #define MICROLABEL_LEVEL_NAME 1
2576 #define MICROLABEL_LEVEL_AUTHOR_HEAD 2
2577 #define MICROLABEL_LEVEL_AUTHOR 3
2578 #define MICROLABEL_IMPORTED_FROM_HEAD 4
2579 #define MICROLABEL_IMPORTED_FROM 5
2580 #define MICROLABEL_IMPORTED_BY_HEAD 6
2581 #define MICROLABEL_IMPORTED_BY 7
2583 static int getMaxTextLength(struct TextPosInfo *pos, int font_nr)
2585 int max_text_width = SXSIZE;
2586 int font_width = getFontWidth(font_nr);
2588 if (pos->align == ALIGN_CENTER)
2589 max_text_width = (pos->x < SXSIZE / 2 ? pos->x * 2 : (SXSIZE - pos->x) * 2);
2590 else if (pos->align == ALIGN_RIGHT)
2591 max_text_width = pos->x;
2593 max_text_width = SXSIZE - pos->x;
2595 return max_text_width / font_width;
2598 static void DrawPreviewLevelLabelExt(int mode)
2600 struct TextPosInfo *pos = &menu.main.text.level_info_2;
2601 char label_text[MAX_OUTPUT_LINESIZE + 1];
2602 int max_len_label_text;
2603 int font_nr = pos->font;
2606 if (!IN_GFX_FIELD_FULL(pos->x, pos->y + getFontHeight(pos->font)))
2609 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
2610 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
2611 mode == MICROLABEL_IMPORTED_BY_HEAD)
2612 font_nr = pos->font_alt;
2614 max_len_label_text = getMaxTextLength(pos, font_nr);
2616 if (pos->size != -1)
2617 max_len_label_text = pos->size;
2619 for (i = 0; i < max_len_label_text; i++)
2620 label_text[i] = ' ';
2621 label_text[max_len_label_text] = '\0';
2623 if (strlen(label_text) > 0)
2624 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2627 (mode == MICROLABEL_LEVEL_NAME ? level.name :
2628 mode == MICROLABEL_LEVEL_AUTHOR_HEAD ? "created by" :
2629 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
2630 mode == MICROLABEL_IMPORTED_FROM_HEAD ? "imported from" :
2631 mode == MICROLABEL_IMPORTED_FROM ? leveldir_current->imported_from :
2632 mode == MICROLABEL_IMPORTED_BY_HEAD ? "imported by" :
2633 mode == MICROLABEL_IMPORTED_BY ? leveldir_current->imported_by :""),
2634 max_len_label_text);
2635 label_text[max_len_label_text] = '\0';
2637 if (strlen(label_text) > 0)
2638 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2640 redraw_mask |= REDRAW_MICROLEVEL;
2643 static void DrawPreviewLevelExt(boolean restart)
2645 static unsigned int scroll_delay = 0;
2646 static unsigned int label_delay = 0;
2647 static int from_x, from_y, scroll_direction;
2648 static int label_state, label_counter;
2649 unsigned int scroll_delay_value = preview.step_delay;
2650 boolean show_level_border = (BorderElement != EL_EMPTY);
2651 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
2652 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
2653 int last_game_status = game_status; /* save current game status */
2660 if (preview.anim_mode == ANIM_CENTERED)
2662 if (level_xsize > preview.xsize)
2663 from_x = (level_xsize - preview.xsize) / 2;
2664 if (level_ysize > preview.ysize)
2665 from_y = (level_ysize - preview.ysize) / 2;
2668 from_x += preview.xoffset;
2669 from_y += preview.yoffset;
2671 scroll_direction = MV_RIGHT;
2675 DrawPreviewLevelPlayfieldExt(from_x, from_y);
2676 DrawPreviewLevelLabelExt(label_state);
2678 /* initialize delay counters */
2679 DelayReached(&scroll_delay, 0);
2680 DelayReached(&label_delay, 0);
2682 if (leveldir_current->name)
2684 struct TextPosInfo *pos = &menu.main.text.level_info_1;
2685 char label_text[MAX_OUTPUT_LINESIZE + 1];
2686 int font_nr = pos->font;
2687 int max_len_label_text = getMaxTextLength(pos, font_nr);
2689 if (pos->size != -1)
2690 max_len_label_text = pos->size;
2692 strncpy(label_text, leveldir_current->name, max_len_label_text);
2693 label_text[max_len_label_text] = '\0';
2695 if (IN_GFX_FIELD_FULL(pos->x, pos->y + getFontHeight(pos->font)))
2696 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2699 game_status = last_game_status; /* restore current game status */
2704 /* scroll preview level, if needed */
2705 if (preview.anim_mode != ANIM_NONE &&
2706 (level_xsize > preview.xsize || level_ysize > preview.ysize) &&
2707 DelayReached(&scroll_delay, scroll_delay_value))
2709 switch (scroll_direction)
2714 from_x -= preview.step_offset;
2715 from_x = (from_x < 0 ? 0 : from_x);
2718 scroll_direction = MV_UP;
2722 if (from_x < level_xsize - preview.xsize)
2724 from_x += preview.step_offset;
2725 from_x = (from_x > level_xsize - preview.xsize ?
2726 level_xsize - preview.xsize : from_x);
2729 scroll_direction = MV_DOWN;
2735 from_y -= preview.step_offset;
2736 from_y = (from_y < 0 ? 0 : from_y);
2739 scroll_direction = MV_RIGHT;
2743 if (from_y < level_ysize - preview.ysize)
2745 from_y += preview.step_offset;
2746 from_y = (from_y > level_ysize - preview.ysize ?
2747 level_ysize - preview.ysize : from_y);
2750 scroll_direction = MV_LEFT;
2757 DrawPreviewLevelPlayfieldExt(from_x, from_y);
2760 /* !!! THIS ALL SUCKS -- SHOULD BE CLEANLY REWRITTEN !!! */
2761 /* redraw micro level label, if needed */
2762 if (!strEqual(level.name, NAMELESS_LEVEL_NAME) &&
2763 !strEqual(level.author, ANONYMOUS_NAME) &&
2764 !strEqual(level.author, leveldir_current->name) &&
2765 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
2767 int max_label_counter = 23;
2769 if (leveldir_current->imported_from != NULL &&
2770 strlen(leveldir_current->imported_from) > 0)
2771 max_label_counter += 14;
2772 if (leveldir_current->imported_by != NULL &&
2773 strlen(leveldir_current->imported_by) > 0)
2774 max_label_counter += 14;
2776 label_counter = (label_counter + 1) % max_label_counter;
2777 label_state = (label_counter >= 0 && label_counter <= 7 ?
2778 MICROLABEL_LEVEL_NAME :
2779 label_counter >= 9 && label_counter <= 12 ?
2780 MICROLABEL_LEVEL_AUTHOR_HEAD :
2781 label_counter >= 14 && label_counter <= 21 ?
2782 MICROLABEL_LEVEL_AUTHOR :
2783 label_counter >= 23 && label_counter <= 26 ?
2784 MICROLABEL_IMPORTED_FROM_HEAD :
2785 label_counter >= 28 && label_counter <= 35 ?
2786 MICROLABEL_IMPORTED_FROM :
2787 label_counter >= 37 && label_counter <= 40 ?
2788 MICROLABEL_IMPORTED_BY_HEAD :
2789 label_counter >= 42 && label_counter <= 49 ?
2790 MICROLABEL_IMPORTED_BY : MICROLABEL_EMPTY);
2792 if (leveldir_current->imported_from == NULL &&
2793 (label_state == MICROLABEL_IMPORTED_FROM_HEAD ||
2794 label_state == MICROLABEL_IMPORTED_FROM))
2795 label_state = (label_state == MICROLABEL_IMPORTED_FROM_HEAD ?
2796 MICROLABEL_IMPORTED_BY_HEAD : MICROLABEL_IMPORTED_BY);
2798 DrawPreviewLevelLabelExt(label_state);
2801 game_status = last_game_status; /* restore current game status */
2804 void DrawPreviewLevelInitial()
2806 DrawPreviewLevelExt(TRUE);
2809 void DrawPreviewLevelAnimation()
2811 DrawPreviewLevelExt(FALSE);
2814 inline void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
2815 int graphic, int sync_frame, int mask_mode)
2817 int frame = getGraphicAnimationFrame(graphic, sync_frame);
2819 if (mask_mode == USE_MASKING)
2820 DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
2822 DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
2825 inline void DrawFixedGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
2826 int graphic, int sync_frame,
2829 int frame = getGraphicAnimationFrame(graphic, sync_frame);
2831 if (mask_mode == USE_MASKING)
2832 DrawFixedGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
2834 DrawFixedGraphicExt(dst_bitmap, x, y, graphic, frame);
2837 inline void DrawGraphicAnimation(int x, int y, int graphic)
2839 int lx = LEVELX(x), ly = LEVELY(y);
2841 if (!IN_SCR_FIELD(x, y))
2844 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR,
2845 graphic, GfxFrame[lx][ly], NO_MASKING);
2847 MarkTileDirty(x, y);
2850 inline void DrawFixedGraphicAnimation(int x, int y, int graphic)
2852 int lx = LEVELX(x), ly = LEVELY(y);
2854 if (!IN_SCR_FIELD(x, y))
2857 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
2858 graphic, GfxFrame[lx][ly], NO_MASKING);
2859 MarkTileDirty(x, y);
2862 void DrawLevelGraphicAnimation(int x, int y, int graphic)
2864 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
2867 void DrawLevelElementAnimation(int x, int y, int element)
2869 int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
2871 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
2874 inline void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
2876 int sx = SCREENX(x), sy = SCREENY(y);
2878 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
2881 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
2884 DrawGraphicAnimation(sx, sy, graphic);
2887 if (GFX_CRUMBLED(TILE_GFX_ELEMENT(x, y)))
2888 DrawLevelFieldCrumbled(x, y);
2890 if (GFX_CRUMBLED(Feld[x][y]))
2891 DrawLevelFieldCrumbled(x, y);
2895 void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
2897 int sx = SCREENX(x), sy = SCREENY(y);
2900 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
2903 graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
2905 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
2908 DrawGraphicAnimation(sx, sy, graphic);
2910 if (GFX_CRUMBLED(element))
2911 DrawLevelFieldCrumbled(x, y);
2914 static int getPlayerGraphic(struct PlayerInfo *player, int move_dir)
2916 if (player->use_murphy)
2918 /* this works only because currently only one player can be "murphy" ... */
2919 static int last_horizontal_dir = MV_LEFT;
2920 int graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir);
2922 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
2923 last_horizontal_dir = move_dir;
2925 if (graphic == IMG_SP_MURPHY) /* undefined => use special graphic */
2927 int direction = (player->is_snapping ? move_dir : last_horizontal_dir);
2929 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
2935 return el_act_dir2img(player->artwork_element, player->GfxAction,move_dir);
2938 static boolean equalGraphics(int graphic1, int graphic2)
2940 struct GraphicInfo *g1 = &graphic_info[graphic1];
2941 struct GraphicInfo *g2 = &graphic_info[graphic2];
2943 return (g1->bitmap == g2->bitmap &&
2944 g1->src_x == g2->src_x &&
2945 g1->src_y == g2->src_y &&
2946 g1->anim_frames == g2->anim_frames &&
2947 g1->anim_delay == g2->anim_delay &&
2948 g1->anim_mode == g2->anim_mode);
2951 void DrawAllPlayers()
2955 for (i = 0; i < MAX_PLAYERS; i++)
2956 if (stored_player[i].active)
2957 DrawPlayer(&stored_player[i]);
2960 void DrawPlayerField(int x, int y)
2962 if (!IS_PLAYER(x, y))
2965 DrawPlayer(PLAYERINFO(x, y));
2968 #define DRAW_PLAYER_OVER_PUSHED_ELEMENT 1
2970 void DrawPlayer(struct PlayerInfo *player)
2972 int jx = player->jx;
2973 int jy = player->jy;
2974 int move_dir = player->MovDir;
2975 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? +1 : 0);
2976 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? +1 : 0);
2977 int last_jx = (player->is_moving ? jx - dx : jx);
2978 int last_jy = (player->is_moving ? jy - dy : jy);
2979 int next_jx = jx + dx;
2980 int next_jy = jy + dy;
2981 boolean player_is_moving = (player->MovPos ? TRUE : FALSE);
2982 boolean player_is_opaque = FALSE;
2983 int sx = SCREENX(jx), sy = SCREENY(jy);
2984 int sxx = 0, syy = 0;
2985 int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
2987 int action = ACTION_DEFAULT;
2988 int last_player_graphic = getPlayerGraphic(player, move_dir);
2989 int last_player_frame = player->Frame;
2992 /* GfxElement[][] is set to the element the player is digging or collecting;
2993 remove also for off-screen player if the player is not moving anymore */
2994 if (IN_LEV_FIELD(jx, jy) && !player_is_moving)
2995 GfxElement[jx][jy] = EL_UNDEFINED;
2997 if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
3001 if (!IN_LEV_FIELD(jx, jy))
3003 printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
3004 printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
3005 printf("DrawPlayerField(): This should never happen!\n");
3010 if (element == EL_EXPLOSION)
3013 action = (player->is_pushing ? ACTION_PUSHING :
3014 player->is_digging ? ACTION_DIGGING :
3015 player->is_collecting ? ACTION_COLLECTING :
3016 player->is_moving ? ACTION_MOVING :
3017 player->is_snapping ? ACTION_SNAPPING :
3018 player->is_dropping ? ACTION_DROPPING :
3019 player->is_waiting ? player->action_waiting : ACTION_DEFAULT);
3021 if (player->is_waiting)
3022 move_dir = player->dir_waiting;
3024 InitPlayerGfxAnimation(player, action, move_dir);
3026 /* ----------------------------------------------------------------------- */
3027 /* draw things in the field the player is leaving, if needed */
3028 /* ----------------------------------------------------------------------- */
3030 if (player->is_moving)
3032 if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
3034 DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
3036 if (last_element == EL_DYNAMITE_ACTIVE ||
3037 last_element == EL_EM_DYNAMITE_ACTIVE ||
3038 last_element == EL_SP_DISK_RED_ACTIVE)
3039 DrawDynamite(last_jx, last_jy);
3041 DrawLevelFieldThruMask(last_jx, last_jy);
3043 else if (last_element == EL_DYNAMITE_ACTIVE ||
3044 last_element == EL_EM_DYNAMITE_ACTIVE ||
3045 last_element == EL_SP_DISK_RED_ACTIVE)
3046 DrawDynamite(last_jx, last_jy);
3048 /* !!! this is not enough to prevent flickering of players which are
3049 moving next to each others without a free tile between them -- this
3050 can only be solved by drawing all players layer by layer (first the
3051 background, then the foreground etc.) !!! => TODO */
3052 else if (!IS_PLAYER(last_jx, last_jy))
3053 DrawLevelField(last_jx, last_jy);
3056 DrawLevelField(last_jx, last_jy);
3059 if (player->is_pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
3060 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
3063 if (!IN_SCR_FIELD(sx, sy))
3066 /* ----------------------------------------------------------------------- */
3067 /* draw things behind the player, if needed */
3068 /* ----------------------------------------------------------------------- */
3071 DrawLevelElement(jx, jy, Back[jx][jy]);
3072 else if (IS_ACTIVE_BOMB(element))
3073 DrawLevelElement(jx, jy, EL_EMPTY);
3076 if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
3078 int old_element = GfxElement[jx][jy];
3079 int old_graphic = el_act_dir2img(old_element, action, move_dir);
3080 int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
3082 if (GFX_CRUMBLED(old_element))
3083 DrawLevelFieldCrumbledDigging(jx, jy, move_dir, player->StepFrame);
3085 DrawGraphic(sx, sy, old_graphic, frame);
3087 if (graphic_info[old_graphic].anim_mode & ANIM_OPAQUE_PLAYER)
3088 player_is_opaque = TRUE;
3092 GfxElement[jx][jy] = EL_UNDEFINED;
3094 /* make sure that pushed elements are drawn with correct frame rate */
3095 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
3097 if (player->is_pushing && player->is_moving && !IS_ANIM_MODE_CE(graphic))
3098 GfxFrame[jx][jy] = player->StepFrame;
3100 DrawLevelField(jx, jy);
3104 #if !DRAW_PLAYER_OVER_PUSHED_ELEMENT
3105 /* ----------------------------------------------------------------------- */
3106 /* draw player himself */
3107 /* ----------------------------------------------------------------------- */
3109 graphic = getPlayerGraphic(player, move_dir);
3111 /* in the case of changed player action or direction, prevent the current
3112 animation frame from being restarted for identical animations */
3113 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
3114 player->Frame = last_player_frame;
3116 frame = getGraphicAnimationFrame(graphic, player->Frame);
3120 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3121 sxx = player->GfxPos;
3123 syy = player->GfxPos;
3126 if (!setup.soft_scrolling && ScreenMovPos)
3129 if (player_is_opaque)
3130 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
3132 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3134 if (SHIELD_ON(player))
3136 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
3137 IMG_SHIELD_NORMAL_ACTIVE);
3138 int frame = getGraphicAnimationFrame(graphic, -1);
3140 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3144 #if DRAW_PLAYER_OVER_PUSHED_ELEMENT
3147 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3148 sxx = player->GfxPos;
3150 syy = player->GfxPos;
3154 /* ----------------------------------------------------------------------- */
3155 /* draw things the player is pushing, if needed */
3156 /* ----------------------------------------------------------------------- */
3158 if (player->is_pushing && player->is_moving)
3160 int px = SCREENX(jx), py = SCREENY(jy);
3161 int pxx = (TILEX - ABS(sxx)) * dx;
3162 int pyy = (TILEY - ABS(syy)) * dy;
3163 int gfx_frame = GfxFrame[jx][jy];
3169 if (!IS_MOVING(jx, jy)) /* push movement already finished */
3171 element = Feld[next_jx][next_jy];
3172 gfx_frame = GfxFrame[next_jx][next_jy];
3175 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
3177 sync_frame = (IS_ANIM_MODE_CE(graphic) ? gfx_frame : player->StepFrame);
3178 frame = getGraphicAnimationFrame(graphic, sync_frame);
3180 /* draw background element under pushed element (like the Sokoban field) */
3181 if (game.use_masked_pushing && IS_MOVING(jx, jy))
3183 /* this allows transparent pushing animation over non-black background */
3186 DrawLevelElement(jx, jy, Back[jx][jy]);
3188 DrawLevelElement(jx, jy, EL_EMPTY);
3190 if (Back[next_jx][next_jy])
3191 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
3193 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
3195 else if (Back[next_jx][next_jy])
3196 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
3199 /* do not draw (EM style) pushing animation when pushing is finished */
3200 /* (two-tile animations usually do not contain start and end frame) */
3201 if (graphic_info[graphic].double_movement && !IS_MOVING(jx, jy))
3202 DrawLevelElement(next_jx, next_jy, Feld[next_jx][next_jy]);
3204 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
3206 /* masked drawing is needed for EMC style (double) movement graphics */
3207 /* !!! (ONLY WHEN DRAWING PUSHED ELEMENT OVER THE PLAYER) !!! */
3208 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
3212 #if DRAW_PLAYER_OVER_PUSHED_ELEMENT
3213 /* ----------------------------------------------------------------------- */
3214 /* draw player himself */
3215 /* ----------------------------------------------------------------------- */
3217 graphic = getPlayerGraphic(player, move_dir);
3219 /* in the case of changed player action or direction, prevent the current
3220 animation frame from being restarted for identical animations */
3221 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
3222 player->Frame = last_player_frame;
3224 frame = getGraphicAnimationFrame(graphic, player->Frame);
3228 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3229 sxx = player->GfxPos;
3231 syy = player->GfxPos;
3234 if (!setup.soft_scrolling && ScreenMovPos)
3237 if (player_is_opaque)
3238 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
3240 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3242 if (SHIELD_ON(player))
3244 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
3245 IMG_SHIELD_NORMAL_ACTIVE);
3246 int frame = getGraphicAnimationFrame(graphic, -1);
3248 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3252 /* ----------------------------------------------------------------------- */
3253 /* draw things in front of player (active dynamite or dynabombs) */
3254 /* ----------------------------------------------------------------------- */
3256 if (IS_ACTIVE_BOMB(element))
3258 graphic = el2img(element);
3259 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
3261 if (game.emulation == EMU_SUPAPLEX)
3262 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
3264 DrawGraphicThruMask(sx, sy, graphic, frame);
3267 if (player_is_moving && last_element == EL_EXPLOSION)
3269 int element = (GfxElement[last_jx][last_jy] != EL_UNDEFINED ?
3270 GfxElement[last_jx][last_jy] : EL_EMPTY);
3271 int graphic = el_act2img(element, ACTION_EXPLODING);
3272 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
3273 int phase = ExplodePhase[last_jx][last_jy] - 1;
3274 int frame = getGraphicAnimationFrame(graphic, phase - delay);
3277 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
3280 /* ----------------------------------------------------------------------- */
3281 /* draw elements the player is just walking/passing through/under */
3282 /* ----------------------------------------------------------------------- */
3284 if (player_is_moving)
3286 /* handle the field the player is leaving ... */
3287 if (IS_ACCESSIBLE_INSIDE(last_element))
3288 DrawLevelField(last_jx, last_jy);
3289 else if (IS_ACCESSIBLE_UNDER(last_element))
3290 DrawLevelFieldThruMask(last_jx, last_jy);
3293 /* do not redraw accessible elements if the player is just pushing them */
3294 if (!player_is_moving || !player->is_pushing)
3296 /* ... and the field the player is entering */
3297 if (IS_ACCESSIBLE_INSIDE(element))
3298 DrawLevelField(jx, jy);
3299 else if (IS_ACCESSIBLE_UNDER(element))
3300 DrawLevelFieldThruMask(jx, jy);
3303 MarkTileDirty(sx, sy);
3306 /* ------------------------------------------------------------------------- */
3308 void WaitForEventToContinue()
3310 boolean still_wait = TRUE;
3312 /* simulate releasing mouse button over last gadget, if still pressed */
3314 HandleGadgets(-1, -1, 0);
3316 button_status = MB_RELEASED;
3330 case EVENT_BUTTONPRESS:
3331 case EVENT_KEYPRESS:
3335 case EVENT_KEYRELEASE:
3336 ClearPlayerAction();
3340 HandleOtherEvents(&event);
3344 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
3351 /* don't eat all CPU time */
3356 #define MAX_REQUEST_LINES 13
3357 #define MAX_REQUEST_LINE_FONT1_LEN 7
3358 #define MAX_REQUEST_LINE_FONT2_LEN 10
3360 static int RequestHandleEvents(unsigned int req_state)
3362 int last_game_status = game_status; /* save current game status */
3366 button_status = MB_RELEASED;
3368 request_gadget_id = -1;
3381 case EVENT_BUTTONPRESS:
3382 case EVENT_BUTTONRELEASE:
3383 case EVENT_MOTIONNOTIFY:
3385 if (event.type == EVENT_MOTIONNOTIFY)
3387 if (!PointerInWindow(window))
3388 continue; /* window and pointer are on different screens */
3393 motion_status = TRUE;
3394 mx = ((MotionEvent *) &event)->x;
3395 my = ((MotionEvent *) &event)->y;
3399 motion_status = FALSE;
3400 mx = ((ButtonEvent *) &event)->x;
3401 my = ((ButtonEvent *) &event)->y;
3402 if (event.type == EVENT_BUTTONPRESS)
3403 button_status = ((ButtonEvent *) &event)->button;
3405 button_status = MB_RELEASED;
3408 /* this sets 'request_gadget_id' */
3409 HandleGadgets(mx, my, button_status);
3411 switch (request_gadget_id)
3413 case TOOL_CTRL_ID_YES:
3416 case TOOL_CTRL_ID_NO:
3419 case TOOL_CTRL_ID_CONFIRM:
3420 result = TRUE | FALSE;
3423 case TOOL_CTRL_ID_PLAYER_1:
3426 case TOOL_CTRL_ID_PLAYER_2:
3429 case TOOL_CTRL_ID_PLAYER_3:
3432 case TOOL_CTRL_ID_PLAYER_4:
3443 case EVENT_KEYPRESS:
3444 switch (GetEventKey((KeyEvent *)&event, TRUE))
3447 if (req_state & REQ_CONFIRM)
3452 #if defined(TARGET_SDL2)
3459 #if defined(TARGET_SDL2)
3469 if (req_state & REQ_PLAYER)
3473 case EVENT_KEYRELEASE:
3474 ClearPlayerAction();
3478 HandleOtherEvents(&event);
3482 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
3484 int joy = AnyJoystick();
3486 if (joy & JOY_BUTTON_1)
3488 else if (joy & JOY_BUTTON_2)
3492 if (game_status == GAME_MODE_PLAYING && local_player->LevelSolved_GameEnd)
3494 HandleGameActions();
3500 if (!PendingEvent()) /* delay only if no pending events */
3504 game_status = GAME_MODE_PSEUDO_DOOR;
3508 game_status = last_game_status; /* restore current game status */
3514 static boolean RequestDoor(char *text, unsigned int req_state)
3516 unsigned int old_door_state;
3517 int last_game_status = game_status; /* save current game status */
3518 int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
3519 int font_nr = FONT_TEXT_2;
3524 if (maxWordLengthInString(text) > MAX_REQUEST_LINE_FONT1_LEN)
3526 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
3527 font_nr = FONT_TEXT_1;
3530 if (game_status == GAME_MODE_PLAYING)
3531 BlitScreenToBitmap(backbuffer);
3533 /* disable deactivated drawing when quick-loading level tape recording */
3534 if (tape.playing && tape.deactivate_display)
3535 TapeDeactivateDisplayOff(TRUE);
3537 SetMouseCursor(CURSOR_DEFAULT);
3539 #if defined(NETWORK_AVALIABLE)
3540 /* pause network game while waiting for request to answer */
3541 if (options.network &&
3542 game_status == GAME_MODE_PLAYING &&
3543 req_state & REQUEST_WAIT_FOR_INPUT)
3544 SendToServer_PausePlaying();
3547 old_door_state = GetDoorState();
3549 /* simulate releasing mouse button over last gadget, if still pressed */
3551 HandleGadgets(-1, -1, 0);
3555 /* draw released gadget before proceeding */
3558 if (old_door_state & DOOR_OPEN_1)
3560 CloseDoor(DOOR_CLOSE_1);
3562 /* save old door content */
3563 BlitBitmap(bitmap_db_door_1, bitmap_db_door_1,
3564 0 * DXSIZE, 0, DXSIZE, DYSIZE, 1 * DXSIZE, 0);
3567 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
3568 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3570 /* clear door drawing field */
3571 DrawBackground(DX, DY, DXSIZE, DYSIZE);
3573 /* force DOOR font inside door area */
3574 game_status = GAME_MODE_PSEUDO_DOOR;
3576 /* write text for request */
3577 for (text_ptr = text, ty = 0; ty < MAX_REQUEST_LINES; ty++)
3579 char text_line[max_request_line_len + 1];
3585 for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
3587 tc = *(text_ptr + tx);
3588 // if (!tc || tc == ' ')
3589 if (!tc || tc == ' ' || tc == '?' || tc == '!')
3593 if ((tc == '?' || tc == '!') && tl == 0)
3603 strncpy(text_line, text_ptr, tl);
3606 DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
3607 DY + 8 + ty * (getFontHeight(font_nr) + 2),
3608 text_line, font_nr);
3610 text_ptr += tl + (tc == ' ' ? 1 : 0);
3611 // text_ptr += tl + (tc == ' ' || tc == '?' || tc == '!' ? 1 : 0);
3614 game_status = last_game_status; /* restore current game status */
3616 if (req_state & REQ_ASK)
3618 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
3619 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
3621 else if (req_state & REQ_CONFIRM)
3623 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
3625 else if (req_state & REQ_PLAYER)
3627 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
3628 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
3629 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
3630 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
3633 /* copy request gadgets to door backbuffer */
3634 BlitBitmap(drawto, bitmap_db_door_1, DX, DY, DXSIZE, DYSIZE, 0, 0);
3636 OpenDoor(DOOR_OPEN_1);
3638 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
3640 if (game_status == GAME_MODE_PLAYING)
3642 SetPanelBackground();
3643 SetDrawBackgroundMask(REDRAW_DOOR_1);
3647 SetDrawBackgroundMask(REDRAW_FIELD);
3653 if (game_status != GAME_MODE_MAIN)
3656 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3658 // ---------- handle request buttons ----------
3659 result = RequestHandleEvents(req_state);
3661 if (game_status != GAME_MODE_MAIN)
3666 if (!(req_state & REQ_STAY_OPEN))
3668 CloseDoor(DOOR_CLOSE_1);
3670 if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
3671 (req_state & REQ_REOPEN))
3672 OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
3677 if (game_status == GAME_MODE_PLAYING)
3679 SetPanelBackground();
3680 SetDrawBackgroundMask(REDRAW_DOOR_1);
3684 SetDrawBackgroundMask(REDRAW_FIELD);
3687 #if defined(NETWORK_AVALIABLE)
3688 /* continue network game after request */
3689 if (options.network &&
3690 game_status == GAME_MODE_PLAYING &&
3691 req_state & REQUEST_WAIT_FOR_INPUT)
3692 SendToServer_ContinuePlaying();
3695 /* restore deactivated drawing when quick-loading level tape recording */
3696 if (tape.playing && tape.deactivate_display)
3697 TapeDeactivateDisplayOn();
3702 static boolean RequestEnvelope(char *text, unsigned int req_state)
3706 if (game_status == GAME_MODE_PLAYING)
3707 BlitScreenToBitmap(backbuffer);
3709 /* disable deactivated drawing when quick-loading level tape recording */
3710 if (tape.playing && tape.deactivate_display)
3711 TapeDeactivateDisplayOff(TRUE);
3713 SetMouseCursor(CURSOR_DEFAULT);
3715 #if defined(NETWORK_AVALIABLE)
3716 /* pause network game while waiting for request to answer */
3717 if (options.network &&
3718 game_status == GAME_MODE_PLAYING &&
3719 req_state & REQUEST_WAIT_FOR_INPUT)
3720 SendToServer_PausePlaying();
3723 /* simulate releasing mouse button over last gadget, if still pressed */
3725 HandleGadgets(-1, -1, 0);
3729 // (replace with setting corresponding request background)
3730 // SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
3731 // SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3733 /* clear door drawing field */
3734 // DrawBackground(DX, DY, DXSIZE, DYSIZE);
3736 ShowEnvelopeRequest(text, req_state, ACTION_OPENING);
3738 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
3740 if (game_status == GAME_MODE_PLAYING)
3742 SetPanelBackground();
3743 SetDrawBackgroundMask(REDRAW_DOOR_1);
3747 SetDrawBackgroundMask(REDRAW_FIELD);
3753 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3755 // ---------- handle request buttons ----------
3756 result = RequestHandleEvents(req_state);
3758 if (game_status != GAME_MODE_MAIN)
3763 ShowEnvelopeRequest(text, req_state, ACTION_CLOSING);
3767 if (game_status == GAME_MODE_PLAYING)
3769 SetPanelBackground();
3770 SetDrawBackgroundMask(REDRAW_DOOR_1);
3774 SetDrawBackgroundMask(REDRAW_FIELD);
3777 #if defined(NETWORK_AVALIABLE)
3778 /* continue network game after request */
3779 if (options.network &&
3780 game_status == GAME_MODE_PLAYING &&
3781 req_state & REQUEST_WAIT_FOR_INPUT)
3782 SendToServer_ContinuePlaying();
3785 /* restore deactivated drawing when quick-loading level tape recording */
3786 if (tape.playing && tape.deactivate_display)
3787 TapeDeactivateDisplayOn();
3792 boolean Request(char *text, unsigned int req_state)
3794 if (global.use_envelope_request)
3795 return RequestEnvelope(text, req_state);
3797 return RequestDoor(text, req_state);
3800 static int compareDoorPartOrderInfo(const void *object1, const void *object2)
3802 const struct DoorPartOrderInfo *dpo1 = (struct DoorPartOrderInfo *)object1;
3803 const struct DoorPartOrderInfo *dpo2 = (struct DoorPartOrderInfo *)object2;
3806 if (dpo1->sort_priority != dpo2->sort_priority)
3807 compare_result = dpo1->sort_priority - dpo2->sort_priority;
3809 compare_result = dpo1->nr - dpo2->nr;
3811 return compare_result;
3814 void InitGraphicCompatibilityInfo_Doors()
3820 struct DoorInfo *door;
3824 { DOOR_1, IMG_DOOR_1_GFX_PART_1, IMG_DOOR_1_GFX_PART_8, &door_1 },
3825 { DOOR_2, IMG_DOOR_2_GFX_PART_1, IMG_DOOR_2_GFX_PART_8, &door_2 },
3827 { -1, -1, -1, NULL }
3829 struct Rect door_rect_list[] =
3831 { DX, DY, DXSIZE, DYSIZE },
3832 { VX, VY, VXSIZE, VYSIZE }
3836 for (i = 0; doors[i].door_token != -1; i++)
3838 int door_token = doors[i].door_token;
3839 int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
3840 int part_1 = doors[i].part_1;
3841 int part_8 = doors[i].part_8;
3842 int part_2 = part_1 + 1;
3843 int part_3 = part_1 + 2;
3844 struct DoorInfo *door = doors[i].door;
3845 struct Rect *door_rect = &door_rect_list[door_index];
3846 boolean door_gfx_redefined = FALSE;
3848 /* check if any door part graphic definitions have been redefined */
3850 for (j = 0; door_part_controls[j].door_token != -1; j++)
3852 struct DoorPartControlInfo *dpc = &door_part_controls[j];
3853 struct FileInfo *fi = getImageListEntryFromImageID(dpc->graphic);
3855 if (dpc->door_token == door_token && fi->redefined)
3856 door_gfx_redefined = TRUE;
3859 /* check for old-style door graphic/animation modifications */
3861 if (!door_gfx_redefined)
3863 if (door->anim_mode & ANIM_STATIC_PANEL)
3865 door->panel.step_xoffset = 0;
3866 door->panel.step_yoffset = 0;
3869 if (door->anim_mode & (ANIM_HORIZONTAL | ANIM_VERTICAL))
3871 struct GraphicInfo *g_part_1 = &graphic_info[part_1];
3872 struct GraphicInfo *g_part_2 = &graphic_info[part_2];
3873 int num_door_steps, num_panel_steps;
3875 /* remove door part graphics other than the two default wings */
3877 for (j = 0; door_part_controls[j].door_token != -1; j++)
3879 struct DoorPartControlInfo *dpc = &door_part_controls[j];
3880 struct GraphicInfo *g = &graphic_info[dpc->graphic];
3882 if (dpc->graphic >= part_3 &&
3883 dpc->graphic <= part_8)
3887 /* set graphics and screen positions of the default wings */
3889 g_part_1->width = door_rect->width;
3890 g_part_1->height = door_rect->height;
3891 g_part_2->width = door_rect->width;
3892 g_part_2->height = door_rect->height;
3893 g_part_2->src_x = door_rect->width;
3894 g_part_2->src_y = g_part_1->src_y;
3896 door->part_2.x = door->part_1.x;
3897 door->part_2.y = door->part_1.y;
3899 if (door->width != -1)
3901 g_part_1->width = door->width;
3902 g_part_2->width = door->width;
3904 // special treatment for graphics and screen position of right wing
3905 g_part_2->src_x += door_rect->width - door->width;
3906 door->part_2.x += door_rect->width - door->width;
3909 if (door->height != -1)
3911 g_part_1->height = door->height;
3912 g_part_2->height = door->height;
3914 // special treatment for graphics and screen position of bottom wing
3915 g_part_2->src_y += door_rect->height - door->height;
3916 door->part_2.y += door_rect->height - door->height;
3919 /* set animation delays for the default wings and panels */
3921 door->part_1.step_delay = door->step_delay;
3922 door->part_2.step_delay = door->step_delay;
3923 door->panel.step_delay = door->step_delay;
3925 /* set animation draw order for the default wings */
3927 door->part_1.sort_priority = 2; /* draw left wing over ... */
3928 door->part_2.sort_priority = 1; /* ... right wing */
3930 /* set animation draw offset for the default wings */
3932 if (door->anim_mode & ANIM_HORIZONTAL)
3934 door->part_1.step_xoffset = door->step_offset;
3935 door->part_1.step_yoffset = 0;
3936 door->part_2.step_xoffset = door->step_offset * -1;
3937 door->part_2.step_yoffset = 0;
3939 num_door_steps = g_part_1->width / door->step_offset;
3941 else // ANIM_VERTICAL
3943 door->part_1.step_xoffset = 0;
3944 door->part_1.step_yoffset = door->step_offset;
3945 door->part_2.step_xoffset = 0;
3946 door->part_2.step_yoffset = door->step_offset * -1;
3948 num_door_steps = g_part_1->height / door->step_offset;
3951 /* set animation draw offset for the default panels */
3953 if (door->step_offset > 1)
3955 num_panel_steps = 2 * door_rect->height / door->step_offset;
3956 door->panel.start_step = num_panel_steps - num_door_steps;
3960 num_panel_steps = door_rect->height / door->step_offset;
3961 door->panel.start_step = num_panel_steps - num_door_steps / 2;
3962 door->panel.step_delay *= 2;
3973 for (i = 0; door_part_controls[i].door_token != -1; i++)
3975 struct DoorPartControlInfo *dpc = &door_part_controls[i];
3976 struct DoorPartOrderInfo *dpo = &door_part_order[i];
3978 /* initialize "start_step_opening" and "start_step_closing", if needed */
3979 if (dpc->pos->start_step_opening == 0 &&
3980 dpc->pos->start_step_closing == 0)
3982 // dpc->pos->start_step_opening = dpc->pos->start_step;
3983 dpc->pos->start_step_closing = dpc->pos->start_step;
3986 /* fill structure for door part draw order (sorted below) */
3988 dpo->sort_priority = dpc->pos->sort_priority;
3991 /* sort door part controls according to sort_priority and graphic number */
3992 qsort(door_part_order, MAX_DOOR_PARTS,
3993 sizeof(struct DoorPartOrderInfo), compareDoorPartOrderInfo);
3996 unsigned int OpenDoor(unsigned int door_state)
3998 if (door_state & DOOR_COPY_BACK)
4000 if (door_state & DOOR_OPEN_1)
4001 BlitBitmap(bitmap_db_door_1, bitmap_db_door_1,
4002 1 * DXSIZE, 0, DXSIZE, DYSIZE, 0 * DXSIZE, 0);
4004 if (door_state & DOOR_OPEN_2)
4005 BlitBitmap(bitmap_db_door_2, bitmap_db_door_2,
4006 1 * VXSIZE, 0, VXSIZE, VYSIZE, 0 * VXSIZE, 0);
4008 door_state &= ~DOOR_COPY_BACK;
4011 return MoveDoor(door_state);
4014 unsigned int CloseDoor(unsigned int door_state)
4016 unsigned int old_door_state = GetDoorState();
4018 if (!(door_state & DOOR_NO_COPY_BACK))
4020 if (old_door_state & DOOR_OPEN_1)
4021 BlitBitmap(backbuffer, bitmap_db_door_1,
4022 DX, DY, DXSIZE, DYSIZE, 0, 0);
4024 if (old_door_state & DOOR_OPEN_2)
4025 BlitBitmap(backbuffer, bitmap_db_door_2,
4026 VX, VY, VXSIZE, VYSIZE, 0, 0);
4028 door_state &= ~DOOR_NO_COPY_BACK;
4031 return MoveDoor(door_state);
4034 unsigned int GetDoorState()
4036 return MoveDoor(DOOR_GET_STATE);
4039 unsigned int SetDoorState(unsigned int door_state)
4041 return MoveDoor(door_state | DOOR_SET_STATE);
4044 int euclid(int a, int b)
4046 return (b ? euclid(b, a % b) : a);
4049 unsigned int MoveDoor(unsigned int door_state)
4051 struct Rect door_rect_list[] =
4053 { DX, DY, DXSIZE, DYSIZE },
4054 { VX, VY, VXSIZE, VYSIZE }
4056 static int door1 = DOOR_OPEN_1;
4057 static int door2 = DOOR_CLOSE_2;
4058 unsigned int door_delay = 0;
4059 unsigned int door_delay_value;
4062 if (door_1.width < 0 || door_1.width > DXSIZE)
4063 door_1.width = DXSIZE;
4064 if (door_1.height < 0 || door_1.height > DYSIZE)
4065 door_1.height = DYSIZE;
4066 if (door_2.width < 0 || door_2.width > VXSIZE)
4067 door_2.width = VXSIZE;
4068 if (door_2.height < 0 || door_2.height > VYSIZE)
4069 door_2.height = VYSIZE;
4071 if (door_state == DOOR_GET_STATE)
4072 return (door1 | door2);
4074 if (door_state & DOOR_SET_STATE)
4076 if (door_state & DOOR_ACTION_1)
4077 door1 = door_state & DOOR_ACTION_1;
4078 if (door_state & DOOR_ACTION_2)
4079 door2 = door_state & DOOR_ACTION_2;
4081 return (door1 | door2);
4084 if (!(door_state & DOOR_FORCE_REDRAW))
4086 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
4087 door_state &= ~DOOR_OPEN_1;
4088 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
4089 door_state &= ~DOOR_CLOSE_1;
4090 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
4091 door_state &= ~DOOR_OPEN_2;
4092 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
4093 door_state &= ~DOOR_CLOSE_2;
4096 if (global.autoplay_leveldir)
4098 door_state |= DOOR_NO_DELAY;
4099 door_state &= ~DOOR_CLOSE_ALL;
4102 if (game_status == GAME_MODE_EDITOR)
4103 door_state |= DOOR_NO_DELAY;
4105 if (door_state & DOOR_ACTION)
4107 boolean door_panel_drawn[NUM_DOORS];
4108 boolean panel_has_doors[NUM_DOORS];
4109 boolean door_part_skip[MAX_DOOR_PARTS];
4110 boolean door_part_done[MAX_DOOR_PARTS];
4111 boolean door_part_done_all;
4112 int num_steps[MAX_DOOR_PARTS];
4113 int max_move_delay = 0; // delay for complete animations of all doors
4114 int max_step_delay = 0; // delay (ms) between two animation frames
4115 int num_move_steps = 0; // number of animation steps for all doors
4116 int current_move_delay = 0;
4120 for (i = 0; i < NUM_DOORS; i++)
4121 panel_has_doors[i] = FALSE;
4123 for (i = 0; i < MAX_DOOR_PARTS; i++)
4125 struct DoorPartControlInfo *dpc = &door_part_controls[i];
4126 struct GraphicInfo *g = &graphic_info[dpc->graphic];
4127 int door_token = dpc->door_token;
4129 door_part_done[i] = FALSE;
4130 door_part_skip[i] = (!(door_state & door_token) ||
4134 for (i = 0; i < MAX_DOOR_PARTS; i++)
4136 int nr = door_part_order[i].nr;
4137 struct DoorPartControlInfo *dpc = &door_part_controls[nr];
4138 struct DoorPartPosInfo *pos = dpc->pos;
4139 struct GraphicInfo *g = &graphic_info[dpc->graphic];
4140 int door_token = dpc->door_token;
4141 int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
4142 boolean is_panel = DOOR_PART_IS_PANEL(nr);
4143 int step_xoffset = ABS(pos->step_xoffset);
4144 int step_yoffset = ABS(pos->step_yoffset);
4145 int step_delay = pos->step_delay;
4146 int current_door_state = door_state & door_token;
4147 boolean door_opening = ((current_door_state & DOOR_OPEN) != 0);
4148 boolean door_closing = ((current_door_state & DOOR_CLOSE) != 0);
4149 boolean part_opening = (is_panel ? door_closing : door_opening);
4150 int start_step = (part_opening ? pos->start_step_opening :
4151 pos->start_step_closing);
4152 float move_xsize = (step_xoffset ? g->width : 0);
4153 float move_ysize = (step_yoffset ? g->height : 0);
4154 int move_xsteps = (step_xoffset ? ceil(move_xsize / step_xoffset) : 0);
4155 int move_ysteps = (step_yoffset ? ceil(move_ysize / step_yoffset) : 0);
4156 int move_steps = (move_xsteps && move_ysteps ?
4157 MIN(move_xsteps, move_ysteps) :
4158 move_xsteps ? move_xsteps : move_ysteps) - start_step;
4159 int move_delay = move_steps * step_delay;
4161 if (door_part_skip[nr])
4165 panel_has_doors[door_index] = TRUE;
4167 max_move_delay = MAX(max_move_delay, move_delay);
4168 max_step_delay = (max_step_delay == 0 ? step_delay :
4169 euclid(max_step_delay, step_delay));
4170 num_steps[nr] = move_steps;
4173 num_move_steps = max_move_delay / max_step_delay;
4175 door_delay_value = max_step_delay;
4177 if ((door_state & DOOR_NO_DELAY) || setup.quick_doors)
4179 start = num_move_steps - 1;
4183 /* opening door sound has priority over simultaneously closing door */
4184 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
4185 PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
4186 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
4187 PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
4190 for (k = start; k < num_move_steps; k++)
4192 door_part_done_all = TRUE;
4194 for (i = 0; i < NUM_DOORS; i++)
4195 door_panel_drawn[i] = FALSE;
4197 for (i = 0; i < MAX_DOOR_PARTS; i++)
4199 int nr = door_part_order[i].nr;
4200 struct DoorPartControlInfo *dpc = &door_part_controls[nr];
4201 struct DoorPartPosInfo *pos = dpc->pos;
4202 struct GraphicInfo *g = &graphic_info[dpc->graphic];
4203 int door_token = dpc->door_token;
4204 int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
4205 boolean is_panel = DOOR_PART_IS_PANEL(nr);
4206 struct Rect *door_rect = &door_rect_list[door_index];
4207 Bitmap *bitmap_db_door = (door_token == DOOR_1 ? bitmap_db_door_1 :
4209 Bitmap *bitmap = (is_panel ? bitmap_db_door : g->bitmap);
4210 int current_door_state = door_state & door_token;
4211 boolean door_opening = ((current_door_state & DOOR_OPEN) != 0);
4212 boolean door_closing = !door_opening;
4213 boolean part_opening = (is_panel ? door_closing : door_opening);
4214 boolean part_closing = !part_opening;
4215 int start_step = (part_opening ? pos->start_step_opening :
4216 pos->start_step_closing);
4217 int step_delay = pos->step_delay;
4218 int step_factor = step_delay / max_step_delay;
4219 int k1 = (step_factor ? k / step_factor + 1 : k);
4220 int k2 = (part_opening ? k1 + start_step : num_steps[nr] - k1);
4221 int kk = (k2 < 0 ? 0 : k2);
4222 int src_x, src_y, src_xx, src_yy;
4223 int dst_x, dst_y, dst_xx, dst_yy;
4226 if (door_part_skip[nr])
4229 if (!(door_state & door_token))
4237 if (!door_panel_drawn[door_index])
4239 ClearRectangle(drawto, door_rect->x, door_rect->y,
4240 door_rect->width, door_rect->height);
4242 door_panel_drawn[door_index] = TRUE;
4245 // draw opening or closing door parts
4247 if (pos->step_xoffset < 0) // door part on right side
4250 dst_xx = pos->x + ABS(kk * pos->step_xoffset);
4253 if (dst_xx + width > door_rect->width)
4254 width = door_rect->width - dst_xx;
4256 else // door part on left side
4259 dst_xx = pos->x - kk * pos->step_xoffset;
4263 src_xx = ABS(dst_xx);
4267 width = g->width - src_xx;
4269 // printf("::: k == %d [%d] \n", k, start_step);
4272 if (pos->step_yoffset < 0) // door part on bottom side
4275 dst_yy = pos->y + ABS(kk * pos->step_yoffset);
4278 if (dst_yy + height > door_rect->height)
4279 height = door_rect->height - dst_yy;
4281 else // door part on top side
4284 dst_yy = pos->y - kk * pos->step_yoffset;
4288 src_yy = ABS(dst_yy);
4292 height = g->height - src_yy;
4302 src_x = g->src_x + src_xx;
4303 src_y = g->src_y + src_yy;
4306 dst_x = door_rect->x + dst_xx;
4307 dst_y = door_rect->y + dst_yy;
4309 if (width >= 0 && width <= g->width &&
4310 height >= 0 && height <= g->height)
4312 if (is_panel || !pos->draw_masked)
4313 BlitBitmap(bitmap, drawto, src_x, src_y, width, height,
4316 BlitBitmapMasked(bitmap, drawto, src_x, src_y, width, height,
4320 redraw_mask |= REDRAW_DOOR_FROM_TOKEN(door_token);
4322 if ((part_opening && (width < 0 || height < 0)) ||
4323 (part_closing && (width >= g->width && height >= g->height)))
4324 door_part_done[nr] = TRUE;
4326 // continue door part animations, but not panel after door has closed
4327 if (!door_part_done[nr] &&
4328 !(is_panel && door_closing && panel_has_doors[door_index]))
4329 door_part_done_all = FALSE;
4332 if (!(door_state & DOOR_NO_DELAY))
4336 if (game_status == GAME_MODE_MAIN)
4339 WaitUntilDelayReached(&door_delay, door_delay_value);
4341 current_move_delay += max_step_delay;
4344 if (door_part_done_all)
4349 if (door_state & DOOR_ACTION_1)
4350 door1 = door_state & DOOR_ACTION_1;
4351 if (door_state & DOOR_ACTION_2)
4352 door2 = door_state & DOOR_ACTION_2;
4354 return (door1 | door2);
4357 void DrawSpecialEditorDoor()
4359 struct GraphicInfo *gfx1 = &graphic_info[IMG_DOOR_2_TOP_BORDER_CORRECTION];
4360 int top_border_width = gfx1->width;
4361 int top_border_height = gfx1->height;
4362 int outer_border = viewport.door_2[GAME_MODE_EDITOR].border_size;
4363 int ex = EX - outer_border;
4364 int ey = EY - outer_border;
4365 int vy = VY - outer_border;
4366 int exsize = EXSIZE + 2 * outer_border;
4368 CloseDoor(DOOR_CLOSE_2);
4370 /* draw bigger level editor toolbox window */
4371 BlitBitmap(gfx1->bitmap, drawto, gfx1->src_x, gfx1->src_y,
4372 top_border_width, top_border_height, ex, ey - top_border_height);
4373 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto, ex, vy,
4374 exsize, EYSIZE - VYSIZE + outer_border, ex, ey);
4376 redraw_mask |= REDRAW_ALL;
4379 void UndrawSpecialEditorDoor()
4381 struct GraphicInfo *gfx1 = &graphic_info[IMG_DOOR_2_TOP_BORDER_CORRECTION];
4382 int top_border_width = gfx1->width;
4383 int top_border_height = gfx1->height;
4384 int outer_border = viewport.door_2[GAME_MODE_EDITOR].border_size;
4385 int ex = EX - outer_border;
4386 int ey = EY - outer_border;
4387 int ey_top = ey - top_border_height;
4388 int exsize = EXSIZE + 2 * outer_border;
4389 int eysize = EYSIZE + 2 * outer_border;
4391 /* draw normal tape recorder window */
4392 if (graphic_info[IMG_GLOBAL_BORDER].bitmap)
4394 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
4395 ex, ey_top, top_border_width, top_border_height,
4397 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
4398 ex, ey, exsize, eysize, ex, ey);
4402 // if screen background is set to "[NONE]", clear editor toolbox window
4403 ClearRectangle(drawto, ex, ey_top, top_border_width, top_border_height);
4404 ClearRectangle(drawto, ex, ey, exsize, eysize);
4407 redraw_mask |= REDRAW_ALL;
4411 /* ---------- new tool button stuff ---------------------------------------- */
4416 struct TextPosInfo *pos;
4419 } toolbutton_info[NUM_TOOL_BUTTONS] =
4422 IMG_REQUEST_BUTTON_GFX_YES, &request.button.yes,
4423 TOOL_CTRL_ID_YES, "yes"
4426 IMG_REQUEST_BUTTON_GFX_NO, &request.button.no,
4427 TOOL_CTRL_ID_NO, "no"
4430 IMG_REQUEST_BUTTON_GFX_CONFIRM, &request.button.confirm,
4431 TOOL_CTRL_ID_CONFIRM, "confirm"
4434 IMG_REQUEST_BUTTON_GFX_PLAYER_1, &request.button.player_1,
4435 TOOL_CTRL_ID_PLAYER_1, "player 1"
4438 IMG_REQUEST_BUTTON_GFX_PLAYER_2, &request.button.player_2,
4439 TOOL_CTRL_ID_PLAYER_2, "player 2"
4442 IMG_REQUEST_BUTTON_GFX_PLAYER_3, &request.button.player_3,
4443 TOOL_CTRL_ID_PLAYER_3, "player 3"
4446 IMG_REQUEST_BUTTON_GFX_PLAYER_4, &request.button.player_4,
4447 TOOL_CTRL_ID_PLAYER_4, "player 4"
4451 void CreateToolButtons()
4455 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4457 struct GraphicInfo *gfx = &graphic_info[toolbutton_info[i].graphic];
4458 struct TextPosInfo *pos = toolbutton_info[i].pos;
4459 struct GadgetInfo *gi;
4460 Bitmap *deco_bitmap = None;
4461 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
4462 unsigned int event_mask = GD_EVENT_RELEASED;
4465 int gd_x = gfx->src_x;
4466 int gd_y = gfx->src_y;
4467 int gd_xp = gfx->src_x + gfx->pressed_xoffset;
4468 int gd_yp = gfx->src_y + gfx->pressed_yoffset;
4471 if (global.use_envelope_request)
4472 setRequestPosition(&dx, &dy, TRUE);
4474 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
4476 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
4478 getSizedGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr), 0,
4479 pos->size, &deco_bitmap, &deco_x, &deco_y);
4480 deco_xpos = (gfx->width - pos->size) / 2;
4481 deco_ypos = (gfx->height - pos->size) / 2;
4484 gi = CreateGadget(GDI_CUSTOM_ID, id,
4485 GDI_INFO_TEXT, toolbutton_info[i].infotext,
4486 GDI_X, dx + GDI_ACTIVE_POS(pos->x),
4487 GDI_Y, dy + GDI_ACTIVE_POS(pos->y),
4488 GDI_WIDTH, gfx->width,
4489 GDI_HEIGHT, gfx->height,
4490 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
4491 GDI_STATE, GD_BUTTON_UNPRESSED,
4492 GDI_DESIGN_UNPRESSED, gfx->bitmap, gd_x, gd_y,
4493 GDI_DESIGN_PRESSED, gfx->bitmap, gd_xp, gd_yp,
4494 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
4495 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
4496 GDI_DECORATION_SIZE, pos->size, pos->size,
4497 GDI_DECORATION_SHIFTING, 1, 1,
4498 GDI_DIRECT_DRAW, FALSE,
4499 GDI_EVENT_MASK, event_mask,
4500 GDI_CALLBACK_ACTION, HandleToolButtons,
4504 Error(ERR_EXIT, "cannot create gadget");
4506 tool_gadget[id] = gi;
4510 void FreeToolButtons()
4514 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4515 FreeGadget(tool_gadget[i]);
4518 static void UnmapToolButtons()
4522 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4523 UnmapGadget(tool_gadget[i]);
4526 static void HandleToolButtons(struct GadgetInfo *gi)
4528 request_gadget_id = gi->custom_id;
4531 static struct Mapping_EM_to_RND_object
4534 boolean is_rnd_to_em_mapping; /* unique mapping EM <-> RND */
4535 boolean is_backside; /* backside of moving element */
4541 em_object_mapping_list[] =
4544 Xblank, TRUE, FALSE,
4548 Yacid_splash_eB, FALSE, FALSE,
4549 EL_ACID_SPLASH_RIGHT, -1, -1
4552 Yacid_splash_wB, FALSE, FALSE,
4553 EL_ACID_SPLASH_LEFT, -1, -1
4556 #ifdef EM_ENGINE_BAD_ROLL
4558 Xstone_force_e, FALSE, FALSE,
4559 EL_ROCK, -1, MV_BIT_RIGHT
4562 Xstone_force_w, FALSE, FALSE,
4563 EL_ROCK, -1, MV_BIT_LEFT
4566 Xnut_force_e, FALSE, FALSE,
4567 EL_NUT, -1, MV_BIT_RIGHT
4570 Xnut_force_w, FALSE, FALSE,
4571 EL_NUT, -1, MV_BIT_LEFT
4574 Xspring_force_e, FALSE, FALSE,
4575 EL_SPRING, -1, MV_BIT_RIGHT
4578 Xspring_force_w, FALSE, FALSE,
4579 EL_SPRING, -1, MV_BIT_LEFT
4582 Xemerald_force_e, FALSE, FALSE,
4583 EL_EMERALD, -1, MV_BIT_RIGHT
4586 Xemerald_force_w, FALSE, FALSE,
4587 EL_EMERALD, -1, MV_BIT_LEFT
4590 Xdiamond_force_e, FALSE, FALSE,
4591 EL_DIAMOND, -1, MV_BIT_RIGHT
4594 Xdiamond_force_w, FALSE, FALSE,
4595 EL_DIAMOND, -1, MV_BIT_LEFT
4598 Xbomb_force_e, FALSE, FALSE,
4599 EL_BOMB, -1, MV_BIT_RIGHT
4602 Xbomb_force_w, FALSE, FALSE,
4603 EL_BOMB, -1, MV_BIT_LEFT
4605 #endif /* EM_ENGINE_BAD_ROLL */
4608 Xstone, TRUE, FALSE,
4612 Xstone_pause, FALSE, FALSE,
4616 Xstone_fall, FALSE, FALSE,
4620 Ystone_s, FALSE, FALSE,
4621 EL_ROCK, ACTION_FALLING, -1
4624 Ystone_sB, FALSE, TRUE,
4625 EL_ROCK, ACTION_FALLING, -1
4628 Ystone_e, FALSE, FALSE,
4629 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
4632 Ystone_eB, FALSE, TRUE,
4633 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
4636 Ystone_w, FALSE, FALSE,
4637 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
4640 Ystone_wB, FALSE, TRUE,
4641 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
4648 Xnut_pause, FALSE, FALSE,
4652 Xnut_fall, FALSE, FALSE,
4656 Ynut_s, FALSE, FALSE,
4657 EL_NUT, ACTION_FALLING, -1
4660 Ynut_sB, FALSE, TRUE,
4661 EL_NUT, ACTION_FALLING, -1
4664 Ynut_e, FALSE, FALSE,
4665 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
4668 Ynut_eB, FALSE, TRUE,
4669 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
4672 Ynut_w, FALSE, FALSE,
4673 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
4676 Ynut_wB, FALSE, TRUE,
4677 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
4680 Xbug_n, TRUE, FALSE,
4684 Xbug_e, TRUE, FALSE,
4685 EL_BUG_RIGHT, -1, -1
4688 Xbug_s, TRUE, FALSE,
4692 Xbug_w, TRUE, FALSE,
4696 Xbug_gon, FALSE, FALSE,
4700 Xbug_goe, FALSE, FALSE,
4701 EL_BUG_RIGHT, -1, -1
4704 Xbug_gos, FALSE, FALSE,
4708 Xbug_gow, FALSE, FALSE,
4712 Ybug_n, FALSE, FALSE,
4713 EL_BUG, ACTION_MOVING, MV_BIT_UP
4716 Ybug_nB, FALSE, TRUE,
4717 EL_BUG, ACTION_MOVING, MV_BIT_UP
4720 Ybug_e, FALSE, FALSE,
4721 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
4724 Ybug_eB, FALSE, TRUE,
4725 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
4728 Ybug_s, FALSE, FALSE,
4729 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
4732 Ybug_sB, FALSE, TRUE,
4733 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
4736 Ybug_w, FALSE, FALSE,
4737 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
4740 Ybug_wB, FALSE, TRUE,
4741 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
4744 Ybug_w_n, FALSE, FALSE,
4745 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
4748 Ybug_n_e, FALSE, FALSE,
4749 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
4752 Ybug_e_s, FALSE, FALSE,
4753 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
4756 Ybug_s_w, FALSE, FALSE,
4757 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
4760 Ybug_e_n, FALSE, FALSE,
4761 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
4764 Ybug_s_e, FALSE, FALSE,
4765 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
4768 Ybug_w_s, FALSE, FALSE,
4769 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
4772 Ybug_n_w, FALSE, FALSE,
4773 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
4776 Ybug_stone, FALSE, FALSE,
4777 EL_BUG, ACTION_SMASHED_BY_ROCK, -1
4780 Ybug_spring, FALSE, FALSE,
4781 EL_BUG, ACTION_SMASHED_BY_SPRING, -1
4784 Xtank_n, TRUE, FALSE,
4785 EL_SPACESHIP_UP, -1, -1
4788 Xtank_e, TRUE, FALSE,
4789 EL_SPACESHIP_RIGHT, -1, -1
4792 Xtank_s, TRUE, FALSE,
4793 EL_SPACESHIP_DOWN, -1, -1
4796 Xtank_w, TRUE, FALSE,
4797 EL_SPACESHIP_LEFT, -1, -1
4800 Xtank_gon, FALSE, FALSE,
4801 EL_SPACESHIP_UP, -1, -1
4804 Xtank_goe, FALSE, FALSE,
4805 EL_SPACESHIP_RIGHT, -1, -1
4808 Xtank_gos, FALSE, FALSE,
4809 EL_SPACESHIP_DOWN, -1, -1
4812 Xtank_gow, FALSE, FALSE,
4813 EL_SPACESHIP_LEFT, -1, -1
4816 Ytank_n, FALSE, FALSE,
4817 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
4820 Ytank_nB, FALSE, TRUE,
4821 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
4824 Ytank_e, FALSE, FALSE,
4825 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
4828 Ytank_eB, FALSE, TRUE,
4829 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
4832 Ytank_s, FALSE, FALSE,
4833 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
4836 Ytank_sB, FALSE, TRUE,
4837 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
4840 Ytank_w, FALSE, FALSE,
4841 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
4844 Ytank_wB, FALSE, TRUE,
4845 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
4848 Ytank_w_n, FALSE, FALSE,
4849 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
4852 Ytank_n_e, FALSE, FALSE,
4853 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
4856 Ytank_e_s, FALSE, FALSE,
4857 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
4860 Ytank_s_w, FALSE, FALSE,
4861 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
4864 Ytank_e_n, FALSE, FALSE,
4865 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
4868 Ytank_s_e, FALSE, FALSE,
4869 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
4872 Ytank_w_s, FALSE, FALSE,
4873 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
4876 Ytank_n_w, FALSE, FALSE,
4877 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
4880 Ytank_stone, FALSE, FALSE,
4881 EL_SPACESHIP, ACTION_SMASHED_BY_ROCK, -1
4884 Ytank_spring, FALSE, FALSE,
4885 EL_SPACESHIP, ACTION_SMASHED_BY_SPRING, -1
4888 Xandroid, TRUE, FALSE,
4889 EL_EMC_ANDROID, ACTION_ACTIVE, -1
4892 Xandroid_1_n, FALSE, FALSE,
4893 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
4896 Xandroid_2_n, FALSE, FALSE,
4897 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
4900 Xandroid_1_e, FALSE, FALSE,
4901 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
4904 Xandroid_2_e, FALSE, FALSE,
4905 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
4908 Xandroid_1_w, FALSE, FALSE,
4909 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
4912 Xandroid_2_w, FALSE, FALSE,
4913 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
4916 Xandroid_1_s, FALSE, FALSE,
4917 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
4920 Xandroid_2_s, FALSE, FALSE,
4921 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
4924 Yandroid_n, FALSE, FALSE,
4925 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
4928 Yandroid_nB, FALSE, TRUE,
4929 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
4932 Yandroid_ne, FALSE, FALSE,
4933 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPRIGHT
4936 Yandroid_neB, FALSE, TRUE,
4937 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPRIGHT
4940 Yandroid_e, FALSE, FALSE,
4941 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
4944 Yandroid_eB, FALSE, TRUE,
4945 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
4948 Yandroid_se, FALSE, FALSE,
4949 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNRIGHT
4952 Yandroid_seB, FALSE, TRUE,
4953 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNRIGHT
4956 Yandroid_s, FALSE, FALSE,
4957 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
4960 Yandroid_sB, FALSE, TRUE,
4961 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
4964 Yandroid_sw, FALSE, FALSE,
4965 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNLEFT
4968 Yandroid_swB, FALSE, TRUE,
4969 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNLEFT
4972 Yandroid_w, FALSE, FALSE,
4973 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
4976 Yandroid_wB, FALSE, TRUE,
4977 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
4980 Yandroid_nw, FALSE, FALSE,
4981 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPLEFT
4984 Yandroid_nwB, FALSE, TRUE,
4985 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPLEFT
4988 Xspring, TRUE, FALSE,
4992 Xspring_pause, FALSE, FALSE,
4996 Xspring_e, FALSE, FALSE,
5000 Xspring_w, FALSE, FALSE,
5004 Xspring_fall, FALSE, FALSE,
5008 Yspring_s, FALSE, FALSE,
5009 EL_SPRING, ACTION_FALLING, -1
5012 Yspring_sB, FALSE, TRUE,
5013 EL_SPRING, ACTION_FALLING, -1
5016 Yspring_e, FALSE, FALSE,
5017 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
5020 Yspring_eB, FALSE, TRUE,
5021 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
5024 Yspring_w, FALSE, FALSE,
5025 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
5028 Yspring_wB, FALSE, TRUE,
5029 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
5032 Yspring_kill_e, FALSE, FALSE,
5033 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
5036 Yspring_kill_eB, FALSE, TRUE,
5037 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
5040 Yspring_kill_w, FALSE, FALSE,
5041 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
5044 Yspring_kill_wB, FALSE, TRUE,
5045 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
5048 Xeater_n, TRUE, FALSE,
5049 EL_YAMYAM_UP, -1, -1
5052 Xeater_e, TRUE, FALSE,
5053 EL_YAMYAM_RIGHT, -1, -1
5056 Xeater_w, TRUE, FALSE,
5057 EL_YAMYAM_LEFT, -1, -1
5060 Xeater_s, TRUE, FALSE,
5061 EL_YAMYAM_DOWN, -1, -1
5064 Yeater_n, FALSE, FALSE,
5065 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
5068 Yeater_nB, FALSE, TRUE,
5069 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
5072 Yeater_e, FALSE, FALSE,
5073 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
5076 Yeater_eB, FALSE, TRUE,
5077 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
5080 Yeater_s, FALSE, FALSE,
5081 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
5084 Yeater_sB, FALSE, TRUE,
5085 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
5088 Yeater_w, FALSE, FALSE,
5089 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
5092 Yeater_wB, FALSE, TRUE,
5093 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
5096 Yeater_stone, FALSE, FALSE,
5097 EL_YAMYAM, ACTION_SMASHED_BY_ROCK, -1
5100 Yeater_spring, FALSE, FALSE,
5101 EL_YAMYAM, ACTION_SMASHED_BY_SPRING, -1
5104 Xalien, TRUE, FALSE,
5108 Xalien_pause, FALSE, FALSE,
5112 Yalien_n, FALSE, FALSE,
5113 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
5116 Yalien_nB, FALSE, TRUE,
5117 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
5120 Yalien_e, FALSE, FALSE,
5121 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
5124 Yalien_eB, FALSE, TRUE,
5125 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
5128 Yalien_s, FALSE, FALSE,
5129 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
5132 Yalien_sB, FALSE, TRUE,
5133 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
5136 Yalien_w, FALSE, FALSE,
5137 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
5140 Yalien_wB, FALSE, TRUE,
5141 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
5144 Yalien_stone, FALSE, FALSE,
5145 EL_ROBOT, ACTION_SMASHED_BY_ROCK, -1
5148 Yalien_spring, FALSE, FALSE,
5149 EL_ROBOT, ACTION_SMASHED_BY_SPRING, -1
5152 Xemerald, TRUE, FALSE,
5156 Xemerald_pause, FALSE, FALSE,
5160 Xemerald_fall, FALSE, FALSE,
5164 Xemerald_shine, FALSE, FALSE,
5165 EL_EMERALD, ACTION_TWINKLING, -1
5168 Yemerald_s, FALSE, FALSE,
5169 EL_EMERALD, ACTION_FALLING, -1
5172 Yemerald_sB, FALSE, TRUE,
5173 EL_EMERALD, ACTION_FALLING, -1
5176 Yemerald_e, FALSE, FALSE,
5177 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
5180 Yemerald_eB, FALSE, TRUE,
5181 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
5184 Yemerald_w, FALSE, FALSE,
5185 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
5188 Yemerald_wB, FALSE, TRUE,
5189 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
5192 Yemerald_eat, FALSE, FALSE,
5193 EL_EMERALD, ACTION_COLLECTING, -1
5196 Yemerald_stone, FALSE, FALSE,
5197 EL_NUT, ACTION_BREAKING, -1
5200 Xdiamond, TRUE, FALSE,
5204 Xdiamond_pause, FALSE, FALSE,
5208 Xdiamond_fall, FALSE, FALSE,
5212 Xdiamond_shine, FALSE, FALSE,
5213 EL_DIAMOND, ACTION_TWINKLING, -1
5216 Ydiamond_s, FALSE, FALSE,
5217 EL_DIAMOND, ACTION_FALLING, -1
5220 Ydiamond_sB, FALSE, TRUE,
5221 EL_DIAMOND, ACTION_FALLING, -1
5224 Ydiamond_e, FALSE, FALSE,
5225 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
5228 Ydiamond_eB, FALSE, TRUE,
5229 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
5232 Ydiamond_w, FALSE, FALSE,
5233 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
5236 Ydiamond_wB, FALSE, TRUE,
5237 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
5240 Ydiamond_eat, FALSE, FALSE,
5241 EL_DIAMOND, ACTION_COLLECTING, -1
5244 Ydiamond_stone, FALSE, FALSE,
5245 EL_DIAMOND, ACTION_SMASHED_BY_ROCK, -1
5248 Xdrip_fall, TRUE, FALSE,
5249 EL_AMOEBA_DROP, -1, -1
5252 Xdrip_stretch, FALSE, FALSE,
5253 EL_AMOEBA_DROP, ACTION_FALLING, -1
5256 Xdrip_stretchB, FALSE, TRUE,
5257 EL_AMOEBA_DROP, ACTION_FALLING, -1
5260 Xdrip_eat, FALSE, FALSE,
5261 EL_AMOEBA_DROP, ACTION_GROWING, -1
5264 Ydrip_s1, FALSE, FALSE,
5265 EL_AMOEBA_DROP, ACTION_FALLING, -1
5268 Ydrip_s1B, FALSE, TRUE,
5269 EL_AMOEBA_DROP, ACTION_FALLING, -1
5272 Ydrip_s2, FALSE, FALSE,
5273 EL_AMOEBA_DROP, ACTION_FALLING, -1
5276 Ydrip_s2B, FALSE, TRUE,
5277 EL_AMOEBA_DROP, ACTION_FALLING, -1
5284 Xbomb_pause, FALSE, FALSE,
5288 Xbomb_fall, FALSE, FALSE,
5292 Ybomb_s, FALSE, FALSE,
5293 EL_BOMB, ACTION_FALLING, -1
5296 Ybomb_sB, FALSE, TRUE,
5297 EL_BOMB, ACTION_FALLING, -1
5300 Ybomb_e, FALSE, FALSE,
5301 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
5304 Ybomb_eB, FALSE, TRUE,
5305 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
5308 Ybomb_w, FALSE, FALSE,
5309 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
5312 Ybomb_wB, FALSE, TRUE,
5313 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
5316 Ybomb_eat, FALSE, FALSE,
5317 EL_BOMB, ACTION_ACTIVATING, -1
5320 Xballoon, TRUE, FALSE,
5324 Yballoon_n, FALSE, FALSE,
5325 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
5328 Yballoon_nB, FALSE, TRUE,
5329 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
5332 Yballoon_e, FALSE, FALSE,
5333 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
5336 Yballoon_eB, FALSE, TRUE,
5337 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
5340 Yballoon_s, FALSE, FALSE,
5341 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
5344 Yballoon_sB, FALSE, TRUE,
5345 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
5348 Yballoon_w, FALSE, FALSE,
5349 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
5352 Yballoon_wB, FALSE, TRUE,
5353 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
5356 Xgrass, TRUE, FALSE,
5357 EL_EMC_GRASS, -1, -1
5360 Ygrass_nB, FALSE, FALSE,
5361 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_UP
5364 Ygrass_eB, FALSE, FALSE,
5365 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_RIGHT
5368 Ygrass_sB, FALSE, FALSE,
5369 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_DOWN
5372 Ygrass_wB, FALSE, FALSE,
5373 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_LEFT
5380 Ydirt_nB, FALSE, FALSE,
5381 EL_SAND, ACTION_DIGGING, MV_BIT_UP
5384 Ydirt_eB, FALSE, FALSE,
5385 EL_SAND, ACTION_DIGGING, MV_BIT_RIGHT
5388 Ydirt_sB, FALSE, FALSE,
5389 EL_SAND, ACTION_DIGGING, MV_BIT_DOWN
5392 Ydirt_wB, FALSE, FALSE,
5393 EL_SAND, ACTION_DIGGING, MV_BIT_LEFT
5396 Xacid_ne, TRUE, FALSE,
5397 EL_ACID_POOL_TOPRIGHT, -1, -1
5400 Xacid_se, TRUE, FALSE,
5401 EL_ACID_POOL_BOTTOMRIGHT, -1, -1
5404 Xacid_s, TRUE, FALSE,
5405 EL_ACID_POOL_BOTTOM, -1, -1
5408 Xacid_sw, TRUE, FALSE,
5409 EL_ACID_POOL_BOTTOMLEFT, -1, -1
5412 Xacid_nw, TRUE, FALSE,
5413 EL_ACID_POOL_TOPLEFT, -1, -1
5416 Xacid_1, TRUE, FALSE,
5420 Xacid_2, FALSE, FALSE,
5424 Xacid_3, FALSE, FALSE,
5428 Xacid_4, FALSE, FALSE,
5432 Xacid_5, FALSE, FALSE,
5436 Xacid_6, FALSE, FALSE,
5440 Xacid_7, FALSE, FALSE,
5444 Xacid_8, FALSE, FALSE,
5448 Xball_1, TRUE, FALSE,
5449 EL_EMC_MAGIC_BALL, -1, -1
5452 Xball_1B, FALSE, FALSE,
5453 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
5456 Xball_2, FALSE, FALSE,
5457 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
5460 Xball_2B, FALSE, FALSE,
5461 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
5464 Yball_eat, FALSE, FALSE,
5465 EL_EMC_MAGIC_BALL, ACTION_DROPPING, -1
5468 Ykey_1_eat, FALSE, FALSE,
5469 EL_EM_KEY_1, ACTION_COLLECTING, -1
5472 Ykey_2_eat, FALSE, FALSE,
5473 EL_EM_KEY_2, ACTION_COLLECTING, -1
5476 Ykey_3_eat, FALSE, FALSE,
5477 EL_EM_KEY_3, ACTION_COLLECTING, -1
5480 Ykey_4_eat, FALSE, FALSE,
5481 EL_EM_KEY_4, ACTION_COLLECTING, -1
5484 Ykey_5_eat, FALSE, FALSE,
5485 EL_EMC_KEY_5, ACTION_COLLECTING, -1
5488 Ykey_6_eat, FALSE, FALSE,
5489 EL_EMC_KEY_6, ACTION_COLLECTING, -1
5492 Ykey_7_eat, FALSE, FALSE,
5493 EL_EMC_KEY_7, ACTION_COLLECTING, -1
5496 Ykey_8_eat, FALSE, FALSE,
5497 EL_EMC_KEY_8, ACTION_COLLECTING, -1
5500 Ylenses_eat, FALSE, FALSE,
5501 EL_EMC_LENSES, ACTION_COLLECTING, -1
5504 Ymagnify_eat, FALSE, FALSE,
5505 EL_EMC_MAGNIFIER, ACTION_COLLECTING, -1
5508 Ygrass_eat, FALSE, FALSE,
5509 EL_EMC_GRASS, ACTION_SNAPPING, -1
5512 Ydirt_eat, FALSE, FALSE,
5513 EL_SAND, ACTION_SNAPPING, -1
5516 Xgrow_ns, TRUE, FALSE,
5517 EL_EXPANDABLE_WALL_VERTICAL, -1, -1
5520 Ygrow_ns_eat, FALSE, FALSE,
5521 EL_EXPANDABLE_WALL_VERTICAL, ACTION_GROWING, -1
5524 Xgrow_ew, TRUE, FALSE,
5525 EL_EXPANDABLE_WALL_HORIZONTAL, -1, -1
5528 Ygrow_ew_eat, FALSE, FALSE,
5529 EL_EXPANDABLE_WALL_HORIZONTAL, ACTION_GROWING, -1
5532 Xwonderwall, TRUE, FALSE,
5533 EL_MAGIC_WALL, -1, -1
5536 XwonderwallB, FALSE, FALSE,
5537 EL_MAGIC_WALL, ACTION_ACTIVE, -1
5540 Xamoeba_1, TRUE, FALSE,
5541 EL_AMOEBA_DRY, ACTION_OTHER, -1
5544 Xamoeba_2, FALSE, FALSE,
5545 EL_AMOEBA_DRY, ACTION_OTHER, -1
5548 Xamoeba_3, FALSE, FALSE,
5549 EL_AMOEBA_DRY, ACTION_OTHER, -1
5552 Xamoeba_4, FALSE, FALSE,
5553 EL_AMOEBA_DRY, ACTION_OTHER, -1
5556 Xamoeba_5, TRUE, FALSE,
5557 EL_AMOEBA_WET, ACTION_OTHER, -1
5560 Xamoeba_6, FALSE, FALSE,
5561 EL_AMOEBA_WET, ACTION_OTHER, -1
5564 Xamoeba_7, FALSE, FALSE,
5565 EL_AMOEBA_WET, ACTION_OTHER, -1
5568 Xamoeba_8, FALSE, FALSE,
5569 EL_AMOEBA_WET, ACTION_OTHER, -1
5572 Xdoor_1, TRUE, FALSE,
5573 EL_EM_GATE_1, -1, -1
5576 Xdoor_2, TRUE, FALSE,
5577 EL_EM_GATE_2, -1, -1
5580 Xdoor_3, TRUE, FALSE,
5581 EL_EM_GATE_3, -1, -1
5584 Xdoor_4, TRUE, FALSE,
5585 EL_EM_GATE_4, -1, -1
5588 Xdoor_5, TRUE, FALSE,
5589 EL_EMC_GATE_5, -1, -1
5592 Xdoor_6, TRUE, FALSE,
5593 EL_EMC_GATE_6, -1, -1
5596 Xdoor_7, TRUE, FALSE,
5597 EL_EMC_GATE_7, -1, -1
5600 Xdoor_8, TRUE, FALSE,
5601 EL_EMC_GATE_8, -1, -1
5604 Xkey_1, TRUE, FALSE,
5608 Xkey_2, TRUE, FALSE,
5612 Xkey_3, TRUE, FALSE,
5616 Xkey_4, TRUE, FALSE,
5620 Xkey_5, TRUE, FALSE,
5621 EL_EMC_KEY_5, -1, -1
5624 Xkey_6, TRUE, FALSE,
5625 EL_EMC_KEY_6, -1, -1
5628 Xkey_7, TRUE, FALSE,
5629 EL_EMC_KEY_7, -1, -1
5632 Xkey_8, TRUE, FALSE,
5633 EL_EMC_KEY_8, -1, -1
5636 Xwind_n, TRUE, FALSE,
5637 EL_BALLOON_SWITCH_UP, -1, -1
5640 Xwind_e, TRUE, FALSE,
5641 EL_BALLOON_SWITCH_RIGHT, -1, -1
5644 Xwind_s, TRUE, FALSE,
5645 EL_BALLOON_SWITCH_DOWN, -1, -1
5648 Xwind_w, TRUE, FALSE,
5649 EL_BALLOON_SWITCH_LEFT, -1, -1
5652 Xwind_nesw, TRUE, FALSE,
5653 EL_BALLOON_SWITCH_ANY, -1, -1
5656 Xwind_stop, TRUE, FALSE,
5657 EL_BALLOON_SWITCH_NONE, -1, -1
5661 EL_EM_EXIT_CLOSED, -1, -1
5664 Xexit_1, TRUE, FALSE,
5665 EL_EM_EXIT_OPEN, -1, -1
5668 Xexit_2, FALSE, FALSE,
5669 EL_EM_EXIT_OPEN, -1, -1
5672 Xexit_3, FALSE, FALSE,
5673 EL_EM_EXIT_OPEN, -1, -1
5676 Xdynamite, TRUE, FALSE,
5677 EL_EM_DYNAMITE, -1, -1
5680 Ydynamite_eat, FALSE, FALSE,
5681 EL_EM_DYNAMITE, ACTION_COLLECTING, -1
5684 Xdynamite_1, TRUE, FALSE,
5685 EL_EM_DYNAMITE_ACTIVE, -1, -1
5688 Xdynamite_2, FALSE, FALSE,
5689 EL_EM_DYNAMITE_ACTIVE, -1, -1
5692 Xdynamite_3, FALSE, FALSE,
5693 EL_EM_DYNAMITE_ACTIVE, -1, -1
5696 Xdynamite_4, FALSE, FALSE,
5697 EL_EM_DYNAMITE_ACTIVE, -1, -1
5700 Xbumper, TRUE, FALSE,
5701 EL_EMC_SPRING_BUMPER, -1, -1
5704 XbumperB, FALSE, FALSE,
5705 EL_EMC_SPRING_BUMPER, ACTION_ACTIVE, -1
5708 Xwheel, TRUE, FALSE,
5709 EL_ROBOT_WHEEL, -1, -1
5712 XwheelB, FALSE, FALSE,
5713 EL_ROBOT_WHEEL, ACTION_ACTIVE, -1
5716 Xswitch, TRUE, FALSE,
5717 EL_EMC_MAGIC_BALL_SWITCH, -1, -1
5720 XswitchB, FALSE, FALSE,
5721 EL_EMC_MAGIC_BALL_SWITCH, ACTION_ACTIVE, -1
5725 EL_QUICKSAND_EMPTY, -1, -1
5728 Xsand_stone, TRUE, FALSE,
5729 EL_QUICKSAND_FULL, -1, -1
5732 Xsand_stonein_1, FALSE, TRUE,
5733 EL_ROCK, ACTION_FILLING, -1
5736 Xsand_stonein_2, FALSE, TRUE,
5737 EL_ROCK, ACTION_FILLING, -1
5740 Xsand_stonein_3, FALSE, TRUE,
5741 EL_ROCK, ACTION_FILLING, -1
5744 Xsand_stonein_4, FALSE, TRUE,
5745 EL_ROCK, ACTION_FILLING, -1
5748 Xsand_stonesand_1, FALSE, FALSE,
5749 EL_QUICKSAND_EMPTYING, -1, -1
5752 Xsand_stonesand_2, FALSE, FALSE,
5753 EL_QUICKSAND_EMPTYING, -1, -1
5756 Xsand_stonesand_3, FALSE, FALSE,
5757 EL_QUICKSAND_EMPTYING, -1, -1
5760 Xsand_stonesand_4, FALSE, FALSE,
5761 EL_QUICKSAND_EMPTYING, -1, -1
5764 Xsand_stonesand_quickout_1, FALSE, FALSE,
5765 EL_QUICKSAND_EMPTYING, -1, -1
5768 Xsand_stonesand_quickout_2, FALSE, FALSE,
5769 EL_QUICKSAND_EMPTYING, -1, -1
5772 Xsand_stoneout_1, FALSE, FALSE,
5773 EL_ROCK, ACTION_EMPTYING, -1
5776 Xsand_stoneout_2, FALSE, FALSE,
5777 EL_ROCK, ACTION_EMPTYING, -1
5780 Xsand_sandstone_1, FALSE, FALSE,
5781 EL_QUICKSAND_FILLING, -1, -1
5784 Xsand_sandstone_2, FALSE, FALSE,
5785 EL_QUICKSAND_FILLING, -1, -1
5788 Xsand_sandstone_3, FALSE, FALSE,
5789 EL_QUICKSAND_FILLING, -1, -1
5792 Xsand_sandstone_4, FALSE, FALSE,
5793 EL_QUICKSAND_FILLING, -1, -1
5796 Xplant, TRUE, FALSE,
5797 EL_EMC_PLANT, -1, -1
5800 Yplant, FALSE, FALSE,
5801 EL_EMC_PLANT, -1, -1
5804 Xlenses, TRUE, FALSE,
5805 EL_EMC_LENSES, -1, -1
5808 Xmagnify, TRUE, FALSE,
5809 EL_EMC_MAGNIFIER, -1, -1
5812 Xdripper, TRUE, FALSE,
5813 EL_EMC_DRIPPER, -1, -1
5816 XdripperB, FALSE, FALSE,
5817 EL_EMC_DRIPPER, ACTION_ACTIVE, -1
5820 Xfake_blank, TRUE, FALSE,
5821 EL_INVISIBLE_WALL, -1, -1
5824 Xfake_blankB, FALSE, FALSE,
5825 EL_INVISIBLE_WALL, ACTION_ACTIVE, -1
5828 Xfake_grass, TRUE, FALSE,
5829 EL_EMC_FAKE_GRASS, -1, -1
5832 Xfake_grassB, FALSE, FALSE,
5833 EL_EMC_FAKE_GRASS, ACTION_ACTIVE, -1
5836 Xfake_door_1, TRUE, FALSE,
5837 EL_EM_GATE_1_GRAY, -1, -1
5840 Xfake_door_2, TRUE, FALSE,
5841 EL_EM_GATE_2_GRAY, -1, -1
5844 Xfake_door_3, TRUE, FALSE,
5845 EL_EM_GATE_3_GRAY, -1, -1
5848 Xfake_door_4, TRUE, FALSE,
5849 EL_EM_GATE_4_GRAY, -1, -1
5852 Xfake_door_5, TRUE, FALSE,
5853 EL_EMC_GATE_5_GRAY, -1, -1
5856 Xfake_door_6, TRUE, FALSE,
5857 EL_EMC_GATE_6_GRAY, -1, -1
5860 Xfake_door_7, TRUE, FALSE,
5861 EL_EMC_GATE_7_GRAY, -1, -1
5864 Xfake_door_8, TRUE, FALSE,
5865 EL_EMC_GATE_8_GRAY, -1, -1
5868 Xfake_acid_1, TRUE, FALSE,
5869 EL_EMC_FAKE_ACID, -1, -1
5872 Xfake_acid_2, FALSE, FALSE,
5873 EL_EMC_FAKE_ACID, -1, -1
5876 Xfake_acid_3, FALSE, FALSE,
5877 EL_EMC_FAKE_ACID, -1, -1
5880 Xfake_acid_4, FALSE, FALSE,
5881 EL_EMC_FAKE_ACID, -1, -1
5884 Xfake_acid_5, FALSE, FALSE,
5885 EL_EMC_FAKE_ACID, -1, -1
5888 Xfake_acid_6, FALSE, FALSE,
5889 EL_EMC_FAKE_ACID, -1, -1
5892 Xfake_acid_7, FALSE, FALSE,
5893 EL_EMC_FAKE_ACID, -1, -1
5896 Xfake_acid_8, FALSE, FALSE,
5897 EL_EMC_FAKE_ACID, -1, -1
5900 Xsteel_1, TRUE, FALSE,
5901 EL_STEELWALL, -1, -1
5904 Xsteel_2, TRUE, FALSE,
5905 EL_EMC_STEELWALL_2, -1, -1
5908 Xsteel_3, TRUE, FALSE,
5909 EL_EMC_STEELWALL_3, -1, -1
5912 Xsteel_4, TRUE, FALSE,
5913 EL_EMC_STEELWALL_4, -1, -1
5916 Xwall_1, TRUE, FALSE,
5920 Xwall_2, TRUE, FALSE,
5921 EL_EMC_WALL_14, -1, -1
5924 Xwall_3, TRUE, FALSE,
5925 EL_EMC_WALL_15, -1, -1
5928 Xwall_4, TRUE, FALSE,
5929 EL_EMC_WALL_16, -1, -1
5932 Xround_wall_1, TRUE, FALSE,
5933 EL_WALL_SLIPPERY, -1, -1
5936 Xround_wall_2, TRUE, FALSE,
5937 EL_EMC_WALL_SLIPPERY_2, -1, -1
5940 Xround_wall_3, TRUE, FALSE,
5941 EL_EMC_WALL_SLIPPERY_3, -1, -1
5944 Xround_wall_4, TRUE, FALSE,
5945 EL_EMC_WALL_SLIPPERY_4, -1, -1
5948 Xdecor_1, TRUE, FALSE,
5949 EL_EMC_WALL_8, -1, -1
5952 Xdecor_2, TRUE, FALSE,
5953 EL_EMC_WALL_6, -1, -1
5956 Xdecor_3, TRUE, FALSE,
5957 EL_EMC_WALL_4, -1, -1
5960 Xdecor_4, TRUE, FALSE,
5961 EL_EMC_WALL_7, -1, -1
5964 Xdecor_5, TRUE, FALSE,
5965 EL_EMC_WALL_5, -1, -1
5968 Xdecor_6, TRUE, FALSE,
5969 EL_EMC_WALL_9, -1, -1
5972 Xdecor_7, TRUE, FALSE,
5973 EL_EMC_WALL_10, -1, -1
5976 Xdecor_8, TRUE, FALSE,
5977 EL_EMC_WALL_1, -1, -1
5980 Xdecor_9, TRUE, FALSE,
5981 EL_EMC_WALL_2, -1, -1
5984 Xdecor_10, TRUE, FALSE,
5985 EL_EMC_WALL_3, -1, -1
5988 Xdecor_11, TRUE, FALSE,
5989 EL_EMC_WALL_11, -1, -1
5992 Xdecor_12, TRUE, FALSE,
5993 EL_EMC_WALL_12, -1, -1
5996 Xalpha_0, TRUE, FALSE,
5997 EL_CHAR('0'), -1, -1
6000 Xalpha_1, TRUE, FALSE,
6001 EL_CHAR('1'), -1, -1
6004 Xalpha_2, TRUE, FALSE,
6005 EL_CHAR('2'), -1, -1
6008 Xalpha_3, TRUE, FALSE,
6009 EL_CHAR('3'), -1, -1
6012 Xalpha_4, TRUE, FALSE,
6013 EL_CHAR('4'), -1, -1
6016 Xalpha_5, TRUE, FALSE,
6017 EL_CHAR('5'), -1, -1
6020 Xalpha_6, TRUE, FALSE,
6021 EL_CHAR('6'), -1, -1
6024 Xalpha_7, TRUE, FALSE,
6025 EL_CHAR('7'), -1, -1
6028 Xalpha_8, TRUE, FALSE,
6029 EL_CHAR('8'), -1, -1
6032 Xalpha_9, TRUE, FALSE,
6033 EL_CHAR('9'), -1, -1
6036 Xalpha_excla, TRUE, FALSE,
6037 EL_CHAR('!'), -1, -1
6040 Xalpha_quote, TRUE, FALSE,
6041 EL_CHAR('"'), -1, -1
6044 Xalpha_comma, TRUE, FALSE,
6045 EL_CHAR(','), -1, -1
6048 Xalpha_minus, TRUE, FALSE,
6049 EL_CHAR('-'), -1, -1
6052 Xalpha_perio, TRUE, FALSE,
6053 EL_CHAR('.'), -1, -1
6056 Xalpha_colon, TRUE, FALSE,
6057 EL_CHAR(':'), -1, -1
6060 Xalpha_quest, TRUE, FALSE,
6061 EL_CHAR('?'), -1, -1
6064 Xalpha_a, TRUE, FALSE,
6065 EL_CHAR('A'), -1, -1
6068 Xalpha_b, TRUE, FALSE,
6069 EL_CHAR('B'), -1, -1
6072 Xalpha_c, TRUE, FALSE,
6073 EL_CHAR('C'), -1, -1
6076 Xalpha_d, TRUE, FALSE,
6077 EL_CHAR('D'), -1, -1
6080 Xalpha_e, TRUE, FALSE,
6081 EL_CHAR('E'), -1, -1
6084 Xalpha_f, TRUE, FALSE,
6085 EL_CHAR('F'), -1, -1
6088 Xalpha_g, TRUE, FALSE,
6089 EL_CHAR('G'), -1, -1
6092 Xalpha_h, TRUE, FALSE,
6093 EL_CHAR('H'), -1, -1
6096 Xalpha_i, TRUE, FALSE,
6097 EL_CHAR('I'), -1, -1
6100 Xalpha_j, TRUE, FALSE,
6101 EL_CHAR('J'), -1, -1
6104 Xalpha_k, TRUE, FALSE,
6105 EL_CHAR('K'), -1, -1
6108 Xalpha_l, TRUE, FALSE,
6109 EL_CHAR('L'), -1, -1
6112 Xalpha_m, TRUE, FALSE,
6113 EL_CHAR('M'), -1, -1
6116 Xalpha_n, TRUE, FALSE,
6117 EL_CHAR('N'), -1, -1
6120 Xalpha_o, TRUE, FALSE,
6121 EL_CHAR('O'), -1, -1
6124 Xalpha_p, TRUE, FALSE,
6125 EL_CHAR('P'), -1, -1
6128 Xalpha_q, TRUE, FALSE,
6129 EL_CHAR('Q'), -1, -1
6132 Xalpha_r, TRUE, FALSE,
6133 EL_CHAR('R'), -1, -1
6136 Xalpha_s, TRUE, FALSE,
6137 EL_CHAR('S'), -1, -1
6140 Xalpha_t, TRUE, FALSE,
6141 EL_CHAR('T'), -1, -1
6144 Xalpha_u, TRUE, FALSE,
6145 EL_CHAR('U'), -1, -1
6148 Xalpha_v, TRUE, FALSE,
6149 EL_CHAR('V'), -1, -1
6152 Xalpha_w, TRUE, FALSE,
6153 EL_CHAR('W'), -1, -1
6156 Xalpha_x, TRUE, FALSE,
6157 EL_CHAR('X'), -1, -1
6160 Xalpha_y, TRUE, FALSE,
6161 EL_CHAR('Y'), -1, -1
6164 Xalpha_z, TRUE, FALSE,
6165 EL_CHAR('Z'), -1, -1
6168 Xalpha_arrow_e, TRUE, FALSE,
6169 EL_CHAR('>'), -1, -1
6172 Xalpha_arrow_w, TRUE, FALSE,
6173 EL_CHAR('<'), -1, -1
6176 Xalpha_copyr, TRUE, FALSE,
6177 EL_CHAR(CHAR_BYTE_COPYRIGHT), -1, -1
6181 Xboom_bug, FALSE, FALSE,
6182 EL_BUG, ACTION_EXPLODING, -1
6185 Xboom_bomb, FALSE, FALSE,
6186 EL_BOMB, ACTION_EXPLODING, -1
6189 Xboom_android, FALSE, FALSE,
6190 EL_EMC_ANDROID, ACTION_OTHER, -1
6193 Xboom_1, FALSE, FALSE,
6194 EL_DEFAULT, ACTION_EXPLODING, -1
6197 Xboom_2, FALSE, FALSE,
6198 EL_DEFAULT, ACTION_EXPLODING, -1
6201 Znormal, FALSE, FALSE,
6205 Zdynamite, FALSE, FALSE,
6209 Zplayer, FALSE, FALSE,
6213 ZBORDER, FALSE, FALSE,
6223 static struct Mapping_EM_to_RND_player
6232 em_player_mapping_list[] =
6236 EL_PLAYER_1, ACTION_MOVING, MV_BIT_UP,
6240 EL_PLAYER_1, ACTION_MOVING, MV_BIT_RIGHT,
6244 EL_PLAYER_1, ACTION_MOVING, MV_BIT_DOWN,
6248 EL_PLAYER_1, ACTION_MOVING, MV_BIT_LEFT,
6252 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_UP,
6256 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_RIGHT,
6260 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_DOWN,
6264 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_LEFT,
6268 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_UP,
6272 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_RIGHT,
6276 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_DOWN,
6280 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_LEFT,
6284 EL_PLAYER_2, ACTION_MOVING, MV_BIT_UP,
6288 EL_PLAYER_2, ACTION_MOVING, MV_BIT_RIGHT,
6292 EL_PLAYER_2, ACTION_MOVING, MV_BIT_DOWN,
6296 EL_PLAYER_2, ACTION_MOVING, MV_BIT_LEFT,
6300 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_UP,
6304 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_RIGHT,
6308 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_DOWN,
6312 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_LEFT,
6316 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_UP,
6320 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_RIGHT,
6324 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_DOWN,
6328 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_LEFT,
6332 EL_PLAYER_1, ACTION_DEFAULT, -1,
6336 EL_PLAYER_2, ACTION_DEFAULT, -1,
6340 EL_PLAYER_3, ACTION_MOVING, MV_BIT_UP,
6344 EL_PLAYER_3, ACTION_MOVING, MV_BIT_RIGHT,
6348 EL_PLAYER_3, ACTION_MOVING, MV_BIT_DOWN,
6352 EL_PLAYER_3, ACTION_MOVING, MV_BIT_LEFT,
6356 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_UP,
6360 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_RIGHT,
6364 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_DOWN,
6368 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_LEFT,
6372 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_UP,
6376 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_RIGHT,
6380 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_DOWN,
6384 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_LEFT,
6388 EL_PLAYER_4, ACTION_MOVING, MV_BIT_UP,
6392 EL_PLAYER_4, ACTION_MOVING, MV_BIT_RIGHT,
6396 EL_PLAYER_4, ACTION_MOVING, MV_BIT_DOWN,
6400 EL_PLAYER_4, ACTION_MOVING, MV_BIT_LEFT,
6404 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_UP,
6408 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_RIGHT,
6412 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_DOWN,
6416 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_LEFT,
6420 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_UP,
6424 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_RIGHT,
6428 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_DOWN,
6432 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_LEFT,
6436 EL_PLAYER_3, ACTION_DEFAULT, -1,
6440 EL_PLAYER_4, ACTION_DEFAULT, -1,
6449 int map_element_RND_to_EM(int element_rnd)
6451 static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
6452 static boolean mapping_initialized = FALSE;
6454 if (!mapping_initialized)
6458 /* return "Xalpha_quest" for all undefined elements in mapping array */
6459 for (i = 0; i < NUM_FILE_ELEMENTS; i++)
6460 mapping_RND_to_EM[i] = Xalpha_quest;
6462 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
6463 if (em_object_mapping_list[i].is_rnd_to_em_mapping)
6464 mapping_RND_to_EM[em_object_mapping_list[i].element_rnd] =
6465 em_object_mapping_list[i].element_em;
6467 mapping_initialized = TRUE;
6470 if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
6471 return mapping_RND_to_EM[element_rnd];
6473 Error(ERR_WARN, "invalid RND level element %d", element_rnd);
6478 int map_element_EM_to_RND(int element_em)
6480 static unsigned short mapping_EM_to_RND[TILE_MAX];
6481 static boolean mapping_initialized = FALSE;
6483 if (!mapping_initialized)
6487 /* return "EL_UNKNOWN" for all undefined elements in mapping array */
6488 for (i = 0; i < TILE_MAX; i++)
6489 mapping_EM_to_RND[i] = EL_UNKNOWN;
6491 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
6492 mapping_EM_to_RND[em_object_mapping_list[i].element_em] =
6493 em_object_mapping_list[i].element_rnd;
6495 mapping_initialized = TRUE;
6498 if (element_em >= 0 && element_em < TILE_MAX)
6499 return mapping_EM_to_RND[element_em];
6501 Error(ERR_WARN, "invalid EM level element %d", element_em);
6506 void map_android_clone_elements_RND_to_EM(struct LevelInfo *level)
6508 struct LevelInfo_EM *level_em = level->native_em_level;
6509 struct LEVEL *lev = level_em->lev;
6512 for (i = 0; i < TILE_MAX; i++)
6513 lev->android_array[i] = Xblank;
6515 for (i = 0; i < level->num_android_clone_elements; i++)
6517 int element_rnd = level->android_clone_element[i];
6518 int element_em = map_element_RND_to_EM(element_rnd);
6520 for (j = 0; em_object_mapping_list[j].element_em != -1; j++)
6521 if (em_object_mapping_list[j].element_rnd == element_rnd)
6522 lev->android_array[em_object_mapping_list[j].element_em] = element_em;
6526 void map_android_clone_elements_EM_to_RND(struct LevelInfo *level)
6528 struct LevelInfo_EM *level_em = level->native_em_level;
6529 struct LEVEL *lev = level_em->lev;
6532 level->num_android_clone_elements = 0;
6534 for (i = 0; i < TILE_MAX; i++)
6536 int element_em = lev->android_array[i];
6538 boolean element_found = FALSE;
6540 if (element_em == Xblank)
6543 element_rnd = map_element_EM_to_RND(element_em);
6545 for (j = 0; j < level->num_android_clone_elements; j++)
6546 if (level->android_clone_element[j] == element_rnd)
6547 element_found = TRUE;
6551 level->android_clone_element[level->num_android_clone_elements++] =
6554 if (level->num_android_clone_elements == MAX_ANDROID_ELEMENTS)
6559 if (level->num_android_clone_elements == 0)
6561 level->num_android_clone_elements = 1;
6562 level->android_clone_element[0] = EL_EMPTY;
6566 int map_direction_RND_to_EM(int direction)
6568 return (direction == MV_UP ? 0 :
6569 direction == MV_RIGHT ? 1 :
6570 direction == MV_DOWN ? 2 :
6571 direction == MV_LEFT ? 3 :
6575 int map_direction_EM_to_RND(int direction)
6577 return (direction == 0 ? MV_UP :
6578 direction == 1 ? MV_RIGHT :
6579 direction == 2 ? MV_DOWN :
6580 direction == 3 ? MV_LEFT :
6584 int map_element_RND_to_SP(int element_rnd)
6586 int element_sp = 0x20; /* map unknown elements to yellow "hardware" */
6588 if (element_rnd >= EL_SP_START &&
6589 element_rnd <= EL_SP_END)
6590 element_sp = element_rnd - EL_SP_START;
6591 else if (element_rnd == EL_EMPTY_SPACE)
6593 else if (element_rnd == EL_INVISIBLE_WALL)
6599 int map_element_SP_to_RND(int element_sp)
6601 int element_rnd = EL_UNKNOWN;
6603 if (element_sp >= 0x00 &&
6605 element_rnd = EL_SP_START + element_sp;
6606 else if (element_sp == 0x28)
6607 element_rnd = EL_INVISIBLE_WALL;
6612 int map_action_SP_to_RND(int action_sp)
6616 case actActive: return ACTION_ACTIVE;
6617 case actImpact: return ACTION_IMPACT;
6618 case actExploding: return ACTION_EXPLODING;
6619 case actDigging: return ACTION_DIGGING;
6620 case actSnapping: return ACTION_SNAPPING;
6621 case actCollecting: return ACTION_COLLECTING;
6622 case actPassing: return ACTION_PASSING;
6623 case actPushing: return ACTION_PUSHING;
6624 case actDropping: return ACTION_DROPPING;
6626 default: return ACTION_DEFAULT;
6630 int get_next_element(int element)
6634 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
6635 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
6636 case EL_QUICKSAND_FAST_FILLING: return EL_QUICKSAND_FAST_FULL;
6637 case EL_QUICKSAND_FAST_EMPTYING: return EL_QUICKSAND_FAST_EMPTY;
6638 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
6639 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
6640 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
6641 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
6642 case EL_DC_MAGIC_WALL_FILLING: return EL_DC_MAGIC_WALL_FULL;
6643 case EL_DC_MAGIC_WALL_EMPTYING: return EL_DC_MAGIC_WALL_ACTIVE;
6644 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
6646 default: return element;
6650 int el_act_dir2img(int element, int action, int direction)
6652 element = GFX_ELEMENT(element);
6653 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
6655 /* direction_graphic[][] == graphic[] for undefined direction graphics */
6656 return element_info[element].direction_graphic[action][direction];
6659 static int el_act_dir2crm(int element, int action, int direction)
6661 element = GFX_ELEMENT(element);
6662 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
6664 /* direction_graphic[][] == graphic[] for undefined direction graphics */
6665 return element_info[element].direction_crumbled[action][direction];
6668 int el_act2img(int element, int action)
6670 element = GFX_ELEMENT(element);
6672 return element_info[element].graphic[action];
6675 int el_act2crm(int element, int action)
6677 element = GFX_ELEMENT(element);
6679 return element_info[element].crumbled[action];
6682 int el_dir2img(int element, int direction)
6684 element = GFX_ELEMENT(element);
6686 return el_act_dir2img(element, ACTION_DEFAULT, direction);
6689 int el2baseimg(int element)
6691 return element_info[element].graphic[ACTION_DEFAULT];
6694 int el2img(int element)
6696 element = GFX_ELEMENT(element);
6698 return element_info[element].graphic[ACTION_DEFAULT];
6701 int el2edimg(int element)
6703 element = GFX_ELEMENT(element);
6705 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
6708 int el2preimg(int element)
6710 element = GFX_ELEMENT(element);
6712 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
6715 int el2panelimg(int element)
6717 element = GFX_ELEMENT(element);
6719 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PANEL];
6722 int font2baseimg(int font_nr)
6724 return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
6727 int getBeltNrFromBeltElement(int element)
6729 return (element < EL_CONVEYOR_BELT_2_LEFT ? 0 :
6730 element < EL_CONVEYOR_BELT_3_LEFT ? 1 :
6731 element < EL_CONVEYOR_BELT_4_LEFT ? 2 : 3);
6734 int getBeltNrFromBeltActiveElement(int element)
6736 return (element < EL_CONVEYOR_BELT_2_LEFT_ACTIVE ? 0 :
6737 element < EL_CONVEYOR_BELT_3_LEFT_ACTIVE ? 1 :
6738 element < EL_CONVEYOR_BELT_4_LEFT_ACTIVE ? 2 : 3);
6741 int getBeltNrFromBeltSwitchElement(int element)
6743 return (element < EL_CONVEYOR_BELT_2_SWITCH_LEFT ? 0 :
6744 element < EL_CONVEYOR_BELT_3_SWITCH_LEFT ? 1 :
6745 element < EL_CONVEYOR_BELT_4_SWITCH_LEFT ? 2 : 3);
6748 int getBeltDirNrFromBeltElement(int element)
6750 static int belt_base_element[4] =
6752 EL_CONVEYOR_BELT_1_LEFT,
6753 EL_CONVEYOR_BELT_2_LEFT,
6754 EL_CONVEYOR_BELT_3_LEFT,
6755 EL_CONVEYOR_BELT_4_LEFT
6758 int belt_nr = getBeltNrFromBeltElement(element);
6759 int belt_dir_nr = element - belt_base_element[belt_nr];
6761 return (belt_dir_nr % 3);
6764 int getBeltDirNrFromBeltSwitchElement(int element)
6766 static int belt_base_element[4] =
6768 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
6769 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
6770 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
6771 EL_CONVEYOR_BELT_4_SWITCH_LEFT
6774 int belt_nr = getBeltNrFromBeltSwitchElement(element);
6775 int belt_dir_nr = element - belt_base_element[belt_nr];
6777 return (belt_dir_nr % 3);
6780 int getBeltDirFromBeltElement(int element)
6782 static int belt_move_dir[3] =
6789 int belt_dir_nr = getBeltDirNrFromBeltElement(element);
6791 return belt_move_dir[belt_dir_nr];
6794 int getBeltDirFromBeltSwitchElement(int element)
6796 static int belt_move_dir[3] =
6803 int belt_dir_nr = getBeltDirNrFromBeltSwitchElement(element);
6805 return belt_move_dir[belt_dir_nr];
6808 int getBeltElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
6810 static int belt_base_element[4] =
6812 EL_CONVEYOR_BELT_1_LEFT,
6813 EL_CONVEYOR_BELT_2_LEFT,
6814 EL_CONVEYOR_BELT_3_LEFT,
6815 EL_CONVEYOR_BELT_4_LEFT
6818 return belt_base_element[belt_nr] + belt_dir_nr;
6821 int getBeltElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
6823 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
6825 return getBeltElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
6828 int getBeltSwitchElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
6830 static int belt_base_element[4] =
6832 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
6833 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
6834 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
6835 EL_CONVEYOR_BELT_4_SWITCH_LEFT
6838 return belt_base_element[belt_nr] + belt_dir_nr;
6841 int getBeltSwitchElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
6843 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
6845 return getBeltSwitchElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
6848 boolean getTeamMode_EM()
6850 return game.team_mode;
6853 int getGameFrameDelay_EM(int native_em_game_frame_delay)
6855 int game_frame_delay_value;
6857 game_frame_delay_value =
6858 (tape.playing && tape.fast_forward ? FfwdFrameDelay :
6859 GameFrameDelay == GAME_FRAME_DELAY ? native_em_game_frame_delay :
6862 if (tape.playing && tape.warp_forward && !tape.pausing)
6863 game_frame_delay_value = 0;
6865 return game_frame_delay_value;
6868 unsigned int InitRND(int seed)
6870 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
6871 return InitEngineRandom_EM(seed);
6872 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
6873 return InitEngineRandom_SP(seed);
6875 return InitEngineRandom_RND(seed);
6878 static struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
6879 static struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
6881 inline static int get_effective_element_EM(int tile, int frame_em)
6883 int element = object_mapping[tile].element_rnd;
6884 int action = object_mapping[tile].action;
6885 boolean is_backside = object_mapping[tile].is_backside;
6886 boolean action_removing = (action == ACTION_DIGGING ||
6887 action == ACTION_SNAPPING ||
6888 action == ACTION_COLLECTING);
6894 case Yacid_splash_eB:
6895 case Yacid_splash_wB:
6896 return (frame_em > 5 ? EL_EMPTY : element);
6902 else /* frame_em == 7 */
6906 case Yacid_splash_eB:
6907 case Yacid_splash_wB:
6910 case Yemerald_stone:
6913 case Ydiamond_stone:
6917 case Xdrip_stretchB:
6936 case Xsand_stonein_1:
6937 case Xsand_stonein_2:
6938 case Xsand_stonein_3:
6939 case Xsand_stonein_4:
6943 return (is_backside || action_removing ? EL_EMPTY : element);
6948 inline static boolean check_linear_animation_EM(int tile)
6952 case Xsand_stonesand_1:
6953 case Xsand_stonesand_quickout_1:
6954 case Xsand_sandstone_1:
6955 case Xsand_stonein_1:
6956 case Xsand_stoneout_1:
6975 case Yacid_splash_eB:
6976 case Yacid_splash_wB:
6977 case Yemerald_stone:
6984 inline static void set_crumbled_graphics_EM(struct GraphicInfo_EM *g_em,
6985 boolean has_crumbled_graphics,
6986 int crumbled, int sync_frame)
6988 /* if element can be crumbled, but certain action graphics are just empty
6989 space (like instantly snapping sand to empty space in 1 frame), do not
6990 treat these empty space graphics as crumbled graphics in EMC engine */
6991 if (crumbled == IMG_EMPTY_SPACE)
6992 has_crumbled_graphics = FALSE;
6994 if (has_crumbled_graphics)
6996 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
6997 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
6998 g_crumbled->anim_delay,
6999 g_crumbled->anim_mode,
7000 g_crumbled->anim_start_frame,
7003 getGraphicSource(crumbled, frame_crumbled, &g_em->crumbled_bitmap,
7004 &g_em->crumbled_src_x, &g_em->crumbled_src_y);
7006 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
7008 g_em->has_crumbled_graphics = TRUE;
7012 g_em->crumbled_bitmap = NULL;
7013 g_em->crumbled_src_x = 0;
7014 g_em->crumbled_src_y = 0;
7015 g_em->crumbled_border_size = 0;
7017 g_em->has_crumbled_graphics = FALSE;
7021 void ResetGfxAnimation_EM(int x, int y, int tile)
7026 void SetGfxAnimation_EM(struct GraphicInfo_EM *g_em,
7027 int tile, int frame_em, int x, int y)
7029 int action = object_mapping[tile].action;
7030 int direction = object_mapping[tile].direction;
7031 int effective_element = get_effective_element_EM(tile, frame_em);
7032 int graphic = (direction == MV_NONE ?
7033 el_act2img(effective_element, action) :
7034 el_act_dir2img(effective_element, action, direction));
7035 struct GraphicInfo *g = &graphic_info[graphic];
7037 boolean action_removing = (action == ACTION_DIGGING ||
7038 action == ACTION_SNAPPING ||
7039 action == ACTION_COLLECTING);
7040 boolean action_moving = (action == ACTION_FALLING ||
7041 action == ACTION_MOVING ||
7042 action == ACTION_PUSHING ||
7043 action == ACTION_EATING ||
7044 action == ACTION_FILLING ||
7045 action == ACTION_EMPTYING);
7046 boolean action_falling = (action == ACTION_FALLING ||
7047 action == ACTION_FILLING ||
7048 action == ACTION_EMPTYING);
7050 /* special case: graphic uses "2nd movement tile" and has defined
7051 7 frames for movement animation (or less) => use default graphic
7052 for last (8th) frame which ends the movement animation */
7053 if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
7055 action = ACTION_DEFAULT; /* (keep action_* unchanged for now) */
7056 graphic = (direction == MV_NONE ?
7057 el_act2img(effective_element, action) :
7058 el_act_dir2img(effective_element, action, direction));
7060 g = &graphic_info[graphic];
7063 if ((action_removing || check_linear_animation_EM(tile)) && frame_em == 0)
7067 else if (action_moving)
7069 boolean is_backside = object_mapping[tile].is_backside;
7073 int direction = object_mapping[tile].direction;
7074 int move_dir = (action_falling ? MV_DOWN : direction);
7079 /* !!! TEST !!! NEW !!! DOES NOT WORK RIGHT YET !!! */
7080 if (g->double_movement && frame_em == 0)
7084 if (move_dir == MV_LEFT)
7085 GfxFrame[x - 1][y] = GfxFrame[x][y];
7086 else if (move_dir == MV_RIGHT)
7087 GfxFrame[x + 1][y] = GfxFrame[x][y];
7088 else if (move_dir == MV_UP)
7089 GfxFrame[x][y - 1] = GfxFrame[x][y];
7090 else if (move_dir == MV_DOWN)
7091 GfxFrame[x][y + 1] = GfxFrame[x][y];
7098 /* special case: animation for Xsand_stonesand_quickout_1/2 twice as fast */
7099 if (tile == Xsand_stonesand_quickout_1 ||
7100 tile == Xsand_stonesand_quickout_2)
7104 if (graphic_info[graphic].anim_global_sync)
7105 sync_frame = FrameCounter;
7106 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
7107 sync_frame = GfxFrame[x][y];
7109 sync_frame = 0; /* playfield border (pseudo steel) */
7111 SetRandomAnimationValue(x, y);
7113 int frame = getAnimationFrame(g->anim_frames,
7116 g->anim_start_frame,
7119 g_em->unique_identifier =
7120 (graphic << 16) | ((frame % 8) << 12) | (g_em->width << 6) | g_em->height;
7123 void getGraphicSourceObjectExt_EM(struct GraphicInfo_EM *g_em,
7124 int tile, int frame_em, int x, int y)
7126 int action = object_mapping[tile].action;
7127 int direction = object_mapping[tile].direction;
7128 boolean is_backside = object_mapping[tile].is_backside;
7129 int effective_element = get_effective_element_EM(tile, frame_em);
7130 int effective_action = action;
7131 int graphic = (direction == MV_NONE ?
7132 el_act2img(effective_element, effective_action) :
7133 el_act_dir2img(effective_element, effective_action,
7135 int crumbled = (direction == MV_NONE ?
7136 el_act2crm(effective_element, effective_action) :
7137 el_act_dir2crm(effective_element, effective_action,
7139 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
7140 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
7141 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
7142 struct GraphicInfo *g = &graphic_info[graphic];
7145 /* special case: graphic uses "2nd movement tile" and has defined
7146 7 frames for movement animation (or less) => use default graphic
7147 for last (8th) frame which ends the movement animation */
7148 if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
7150 effective_action = ACTION_DEFAULT;
7151 graphic = (direction == MV_NONE ?
7152 el_act2img(effective_element, effective_action) :
7153 el_act_dir2img(effective_element, effective_action,
7155 crumbled = (direction == MV_NONE ?
7156 el_act2crm(effective_element, effective_action) :
7157 el_act_dir2crm(effective_element, effective_action,
7160 g = &graphic_info[graphic];
7163 if (graphic_info[graphic].anim_global_sync)
7164 sync_frame = FrameCounter;
7165 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
7166 sync_frame = GfxFrame[x][y];
7168 sync_frame = 0; /* playfield border (pseudo steel) */
7170 SetRandomAnimationValue(x, y);
7172 int frame = getAnimationFrame(g->anim_frames,
7175 g->anim_start_frame,
7178 getGraphicSourceExt(graphic, frame, &g_em->bitmap, &g_em->src_x, &g_em->src_y,
7179 g->double_movement && is_backside);
7181 /* (updating the "crumbled" graphic definitions is probably not really needed,
7182 as animations for crumbled graphics can't be longer than one EMC cycle) */
7183 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
7187 void getGraphicSourcePlayerExt_EM(struct GraphicInfo_EM *g_em,
7188 int player_nr, int anim, int frame_em)
7190 int element = player_mapping[player_nr][anim].element_rnd;
7191 int action = player_mapping[player_nr][anim].action;
7192 int direction = player_mapping[player_nr][anim].direction;
7193 int graphic = (direction == MV_NONE ?
7194 el_act2img(element, action) :
7195 el_act_dir2img(element, action, direction));
7196 struct GraphicInfo *g = &graphic_info[graphic];
7199 InitPlayerGfxAnimation(&stored_player[player_nr], action, direction);
7201 stored_player[player_nr].StepFrame = frame_em;
7203 sync_frame = stored_player[player_nr].Frame;
7205 int frame = getAnimationFrame(g->anim_frames,
7208 g->anim_start_frame,
7211 getGraphicSourceExt(graphic, frame, &g_em->bitmap,
7212 &g_em->src_x, &g_em->src_y, FALSE);
7215 void InitGraphicInfo_EM(void)
7220 int num_em_gfx_errors = 0;
7222 if (graphic_info_em_object[0][0].bitmap == NULL)
7224 /* EM graphics not yet initialized in em_open_all() */
7229 printf("::: [4 errors can be ignored (1 x 'bomb', 3 x 'em_dynamite']\n");
7232 /* always start with reliable default values */
7233 for (i = 0; i < TILE_MAX; i++)
7235 object_mapping[i].element_rnd = EL_UNKNOWN;
7236 object_mapping[i].is_backside = FALSE;
7237 object_mapping[i].action = ACTION_DEFAULT;
7238 object_mapping[i].direction = MV_NONE;
7241 /* always start with reliable default values */
7242 for (p = 0; p < MAX_PLAYERS; p++)
7244 for (i = 0; i < SPR_MAX; i++)
7246 player_mapping[p][i].element_rnd = EL_UNKNOWN;
7247 player_mapping[p][i].action = ACTION_DEFAULT;
7248 player_mapping[p][i].direction = MV_NONE;
7252 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
7254 int e = em_object_mapping_list[i].element_em;
7256 object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd;
7257 object_mapping[e].is_backside = em_object_mapping_list[i].is_backside;
7259 if (em_object_mapping_list[i].action != -1)
7260 object_mapping[e].action = em_object_mapping_list[i].action;
7262 if (em_object_mapping_list[i].direction != -1)
7263 object_mapping[e].direction =
7264 MV_DIR_FROM_BIT(em_object_mapping_list[i].direction);
7267 for (i = 0; em_player_mapping_list[i].action_em != -1; i++)
7269 int a = em_player_mapping_list[i].action_em;
7270 int p = em_player_mapping_list[i].player_nr;
7272 player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd;
7274 if (em_player_mapping_list[i].action != -1)
7275 player_mapping[p][a].action = em_player_mapping_list[i].action;
7277 if (em_player_mapping_list[i].direction != -1)
7278 player_mapping[p][a].direction =
7279 MV_DIR_FROM_BIT(em_player_mapping_list[i].direction);
7282 for (i = 0; i < TILE_MAX; i++)
7284 int element = object_mapping[i].element_rnd;
7285 int action = object_mapping[i].action;
7286 int direction = object_mapping[i].direction;
7287 boolean is_backside = object_mapping[i].is_backside;
7288 boolean action_exploding = ((action == ACTION_EXPLODING ||
7289 action == ACTION_SMASHED_BY_ROCK ||
7290 action == ACTION_SMASHED_BY_SPRING) &&
7291 element != EL_DIAMOND);
7292 boolean action_active = (action == ACTION_ACTIVE);
7293 boolean action_other = (action == ACTION_OTHER);
7295 for (j = 0; j < 8; j++)
7297 int effective_element = get_effective_element_EM(i, j);
7298 int effective_action = (j < 7 ? action :
7299 i == Xdrip_stretch ? action :
7300 i == Xdrip_stretchB ? action :
7301 i == Ydrip_s1 ? action :
7302 i == Ydrip_s1B ? action :
7303 i == Xball_1B ? action :
7304 i == Xball_2 ? action :
7305 i == Xball_2B ? action :
7306 i == Yball_eat ? action :
7307 i == Ykey_1_eat ? action :
7308 i == Ykey_2_eat ? action :
7309 i == Ykey_3_eat ? action :
7310 i == Ykey_4_eat ? action :
7311 i == Ykey_5_eat ? action :
7312 i == Ykey_6_eat ? action :
7313 i == Ykey_7_eat ? action :
7314 i == Ykey_8_eat ? action :
7315 i == Ylenses_eat ? action :
7316 i == Ymagnify_eat ? action :
7317 i == Ygrass_eat ? action :
7318 i == Ydirt_eat ? action :
7319 i == Xsand_stonein_1 ? action :
7320 i == Xsand_stonein_2 ? action :
7321 i == Xsand_stonein_3 ? action :
7322 i == Xsand_stonein_4 ? action :
7323 i == Xsand_stoneout_1 ? action :
7324 i == Xsand_stoneout_2 ? action :
7325 i == Xboom_android ? ACTION_EXPLODING :
7326 action_exploding ? ACTION_EXPLODING :
7327 action_active ? action :
7328 action_other ? action :
7330 int graphic = (el_act_dir2img(effective_element, effective_action,
7332 int crumbled = (el_act_dir2crm(effective_element, effective_action,
7334 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
7335 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
7336 boolean has_action_graphics = (graphic != base_graphic);
7337 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
7338 struct GraphicInfo *g = &graphic_info[graphic];
7339 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
7342 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
7343 boolean special_animation = (action != ACTION_DEFAULT &&
7344 g->anim_frames == 3 &&
7345 g->anim_delay == 2 &&
7346 g->anim_mode & ANIM_LINEAR);
7347 int sync_frame = (i == Xdrip_stretch ? 7 :
7348 i == Xdrip_stretchB ? 7 :
7349 i == Ydrip_s2 ? j + 8 :
7350 i == Ydrip_s2B ? j + 8 :
7359 i == Xfake_acid_1 ? 0 :
7360 i == Xfake_acid_2 ? 10 :
7361 i == Xfake_acid_3 ? 20 :
7362 i == Xfake_acid_4 ? 30 :
7363 i == Xfake_acid_5 ? 40 :
7364 i == Xfake_acid_6 ? 50 :
7365 i == Xfake_acid_7 ? 60 :
7366 i == Xfake_acid_8 ? 70 :
7368 i == Xball_2B ? j + 8 :
7369 i == Yball_eat ? j + 1 :
7370 i == Ykey_1_eat ? j + 1 :
7371 i == Ykey_2_eat ? j + 1 :
7372 i == Ykey_3_eat ? j + 1 :
7373 i == Ykey_4_eat ? j + 1 :
7374 i == Ykey_5_eat ? j + 1 :
7375 i == Ykey_6_eat ? j + 1 :
7376 i == Ykey_7_eat ? j + 1 :
7377 i == Ykey_8_eat ? j + 1 :
7378 i == Ylenses_eat ? j + 1 :
7379 i == Ymagnify_eat ? j + 1 :
7380 i == Ygrass_eat ? j + 1 :
7381 i == Ydirt_eat ? j + 1 :
7382 i == Xamoeba_1 ? 0 :
7383 i == Xamoeba_2 ? 1 :
7384 i == Xamoeba_3 ? 2 :
7385 i == Xamoeba_4 ? 3 :
7386 i == Xamoeba_5 ? 0 :
7387 i == Xamoeba_6 ? 1 :
7388 i == Xamoeba_7 ? 2 :
7389 i == Xamoeba_8 ? 3 :
7390 i == Xexit_2 ? j + 8 :
7391 i == Xexit_3 ? j + 16 :
7392 i == Xdynamite_1 ? 0 :
7393 i == Xdynamite_2 ? 8 :
7394 i == Xdynamite_3 ? 16 :
7395 i == Xdynamite_4 ? 24 :
7396 i == Xsand_stonein_1 ? j + 1 :
7397 i == Xsand_stonein_2 ? j + 9 :
7398 i == Xsand_stonein_3 ? j + 17 :
7399 i == Xsand_stonein_4 ? j + 25 :
7400 i == Xsand_stoneout_1 && j == 0 ? 0 :
7401 i == Xsand_stoneout_1 && j == 1 ? 0 :
7402 i == Xsand_stoneout_1 && j == 2 ? 1 :
7403 i == Xsand_stoneout_1 && j == 3 ? 2 :
7404 i == Xsand_stoneout_1 && j == 4 ? 2 :
7405 i == Xsand_stoneout_1 && j == 5 ? 3 :
7406 i == Xsand_stoneout_1 && j == 6 ? 4 :
7407 i == Xsand_stoneout_1 && j == 7 ? 4 :
7408 i == Xsand_stoneout_2 && j == 0 ? 5 :
7409 i == Xsand_stoneout_2 && j == 1 ? 6 :
7410 i == Xsand_stoneout_2 && j == 2 ? 7 :
7411 i == Xsand_stoneout_2 && j == 3 ? 8 :
7412 i == Xsand_stoneout_2 && j == 4 ? 9 :
7413 i == Xsand_stoneout_2 && j == 5 ? 11 :
7414 i == Xsand_stoneout_2 && j == 6 ? 13 :
7415 i == Xsand_stoneout_2 && j == 7 ? 15 :
7416 i == Xboom_bug && j == 1 ? 2 :
7417 i == Xboom_bug && j == 2 ? 2 :
7418 i == Xboom_bug && j == 3 ? 4 :
7419 i == Xboom_bug && j == 4 ? 4 :
7420 i == Xboom_bug && j == 5 ? 2 :
7421 i == Xboom_bug && j == 6 ? 2 :
7422 i == Xboom_bug && j == 7 ? 0 :
7423 i == Xboom_bomb && j == 1 ? 2 :
7424 i == Xboom_bomb && j == 2 ? 2 :
7425 i == Xboom_bomb && j == 3 ? 4 :
7426 i == Xboom_bomb && j == 4 ? 4 :
7427 i == Xboom_bomb && j == 5 ? 2 :
7428 i == Xboom_bomb && j == 6 ? 2 :
7429 i == Xboom_bomb && j == 7 ? 0 :
7430 i == Xboom_android && j == 7 ? 6 :
7431 i == Xboom_1 && j == 1 ? 2 :
7432 i == Xboom_1 && j == 2 ? 2 :
7433 i == Xboom_1 && j == 3 ? 4 :
7434 i == Xboom_1 && j == 4 ? 4 :
7435 i == Xboom_1 && j == 5 ? 6 :
7436 i == Xboom_1 && j == 6 ? 6 :
7437 i == Xboom_1 && j == 7 ? 8 :
7438 i == Xboom_2 && j == 0 ? 8 :
7439 i == Xboom_2 && j == 1 ? 8 :
7440 i == Xboom_2 && j == 2 ? 10 :
7441 i == Xboom_2 && j == 3 ? 10 :
7442 i == Xboom_2 && j == 4 ? 10 :
7443 i == Xboom_2 && j == 5 ? 12 :
7444 i == Xboom_2 && j == 6 ? 12 :
7445 i == Xboom_2 && j == 7 ? 12 :
7446 special_animation && j == 4 ? 3 :
7447 effective_action != action ? 0 :
7451 Bitmap *debug_bitmap = g_em->bitmap;
7452 int debug_src_x = g_em->src_x;
7453 int debug_src_y = g_em->src_y;
7456 int frame = getAnimationFrame(g->anim_frames,
7459 g->anim_start_frame,
7462 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y,
7463 g->double_movement && is_backside);
7465 g_em->bitmap = src_bitmap;
7466 g_em->src_x = src_x;
7467 g_em->src_y = src_y;
7468 g_em->src_offset_x = 0;
7469 g_em->src_offset_y = 0;
7470 g_em->dst_offset_x = 0;
7471 g_em->dst_offset_y = 0;
7472 g_em->width = TILEX;
7473 g_em->height = TILEY;
7475 g_em->preserve_background = FALSE;
7477 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
7480 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
7481 effective_action == ACTION_MOVING ||
7482 effective_action == ACTION_PUSHING ||
7483 effective_action == ACTION_EATING)) ||
7484 (!has_action_graphics && (effective_action == ACTION_FILLING ||
7485 effective_action == ACTION_EMPTYING)))
7488 (effective_action == ACTION_FALLING ||
7489 effective_action == ACTION_FILLING ||
7490 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
7491 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
7492 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
7493 int num_steps = (i == Ydrip_s1 ? 16 :
7494 i == Ydrip_s1B ? 16 :
7495 i == Ydrip_s2 ? 16 :
7496 i == Ydrip_s2B ? 16 :
7497 i == Xsand_stonein_1 ? 32 :
7498 i == Xsand_stonein_2 ? 32 :
7499 i == Xsand_stonein_3 ? 32 :
7500 i == Xsand_stonein_4 ? 32 :
7501 i == Xsand_stoneout_1 ? 16 :
7502 i == Xsand_stoneout_2 ? 16 : 8);
7503 int cx = ABS(dx) * (TILEX / num_steps);
7504 int cy = ABS(dy) * (TILEY / num_steps);
7505 int step_frame = (i == Ydrip_s2 ? j + 8 :
7506 i == Ydrip_s2B ? j + 8 :
7507 i == Xsand_stonein_2 ? j + 8 :
7508 i == Xsand_stonein_3 ? j + 16 :
7509 i == Xsand_stonein_4 ? j + 24 :
7510 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
7511 int step = (is_backside ? step_frame : num_steps - step_frame);
7513 if (is_backside) /* tile where movement starts */
7515 if (dx < 0 || dy < 0)
7517 g_em->src_offset_x = cx * step;
7518 g_em->src_offset_y = cy * step;
7522 g_em->dst_offset_x = cx * step;
7523 g_em->dst_offset_y = cy * step;
7526 else /* tile where movement ends */
7528 if (dx < 0 || dy < 0)
7530 g_em->dst_offset_x = cx * step;
7531 g_em->dst_offset_y = cy * step;
7535 g_em->src_offset_x = cx * step;
7536 g_em->src_offset_y = cy * step;
7540 g_em->width = TILEX - cx * step;
7541 g_em->height = TILEY - cy * step;
7544 /* create unique graphic identifier to decide if tile must be redrawn */
7545 /* bit 31 - 16 (16 bit): EM style graphic
7546 bit 15 - 12 ( 4 bit): EM style frame
7547 bit 11 - 6 ( 6 bit): graphic width
7548 bit 5 - 0 ( 6 bit): graphic height */
7549 g_em->unique_identifier =
7550 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
7554 /* skip check for EMC elements not contained in original EMC artwork */
7555 if (element == EL_EMC_FAKE_ACID)
7558 if (g_em->bitmap != debug_bitmap ||
7559 g_em->src_x != debug_src_x ||
7560 g_em->src_y != debug_src_y ||
7561 g_em->src_offset_x != 0 ||
7562 g_em->src_offset_y != 0 ||
7563 g_em->dst_offset_x != 0 ||
7564 g_em->dst_offset_y != 0 ||
7565 g_em->width != TILEX ||
7566 g_em->height != TILEY)
7568 static int last_i = -1;
7576 printf("::: EMC GFX ERROR for element %d -> %d ('%s', '%s', %d)",
7577 i, element, element_info[element].token_name,
7578 element_action_info[effective_action].suffix, direction);
7580 if (element != effective_element)
7581 printf(" [%d ('%s')]",
7583 element_info[effective_element].token_name);
7587 if (g_em->bitmap != debug_bitmap)
7588 printf(" %d (%d): different bitmap! (0x%08x != 0x%08x)\n",
7589 j, is_backside, (int)(g_em->bitmap), (int)(debug_bitmap));
7591 if (g_em->src_x != debug_src_x ||
7592 g_em->src_y != debug_src_y)
7593 printf(" frame %d (%c): %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
7594 j, (is_backside ? 'B' : 'F'),
7595 g_em->src_x, g_em->src_y,
7596 g_em->src_x / 32, g_em->src_y / 32,
7597 debug_src_x, debug_src_y,
7598 debug_src_x / 32, debug_src_y / 32);
7600 if (g_em->src_offset_x != 0 ||
7601 g_em->src_offset_y != 0 ||
7602 g_em->dst_offset_x != 0 ||
7603 g_em->dst_offset_y != 0)
7604 printf(" %d (%d): offsets %d,%d and %d,%d should be all 0\n",
7606 g_em->src_offset_x, g_em->src_offset_y,
7607 g_em->dst_offset_x, g_em->dst_offset_y);
7609 if (g_em->width != TILEX ||
7610 g_em->height != TILEY)
7611 printf(" %d (%d): size %d,%d should be %d,%d\n",
7613 g_em->width, g_em->height, TILEX, TILEY);
7615 num_em_gfx_errors++;
7622 for (i = 0; i < TILE_MAX; i++)
7624 for (j = 0; j < 8; j++)
7626 int element = object_mapping[i].element_rnd;
7627 int action = object_mapping[i].action;
7628 int direction = object_mapping[i].direction;
7629 boolean is_backside = object_mapping[i].is_backside;
7630 int graphic_action = el_act_dir2img(element, action, direction);
7631 int graphic_default = el_act_dir2img(element, ACTION_DEFAULT, direction);
7633 if ((action == ACTION_SMASHED_BY_ROCK ||
7634 action == ACTION_SMASHED_BY_SPRING ||
7635 action == ACTION_EATING) &&
7636 graphic_action == graphic_default)
7638 int e = (action == ACTION_SMASHED_BY_ROCK ? Ystone_s :
7639 action == ACTION_SMASHED_BY_SPRING ? Yspring_s :
7640 direction == MV_LEFT ? (is_backside? Yspring_wB: Yspring_w) :
7641 direction == MV_RIGHT ? (is_backside? Yspring_eB: Yspring_e) :
7644 /* no separate animation for "smashed by rock" -- use rock instead */
7645 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
7646 struct GraphicInfo_EM *g_xx = &graphic_info_em_object[e][7 - j];
7648 g_em->bitmap = g_xx->bitmap;
7649 g_em->src_x = g_xx->src_x;
7650 g_em->src_y = g_xx->src_y;
7651 g_em->src_offset_x = g_xx->src_offset_x;
7652 g_em->src_offset_y = g_xx->src_offset_y;
7653 g_em->dst_offset_x = g_xx->dst_offset_x;
7654 g_em->dst_offset_y = g_xx->dst_offset_y;
7655 g_em->width = g_xx->width;
7656 g_em->height = g_xx->height;
7657 g_em->unique_identifier = g_xx->unique_identifier;
7660 g_em->preserve_background = TRUE;
7665 for (p = 0; p < MAX_PLAYERS; p++)
7667 for (i = 0; i < SPR_MAX; i++)
7669 int element = player_mapping[p][i].element_rnd;
7670 int action = player_mapping[p][i].action;
7671 int direction = player_mapping[p][i].direction;
7673 for (j = 0; j < 8; j++)
7675 int effective_element = element;
7676 int effective_action = action;
7677 int graphic = (direction == MV_NONE ?
7678 el_act2img(effective_element, effective_action) :
7679 el_act_dir2img(effective_element, effective_action,
7681 struct GraphicInfo *g = &graphic_info[graphic];
7682 struct GraphicInfo_EM *g_em = &graphic_info_em_player[p][i][7 - j];
7688 Bitmap *debug_bitmap = g_em->bitmap;
7689 int debug_src_x = g_em->src_x;
7690 int debug_src_y = g_em->src_y;
7693 int frame = getAnimationFrame(g->anim_frames,
7696 g->anim_start_frame,
7699 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
7701 g_em->bitmap = src_bitmap;
7702 g_em->src_x = src_x;
7703 g_em->src_y = src_y;
7704 g_em->src_offset_x = 0;
7705 g_em->src_offset_y = 0;
7706 g_em->dst_offset_x = 0;
7707 g_em->dst_offset_y = 0;
7708 g_em->width = TILEX;
7709 g_em->height = TILEY;
7713 /* skip check for EMC elements not contained in original EMC artwork */
7714 if (element == EL_PLAYER_3 ||
7715 element == EL_PLAYER_4)
7718 if (g_em->bitmap != debug_bitmap ||
7719 g_em->src_x != debug_src_x ||
7720 g_em->src_y != debug_src_y)
7722 static int last_i = -1;
7730 printf("::: EMC GFX ERROR for p/a %d/%d -> %d ('%s', '%s', %d)",
7731 p, i, element, element_info[element].token_name,
7732 element_action_info[effective_action].suffix, direction);
7734 if (element != effective_element)
7735 printf(" [%d ('%s')]",
7737 element_info[effective_element].token_name);
7741 if (g_em->bitmap != debug_bitmap)
7742 printf(" %d: different bitmap! (0x%08x != 0x%08x)\n",
7743 j, (int)(g_em->bitmap), (int)(debug_bitmap));
7745 if (g_em->src_x != debug_src_x ||
7746 g_em->src_y != debug_src_y)
7747 printf(" frame %d: %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
7749 g_em->src_x, g_em->src_y,
7750 g_em->src_x / 32, g_em->src_y / 32,
7751 debug_src_x, debug_src_y,
7752 debug_src_x / 32, debug_src_y / 32);
7754 num_em_gfx_errors++;
7764 printf("::: [%d errors found]\n", num_em_gfx_errors);
7770 void CheckSingleStepMode_EM(byte action[MAX_PLAYERS], int frame,
7771 boolean any_player_moving,
7772 boolean player_is_dropping)
7774 if (tape.single_step && tape.recording && !tape.pausing)
7775 if (frame == 0 && !player_is_dropping)
7776 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
7779 void CheckSingleStepMode_SP(boolean murphy_is_waiting,
7780 boolean murphy_is_dropping)
7782 if (tape.single_step && tape.recording && !tape.pausing)
7783 if (murphy_is_waiting)
7784 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
7787 void getGraphicSource_SP(struct GraphicInfo_SP *g_sp,
7788 int graphic, int sync_frame, int x, int y)
7790 int frame = getGraphicAnimationFrame(graphic, sync_frame);
7792 getGraphicSource(graphic, frame, &g_sp->bitmap, &g_sp->src_x, &g_sp->src_y);
7795 boolean isNextAnimationFrame_SP(int graphic, int sync_frame)
7797 return (IS_NEXT_FRAME(sync_frame, graphic));
7800 int getGraphicInfo_Delay(int graphic)
7802 return graphic_info[graphic].anim_delay;
7805 void PlayMenuSoundExt(int sound)
7807 if (sound == SND_UNDEFINED)
7810 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
7811 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
7814 if (IS_LOOP_SOUND(sound))
7815 PlaySoundLoop(sound);
7820 void PlayMenuSound()
7822 PlayMenuSoundExt(menu.sound[game_status]);
7825 void PlayMenuSoundStereo(int sound, int stereo_position)
7827 if (sound == SND_UNDEFINED)
7830 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
7831 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
7834 if (IS_LOOP_SOUND(sound))
7835 PlaySoundExt(sound, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_LOOP);
7837 PlaySoundStereo(sound, stereo_position);
7840 void PlayMenuSoundIfLoopExt(int sound)
7842 if (sound == SND_UNDEFINED)
7845 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
7846 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
7849 if (IS_LOOP_SOUND(sound))
7850 PlaySoundLoop(sound);
7853 void PlayMenuSoundIfLoop()
7855 PlayMenuSoundIfLoopExt(menu.sound[game_status]);
7858 void PlayMenuMusicExt(int music)
7860 if (music == MUS_UNDEFINED)
7863 if (!setup.sound_music)
7869 void PlayMenuMusic()
7871 PlayMenuMusicExt(menu.music[game_status]);
7874 void PlaySoundActivating()
7877 PlaySound(SND_MENU_ITEM_ACTIVATING);
7881 void PlaySoundSelecting()
7884 PlaySound(SND_MENU_ITEM_SELECTING);
7888 void ToggleFullscreenOrChangeWindowScalingIfNeeded()
7890 boolean change_fullscreen = (setup.fullscreen !=
7891 video.fullscreen_enabled);
7892 boolean change_fullscreen_mode = (video.fullscreen_enabled &&
7893 !strEqual(setup.fullscreen_mode,
7894 video.fullscreen_mode_current));
7895 boolean change_window_scaling_percent = (!video.fullscreen_enabled &&
7896 setup.window_scaling_percent !=
7897 video.window_scaling_percent);
7899 if (change_window_scaling_percent && video.fullscreen_enabled)
7902 if (!change_window_scaling_percent && !video.fullscreen_available)
7905 #if defined(TARGET_SDL2)
7906 if (change_window_scaling_percent)
7908 SDLSetWindowScaling(setup.window_scaling_percent);
7912 else if (change_fullscreen)
7914 SDLSetWindowFullscreen(setup.fullscreen);
7916 /* set setup value according to successfully changed fullscreen mode */
7917 setup.fullscreen = video.fullscreen_enabled;
7923 if (change_fullscreen ||
7924 change_fullscreen_mode ||
7925 change_window_scaling_percent)
7927 Bitmap *tmp_backbuffer = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
7929 /* save backbuffer content which gets lost when toggling fullscreen mode */
7930 BlitBitmap(backbuffer, tmp_backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
7932 if (change_fullscreen_mode)
7934 /* keep fullscreen, but change fullscreen mode (screen resolution) */
7935 video.fullscreen_enabled = FALSE; /* force new fullscreen mode */
7938 if (change_window_scaling_percent)
7940 /* keep window mode, but change window scaling */
7941 video.fullscreen_enabled = TRUE; /* force new window scaling */
7944 /* toggle fullscreen */
7945 ChangeVideoModeIfNeeded(setup.fullscreen);
7947 /* set setup value according to successfully changed fullscreen mode */
7948 setup.fullscreen = video.fullscreen_enabled;
7950 /* restore backbuffer content from temporary backbuffer backup bitmap */
7951 BlitBitmap(tmp_backbuffer, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
7953 FreeBitmap(tmp_backbuffer);
7955 /* update visible window/screen */
7956 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
7960 void ChangeViewportPropertiesIfNeeded()
7962 int gfx_game_mode = game_status;
7963 int gfx_game_mode2 = (game_status == GAME_MODE_EDITOR ? GAME_MODE_DEFAULT :
7965 struct RectWithBorder *vp_playfield = &viewport.playfield[gfx_game_mode];
7966 struct RectWithBorder *vp_door_1 = &viewport.door_1[gfx_game_mode];
7967 struct RectWithBorder *vp_door_2 = &viewport.door_2[gfx_game_mode2];
7968 struct RectWithBorder *vp_door_3 = &viewport.door_2[GAME_MODE_EDITOR];
7969 int border_size = vp_playfield->border_size;
7970 int new_sx = vp_playfield->x + border_size;
7971 int new_sy = vp_playfield->y + border_size;
7972 int new_sxsize = vp_playfield->width - 2 * border_size;
7973 int new_sysize = vp_playfield->height - 2 * border_size;
7974 int new_real_sx = vp_playfield->x;
7975 int new_real_sy = vp_playfield->y;
7976 int new_full_sxsize = vp_playfield->width;
7977 int new_full_sysize = vp_playfield->height;
7978 int new_dx = vp_door_1->x;
7979 int new_dy = vp_door_1->y;
7980 int new_dxsize = vp_door_1->width;
7981 int new_dysize = vp_door_1->height;
7982 int new_vx = vp_door_2->x;
7983 int new_vy = vp_door_2->y;
7984 int new_vxsize = vp_door_2->width;
7985 int new_vysize = vp_door_2->height;
7986 int new_ex = vp_door_3->x;
7987 int new_ey = vp_door_3->y;
7988 int new_exsize = vp_door_3->width;
7989 int new_eysize = vp_door_3->height;
7990 int new_tilesize_var =
7991 (setup.small_game_graphics ? MINI_TILESIZE : game.tile_size);
7993 int tilesize = (gfx_game_mode == GAME_MODE_PLAYING ? new_tilesize_var :
7994 gfx_game_mode == GAME_MODE_EDITOR ? MINI_TILESIZE : TILESIZE);
7995 int new_scr_fieldx = new_sxsize / tilesize;
7996 int new_scr_fieldy = new_sysize / tilesize;
7997 int new_scr_fieldx_buffers = new_sxsize / new_tilesize_var;
7998 int new_scr_fieldy_buffers = new_sysize / new_tilesize_var;
7999 boolean init_gfx_buffers = FALSE;
8000 boolean init_video_buffer = FALSE;
8001 boolean init_gadgets_and_toons = FALSE;
8002 boolean init_em_graphics = FALSE;
8004 if (viewport.window.width != WIN_XSIZE ||
8005 viewport.window.height != WIN_YSIZE)
8007 WIN_XSIZE = viewport.window.width;
8008 WIN_YSIZE = viewport.window.height;
8010 init_video_buffer = TRUE;
8011 init_gfx_buffers = TRUE;
8013 // printf("::: video: init_video_buffer, init_gfx_buffers\n");
8016 if (new_scr_fieldx != SCR_FIELDX ||
8017 new_scr_fieldy != SCR_FIELDY)
8019 /* this always toggles between MAIN and GAME when using small tile size */
8021 SCR_FIELDX = new_scr_fieldx;
8022 SCR_FIELDY = new_scr_fieldy;
8024 // printf("::: new_scr_fieldx != SCR_FIELDX ...\n");
8035 new_sxsize != SXSIZE ||
8036 new_sysize != SYSIZE ||
8037 new_dxsize != DXSIZE ||
8038 new_dysize != DYSIZE ||
8039 new_vxsize != VXSIZE ||
8040 new_vysize != VYSIZE ||
8041 new_exsize != EXSIZE ||
8042 new_eysize != EYSIZE ||
8043 new_real_sx != REAL_SX ||
8044 new_real_sy != REAL_SY ||
8045 new_full_sxsize != FULL_SXSIZE ||
8046 new_full_sysize != FULL_SYSIZE ||
8047 new_tilesize_var != TILESIZE_VAR
8050 if (new_tilesize_var != TILESIZE_VAR)
8052 // printf("::: new_tilesize_var != TILESIZE_VAR\n");
8054 // changing tile size invalidates scroll values of engine snapshots
8055 FreeEngineSnapshot();
8057 // changing tile size requires update of graphic mapping for EM engine
8058 init_em_graphics = TRUE;
8069 SXSIZE = new_sxsize;
8070 SYSIZE = new_sysize;
8071 DXSIZE = new_dxsize;
8072 DYSIZE = new_dysize;
8073 VXSIZE = new_vxsize;
8074 VYSIZE = new_vysize;
8075 EXSIZE = new_exsize;
8076 EYSIZE = new_eysize;
8077 REAL_SX = new_real_sx;
8078 REAL_SY = new_real_sy;
8079 FULL_SXSIZE = new_full_sxsize;
8080 FULL_SYSIZE = new_full_sysize;
8081 TILESIZE_VAR = new_tilesize_var;
8083 init_gfx_buffers = TRUE;
8084 init_gadgets_and_toons = TRUE;
8086 // printf("::: viewports: init_gfx_buffers\n");
8087 // printf("::: viewports: init_gadgets_and_toons\n");
8090 if (init_gfx_buffers)
8092 // printf("::: init_gfx_buffers\n");
8094 SCR_FIELDX = new_scr_fieldx_buffers;
8095 SCR_FIELDY = new_scr_fieldy_buffers;
8099 SCR_FIELDX = new_scr_fieldx;
8100 SCR_FIELDY = new_scr_fieldy;
8103 if (init_video_buffer)
8105 // printf("::: init_video_buffer\n");
8107 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
8109 SetDrawDeactivationMask(REDRAW_NONE);
8110 SetDrawBackgroundMask(REDRAW_FIELD);
8113 if (init_gadgets_and_toons)
8115 // printf("::: init_gadgets_and_toons\n");
8121 if (init_em_graphics)
8123 InitGraphicInfo_EM();