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 max_move_delay_doors_only = 0; // delay for doors only (no panel)
4117 int num_move_steps_doors_only = 0; // steps for doors only (no panel)
4118 int current_move_delay = 0;
4122 for (i = 0; i < NUM_DOORS; i++)
4123 panel_has_doors[i] = FALSE;
4125 for (i = 0; i < MAX_DOOR_PARTS; i++)
4127 struct DoorPartControlInfo *dpc = &door_part_controls[i];
4128 struct GraphicInfo *g = &graphic_info[dpc->graphic];
4129 int door_token = dpc->door_token;
4131 door_part_done[i] = FALSE;
4132 door_part_skip[i] = (!(door_state & door_token) ||
4136 for (i = 0; i < MAX_DOOR_PARTS; i++)
4138 int nr = door_part_order[i].nr;
4139 struct DoorPartControlInfo *dpc = &door_part_controls[nr];
4140 struct DoorPartPosInfo *pos = dpc->pos;
4141 struct GraphicInfo *g = &graphic_info[dpc->graphic];
4142 int door_token = dpc->door_token;
4143 int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
4144 boolean is_panel = DOOR_PART_IS_PANEL(nr);
4145 int step_xoffset = ABS(pos->step_xoffset);
4146 int step_yoffset = ABS(pos->step_yoffset);
4147 int step_delay = pos->step_delay;
4148 int current_door_state = door_state & door_token;
4149 boolean door_opening = ((current_door_state & DOOR_OPEN) != 0);
4150 boolean door_closing = ((current_door_state & DOOR_CLOSE) != 0);
4151 boolean part_opening = (is_panel ? door_closing : door_opening);
4152 int start_step = (part_opening ? pos->start_step_opening :
4153 pos->start_step_closing);
4154 float move_xsize = (step_xoffset ? g->width : 0);
4155 float move_ysize = (step_yoffset ? g->height : 0);
4156 int move_xsteps = (step_xoffset ? ceil(move_xsize / step_xoffset) : 0);
4157 int move_ysteps = (step_yoffset ? ceil(move_ysize / step_yoffset) : 0);
4158 int move_steps = (move_xsteps && move_ysteps ?
4159 MIN(move_xsteps, move_ysteps) :
4160 move_xsteps ? move_xsteps : move_ysteps) - start_step;
4161 int move_delay = move_steps * step_delay;
4163 if (door_part_skip[nr])
4166 max_move_delay = MAX(max_move_delay, move_delay);
4167 max_step_delay = (max_step_delay == 0 ? step_delay :
4168 euclid(max_step_delay, step_delay));
4169 num_steps[nr] = move_steps;
4173 max_move_delay_doors_only = MAX(max_move_delay_doors_only, move_delay);
4175 panel_has_doors[door_index] = TRUE;
4179 num_move_steps = max_move_delay / max_step_delay;
4180 num_move_steps_doors_only = max_move_delay_doors_only / max_step_delay;
4182 door_delay_value = max_step_delay;
4184 if ((door_state & DOOR_NO_DELAY) || setup.quick_doors)
4186 start = num_move_steps - 1;
4190 /* opening door sound has priority over simultaneously closing door */
4191 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
4192 PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
4193 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
4194 PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
4197 for (k = start; k < num_move_steps; k++)
4199 door_part_done_all = TRUE;
4201 for (i = 0; i < NUM_DOORS; i++)
4202 door_panel_drawn[i] = FALSE;
4204 for (i = 0; i < MAX_DOOR_PARTS; i++)
4206 int nr = door_part_order[i].nr;
4207 struct DoorPartControlInfo *dpc = &door_part_controls[nr];
4208 struct DoorPartPosInfo *pos = dpc->pos;
4209 struct GraphicInfo *g = &graphic_info[dpc->graphic];
4210 int door_token = dpc->door_token;
4211 int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
4212 boolean is_panel = DOOR_PART_IS_PANEL(nr);
4213 boolean is_panel_and_door_has_closed = FALSE;
4214 struct Rect *door_rect = &door_rect_list[door_index];
4215 Bitmap *bitmap_db_door = (door_token == DOOR_1 ? bitmap_db_door_1 :
4217 Bitmap *bitmap = (is_panel ? bitmap_db_door : g->bitmap);
4218 int current_door_state = door_state & door_token;
4219 boolean door_opening = ((current_door_state & DOOR_OPEN) != 0);
4220 boolean door_closing = !door_opening;
4221 boolean part_opening = (is_panel ? door_closing : door_opening);
4222 boolean part_closing = !part_opening;
4223 int start_step = (part_opening ? pos->start_step_opening :
4224 pos->start_step_closing);
4225 int step_delay = pos->step_delay;
4226 int step_factor = step_delay / max_step_delay;
4227 int k1 = (step_factor ? k / step_factor + 1 : k);
4228 int k2 = (part_opening ? k1 + start_step : num_steps[nr] - k1);
4229 int kk = MAX(0, k2);
4232 int src_x, src_y, src_xx, src_yy;
4233 int dst_x, dst_y, dst_xx, dst_yy;
4236 if (door_part_skip[nr])
4239 if (!(door_state & door_token))
4247 int k2_door = (door_opening ? k : num_move_steps_doors_only - k - 1);
4248 int kk_door = MAX(0, k2_door);
4249 int sync_frame = kk_door * door_delay_value;
4250 int frame = getGraphicAnimationFrame(dpc->graphic, sync_frame);
4252 getGraphicSource(dpc->graphic, frame, &bitmap, &g_src_x, &g_src_y);
4257 if (!door_panel_drawn[door_index])
4259 ClearRectangle(drawto, door_rect->x, door_rect->y,
4260 door_rect->width, door_rect->height);
4262 door_panel_drawn[door_index] = TRUE;
4265 // draw opening or closing door parts
4267 if (pos->step_xoffset < 0) // door part on right side
4270 dst_xx = pos->x + ABS(kk * pos->step_xoffset);
4273 if (dst_xx + width > door_rect->width)
4274 width = door_rect->width - dst_xx;
4276 else // door part on left side
4279 dst_xx = pos->x - kk * pos->step_xoffset;
4283 src_xx = ABS(dst_xx);
4287 width = g->width - src_xx;
4289 // printf("::: k == %d [%d] \n", k, start_step);
4292 if (pos->step_yoffset < 0) // door part on bottom side
4295 dst_yy = pos->y + ABS(kk * pos->step_yoffset);
4298 if (dst_yy + height > door_rect->height)
4299 height = door_rect->height - dst_yy;
4301 else // door part on top side
4304 dst_yy = pos->y - kk * pos->step_yoffset;
4308 src_yy = ABS(dst_yy);
4312 height = g->height - src_yy;
4315 src_x = g_src_x + src_xx;
4316 src_y = g_src_y + src_yy;
4318 dst_x = door_rect->x + dst_xx;
4319 dst_y = door_rect->y + dst_yy;
4321 is_panel_and_door_has_closed =
4324 panel_has_doors[door_index] &&
4325 k >= num_move_steps_doors_only - 1);
4327 if (width >= 0 && width <= g->width &&
4328 height >= 0 && height <= g->height &&
4329 !is_panel_and_door_has_closed)
4331 if (is_panel || !pos->draw_masked)
4332 BlitBitmap(bitmap, drawto, src_x, src_y, width, height,
4335 BlitBitmapMasked(bitmap, drawto, src_x, src_y, width, height,
4339 redraw_mask |= REDRAW_DOOR_FROM_TOKEN(door_token);
4341 if ((part_opening && (width < 0 || height < 0)) ||
4342 (part_closing && (width >= g->width && height >= g->height)))
4343 door_part_done[nr] = TRUE;
4345 // continue door part animations, but not panel after door has closed
4346 if (!door_part_done[nr] && !is_panel_and_door_has_closed)
4347 door_part_done_all = FALSE;
4350 if (!(door_state & DOOR_NO_DELAY))
4354 if (game_status == GAME_MODE_MAIN)
4357 WaitUntilDelayReached(&door_delay, door_delay_value);
4359 current_move_delay += max_step_delay;
4362 if (door_part_done_all)
4367 if (door_state & DOOR_ACTION_1)
4368 door1 = door_state & DOOR_ACTION_1;
4369 if (door_state & DOOR_ACTION_2)
4370 door2 = door_state & DOOR_ACTION_2;
4372 return (door1 | door2);
4375 void DrawSpecialEditorDoor()
4377 struct GraphicInfo *gfx1 = &graphic_info[IMG_DOOR_2_TOP_BORDER_CORRECTION];
4378 int top_border_width = gfx1->width;
4379 int top_border_height = gfx1->height;
4380 int outer_border = viewport.door_2[GAME_MODE_EDITOR].border_size;
4381 int ex = EX - outer_border;
4382 int ey = EY - outer_border;
4383 int vy = VY - outer_border;
4384 int exsize = EXSIZE + 2 * outer_border;
4386 CloseDoor(DOOR_CLOSE_2);
4388 /* draw bigger level editor toolbox window */
4389 BlitBitmap(gfx1->bitmap, drawto, gfx1->src_x, gfx1->src_y,
4390 top_border_width, top_border_height, ex, ey - top_border_height);
4391 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto, ex, vy,
4392 exsize, EYSIZE - VYSIZE + outer_border, ex, ey);
4394 redraw_mask |= REDRAW_ALL;
4397 void UndrawSpecialEditorDoor()
4399 struct GraphicInfo *gfx1 = &graphic_info[IMG_DOOR_2_TOP_BORDER_CORRECTION];
4400 int top_border_width = gfx1->width;
4401 int top_border_height = gfx1->height;
4402 int outer_border = viewport.door_2[GAME_MODE_EDITOR].border_size;
4403 int ex = EX - outer_border;
4404 int ey = EY - outer_border;
4405 int ey_top = ey - top_border_height;
4406 int exsize = EXSIZE + 2 * outer_border;
4407 int eysize = EYSIZE + 2 * outer_border;
4409 /* draw normal tape recorder window */
4410 if (graphic_info[IMG_GLOBAL_BORDER].bitmap)
4412 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
4413 ex, ey_top, top_border_width, top_border_height,
4415 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
4416 ex, ey, exsize, eysize, ex, ey);
4420 // if screen background is set to "[NONE]", clear editor toolbox window
4421 ClearRectangle(drawto, ex, ey_top, top_border_width, top_border_height);
4422 ClearRectangle(drawto, ex, ey, exsize, eysize);
4425 redraw_mask |= REDRAW_ALL;
4429 /* ---------- new tool button stuff ---------------------------------------- */
4434 struct TextPosInfo *pos;
4437 } toolbutton_info[NUM_TOOL_BUTTONS] =
4440 IMG_REQUEST_BUTTON_GFX_YES, &request.button.yes,
4441 TOOL_CTRL_ID_YES, "yes"
4444 IMG_REQUEST_BUTTON_GFX_NO, &request.button.no,
4445 TOOL_CTRL_ID_NO, "no"
4448 IMG_REQUEST_BUTTON_GFX_CONFIRM, &request.button.confirm,
4449 TOOL_CTRL_ID_CONFIRM, "confirm"
4452 IMG_REQUEST_BUTTON_GFX_PLAYER_1, &request.button.player_1,
4453 TOOL_CTRL_ID_PLAYER_1, "player 1"
4456 IMG_REQUEST_BUTTON_GFX_PLAYER_2, &request.button.player_2,
4457 TOOL_CTRL_ID_PLAYER_2, "player 2"
4460 IMG_REQUEST_BUTTON_GFX_PLAYER_3, &request.button.player_3,
4461 TOOL_CTRL_ID_PLAYER_3, "player 3"
4464 IMG_REQUEST_BUTTON_GFX_PLAYER_4, &request.button.player_4,
4465 TOOL_CTRL_ID_PLAYER_4, "player 4"
4469 void CreateToolButtons()
4473 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4475 struct GraphicInfo *gfx = &graphic_info[toolbutton_info[i].graphic];
4476 struct TextPosInfo *pos = toolbutton_info[i].pos;
4477 struct GadgetInfo *gi;
4478 Bitmap *deco_bitmap = None;
4479 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
4480 unsigned int event_mask = GD_EVENT_RELEASED;
4483 int gd_x = gfx->src_x;
4484 int gd_y = gfx->src_y;
4485 int gd_xp = gfx->src_x + gfx->pressed_xoffset;
4486 int gd_yp = gfx->src_y + gfx->pressed_yoffset;
4489 if (global.use_envelope_request)
4490 setRequestPosition(&dx, &dy, TRUE);
4492 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
4494 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
4496 getSizedGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr), 0,
4497 pos->size, &deco_bitmap, &deco_x, &deco_y);
4498 deco_xpos = (gfx->width - pos->size) / 2;
4499 deco_ypos = (gfx->height - pos->size) / 2;
4502 gi = CreateGadget(GDI_CUSTOM_ID, id,
4503 GDI_INFO_TEXT, toolbutton_info[i].infotext,
4504 GDI_X, dx + GDI_ACTIVE_POS(pos->x),
4505 GDI_Y, dy + GDI_ACTIVE_POS(pos->y),
4506 GDI_WIDTH, gfx->width,
4507 GDI_HEIGHT, gfx->height,
4508 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
4509 GDI_STATE, GD_BUTTON_UNPRESSED,
4510 GDI_DESIGN_UNPRESSED, gfx->bitmap, gd_x, gd_y,
4511 GDI_DESIGN_PRESSED, gfx->bitmap, gd_xp, gd_yp,
4512 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
4513 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
4514 GDI_DECORATION_SIZE, pos->size, pos->size,
4515 GDI_DECORATION_SHIFTING, 1, 1,
4516 GDI_DIRECT_DRAW, FALSE,
4517 GDI_EVENT_MASK, event_mask,
4518 GDI_CALLBACK_ACTION, HandleToolButtons,
4522 Error(ERR_EXIT, "cannot create gadget");
4524 tool_gadget[id] = gi;
4528 void FreeToolButtons()
4532 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4533 FreeGadget(tool_gadget[i]);
4536 static void UnmapToolButtons()
4540 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4541 UnmapGadget(tool_gadget[i]);
4544 static void HandleToolButtons(struct GadgetInfo *gi)
4546 request_gadget_id = gi->custom_id;
4549 static struct Mapping_EM_to_RND_object
4552 boolean is_rnd_to_em_mapping; /* unique mapping EM <-> RND */
4553 boolean is_backside; /* backside of moving element */
4559 em_object_mapping_list[] =
4562 Xblank, TRUE, FALSE,
4566 Yacid_splash_eB, FALSE, FALSE,
4567 EL_ACID_SPLASH_RIGHT, -1, -1
4570 Yacid_splash_wB, FALSE, FALSE,
4571 EL_ACID_SPLASH_LEFT, -1, -1
4574 #ifdef EM_ENGINE_BAD_ROLL
4576 Xstone_force_e, FALSE, FALSE,
4577 EL_ROCK, -1, MV_BIT_RIGHT
4580 Xstone_force_w, FALSE, FALSE,
4581 EL_ROCK, -1, MV_BIT_LEFT
4584 Xnut_force_e, FALSE, FALSE,
4585 EL_NUT, -1, MV_BIT_RIGHT
4588 Xnut_force_w, FALSE, FALSE,
4589 EL_NUT, -1, MV_BIT_LEFT
4592 Xspring_force_e, FALSE, FALSE,
4593 EL_SPRING, -1, MV_BIT_RIGHT
4596 Xspring_force_w, FALSE, FALSE,
4597 EL_SPRING, -1, MV_BIT_LEFT
4600 Xemerald_force_e, FALSE, FALSE,
4601 EL_EMERALD, -1, MV_BIT_RIGHT
4604 Xemerald_force_w, FALSE, FALSE,
4605 EL_EMERALD, -1, MV_BIT_LEFT
4608 Xdiamond_force_e, FALSE, FALSE,
4609 EL_DIAMOND, -1, MV_BIT_RIGHT
4612 Xdiamond_force_w, FALSE, FALSE,
4613 EL_DIAMOND, -1, MV_BIT_LEFT
4616 Xbomb_force_e, FALSE, FALSE,
4617 EL_BOMB, -1, MV_BIT_RIGHT
4620 Xbomb_force_w, FALSE, FALSE,
4621 EL_BOMB, -1, MV_BIT_LEFT
4623 #endif /* EM_ENGINE_BAD_ROLL */
4626 Xstone, TRUE, FALSE,
4630 Xstone_pause, FALSE, FALSE,
4634 Xstone_fall, FALSE, FALSE,
4638 Ystone_s, FALSE, FALSE,
4639 EL_ROCK, ACTION_FALLING, -1
4642 Ystone_sB, FALSE, TRUE,
4643 EL_ROCK, ACTION_FALLING, -1
4646 Ystone_e, FALSE, FALSE,
4647 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
4650 Ystone_eB, FALSE, TRUE,
4651 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
4654 Ystone_w, FALSE, FALSE,
4655 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
4658 Ystone_wB, FALSE, TRUE,
4659 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
4666 Xnut_pause, FALSE, FALSE,
4670 Xnut_fall, FALSE, FALSE,
4674 Ynut_s, FALSE, FALSE,
4675 EL_NUT, ACTION_FALLING, -1
4678 Ynut_sB, FALSE, TRUE,
4679 EL_NUT, ACTION_FALLING, -1
4682 Ynut_e, FALSE, FALSE,
4683 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
4686 Ynut_eB, FALSE, TRUE,
4687 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
4690 Ynut_w, FALSE, FALSE,
4691 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
4694 Ynut_wB, FALSE, TRUE,
4695 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
4698 Xbug_n, TRUE, FALSE,
4702 Xbug_e, TRUE, FALSE,
4703 EL_BUG_RIGHT, -1, -1
4706 Xbug_s, TRUE, FALSE,
4710 Xbug_w, TRUE, FALSE,
4714 Xbug_gon, FALSE, FALSE,
4718 Xbug_goe, FALSE, FALSE,
4719 EL_BUG_RIGHT, -1, -1
4722 Xbug_gos, FALSE, FALSE,
4726 Xbug_gow, FALSE, FALSE,
4730 Ybug_n, FALSE, FALSE,
4731 EL_BUG, ACTION_MOVING, MV_BIT_UP
4734 Ybug_nB, FALSE, TRUE,
4735 EL_BUG, ACTION_MOVING, MV_BIT_UP
4738 Ybug_e, FALSE, FALSE,
4739 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
4742 Ybug_eB, FALSE, TRUE,
4743 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
4746 Ybug_s, FALSE, FALSE,
4747 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
4750 Ybug_sB, FALSE, TRUE,
4751 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
4754 Ybug_w, FALSE, FALSE,
4755 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
4758 Ybug_wB, FALSE, TRUE,
4759 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
4762 Ybug_w_n, FALSE, FALSE,
4763 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
4766 Ybug_n_e, FALSE, FALSE,
4767 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
4770 Ybug_e_s, FALSE, FALSE,
4771 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
4774 Ybug_s_w, FALSE, FALSE,
4775 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
4778 Ybug_e_n, FALSE, FALSE,
4779 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
4782 Ybug_s_e, FALSE, FALSE,
4783 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
4786 Ybug_w_s, FALSE, FALSE,
4787 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
4790 Ybug_n_w, FALSE, FALSE,
4791 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
4794 Ybug_stone, FALSE, FALSE,
4795 EL_BUG, ACTION_SMASHED_BY_ROCK, -1
4798 Ybug_spring, FALSE, FALSE,
4799 EL_BUG, ACTION_SMASHED_BY_SPRING, -1
4802 Xtank_n, TRUE, FALSE,
4803 EL_SPACESHIP_UP, -1, -1
4806 Xtank_e, TRUE, FALSE,
4807 EL_SPACESHIP_RIGHT, -1, -1
4810 Xtank_s, TRUE, FALSE,
4811 EL_SPACESHIP_DOWN, -1, -1
4814 Xtank_w, TRUE, FALSE,
4815 EL_SPACESHIP_LEFT, -1, -1
4818 Xtank_gon, FALSE, FALSE,
4819 EL_SPACESHIP_UP, -1, -1
4822 Xtank_goe, FALSE, FALSE,
4823 EL_SPACESHIP_RIGHT, -1, -1
4826 Xtank_gos, FALSE, FALSE,
4827 EL_SPACESHIP_DOWN, -1, -1
4830 Xtank_gow, FALSE, FALSE,
4831 EL_SPACESHIP_LEFT, -1, -1
4834 Ytank_n, FALSE, FALSE,
4835 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
4838 Ytank_nB, FALSE, TRUE,
4839 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
4842 Ytank_e, FALSE, FALSE,
4843 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
4846 Ytank_eB, FALSE, TRUE,
4847 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
4850 Ytank_s, FALSE, FALSE,
4851 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
4854 Ytank_sB, FALSE, TRUE,
4855 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
4858 Ytank_w, FALSE, FALSE,
4859 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
4862 Ytank_wB, FALSE, TRUE,
4863 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
4866 Ytank_w_n, FALSE, FALSE,
4867 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
4870 Ytank_n_e, FALSE, FALSE,
4871 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
4874 Ytank_e_s, FALSE, FALSE,
4875 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
4878 Ytank_s_w, FALSE, FALSE,
4879 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
4882 Ytank_e_n, FALSE, FALSE,
4883 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
4886 Ytank_s_e, FALSE, FALSE,
4887 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
4890 Ytank_w_s, FALSE, FALSE,
4891 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
4894 Ytank_n_w, FALSE, FALSE,
4895 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
4898 Ytank_stone, FALSE, FALSE,
4899 EL_SPACESHIP, ACTION_SMASHED_BY_ROCK, -1
4902 Ytank_spring, FALSE, FALSE,
4903 EL_SPACESHIP, ACTION_SMASHED_BY_SPRING, -1
4906 Xandroid, TRUE, FALSE,
4907 EL_EMC_ANDROID, ACTION_ACTIVE, -1
4910 Xandroid_1_n, FALSE, FALSE,
4911 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
4914 Xandroid_2_n, FALSE, FALSE,
4915 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
4918 Xandroid_1_e, FALSE, FALSE,
4919 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
4922 Xandroid_2_e, FALSE, FALSE,
4923 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
4926 Xandroid_1_w, FALSE, FALSE,
4927 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
4930 Xandroid_2_w, FALSE, FALSE,
4931 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
4934 Xandroid_1_s, FALSE, FALSE,
4935 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
4938 Xandroid_2_s, FALSE, FALSE,
4939 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
4942 Yandroid_n, FALSE, FALSE,
4943 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
4946 Yandroid_nB, FALSE, TRUE,
4947 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
4950 Yandroid_ne, FALSE, FALSE,
4951 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPRIGHT
4954 Yandroid_neB, FALSE, TRUE,
4955 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPRIGHT
4958 Yandroid_e, FALSE, FALSE,
4959 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
4962 Yandroid_eB, FALSE, TRUE,
4963 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
4966 Yandroid_se, FALSE, FALSE,
4967 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNRIGHT
4970 Yandroid_seB, FALSE, TRUE,
4971 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNRIGHT
4974 Yandroid_s, FALSE, FALSE,
4975 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
4978 Yandroid_sB, FALSE, TRUE,
4979 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
4982 Yandroid_sw, FALSE, FALSE,
4983 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNLEFT
4986 Yandroid_swB, FALSE, TRUE,
4987 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNLEFT
4990 Yandroid_w, FALSE, FALSE,
4991 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
4994 Yandroid_wB, FALSE, TRUE,
4995 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
4998 Yandroid_nw, FALSE, FALSE,
4999 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPLEFT
5002 Yandroid_nwB, FALSE, TRUE,
5003 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPLEFT
5006 Xspring, TRUE, FALSE,
5010 Xspring_pause, FALSE, FALSE,
5014 Xspring_e, FALSE, FALSE,
5018 Xspring_w, FALSE, FALSE,
5022 Xspring_fall, FALSE, FALSE,
5026 Yspring_s, FALSE, FALSE,
5027 EL_SPRING, ACTION_FALLING, -1
5030 Yspring_sB, FALSE, TRUE,
5031 EL_SPRING, ACTION_FALLING, -1
5034 Yspring_e, FALSE, FALSE,
5035 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
5038 Yspring_eB, FALSE, TRUE,
5039 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
5042 Yspring_w, FALSE, FALSE,
5043 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
5046 Yspring_wB, FALSE, TRUE,
5047 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
5050 Yspring_kill_e, FALSE, FALSE,
5051 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
5054 Yspring_kill_eB, FALSE, TRUE,
5055 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
5058 Yspring_kill_w, FALSE, FALSE,
5059 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
5062 Yspring_kill_wB, FALSE, TRUE,
5063 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
5066 Xeater_n, TRUE, FALSE,
5067 EL_YAMYAM_UP, -1, -1
5070 Xeater_e, TRUE, FALSE,
5071 EL_YAMYAM_RIGHT, -1, -1
5074 Xeater_w, TRUE, FALSE,
5075 EL_YAMYAM_LEFT, -1, -1
5078 Xeater_s, TRUE, FALSE,
5079 EL_YAMYAM_DOWN, -1, -1
5082 Yeater_n, FALSE, FALSE,
5083 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
5086 Yeater_nB, FALSE, TRUE,
5087 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
5090 Yeater_e, FALSE, FALSE,
5091 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
5094 Yeater_eB, FALSE, TRUE,
5095 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
5098 Yeater_s, FALSE, FALSE,
5099 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
5102 Yeater_sB, FALSE, TRUE,
5103 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
5106 Yeater_w, FALSE, FALSE,
5107 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
5110 Yeater_wB, FALSE, TRUE,
5111 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
5114 Yeater_stone, FALSE, FALSE,
5115 EL_YAMYAM, ACTION_SMASHED_BY_ROCK, -1
5118 Yeater_spring, FALSE, FALSE,
5119 EL_YAMYAM, ACTION_SMASHED_BY_SPRING, -1
5122 Xalien, TRUE, FALSE,
5126 Xalien_pause, FALSE, FALSE,
5130 Yalien_n, FALSE, FALSE,
5131 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
5134 Yalien_nB, FALSE, TRUE,
5135 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
5138 Yalien_e, FALSE, FALSE,
5139 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
5142 Yalien_eB, FALSE, TRUE,
5143 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
5146 Yalien_s, FALSE, FALSE,
5147 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
5150 Yalien_sB, FALSE, TRUE,
5151 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
5154 Yalien_w, FALSE, FALSE,
5155 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
5158 Yalien_wB, FALSE, TRUE,
5159 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
5162 Yalien_stone, FALSE, FALSE,
5163 EL_ROBOT, ACTION_SMASHED_BY_ROCK, -1
5166 Yalien_spring, FALSE, FALSE,
5167 EL_ROBOT, ACTION_SMASHED_BY_SPRING, -1
5170 Xemerald, TRUE, FALSE,
5174 Xemerald_pause, FALSE, FALSE,
5178 Xemerald_fall, FALSE, FALSE,
5182 Xemerald_shine, FALSE, FALSE,
5183 EL_EMERALD, ACTION_TWINKLING, -1
5186 Yemerald_s, FALSE, FALSE,
5187 EL_EMERALD, ACTION_FALLING, -1
5190 Yemerald_sB, FALSE, TRUE,
5191 EL_EMERALD, ACTION_FALLING, -1
5194 Yemerald_e, FALSE, FALSE,
5195 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
5198 Yemerald_eB, FALSE, TRUE,
5199 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
5202 Yemerald_w, FALSE, FALSE,
5203 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
5206 Yemerald_wB, FALSE, TRUE,
5207 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
5210 Yemerald_eat, FALSE, FALSE,
5211 EL_EMERALD, ACTION_COLLECTING, -1
5214 Yemerald_stone, FALSE, FALSE,
5215 EL_NUT, ACTION_BREAKING, -1
5218 Xdiamond, TRUE, FALSE,
5222 Xdiamond_pause, FALSE, FALSE,
5226 Xdiamond_fall, FALSE, FALSE,
5230 Xdiamond_shine, FALSE, FALSE,
5231 EL_DIAMOND, ACTION_TWINKLING, -1
5234 Ydiamond_s, FALSE, FALSE,
5235 EL_DIAMOND, ACTION_FALLING, -1
5238 Ydiamond_sB, FALSE, TRUE,
5239 EL_DIAMOND, ACTION_FALLING, -1
5242 Ydiamond_e, FALSE, FALSE,
5243 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
5246 Ydiamond_eB, FALSE, TRUE,
5247 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
5250 Ydiamond_w, FALSE, FALSE,
5251 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
5254 Ydiamond_wB, FALSE, TRUE,
5255 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
5258 Ydiamond_eat, FALSE, FALSE,
5259 EL_DIAMOND, ACTION_COLLECTING, -1
5262 Ydiamond_stone, FALSE, FALSE,
5263 EL_DIAMOND, ACTION_SMASHED_BY_ROCK, -1
5266 Xdrip_fall, TRUE, FALSE,
5267 EL_AMOEBA_DROP, -1, -1
5270 Xdrip_stretch, FALSE, FALSE,
5271 EL_AMOEBA_DROP, ACTION_FALLING, -1
5274 Xdrip_stretchB, FALSE, TRUE,
5275 EL_AMOEBA_DROP, ACTION_FALLING, -1
5278 Xdrip_eat, FALSE, FALSE,
5279 EL_AMOEBA_DROP, ACTION_GROWING, -1
5282 Ydrip_s1, FALSE, FALSE,
5283 EL_AMOEBA_DROP, ACTION_FALLING, -1
5286 Ydrip_s1B, FALSE, TRUE,
5287 EL_AMOEBA_DROP, ACTION_FALLING, -1
5290 Ydrip_s2, FALSE, FALSE,
5291 EL_AMOEBA_DROP, ACTION_FALLING, -1
5294 Ydrip_s2B, FALSE, TRUE,
5295 EL_AMOEBA_DROP, ACTION_FALLING, -1
5302 Xbomb_pause, FALSE, FALSE,
5306 Xbomb_fall, FALSE, FALSE,
5310 Ybomb_s, FALSE, FALSE,
5311 EL_BOMB, ACTION_FALLING, -1
5314 Ybomb_sB, FALSE, TRUE,
5315 EL_BOMB, ACTION_FALLING, -1
5318 Ybomb_e, FALSE, FALSE,
5319 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
5322 Ybomb_eB, FALSE, TRUE,
5323 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
5326 Ybomb_w, FALSE, FALSE,
5327 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
5330 Ybomb_wB, FALSE, TRUE,
5331 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
5334 Ybomb_eat, FALSE, FALSE,
5335 EL_BOMB, ACTION_ACTIVATING, -1
5338 Xballoon, TRUE, FALSE,
5342 Yballoon_n, FALSE, FALSE,
5343 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
5346 Yballoon_nB, FALSE, TRUE,
5347 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
5350 Yballoon_e, FALSE, FALSE,
5351 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
5354 Yballoon_eB, FALSE, TRUE,
5355 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
5358 Yballoon_s, FALSE, FALSE,
5359 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
5362 Yballoon_sB, FALSE, TRUE,
5363 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
5366 Yballoon_w, FALSE, FALSE,
5367 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
5370 Yballoon_wB, FALSE, TRUE,
5371 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
5374 Xgrass, TRUE, FALSE,
5375 EL_EMC_GRASS, -1, -1
5378 Ygrass_nB, FALSE, FALSE,
5379 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_UP
5382 Ygrass_eB, FALSE, FALSE,
5383 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_RIGHT
5386 Ygrass_sB, FALSE, FALSE,
5387 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_DOWN
5390 Ygrass_wB, FALSE, FALSE,
5391 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_LEFT
5398 Ydirt_nB, FALSE, FALSE,
5399 EL_SAND, ACTION_DIGGING, MV_BIT_UP
5402 Ydirt_eB, FALSE, FALSE,
5403 EL_SAND, ACTION_DIGGING, MV_BIT_RIGHT
5406 Ydirt_sB, FALSE, FALSE,
5407 EL_SAND, ACTION_DIGGING, MV_BIT_DOWN
5410 Ydirt_wB, FALSE, FALSE,
5411 EL_SAND, ACTION_DIGGING, MV_BIT_LEFT
5414 Xacid_ne, TRUE, FALSE,
5415 EL_ACID_POOL_TOPRIGHT, -1, -1
5418 Xacid_se, TRUE, FALSE,
5419 EL_ACID_POOL_BOTTOMRIGHT, -1, -1
5422 Xacid_s, TRUE, FALSE,
5423 EL_ACID_POOL_BOTTOM, -1, -1
5426 Xacid_sw, TRUE, FALSE,
5427 EL_ACID_POOL_BOTTOMLEFT, -1, -1
5430 Xacid_nw, TRUE, FALSE,
5431 EL_ACID_POOL_TOPLEFT, -1, -1
5434 Xacid_1, TRUE, FALSE,
5438 Xacid_2, FALSE, FALSE,
5442 Xacid_3, FALSE, FALSE,
5446 Xacid_4, FALSE, FALSE,
5450 Xacid_5, FALSE, FALSE,
5454 Xacid_6, FALSE, FALSE,
5458 Xacid_7, FALSE, FALSE,
5462 Xacid_8, FALSE, FALSE,
5466 Xball_1, TRUE, FALSE,
5467 EL_EMC_MAGIC_BALL, -1, -1
5470 Xball_1B, FALSE, FALSE,
5471 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
5474 Xball_2, FALSE, FALSE,
5475 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
5478 Xball_2B, FALSE, FALSE,
5479 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
5482 Yball_eat, FALSE, FALSE,
5483 EL_EMC_MAGIC_BALL, ACTION_DROPPING, -1
5486 Ykey_1_eat, FALSE, FALSE,
5487 EL_EM_KEY_1, ACTION_COLLECTING, -1
5490 Ykey_2_eat, FALSE, FALSE,
5491 EL_EM_KEY_2, ACTION_COLLECTING, -1
5494 Ykey_3_eat, FALSE, FALSE,
5495 EL_EM_KEY_3, ACTION_COLLECTING, -1
5498 Ykey_4_eat, FALSE, FALSE,
5499 EL_EM_KEY_4, ACTION_COLLECTING, -1
5502 Ykey_5_eat, FALSE, FALSE,
5503 EL_EMC_KEY_5, ACTION_COLLECTING, -1
5506 Ykey_6_eat, FALSE, FALSE,
5507 EL_EMC_KEY_6, ACTION_COLLECTING, -1
5510 Ykey_7_eat, FALSE, FALSE,
5511 EL_EMC_KEY_7, ACTION_COLLECTING, -1
5514 Ykey_8_eat, FALSE, FALSE,
5515 EL_EMC_KEY_8, ACTION_COLLECTING, -1
5518 Ylenses_eat, FALSE, FALSE,
5519 EL_EMC_LENSES, ACTION_COLLECTING, -1
5522 Ymagnify_eat, FALSE, FALSE,
5523 EL_EMC_MAGNIFIER, ACTION_COLLECTING, -1
5526 Ygrass_eat, FALSE, FALSE,
5527 EL_EMC_GRASS, ACTION_SNAPPING, -1
5530 Ydirt_eat, FALSE, FALSE,
5531 EL_SAND, ACTION_SNAPPING, -1
5534 Xgrow_ns, TRUE, FALSE,
5535 EL_EXPANDABLE_WALL_VERTICAL, -1, -1
5538 Ygrow_ns_eat, FALSE, FALSE,
5539 EL_EXPANDABLE_WALL_VERTICAL, ACTION_GROWING, -1
5542 Xgrow_ew, TRUE, FALSE,
5543 EL_EXPANDABLE_WALL_HORIZONTAL, -1, -1
5546 Ygrow_ew_eat, FALSE, FALSE,
5547 EL_EXPANDABLE_WALL_HORIZONTAL, ACTION_GROWING, -1
5550 Xwonderwall, TRUE, FALSE,
5551 EL_MAGIC_WALL, -1, -1
5554 XwonderwallB, FALSE, FALSE,
5555 EL_MAGIC_WALL, ACTION_ACTIVE, -1
5558 Xamoeba_1, TRUE, FALSE,
5559 EL_AMOEBA_DRY, ACTION_OTHER, -1
5562 Xamoeba_2, FALSE, FALSE,
5563 EL_AMOEBA_DRY, ACTION_OTHER, -1
5566 Xamoeba_3, FALSE, FALSE,
5567 EL_AMOEBA_DRY, ACTION_OTHER, -1
5570 Xamoeba_4, FALSE, FALSE,
5571 EL_AMOEBA_DRY, ACTION_OTHER, -1
5574 Xamoeba_5, TRUE, FALSE,
5575 EL_AMOEBA_WET, ACTION_OTHER, -1
5578 Xamoeba_6, FALSE, FALSE,
5579 EL_AMOEBA_WET, ACTION_OTHER, -1
5582 Xamoeba_7, FALSE, FALSE,
5583 EL_AMOEBA_WET, ACTION_OTHER, -1
5586 Xamoeba_8, FALSE, FALSE,
5587 EL_AMOEBA_WET, ACTION_OTHER, -1
5590 Xdoor_1, TRUE, FALSE,
5591 EL_EM_GATE_1, -1, -1
5594 Xdoor_2, TRUE, FALSE,
5595 EL_EM_GATE_2, -1, -1
5598 Xdoor_3, TRUE, FALSE,
5599 EL_EM_GATE_3, -1, -1
5602 Xdoor_4, TRUE, FALSE,
5603 EL_EM_GATE_4, -1, -1
5606 Xdoor_5, TRUE, FALSE,
5607 EL_EMC_GATE_5, -1, -1
5610 Xdoor_6, TRUE, FALSE,
5611 EL_EMC_GATE_6, -1, -1
5614 Xdoor_7, TRUE, FALSE,
5615 EL_EMC_GATE_7, -1, -1
5618 Xdoor_8, TRUE, FALSE,
5619 EL_EMC_GATE_8, -1, -1
5622 Xkey_1, TRUE, FALSE,
5626 Xkey_2, TRUE, FALSE,
5630 Xkey_3, TRUE, FALSE,
5634 Xkey_4, TRUE, FALSE,
5638 Xkey_5, TRUE, FALSE,
5639 EL_EMC_KEY_5, -1, -1
5642 Xkey_6, TRUE, FALSE,
5643 EL_EMC_KEY_6, -1, -1
5646 Xkey_7, TRUE, FALSE,
5647 EL_EMC_KEY_7, -1, -1
5650 Xkey_8, TRUE, FALSE,
5651 EL_EMC_KEY_8, -1, -1
5654 Xwind_n, TRUE, FALSE,
5655 EL_BALLOON_SWITCH_UP, -1, -1
5658 Xwind_e, TRUE, FALSE,
5659 EL_BALLOON_SWITCH_RIGHT, -1, -1
5662 Xwind_s, TRUE, FALSE,
5663 EL_BALLOON_SWITCH_DOWN, -1, -1
5666 Xwind_w, TRUE, FALSE,
5667 EL_BALLOON_SWITCH_LEFT, -1, -1
5670 Xwind_nesw, TRUE, FALSE,
5671 EL_BALLOON_SWITCH_ANY, -1, -1
5674 Xwind_stop, TRUE, FALSE,
5675 EL_BALLOON_SWITCH_NONE, -1, -1
5679 EL_EM_EXIT_CLOSED, -1, -1
5682 Xexit_1, TRUE, FALSE,
5683 EL_EM_EXIT_OPEN, -1, -1
5686 Xexit_2, FALSE, FALSE,
5687 EL_EM_EXIT_OPEN, -1, -1
5690 Xexit_3, FALSE, FALSE,
5691 EL_EM_EXIT_OPEN, -1, -1
5694 Xdynamite, TRUE, FALSE,
5695 EL_EM_DYNAMITE, -1, -1
5698 Ydynamite_eat, FALSE, FALSE,
5699 EL_EM_DYNAMITE, ACTION_COLLECTING, -1
5702 Xdynamite_1, TRUE, FALSE,
5703 EL_EM_DYNAMITE_ACTIVE, -1, -1
5706 Xdynamite_2, FALSE, FALSE,
5707 EL_EM_DYNAMITE_ACTIVE, -1, -1
5710 Xdynamite_3, FALSE, FALSE,
5711 EL_EM_DYNAMITE_ACTIVE, -1, -1
5714 Xdynamite_4, FALSE, FALSE,
5715 EL_EM_DYNAMITE_ACTIVE, -1, -1
5718 Xbumper, TRUE, FALSE,
5719 EL_EMC_SPRING_BUMPER, -1, -1
5722 XbumperB, FALSE, FALSE,
5723 EL_EMC_SPRING_BUMPER, ACTION_ACTIVE, -1
5726 Xwheel, TRUE, FALSE,
5727 EL_ROBOT_WHEEL, -1, -1
5730 XwheelB, FALSE, FALSE,
5731 EL_ROBOT_WHEEL, ACTION_ACTIVE, -1
5734 Xswitch, TRUE, FALSE,
5735 EL_EMC_MAGIC_BALL_SWITCH, -1, -1
5738 XswitchB, FALSE, FALSE,
5739 EL_EMC_MAGIC_BALL_SWITCH, ACTION_ACTIVE, -1
5743 EL_QUICKSAND_EMPTY, -1, -1
5746 Xsand_stone, TRUE, FALSE,
5747 EL_QUICKSAND_FULL, -1, -1
5750 Xsand_stonein_1, FALSE, TRUE,
5751 EL_ROCK, ACTION_FILLING, -1
5754 Xsand_stonein_2, FALSE, TRUE,
5755 EL_ROCK, ACTION_FILLING, -1
5758 Xsand_stonein_3, FALSE, TRUE,
5759 EL_ROCK, ACTION_FILLING, -1
5762 Xsand_stonein_4, FALSE, TRUE,
5763 EL_ROCK, ACTION_FILLING, -1
5766 Xsand_stonesand_1, FALSE, FALSE,
5767 EL_QUICKSAND_EMPTYING, -1, -1
5770 Xsand_stonesand_2, FALSE, FALSE,
5771 EL_QUICKSAND_EMPTYING, -1, -1
5774 Xsand_stonesand_3, FALSE, FALSE,
5775 EL_QUICKSAND_EMPTYING, -1, -1
5778 Xsand_stonesand_4, FALSE, FALSE,
5779 EL_QUICKSAND_EMPTYING, -1, -1
5782 Xsand_stonesand_quickout_1, FALSE, FALSE,
5783 EL_QUICKSAND_EMPTYING, -1, -1
5786 Xsand_stonesand_quickout_2, FALSE, FALSE,
5787 EL_QUICKSAND_EMPTYING, -1, -1
5790 Xsand_stoneout_1, FALSE, FALSE,
5791 EL_ROCK, ACTION_EMPTYING, -1
5794 Xsand_stoneout_2, FALSE, FALSE,
5795 EL_ROCK, ACTION_EMPTYING, -1
5798 Xsand_sandstone_1, FALSE, FALSE,
5799 EL_QUICKSAND_FILLING, -1, -1
5802 Xsand_sandstone_2, FALSE, FALSE,
5803 EL_QUICKSAND_FILLING, -1, -1
5806 Xsand_sandstone_3, FALSE, FALSE,
5807 EL_QUICKSAND_FILLING, -1, -1
5810 Xsand_sandstone_4, FALSE, FALSE,
5811 EL_QUICKSAND_FILLING, -1, -1
5814 Xplant, TRUE, FALSE,
5815 EL_EMC_PLANT, -1, -1
5818 Yplant, FALSE, FALSE,
5819 EL_EMC_PLANT, -1, -1
5822 Xlenses, TRUE, FALSE,
5823 EL_EMC_LENSES, -1, -1
5826 Xmagnify, TRUE, FALSE,
5827 EL_EMC_MAGNIFIER, -1, -1
5830 Xdripper, TRUE, FALSE,
5831 EL_EMC_DRIPPER, -1, -1
5834 XdripperB, FALSE, FALSE,
5835 EL_EMC_DRIPPER, ACTION_ACTIVE, -1
5838 Xfake_blank, TRUE, FALSE,
5839 EL_INVISIBLE_WALL, -1, -1
5842 Xfake_blankB, FALSE, FALSE,
5843 EL_INVISIBLE_WALL, ACTION_ACTIVE, -1
5846 Xfake_grass, TRUE, FALSE,
5847 EL_EMC_FAKE_GRASS, -1, -1
5850 Xfake_grassB, FALSE, FALSE,
5851 EL_EMC_FAKE_GRASS, ACTION_ACTIVE, -1
5854 Xfake_door_1, TRUE, FALSE,
5855 EL_EM_GATE_1_GRAY, -1, -1
5858 Xfake_door_2, TRUE, FALSE,
5859 EL_EM_GATE_2_GRAY, -1, -1
5862 Xfake_door_3, TRUE, FALSE,
5863 EL_EM_GATE_3_GRAY, -1, -1
5866 Xfake_door_4, TRUE, FALSE,
5867 EL_EM_GATE_4_GRAY, -1, -1
5870 Xfake_door_5, TRUE, FALSE,
5871 EL_EMC_GATE_5_GRAY, -1, -1
5874 Xfake_door_6, TRUE, FALSE,
5875 EL_EMC_GATE_6_GRAY, -1, -1
5878 Xfake_door_7, TRUE, FALSE,
5879 EL_EMC_GATE_7_GRAY, -1, -1
5882 Xfake_door_8, TRUE, FALSE,
5883 EL_EMC_GATE_8_GRAY, -1, -1
5886 Xfake_acid_1, TRUE, FALSE,
5887 EL_EMC_FAKE_ACID, -1, -1
5890 Xfake_acid_2, FALSE, FALSE,
5891 EL_EMC_FAKE_ACID, -1, -1
5894 Xfake_acid_3, FALSE, FALSE,
5895 EL_EMC_FAKE_ACID, -1, -1
5898 Xfake_acid_4, FALSE, FALSE,
5899 EL_EMC_FAKE_ACID, -1, -1
5902 Xfake_acid_5, FALSE, FALSE,
5903 EL_EMC_FAKE_ACID, -1, -1
5906 Xfake_acid_6, FALSE, FALSE,
5907 EL_EMC_FAKE_ACID, -1, -1
5910 Xfake_acid_7, FALSE, FALSE,
5911 EL_EMC_FAKE_ACID, -1, -1
5914 Xfake_acid_8, FALSE, FALSE,
5915 EL_EMC_FAKE_ACID, -1, -1
5918 Xsteel_1, TRUE, FALSE,
5919 EL_STEELWALL, -1, -1
5922 Xsteel_2, TRUE, FALSE,
5923 EL_EMC_STEELWALL_2, -1, -1
5926 Xsteel_3, TRUE, FALSE,
5927 EL_EMC_STEELWALL_3, -1, -1
5930 Xsteel_4, TRUE, FALSE,
5931 EL_EMC_STEELWALL_4, -1, -1
5934 Xwall_1, TRUE, FALSE,
5938 Xwall_2, TRUE, FALSE,
5939 EL_EMC_WALL_14, -1, -1
5942 Xwall_3, TRUE, FALSE,
5943 EL_EMC_WALL_15, -1, -1
5946 Xwall_4, TRUE, FALSE,
5947 EL_EMC_WALL_16, -1, -1
5950 Xround_wall_1, TRUE, FALSE,
5951 EL_WALL_SLIPPERY, -1, -1
5954 Xround_wall_2, TRUE, FALSE,
5955 EL_EMC_WALL_SLIPPERY_2, -1, -1
5958 Xround_wall_3, TRUE, FALSE,
5959 EL_EMC_WALL_SLIPPERY_3, -1, -1
5962 Xround_wall_4, TRUE, FALSE,
5963 EL_EMC_WALL_SLIPPERY_4, -1, -1
5966 Xdecor_1, TRUE, FALSE,
5967 EL_EMC_WALL_8, -1, -1
5970 Xdecor_2, TRUE, FALSE,
5971 EL_EMC_WALL_6, -1, -1
5974 Xdecor_3, TRUE, FALSE,
5975 EL_EMC_WALL_4, -1, -1
5978 Xdecor_4, TRUE, FALSE,
5979 EL_EMC_WALL_7, -1, -1
5982 Xdecor_5, TRUE, FALSE,
5983 EL_EMC_WALL_5, -1, -1
5986 Xdecor_6, TRUE, FALSE,
5987 EL_EMC_WALL_9, -1, -1
5990 Xdecor_7, TRUE, FALSE,
5991 EL_EMC_WALL_10, -1, -1
5994 Xdecor_8, TRUE, FALSE,
5995 EL_EMC_WALL_1, -1, -1
5998 Xdecor_9, TRUE, FALSE,
5999 EL_EMC_WALL_2, -1, -1
6002 Xdecor_10, TRUE, FALSE,
6003 EL_EMC_WALL_3, -1, -1
6006 Xdecor_11, TRUE, FALSE,
6007 EL_EMC_WALL_11, -1, -1
6010 Xdecor_12, TRUE, FALSE,
6011 EL_EMC_WALL_12, -1, -1
6014 Xalpha_0, TRUE, FALSE,
6015 EL_CHAR('0'), -1, -1
6018 Xalpha_1, TRUE, FALSE,
6019 EL_CHAR('1'), -1, -1
6022 Xalpha_2, TRUE, FALSE,
6023 EL_CHAR('2'), -1, -1
6026 Xalpha_3, TRUE, FALSE,
6027 EL_CHAR('3'), -1, -1
6030 Xalpha_4, TRUE, FALSE,
6031 EL_CHAR('4'), -1, -1
6034 Xalpha_5, TRUE, FALSE,
6035 EL_CHAR('5'), -1, -1
6038 Xalpha_6, TRUE, FALSE,
6039 EL_CHAR('6'), -1, -1
6042 Xalpha_7, TRUE, FALSE,
6043 EL_CHAR('7'), -1, -1
6046 Xalpha_8, TRUE, FALSE,
6047 EL_CHAR('8'), -1, -1
6050 Xalpha_9, TRUE, FALSE,
6051 EL_CHAR('9'), -1, -1
6054 Xalpha_excla, TRUE, FALSE,
6055 EL_CHAR('!'), -1, -1
6058 Xalpha_quote, TRUE, FALSE,
6059 EL_CHAR('"'), -1, -1
6062 Xalpha_comma, TRUE, FALSE,
6063 EL_CHAR(','), -1, -1
6066 Xalpha_minus, TRUE, FALSE,
6067 EL_CHAR('-'), -1, -1
6070 Xalpha_perio, TRUE, FALSE,
6071 EL_CHAR('.'), -1, -1
6074 Xalpha_colon, TRUE, FALSE,
6075 EL_CHAR(':'), -1, -1
6078 Xalpha_quest, TRUE, FALSE,
6079 EL_CHAR('?'), -1, -1
6082 Xalpha_a, TRUE, FALSE,
6083 EL_CHAR('A'), -1, -1
6086 Xalpha_b, TRUE, FALSE,
6087 EL_CHAR('B'), -1, -1
6090 Xalpha_c, TRUE, FALSE,
6091 EL_CHAR('C'), -1, -1
6094 Xalpha_d, TRUE, FALSE,
6095 EL_CHAR('D'), -1, -1
6098 Xalpha_e, TRUE, FALSE,
6099 EL_CHAR('E'), -1, -1
6102 Xalpha_f, TRUE, FALSE,
6103 EL_CHAR('F'), -1, -1
6106 Xalpha_g, TRUE, FALSE,
6107 EL_CHAR('G'), -1, -1
6110 Xalpha_h, TRUE, FALSE,
6111 EL_CHAR('H'), -1, -1
6114 Xalpha_i, TRUE, FALSE,
6115 EL_CHAR('I'), -1, -1
6118 Xalpha_j, TRUE, FALSE,
6119 EL_CHAR('J'), -1, -1
6122 Xalpha_k, TRUE, FALSE,
6123 EL_CHAR('K'), -1, -1
6126 Xalpha_l, TRUE, FALSE,
6127 EL_CHAR('L'), -1, -1
6130 Xalpha_m, TRUE, FALSE,
6131 EL_CHAR('M'), -1, -1
6134 Xalpha_n, TRUE, FALSE,
6135 EL_CHAR('N'), -1, -1
6138 Xalpha_o, TRUE, FALSE,
6139 EL_CHAR('O'), -1, -1
6142 Xalpha_p, TRUE, FALSE,
6143 EL_CHAR('P'), -1, -1
6146 Xalpha_q, TRUE, FALSE,
6147 EL_CHAR('Q'), -1, -1
6150 Xalpha_r, TRUE, FALSE,
6151 EL_CHAR('R'), -1, -1
6154 Xalpha_s, TRUE, FALSE,
6155 EL_CHAR('S'), -1, -1
6158 Xalpha_t, TRUE, FALSE,
6159 EL_CHAR('T'), -1, -1
6162 Xalpha_u, TRUE, FALSE,
6163 EL_CHAR('U'), -1, -1
6166 Xalpha_v, TRUE, FALSE,
6167 EL_CHAR('V'), -1, -1
6170 Xalpha_w, TRUE, FALSE,
6171 EL_CHAR('W'), -1, -1
6174 Xalpha_x, TRUE, FALSE,
6175 EL_CHAR('X'), -1, -1
6178 Xalpha_y, TRUE, FALSE,
6179 EL_CHAR('Y'), -1, -1
6182 Xalpha_z, TRUE, FALSE,
6183 EL_CHAR('Z'), -1, -1
6186 Xalpha_arrow_e, TRUE, FALSE,
6187 EL_CHAR('>'), -1, -1
6190 Xalpha_arrow_w, TRUE, FALSE,
6191 EL_CHAR('<'), -1, -1
6194 Xalpha_copyr, TRUE, FALSE,
6195 EL_CHAR(CHAR_BYTE_COPYRIGHT), -1, -1
6199 Xboom_bug, FALSE, FALSE,
6200 EL_BUG, ACTION_EXPLODING, -1
6203 Xboom_bomb, FALSE, FALSE,
6204 EL_BOMB, ACTION_EXPLODING, -1
6207 Xboom_android, FALSE, FALSE,
6208 EL_EMC_ANDROID, ACTION_OTHER, -1
6211 Xboom_1, FALSE, FALSE,
6212 EL_DEFAULT, ACTION_EXPLODING, -1
6215 Xboom_2, FALSE, FALSE,
6216 EL_DEFAULT, ACTION_EXPLODING, -1
6219 Znormal, FALSE, FALSE,
6223 Zdynamite, FALSE, FALSE,
6227 Zplayer, FALSE, FALSE,
6231 ZBORDER, FALSE, FALSE,
6241 static struct Mapping_EM_to_RND_player
6250 em_player_mapping_list[] =
6254 EL_PLAYER_1, ACTION_MOVING, MV_BIT_UP,
6258 EL_PLAYER_1, ACTION_MOVING, MV_BIT_RIGHT,
6262 EL_PLAYER_1, ACTION_MOVING, MV_BIT_DOWN,
6266 EL_PLAYER_1, ACTION_MOVING, MV_BIT_LEFT,
6270 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_UP,
6274 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_RIGHT,
6278 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_DOWN,
6282 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_LEFT,
6286 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_UP,
6290 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_RIGHT,
6294 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_DOWN,
6298 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_LEFT,
6302 EL_PLAYER_2, ACTION_MOVING, MV_BIT_UP,
6306 EL_PLAYER_2, ACTION_MOVING, MV_BIT_RIGHT,
6310 EL_PLAYER_2, ACTION_MOVING, MV_BIT_DOWN,
6314 EL_PLAYER_2, ACTION_MOVING, MV_BIT_LEFT,
6318 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_UP,
6322 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_RIGHT,
6326 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_DOWN,
6330 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_LEFT,
6334 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_UP,
6338 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_RIGHT,
6342 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_DOWN,
6346 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_LEFT,
6350 EL_PLAYER_1, ACTION_DEFAULT, -1,
6354 EL_PLAYER_2, ACTION_DEFAULT, -1,
6358 EL_PLAYER_3, ACTION_MOVING, MV_BIT_UP,
6362 EL_PLAYER_3, ACTION_MOVING, MV_BIT_RIGHT,
6366 EL_PLAYER_3, ACTION_MOVING, MV_BIT_DOWN,
6370 EL_PLAYER_3, ACTION_MOVING, MV_BIT_LEFT,
6374 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_UP,
6378 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_RIGHT,
6382 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_DOWN,
6386 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_LEFT,
6390 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_UP,
6394 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_RIGHT,
6398 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_DOWN,
6402 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_LEFT,
6406 EL_PLAYER_4, ACTION_MOVING, MV_BIT_UP,
6410 EL_PLAYER_4, ACTION_MOVING, MV_BIT_RIGHT,
6414 EL_PLAYER_4, ACTION_MOVING, MV_BIT_DOWN,
6418 EL_PLAYER_4, ACTION_MOVING, MV_BIT_LEFT,
6422 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_UP,
6426 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_RIGHT,
6430 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_DOWN,
6434 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_LEFT,
6438 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_UP,
6442 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_RIGHT,
6446 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_DOWN,
6450 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_LEFT,
6454 EL_PLAYER_3, ACTION_DEFAULT, -1,
6458 EL_PLAYER_4, ACTION_DEFAULT, -1,
6467 int map_element_RND_to_EM(int element_rnd)
6469 static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
6470 static boolean mapping_initialized = FALSE;
6472 if (!mapping_initialized)
6476 /* return "Xalpha_quest" for all undefined elements in mapping array */
6477 for (i = 0; i < NUM_FILE_ELEMENTS; i++)
6478 mapping_RND_to_EM[i] = Xalpha_quest;
6480 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
6481 if (em_object_mapping_list[i].is_rnd_to_em_mapping)
6482 mapping_RND_to_EM[em_object_mapping_list[i].element_rnd] =
6483 em_object_mapping_list[i].element_em;
6485 mapping_initialized = TRUE;
6488 if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
6489 return mapping_RND_to_EM[element_rnd];
6491 Error(ERR_WARN, "invalid RND level element %d", element_rnd);
6496 int map_element_EM_to_RND(int element_em)
6498 static unsigned short mapping_EM_to_RND[TILE_MAX];
6499 static boolean mapping_initialized = FALSE;
6501 if (!mapping_initialized)
6505 /* return "EL_UNKNOWN" for all undefined elements in mapping array */
6506 for (i = 0; i < TILE_MAX; i++)
6507 mapping_EM_to_RND[i] = EL_UNKNOWN;
6509 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
6510 mapping_EM_to_RND[em_object_mapping_list[i].element_em] =
6511 em_object_mapping_list[i].element_rnd;
6513 mapping_initialized = TRUE;
6516 if (element_em >= 0 && element_em < TILE_MAX)
6517 return mapping_EM_to_RND[element_em];
6519 Error(ERR_WARN, "invalid EM level element %d", element_em);
6524 void map_android_clone_elements_RND_to_EM(struct LevelInfo *level)
6526 struct LevelInfo_EM *level_em = level->native_em_level;
6527 struct LEVEL *lev = level_em->lev;
6530 for (i = 0; i < TILE_MAX; i++)
6531 lev->android_array[i] = Xblank;
6533 for (i = 0; i < level->num_android_clone_elements; i++)
6535 int element_rnd = level->android_clone_element[i];
6536 int element_em = map_element_RND_to_EM(element_rnd);
6538 for (j = 0; em_object_mapping_list[j].element_em != -1; j++)
6539 if (em_object_mapping_list[j].element_rnd == element_rnd)
6540 lev->android_array[em_object_mapping_list[j].element_em] = element_em;
6544 void map_android_clone_elements_EM_to_RND(struct LevelInfo *level)
6546 struct LevelInfo_EM *level_em = level->native_em_level;
6547 struct LEVEL *lev = level_em->lev;
6550 level->num_android_clone_elements = 0;
6552 for (i = 0; i < TILE_MAX; i++)
6554 int element_em = lev->android_array[i];
6556 boolean element_found = FALSE;
6558 if (element_em == Xblank)
6561 element_rnd = map_element_EM_to_RND(element_em);
6563 for (j = 0; j < level->num_android_clone_elements; j++)
6564 if (level->android_clone_element[j] == element_rnd)
6565 element_found = TRUE;
6569 level->android_clone_element[level->num_android_clone_elements++] =
6572 if (level->num_android_clone_elements == MAX_ANDROID_ELEMENTS)
6577 if (level->num_android_clone_elements == 0)
6579 level->num_android_clone_elements = 1;
6580 level->android_clone_element[0] = EL_EMPTY;
6584 int map_direction_RND_to_EM(int direction)
6586 return (direction == MV_UP ? 0 :
6587 direction == MV_RIGHT ? 1 :
6588 direction == MV_DOWN ? 2 :
6589 direction == MV_LEFT ? 3 :
6593 int map_direction_EM_to_RND(int direction)
6595 return (direction == 0 ? MV_UP :
6596 direction == 1 ? MV_RIGHT :
6597 direction == 2 ? MV_DOWN :
6598 direction == 3 ? MV_LEFT :
6602 int map_element_RND_to_SP(int element_rnd)
6604 int element_sp = 0x20; /* map unknown elements to yellow "hardware" */
6606 if (element_rnd >= EL_SP_START &&
6607 element_rnd <= EL_SP_END)
6608 element_sp = element_rnd - EL_SP_START;
6609 else if (element_rnd == EL_EMPTY_SPACE)
6611 else if (element_rnd == EL_INVISIBLE_WALL)
6617 int map_element_SP_to_RND(int element_sp)
6619 int element_rnd = EL_UNKNOWN;
6621 if (element_sp >= 0x00 &&
6623 element_rnd = EL_SP_START + element_sp;
6624 else if (element_sp == 0x28)
6625 element_rnd = EL_INVISIBLE_WALL;
6630 int map_action_SP_to_RND(int action_sp)
6634 case actActive: return ACTION_ACTIVE;
6635 case actImpact: return ACTION_IMPACT;
6636 case actExploding: return ACTION_EXPLODING;
6637 case actDigging: return ACTION_DIGGING;
6638 case actSnapping: return ACTION_SNAPPING;
6639 case actCollecting: return ACTION_COLLECTING;
6640 case actPassing: return ACTION_PASSING;
6641 case actPushing: return ACTION_PUSHING;
6642 case actDropping: return ACTION_DROPPING;
6644 default: return ACTION_DEFAULT;
6648 int get_next_element(int element)
6652 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
6653 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
6654 case EL_QUICKSAND_FAST_FILLING: return EL_QUICKSAND_FAST_FULL;
6655 case EL_QUICKSAND_FAST_EMPTYING: return EL_QUICKSAND_FAST_EMPTY;
6656 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
6657 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
6658 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
6659 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
6660 case EL_DC_MAGIC_WALL_FILLING: return EL_DC_MAGIC_WALL_FULL;
6661 case EL_DC_MAGIC_WALL_EMPTYING: return EL_DC_MAGIC_WALL_ACTIVE;
6662 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
6664 default: return element;
6668 int el_act_dir2img(int element, int action, int direction)
6670 element = GFX_ELEMENT(element);
6671 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
6673 /* direction_graphic[][] == graphic[] for undefined direction graphics */
6674 return element_info[element].direction_graphic[action][direction];
6677 static int el_act_dir2crm(int element, int action, int direction)
6679 element = GFX_ELEMENT(element);
6680 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
6682 /* direction_graphic[][] == graphic[] for undefined direction graphics */
6683 return element_info[element].direction_crumbled[action][direction];
6686 int el_act2img(int element, int action)
6688 element = GFX_ELEMENT(element);
6690 return element_info[element].graphic[action];
6693 int el_act2crm(int element, int action)
6695 element = GFX_ELEMENT(element);
6697 return element_info[element].crumbled[action];
6700 int el_dir2img(int element, int direction)
6702 element = GFX_ELEMENT(element);
6704 return el_act_dir2img(element, ACTION_DEFAULT, direction);
6707 int el2baseimg(int element)
6709 return element_info[element].graphic[ACTION_DEFAULT];
6712 int el2img(int element)
6714 element = GFX_ELEMENT(element);
6716 return element_info[element].graphic[ACTION_DEFAULT];
6719 int el2edimg(int element)
6721 element = GFX_ELEMENT(element);
6723 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
6726 int el2preimg(int element)
6728 element = GFX_ELEMENT(element);
6730 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
6733 int el2panelimg(int element)
6735 element = GFX_ELEMENT(element);
6737 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PANEL];
6740 int font2baseimg(int font_nr)
6742 return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
6745 int getBeltNrFromBeltElement(int element)
6747 return (element < EL_CONVEYOR_BELT_2_LEFT ? 0 :
6748 element < EL_CONVEYOR_BELT_3_LEFT ? 1 :
6749 element < EL_CONVEYOR_BELT_4_LEFT ? 2 : 3);
6752 int getBeltNrFromBeltActiveElement(int element)
6754 return (element < EL_CONVEYOR_BELT_2_LEFT_ACTIVE ? 0 :
6755 element < EL_CONVEYOR_BELT_3_LEFT_ACTIVE ? 1 :
6756 element < EL_CONVEYOR_BELT_4_LEFT_ACTIVE ? 2 : 3);
6759 int getBeltNrFromBeltSwitchElement(int element)
6761 return (element < EL_CONVEYOR_BELT_2_SWITCH_LEFT ? 0 :
6762 element < EL_CONVEYOR_BELT_3_SWITCH_LEFT ? 1 :
6763 element < EL_CONVEYOR_BELT_4_SWITCH_LEFT ? 2 : 3);
6766 int getBeltDirNrFromBeltElement(int element)
6768 static int belt_base_element[4] =
6770 EL_CONVEYOR_BELT_1_LEFT,
6771 EL_CONVEYOR_BELT_2_LEFT,
6772 EL_CONVEYOR_BELT_3_LEFT,
6773 EL_CONVEYOR_BELT_4_LEFT
6776 int belt_nr = getBeltNrFromBeltElement(element);
6777 int belt_dir_nr = element - belt_base_element[belt_nr];
6779 return (belt_dir_nr % 3);
6782 int getBeltDirNrFromBeltSwitchElement(int element)
6784 static int belt_base_element[4] =
6786 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
6787 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
6788 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
6789 EL_CONVEYOR_BELT_4_SWITCH_LEFT
6792 int belt_nr = getBeltNrFromBeltSwitchElement(element);
6793 int belt_dir_nr = element - belt_base_element[belt_nr];
6795 return (belt_dir_nr % 3);
6798 int getBeltDirFromBeltElement(int element)
6800 static int belt_move_dir[3] =
6807 int belt_dir_nr = getBeltDirNrFromBeltElement(element);
6809 return belt_move_dir[belt_dir_nr];
6812 int getBeltDirFromBeltSwitchElement(int element)
6814 static int belt_move_dir[3] =
6821 int belt_dir_nr = getBeltDirNrFromBeltSwitchElement(element);
6823 return belt_move_dir[belt_dir_nr];
6826 int getBeltElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
6828 static int belt_base_element[4] =
6830 EL_CONVEYOR_BELT_1_LEFT,
6831 EL_CONVEYOR_BELT_2_LEFT,
6832 EL_CONVEYOR_BELT_3_LEFT,
6833 EL_CONVEYOR_BELT_4_LEFT
6836 return belt_base_element[belt_nr] + belt_dir_nr;
6839 int getBeltElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
6841 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
6843 return getBeltElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
6846 int getBeltSwitchElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
6848 static int belt_base_element[4] =
6850 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
6851 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
6852 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
6853 EL_CONVEYOR_BELT_4_SWITCH_LEFT
6856 return belt_base_element[belt_nr] + belt_dir_nr;
6859 int getBeltSwitchElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
6861 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
6863 return getBeltSwitchElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
6866 boolean getTeamMode_EM()
6868 return game.team_mode;
6871 int getGameFrameDelay_EM(int native_em_game_frame_delay)
6873 int game_frame_delay_value;
6875 game_frame_delay_value =
6876 (tape.playing && tape.fast_forward ? FfwdFrameDelay :
6877 GameFrameDelay == GAME_FRAME_DELAY ? native_em_game_frame_delay :
6880 if (tape.playing && tape.warp_forward && !tape.pausing)
6881 game_frame_delay_value = 0;
6883 return game_frame_delay_value;
6886 unsigned int InitRND(int seed)
6888 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
6889 return InitEngineRandom_EM(seed);
6890 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
6891 return InitEngineRandom_SP(seed);
6893 return InitEngineRandom_RND(seed);
6896 static struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
6897 static struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
6899 inline static int get_effective_element_EM(int tile, int frame_em)
6901 int element = object_mapping[tile].element_rnd;
6902 int action = object_mapping[tile].action;
6903 boolean is_backside = object_mapping[tile].is_backside;
6904 boolean action_removing = (action == ACTION_DIGGING ||
6905 action == ACTION_SNAPPING ||
6906 action == ACTION_COLLECTING);
6912 case Yacid_splash_eB:
6913 case Yacid_splash_wB:
6914 return (frame_em > 5 ? EL_EMPTY : element);
6920 else /* frame_em == 7 */
6924 case Yacid_splash_eB:
6925 case Yacid_splash_wB:
6928 case Yemerald_stone:
6931 case Ydiamond_stone:
6935 case Xdrip_stretchB:
6954 case Xsand_stonein_1:
6955 case Xsand_stonein_2:
6956 case Xsand_stonein_3:
6957 case Xsand_stonein_4:
6961 return (is_backside || action_removing ? EL_EMPTY : element);
6966 inline static boolean check_linear_animation_EM(int tile)
6970 case Xsand_stonesand_1:
6971 case Xsand_stonesand_quickout_1:
6972 case Xsand_sandstone_1:
6973 case Xsand_stonein_1:
6974 case Xsand_stoneout_1:
6993 case Yacid_splash_eB:
6994 case Yacid_splash_wB:
6995 case Yemerald_stone:
7002 inline static void set_crumbled_graphics_EM(struct GraphicInfo_EM *g_em,
7003 boolean has_crumbled_graphics,
7004 int crumbled, int sync_frame)
7006 /* if element can be crumbled, but certain action graphics are just empty
7007 space (like instantly snapping sand to empty space in 1 frame), do not
7008 treat these empty space graphics as crumbled graphics in EMC engine */
7009 if (crumbled == IMG_EMPTY_SPACE)
7010 has_crumbled_graphics = FALSE;
7012 if (has_crumbled_graphics)
7014 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
7015 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
7016 g_crumbled->anim_delay,
7017 g_crumbled->anim_mode,
7018 g_crumbled->anim_start_frame,
7021 getGraphicSource(crumbled, frame_crumbled, &g_em->crumbled_bitmap,
7022 &g_em->crumbled_src_x, &g_em->crumbled_src_y);
7024 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
7026 g_em->has_crumbled_graphics = TRUE;
7030 g_em->crumbled_bitmap = NULL;
7031 g_em->crumbled_src_x = 0;
7032 g_em->crumbled_src_y = 0;
7033 g_em->crumbled_border_size = 0;
7035 g_em->has_crumbled_graphics = FALSE;
7039 void ResetGfxAnimation_EM(int x, int y, int tile)
7044 void SetGfxAnimation_EM(struct GraphicInfo_EM *g_em,
7045 int tile, int frame_em, int x, int y)
7047 int action = object_mapping[tile].action;
7048 int direction = object_mapping[tile].direction;
7049 int effective_element = get_effective_element_EM(tile, frame_em);
7050 int graphic = (direction == MV_NONE ?
7051 el_act2img(effective_element, action) :
7052 el_act_dir2img(effective_element, action, direction));
7053 struct GraphicInfo *g = &graphic_info[graphic];
7055 boolean action_removing = (action == ACTION_DIGGING ||
7056 action == ACTION_SNAPPING ||
7057 action == ACTION_COLLECTING);
7058 boolean action_moving = (action == ACTION_FALLING ||
7059 action == ACTION_MOVING ||
7060 action == ACTION_PUSHING ||
7061 action == ACTION_EATING ||
7062 action == ACTION_FILLING ||
7063 action == ACTION_EMPTYING);
7064 boolean action_falling = (action == ACTION_FALLING ||
7065 action == ACTION_FILLING ||
7066 action == ACTION_EMPTYING);
7068 /* special case: graphic uses "2nd movement tile" and has defined
7069 7 frames for movement animation (or less) => use default graphic
7070 for last (8th) frame which ends the movement animation */
7071 if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
7073 action = ACTION_DEFAULT; /* (keep action_* unchanged for now) */
7074 graphic = (direction == MV_NONE ?
7075 el_act2img(effective_element, action) :
7076 el_act_dir2img(effective_element, action, direction));
7078 g = &graphic_info[graphic];
7081 if ((action_removing || check_linear_animation_EM(tile)) && frame_em == 0)
7085 else if (action_moving)
7087 boolean is_backside = object_mapping[tile].is_backside;
7091 int direction = object_mapping[tile].direction;
7092 int move_dir = (action_falling ? MV_DOWN : direction);
7097 /* !!! TEST !!! NEW !!! DOES NOT WORK RIGHT YET !!! */
7098 if (g->double_movement && frame_em == 0)
7102 if (move_dir == MV_LEFT)
7103 GfxFrame[x - 1][y] = GfxFrame[x][y];
7104 else if (move_dir == MV_RIGHT)
7105 GfxFrame[x + 1][y] = GfxFrame[x][y];
7106 else if (move_dir == MV_UP)
7107 GfxFrame[x][y - 1] = GfxFrame[x][y];
7108 else if (move_dir == MV_DOWN)
7109 GfxFrame[x][y + 1] = GfxFrame[x][y];
7116 /* special case: animation for Xsand_stonesand_quickout_1/2 twice as fast */
7117 if (tile == Xsand_stonesand_quickout_1 ||
7118 tile == Xsand_stonesand_quickout_2)
7122 if (graphic_info[graphic].anim_global_sync)
7123 sync_frame = FrameCounter;
7124 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
7125 sync_frame = GfxFrame[x][y];
7127 sync_frame = 0; /* playfield border (pseudo steel) */
7129 SetRandomAnimationValue(x, y);
7131 int frame = getAnimationFrame(g->anim_frames,
7134 g->anim_start_frame,
7137 g_em->unique_identifier =
7138 (graphic << 16) | ((frame % 8) << 12) | (g_em->width << 6) | g_em->height;
7141 void getGraphicSourceObjectExt_EM(struct GraphicInfo_EM *g_em,
7142 int tile, int frame_em, int x, int y)
7144 int action = object_mapping[tile].action;
7145 int direction = object_mapping[tile].direction;
7146 boolean is_backside = object_mapping[tile].is_backside;
7147 int effective_element = get_effective_element_EM(tile, frame_em);
7148 int effective_action = action;
7149 int graphic = (direction == MV_NONE ?
7150 el_act2img(effective_element, effective_action) :
7151 el_act_dir2img(effective_element, effective_action,
7153 int crumbled = (direction == MV_NONE ?
7154 el_act2crm(effective_element, effective_action) :
7155 el_act_dir2crm(effective_element, effective_action,
7157 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
7158 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
7159 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
7160 struct GraphicInfo *g = &graphic_info[graphic];
7163 /* special case: graphic uses "2nd movement tile" and has defined
7164 7 frames for movement animation (or less) => use default graphic
7165 for last (8th) frame which ends the movement animation */
7166 if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
7168 effective_action = ACTION_DEFAULT;
7169 graphic = (direction == MV_NONE ?
7170 el_act2img(effective_element, effective_action) :
7171 el_act_dir2img(effective_element, effective_action,
7173 crumbled = (direction == MV_NONE ?
7174 el_act2crm(effective_element, effective_action) :
7175 el_act_dir2crm(effective_element, effective_action,
7178 g = &graphic_info[graphic];
7181 if (graphic_info[graphic].anim_global_sync)
7182 sync_frame = FrameCounter;
7183 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
7184 sync_frame = GfxFrame[x][y];
7186 sync_frame = 0; /* playfield border (pseudo steel) */
7188 SetRandomAnimationValue(x, y);
7190 int frame = getAnimationFrame(g->anim_frames,
7193 g->anim_start_frame,
7196 getGraphicSourceExt(graphic, frame, &g_em->bitmap, &g_em->src_x, &g_em->src_y,
7197 g->double_movement && is_backside);
7199 /* (updating the "crumbled" graphic definitions is probably not really needed,
7200 as animations for crumbled graphics can't be longer than one EMC cycle) */
7201 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
7205 void getGraphicSourcePlayerExt_EM(struct GraphicInfo_EM *g_em,
7206 int player_nr, int anim, int frame_em)
7208 int element = player_mapping[player_nr][anim].element_rnd;
7209 int action = player_mapping[player_nr][anim].action;
7210 int direction = player_mapping[player_nr][anim].direction;
7211 int graphic = (direction == MV_NONE ?
7212 el_act2img(element, action) :
7213 el_act_dir2img(element, action, direction));
7214 struct GraphicInfo *g = &graphic_info[graphic];
7217 InitPlayerGfxAnimation(&stored_player[player_nr], action, direction);
7219 stored_player[player_nr].StepFrame = frame_em;
7221 sync_frame = stored_player[player_nr].Frame;
7223 int frame = getAnimationFrame(g->anim_frames,
7226 g->anim_start_frame,
7229 getGraphicSourceExt(graphic, frame, &g_em->bitmap,
7230 &g_em->src_x, &g_em->src_y, FALSE);
7233 void InitGraphicInfo_EM(void)
7238 int num_em_gfx_errors = 0;
7240 if (graphic_info_em_object[0][0].bitmap == NULL)
7242 /* EM graphics not yet initialized in em_open_all() */
7247 printf("::: [4 errors can be ignored (1 x 'bomb', 3 x 'em_dynamite']\n");
7250 /* always start with reliable default values */
7251 for (i = 0; i < TILE_MAX; i++)
7253 object_mapping[i].element_rnd = EL_UNKNOWN;
7254 object_mapping[i].is_backside = FALSE;
7255 object_mapping[i].action = ACTION_DEFAULT;
7256 object_mapping[i].direction = MV_NONE;
7259 /* always start with reliable default values */
7260 for (p = 0; p < MAX_PLAYERS; p++)
7262 for (i = 0; i < SPR_MAX; i++)
7264 player_mapping[p][i].element_rnd = EL_UNKNOWN;
7265 player_mapping[p][i].action = ACTION_DEFAULT;
7266 player_mapping[p][i].direction = MV_NONE;
7270 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
7272 int e = em_object_mapping_list[i].element_em;
7274 object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd;
7275 object_mapping[e].is_backside = em_object_mapping_list[i].is_backside;
7277 if (em_object_mapping_list[i].action != -1)
7278 object_mapping[e].action = em_object_mapping_list[i].action;
7280 if (em_object_mapping_list[i].direction != -1)
7281 object_mapping[e].direction =
7282 MV_DIR_FROM_BIT(em_object_mapping_list[i].direction);
7285 for (i = 0; em_player_mapping_list[i].action_em != -1; i++)
7287 int a = em_player_mapping_list[i].action_em;
7288 int p = em_player_mapping_list[i].player_nr;
7290 player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd;
7292 if (em_player_mapping_list[i].action != -1)
7293 player_mapping[p][a].action = em_player_mapping_list[i].action;
7295 if (em_player_mapping_list[i].direction != -1)
7296 player_mapping[p][a].direction =
7297 MV_DIR_FROM_BIT(em_player_mapping_list[i].direction);
7300 for (i = 0; i < TILE_MAX; i++)
7302 int element = object_mapping[i].element_rnd;
7303 int action = object_mapping[i].action;
7304 int direction = object_mapping[i].direction;
7305 boolean is_backside = object_mapping[i].is_backside;
7306 boolean action_exploding = ((action == ACTION_EXPLODING ||
7307 action == ACTION_SMASHED_BY_ROCK ||
7308 action == ACTION_SMASHED_BY_SPRING) &&
7309 element != EL_DIAMOND);
7310 boolean action_active = (action == ACTION_ACTIVE);
7311 boolean action_other = (action == ACTION_OTHER);
7313 for (j = 0; j < 8; j++)
7315 int effective_element = get_effective_element_EM(i, j);
7316 int effective_action = (j < 7 ? action :
7317 i == Xdrip_stretch ? action :
7318 i == Xdrip_stretchB ? action :
7319 i == Ydrip_s1 ? action :
7320 i == Ydrip_s1B ? action :
7321 i == Xball_1B ? action :
7322 i == Xball_2 ? action :
7323 i == Xball_2B ? action :
7324 i == Yball_eat ? action :
7325 i == Ykey_1_eat ? action :
7326 i == Ykey_2_eat ? action :
7327 i == Ykey_3_eat ? action :
7328 i == Ykey_4_eat ? action :
7329 i == Ykey_5_eat ? action :
7330 i == Ykey_6_eat ? action :
7331 i == Ykey_7_eat ? action :
7332 i == Ykey_8_eat ? action :
7333 i == Ylenses_eat ? action :
7334 i == Ymagnify_eat ? action :
7335 i == Ygrass_eat ? action :
7336 i == Ydirt_eat ? action :
7337 i == Xsand_stonein_1 ? action :
7338 i == Xsand_stonein_2 ? action :
7339 i == Xsand_stonein_3 ? action :
7340 i == Xsand_stonein_4 ? action :
7341 i == Xsand_stoneout_1 ? action :
7342 i == Xsand_stoneout_2 ? action :
7343 i == Xboom_android ? ACTION_EXPLODING :
7344 action_exploding ? ACTION_EXPLODING :
7345 action_active ? action :
7346 action_other ? action :
7348 int graphic = (el_act_dir2img(effective_element, effective_action,
7350 int crumbled = (el_act_dir2crm(effective_element, effective_action,
7352 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
7353 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
7354 boolean has_action_graphics = (graphic != base_graphic);
7355 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
7356 struct GraphicInfo *g = &graphic_info[graphic];
7357 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
7360 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
7361 boolean special_animation = (action != ACTION_DEFAULT &&
7362 g->anim_frames == 3 &&
7363 g->anim_delay == 2 &&
7364 g->anim_mode & ANIM_LINEAR);
7365 int sync_frame = (i == Xdrip_stretch ? 7 :
7366 i == Xdrip_stretchB ? 7 :
7367 i == Ydrip_s2 ? j + 8 :
7368 i == Ydrip_s2B ? j + 8 :
7377 i == Xfake_acid_1 ? 0 :
7378 i == Xfake_acid_2 ? 10 :
7379 i == Xfake_acid_3 ? 20 :
7380 i == Xfake_acid_4 ? 30 :
7381 i == Xfake_acid_5 ? 40 :
7382 i == Xfake_acid_6 ? 50 :
7383 i == Xfake_acid_7 ? 60 :
7384 i == Xfake_acid_8 ? 70 :
7386 i == Xball_2B ? j + 8 :
7387 i == Yball_eat ? j + 1 :
7388 i == Ykey_1_eat ? j + 1 :
7389 i == Ykey_2_eat ? j + 1 :
7390 i == Ykey_3_eat ? j + 1 :
7391 i == Ykey_4_eat ? j + 1 :
7392 i == Ykey_5_eat ? j + 1 :
7393 i == Ykey_6_eat ? j + 1 :
7394 i == Ykey_7_eat ? j + 1 :
7395 i == Ykey_8_eat ? j + 1 :
7396 i == Ylenses_eat ? j + 1 :
7397 i == Ymagnify_eat ? j + 1 :
7398 i == Ygrass_eat ? j + 1 :
7399 i == Ydirt_eat ? j + 1 :
7400 i == Xamoeba_1 ? 0 :
7401 i == Xamoeba_2 ? 1 :
7402 i == Xamoeba_3 ? 2 :
7403 i == Xamoeba_4 ? 3 :
7404 i == Xamoeba_5 ? 0 :
7405 i == Xamoeba_6 ? 1 :
7406 i == Xamoeba_7 ? 2 :
7407 i == Xamoeba_8 ? 3 :
7408 i == Xexit_2 ? j + 8 :
7409 i == Xexit_3 ? j + 16 :
7410 i == Xdynamite_1 ? 0 :
7411 i == Xdynamite_2 ? 8 :
7412 i == Xdynamite_3 ? 16 :
7413 i == Xdynamite_4 ? 24 :
7414 i == Xsand_stonein_1 ? j + 1 :
7415 i == Xsand_stonein_2 ? j + 9 :
7416 i == Xsand_stonein_3 ? j + 17 :
7417 i == Xsand_stonein_4 ? j + 25 :
7418 i == Xsand_stoneout_1 && j == 0 ? 0 :
7419 i == Xsand_stoneout_1 && j == 1 ? 0 :
7420 i == Xsand_stoneout_1 && j == 2 ? 1 :
7421 i == Xsand_stoneout_1 && j == 3 ? 2 :
7422 i == Xsand_stoneout_1 && j == 4 ? 2 :
7423 i == Xsand_stoneout_1 && j == 5 ? 3 :
7424 i == Xsand_stoneout_1 && j == 6 ? 4 :
7425 i == Xsand_stoneout_1 && j == 7 ? 4 :
7426 i == Xsand_stoneout_2 && j == 0 ? 5 :
7427 i == Xsand_stoneout_2 && j == 1 ? 6 :
7428 i == Xsand_stoneout_2 && j == 2 ? 7 :
7429 i == Xsand_stoneout_2 && j == 3 ? 8 :
7430 i == Xsand_stoneout_2 && j == 4 ? 9 :
7431 i == Xsand_stoneout_2 && j == 5 ? 11 :
7432 i == Xsand_stoneout_2 && j == 6 ? 13 :
7433 i == Xsand_stoneout_2 && j == 7 ? 15 :
7434 i == Xboom_bug && j == 1 ? 2 :
7435 i == Xboom_bug && j == 2 ? 2 :
7436 i == Xboom_bug && j == 3 ? 4 :
7437 i == Xboom_bug && j == 4 ? 4 :
7438 i == Xboom_bug && j == 5 ? 2 :
7439 i == Xboom_bug && j == 6 ? 2 :
7440 i == Xboom_bug && j == 7 ? 0 :
7441 i == Xboom_bomb && j == 1 ? 2 :
7442 i == Xboom_bomb && j == 2 ? 2 :
7443 i == Xboom_bomb && j == 3 ? 4 :
7444 i == Xboom_bomb && j == 4 ? 4 :
7445 i == Xboom_bomb && j == 5 ? 2 :
7446 i == Xboom_bomb && j == 6 ? 2 :
7447 i == Xboom_bomb && j == 7 ? 0 :
7448 i == Xboom_android && j == 7 ? 6 :
7449 i == Xboom_1 && j == 1 ? 2 :
7450 i == Xboom_1 && j == 2 ? 2 :
7451 i == Xboom_1 && j == 3 ? 4 :
7452 i == Xboom_1 && j == 4 ? 4 :
7453 i == Xboom_1 && j == 5 ? 6 :
7454 i == Xboom_1 && j == 6 ? 6 :
7455 i == Xboom_1 && j == 7 ? 8 :
7456 i == Xboom_2 && j == 0 ? 8 :
7457 i == Xboom_2 && j == 1 ? 8 :
7458 i == Xboom_2 && j == 2 ? 10 :
7459 i == Xboom_2 && j == 3 ? 10 :
7460 i == Xboom_2 && j == 4 ? 10 :
7461 i == Xboom_2 && j == 5 ? 12 :
7462 i == Xboom_2 && j == 6 ? 12 :
7463 i == Xboom_2 && j == 7 ? 12 :
7464 special_animation && j == 4 ? 3 :
7465 effective_action != action ? 0 :
7469 Bitmap *debug_bitmap = g_em->bitmap;
7470 int debug_src_x = g_em->src_x;
7471 int debug_src_y = g_em->src_y;
7474 int frame = getAnimationFrame(g->anim_frames,
7477 g->anim_start_frame,
7480 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y,
7481 g->double_movement && is_backside);
7483 g_em->bitmap = src_bitmap;
7484 g_em->src_x = src_x;
7485 g_em->src_y = src_y;
7486 g_em->src_offset_x = 0;
7487 g_em->src_offset_y = 0;
7488 g_em->dst_offset_x = 0;
7489 g_em->dst_offset_y = 0;
7490 g_em->width = TILEX;
7491 g_em->height = TILEY;
7493 g_em->preserve_background = FALSE;
7495 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
7498 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
7499 effective_action == ACTION_MOVING ||
7500 effective_action == ACTION_PUSHING ||
7501 effective_action == ACTION_EATING)) ||
7502 (!has_action_graphics && (effective_action == ACTION_FILLING ||
7503 effective_action == ACTION_EMPTYING)))
7506 (effective_action == ACTION_FALLING ||
7507 effective_action == ACTION_FILLING ||
7508 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
7509 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
7510 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
7511 int num_steps = (i == Ydrip_s1 ? 16 :
7512 i == Ydrip_s1B ? 16 :
7513 i == Ydrip_s2 ? 16 :
7514 i == Ydrip_s2B ? 16 :
7515 i == Xsand_stonein_1 ? 32 :
7516 i == Xsand_stonein_2 ? 32 :
7517 i == Xsand_stonein_3 ? 32 :
7518 i == Xsand_stonein_4 ? 32 :
7519 i == Xsand_stoneout_1 ? 16 :
7520 i == Xsand_stoneout_2 ? 16 : 8);
7521 int cx = ABS(dx) * (TILEX / num_steps);
7522 int cy = ABS(dy) * (TILEY / num_steps);
7523 int step_frame = (i == Ydrip_s2 ? j + 8 :
7524 i == Ydrip_s2B ? j + 8 :
7525 i == Xsand_stonein_2 ? j + 8 :
7526 i == Xsand_stonein_3 ? j + 16 :
7527 i == Xsand_stonein_4 ? j + 24 :
7528 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
7529 int step = (is_backside ? step_frame : num_steps - step_frame);
7531 if (is_backside) /* tile where movement starts */
7533 if (dx < 0 || dy < 0)
7535 g_em->src_offset_x = cx * step;
7536 g_em->src_offset_y = cy * step;
7540 g_em->dst_offset_x = cx * step;
7541 g_em->dst_offset_y = cy * step;
7544 else /* tile where movement ends */
7546 if (dx < 0 || dy < 0)
7548 g_em->dst_offset_x = cx * step;
7549 g_em->dst_offset_y = cy * step;
7553 g_em->src_offset_x = cx * step;
7554 g_em->src_offset_y = cy * step;
7558 g_em->width = TILEX - cx * step;
7559 g_em->height = TILEY - cy * step;
7562 /* create unique graphic identifier to decide if tile must be redrawn */
7563 /* bit 31 - 16 (16 bit): EM style graphic
7564 bit 15 - 12 ( 4 bit): EM style frame
7565 bit 11 - 6 ( 6 bit): graphic width
7566 bit 5 - 0 ( 6 bit): graphic height */
7567 g_em->unique_identifier =
7568 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
7572 /* skip check for EMC elements not contained in original EMC artwork */
7573 if (element == EL_EMC_FAKE_ACID)
7576 if (g_em->bitmap != debug_bitmap ||
7577 g_em->src_x != debug_src_x ||
7578 g_em->src_y != debug_src_y ||
7579 g_em->src_offset_x != 0 ||
7580 g_em->src_offset_y != 0 ||
7581 g_em->dst_offset_x != 0 ||
7582 g_em->dst_offset_y != 0 ||
7583 g_em->width != TILEX ||
7584 g_em->height != TILEY)
7586 static int last_i = -1;
7594 printf("::: EMC GFX ERROR for element %d -> %d ('%s', '%s', %d)",
7595 i, element, element_info[element].token_name,
7596 element_action_info[effective_action].suffix, direction);
7598 if (element != effective_element)
7599 printf(" [%d ('%s')]",
7601 element_info[effective_element].token_name);
7605 if (g_em->bitmap != debug_bitmap)
7606 printf(" %d (%d): different bitmap! (0x%08x != 0x%08x)\n",
7607 j, is_backside, (int)(g_em->bitmap), (int)(debug_bitmap));
7609 if (g_em->src_x != debug_src_x ||
7610 g_em->src_y != debug_src_y)
7611 printf(" frame %d (%c): %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
7612 j, (is_backside ? 'B' : 'F'),
7613 g_em->src_x, g_em->src_y,
7614 g_em->src_x / 32, g_em->src_y / 32,
7615 debug_src_x, debug_src_y,
7616 debug_src_x / 32, debug_src_y / 32);
7618 if (g_em->src_offset_x != 0 ||
7619 g_em->src_offset_y != 0 ||
7620 g_em->dst_offset_x != 0 ||
7621 g_em->dst_offset_y != 0)
7622 printf(" %d (%d): offsets %d,%d and %d,%d should be all 0\n",
7624 g_em->src_offset_x, g_em->src_offset_y,
7625 g_em->dst_offset_x, g_em->dst_offset_y);
7627 if (g_em->width != TILEX ||
7628 g_em->height != TILEY)
7629 printf(" %d (%d): size %d,%d should be %d,%d\n",
7631 g_em->width, g_em->height, TILEX, TILEY);
7633 num_em_gfx_errors++;
7640 for (i = 0; i < TILE_MAX; i++)
7642 for (j = 0; j < 8; j++)
7644 int element = object_mapping[i].element_rnd;
7645 int action = object_mapping[i].action;
7646 int direction = object_mapping[i].direction;
7647 boolean is_backside = object_mapping[i].is_backside;
7648 int graphic_action = el_act_dir2img(element, action, direction);
7649 int graphic_default = el_act_dir2img(element, ACTION_DEFAULT, direction);
7651 if ((action == ACTION_SMASHED_BY_ROCK ||
7652 action == ACTION_SMASHED_BY_SPRING ||
7653 action == ACTION_EATING) &&
7654 graphic_action == graphic_default)
7656 int e = (action == ACTION_SMASHED_BY_ROCK ? Ystone_s :
7657 action == ACTION_SMASHED_BY_SPRING ? Yspring_s :
7658 direction == MV_LEFT ? (is_backside? Yspring_wB: Yspring_w) :
7659 direction == MV_RIGHT ? (is_backside? Yspring_eB: Yspring_e) :
7662 /* no separate animation for "smashed by rock" -- use rock instead */
7663 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
7664 struct GraphicInfo_EM *g_xx = &graphic_info_em_object[e][7 - j];
7666 g_em->bitmap = g_xx->bitmap;
7667 g_em->src_x = g_xx->src_x;
7668 g_em->src_y = g_xx->src_y;
7669 g_em->src_offset_x = g_xx->src_offset_x;
7670 g_em->src_offset_y = g_xx->src_offset_y;
7671 g_em->dst_offset_x = g_xx->dst_offset_x;
7672 g_em->dst_offset_y = g_xx->dst_offset_y;
7673 g_em->width = g_xx->width;
7674 g_em->height = g_xx->height;
7675 g_em->unique_identifier = g_xx->unique_identifier;
7678 g_em->preserve_background = TRUE;
7683 for (p = 0; p < MAX_PLAYERS; p++)
7685 for (i = 0; i < SPR_MAX; i++)
7687 int element = player_mapping[p][i].element_rnd;
7688 int action = player_mapping[p][i].action;
7689 int direction = player_mapping[p][i].direction;
7691 for (j = 0; j < 8; j++)
7693 int effective_element = element;
7694 int effective_action = action;
7695 int graphic = (direction == MV_NONE ?
7696 el_act2img(effective_element, effective_action) :
7697 el_act_dir2img(effective_element, effective_action,
7699 struct GraphicInfo *g = &graphic_info[graphic];
7700 struct GraphicInfo_EM *g_em = &graphic_info_em_player[p][i][7 - j];
7706 Bitmap *debug_bitmap = g_em->bitmap;
7707 int debug_src_x = g_em->src_x;
7708 int debug_src_y = g_em->src_y;
7711 int frame = getAnimationFrame(g->anim_frames,
7714 g->anim_start_frame,
7717 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
7719 g_em->bitmap = src_bitmap;
7720 g_em->src_x = src_x;
7721 g_em->src_y = src_y;
7722 g_em->src_offset_x = 0;
7723 g_em->src_offset_y = 0;
7724 g_em->dst_offset_x = 0;
7725 g_em->dst_offset_y = 0;
7726 g_em->width = TILEX;
7727 g_em->height = TILEY;
7731 /* skip check for EMC elements not contained in original EMC artwork */
7732 if (element == EL_PLAYER_3 ||
7733 element == EL_PLAYER_4)
7736 if (g_em->bitmap != debug_bitmap ||
7737 g_em->src_x != debug_src_x ||
7738 g_em->src_y != debug_src_y)
7740 static int last_i = -1;
7748 printf("::: EMC GFX ERROR for p/a %d/%d -> %d ('%s', '%s', %d)",
7749 p, i, element, element_info[element].token_name,
7750 element_action_info[effective_action].suffix, direction);
7752 if (element != effective_element)
7753 printf(" [%d ('%s')]",
7755 element_info[effective_element].token_name);
7759 if (g_em->bitmap != debug_bitmap)
7760 printf(" %d: different bitmap! (0x%08x != 0x%08x)\n",
7761 j, (int)(g_em->bitmap), (int)(debug_bitmap));
7763 if (g_em->src_x != debug_src_x ||
7764 g_em->src_y != debug_src_y)
7765 printf(" frame %d: %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
7767 g_em->src_x, g_em->src_y,
7768 g_em->src_x / 32, g_em->src_y / 32,
7769 debug_src_x, debug_src_y,
7770 debug_src_x / 32, debug_src_y / 32);
7772 num_em_gfx_errors++;
7782 printf("::: [%d errors found]\n", num_em_gfx_errors);
7788 void CheckSingleStepMode_EM(byte action[MAX_PLAYERS], int frame,
7789 boolean any_player_moving,
7790 boolean player_is_dropping)
7792 if (tape.single_step && tape.recording && !tape.pausing)
7793 if (frame == 0 && !player_is_dropping)
7794 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
7797 void CheckSingleStepMode_SP(boolean murphy_is_waiting,
7798 boolean murphy_is_dropping)
7800 if (tape.single_step && tape.recording && !tape.pausing)
7801 if (murphy_is_waiting)
7802 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
7805 void getGraphicSource_SP(struct GraphicInfo_SP *g_sp,
7806 int graphic, int sync_frame, int x, int y)
7808 int frame = getGraphicAnimationFrame(graphic, sync_frame);
7810 getGraphicSource(graphic, frame, &g_sp->bitmap, &g_sp->src_x, &g_sp->src_y);
7813 boolean isNextAnimationFrame_SP(int graphic, int sync_frame)
7815 return (IS_NEXT_FRAME(sync_frame, graphic));
7818 int getGraphicInfo_Delay(int graphic)
7820 return graphic_info[graphic].anim_delay;
7823 void PlayMenuSoundExt(int sound)
7825 if (sound == SND_UNDEFINED)
7828 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
7829 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
7832 if (IS_LOOP_SOUND(sound))
7833 PlaySoundLoop(sound);
7838 void PlayMenuSound()
7840 PlayMenuSoundExt(menu.sound[game_status]);
7843 void PlayMenuSoundStereo(int sound, int stereo_position)
7845 if (sound == SND_UNDEFINED)
7848 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
7849 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
7852 if (IS_LOOP_SOUND(sound))
7853 PlaySoundExt(sound, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_LOOP);
7855 PlaySoundStereo(sound, stereo_position);
7858 void PlayMenuSoundIfLoopExt(int sound)
7860 if (sound == SND_UNDEFINED)
7863 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
7864 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
7867 if (IS_LOOP_SOUND(sound))
7868 PlaySoundLoop(sound);
7871 void PlayMenuSoundIfLoop()
7873 PlayMenuSoundIfLoopExt(menu.sound[game_status]);
7876 void PlayMenuMusicExt(int music)
7878 if (music == MUS_UNDEFINED)
7881 if (!setup.sound_music)
7887 void PlayMenuMusic()
7889 PlayMenuMusicExt(menu.music[game_status]);
7892 void PlaySoundActivating()
7895 PlaySound(SND_MENU_ITEM_ACTIVATING);
7899 void PlaySoundSelecting()
7902 PlaySound(SND_MENU_ITEM_SELECTING);
7906 void ToggleFullscreenOrChangeWindowScalingIfNeeded()
7908 boolean change_fullscreen = (setup.fullscreen !=
7909 video.fullscreen_enabled);
7910 boolean change_fullscreen_mode = (video.fullscreen_enabled &&
7911 !strEqual(setup.fullscreen_mode,
7912 video.fullscreen_mode_current));
7913 boolean change_window_scaling_percent = (!video.fullscreen_enabled &&
7914 setup.window_scaling_percent !=
7915 video.window_scaling_percent);
7917 if (change_window_scaling_percent && video.fullscreen_enabled)
7920 if (!change_window_scaling_percent && !video.fullscreen_available)
7923 #if defined(TARGET_SDL2)
7924 if (change_window_scaling_percent)
7926 SDLSetWindowScaling(setup.window_scaling_percent);
7930 else if (change_fullscreen)
7932 SDLSetWindowFullscreen(setup.fullscreen);
7934 /* set setup value according to successfully changed fullscreen mode */
7935 setup.fullscreen = video.fullscreen_enabled;
7941 if (change_fullscreen ||
7942 change_fullscreen_mode ||
7943 change_window_scaling_percent)
7945 Bitmap *tmp_backbuffer = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
7947 /* save backbuffer content which gets lost when toggling fullscreen mode */
7948 BlitBitmap(backbuffer, tmp_backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
7950 if (change_fullscreen_mode)
7952 /* keep fullscreen, but change fullscreen mode (screen resolution) */
7953 video.fullscreen_enabled = FALSE; /* force new fullscreen mode */
7956 if (change_window_scaling_percent)
7958 /* keep window mode, but change window scaling */
7959 video.fullscreen_enabled = TRUE; /* force new window scaling */
7962 /* toggle fullscreen */
7963 ChangeVideoModeIfNeeded(setup.fullscreen);
7965 /* set setup value according to successfully changed fullscreen mode */
7966 setup.fullscreen = video.fullscreen_enabled;
7968 /* restore backbuffer content from temporary backbuffer backup bitmap */
7969 BlitBitmap(tmp_backbuffer, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
7971 FreeBitmap(tmp_backbuffer);
7973 /* update visible window/screen */
7974 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
7978 void ChangeViewportPropertiesIfNeeded()
7980 int gfx_game_mode = game_status;
7981 int gfx_game_mode2 = (game_status == GAME_MODE_EDITOR ? GAME_MODE_DEFAULT :
7983 struct RectWithBorder *vp_playfield = &viewport.playfield[gfx_game_mode];
7984 struct RectWithBorder *vp_door_1 = &viewport.door_1[gfx_game_mode];
7985 struct RectWithBorder *vp_door_2 = &viewport.door_2[gfx_game_mode2];
7986 struct RectWithBorder *vp_door_3 = &viewport.door_2[GAME_MODE_EDITOR];
7987 int border_size = vp_playfield->border_size;
7988 int new_sx = vp_playfield->x + border_size;
7989 int new_sy = vp_playfield->y + border_size;
7990 int new_sxsize = vp_playfield->width - 2 * border_size;
7991 int new_sysize = vp_playfield->height - 2 * border_size;
7992 int new_real_sx = vp_playfield->x;
7993 int new_real_sy = vp_playfield->y;
7994 int new_full_sxsize = vp_playfield->width;
7995 int new_full_sysize = vp_playfield->height;
7996 int new_dx = vp_door_1->x;
7997 int new_dy = vp_door_1->y;
7998 int new_dxsize = vp_door_1->width;
7999 int new_dysize = vp_door_1->height;
8000 int new_vx = vp_door_2->x;
8001 int new_vy = vp_door_2->y;
8002 int new_vxsize = vp_door_2->width;
8003 int new_vysize = vp_door_2->height;
8004 int new_ex = vp_door_3->x;
8005 int new_ey = vp_door_3->y;
8006 int new_exsize = vp_door_3->width;
8007 int new_eysize = vp_door_3->height;
8008 int new_tilesize_var =
8009 (setup.small_game_graphics ? MINI_TILESIZE : game.tile_size);
8011 int tilesize = (gfx_game_mode == GAME_MODE_PLAYING ? new_tilesize_var :
8012 gfx_game_mode == GAME_MODE_EDITOR ? MINI_TILESIZE : TILESIZE);
8013 int new_scr_fieldx = new_sxsize / tilesize;
8014 int new_scr_fieldy = new_sysize / tilesize;
8015 int new_scr_fieldx_buffers = new_sxsize / new_tilesize_var;
8016 int new_scr_fieldy_buffers = new_sysize / new_tilesize_var;
8017 boolean init_gfx_buffers = FALSE;
8018 boolean init_video_buffer = FALSE;
8019 boolean init_gadgets_and_toons = FALSE;
8020 boolean init_em_graphics = FALSE;
8022 if (viewport.window.width != WIN_XSIZE ||
8023 viewport.window.height != WIN_YSIZE)
8025 WIN_XSIZE = viewport.window.width;
8026 WIN_YSIZE = viewport.window.height;
8028 init_video_buffer = TRUE;
8029 init_gfx_buffers = TRUE;
8031 // printf("::: video: init_video_buffer, init_gfx_buffers\n");
8034 if (new_scr_fieldx != SCR_FIELDX ||
8035 new_scr_fieldy != SCR_FIELDY)
8037 /* this always toggles between MAIN and GAME when using small tile size */
8039 SCR_FIELDX = new_scr_fieldx;
8040 SCR_FIELDY = new_scr_fieldy;
8042 // printf("::: new_scr_fieldx != SCR_FIELDX ...\n");
8053 new_sxsize != SXSIZE ||
8054 new_sysize != SYSIZE ||
8055 new_dxsize != DXSIZE ||
8056 new_dysize != DYSIZE ||
8057 new_vxsize != VXSIZE ||
8058 new_vysize != VYSIZE ||
8059 new_exsize != EXSIZE ||
8060 new_eysize != EYSIZE ||
8061 new_real_sx != REAL_SX ||
8062 new_real_sy != REAL_SY ||
8063 new_full_sxsize != FULL_SXSIZE ||
8064 new_full_sysize != FULL_SYSIZE ||
8065 new_tilesize_var != TILESIZE_VAR
8068 if (new_tilesize_var != TILESIZE_VAR)
8070 // printf("::: new_tilesize_var != TILESIZE_VAR\n");
8072 // changing tile size invalidates scroll values of engine snapshots
8073 FreeEngineSnapshot();
8075 // changing tile size requires update of graphic mapping for EM engine
8076 init_em_graphics = TRUE;
8087 SXSIZE = new_sxsize;
8088 SYSIZE = new_sysize;
8089 DXSIZE = new_dxsize;
8090 DYSIZE = new_dysize;
8091 VXSIZE = new_vxsize;
8092 VYSIZE = new_vysize;
8093 EXSIZE = new_exsize;
8094 EYSIZE = new_eysize;
8095 REAL_SX = new_real_sx;
8096 REAL_SY = new_real_sy;
8097 FULL_SXSIZE = new_full_sxsize;
8098 FULL_SYSIZE = new_full_sysize;
8099 TILESIZE_VAR = new_tilesize_var;
8101 init_gfx_buffers = TRUE;
8102 init_gadgets_and_toons = TRUE;
8104 // printf("::: viewports: init_gfx_buffers\n");
8105 // printf("::: viewports: init_gadgets_and_toons\n");
8108 if (init_gfx_buffers)
8110 // printf("::: init_gfx_buffers\n");
8112 SCR_FIELDX = new_scr_fieldx_buffers;
8113 SCR_FIELDY = new_scr_fieldy_buffers;
8117 SCR_FIELDX = new_scr_fieldx;
8118 SCR_FIELDY = new_scr_fieldy;
8121 if (init_video_buffer)
8123 // printf("::: init_video_buffer\n");
8125 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
8127 SetDrawDeactivationMask(REDRAW_NONE);
8128 SetDrawBackgroundMask(REDRAW_FIELD);
8131 if (init_gadgets_and_toons)
8133 // printf("::: init_gadgets_and_toons\n");
8139 if (init_em_graphics)
8141 InitGraphicInfo_EM();