1 /***********************************************************
2 * Rocks'n'Diamonds -- McDuffin Strikes Back! *
3 *----------------------------------------------------------*
4 * (c) 1995-2006 Artsoft Entertainment *
6 * Detmolder Strasse 189 *
9 * e-mail: info@artsoft.org *
10 *----------------------------------------------------------*
12 ***********************************************************/
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 /* forward declaration for internal use */
41 static void UnmapToolButtons();
42 static void HandleToolButtons(struct GadgetInfo *);
43 static int el_act_dir2crm(int, int, int);
44 static int el_act2crm(int, int);
46 static struct GadgetInfo *tool_gadget[NUM_TOOL_BUTTONS];
47 static int request_gadget_id = -1;
49 static char *print_if_not_empty(int element)
51 static char *s = NULL;
52 char *token_name = element_info[element].token_name;
57 s = checked_malloc(strlen(token_name) + 10 + 1);
59 if (element != EL_EMPTY)
60 sprintf(s, "%d\t['%s']", element, token_name);
62 sprintf(s, "%d", element);
67 void DumpTile(int x, int y)
72 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
79 printf("Field Info: SCREEN(%d, %d), LEVEL(%d, %d)\n", sx, sy, x, y);
82 if (!IN_LEV_FIELD(x, y))
84 printf("(not in level field)\n");
90 printf(" Feld: %d\t['%s']\n", Feld[x][y],
91 element_info[Feld[x][y]].token_name);
92 printf(" Back: %s\n", print_if_not_empty(Back[x][y]));
93 printf(" Store: %s\n", print_if_not_empty(Store[x][y]));
94 printf(" Store2: %s\n", print_if_not_empty(Store2[x][y]));
95 printf(" StorePlayer: %s\n", print_if_not_empty(StorePlayer[x][y]));
96 printf(" MovPos: %d\n", MovPos[x][y]);
97 printf(" MovDir: %d\n", MovDir[x][y]);
98 printf(" MovDelay: %d\n", MovDelay[x][y]);
99 printf(" ChangeDelay: %d\n", ChangeDelay[x][y]);
100 printf(" CustomValue: %d\n", CustomValue[x][y]);
101 printf(" GfxElement: %d\n", GfxElement[x][y]);
102 printf(" GfxAction: %d\n", GfxAction[x][y]);
103 printf(" GfxFrame: %d\n", GfxFrame[x][y]);
107 void SetDrawtoField(int mode)
109 if (mode == DRAW_BUFFERED && setup.soft_scrolling)
116 BX2 = SCR_FIELDX + 1;
117 BY2 = SCR_FIELDY + 1;
131 drawto_field = fieldbuffer;
133 else /* DRAW_BACKBUFFER */
139 BX2 = SCR_FIELDX - 1;
140 BY2 = SCR_FIELDY - 1;
144 drawto_field = backbuffer;
148 void RedrawPlayfield(boolean force_redraw, int x, int y, int width, int height)
150 if (game_status == GAME_MODE_PLAYING &&
151 level.game_engine_type == GAME_ENGINE_TYPE_EM)
153 /* currently there is no partial redraw -- always redraw whole playfield */
154 RedrawPlayfield_EM(TRUE);
156 /* blit playfield from scroll buffer to normal back buffer for fading in */
157 BlitScreenToBitmap_EM(backbuffer);
159 else if (game_status == GAME_MODE_PLAYING &&
160 level.game_engine_type == GAME_ENGINE_TYPE_SP)
162 /* currently there is no partial redraw -- always redraw whole playfield */
163 RedrawPlayfield_SP(TRUE);
165 /* blit playfield from scroll buffer to normal back buffer for fading in */
166 BlitScreenToBitmap_SP(backbuffer);
168 else if (game_status == GAME_MODE_PLAYING &&
169 !game.envelope_active)
175 width = gfx.sxsize + 2 * TILEX;
176 height = gfx.sysize + 2 * TILEY;
182 int x1 = (x - SX) / TILEX, y1 = (y - SY) / TILEY;
183 int x2 = (x - SX + width) / TILEX, y2 = (y - SY + height) / TILEY;
185 for (xx = BX1; xx <= BX2; xx++)
186 for (yy = BY1; yy <= BY2; yy++)
187 if (xx >= x1 && xx <= x2 && yy >= y1 && yy <= y2)
188 DrawScreenField(xx, yy);
192 if (setup.soft_scrolling)
194 int fx = FX, fy = FY;
196 fx += (ScreenMovDir & (MV_LEFT|MV_RIGHT) ? ScreenGfxPos : 0);
197 fy += (ScreenMovDir & (MV_UP|MV_DOWN) ? ScreenGfxPos : 0);
199 BlitBitmap(fieldbuffer, backbuffer, fx,fy, SXSIZE,SYSIZE, SX,SY);
211 BlitBitmap(drawto, window, x, y, width, height, x, y);
214 void DrawMaskedBorder_Rect(int x, int y, int width, int height)
216 Bitmap *bitmap = graphic_info[IMG_GLOBAL_BORDER].bitmap;
218 SetClipOrigin(bitmap, bitmap->stored_clip_gc, 0, 0);
219 BlitBitmapMasked(bitmap, backbuffer, x, y, width, height, x, y);
222 void DrawMaskedBorder_FIELD()
224 if (global.border_status >= GAME_MODE_TITLE &&
225 global.border_status <= GAME_MODE_PLAYING &&
226 border.draw_masked[global.border_status])
227 DrawMaskedBorder_Rect(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
230 void DrawMaskedBorder_DOOR_1()
232 if (border.draw_masked[GFX_SPECIAL_ARG_DOOR] &&
233 (global.border_status != GAME_MODE_EDITOR ||
234 border.draw_masked[GFX_SPECIAL_ARG_EDITOR]))
235 DrawMaskedBorder_Rect(DX, DY, DXSIZE, DYSIZE);
238 void DrawMaskedBorder_DOOR_2()
240 if (border.draw_masked[GFX_SPECIAL_ARG_DOOR] &&
241 global.border_status != GAME_MODE_EDITOR)
242 DrawMaskedBorder_Rect(VX, VY, VXSIZE, VYSIZE);
245 void DrawMaskedBorder_DOOR_3()
247 /* currently not available */
250 void DrawMaskedBorder_ALL()
252 DrawMaskedBorder_FIELD();
253 DrawMaskedBorder_DOOR_1();
254 DrawMaskedBorder_DOOR_2();
255 DrawMaskedBorder_DOOR_3();
258 void DrawMaskedBorder(int redraw_mask)
260 /* never draw masked screen borders on borderless screens */
261 if (effectiveGameStatus() == GAME_MODE_LOADING ||
262 effectiveGameStatus() == GAME_MODE_TITLE)
265 /* never draw masked screen borders when displaying request outside door */
266 if (effectiveGameStatus() == GAME_MODE_PSEUDO_DOOR &&
267 global.use_envelope_request)
270 if (redraw_mask & REDRAW_ALL)
271 DrawMaskedBorder_ALL();
274 if (redraw_mask & REDRAW_FIELD)
275 DrawMaskedBorder_FIELD();
276 if (redraw_mask & REDRAW_DOOR_1)
277 DrawMaskedBorder_DOOR_1();
278 if (redraw_mask & REDRAW_DOOR_2)
279 DrawMaskedBorder_DOOR_2();
280 if (redraw_mask & REDRAW_DOOR_3)
281 DrawMaskedBorder_DOOR_3();
288 DrawBuffer *buffer = (drawto_field == window ? backbuffer : drawto_field);
291 printf("::: TILES TO REFRESH: %d\n", redraw_tiles);
292 for (x = 0; x < SCR_FIELDX; x++)
293 for (y = 0 ; y < SCR_FIELDY; y++)
294 if (redraw[redraw_x1 + x][redraw_y1 + y])
295 printf("::: - %d, %d [%s]\n",
296 LEVELX(x), LEVELY(y),
297 EL_NAME(Feld[LEVELX(x)][LEVELY(y)]));
300 if (redraw_mask & REDRAW_TILES && redraw_tiles > REDRAWTILES_THRESHOLD)
301 redraw_mask |= REDRAW_FIELD;
303 if (redraw_mask & REDRAW_FIELD)
304 redraw_mask &= ~REDRAW_TILES;
306 if (redraw_mask == REDRAW_NONE)
309 if (redraw_mask & REDRAW_TILES &&
310 game_status == GAME_MODE_PLAYING &&
311 border.draw_masked[GAME_MODE_PLAYING])
312 redraw_mask |= REDRAW_FIELD;
314 if (global.fps_slowdown && game_status == GAME_MODE_PLAYING)
316 static boolean last_frame_skipped = FALSE;
317 boolean skip_even_when_not_scrolling = TRUE;
318 boolean just_scrolling = (ScreenMovDir != 0);
319 boolean verbose = FALSE;
321 if (global.fps_slowdown_factor > 1 &&
322 (FrameCounter % global.fps_slowdown_factor) &&
323 (just_scrolling || skip_even_when_not_scrolling))
325 redraw_mask &= ~REDRAW_MAIN;
327 last_frame_skipped = TRUE;
330 printf("FRAME SKIPPED\n");
334 if (last_frame_skipped)
335 redraw_mask |= REDRAW_FIELD;
337 last_frame_skipped = FALSE;
340 printf("frame not skipped\n");
344 /* synchronize X11 graphics at this point; if we would synchronize the
345 display immediately after the buffer switching (after the XFlush),
346 this could mean that we have to wait for the graphics to complete,
347 although we could go on doing calculations for the next frame */
351 /* never draw masked border to backbuffer when using playfield buffer */
352 if (game_status != GAME_MODE_PLAYING ||
353 redraw_mask & REDRAW_FROM_BACKBUFFER ||
354 buffer == backbuffer)
355 DrawMaskedBorder(redraw_mask);
357 DrawMaskedBorder(redraw_mask & REDRAW_DOORS);
359 if (redraw_mask & REDRAW_ALL)
361 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
363 redraw_mask = REDRAW_NONE;
366 if (redraw_mask & REDRAW_FIELD)
369 printf("::: REDRAW_FIELD\n");
372 if (game_status != GAME_MODE_PLAYING ||
373 redraw_mask & REDRAW_FROM_BACKBUFFER)
375 BlitBitmap(backbuffer, window,
376 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE, REAL_SX, REAL_SY);
380 int fx = FX, fy = FY;
382 if (setup.soft_scrolling)
384 fx += (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
385 fy += (ScreenMovDir & (MV_UP | MV_DOWN) ? ScreenGfxPos : 0);
388 if (setup.soft_scrolling ||
389 ABS(ScreenMovPos) + ScrollStepSize == TILEX ||
390 ABS(ScreenMovPos) == ScrollStepSize ||
391 redraw_tiles > REDRAWTILES_THRESHOLD)
393 if (border.draw_masked[GAME_MODE_PLAYING])
395 if (buffer != backbuffer)
397 /* copy playfield buffer to backbuffer to add masked border */
398 BlitBitmap(buffer, backbuffer, fx, fy, SXSIZE, SYSIZE, SX, SY);
399 DrawMaskedBorder(REDRAW_FIELD);
402 BlitBitmap(backbuffer, window,
403 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
408 BlitBitmap(buffer, window, fx, fy, SXSIZE, SYSIZE, SX, SY);
413 printf("redrawing all (ScreenGfxPos == %d) because %s\n",
415 (setup.soft_scrolling ?
416 "setup.soft_scrolling" :
417 ABS(ScreenGfxPos) + ScrollStepSize == TILEX ?
418 "ABS(ScreenGfxPos) + ScrollStepSize == TILEX" :
419 ABS(ScreenGfxPos) == ScrollStepSize ?
420 "ABS(ScreenGfxPos) == ScrollStepSize" :
421 "redraw_tiles > REDRAWTILES_THRESHOLD"));
427 redraw_mask &= ~REDRAW_MAIN;
430 if (redraw_mask & REDRAW_DOORS)
432 if (redraw_mask & REDRAW_DOOR_1)
433 BlitBitmap(backbuffer, window, DX, DY, DXSIZE, DYSIZE, DX, DY);
435 if (redraw_mask & REDRAW_DOOR_2)
436 BlitBitmap(backbuffer, window, VX, VY, VXSIZE, VYSIZE, VX, VY);
438 if (redraw_mask & REDRAW_DOOR_3)
439 BlitBitmap(backbuffer, window, EX, EY, EXSIZE, EYSIZE, EX, EY);
441 redraw_mask &= ~REDRAW_DOORS;
444 if (redraw_mask & REDRAW_MICROLEVEL)
446 BlitBitmap(backbuffer, window, SX, SY + 10 * TILEY, SXSIZE, 7 * TILEY,
447 SX, SY + 10 * TILEY);
449 redraw_mask &= ~REDRAW_MICROLEVEL;
452 if (redraw_mask & REDRAW_TILES)
455 printf("::: REDRAW_TILES\n");
458 for (x = 0; x < SCR_FIELDX; x++)
459 for (y = 0 ; y < SCR_FIELDY; y++)
460 if (redraw[redraw_x1 + x][redraw_y1 + y])
461 BlitBitmap(buffer, window,
462 FX + x * TILEX, FY + y * TILEY, TILEX, TILEY,
463 SX + x * TILEX, SY + y * TILEY);
466 if (redraw_mask & REDRAW_FPS) /* display frames per second */
471 sprintf(info1, " (only every %d. frame)", global.fps_slowdown_factor);
472 if (!global.fps_slowdown)
475 sprintf(text, "%04.1f fps%s", global.frames_per_second, info1);
477 DrawTextExt(window, SX + SXSIZE + SX, 0, text, FONT_TEXT_2, BLIT_OPAQUE);
479 DrawTextExt(window, SX, SY, text, FONT_TEXT_2, BLIT_OPAQUE);
485 for (x = 0; x < MAX_BUF_XSIZE; x++)
486 for (y = 0; y < MAX_BUF_YSIZE; y++)
489 redraw_mask = REDRAW_NONE;
492 static void FadeCrossSaveBackbuffer()
494 BlitBitmap(backbuffer, bitmap_db_cross, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
497 static void FadeExt(int fade_mask, int fade_mode, int fade_type)
499 static int fade_type_skip = FADE_TYPE_NONE;
500 void (*draw_border_function)(void) = NULL;
501 Bitmap *bitmap = (fade_mode & FADE_TYPE_TRANSFORM ? bitmap_db_cross : NULL);
502 int x, y, width, height;
503 int fade_delay, post_delay;
505 if (fade_type == FADE_TYPE_FADE_OUT)
507 if (fade_type_skip != FADE_TYPE_NONE)
510 printf("::: skipping %d ... [%d] (X)\n", fade_mode, fade_type_skip);
513 /* skip all fade operations until specified fade operation */
514 if (fade_type & fade_type_skip)
515 fade_type_skip = FADE_TYPE_NONE;
520 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
522 FadeCrossSaveBackbuffer();
528 redraw_mask |= fade_mask;
530 if (fade_type == FADE_TYPE_SKIP)
533 printf("::: will skip %d ... [%d]\n", fade_mode, fade_type_skip);
536 fade_type_skip = fade_mode;
542 printf("::: !!! FADING %d ... [%d] [%d]\n", fade_mode, fade_type,
547 fade_delay = fading.fade_delay;
548 post_delay = (fade_mode == FADE_MODE_FADE_OUT ? fading.post_delay : 0);
551 if (fade_type_skip != FADE_TYPE_NONE)
554 printf("::: skipping %d ... [%d]\n", fade_mode, fade_type_skip);
557 /* skip all fade operations until specified fade operation */
558 if (fade_type & fade_type_skip)
559 fade_type_skip = FADE_TYPE_NONE;
569 if (global.autoplay_leveldir)
571 // fading.fade_mode = FADE_MODE_NONE;
578 if (fading.fade_mode == FADE_MODE_NONE)
586 /* !!! what about fade_mask == REDRAW_FIELD | REDRAW_ALL ??? !!! */
589 printf("::: NOW FADING %d ... [%d]\n", fade_mode, fade_type);
593 if (fade_mask == REDRAW_NONE)
594 fade_mask = REDRAW_FIELD;
597 // if (fade_mask & REDRAW_FIELD)
598 if (fade_mask == REDRAW_FIELD)
603 height = FULL_SYSIZE;
606 fade_delay = fading.fade_delay;
607 post_delay = (fade_mode == FADE_MODE_FADE_OUT ? fading.post_delay : 0);
610 if (border.draw_masked_when_fading)
611 draw_border_function = DrawMaskedBorder_FIELD; /* update when fading */
613 DrawMaskedBorder_FIELD(); /* draw once */
615 else /* REDRAW_ALL */
623 fade_delay = fading.fade_delay;
624 post_delay = (fade_mode == FADE_MODE_FADE_OUT ? fading.post_delay : 0);
629 if (!setup.fade_screens ||
631 fading.fade_mode == FADE_MODE_NONE)
633 if (!setup.fade_screens || fade_delay == 0)
636 if (fade_mode == FADE_MODE_FADE_OUT)
640 if (fade_mode == FADE_MODE_FADE_OUT &&
641 fading.fade_mode != FADE_MODE_NONE)
642 ClearRectangle(backbuffer, x, y, width, height);
646 BlitBitmap(backbuffer, window, x, y, width, height, x, y);
647 redraw_mask = REDRAW_NONE;
655 FadeRectangle(bitmap, x, y, width, height, fade_mode, fade_delay, post_delay,
656 draw_border_function);
658 redraw_mask &= ~fade_mask;
661 void FadeIn(int fade_mask)
663 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
664 FadeExt(fade_mask, fading.fade_mode, FADE_TYPE_FADE_IN);
666 FadeExt(fade_mask, FADE_MODE_FADE_IN, FADE_TYPE_FADE_IN);
669 void FadeOut(int fade_mask)
671 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
672 FadeExt(fade_mask, fading.fade_mode, FADE_TYPE_FADE_OUT);
674 FadeExt(fade_mask, FADE_MODE_FADE_OUT, FADE_TYPE_FADE_OUT);
676 global.border_status = game_status;
679 static void FadeSetLeaveNext(struct TitleFadingInfo fading_leave, boolean set)
681 static struct TitleFadingInfo fading_leave_stored;
684 fading_leave_stored = fading_leave;
686 fading = fading_leave_stored;
689 void FadeSetEnterMenu()
691 fading = menu.enter_menu;
694 printf("::: storing enter_menu\n");
697 FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
700 void FadeSetLeaveMenu()
702 fading = menu.leave_menu;
705 printf("::: storing leave_menu\n");
708 FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
711 void FadeSetEnterScreen()
713 fading = menu.enter_screen[game_status];
716 printf("::: storing leave_screen[%d]\n", game_status);
719 FadeSetLeaveNext(menu.leave_screen[game_status], TRUE); /* store */
722 void FadeSetNextScreen()
724 fading = menu.next_screen;
727 printf("::: storing next_screen\n");
730 // (do not overwrite fade mode set by FadeSetEnterScreen)
731 // FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
734 void FadeSetLeaveScreen()
737 printf("::: recalling last stored value\n");
740 FadeSetLeaveNext(menu.leave_screen[game_status], FALSE); /* recall */
743 void FadeSetFromType(int type)
745 if (type & TYPE_ENTER_SCREEN)
746 FadeSetEnterScreen();
747 else if (type & TYPE_ENTER)
749 else if (type & TYPE_LEAVE)
753 void FadeSetDisabled()
755 static struct TitleFadingInfo fading_none = { FADE_MODE_NONE, -1, -1, -1 };
757 fading = fading_none;
760 void FadeSkipNextFadeIn()
762 FadeExt(0, FADE_MODE_SKIP_FADE_IN, FADE_TYPE_SKIP);
765 void FadeSkipNextFadeOut()
767 FadeExt(0, FADE_MODE_SKIP_FADE_OUT, FADE_TYPE_SKIP);
770 void SetWindowBackgroundImageIfDefined(int graphic)
772 if (graphic_info[graphic].bitmap)
773 SetWindowBackgroundBitmap(graphic_info[graphic].bitmap);
776 void SetMainBackgroundImageIfDefined(int graphic)
778 if (graphic_info[graphic].bitmap)
779 SetMainBackgroundBitmap(graphic_info[graphic].bitmap);
782 void SetDoorBackgroundImageIfDefined(int graphic)
784 if (graphic_info[graphic].bitmap)
785 SetDoorBackgroundBitmap(graphic_info[graphic].bitmap);
788 void SetWindowBackgroundImage(int graphic)
790 SetWindowBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
791 graphic_info[graphic].bitmap ?
792 graphic_info[graphic].bitmap :
793 graphic_info[IMG_BACKGROUND].bitmap);
796 void SetMainBackgroundImage(int graphic)
798 SetMainBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
799 graphic_info[graphic].bitmap ?
800 graphic_info[graphic].bitmap :
801 graphic_info[IMG_BACKGROUND].bitmap);
804 void SetDoorBackgroundImage(int graphic)
806 SetDoorBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
807 graphic_info[graphic].bitmap ?
808 graphic_info[graphic].bitmap :
809 graphic_info[IMG_BACKGROUND].bitmap);
812 void SetPanelBackground()
815 struct GraphicInfo *gfx = &graphic_info[IMG_BACKGROUND_PANEL];
818 BlitBitmapTiled(gfx->bitmap, bitmap_db_panel, gfx->src_x, gfx->src_y,
819 gfx->width, gfx->height, 0, 0, DXSIZE, DYSIZE);
821 /* (ClearRectangle() only needed if panel bitmap is smaller than panel) */
822 ClearRectangle(bitmap_db_panel, DX, DY, DXSIZE, DYSIZE);
823 BlitBitmap(gfx->bitmap, bitmap_db_panel, gfx->src_x, gfx->src_y,
824 MIN(gfx->width, DXSIZE), MIN(gfx->height, DYSIZE), 0, 0);
827 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, bitmap_db_panel,
828 DOOR_GFX_PAGEX5, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE, 0, 0);
831 SetDoorBackgroundBitmap(bitmap_db_panel);
834 void DrawBackground(int x, int y, int width, int height)
836 /* !!! "drawto" might still point to playfield buffer here (see below) !!! */
837 /* (when entering hall of fame after playing) */
839 ClearRectangleOnBackground(drawto, x, y, width, height);
841 ClearRectangleOnBackground(backbuffer, x, y, width, height);
844 redraw_mask |= REDRAW_FIELD;
847 void DrawBackgroundForFont(int x, int y, int width, int height, int font_nr)
849 struct FontBitmapInfo *font = getFontBitmapInfo(font_nr);
851 if (font->bitmap == NULL)
854 DrawBackground(x, y, width, height);
857 void DrawBackgroundForGraphic(int x, int y, int width, int height, int graphic)
859 struct GraphicInfo *g = &graphic_info[graphic];
861 if (g->bitmap == NULL)
864 DrawBackground(x, y, width, height);
869 /* !!! "drawto" might still point to playfield buffer here (see above) !!! */
870 /* (when entering hall of fame after playing) */
871 DrawBackground(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
873 /* !!! maybe this should be done before clearing the background !!! */
874 if (setup.soft_scrolling && game_status == GAME_MODE_PLAYING)
876 ClearRectangle(fieldbuffer, 0, 0, FXSIZE, FYSIZE);
877 SetDrawtoField(DRAW_BUFFERED);
880 SetDrawtoField(DRAW_BACKBUFFER);
883 void MarkTileDirty(int x, int y)
885 int xx = redraw_x1 + x;
886 int yy = redraw_y1 + y;
891 redraw[xx][yy] = TRUE;
892 redraw_mask |= REDRAW_TILES;
895 void SetBorderElement()
899 BorderElement = EL_EMPTY;
901 for (y = 0; y < lev_fieldy && BorderElement == EL_EMPTY; y++)
903 for (x = 0; x < lev_fieldx; x++)
905 if (!IS_INDESTRUCTIBLE(Feld[x][y]))
906 BorderElement = EL_STEELWALL;
908 if (y != 0 && y != lev_fieldy - 1 && x != lev_fieldx - 1)
914 void FloodFillLevel(int from_x, int from_y, int fill_element,
915 short field[MAX_LEV_FIELDX][MAX_LEV_FIELDY],
916 int max_fieldx, int max_fieldy)
920 static int check[4][2] = { { -1, 0 }, { 0, -1 }, { 1, 0 }, { 0, 1 } };
921 static int safety = 0;
923 /* check if starting field still has the desired content */
924 if (field[from_x][from_y] == fill_element)
929 if (safety > max_fieldx * max_fieldy)
930 Error(ERR_EXIT, "Something went wrong in 'FloodFill()'. Please debug.");
932 old_element = field[from_x][from_y];
933 field[from_x][from_y] = fill_element;
935 for (i = 0; i < 4; i++)
937 x = from_x + check[i][0];
938 y = from_y + check[i][1];
940 if (IN_FIELD(x, y, max_fieldx, max_fieldy) && field[x][y] == old_element)
941 FloodFillLevel(x, y, fill_element, field, max_fieldx, max_fieldy);
947 void SetRandomAnimationValue(int x, int y)
949 gfx.anim_random_frame = GfxRandom[x][y];
952 inline int getGraphicAnimationFrame(int graphic, int sync_frame)
954 /* animation synchronized with global frame counter, not move position */
955 if (graphic_info[graphic].anim_global_sync || sync_frame < 0)
956 sync_frame = FrameCounter;
958 return getAnimationFrame(graphic_info[graphic].anim_frames,
959 graphic_info[graphic].anim_delay,
960 graphic_info[graphic].anim_mode,
961 graphic_info[graphic].anim_start_frame,
965 void getSizedGraphicSource(int graphic, int frame, int tilesize_raw,
966 Bitmap **bitmap, int *x, int *y)
970 int width_mult, width_div;
971 int height_mult, height_div;
975 { 15, 16, 2, 3 }, /* 1 x 1 */
976 { 7, 8, 2, 3 }, /* 2 x 2 */
977 { 3, 4, 2, 3 }, /* 4 x 4 */
978 { 1, 2, 2, 3 }, /* 8 x 8 */
979 { 0, 1, 2, 3 }, /* 16 x 16 */
980 { 0, 1, 0, 1 }, /* 32 x 32 */
982 struct GraphicInfo *g = &graphic_info[graphic];
983 Bitmap *src_bitmap = g->bitmap;
984 int tilesize = MIN(MAX(1, tilesize_raw), TILESIZE);
985 int offset_calc_pos = log_2(tilesize);
986 int width_mult = offset_calc[offset_calc_pos].width_mult;
987 int width_div = offset_calc[offset_calc_pos].width_div;
988 int height_mult = offset_calc[offset_calc_pos].height_mult;
989 int height_div = offset_calc[offset_calc_pos].height_div;
990 int startx = src_bitmap->width * width_mult / width_div;
991 int starty = src_bitmap->height * height_mult / height_div;
992 int src_x = g->src_x * tilesize / TILESIZE;
993 int src_y = g->src_y * tilesize / TILESIZE;
994 int width = g->width * tilesize / TILESIZE;
995 int height = g->height * tilesize / TILESIZE;
996 int offset_x = g->offset_x * tilesize / TILESIZE;
997 int offset_y = g->offset_y * tilesize / TILESIZE;
999 if (g->offset_y == 0) /* frames are ordered horizontally */
1001 int max_width = g->anim_frames_per_line * width;
1002 int pos = (src_y / height) * max_width + src_x + frame * offset_x;
1004 src_x = pos % max_width;
1005 src_y = src_y % height + pos / max_width * height;
1007 else if (g->offset_x == 0) /* frames are ordered vertically */
1009 int max_height = g->anim_frames_per_line * height;
1010 int pos = (src_x / width) * max_height + src_y + frame * offset_y;
1012 src_x = src_x % width + pos / max_height * width;
1013 src_y = pos % max_height;
1015 else /* frames are ordered diagonally */
1017 src_x = src_x + frame * offset_x;
1018 src_y = src_y + frame * offset_y;
1021 *bitmap = src_bitmap;
1022 *x = startx + src_x;
1023 *y = starty + src_y;
1026 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
1029 getSizedGraphicSource(graphic, 0, MINI_TILESIZE, bitmap, x, y);
1031 struct GraphicInfo *g = &graphic_info[graphic];
1032 int mini_startx = 0;
1033 int mini_starty = g->bitmap->height * 2 / 3;
1035 *bitmap = g->bitmap;
1036 *x = mini_startx + g->src_x / 2;
1037 *y = mini_starty + g->src_y / 2;
1041 inline void getGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
1042 int *x, int *y, boolean get_backside)
1044 struct GraphicInfo *g = &graphic_info[graphic];
1045 int src_x = g->src_x + (get_backside ? g->offset2_x : 0);
1046 int src_y = g->src_y + (get_backside ? g->offset2_y : 0);
1048 *bitmap = g->bitmap;
1050 if (g->offset_y == 0) /* frames are ordered horizontally */
1052 int max_width = g->anim_frames_per_line * g->width;
1053 int pos = (src_y / g->height) * max_width + src_x + frame * g->offset_x;
1055 *x = pos % max_width;
1056 *y = src_y % g->height + pos / max_width * g->height;
1058 else if (g->offset_x == 0) /* frames are ordered vertically */
1060 int max_height = g->anim_frames_per_line * g->height;
1061 int pos = (src_x / g->width) * max_height + src_y + frame * g->offset_y;
1063 *x = src_x % g->width + pos / max_height * g->width;
1064 *y = pos % max_height;
1066 else /* frames are ordered diagonally */
1068 *x = src_x + frame * g->offset_x;
1069 *y = src_y + frame * g->offset_y;
1073 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
1075 getGraphicSourceExt(graphic, frame, bitmap, x, y, FALSE);
1078 void DrawGraphic(int x, int y, int graphic, int frame)
1081 if (!IN_SCR_FIELD(x, y))
1083 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
1084 printf("DrawGraphic(): This should never happen!\n");
1089 DrawGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic, frame);
1090 MarkTileDirty(x, y);
1093 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
1099 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1100 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
1103 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
1106 if (!IN_SCR_FIELD(x, y))
1108 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
1109 printf("DrawGraphicThruMask(): This should never happen!\n");
1114 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y *TILEY, graphic,
1116 MarkTileDirty(x, y);
1119 void DrawGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y, int graphic,
1125 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1127 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1128 dst_x - src_x, dst_y - src_y);
1129 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dst_x, dst_y);
1132 void DrawSizedGraphic(int x, int y, int graphic, int frame, int tilesize)
1134 DrawSizedGraphicExt(drawto, SX + x * tilesize, SY + y * tilesize, graphic,
1136 MarkTileDirty(x / tilesize, y / tilesize);
1139 void DrawSizedGraphicExt(DrawBuffer *d, int x, int y, int graphic, int frame,
1145 getSizedGraphicSource(graphic, frame, tilesize, &src_bitmap, &src_x, &src_y);
1146 BlitBitmap(src_bitmap, d, src_x, src_y, tilesize, tilesize, x, y);
1149 void DrawMiniGraphic(int x, int y, int graphic)
1151 DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
1152 MarkTileDirty(x / 2, y / 2);
1155 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
1160 getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1161 BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
1164 inline static void DrawGraphicShiftedNormal(int x, int y, int dx, int dy,
1165 int graphic, int frame,
1166 int cut_mode, int mask_mode)
1171 int width = TILEX, height = TILEY;
1174 if (dx || dy) /* shifted graphic */
1176 if (x < BX1) /* object enters playfield from the left */
1183 else if (x > BX2) /* object enters playfield from the right */
1189 else if (x==BX1 && dx < 0) /* object leaves playfield to the left */
1195 else if (x==BX2 && dx > 0) /* object leaves playfield to the right */
1197 else if (dx) /* general horizontal movement */
1198 MarkTileDirty(x + SIGN(dx), y);
1200 if (y < BY1) /* object enters playfield from the top */
1202 if (cut_mode==CUT_BELOW) /* object completely above top border */
1210 else if (y > BY2) /* object enters playfield from the bottom */
1216 else if (y==BY1 && dy < 0) /* object leaves playfield to the top */
1222 else if (dy > 0 && cut_mode == CUT_ABOVE)
1224 if (y == BY2) /* object completely above bottom border */
1230 MarkTileDirty(x, y + 1);
1231 } /* object leaves playfield to the bottom */
1232 else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
1234 else if (dy) /* general vertical movement */
1235 MarkTileDirty(x, y + SIGN(dy));
1239 if (!IN_SCR_FIELD(x, y))
1241 printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
1242 printf("DrawGraphicShifted(): This should never happen!\n");
1247 if (width > 0 && height > 0)
1249 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1254 dst_x = FX + x * TILEX + dx;
1255 dst_y = FY + y * TILEY + dy;
1257 if (mask_mode == USE_MASKING)
1259 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1260 dst_x - src_x, dst_y - src_y);
1261 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1265 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1268 MarkTileDirty(x, y);
1272 inline static void DrawGraphicShiftedDouble(int x, int y, int dx, int dy,
1273 int graphic, int frame,
1274 int cut_mode, int mask_mode)
1279 int width = TILEX, height = TILEY;
1282 int x2 = x + SIGN(dx);
1283 int y2 = y + SIGN(dy);
1285 /* !!! DOES NOT WORK FOR SLOW MOVEMENT !!! */
1286 int sync_frame = GfxFrame[LEVELX(x)][LEVELY(y)];
1288 /* movement with two-tile animations must be sync'ed with movement position,
1289 not with current GfxFrame (which can be higher when using slow movement) */
1290 int anim_pos = (dx ? ABS(dx) : ABS(dy));
1291 int anim_frames = graphic_info[graphic].anim_frames;
1293 /* (we also need anim_delay here for movement animations with less frames) */
1294 int anim_delay = graphic_info[graphic].anim_delay;
1295 int sync_frame = anim_pos * anim_frames * anim_delay / TILESIZE;
1297 int sync_frame = anim_pos * anim_frames / TILESIZE;
1300 boolean draw_start_tile = (cut_mode != CUT_ABOVE); /* only for falling! */
1301 boolean draw_end_tile = (cut_mode != CUT_BELOW); /* only for falling! */
1303 /* re-calculate animation frame for two-tile movement animation */
1304 frame = getGraphicAnimationFrame(graphic, sync_frame);
1308 printf("::: %d, %d, %d => %d [%d]\n",
1309 anim_pos, anim_frames, anim_delay, sync_frame, graphic);
1311 printf("::: %d, %d => %d\n",
1312 anim_pos, anim_frames, sync_frame);
1317 printf("::: %d [%d, %d] [%d] [%d]\n", frame, sync_frame, dy,
1318 GfxFrame[LEVELX(x)][LEVELY(y)], mask_mode);
1321 /* check if movement start graphic inside screen area and should be drawn */
1322 if (draw_start_tile && IN_SCR_FIELD(x1, y1))
1324 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, TRUE);
1326 dst_x = FX + x1 * TILEX;
1327 dst_y = FY + y1 * TILEY;
1329 if (mask_mode == USE_MASKING)
1331 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1332 dst_x - src_x, dst_y - src_y);
1333 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1337 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1340 MarkTileDirty(x1, y1);
1343 /* check if movement end graphic inside screen area and should be drawn */
1344 if (draw_end_tile && IN_SCR_FIELD(x2, y2))
1346 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
1348 dst_x = FX + x2 * TILEX;
1349 dst_y = FY + y2 * TILEY;
1351 if (mask_mode == USE_MASKING)
1353 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1354 dst_x - src_x, dst_y - src_y);
1355 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1359 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1362 MarkTileDirty(x2, y2);
1366 static void DrawGraphicShifted(int x, int y, int dx, int dy,
1367 int graphic, int frame,
1368 int cut_mode, int mask_mode)
1372 DrawGraphic(x, y, graphic, frame);
1377 if (graphic_info[graphic].double_movement) /* EM style movement images */
1378 DrawGraphicShiftedDouble(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1380 DrawGraphicShiftedNormal(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1383 void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
1384 int frame, int cut_mode)
1386 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, USE_MASKING);
1389 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
1390 int cut_mode, int mask_mode)
1392 int lx = LEVELX(x), ly = LEVELY(y);
1396 if (IN_LEV_FIELD(lx, ly))
1398 SetRandomAnimationValue(lx, ly);
1400 graphic = el_act_dir2img(element, GfxAction[lx][ly], GfxDir[lx][ly]);
1401 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1403 /* do not use double (EM style) movement graphic when not moving */
1404 if (graphic_info[graphic].double_movement && !dx && !dy)
1406 graphic = el_act_dir2img(element, ACTION_DEFAULT, GfxDir[lx][ly]);
1407 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1410 else /* border element */
1412 graphic = el2img(element);
1413 frame = getGraphicAnimationFrame(graphic, -1);
1416 if (element == EL_EXPANDABLE_WALL)
1418 boolean left_stopped = FALSE, right_stopped = FALSE;
1420 if (!IN_LEV_FIELD(lx - 1, ly) || IS_WALL(Feld[lx - 1][ly]))
1421 left_stopped = TRUE;
1422 if (!IN_LEV_FIELD(lx + 1, ly) || IS_WALL(Feld[lx + 1][ly]))
1423 right_stopped = TRUE;
1425 if (left_stopped && right_stopped)
1427 else if (left_stopped)
1429 graphic = IMG_EXPANDABLE_WALL_GROWING_RIGHT;
1430 frame = graphic_info[graphic].anim_frames - 1;
1432 else if (right_stopped)
1434 graphic = IMG_EXPANDABLE_WALL_GROWING_LEFT;
1435 frame = graphic_info[graphic].anim_frames - 1;
1440 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
1441 else if (mask_mode == USE_MASKING)
1442 DrawGraphicThruMask(x, y, graphic, frame);
1444 DrawGraphic(x, y, graphic, frame);
1447 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
1448 int cut_mode, int mask_mode)
1450 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1451 DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
1452 cut_mode, mask_mode);
1455 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
1458 DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1461 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
1464 DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1467 void DrawLevelElementThruMask(int x, int y, int element)
1469 DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1472 void DrawLevelFieldThruMask(int x, int y)
1474 DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
1477 /* !!! implementation of quicksand is totally broken !!! */
1478 #define IS_CRUMBLED_TILE(x, y, e) \
1479 (GFX_CRUMBLED(e) && (!IN_LEV_FIELD(x, y) || \
1480 !IS_MOVING(x, y) || \
1481 (e) == EL_QUICKSAND_EMPTYING || \
1482 (e) == EL_QUICKSAND_FAST_EMPTYING))
1484 static void DrawLevelFieldCrumbledInnerCorners(int x, int y, int dx, int dy,
1489 int width, height, cx, cy;
1490 int sx = SCREENX(x), sy = SCREENY(y);
1491 int crumbled_border_size = graphic_info[graphic].border_size;
1494 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1496 for (i = 1; i < 4; i++)
1498 int dxx = (i & 1 ? dx : 0);
1499 int dyy = (i & 2 ? dy : 0);
1502 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1505 /* check if neighbour field is of same crumble type */
1506 boolean same = (IS_CRUMBLED_TILE(xx, yy, element) &&
1507 graphic_info[graphic].class ==
1508 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class);
1510 /* return if check prevents inner corner */
1511 if (same == (dxx == dx && dyy == dy))
1515 /* if we reach this point, we have an inner corner */
1517 getGraphicSource(graphic, 1, &src_bitmap, &src_x, &src_y);
1519 width = crumbled_border_size;
1520 height = crumbled_border_size;
1521 cx = (dx > 0 ? TILEX - crumbled_border_size : 0);
1522 cy = (dy > 0 ? TILEY - crumbled_border_size : 0);
1524 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1525 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
1528 static void DrawLevelFieldCrumbledBorders(int x, int y, int graphic, int frame,
1533 int width, height, bx, by, cx, cy;
1534 int sx = SCREENX(x), sy = SCREENY(y);
1535 int crumbled_border_size = graphic_info[graphic].border_size;
1538 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1540 /* draw simple, sloppy, non-corner-accurate crumbled border */
1543 width = (dir == 1 || dir == 2 ? crumbled_border_size : TILEX);
1544 height = (dir == 0 || dir == 3 ? crumbled_border_size : TILEY);
1545 cx = (dir == 2 ? TILEX - crumbled_border_size : 0);
1546 cy = (dir == 3 ? TILEY - crumbled_border_size : 0);
1548 if (dir == 1 || dir == 2) /* left or right crumbled border */
1550 width = crumbled_border_size;
1552 cx = (dir == 2 ? TILEX - crumbled_border_size : 0);
1555 else /* top or bottom crumbled border */
1558 height = crumbled_border_size;
1560 cy = (dir == 3 ? TILEY - crumbled_border_size : 0);
1564 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1565 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
1567 /* (remaining middle border part must be at least as big as corner part) */
1568 if (!(graphic_info[graphic].style & STYLE_ACCURATE_BORDERS) ||
1569 crumbled_border_size >= TILESIZE / 3)
1572 /* correct corners of crumbled border, if needed */
1575 for (i = -1; i <= 1; i+=2)
1577 int xx = x + (dir == 0 || dir == 3 ? i : 0);
1578 int yy = y + (dir == 1 || dir == 2 ? i : 0);
1579 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1582 /* check if neighbour field is of same crumble type */
1583 if (IS_CRUMBLED_TILE(xx, yy, element) &&
1584 graphic_info[graphic].class ==
1585 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
1587 /* no crumbled corner, but continued crumbled border */
1589 int c1 = (dir == 2 || dir == 3 ? TILESIZE - crumbled_border_size : 0);
1590 int c2 = (i == 1 ? TILESIZE - crumbled_border_size : 0);
1591 int b1 = (i == 1 ? crumbled_border_size :
1592 TILESIZE - 2 * crumbled_border_size);
1594 width = crumbled_border_size;
1595 height = crumbled_border_size;
1597 if (dir == 1 || dir == 2)
1612 BlitBitmap(src_bitmap, drawto_field, src_x + bx, src_y + by,
1613 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
1617 if (dir == 1 || dir == 2) /* left or right crumbled border */
1619 for (i = -1; i <= 1; i+=2)
1623 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1626 /* check if neighbour field is of same crumble type */
1627 if (IS_CRUMBLED_TILE(xx, yy, element) &&
1628 graphic_info[graphic].class ==
1629 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
1631 /* no crumbled corner, but continued crumbled border */
1633 width = crumbled_border_size;
1634 height = crumbled_border_size;
1635 cx = (dir == 2 ? TILEX - crumbled_border_size : 0);
1636 cy = (i == 1 ? TILEY - crumbled_border_size : 0);
1638 by = (i == 1 ? crumbled_border_size :
1639 TILEY - 2 * crumbled_border_size);
1641 BlitBitmap(src_bitmap, drawto_field, src_x + bx, src_y + by,
1642 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
1646 else /* top or bottom crumbled border */
1648 for (i = -1; i <= 1; i+=2)
1652 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1655 /* check if neighbour field is of same crumble type */
1656 if (IS_CRUMBLED_TILE(xx, yy, element) &&
1657 graphic_info[graphic].class ==
1658 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
1660 /* no crumbled corner, but continued crumbled border */
1662 width = crumbled_border_size;
1663 height = crumbled_border_size;
1664 cx = (i == 1 ? TILEX - crumbled_border_size : 0);
1665 cy = (dir == 3 ? TILEY - crumbled_border_size : 0);
1666 bx = (i == 1 ? crumbled_border_size :
1667 TILEX - 2 * crumbled_border_size);
1670 BlitBitmap(src_bitmap, drawto_field, src_x + bx, src_y + by,
1671 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
1678 static void DrawLevelFieldCrumbledExt(int x, int y, int graphic, int frame)
1680 int sx = SCREENX(x), sy = SCREENY(y);
1683 static int xy[4][2] =
1691 if (!IN_LEV_FIELD(x, y))
1694 element = TILE_GFX_ELEMENT(x, y);
1696 /* crumble field itself */
1697 if (IS_CRUMBLED_TILE(x, y, element))
1699 if (!IN_SCR_FIELD(sx, sy))
1702 for (i = 0; i < 4; i++)
1704 int xx = x + xy[i][0];
1705 int yy = y + xy[i][1];
1707 element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1710 /* check if neighbour field is of same crumble type */
1712 if (IS_CRUMBLED_TILE(xx, yy, element) &&
1713 graphic_info[graphic].class ==
1714 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
1717 if (IS_CRUMBLED_TILE(xx, yy, element))
1721 DrawLevelFieldCrumbledBorders(x, y, graphic, frame, i);
1724 if ((graphic_info[graphic].style & STYLE_INNER_CORNERS) &&
1725 graphic_info[graphic].anim_frames == 2)
1727 for (i = 0; i < 4; i++)
1729 int dx = (i & 1 ? +1 : -1);
1730 int dy = (i & 2 ? +1 : -1);
1732 DrawLevelFieldCrumbledInnerCorners(x, y, dx, dy, graphic);
1736 MarkTileDirty(sx, sy);
1738 else /* center field not crumbled -- crumble neighbour fields */
1740 for (i = 0; i < 4; i++)
1742 int xx = x + xy[i][0];
1743 int yy = y + xy[i][1];
1744 int sxx = sx + xy[i][0];
1745 int syy = sy + xy[i][1];
1747 if (!IN_LEV_FIELD(xx, yy) ||
1748 !IN_SCR_FIELD(sxx, syy))
1751 if (Feld[xx][yy] == EL_ELEMENT_SNAPPING)
1754 element = TILE_GFX_ELEMENT(xx, yy);
1756 if (!IS_CRUMBLED_TILE(xx, yy, element))
1759 graphic = el_act2crm(element, ACTION_DEFAULT);
1761 DrawLevelFieldCrumbledBorders(xx, yy, graphic, 0, 3 - i);
1763 MarkTileDirty(sxx, syy);
1768 void DrawLevelFieldCrumbled(int x, int y)
1772 if (!IN_LEV_FIELD(x, y))
1776 /* !!! CHECK THIS !!! */
1779 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
1780 GFX_CRUMBLED(GfxElement[x][y]))
1783 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
1784 GfxElement[x][y] != EL_UNDEFINED &&
1785 GFX_CRUMBLED(GfxElement[x][y]))
1787 DrawLevelFieldCrumbledDigging(x, y, GfxDir[x][y], GfxFrame[x][y]);
1794 graphic = el_act2crm(TILE_GFX_ELEMENT(x, y), ACTION_DEFAULT);
1796 graphic = el_act2crm(Feld[x][y], ACTION_DEFAULT);
1799 DrawLevelFieldCrumbledExt(x, y, graphic, 0);
1802 void DrawLevelFieldCrumbledDigging(int x, int y, int direction,
1805 int graphic1 = el_act_dir2img(GfxElement[x][y], ACTION_DIGGING, direction);
1806 int graphic2 = el_act_dir2crm(GfxElement[x][y], ACTION_DIGGING, direction);
1807 int frame1 = getGraphicAnimationFrame(graphic1, step_frame);
1808 int frame2 = getGraphicAnimationFrame(graphic2, step_frame);
1809 int sx = SCREENX(x), sy = SCREENY(y);
1811 DrawGraphic(sx, sy, graphic1, frame1);
1812 DrawLevelFieldCrumbledExt(x, y, graphic2, frame2);
1815 void DrawLevelFieldCrumbledNeighbours(int x, int y)
1817 int sx = SCREENX(x), sy = SCREENY(y);
1818 static int xy[4][2] =
1827 for (i = 0; i < 4; i++)
1829 int xx = x + xy[i][0];
1830 int yy = y + xy[i][1];
1831 int sxx = sx + xy[i][0];
1832 int syy = sy + xy[i][1];
1834 if (!IN_LEV_FIELD(xx, yy) ||
1835 !IN_SCR_FIELD(sxx, syy) ||
1836 !GFX_CRUMBLED(Feld[xx][yy]) ||
1840 DrawLevelField(xx, yy);
1844 static int getBorderElement(int x, int y)
1848 { EL_STEELWALL_TOPLEFT, EL_INVISIBLE_STEELWALL_TOPLEFT },
1849 { EL_STEELWALL_TOPRIGHT, EL_INVISIBLE_STEELWALL_TOPRIGHT },
1850 { EL_STEELWALL_BOTTOMLEFT, EL_INVISIBLE_STEELWALL_BOTTOMLEFT },
1851 { EL_STEELWALL_BOTTOMRIGHT, EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
1852 { EL_STEELWALL_VERTICAL, EL_INVISIBLE_STEELWALL_VERTICAL },
1853 { EL_STEELWALL_HORIZONTAL, EL_INVISIBLE_STEELWALL_HORIZONTAL },
1854 { EL_STEELWALL, EL_INVISIBLE_STEELWALL }
1856 int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
1857 int steel_position = (x == -1 && y == -1 ? 0 :
1858 x == lev_fieldx && y == -1 ? 1 :
1859 x == -1 && y == lev_fieldy ? 2 :
1860 x == lev_fieldx && y == lev_fieldy ? 3 :
1861 x == -1 || x == lev_fieldx ? 4 :
1862 y == -1 || y == lev_fieldy ? 5 : 6);
1864 return border[steel_position][steel_type];
1867 void DrawScreenElement(int x, int y, int element)
1869 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
1870 DrawLevelFieldCrumbled(LEVELX(x), LEVELY(y));
1873 void DrawLevelElement(int x, int y, int element)
1875 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1876 DrawScreenElement(SCREENX(x), SCREENY(y), element);
1879 void DrawScreenField(int x, int y)
1881 int lx = LEVELX(x), ly = LEVELY(y);
1882 int element, content;
1884 if (!IN_LEV_FIELD(lx, ly))
1886 if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
1889 element = getBorderElement(lx, ly);
1891 DrawScreenElement(x, y, element);
1896 element = Feld[lx][ly];
1897 content = Store[lx][ly];
1899 if (IS_MOVING(lx, ly))
1901 int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
1902 boolean cut_mode = NO_CUTTING;
1904 if (element == EL_QUICKSAND_EMPTYING ||
1905 element == EL_QUICKSAND_FAST_EMPTYING ||
1906 element == EL_MAGIC_WALL_EMPTYING ||
1907 element == EL_BD_MAGIC_WALL_EMPTYING ||
1908 element == EL_DC_MAGIC_WALL_EMPTYING ||
1909 element == EL_AMOEBA_DROPPING)
1910 cut_mode = CUT_ABOVE;
1911 else if (element == EL_QUICKSAND_FILLING ||
1912 element == EL_QUICKSAND_FAST_FILLING ||
1913 element == EL_MAGIC_WALL_FILLING ||
1914 element == EL_BD_MAGIC_WALL_FILLING ||
1915 element == EL_DC_MAGIC_WALL_FILLING)
1916 cut_mode = CUT_BELOW;
1919 if (lx == 9 && ly == 1)
1920 printf("::: %s [%d] [%d, %d] [%d]\n",
1921 EL_NAME(TILE_GFX_ELEMENT(lx, ly)),
1922 el_act2crm(TILE_GFX_ELEMENT(lx, ly), ACTION_DEFAULT),
1923 element_info[EL_QUICKSAND_EMPTYING].graphic[ACTION_DEFAULT],
1924 element_info[EL_QUICKSAND_EMPTYING].crumbled[ACTION_DEFAULT],
1925 GFX_CRUMBLED(TILE_GFX_ELEMENT(lx, ly)));
1928 if (cut_mode == CUT_ABOVE)
1930 DrawScreenElement(x, y, element);
1932 DrawScreenElementShifted(x, y, 0, 0, element, NO_CUTTING);
1935 DrawScreenElement(x, y, EL_EMPTY);
1938 DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
1939 else if (cut_mode == NO_CUTTING)
1940 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
1943 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
1946 if (cut_mode == CUT_BELOW &&
1947 IN_LEV_FIELD(lx, ly + 1) && IN_SCR_FIELD(x, y + 1))
1948 DrawLevelElement(lx, ly + 1, element);
1952 if (content == EL_ACID)
1954 int dir = MovDir[lx][ly];
1955 int newlx = lx + (dir == MV_LEFT ? -1 : dir == MV_RIGHT ? +1 : 0);
1956 int newly = ly + (dir == MV_UP ? -1 : dir == MV_DOWN ? +1 : 0);
1958 DrawLevelElementThruMask(newlx, newly, EL_ACID);
1961 else if (IS_BLOCKED(lx, ly))
1966 boolean cut_mode = NO_CUTTING;
1967 int element_old, content_old;
1969 Blocked2Moving(lx, ly, &oldx, &oldy);
1972 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
1973 MovDir[oldx][oldy] == MV_RIGHT);
1975 element_old = Feld[oldx][oldy];
1976 content_old = Store[oldx][oldy];
1978 if (element_old == EL_QUICKSAND_EMPTYING ||
1979 element_old == EL_QUICKSAND_FAST_EMPTYING ||
1980 element_old == EL_MAGIC_WALL_EMPTYING ||
1981 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
1982 element_old == EL_DC_MAGIC_WALL_EMPTYING ||
1983 element_old == EL_AMOEBA_DROPPING)
1984 cut_mode = CUT_ABOVE;
1986 DrawScreenElement(x, y, EL_EMPTY);
1989 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
1991 else if (cut_mode == NO_CUTTING)
1992 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
1995 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
1998 else if (IS_DRAWABLE(element))
1999 DrawScreenElement(x, y, element);
2001 DrawScreenElement(x, y, EL_EMPTY);
2004 void DrawLevelField(int x, int y)
2006 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
2007 DrawScreenField(SCREENX(x), SCREENY(y));
2008 else if (IS_MOVING(x, y))
2012 Moving2Blocked(x, y, &newx, &newy);
2013 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
2014 DrawScreenField(SCREENX(newx), SCREENY(newy));
2016 else if (IS_BLOCKED(x, y))
2020 Blocked2Moving(x, y, &oldx, &oldy);
2021 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
2022 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
2026 void DrawMiniElement(int x, int y, int element)
2030 graphic = el2edimg(element);
2031 DrawMiniGraphic(x, y, graphic);
2034 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
2036 int x = sx + scroll_x, y = sy + scroll_y;
2038 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
2039 DrawMiniElement(sx, sy, EL_EMPTY);
2040 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
2041 DrawMiniElement(sx, sy, Feld[x][y]);
2043 DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
2046 void DrawEnvelopeBackground(int envelope_nr, int startx, int starty,
2047 int x, int y, int xsize, int ysize, int font_nr)
2049 int font_width = getFontWidth(font_nr);
2050 int font_height = getFontHeight(font_nr);
2051 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2054 int dst_x = SX + startx + x * font_width;
2055 int dst_y = SY + starty + y * font_height;
2056 int width = graphic_info[graphic].width;
2057 int height = graphic_info[graphic].height;
2058 int inner_width = MAX(width - 2 * font_width, font_width);
2059 int inner_height = MAX(height - 2 * font_height, font_height);
2060 int inner_sx = (width >= 3 * font_width ? font_width : 0);
2061 int inner_sy = (height >= 3 * font_height ? font_height : 0);
2062 boolean draw_masked = graphic_info[graphic].draw_masked;
2064 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
2066 if (src_bitmap == NULL || width < font_width || height < font_height)
2068 ClearRectangle(drawto, dst_x, dst_y, font_width, font_height);
2072 src_x += (x == 0 ? 0 : x == xsize - 1 ? width - font_width :
2073 inner_sx + (x - 1) * font_width % inner_width);
2074 src_y += (y == 0 ? 0 : y == ysize - 1 ? height - font_height :
2075 inner_sy + (y - 1) * font_height % inner_height);
2079 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
2080 dst_x - src_x, dst_y - src_y);
2081 BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, font_width, font_height,
2085 BlitBitmap(src_bitmap, drawto, src_x, src_y, font_width, font_height,
2089 void AnimateEnvelope(int envelope_nr, int anim_mode, int action)
2091 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2092 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
2093 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
2094 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2095 boolean no_delay = (tape.warp_forward);
2096 unsigned long anim_delay = 0;
2097 int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
2098 int anim_delay_value = (no_delay ? 0 : frame_delay_value);
2099 int font_nr = FONT_ENVELOPE_1 + envelope_nr;
2100 int font_width = getFontWidth(font_nr);
2101 int font_height = getFontHeight(font_nr);
2102 int max_xsize = level.envelope[envelope_nr].xsize;
2103 int max_ysize = level.envelope[envelope_nr].ysize;
2104 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
2105 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
2106 int xend = max_xsize;
2107 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
2108 int xstep = (xstart < xend ? 1 : 0);
2109 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
2112 for (x = xstart, y = ystart; x <= xend && y <= yend; x += xstep, y += ystep)
2114 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
2115 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
2116 int sx = (SXSIZE - xsize * font_width) / 2;
2117 int sy = (SYSIZE - ysize * font_height) / 2;
2120 SetDrawtoField(DRAW_BUFFERED);
2122 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
2124 SetDrawtoField(DRAW_BACKBUFFER);
2126 for (yy = 0; yy < ysize; yy++) for (xx = 0; xx < xsize; xx++)
2127 DrawEnvelopeBackground(envelope_nr, sx,sy, xx,yy, xsize, ysize, font_nr);
2130 DrawTextBuffer(SX + sx + font_width, SY + sy + font_height,
2131 level.envelope[envelope_nr].text, font_nr, max_xsize,
2132 xsize - 2, ysize - 2, 0, mask_mode,
2133 level.envelope[envelope_nr].autowrap,
2134 level.envelope[envelope_nr].centered, FALSE);
2136 DrawTextToTextArea(SX + sx + font_width, SY + sy + font_height,
2137 level.envelope[envelope_nr].text, font_nr, max_xsize,
2138 xsize - 2, ysize - 2, mask_mode);
2141 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
2144 WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
2148 void AnimateEnvelopeDoor(char *text, int anim_mode, int action)
2151 int envelope_nr = 0;
2153 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2154 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
2155 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
2156 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2157 boolean no_delay = (tape.warp_forward);
2158 unsigned long anim_delay = 0;
2159 int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
2160 int anim_delay_value = (no_delay ? 0 : frame_delay_value);
2162 int max_word_len = maxWordLengthInString(text);
2163 int font_nr = (max_word_len > 7 ? FONT_TEXT_1 : FONT_TEXT_2);
2165 int font_nr = FONT_ENVELOPE_1 + envelope_nr;
2167 int font_width = getFontWidth(font_nr);
2168 int font_height = getFontHeight(font_nr);
2172 int max_xsize = DXSIZE / font_width;
2173 int max_ysize = DYSIZE / font_height;
2175 int max_xsize = 7; /* tools.c: MAX_REQUEST_LINE_FONT1_LEN == 7 */
2176 int max_ysize = 13; /* tools.c: MAX_REQUEST_LINES == 13 */
2180 int max_xsize = level.envelope[envelope_nr].xsize;
2181 int max_ysize = level.envelope[envelope_nr].ysize;
2183 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
2184 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
2185 int xend = max_xsize;
2186 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
2187 int xstep = (xstart < xend ? 1 : 0);
2188 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
2193 char *text_copy = getStringCopy(text);
2196 font_nr = FONT_TEXT_2;
2198 if (maxWordLengthInString(text) > 7) /* MAX_REQUEST_LINE_FONT1_LEN == 7 */
2200 max_xsize = 10; /* tools.c: MAX_REQUEST_LINE_FONT2_LEN == 10 */
2201 font_nr = FONT_TEXT_1;
2204 int max_word_len = 0;
2206 char *text_copy = getStringCopy(text);
2208 font_nr = FONT_TEXT_2;
2210 for (text_ptr = text; *text_ptr; text_ptr++)
2212 max_word_len = (*text_ptr != ' ' ? max_word_len + 1 : 0);
2214 if (max_word_len > 7) /* tools.c: MAX_REQUEST_LINE_FONT1_LEN == 7 */
2216 max_xsize = 10; /* tools.c: MAX_REQUEST_LINE_FONT2_LEN == 10 */
2217 font_nr = FONT_TEXT_1;
2226 for (text_ptr = text_copy; *text_ptr; text_ptr++)
2227 if (*text_ptr == ' ')
2232 dDX = SX + (SXSIZE - DXSIZE) / 2 - DX;
2233 dDY = SY + (SYSIZE - DYSIZE) / 2 - DY;
2235 dDX = SX + SXSIZE / 2 - max_xsize * font_width / 2 - DX;
2236 dDY = SY + SYSIZE / 2 - max_ysize * font_height / 2 - DY;
2239 for (x = xstart, y = ystart; x <= xend && y <= yend; x += xstep, y += ystep)
2241 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
2242 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
2243 int sx = (SXSIZE - xsize * font_width) / 2;
2244 int sy = (SYSIZE - ysize * font_height) / 2;
2248 BlitBitmap(bitmap_db_store, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2250 SetDrawtoField(DRAW_BUFFERED);
2252 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
2254 SetDrawtoField(DRAW_BACKBUFFER);
2257 for (yy = 0; yy < ysize; yy++) for (xx = 0; xx < xsize; xx++)
2258 DrawEnvelopeBackground(envelope_nr, sx,sy, xx,yy, xsize, ysize, font_nr);
2263 DrawTextBuffer(SX + sx + font_width, SY + sy + font_height + 8,
2264 text_copy, font_nr, max_xsize,
2265 xsize - 2, ysize - 2, 2, mask_mode,
2266 FALSE, TRUE, FALSE);
2268 DrawTextBuffer(SX + sx + font_width, SY + sy + font_height,
2269 level.envelope[envelope_nr].text, font_nr, max_xsize,
2270 xsize - 2, ysize - 2, 0, mask_mode,
2271 level.envelope[envelope_nr].autowrap,
2272 level.envelope[envelope_nr].centered, FALSE);
2276 DrawTextToTextArea(SX + sx + font_width, SY + sy + font_height,
2277 level.envelope[envelope_nr].text, font_nr, max_xsize,
2278 xsize - 2, ysize - 2, mask_mode);
2281 /* copy request gadgets to door backbuffer */
2283 if ((ysize - 2) > 13)
2284 BlitBitmap(bitmap_db_door, drawto,
2285 DOOR_GFX_PAGEX1 + (DXSIZE - (xsize - 2) * font_width) / 2,
2286 DOOR_GFX_PAGEY1 + 13 * font_height,
2287 (xsize - 2) * font_width,
2288 (ysize - 2 - 13) * font_height,
2289 SX + sx + font_width,
2290 SY + sy + font_height * (1 + 13));
2292 if ((ysize - 2) > 13)
2293 BlitBitmap(bitmap_db_door, drawto,
2294 DOOR_GFX_PAGEX1 + (DXSIZE - (xsize - 2) * font_width) / 2,
2295 DOOR_GFX_PAGEY1 + 13 * font_height,
2296 (xsize - 2) * font_width,
2297 (ysize - 2 - 13) * font_height,
2298 SX + sx + font_width,
2299 SY + sy + font_height * (1 + 13));
2303 redraw_mask = REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
2304 // redraw_mask |= REDRAW_ALL | REDRAW_FROM_BACKBUFFER;
2306 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
2316 WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
2324 void ShowEnvelope(int envelope_nr)
2326 int element = EL_ENVELOPE_1 + envelope_nr;
2327 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2328 int sound_opening = element_info[element].sound[ACTION_OPENING];
2329 int sound_closing = element_info[element].sound[ACTION_CLOSING];
2330 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2331 boolean no_delay = (tape.warp_forward);
2332 int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
2333 int wait_delay_value = (no_delay ? 0 : normal_delay_value);
2334 int anim_mode = graphic_info[graphic].anim_mode;
2335 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
2336 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
2338 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
2340 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
2342 if (anim_mode == ANIM_DEFAULT)
2343 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_OPENING);
2345 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_OPENING);
2348 Delay(wait_delay_value);
2350 WaitForEventToContinue();
2352 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
2354 if (anim_mode != ANIM_NONE)
2355 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_CLOSING);
2357 if (anim_mode == ANIM_DEFAULT)
2358 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_CLOSING);
2360 game.envelope_active = FALSE;
2362 SetDrawtoField(DRAW_BUFFERED);
2364 redraw_mask |= REDRAW_FIELD;
2368 void ShowEnvelopeDoor(char *text, int action)
2371 int last_game_status = game_status; /* save current game status */
2372 // int last_draw_background_mask = gfx.draw_background_mask;
2373 int envelope_nr = 0;
2375 int element = EL_ENVELOPE_1 + envelope_nr;
2376 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2377 int sound_opening = element_info[element].sound[ACTION_OPENING];
2378 int sound_closing = element_info[element].sound[ACTION_CLOSING];
2380 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2381 boolean no_delay = (tape.warp_forward);
2382 int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
2383 int wait_delay_value = (no_delay ? 0 : normal_delay_value);
2385 int anim_mode = graphic_info[graphic].anim_mode;
2386 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
2387 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
2390 if (game_status == GAME_MODE_PLAYING)
2392 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
2393 BlitScreenToBitmap_EM(backbuffer);
2394 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
2395 BlitScreenToBitmap_SP(backbuffer);
2398 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
2402 SetDrawtoField(DRAW_BACKBUFFER);
2404 // SetDrawBackgroundMask(REDRAW_NONE);
2406 if (action == ACTION_OPENING)
2408 BlitBitmap(backbuffer, bitmap_db_store, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2410 if (game_status != GAME_MODE_MAIN)
2414 /* force DOOR font inside door area */
2415 game_status = GAME_MODE_PSEUDO_DOOR;
2418 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
2420 if (action == ACTION_OPENING)
2422 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
2424 if (anim_mode == ANIM_DEFAULT)
2425 AnimateEnvelopeDoor(text, ANIM_DEFAULT, ACTION_OPENING);
2427 AnimateEnvelopeDoor(text, main_anim_mode, ACTION_OPENING);
2431 Delay(wait_delay_value);
2433 WaitForEventToContinue();
2438 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
2440 if (anim_mode != ANIM_NONE)
2441 AnimateEnvelopeDoor(text, main_anim_mode, ACTION_CLOSING);
2443 if (anim_mode == ANIM_DEFAULT)
2444 AnimateEnvelopeDoor(text, ANIM_DEFAULT, ACTION_CLOSING);
2447 game.envelope_active = FALSE;
2450 // game_status = last_game_status; /* restore current game status */
2452 if (action == ACTION_CLOSING)
2454 if (game_status != GAME_MODE_MAIN)
2457 BlitBitmap(bitmap_db_store, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2460 SetDrawtoField(DRAW_BUFFERED);
2463 // SetDrawBackgroundMask(last_draw_background_mask);
2466 redraw_mask = REDRAW_FIELD;
2467 // redraw_mask |= REDRAW_ALL;
2469 redraw_mask |= REDRAW_FIELD;
2473 if (game_status == GAME_MODE_MAIN)
2478 /* (important: after "BackToFront()", but before "SetDrawtoField()") */
2479 game_status = last_game_status; /* restore current game status */
2481 if (game_status == GAME_MODE_PLAYING &&
2482 level.game_engine_type == GAME_ENGINE_TYPE_RND)
2483 SetDrawtoField(DRAW_BUFFERED);
2489 void DrawPreviewElement(int dst_x, int dst_y, int element, int tilesize)
2493 int graphic = el2preimg(element);
2495 getSizedGraphicSource(graphic, 0, tilesize, &src_bitmap, &src_x, &src_y);
2496 BlitBitmap(src_bitmap, drawto, src_x, src_y, tilesize, tilesize, dst_x,dst_y);
2504 SetMainBackgroundImage(IMG_BACKGROUND_PLAYING);
2505 SetDrawBackgroundMask(REDRAW_FIELD);
2507 SetDrawBackgroundMask(REDRAW_NONE);
2512 for (x = BX1; x <= BX2; x++)
2513 for (y = BY1; y <= BY2; y++)
2514 DrawScreenField(x, y);
2516 redraw_mask |= REDRAW_FIELD;
2519 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
2523 for (x = 0; x < size_x; x++)
2524 for (y = 0; y < size_y; y++)
2525 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
2527 redraw_mask |= REDRAW_FIELD;
2530 static void DrawPreviewLevelExt(int from_x, int from_y)
2532 boolean show_level_border = (BorderElement != EL_EMPTY);
2533 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
2534 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
2535 int tile_size = preview.tile_size;
2536 int preview_width = preview.xsize * tile_size;
2537 int preview_height = preview.ysize * tile_size;
2538 int real_preview_xsize = MIN(level_xsize, preview.xsize);
2539 int real_preview_ysize = MIN(level_ysize, preview.ysize);
2540 int dst_x = SX + ALIGNED_XPOS(preview.x, preview_width, preview.align);
2541 int dst_y = SY + ALIGNED_YPOS(preview.y, preview_height, preview.valign);
2544 DrawBackground(dst_x, dst_y, preview_width, preview_height);
2546 dst_x += (preview_width - real_preview_xsize * tile_size) / 2;
2547 dst_y += (preview_height - real_preview_ysize * tile_size) / 2;
2549 for (x = 0; x < real_preview_xsize; x++)
2551 for (y = 0; y < real_preview_ysize; y++)
2553 int lx = from_x + x + (show_level_border ? -1 : 0);
2554 int ly = from_y + y + (show_level_border ? -1 : 0);
2555 int element = (IN_LEV_FIELD(lx, ly) ? level.field[lx][ly] :
2556 getBorderElement(lx, ly));
2558 DrawPreviewElement(dst_x + x * tile_size, dst_y + y * tile_size,
2559 element, tile_size);
2563 redraw_mask |= REDRAW_MICROLEVEL;
2566 #define MICROLABEL_EMPTY 0
2567 #define MICROLABEL_LEVEL_NAME 1
2568 #define MICROLABEL_LEVEL_AUTHOR_HEAD 2
2569 #define MICROLABEL_LEVEL_AUTHOR 3
2570 #define MICROLABEL_IMPORTED_FROM_HEAD 4
2571 #define MICROLABEL_IMPORTED_FROM 5
2572 #define MICROLABEL_IMPORTED_BY_HEAD 6
2573 #define MICROLABEL_IMPORTED_BY 7
2575 static int getMaxTextLength(struct TextPosInfo *pos, int font_nr)
2577 int max_text_width = SXSIZE;
2578 int font_width = getFontWidth(font_nr);
2580 if (pos->align == ALIGN_CENTER)
2581 max_text_width = (pos->x < SXSIZE / 2 ? pos->x * 2 : (SXSIZE - pos->x) * 2);
2582 else if (pos->align == ALIGN_RIGHT)
2583 max_text_width = pos->x;
2585 max_text_width = SXSIZE - pos->x;
2587 return max_text_width / font_width;
2590 static void DrawPreviewLevelLabelExt(int mode)
2592 struct TextPosInfo *pos = &menu.main.text.level_info_2;
2593 char label_text[MAX_OUTPUT_LINESIZE + 1];
2594 int max_len_label_text;
2596 int font_nr = pos->font;
2599 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
2600 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
2601 mode == MICROLABEL_IMPORTED_BY_HEAD)
2602 font_nr = pos->font_alt;
2604 int font_nr = FONT_TEXT_2;
2607 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
2608 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
2609 mode == MICROLABEL_IMPORTED_BY_HEAD)
2610 font_nr = FONT_TEXT_3;
2614 max_len_label_text = getMaxTextLength(pos, font_nr);
2616 max_len_label_text = SXSIZE / getFontWidth(font_nr);
2620 if (pos->size != -1)
2621 max_len_label_text = pos->size;
2624 for (i = 0; i < max_len_label_text; i++)
2625 label_text[i] = ' ';
2626 label_text[max_len_label_text] = '\0';
2628 if (strlen(label_text) > 0)
2631 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2633 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
2634 int lypos = MICROLABEL2_YPOS;
2636 DrawText(lxpos, lypos, label_text, font_nr);
2641 (mode == MICROLABEL_LEVEL_NAME ? level.name :
2642 mode == MICROLABEL_LEVEL_AUTHOR_HEAD ? "created by" :
2643 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
2644 mode == MICROLABEL_IMPORTED_FROM_HEAD ? "imported from" :
2645 mode == MICROLABEL_IMPORTED_FROM ? leveldir_current->imported_from :
2646 mode == MICROLABEL_IMPORTED_BY_HEAD ? "imported by" :
2647 mode == MICROLABEL_IMPORTED_BY ? leveldir_current->imported_by :""),
2648 max_len_label_text);
2649 label_text[max_len_label_text] = '\0';
2651 if (strlen(label_text) > 0)
2654 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2656 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
2657 int lypos = MICROLABEL2_YPOS;
2659 DrawText(lxpos, lypos, label_text, font_nr);
2663 redraw_mask |= REDRAW_MICROLEVEL;
2666 void DrawPreviewLevel(boolean restart)
2668 static unsigned long scroll_delay = 0;
2669 static unsigned long label_delay = 0;
2670 static int from_x, from_y, scroll_direction;
2671 static int label_state, label_counter;
2672 unsigned long scroll_delay_value = preview.step_delay;
2673 boolean show_level_border = (BorderElement != EL_EMPTY);
2674 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
2675 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
2676 int last_game_status = game_status; /* save current game status */
2679 /* force PREVIEW font on preview level */
2680 game_status = GAME_MODE_PSEUDO_PREVIEW;
2688 if (preview.anim_mode == ANIM_CENTERED)
2690 if (level_xsize > preview.xsize)
2691 from_x = (level_xsize - preview.xsize) / 2;
2692 if (level_ysize > preview.ysize)
2693 from_y = (level_ysize - preview.ysize) / 2;
2696 from_x += preview.xoffset;
2697 from_y += preview.yoffset;
2699 scroll_direction = MV_RIGHT;
2703 DrawPreviewLevelExt(from_x, from_y);
2704 DrawPreviewLevelLabelExt(label_state);
2706 /* initialize delay counters */
2707 DelayReached(&scroll_delay, 0);
2708 DelayReached(&label_delay, 0);
2710 if (leveldir_current->name)
2712 struct TextPosInfo *pos = &menu.main.text.level_info_1;
2713 char label_text[MAX_OUTPUT_LINESIZE + 1];
2715 int font_nr = pos->font;
2717 int font_nr = FONT_TEXT_1;
2720 int max_len_label_text = getMaxTextLength(pos, font_nr);
2722 int max_len_label_text = SXSIZE / getFontWidth(font_nr);
2730 if (pos->size != -1)
2731 max_len_label_text = pos->size;
2734 strncpy(label_text, leveldir_current->name, max_len_label_text);
2735 label_text[max_len_label_text] = '\0';
2738 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2740 lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
2741 lypos = SY + MICROLABEL1_YPOS;
2743 DrawText(lxpos, lypos, label_text, font_nr);
2747 game_status = last_game_status; /* restore current game status */
2752 /* scroll preview level, if needed */
2753 if (preview.anim_mode != ANIM_NONE &&
2754 (level_xsize > preview.xsize || level_ysize > preview.ysize) &&
2755 DelayReached(&scroll_delay, scroll_delay_value))
2757 switch (scroll_direction)
2762 from_x -= preview.step_offset;
2763 from_x = (from_x < 0 ? 0 : from_x);
2766 scroll_direction = MV_UP;
2770 if (from_x < level_xsize - preview.xsize)
2772 from_x += preview.step_offset;
2773 from_x = (from_x > level_xsize - preview.xsize ?
2774 level_xsize - preview.xsize : from_x);
2777 scroll_direction = MV_DOWN;
2783 from_y -= preview.step_offset;
2784 from_y = (from_y < 0 ? 0 : from_y);
2787 scroll_direction = MV_RIGHT;
2791 if (from_y < level_ysize - preview.ysize)
2793 from_y += preview.step_offset;
2794 from_y = (from_y > level_ysize - preview.ysize ?
2795 level_ysize - preview.ysize : from_y);
2798 scroll_direction = MV_LEFT;
2805 DrawPreviewLevelExt(from_x, from_y);
2808 /* !!! THIS ALL SUCKS -- SHOULD BE CLEANLY REWRITTEN !!! */
2809 /* redraw micro level label, if needed */
2810 if (!strEqual(level.name, NAMELESS_LEVEL_NAME) &&
2811 !strEqual(level.author, ANONYMOUS_NAME) &&
2812 !strEqual(level.author, leveldir_current->name) &&
2813 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
2815 int max_label_counter = 23;
2817 if (leveldir_current->imported_from != NULL &&
2818 strlen(leveldir_current->imported_from) > 0)
2819 max_label_counter += 14;
2820 if (leveldir_current->imported_by != NULL &&
2821 strlen(leveldir_current->imported_by) > 0)
2822 max_label_counter += 14;
2824 label_counter = (label_counter + 1) % max_label_counter;
2825 label_state = (label_counter >= 0 && label_counter <= 7 ?
2826 MICROLABEL_LEVEL_NAME :
2827 label_counter >= 9 && label_counter <= 12 ?
2828 MICROLABEL_LEVEL_AUTHOR_HEAD :
2829 label_counter >= 14 && label_counter <= 21 ?
2830 MICROLABEL_LEVEL_AUTHOR :
2831 label_counter >= 23 && label_counter <= 26 ?
2832 MICROLABEL_IMPORTED_FROM_HEAD :
2833 label_counter >= 28 && label_counter <= 35 ?
2834 MICROLABEL_IMPORTED_FROM :
2835 label_counter >= 37 && label_counter <= 40 ?
2836 MICROLABEL_IMPORTED_BY_HEAD :
2837 label_counter >= 42 && label_counter <= 49 ?
2838 MICROLABEL_IMPORTED_BY : MICROLABEL_EMPTY);
2840 if (leveldir_current->imported_from == NULL &&
2841 (label_state == MICROLABEL_IMPORTED_FROM_HEAD ||
2842 label_state == MICROLABEL_IMPORTED_FROM))
2843 label_state = (label_state == MICROLABEL_IMPORTED_FROM_HEAD ?
2844 MICROLABEL_IMPORTED_BY_HEAD : MICROLABEL_IMPORTED_BY);
2846 DrawPreviewLevelLabelExt(label_state);
2849 game_status = last_game_status; /* restore current game status */
2852 inline void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
2853 int graphic, int sync_frame, int mask_mode)
2855 int frame = getGraphicAnimationFrame(graphic, sync_frame);
2857 if (mask_mode == USE_MASKING)
2858 DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
2860 DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
2863 inline void DrawGraphicAnimation(int x, int y, int graphic)
2865 int lx = LEVELX(x), ly = LEVELY(y);
2867 if (!IN_SCR_FIELD(x, y))
2870 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
2871 graphic, GfxFrame[lx][ly], NO_MASKING);
2872 MarkTileDirty(x, y);
2875 void DrawLevelGraphicAnimation(int x, int y, int graphic)
2877 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
2880 void DrawLevelElementAnimation(int x, int y, int element)
2882 int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
2884 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
2887 inline void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
2889 int sx = SCREENX(x), sy = SCREENY(y);
2891 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
2894 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
2897 DrawGraphicAnimation(sx, sy, graphic);
2900 if (GFX_CRUMBLED(TILE_GFX_ELEMENT(x, y)))
2901 DrawLevelFieldCrumbled(x, y);
2903 if (GFX_CRUMBLED(Feld[x][y]))
2904 DrawLevelFieldCrumbled(x, y);
2908 void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
2910 int sx = SCREENX(x), sy = SCREENY(y);
2913 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
2916 graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
2918 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
2921 DrawGraphicAnimation(sx, sy, graphic);
2923 if (GFX_CRUMBLED(element))
2924 DrawLevelFieldCrumbled(x, y);
2927 static int getPlayerGraphic(struct PlayerInfo *player, int move_dir)
2929 if (player->use_murphy)
2931 /* this works only because currently only one player can be "murphy" ... */
2932 static int last_horizontal_dir = MV_LEFT;
2933 int graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir);
2935 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
2936 last_horizontal_dir = move_dir;
2938 if (graphic == IMG_SP_MURPHY) /* undefined => use special graphic */
2940 int direction = (player->is_snapping ? move_dir : last_horizontal_dir);
2942 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
2948 return el_act_dir2img(player->artwork_element, player->GfxAction,move_dir);
2951 static boolean equalGraphics(int graphic1, int graphic2)
2953 struct GraphicInfo *g1 = &graphic_info[graphic1];
2954 struct GraphicInfo *g2 = &graphic_info[graphic2];
2956 return (g1->bitmap == g2->bitmap &&
2957 g1->src_x == g2->src_x &&
2958 g1->src_y == g2->src_y &&
2959 g1->anim_frames == g2->anim_frames &&
2960 g1->anim_delay == g2->anim_delay &&
2961 g1->anim_mode == g2->anim_mode);
2964 void DrawAllPlayers()
2968 for (i = 0; i < MAX_PLAYERS; i++)
2969 if (stored_player[i].active)
2970 DrawPlayer(&stored_player[i]);
2973 void DrawPlayerField(int x, int y)
2975 if (!IS_PLAYER(x, y))
2978 DrawPlayer(PLAYERINFO(x, y));
2981 #define DRAW_PLAYER_OVER_PUSHED_ELEMENT 1
2983 void DrawPlayer(struct PlayerInfo *player)
2985 int jx = player->jx;
2986 int jy = player->jy;
2987 int move_dir = player->MovDir;
2988 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? +1 : 0);
2989 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? +1 : 0);
2990 int last_jx = (player->is_moving ? jx - dx : jx);
2991 int last_jy = (player->is_moving ? jy - dy : jy);
2992 int next_jx = jx + dx;
2993 int next_jy = jy + dy;
2994 boolean player_is_moving = (player->MovPos ? TRUE : FALSE);
2995 boolean player_is_opaque = FALSE;
2996 int sx = SCREENX(jx), sy = SCREENY(jy);
2997 int sxx = 0, syy = 0;
2998 int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
3000 int action = ACTION_DEFAULT;
3001 int last_player_graphic = getPlayerGraphic(player, move_dir);
3002 int last_player_frame = player->Frame;
3005 /* GfxElement[][] is set to the element the player is digging or collecting;
3006 remove also for off-screen player if the player is not moving anymore */
3007 if (IN_LEV_FIELD(jx, jy) && !player_is_moving)
3008 GfxElement[jx][jy] = EL_UNDEFINED;
3010 if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
3014 if (!IN_LEV_FIELD(jx, jy))
3016 printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
3017 printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
3018 printf("DrawPlayerField(): This should never happen!\n");
3023 if (element == EL_EXPLOSION)
3026 action = (player->is_pushing ? ACTION_PUSHING :
3027 player->is_digging ? ACTION_DIGGING :
3028 player->is_collecting ? ACTION_COLLECTING :
3029 player->is_moving ? ACTION_MOVING :
3030 player->is_snapping ? ACTION_SNAPPING :
3031 player->is_dropping ? ACTION_DROPPING :
3032 player->is_waiting ? player->action_waiting : ACTION_DEFAULT);
3034 if (player->is_waiting)
3035 move_dir = player->dir_waiting;
3037 InitPlayerGfxAnimation(player, action, move_dir);
3039 /* ----------------------------------------------------------------------- */
3040 /* draw things in the field the player is leaving, if needed */
3041 /* ----------------------------------------------------------------------- */
3043 if (player->is_moving)
3045 if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
3047 DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
3049 if (last_element == EL_DYNAMITE_ACTIVE ||
3050 last_element == EL_EM_DYNAMITE_ACTIVE ||
3051 last_element == EL_SP_DISK_RED_ACTIVE)
3052 DrawDynamite(last_jx, last_jy);
3054 DrawLevelFieldThruMask(last_jx, last_jy);
3056 else if (last_element == EL_DYNAMITE_ACTIVE ||
3057 last_element == EL_EM_DYNAMITE_ACTIVE ||
3058 last_element == EL_SP_DISK_RED_ACTIVE)
3059 DrawDynamite(last_jx, last_jy);
3061 /* !!! this is not enough to prevent flickering of players which are
3062 moving next to each others without a free tile between them -- this
3063 can only be solved by drawing all players layer by layer (first the
3064 background, then the foreground etc.) !!! => TODO */
3065 else if (!IS_PLAYER(last_jx, last_jy))
3066 DrawLevelField(last_jx, last_jy);
3069 DrawLevelField(last_jx, last_jy);
3072 if (player->is_pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
3073 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
3076 if (!IN_SCR_FIELD(sx, sy))
3079 /* ----------------------------------------------------------------------- */
3080 /* draw things behind the player, if needed */
3081 /* ----------------------------------------------------------------------- */
3084 DrawLevelElement(jx, jy, Back[jx][jy]);
3085 else if (IS_ACTIVE_BOMB(element))
3086 DrawLevelElement(jx, jy, EL_EMPTY);
3089 if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
3091 int old_element = GfxElement[jx][jy];
3092 int old_graphic = el_act_dir2img(old_element, action, move_dir);
3093 int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
3095 if (GFX_CRUMBLED(old_element))
3096 DrawLevelFieldCrumbledDigging(jx, jy, move_dir, player->StepFrame);
3098 DrawGraphic(sx, sy, old_graphic, frame);
3100 if (graphic_info[old_graphic].anim_mode & ANIM_OPAQUE_PLAYER)
3101 player_is_opaque = TRUE;
3105 GfxElement[jx][jy] = EL_UNDEFINED;
3107 /* make sure that pushed elements are drawn with correct frame rate */
3109 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
3111 if (player->is_pushing && player->is_moving && !IS_ANIM_MODE_CE(graphic))
3112 GfxFrame[jx][jy] = player->StepFrame;
3114 if (player->is_pushing && player->is_moving)
3115 GfxFrame[jx][jy] = player->StepFrame;
3118 DrawLevelField(jx, jy);
3122 #if !DRAW_PLAYER_OVER_PUSHED_ELEMENT
3123 /* ----------------------------------------------------------------------- */
3124 /* draw player himself */
3125 /* ----------------------------------------------------------------------- */
3127 graphic = getPlayerGraphic(player, move_dir);
3129 /* in the case of changed player action or direction, prevent the current
3130 animation frame from being restarted for identical animations */
3131 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
3132 player->Frame = last_player_frame;
3134 frame = getGraphicAnimationFrame(graphic, player->Frame);
3138 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3139 sxx = player->GfxPos;
3141 syy = player->GfxPos;
3144 if (!setup.soft_scrolling && ScreenMovPos)
3147 if (player_is_opaque)
3148 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
3150 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3152 if (SHIELD_ON(player))
3154 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
3155 IMG_SHIELD_NORMAL_ACTIVE);
3156 int frame = getGraphicAnimationFrame(graphic, -1);
3158 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3162 #if DRAW_PLAYER_OVER_PUSHED_ELEMENT
3165 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3166 sxx = player->GfxPos;
3168 syy = player->GfxPos;
3172 /* ----------------------------------------------------------------------- */
3173 /* draw things the player is pushing, if needed */
3174 /* ----------------------------------------------------------------------- */
3177 printf("::: %d, %d [%d, %d] [%d]\n",
3178 player->is_pushing, player_is_moving, player->GfxAction,
3179 player->is_moving, player_is_moving);
3183 if (player->is_pushing && player->is_moving)
3185 int px = SCREENX(jx), py = SCREENY(jy);
3186 int pxx = (TILEX - ABS(sxx)) * dx;
3187 int pyy = (TILEY - ABS(syy)) * dy;
3188 int gfx_frame = GfxFrame[jx][jy];
3194 if (!IS_MOVING(jx, jy)) /* push movement already finished */
3196 element = Feld[next_jx][next_jy];
3197 gfx_frame = GfxFrame[next_jx][next_jy];
3200 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
3203 sync_frame = (IS_ANIM_MODE_CE(graphic) ? gfx_frame : player->StepFrame);
3204 frame = getGraphicAnimationFrame(graphic, sync_frame);
3206 frame = getGraphicAnimationFrame(graphic, player->StepFrame);
3209 /* draw background element under pushed element (like the Sokoban field) */
3211 if (game.use_masked_pushing && IS_MOVING(jx, jy))
3213 /* this allows transparent pushing animation over non-black background */
3216 DrawLevelElement(jx, jy, Back[jx][jy]);
3218 DrawLevelElement(jx, jy, EL_EMPTY);
3220 if (Back[next_jx][next_jy])
3221 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
3223 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
3225 else if (Back[next_jx][next_jy])
3226 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
3228 if (Back[next_jx][next_jy])
3229 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
3233 printf("::: %d, %d, %d, %d [%d] [%d, %d, %d] [%d] [%d, %d] [%d, %d]\n",
3234 jx, px, player->GfxPos, player->StepFrame,
3239 GfxFrame[jx][jy], GfxFrame[next_jx][next_jy]);
3243 /* do not draw (EM style) pushing animation when pushing is finished */
3244 /* (two-tile animations usually do not contain start and end frame) */
3245 if (graphic_info[graphic].double_movement && !IS_MOVING(jx, jy))
3246 DrawLevelElement(next_jx, next_jy, Feld[next_jx][next_jy]);
3248 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
3250 /* masked drawing is needed for EMC style (double) movement graphics */
3251 /* !!! (ONLY WHEN DRAWING PUSHED ELEMENT OVER THE PLAYER) !!! */
3252 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
3257 #if DRAW_PLAYER_OVER_PUSHED_ELEMENT
3258 /* ----------------------------------------------------------------------- */
3259 /* draw player himself */
3260 /* ----------------------------------------------------------------------- */
3262 graphic = getPlayerGraphic(player, move_dir);
3264 /* in the case of changed player action or direction, prevent the current
3265 animation frame from being restarted for identical animations */
3266 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
3267 player->Frame = last_player_frame;
3269 frame = getGraphicAnimationFrame(graphic, player->Frame);
3273 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3274 sxx = player->GfxPos;
3276 syy = player->GfxPos;
3279 if (!setup.soft_scrolling && ScreenMovPos)
3282 if (player_is_opaque)
3283 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
3285 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3287 if (SHIELD_ON(player))
3289 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
3290 IMG_SHIELD_NORMAL_ACTIVE);
3291 int frame = getGraphicAnimationFrame(graphic, -1);
3293 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3297 /* ----------------------------------------------------------------------- */
3298 /* draw things in front of player (active dynamite or dynabombs) */
3299 /* ----------------------------------------------------------------------- */
3301 if (IS_ACTIVE_BOMB(element))
3303 graphic = el2img(element);
3304 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
3306 if (game.emulation == EMU_SUPAPLEX)
3307 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
3309 DrawGraphicThruMask(sx, sy, graphic, frame);
3312 if (player_is_moving && last_element == EL_EXPLOSION)
3314 int element = (GfxElement[last_jx][last_jy] != EL_UNDEFINED ?
3315 GfxElement[last_jx][last_jy] : EL_EMPTY);
3316 int graphic = el_act2img(element, ACTION_EXPLODING);
3317 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
3318 int phase = ExplodePhase[last_jx][last_jy] - 1;
3319 int frame = getGraphicAnimationFrame(graphic, phase - delay);
3322 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
3325 /* ----------------------------------------------------------------------- */
3326 /* draw elements the player is just walking/passing through/under */
3327 /* ----------------------------------------------------------------------- */
3329 if (player_is_moving)
3331 /* handle the field the player is leaving ... */
3332 if (IS_ACCESSIBLE_INSIDE(last_element))
3333 DrawLevelField(last_jx, last_jy);
3334 else if (IS_ACCESSIBLE_UNDER(last_element))
3335 DrawLevelFieldThruMask(last_jx, last_jy);
3338 /* do not redraw accessible elements if the player is just pushing them */
3339 if (!player_is_moving || !player->is_pushing)
3341 /* ... and the field the player is entering */
3342 if (IS_ACCESSIBLE_INSIDE(element))
3343 DrawLevelField(jx, jy);
3344 else if (IS_ACCESSIBLE_UNDER(element))
3345 DrawLevelFieldThruMask(jx, jy);
3348 MarkTileDirty(sx, sy);
3351 /* ------------------------------------------------------------------------- */
3353 void WaitForEventToContinue()
3355 boolean still_wait = TRUE;
3357 /* simulate releasing mouse button over last gadget, if still pressed */
3359 HandleGadgets(-1, -1, 0);
3361 button_status = MB_RELEASED;
3377 case EVENT_BUTTONPRESS:
3378 case EVENT_KEYPRESS:
3382 case EVENT_KEYRELEASE:
3383 ClearPlayerAction();
3387 HandleOtherEvents(&event);
3391 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
3398 /* don't eat all CPU time */
3403 #define MAX_REQUEST_LINES 13
3404 #define MAX_REQUEST_LINE_FONT1_LEN 7
3405 #define MAX_REQUEST_LINE_FONT2_LEN 10
3407 boolean Request(char *text, unsigned int req_state)
3409 int mx, my, ty, result = -1;
3410 unsigned int old_door_state;
3411 int last_game_status = game_status; /* save current game status */
3412 int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
3413 int font_nr = FONT_TEXT_2;
3415 int max_word_len = 0;
3420 global.use_envelope_request = TRUE * 1;
3423 if (maxWordLengthInString(text) > MAX_REQUEST_LINE_FONT1_LEN)
3425 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
3426 font_nr = FONT_TEXT_1;
3429 for (text_ptr = text; *text_ptr; text_ptr++)
3431 max_word_len = (*text_ptr != ' ' ? max_word_len + 1 : 0);
3433 if (max_word_len > MAX_REQUEST_LINE_FONT1_LEN)
3435 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
3437 font_nr = FONT_TEXT_1;
3439 font_nr = FONT_LEVEL_NUMBER;
3447 if (game_status == GAME_MODE_PLAYING)
3449 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
3450 BlitScreenToBitmap_EM(backbuffer);
3451 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
3452 BlitScreenToBitmap_SP(backbuffer);
3455 /* disable deactivated drawing when quick-loading level tape recording */
3456 if (tape.playing && tape.deactivate_display)
3457 TapeDeactivateDisplayOff(TRUE);
3459 SetMouseCursor(CURSOR_DEFAULT);
3461 #if defined(NETWORK_AVALIABLE)
3462 /* pause network game while waiting for request to answer */
3463 if (options.network &&
3464 game_status == GAME_MODE_PLAYING &&
3465 req_state & REQUEST_WAIT_FOR_INPUT)
3466 SendToServer_PausePlaying();
3469 old_door_state = GetDoorState();
3471 /* simulate releasing mouse button over last gadget, if still pressed */
3473 HandleGadgets(-1, -1, 0);
3477 /* draw released gadget before proceeding */
3481 if (old_door_state & DOOR_OPEN_1 && !global.use_envelope_request)
3483 if (old_door_state & DOOR_OPEN_1)
3487 if (!global.use_envelope_request)
3488 CloseDoor(DOOR_CLOSE_1);
3490 CloseDoor(DOOR_CLOSE_1);
3493 /* save old door content */
3494 BlitBitmap(bitmap_db_door, bitmap_db_door,
3495 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
3496 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
3500 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
3503 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3505 /* clear door drawing field */
3506 DrawBackground(DX, DY, DXSIZE, DYSIZE);
3508 /* force DOOR font inside door area */
3509 game_status = GAME_MODE_PSEUDO_DOOR;
3511 /* write text for request */
3512 for (text_ptr = text, ty = 0; ty < MAX_REQUEST_LINES; ty++)
3514 char text_line[max_request_line_len + 1];
3520 for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
3522 tc = *(text_ptr + tx);
3523 if (!tc || tc == ' ')
3534 strncpy(text_line, text_ptr, tl);
3537 DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
3538 DY + 8 + ty * (getFontHeight(font_nr) + 2),
3539 text_line, font_nr);
3541 text_ptr += tl + (tc == ' ' ? 1 : 0);
3544 game_status = last_game_status; /* restore current game status */
3547 if (global.use_envelope_request)
3551 CreateToolButtons();
3555 if (req_state & REQ_ASK)
3557 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
3558 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
3560 else if (req_state & REQ_CONFIRM)
3562 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
3564 else if (req_state & REQ_PLAYER)
3566 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
3567 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
3568 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
3569 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
3572 /* copy request gadgets to door backbuffer */
3573 BlitBitmap(drawto, bitmap_db_door,
3574 DX, DY, DXSIZE, DYSIZE,
3575 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
3578 if (global.use_envelope_request)
3580 ShowEnvelopeDoor(text, ACTION_OPENING);
3582 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3584 if ((req_state & REQ_ASK && (i == TOOL_CTRL_ID_YES ||
3585 i == TOOL_CTRL_ID_NO)) ||
3586 (req_state & REQ_CONFIRM && i == TOOL_CTRL_ID_CONFIRM) ||
3587 (req_state & REQ_PLAYER && (i == TOOL_CTRL_ID_PLAYER_1 &&
3588 i == TOOL_CTRL_ID_PLAYER_2 &&
3589 i == TOOL_CTRL_ID_PLAYER_3 &&
3590 i == TOOL_CTRL_ID_PLAYER_4)))
3592 int x = tool_gadget[i]->x + dDX;
3593 int y = tool_gadget[i]->y + dDY;
3595 ModifyGadget(tool_gadget[i], GDI_X, x, GDI_Y, y, GDI_END);
3602 if (!global.use_envelope_request)
3603 OpenDoor(DOOR_OPEN_1);
3605 OpenDoor(DOOR_OPEN_1);
3608 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
3610 if (game_status == GAME_MODE_PLAYING)
3612 SetPanelBackground();
3613 SetDrawBackgroundMask(REDRAW_DOOR_1);
3617 SetDrawBackgroundMask(REDRAW_FIELD);
3624 if (game_status != GAME_MODE_MAIN && !global.use_envelope_request)
3627 if (game_status != GAME_MODE_MAIN)
3631 button_status = MB_RELEASED;
3633 request_gadget_id = -1;
3635 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3647 case EVENT_BUTTONPRESS:
3648 case EVENT_BUTTONRELEASE:
3649 case EVENT_MOTIONNOTIFY:
3651 if (event.type == EVENT_MOTIONNOTIFY)
3653 if (!PointerInWindow(window))
3654 continue; /* window and pointer are on different screens */
3659 motion_status = TRUE;
3660 mx = ((MotionEvent *) &event)->x;
3661 my = ((MotionEvent *) &event)->y;
3665 motion_status = FALSE;
3666 mx = ((ButtonEvent *) &event)->x;
3667 my = ((ButtonEvent *) &event)->y;
3668 if (event.type == EVENT_BUTTONPRESS)
3669 button_status = ((ButtonEvent *) &event)->button;
3671 button_status = MB_RELEASED;
3674 /* this sets 'request_gadget_id' */
3675 HandleGadgets(mx, my, button_status);
3677 switch (request_gadget_id)
3679 case TOOL_CTRL_ID_YES:
3682 case TOOL_CTRL_ID_NO:
3685 case TOOL_CTRL_ID_CONFIRM:
3686 result = TRUE | FALSE;
3689 case TOOL_CTRL_ID_PLAYER_1:
3692 case TOOL_CTRL_ID_PLAYER_2:
3695 case TOOL_CTRL_ID_PLAYER_3:
3698 case TOOL_CTRL_ID_PLAYER_4:
3709 case EVENT_KEYPRESS:
3710 switch (GetEventKey((KeyEvent *)&event, TRUE))
3713 if (req_state & REQ_CONFIRM)
3729 if (req_state & REQ_PLAYER)
3733 case EVENT_KEYRELEASE:
3734 ClearPlayerAction();
3738 HandleOtherEvents(&event);
3742 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
3744 int joy = AnyJoystick();
3746 if (joy & JOY_BUTTON_1)
3748 else if (joy & JOY_BUTTON_2)
3754 if (game_status == GAME_MODE_PLAYING && local_player->LevelSolved_GameEnd)
3756 HandleGameActions();
3762 if (!PendingEvent()) /* delay only if no pending events */
3767 game_status = GAME_MODE_PSEUDO_DOOR;
3773 game_status = last_game_status; /* restore current game status */
3781 if (!PendingEvent()) /* delay only if no pending events */
3784 /* don't eat all CPU time */
3791 if (game_status != GAME_MODE_MAIN)
3797 if (global.use_envelope_request)
3798 ShowEnvelopeDoor(text, ACTION_CLOSING);
3802 if (!(req_state & REQ_STAY_OPEN) && !global.use_envelope_request)
3804 if (!(req_state & REQ_STAY_OPEN))
3807 CloseDoor(DOOR_CLOSE_1);
3809 if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
3810 (req_state & REQ_REOPEN))
3811 OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
3816 if (game_status == GAME_MODE_PLAYING)
3818 SetPanelBackground();
3819 SetDrawBackgroundMask(REDRAW_DOOR_1);
3823 SetDrawBackgroundMask(REDRAW_FIELD);
3826 #if defined(NETWORK_AVALIABLE)
3827 /* continue network game after request */
3828 if (options.network &&
3829 game_status == GAME_MODE_PLAYING &&
3830 req_state & REQUEST_WAIT_FOR_INPUT)
3831 SendToServer_ContinuePlaying();
3834 /* restore deactivated drawing when quick-loading level tape recording */
3835 if (tape.playing && tape.deactivate_display)
3836 TapeDeactivateDisplayOn();
3841 unsigned int OpenDoor(unsigned int door_state)
3843 if (door_state & DOOR_COPY_BACK)
3845 if (door_state & DOOR_OPEN_1)
3846 BlitBitmap(bitmap_db_door, bitmap_db_door,
3847 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
3848 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
3850 if (door_state & DOOR_OPEN_2)
3851 BlitBitmap(bitmap_db_door, bitmap_db_door,
3852 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY2, VXSIZE, VYSIZE,
3853 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
3855 door_state &= ~DOOR_COPY_BACK;
3858 return MoveDoor(door_state);
3861 unsigned int CloseDoor(unsigned int door_state)
3863 unsigned int old_door_state = GetDoorState();
3865 if (!(door_state & DOOR_NO_COPY_BACK))
3867 if (old_door_state & DOOR_OPEN_1)
3868 BlitBitmap(backbuffer, bitmap_db_door,
3869 DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
3871 if (old_door_state & DOOR_OPEN_2)
3872 BlitBitmap(backbuffer, bitmap_db_door,
3873 VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
3875 door_state &= ~DOOR_NO_COPY_BACK;
3878 return MoveDoor(door_state);
3881 unsigned int GetDoorState()
3883 return MoveDoor(DOOR_GET_STATE);
3886 unsigned int SetDoorState(unsigned int door_state)
3888 return MoveDoor(door_state | DOOR_SET_STATE);
3891 unsigned int MoveDoor(unsigned int door_state)
3893 static int door1 = DOOR_OPEN_1;
3894 static int door2 = DOOR_CLOSE_2;
3895 unsigned long door_delay = 0;
3896 unsigned long door_delay_value;
3899 if (door_1.width < 0 || door_1.width > DXSIZE)
3900 door_1.width = DXSIZE;
3901 if (door_1.height < 0 || door_1.height > DYSIZE)
3902 door_1.height = DYSIZE;
3903 if (door_2.width < 0 || door_2.width > VXSIZE)
3904 door_2.width = VXSIZE;
3905 if (door_2.height < 0 || door_2.height > VYSIZE)
3906 door_2.height = VYSIZE;
3908 if (door_state == DOOR_GET_STATE)
3909 return (door1 | door2);
3911 if (door_state & DOOR_SET_STATE)
3913 if (door_state & DOOR_ACTION_1)
3914 door1 = door_state & DOOR_ACTION_1;
3915 if (door_state & DOOR_ACTION_2)
3916 door2 = door_state & DOOR_ACTION_2;
3918 return (door1 | door2);
3921 if (!(door_state & DOOR_FORCE_REDRAW))
3923 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
3924 door_state &= ~DOOR_OPEN_1;
3925 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
3926 door_state &= ~DOOR_CLOSE_1;
3927 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
3928 door_state &= ~DOOR_OPEN_2;
3929 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
3930 door_state &= ~DOOR_CLOSE_2;
3933 door_delay_value = (door_state & DOOR_ACTION_1 ? door_1.step_delay :
3936 if (setup.quick_doors)
3938 stepsize = 20; /* must be chosen to always draw last frame */
3939 door_delay_value = 0;
3942 if (global.autoplay_leveldir)
3944 door_state |= DOOR_NO_DELAY;
3945 door_state &= ~DOOR_CLOSE_ALL;
3949 if (game_status == GAME_MODE_EDITOR)
3950 door_state |= DOOR_NO_DELAY;
3953 if (door_state & DOOR_ACTION)
3955 boolean handle_door_1 = (door_state & DOOR_ACTION_1);
3956 boolean handle_door_2 = (door_state & DOOR_ACTION_2);
3957 boolean door_1_done = (!handle_door_1);
3958 boolean door_2_done = (!handle_door_2);
3959 boolean door_1_vertical = (door_1.anim_mode & ANIM_VERTICAL);
3960 boolean door_2_vertical = (door_2.anim_mode & ANIM_VERTICAL);
3961 int door_size_1 = (door_1_vertical ? door_1.height : door_1.width);
3962 int door_size_2 = (door_2_vertical ? door_2.height : door_2.width);
3963 int max_door_size_1 = (door_1_vertical ? DYSIZE : DXSIZE);
3964 int max_door_size_2 = (door_2_vertical ? VYSIZE : VXSIZE);
3965 int door_size = (handle_door_1 ? door_size_1 : door_size_2);
3966 int max_door_size = (handle_door_1 ? max_door_size_1 : max_door_size_2);
3967 int door_skip = max_door_size - door_size;
3968 int end = door_size;
3969 int start = ((door_state & DOOR_NO_DELAY) ? end : 0);
3972 if (!(door_state & DOOR_NO_DELAY) && !setup.quick_doors)
3974 /* opening door sound has priority over simultaneously closing door */
3975 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
3976 PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
3977 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
3978 PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
3981 for (k = start; k <= end && !(door_1_done && door_2_done); k += stepsize)
3984 Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
3985 GC gc = bitmap->stored_clip_gc;
3987 if (door_state & DOOR_ACTION_1)
3989 int a = MIN(x * door_1.step_offset, end);
3990 int p = (door_state & DOOR_OPEN_1 ? end - a : a);
3991 int i = p + door_skip;
3993 if (door_1.anim_mode & ANIM_STATIC_PANEL)
3995 BlitBitmap(bitmap_db_door, drawto,
3996 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1,
3997 DXSIZE, DYSIZE, DX, DY);
4001 BlitBitmap(bitmap_db_door, drawto,
4002 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + p / 2,
4003 DXSIZE, DYSIZE - p / 2, DX, DY);
4005 ClearRectangle(drawto, DX, DY + DYSIZE - p / 2, DXSIZE, p / 2);
4008 if (door_1.anim_mode & ANIM_HORIZONTAL && x <= DXSIZE)
4010 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
4011 int dst1_x = DX + DXSIZE - i, dst1_y = DY;
4012 int src2_x = DXSIZE - i, src2_y = DOOR_GFX_PAGEY1;
4013 int dst2_x = DX, dst2_y = DY;
4014 int width = i, height = DYSIZE;
4016 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
4017 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
4020 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
4021 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
4024 else if (door_1.anim_mode & ANIM_VERTICAL && x <= DYSIZE)
4026 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
4027 int dst1_x = DX, dst1_y = DY + DYSIZE - i;
4028 int src2_x = 0, src2_y = DOOR_GFX_PAGEY1 + DYSIZE - i;
4029 int dst2_x = DX, dst2_y = DY;
4030 int width = DXSIZE, height = i;
4032 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
4033 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
4036 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
4037 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
4040 else if (x <= DXSIZE) /* ANIM_DEFAULT */
4042 int j = (door_1.anim_mode == ANIM_DEFAULT ? (DXSIZE - i) / 3 : 0);
4044 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
4045 BlitBitmapMasked(bitmap, drawto,
4046 DXSIZE, DOOR_GFX_PAGEY1, i, 77,
4047 DX + DXSIZE - i, DY + j);
4048 BlitBitmapMasked(bitmap, drawto,
4049 DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
4050 DX + DXSIZE - i, DY + 140 + j);
4051 SetClipOrigin(bitmap, gc, DX - DXSIZE + i,
4052 DY - (DOOR_GFX_PAGEY1 + j));
4053 BlitBitmapMasked(bitmap, drawto,
4054 DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
4056 BlitBitmapMasked(bitmap, drawto,
4057 DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
4060 BlitBitmapMasked(bitmap, drawto,
4061 DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
4063 BlitBitmapMasked(bitmap, drawto,
4064 DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
4066 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
4067 BlitBitmapMasked(bitmap, drawto,
4068 DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
4069 DX + DXSIZE - i, DY + 77 + j);
4070 BlitBitmapMasked(bitmap, drawto,
4071 DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
4072 DX + DXSIZE - i, DY + 203 + j);
4075 redraw_mask |= REDRAW_DOOR_1;
4076 door_1_done = (a == end);
4079 if (door_state & DOOR_ACTION_2)
4081 int a = MIN(x * door_2.step_offset, door_size);
4082 int p = (door_state & DOOR_OPEN_2 ? door_size - a : a);
4083 int i = p + door_skip;
4085 if (door_2.anim_mode & ANIM_STATIC_PANEL)
4087 BlitBitmap(bitmap_db_door, drawto,
4088 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2,
4089 VXSIZE, VYSIZE, VX, VY);
4091 else if (x <= VYSIZE)
4093 BlitBitmap(bitmap_db_door, drawto,
4094 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + p / 2,
4095 VXSIZE, VYSIZE - p / 2, VX, VY);
4097 ClearRectangle(drawto, VX, VY + VYSIZE - p / 2, VXSIZE, p / 2);
4100 if (door_2.anim_mode & ANIM_HORIZONTAL && x <= VXSIZE)
4102 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
4103 int dst1_x = VX + VXSIZE - i, dst1_y = VY;
4104 int src2_x = VXSIZE - i, src2_y = DOOR_GFX_PAGEY2;
4105 int dst2_x = VX, dst2_y = VY;
4106 int width = i, height = VYSIZE;
4108 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
4109 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
4112 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
4113 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
4116 else if (door_2.anim_mode & ANIM_VERTICAL && x <= VYSIZE)
4118 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
4119 int dst1_x = VX, dst1_y = VY + VYSIZE - i;
4120 int src2_x = 0, src2_y = DOOR_GFX_PAGEY2 + VYSIZE - i;
4121 int dst2_x = VX, dst2_y = VY;
4122 int width = VXSIZE, height = i;
4124 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
4125 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
4128 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
4129 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
4132 else if (x <= VXSIZE) /* ANIM_DEFAULT */
4134 int j = (door_2.anim_mode == ANIM_DEFAULT ? (VXSIZE - i) / 3 : 0);
4136 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
4137 BlitBitmapMasked(bitmap, drawto,
4138 VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
4139 VX + VXSIZE - i, VY + j);
4140 SetClipOrigin(bitmap, gc,
4141 VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
4142 BlitBitmapMasked(bitmap, drawto,
4143 VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
4146 BlitBitmapMasked(bitmap, drawto,
4147 VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
4148 i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
4149 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
4150 BlitBitmapMasked(bitmap, drawto,
4151 VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
4153 VX + VXSIZE - i, VY + VYSIZE / 2 + j);
4156 redraw_mask |= REDRAW_DOOR_2;
4157 door_2_done = (a == VXSIZE);
4160 if (!(door_state & DOOR_NO_DELAY))
4164 if (game_status == GAME_MODE_MAIN)
4167 WaitUntilDelayReached(&door_delay, door_delay_value);
4172 if (door_state & DOOR_ACTION_1)
4173 door1 = door_state & DOOR_ACTION_1;
4174 if (door_state & DOOR_ACTION_2)
4175 door2 = door_state & DOOR_ACTION_2;
4177 return (door1 | door2);
4180 void DrawSpecialEditorDoor()
4182 /* draw bigger toolbox window */
4183 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
4184 DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
4186 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
4187 EX - 6, VY - 4, EXSIZE + 12, EYSIZE - VYSIZE + 4,
4190 redraw_mask |= REDRAW_ALL;
4193 void UndrawSpecialEditorDoor()
4195 /* draw normal tape recorder window */
4196 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
4197 EX - 6, EY - 12, EXSIZE + 12, EYSIZE - VYSIZE + 12,
4200 redraw_mask |= REDRAW_ALL;
4204 /* ---------- new tool button stuff ---------------------------------------- */
4206 /* graphic position values for tool buttons */
4207 #define TOOL_BUTTON_YES_XPOS 2
4208 #define TOOL_BUTTON_YES_YPOS 250
4209 #define TOOL_BUTTON_YES_GFX_YPOS 0
4210 #define TOOL_BUTTON_YES_XSIZE 46
4211 #define TOOL_BUTTON_YES_YSIZE 28
4212 #define TOOL_BUTTON_NO_XPOS 52
4213 #define TOOL_BUTTON_NO_YPOS TOOL_BUTTON_YES_YPOS
4214 #define TOOL_BUTTON_NO_GFX_YPOS TOOL_BUTTON_YES_GFX_YPOS
4215 #define TOOL_BUTTON_NO_XSIZE TOOL_BUTTON_YES_XSIZE
4216 #define TOOL_BUTTON_NO_YSIZE TOOL_BUTTON_YES_YSIZE
4217 #define TOOL_BUTTON_CONFIRM_XPOS TOOL_BUTTON_YES_XPOS
4218 #define TOOL_BUTTON_CONFIRM_YPOS TOOL_BUTTON_YES_YPOS
4219 #define TOOL_BUTTON_CONFIRM_GFX_YPOS 30
4220 #define TOOL_BUTTON_CONFIRM_XSIZE 96
4221 #define TOOL_BUTTON_CONFIRM_YSIZE TOOL_BUTTON_YES_YSIZE
4222 #define TOOL_BUTTON_PLAYER_XSIZE 30
4223 #define TOOL_BUTTON_PLAYER_YSIZE 30
4224 #define TOOL_BUTTON_PLAYER_GFX_XPOS 5
4225 #define TOOL_BUTTON_PLAYER_GFX_YPOS 185
4226 #define TOOL_BUTTON_PLAYER_XPOS (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
4227 #define TOOL_BUTTON_PLAYER_YPOS (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
4228 #define TOOL_BUTTON_PLAYER1_XPOS (TOOL_BUTTON_PLAYER_XPOS \
4229 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
4230 #define TOOL_BUTTON_PLAYER2_XPOS (TOOL_BUTTON_PLAYER_XPOS \
4231 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
4232 #define TOOL_BUTTON_PLAYER3_XPOS (TOOL_BUTTON_PLAYER_XPOS \
4233 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
4234 #define TOOL_BUTTON_PLAYER4_XPOS (TOOL_BUTTON_PLAYER_XPOS \
4235 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
4236 #define TOOL_BUTTON_PLAYER1_YPOS (TOOL_BUTTON_PLAYER_YPOS \
4237 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
4238 #define TOOL_BUTTON_PLAYER2_YPOS (TOOL_BUTTON_PLAYER_YPOS \
4239 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
4240 #define TOOL_BUTTON_PLAYER3_YPOS (TOOL_BUTTON_PLAYER_YPOS \
4241 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
4242 #define TOOL_BUTTON_PLAYER4_YPOS (TOOL_BUTTON_PLAYER_YPOS \
4243 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
4252 } toolbutton_info[NUM_TOOL_BUTTONS] =
4255 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_GFX_YPOS,
4256 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_YPOS,
4257 TOOL_BUTTON_YES_XSIZE, TOOL_BUTTON_YES_YSIZE,
4262 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_GFX_YPOS,
4263 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_YPOS,
4264 TOOL_BUTTON_NO_XSIZE, TOOL_BUTTON_NO_YSIZE,
4269 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_GFX_YPOS,
4270 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_YPOS,
4271 TOOL_BUTTON_CONFIRM_XSIZE, TOOL_BUTTON_CONFIRM_YSIZE,
4272 TOOL_CTRL_ID_CONFIRM,
4276 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
4277 TOOL_BUTTON_PLAYER1_XPOS, TOOL_BUTTON_PLAYER1_YPOS,
4278 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
4279 TOOL_CTRL_ID_PLAYER_1,
4283 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
4284 TOOL_BUTTON_PLAYER2_XPOS, TOOL_BUTTON_PLAYER2_YPOS,
4285 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
4286 TOOL_CTRL_ID_PLAYER_2,
4290 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
4291 TOOL_BUTTON_PLAYER3_XPOS, TOOL_BUTTON_PLAYER3_YPOS,
4292 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
4293 TOOL_CTRL_ID_PLAYER_3,
4297 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
4298 TOOL_BUTTON_PLAYER4_XPOS, TOOL_BUTTON_PLAYER4_YPOS,
4299 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
4300 TOOL_CTRL_ID_PLAYER_4,
4305 void CreateToolButtons()
4309 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4311 Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
4312 Bitmap *deco_bitmap = None;
4313 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
4314 struct GadgetInfo *gi;
4315 unsigned long event_mask;
4316 int gd_xoffset, gd_yoffset;
4317 int gd_x1, gd_x2, gd_y;
4320 event_mask = GD_EVENT_RELEASED;
4322 gd_xoffset = toolbutton_info[i].xpos;
4323 gd_yoffset = toolbutton_info[i].ypos;
4324 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
4325 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
4326 gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
4328 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
4330 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
4332 getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr),
4333 &deco_bitmap, &deco_x, &deco_y);
4334 deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
4335 deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
4338 gi = CreateGadget(GDI_CUSTOM_ID, id,
4339 GDI_INFO_TEXT, toolbutton_info[i].infotext,
4340 GDI_X, DX + toolbutton_info[i].x,
4341 GDI_Y, DY + toolbutton_info[i].y,
4342 GDI_WIDTH, toolbutton_info[i].width,
4343 GDI_HEIGHT, toolbutton_info[i].height,
4344 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
4345 GDI_STATE, GD_BUTTON_UNPRESSED,
4346 GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
4347 GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
4348 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
4349 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
4350 GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
4351 GDI_DECORATION_SHIFTING, 1, 1,
4352 GDI_DIRECT_DRAW, FALSE,
4353 GDI_EVENT_MASK, event_mask,
4354 GDI_CALLBACK_ACTION, HandleToolButtons,
4358 Error(ERR_EXIT, "cannot create gadget");
4360 tool_gadget[id] = gi;
4364 void FreeToolButtons()
4368 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4369 FreeGadget(tool_gadget[i]);
4372 static void UnmapToolButtons()
4376 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4377 UnmapGadget(tool_gadget[i]);
4380 static void HandleToolButtons(struct GadgetInfo *gi)
4382 request_gadget_id = gi->custom_id;
4385 static struct Mapping_EM_to_RND_object
4388 boolean is_rnd_to_em_mapping; /* unique mapping EM <-> RND */
4389 boolean is_backside; /* backside of moving element */
4395 em_object_mapping_list[] =
4398 Xblank, TRUE, FALSE,
4402 Yacid_splash_eB, FALSE, FALSE,
4403 EL_ACID_SPLASH_RIGHT, -1, -1
4406 Yacid_splash_wB, FALSE, FALSE,
4407 EL_ACID_SPLASH_LEFT, -1, -1
4410 #ifdef EM_ENGINE_BAD_ROLL
4412 Xstone_force_e, FALSE, FALSE,
4413 EL_ROCK, -1, MV_BIT_RIGHT
4416 Xstone_force_w, FALSE, FALSE,
4417 EL_ROCK, -1, MV_BIT_LEFT
4420 Xnut_force_e, FALSE, FALSE,
4421 EL_NUT, -1, MV_BIT_RIGHT
4424 Xnut_force_w, FALSE, FALSE,
4425 EL_NUT, -1, MV_BIT_LEFT
4428 Xspring_force_e, FALSE, FALSE,
4429 EL_SPRING, -1, MV_BIT_RIGHT
4432 Xspring_force_w, FALSE, FALSE,
4433 EL_SPRING, -1, MV_BIT_LEFT
4436 Xemerald_force_e, FALSE, FALSE,
4437 EL_EMERALD, -1, MV_BIT_RIGHT
4440 Xemerald_force_w, FALSE, FALSE,
4441 EL_EMERALD, -1, MV_BIT_LEFT
4444 Xdiamond_force_e, FALSE, FALSE,
4445 EL_DIAMOND, -1, MV_BIT_RIGHT
4448 Xdiamond_force_w, FALSE, FALSE,
4449 EL_DIAMOND, -1, MV_BIT_LEFT
4452 Xbomb_force_e, FALSE, FALSE,
4453 EL_BOMB, -1, MV_BIT_RIGHT
4456 Xbomb_force_w, FALSE, FALSE,
4457 EL_BOMB, -1, MV_BIT_LEFT
4459 #endif /* EM_ENGINE_BAD_ROLL */
4462 Xstone, TRUE, FALSE,
4466 Xstone_pause, FALSE, FALSE,
4470 Xstone_fall, FALSE, FALSE,
4474 Ystone_s, FALSE, FALSE,
4475 EL_ROCK, ACTION_FALLING, -1
4478 Ystone_sB, FALSE, TRUE,
4479 EL_ROCK, ACTION_FALLING, -1
4482 Ystone_e, FALSE, FALSE,
4483 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
4486 Ystone_eB, FALSE, TRUE,
4487 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
4490 Ystone_w, FALSE, FALSE,
4491 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
4494 Ystone_wB, FALSE, TRUE,
4495 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
4502 Xnut_pause, FALSE, FALSE,
4506 Xnut_fall, FALSE, FALSE,
4510 Ynut_s, FALSE, FALSE,
4511 EL_NUT, ACTION_FALLING, -1
4514 Ynut_sB, FALSE, TRUE,
4515 EL_NUT, ACTION_FALLING, -1
4518 Ynut_e, FALSE, FALSE,
4519 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
4522 Ynut_eB, FALSE, TRUE,
4523 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
4526 Ynut_w, FALSE, FALSE,
4527 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
4530 Ynut_wB, FALSE, TRUE,
4531 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
4534 Xbug_n, TRUE, FALSE,
4538 Xbug_e, TRUE, FALSE,
4539 EL_BUG_RIGHT, -1, -1
4542 Xbug_s, TRUE, FALSE,
4546 Xbug_w, TRUE, FALSE,
4550 Xbug_gon, FALSE, FALSE,
4554 Xbug_goe, FALSE, FALSE,
4555 EL_BUG_RIGHT, -1, -1
4558 Xbug_gos, FALSE, FALSE,
4562 Xbug_gow, FALSE, FALSE,
4566 Ybug_n, FALSE, FALSE,
4567 EL_BUG, ACTION_MOVING, MV_BIT_UP
4570 Ybug_nB, FALSE, TRUE,
4571 EL_BUG, ACTION_MOVING, MV_BIT_UP
4574 Ybug_e, FALSE, FALSE,
4575 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
4578 Ybug_eB, FALSE, TRUE,
4579 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
4582 Ybug_s, FALSE, FALSE,
4583 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
4586 Ybug_sB, FALSE, TRUE,
4587 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
4590 Ybug_w, FALSE, FALSE,
4591 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
4594 Ybug_wB, FALSE, TRUE,
4595 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
4598 Ybug_w_n, FALSE, FALSE,
4599 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
4602 Ybug_n_e, FALSE, FALSE,
4603 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
4606 Ybug_e_s, FALSE, FALSE,
4607 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
4610 Ybug_s_w, FALSE, FALSE,
4611 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
4614 Ybug_e_n, FALSE, FALSE,
4615 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
4618 Ybug_s_e, FALSE, FALSE,
4619 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
4622 Ybug_w_s, FALSE, FALSE,
4623 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
4626 Ybug_n_w, FALSE, FALSE,
4627 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
4630 Ybug_stone, FALSE, FALSE,
4631 EL_BUG, ACTION_SMASHED_BY_ROCK, -1
4634 Ybug_spring, FALSE, FALSE,
4635 EL_BUG, ACTION_SMASHED_BY_SPRING, -1
4638 Xtank_n, TRUE, FALSE,
4639 EL_SPACESHIP_UP, -1, -1
4642 Xtank_e, TRUE, FALSE,
4643 EL_SPACESHIP_RIGHT, -1, -1
4646 Xtank_s, TRUE, FALSE,
4647 EL_SPACESHIP_DOWN, -1, -1
4650 Xtank_w, TRUE, FALSE,
4651 EL_SPACESHIP_LEFT, -1, -1
4654 Xtank_gon, FALSE, FALSE,
4655 EL_SPACESHIP_UP, -1, -1
4658 Xtank_goe, FALSE, FALSE,
4659 EL_SPACESHIP_RIGHT, -1, -1
4662 Xtank_gos, FALSE, FALSE,
4663 EL_SPACESHIP_DOWN, -1, -1
4666 Xtank_gow, FALSE, FALSE,
4667 EL_SPACESHIP_LEFT, -1, -1
4670 Ytank_n, FALSE, FALSE,
4671 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
4674 Ytank_nB, FALSE, TRUE,
4675 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
4678 Ytank_e, FALSE, FALSE,
4679 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
4682 Ytank_eB, FALSE, TRUE,
4683 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
4686 Ytank_s, FALSE, FALSE,
4687 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
4690 Ytank_sB, FALSE, TRUE,
4691 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
4694 Ytank_w, FALSE, FALSE,
4695 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
4698 Ytank_wB, FALSE, TRUE,
4699 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
4702 Ytank_w_n, FALSE, FALSE,
4703 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
4706 Ytank_n_e, FALSE, FALSE,
4707 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
4710 Ytank_e_s, FALSE, FALSE,
4711 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
4714 Ytank_s_w, FALSE, FALSE,
4715 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
4718 Ytank_e_n, FALSE, FALSE,
4719 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
4722 Ytank_s_e, FALSE, FALSE,
4723 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
4726 Ytank_w_s, FALSE, FALSE,
4727 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
4730 Ytank_n_w, FALSE, FALSE,
4731 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
4734 Ytank_stone, FALSE, FALSE,
4735 EL_SPACESHIP, ACTION_SMASHED_BY_ROCK, -1
4738 Ytank_spring, FALSE, FALSE,
4739 EL_SPACESHIP, ACTION_SMASHED_BY_SPRING, -1
4742 Xandroid, TRUE, FALSE,
4743 EL_EMC_ANDROID, ACTION_ACTIVE, -1
4746 Xandroid_1_n, FALSE, FALSE,
4747 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
4750 Xandroid_2_n, FALSE, FALSE,
4751 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
4754 Xandroid_1_e, FALSE, FALSE,
4755 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
4758 Xandroid_2_e, FALSE, FALSE,
4759 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
4762 Xandroid_1_w, FALSE, FALSE,
4763 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
4766 Xandroid_2_w, FALSE, FALSE,
4767 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
4770 Xandroid_1_s, FALSE, FALSE,
4771 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
4774 Xandroid_2_s, FALSE, FALSE,
4775 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
4778 Yandroid_n, FALSE, FALSE,
4779 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
4782 Yandroid_nB, FALSE, TRUE,
4783 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
4786 Yandroid_ne, FALSE, FALSE,
4787 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPRIGHT
4790 Yandroid_neB, FALSE, TRUE,
4791 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPRIGHT
4794 Yandroid_e, FALSE, FALSE,
4795 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
4798 Yandroid_eB, FALSE, TRUE,
4799 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
4802 Yandroid_se, FALSE, FALSE,
4803 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNRIGHT
4806 Yandroid_seB, FALSE, TRUE,
4807 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNRIGHT
4810 Yandroid_s, FALSE, FALSE,
4811 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
4814 Yandroid_sB, FALSE, TRUE,
4815 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
4818 Yandroid_sw, FALSE, FALSE,
4819 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNLEFT
4822 Yandroid_swB, FALSE, TRUE,
4823 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNLEFT
4826 Yandroid_w, FALSE, FALSE,
4827 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
4830 Yandroid_wB, FALSE, TRUE,
4831 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
4834 Yandroid_nw, FALSE, FALSE,
4835 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPLEFT
4838 Yandroid_nwB, FALSE, TRUE,
4839 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPLEFT
4842 Xspring, TRUE, FALSE,
4846 Xspring_pause, FALSE, FALSE,
4850 Xspring_e, FALSE, FALSE,
4854 Xspring_w, FALSE, FALSE,
4858 Xspring_fall, FALSE, FALSE,
4862 Yspring_s, FALSE, FALSE,
4863 EL_SPRING, ACTION_FALLING, -1
4866 Yspring_sB, FALSE, TRUE,
4867 EL_SPRING, ACTION_FALLING, -1
4870 Yspring_e, FALSE, FALSE,
4871 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
4874 Yspring_eB, FALSE, TRUE,
4875 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
4878 Yspring_w, FALSE, FALSE,
4879 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
4882 Yspring_wB, FALSE, TRUE,
4883 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
4886 Yspring_kill_e, FALSE, FALSE,
4887 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
4890 Yspring_kill_eB, FALSE, TRUE,
4891 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
4894 Yspring_kill_w, FALSE, FALSE,
4895 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
4898 Yspring_kill_wB, FALSE, TRUE,
4899 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
4902 Xeater_n, TRUE, FALSE,
4903 EL_YAMYAM_UP, -1, -1
4906 Xeater_e, TRUE, FALSE,
4907 EL_YAMYAM_RIGHT, -1, -1
4910 Xeater_w, TRUE, FALSE,
4911 EL_YAMYAM_LEFT, -1, -1
4914 Xeater_s, TRUE, FALSE,
4915 EL_YAMYAM_DOWN, -1, -1
4918 Yeater_n, FALSE, FALSE,
4919 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
4922 Yeater_nB, FALSE, TRUE,
4923 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
4926 Yeater_e, FALSE, FALSE,
4927 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
4930 Yeater_eB, FALSE, TRUE,
4931 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
4934 Yeater_s, FALSE, FALSE,
4935 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
4938 Yeater_sB, FALSE, TRUE,
4939 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
4942 Yeater_w, FALSE, FALSE,
4943 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
4946 Yeater_wB, FALSE, TRUE,
4947 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
4950 Yeater_stone, FALSE, FALSE,
4951 EL_YAMYAM, ACTION_SMASHED_BY_ROCK, -1
4954 Yeater_spring, FALSE, FALSE,
4955 EL_YAMYAM, ACTION_SMASHED_BY_SPRING, -1
4958 Xalien, TRUE, FALSE,
4962 Xalien_pause, FALSE, FALSE,
4966 Yalien_n, FALSE, FALSE,
4967 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
4970 Yalien_nB, FALSE, TRUE,
4971 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
4974 Yalien_e, FALSE, FALSE,
4975 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
4978 Yalien_eB, FALSE, TRUE,
4979 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
4982 Yalien_s, FALSE, FALSE,
4983 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
4986 Yalien_sB, FALSE, TRUE,
4987 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
4990 Yalien_w, FALSE, FALSE,
4991 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
4994 Yalien_wB, FALSE, TRUE,
4995 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
4998 Yalien_stone, FALSE, FALSE,
4999 EL_ROBOT, ACTION_SMASHED_BY_ROCK, -1
5002 Yalien_spring, FALSE, FALSE,
5003 EL_ROBOT, ACTION_SMASHED_BY_SPRING, -1
5006 Xemerald, TRUE, FALSE,
5010 Xemerald_pause, FALSE, FALSE,
5014 Xemerald_fall, FALSE, FALSE,
5018 Xemerald_shine, FALSE, FALSE,
5019 EL_EMERALD, ACTION_TWINKLING, -1
5022 Yemerald_s, FALSE, FALSE,
5023 EL_EMERALD, ACTION_FALLING, -1
5026 Yemerald_sB, FALSE, TRUE,
5027 EL_EMERALD, ACTION_FALLING, -1
5030 Yemerald_e, FALSE, FALSE,
5031 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
5034 Yemerald_eB, FALSE, TRUE,
5035 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
5038 Yemerald_w, FALSE, FALSE,
5039 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
5042 Yemerald_wB, FALSE, TRUE,
5043 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
5046 Yemerald_eat, FALSE, FALSE,
5047 EL_EMERALD, ACTION_COLLECTING, -1
5050 Yemerald_stone, FALSE, FALSE,
5051 EL_NUT, ACTION_BREAKING, -1
5054 Xdiamond, TRUE, FALSE,
5058 Xdiamond_pause, FALSE, FALSE,
5062 Xdiamond_fall, FALSE, FALSE,
5066 Xdiamond_shine, FALSE, FALSE,
5067 EL_DIAMOND, ACTION_TWINKLING, -1
5070 Ydiamond_s, FALSE, FALSE,
5071 EL_DIAMOND, ACTION_FALLING, -1
5074 Ydiamond_sB, FALSE, TRUE,
5075 EL_DIAMOND, ACTION_FALLING, -1
5078 Ydiamond_e, FALSE, FALSE,
5079 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
5082 Ydiamond_eB, FALSE, TRUE,
5083 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
5086 Ydiamond_w, FALSE, FALSE,
5087 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
5090 Ydiamond_wB, FALSE, TRUE,
5091 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
5094 Ydiamond_eat, FALSE, FALSE,
5095 EL_DIAMOND, ACTION_COLLECTING, -1
5098 Ydiamond_stone, FALSE, FALSE,
5099 EL_DIAMOND, ACTION_SMASHED_BY_ROCK, -1
5102 Xdrip_fall, TRUE, FALSE,
5103 EL_AMOEBA_DROP, -1, -1
5106 Xdrip_stretch, FALSE, FALSE,
5107 EL_AMOEBA_DROP, ACTION_FALLING, -1
5110 Xdrip_stretchB, FALSE, TRUE,
5111 EL_AMOEBA_DROP, ACTION_FALLING, -1
5114 Xdrip_eat, FALSE, FALSE,
5115 EL_AMOEBA_DROP, ACTION_GROWING, -1
5118 Ydrip_s1, FALSE, FALSE,
5119 EL_AMOEBA_DROP, ACTION_FALLING, -1
5122 Ydrip_s1B, FALSE, TRUE,
5123 EL_AMOEBA_DROP, ACTION_FALLING, -1
5126 Ydrip_s2, FALSE, FALSE,
5127 EL_AMOEBA_DROP, ACTION_FALLING, -1
5130 Ydrip_s2B, FALSE, TRUE,
5131 EL_AMOEBA_DROP, ACTION_FALLING, -1
5138 Xbomb_pause, FALSE, FALSE,
5142 Xbomb_fall, FALSE, FALSE,
5146 Ybomb_s, FALSE, FALSE,
5147 EL_BOMB, ACTION_FALLING, -1
5150 Ybomb_sB, FALSE, TRUE,
5151 EL_BOMB, ACTION_FALLING, -1
5154 Ybomb_e, FALSE, FALSE,
5155 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
5158 Ybomb_eB, FALSE, TRUE,
5159 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
5162 Ybomb_w, FALSE, FALSE,
5163 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
5166 Ybomb_wB, FALSE, TRUE,
5167 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
5170 Ybomb_eat, FALSE, FALSE,
5171 EL_BOMB, ACTION_ACTIVATING, -1
5174 Xballoon, TRUE, FALSE,
5178 Yballoon_n, FALSE, FALSE,
5179 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
5182 Yballoon_nB, FALSE, TRUE,
5183 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
5186 Yballoon_e, FALSE, FALSE,
5187 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
5190 Yballoon_eB, FALSE, TRUE,
5191 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
5194 Yballoon_s, FALSE, FALSE,
5195 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
5198 Yballoon_sB, FALSE, TRUE,
5199 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
5202 Yballoon_w, FALSE, FALSE,
5203 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
5206 Yballoon_wB, FALSE, TRUE,
5207 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
5210 Xgrass, TRUE, FALSE,
5211 EL_EMC_GRASS, -1, -1
5214 Ygrass_nB, FALSE, FALSE,
5215 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_UP
5218 Ygrass_eB, FALSE, FALSE,
5219 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_RIGHT
5222 Ygrass_sB, FALSE, FALSE,
5223 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_DOWN
5226 Ygrass_wB, FALSE, FALSE,
5227 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_LEFT
5234 Ydirt_nB, FALSE, FALSE,
5235 EL_SAND, ACTION_DIGGING, MV_BIT_UP
5238 Ydirt_eB, FALSE, FALSE,
5239 EL_SAND, ACTION_DIGGING, MV_BIT_RIGHT
5242 Ydirt_sB, FALSE, FALSE,
5243 EL_SAND, ACTION_DIGGING, MV_BIT_DOWN
5246 Ydirt_wB, FALSE, FALSE,
5247 EL_SAND, ACTION_DIGGING, MV_BIT_LEFT
5250 Xacid_ne, TRUE, FALSE,
5251 EL_ACID_POOL_TOPRIGHT, -1, -1
5254 Xacid_se, TRUE, FALSE,
5255 EL_ACID_POOL_BOTTOMRIGHT, -1, -1
5258 Xacid_s, TRUE, FALSE,
5259 EL_ACID_POOL_BOTTOM, -1, -1
5262 Xacid_sw, TRUE, FALSE,
5263 EL_ACID_POOL_BOTTOMLEFT, -1, -1
5266 Xacid_nw, TRUE, FALSE,
5267 EL_ACID_POOL_TOPLEFT, -1, -1
5270 Xacid_1, TRUE, FALSE,
5274 Xacid_2, FALSE, FALSE,
5278 Xacid_3, FALSE, FALSE,
5282 Xacid_4, FALSE, FALSE,
5286 Xacid_5, FALSE, FALSE,
5290 Xacid_6, FALSE, FALSE,
5294 Xacid_7, FALSE, FALSE,
5298 Xacid_8, FALSE, FALSE,
5302 Xball_1, TRUE, FALSE,
5303 EL_EMC_MAGIC_BALL, -1, -1
5306 Xball_1B, FALSE, FALSE,
5307 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
5310 Xball_2, FALSE, FALSE,
5311 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
5314 Xball_2B, FALSE, FALSE,
5315 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
5318 Yball_eat, FALSE, FALSE,
5319 EL_EMC_MAGIC_BALL, ACTION_DROPPING, -1
5322 Ykey_1_eat, FALSE, FALSE,
5323 EL_EM_KEY_1, ACTION_COLLECTING, -1
5326 Ykey_2_eat, FALSE, FALSE,
5327 EL_EM_KEY_2, ACTION_COLLECTING, -1
5330 Ykey_3_eat, FALSE, FALSE,
5331 EL_EM_KEY_3, ACTION_COLLECTING, -1
5334 Ykey_4_eat, FALSE, FALSE,
5335 EL_EM_KEY_4, ACTION_COLLECTING, -1
5338 Ykey_5_eat, FALSE, FALSE,
5339 EL_EMC_KEY_5, ACTION_COLLECTING, -1
5342 Ykey_6_eat, FALSE, FALSE,
5343 EL_EMC_KEY_6, ACTION_COLLECTING, -1
5346 Ykey_7_eat, FALSE, FALSE,
5347 EL_EMC_KEY_7, ACTION_COLLECTING, -1
5350 Ykey_8_eat, FALSE, FALSE,
5351 EL_EMC_KEY_8, ACTION_COLLECTING, -1
5354 Ylenses_eat, FALSE, FALSE,
5355 EL_EMC_LENSES, ACTION_COLLECTING, -1
5358 Ymagnify_eat, FALSE, FALSE,
5359 EL_EMC_MAGNIFIER, ACTION_COLLECTING, -1
5362 Ygrass_eat, FALSE, FALSE,
5363 EL_EMC_GRASS, ACTION_SNAPPING, -1
5366 Ydirt_eat, FALSE, FALSE,
5367 EL_SAND, ACTION_SNAPPING, -1
5370 Xgrow_ns, TRUE, FALSE,
5371 EL_EXPANDABLE_WALL_VERTICAL, -1, -1
5374 Ygrow_ns_eat, FALSE, FALSE,
5375 EL_EXPANDABLE_WALL_VERTICAL, ACTION_GROWING, -1
5378 Xgrow_ew, TRUE, FALSE,
5379 EL_EXPANDABLE_WALL_HORIZONTAL, -1, -1
5382 Ygrow_ew_eat, FALSE, FALSE,
5383 EL_EXPANDABLE_WALL_HORIZONTAL, ACTION_GROWING, -1
5386 Xwonderwall, TRUE, FALSE,
5387 EL_MAGIC_WALL, -1, -1
5390 XwonderwallB, FALSE, FALSE,
5391 EL_MAGIC_WALL, ACTION_ACTIVE, -1
5394 Xamoeba_1, TRUE, FALSE,
5395 EL_AMOEBA_DRY, ACTION_OTHER, -1
5398 Xamoeba_2, FALSE, FALSE,
5399 EL_AMOEBA_DRY, ACTION_OTHER, -1
5402 Xamoeba_3, FALSE, FALSE,
5403 EL_AMOEBA_DRY, ACTION_OTHER, -1
5406 Xamoeba_4, FALSE, FALSE,
5407 EL_AMOEBA_DRY, ACTION_OTHER, -1
5410 Xamoeba_5, TRUE, FALSE,
5411 EL_AMOEBA_WET, ACTION_OTHER, -1
5414 Xamoeba_6, FALSE, FALSE,
5415 EL_AMOEBA_WET, ACTION_OTHER, -1
5418 Xamoeba_7, FALSE, FALSE,
5419 EL_AMOEBA_WET, ACTION_OTHER, -1
5422 Xamoeba_8, FALSE, FALSE,
5423 EL_AMOEBA_WET, ACTION_OTHER, -1
5426 Xdoor_1, TRUE, FALSE,
5427 EL_EM_GATE_1, -1, -1
5430 Xdoor_2, TRUE, FALSE,
5431 EL_EM_GATE_2, -1, -1
5434 Xdoor_3, TRUE, FALSE,
5435 EL_EM_GATE_3, -1, -1
5438 Xdoor_4, TRUE, FALSE,
5439 EL_EM_GATE_4, -1, -1
5442 Xdoor_5, TRUE, FALSE,
5443 EL_EMC_GATE_5, -1, -1
5446 Xdoor_6, TRUE, FALSE,
5447 EL_EMC_GATE_6, -1, -1
5450 Xdoor_7, TRUE, FALSE,
5451 EL_EMC_GATE_7, -1, -1
5454 Xdoor_8, TRUE, FALSE,
5455 EL_EMC_GATE_8, -1, -1
5458 Xkey_1, TRUE, FALSE,
5462 Xkey_2, TRUE, FALSE,
5466 Xkey_3, TRUE, FALSE,
5470 Xkey_4, TRUE, FALSE,
5474 Xkey_5, TRUE, FALSE,
5475 EL_EMC_KEY_5, -1, -1
5478 Xkey_6, TRUE, FALSE,
5479 EL_EMC_KEY_6, -1, -1
5482 Xkey_7, TRUE, FALSE,
5483 EL_EMC_KEY_7, -1, -1
5486 Xkey_8, TRUE, FALSE,
5487 EL_EMC_KEY_8, -1, -1
5490 Xwind_n, TRUE, FALSE,
5491 EL_BALLOON_SWITCH_UP, -1, -1
5494 Xwind_e, TRUE, FALSE,
5495 EL_BALLOON_SWITCH_RIGHT, -1, -1
5498 Xwind_s, TRUE, FALSE,
5499 EL_BALLOON_SWITCH_DOWN, -1, -1
5502 Xwind_w, TRUE, FALSE,
5503 EL_BALLOON_SWITCH_LEFT, -1, -1
5506 Xwind_nesw, TRUE, FALSE,
5507 EL_BALLOON_SWITCH_ANY, -1, -1
5510 Xwind_stop, TRUE, FALSE,
5511 EL_BALLOON_SWITCH_NONE, -1, -1
5515 EL_EM_EXIT_CLOSED, -1, -1
5518 Xexit_1, TRUE, FALSE,
5519 EL_EM_EXIT_OPEN, -1, -1
5522 Xexit_2, FALSE, FALSE,
5523 EL_EM_EXIT_OPEN, -1, -1
5526 Xexit_3, FALSE, FALSE,
5527 EL_EM_EXIT_OPEN, -1, -1
5530 Xdynamite, TRUE, FALSE,
5531 EL_EM_DYNAMITE, -1, -1
5534 Ydynamite_eat, FALSE, FALSE,
5535 EL_EM_DYNAMITE, ACTION_COLLECTING, -1
5538 Xdynamite_1, TRUE, FALSE,
5539 EL_EM_DYNAMITE_ACTIVE, -1, -1
5542 Xdynamite_2, FALSE, FALSE,
5543 EL_EM_DYNAMITE_ACTIVE, -1, -1
5546 Xdynamite_3, FALSE, FALSE,
5547 EL_EM_DYNAMITE_ACTIVE, -1, -1
5550 Xdynamite_4, FALSE, FALSE,
5551 EL_EM_DYNAMITE_ACTIVE, -1, -1
5554 Xbumper, TRUE, FALSE,
5555 EL_EMC_SPRING_BUMPER, -1, -1
5558 XbumperB, FALSE, FALSE,
5559 EL_EMC_SPRING_BUMPER, ACTION_ACTIVE, -1
5562 Xwheel, TRUE, FALSE,
5563 EL_ROBOT_WHEEL, -1, -1
5566 XwheelB, FALSE, FALSE,
5567 EL_ROBOT_WHEEL, ACTION_ACTIVE, -1
5570 Xswitch, TRUE, FALSE,
5571 EL_EMC_MAGIC_BALL_SWITCH, -1, -1
5574 XswitchB, FALSE, FALSE,
5575 EL_EMC_MAGIC_BALL_SWITCH, ACTION_ACTIVE, -1
5579 EL_QUICKSAND_EMPTY, -1, -1
5582 Xsand_stone, TRUE, FALSE,
5583 EL_QUICKSAND_FULL, -1, -1
5586 Xsand_stonein_1, FALSE, TRUE,
5587 EL_ROCK, ACTION_FILLING, -1
5590 Xsand_stonein_2, FALSE, TRUE,
5591 EL_ROCK, ACTION_FILLING, -1
5594 Xsand_stonein_3, FALSE, TRUE,
5595 EL_ROCK, ACTION_FILLING, -1
5598 Xsand_stonein_4, FALSE, TRUE,
5599 EL_ROCK, ACTION_FILLING, -1
5603 Xsand_stonesand_1, FALSE, FALSE,
5604 EL_QUICKSAND_EMPTYING, -1, -1
5607 Xsand_stonesand_2, FALSE, FALSE,
5608 EL_QUICKSAND_EMPTYING, -1, -1
5611 Xsand_stonesand_3, FALSE, FALSE,
5612 EL_QUICKSAND_EMPTYING, -1, -1
5615 Xsand_stonesand_4, FALSE, FALSE,
5616 EL_QUICKSAND_EMPTYING, -1, -1
5619 Xsand_stonesand_quickout_1, FALSE, FALSE,
5620 EL_QUICKSAND_EMPTYING, -1, -1
5623 Xsand_stonesand_quickout_2, FALSE, FALSE,
5624 EL_QUICKSAND_EMPTYING, -1, -1
5628 Xsand_stonesand_1, FALSE, FALSE,
5629 EL_QUICKSAND_FULL, -1, -1
5632 Xsand_stonesand_2, FALSE, FALSE,
5633 EL_QUICKSAND_FULL, -1, -1
5636 Xsand_stonesand_3, FALSE, FALSE,
5637 EL_QUICKSAND_FULL, -1, -1
5640 Xsand_stonesand_4, FALSE, FALSE,
5641 EL_QUICKSAND_FULL, -1, -1
5645 Xsand_stoneout_1, FALSE, FALSE,
5646 EL_ROCK, ACTION_EMPTYING, -1
5649 Xsand_stoneout_2, FALSE, FALSE,
5650 EL_ROCK, ACTION_EMPTYING, -1
5654 Xsand_sandstone_1, FALSE, FALSE,
5655 EL_QUICKSAND_FILLING, -1, -1
5658 Xsand_sandstone_2, FALSE, FALSE,
5659 EL_QUICKSAND_FILLING, -1, -1
5662 Xsand_sandstone_3, FALSE, FALSE,
5663 EL_QUICKSAND_FILLING, -1, -1
5666 Xsand_sandstone_4, FALSE, FALSE,
5667 EL_QUICKSAND_FILLING, -1, -1
5671 Xsand_sandstone_1, FALSE, FALSE,
5672 EL_QUICKSAND_FULL, -1, -1
5675 Xsand_sandstone_2, FALSE, FALSE,
5676 EL_QUICKSAND_FULL, -1, -1
5679 Xsand_sandstone_3, FALSE, FALSE,
5680 EL_QUICKSAND_FULL, -1, -1
5683 Xsand_sandstone_4, FALSE, FALSE,
5684 EL_QUICKSAND_FULL, -1, -1
5688 Xplant, TRUE, FALSE,
5689 EL_EMC_PLANT, -1, -1
5692 Yplant, FALSE, FALSE,
5693 EL_EMC_PLANT, -1, -1
5696 Xlenses, TRUE, FALSE,
5697 EL_EMC_LENSES, -1, -1
5700 Xmagnify, TRUE, FALSE,
5701 EL_EMC_MAGNIFIER, -1, -1
5704 Xdripper, TRUE, FALSE,
5705 EL_EMC_DRIPPER, -1, -1
5708 XdripperB, FALSE, FALSE,
5709 EL_EMC_DRIPPER, ACTION_ACTIVE, -1
5712 Xfake_blank, TRUE, FALSE,
5713 EL_INVISIBLE_WALL, -1, -1
5716 Xfake_blankB, FALSE, FALSE,
5717 EL_INVISIBLE_WALL, ACTION_ACTIVE, -1
5720 Xfake_grass, TRUE, FALSE,
5721 EL_EMC_FAKE_GRASS, -1, -1
5724 Xfake_grassB, FALSE, FALSE,
5725 EL_EMC_FAKE_GRASS, ACTION_ACTIVE, -1
5728 Xfake_door_1, TRUE, FALSE,
5729 EL_EM_GATE_1_GRAY, -1, -1
5732 Xfake_door_2, TRUE, FALSE,
5733 EL_EM_GATE_2_GRAY, -1, -1
5736 Xfake_door_3, TRUE, FALSE,
5737 EL_EM_GATE_3_GRAY, -1, -1
5740 Xfake_door_4, TRUE, FALSE,
5741 EL_EM_GATE_4_GRAY, -1, -1
5744 Xfake_door_5, TRUE, FALSE,
5745 EL_EMC_GATE_5_GRAY, -1, -1
5748 Xfake_door_6, TRUE, FALSE,
5749 EL_EMC_GATE_6_GRAY, -1, -1
5752 Xfake_door_7, TRUE, FALSE,
5753 EL_EMC_GATE_7_GRAY, -1, -1
5756 Xfake_door_8, TRUE, FALSE,
5757 EL_EMC_GATE_8_GRAY, -1, -1
5760 Xfake_acid_1, TRUE, FALSE,
5761 EL_EMC_FAKE_ACID, -1, -1
5764 Xfake_acid_2, FALSE, FALSE,
5765 EL_EMC_FAKE_ACID, -1, -1
5768 Xfake_acid_3, FALSE, FALSE,
5769 EL_EMC_FAKE_ACID, -1, -1
5772 Xfake_acid_4, FALSE, FALSE,
5773 EL_EMC_FAKE_ACID, -1, -1
5776 Xfake_acid_5, FALSE, FALSE,
5777 EL_EMC_FAKE_ACID, -1, -1
5780 Xfake_acid_6, FALSE, FALSE,
5781 EL_EMC_FAKE_ACID, -1, -1
5784 Xfake_acid_7, FALSE, FALSE,
5785 EL_EMC_FAKE_ACID, -1, -1
5788 Xfake_acid_8, FALSE, FALSE,
5789 EL_EMC_FAKE_ACID, -1, -1
5792 Xsteel_1, TRUE, FALSE,
5793 EL_STEELWALL, -1, -1
5796 Xsteel_2, TRUE, FALSE,
5797 EL_EMC_STEELWALL_2, -1, -1
5800 Xsteel_3, TRUE, FALSE,
5801 EL_EMC_STEELWALL_3, -1, -1
5804 Xsteel_4, TRUE, FALSE,
5805 EL_EMC_STEELWALL_4, -1, -1
5808 Xwall_1, TRUE, FALSE,
5812 Xwall_2, TRUE, FALSE,
5813 EL_EMC_WALL_14, -1, -1
5816 Xwall_3, TRUE, FALSE,
5817 EL_EMC_WALL_15, -1, -1
5820 Xwall_4, TRUE, FALSE,
5821 EL_EMC_WALL_16, -1, -1
5824 Xround_wall_1, TRUE, FALSE,
5825 EL_WALL_SLIPPERY, -1, -1
5828 Xround_wall_2, TRUE, FALSE,
5829 EL_EMC_WALL_SLIPPERY_2, -1, -1
5832 Xround_wall_3, TRUE, FALSE,
5833 EL_EMC_WALL_SLIPPERY_3, -1, -1
5836 Xround_wall_4, TRUE, FALSE,
5837 EL_EMC_WALL_SLIPPERY_4, -1, -1
5840 Xdecor_1, TRUE, FALSE,
5841 EL_EMC_WALL_8, -1, -1
5844 Xdecor_2, TRUE, FALSE,
5845 EL_EMC_WALL_6, -1, -1
5848 Xdecor_3, TRUE, FALSE,
5849 EL_EMC_WALL_4, -1, -1
5852 Xdecor_4, TRUE, FALSE,
5853 EL_EMC_WALL_7, -1, -1
5856 Xdecor_5, TRUE, FALSE,
5857 EL_EMC_WALL_5, -1, -1
5860 Xdecor_6, TRUE, FALSE,
5861 EL_EMC_WALL_9, -1, -1
5864 Xdecor_7, TRUE, FALSE,
5865 EL_EMC_WALL_10, -1, -1
5868 Xdecor_8, TRUE, FALSE,
5869 EL_EMC_WALL_1, -1, -1
5872 Xdecor_9, TRUE, FALSE,
5873 EL_EMC_WALL_2, -1, -1
5876 Xdecor_10, TRUE, FALSE,
5877 EL_EMC_WALL_3, -1, -1
5880 Xdecor_11, TRUE, FALSE,
5881 EL_EMC_WALL_11, -1, -1
5884 Xdecor_12, TRUE, FALSE,
5885 EL_EMC_WALL_12, -1, -1
5888 Xalpha_0, TRUE, FALSE,
5889 EL_CHAR('0'), -1, -1
5892 Xalpha_1, TRUE, FALSE,
5893 EL_CHAR('1'), -1, -1
5896 Xalpha_2, TRUE, FALSE,
5897 EL_CHAR('2'), -1, -1
5900 Xalpha_3, TRUE, FALSE,
5901 EL_CHAR('3'), -1, -1
5904 Xalpha_4, TRUE, FALSE,
5905 EL_CHAR('4'), -1, -1
5908 Xalpha_5, TRUE, FALSE,
5909 EL_CHAR('5'), -1, -1
5912 Xalpha_6, TRUE, FALSE,
5913 EL_CHAR('6'), -1, -1
5916 Xalpha_7, TRUE, FALSE,
5917 EL_CHAR('7'), -1, -1
5920 Xalpha_8, TRUE, FALSE,
5921 EL_CHAR('8'), -1, -1
5924 Xalpha_9, TRUE, FALSE,
5925 EL_CHAR('9'), -1, -1
5928 Xalpha_excla, TRUE, FALSE,
5929 EL_CHAR('!'), -1, -1
5932 Xalpha_quote, TRUE, FALSE,
5933 EL_CHAR('"'), -1, -1
5936 Xalpha_comma, TRUE, FALSE,
5937 EL_CHAR(','), -1, -1
5940 Xalpha_minus, TRUE, FALSE,
5941 EL_CHAR('-'), -1, -1
5944 Xalpha_perio, TRUE, FALSE,
5945 EL_CHAR('.'), -1, -1
5948 Xalpha_colon, TRUE, FALSE,
5949 EL_CHAR(':'), -1, -1
5952 Xalpha_quest, TRUE, FALSE,
5953 EL_CHAR('?'), -1, -1
5956 Xalpha_a, TRUE, FALSE,
5957 EL_CHAR('A'), -1, -1
5960 Xalpha_b, TRUE, FALSE,
5961 EL_CHAR('B'), -1, -1
5964 Xalpha_c, TRUE, FALSE,
5965 EL_CHAR('C'), -1, -1
5968 Xalpha_d, TRUE, FALSE,
5969 EL_CHAR('D'), -1, -1
5972 Xalpha_e, TRUE, FALSE,
5973 EL_CHAR('E'), -1, -1
5976 Xalpha_f, TRUE, FALSE,
5977 EL_CHAR('F'), -1, -1
5980 Xalpha_g, TRUE, FALSE,
5981 EL_CHAR('G'), -1, -1
5984 Xalpha_h, TRUE, FALSE,
5985 EL_CHAR('H'), -1, -1
5988 Xalpha_i, TRUE, FALSE,
5989 EL_CHAR('I'), -1, -1
5992 Xalpha_j, TRUE, FALSE,
5993 EL_CHAR('J'), -1, -1
5996 Xalpha_k, TRUE, FALSE,
5997 EL_CHAR('K'), -1, -1
6000 Xalpha_l, TRUE, FALSE,
6001 EL_CHAR('L'), -1, -1
6004 Xalpha_m, TRUE, FALSE,
6005 EL_CHAR('M'), -1, -1
6008 Xalpha_n, TRUE, FALSE,
6009 EL_CHAR('N'), -1, -1
6012 Xalpha_o, TRUE, FALSE,
6013 EL_CHAR('O'), -1, -1
6016 Xalpha_p, TRUE, FALSE,
6017 EL_CHAR('P'), -1, -1
6020 Xalpha_q, TRUE, FALSE,
6021 EL_CHAR('Q'), -1, -1
6024 Xalpha_r, TRUE, FALSE,
6025 EL_CHAR('R'), -1, -1
6028 Xalpha_s, TRUE, FALSE,
6029 EL_CHAR('S'), -1, -1
6032 Xalpha_t, TRUE, FALSE,
6033 EL_CHAR('T'), -1, -1
6036 Xalpha_u, TRUE, FALSE,
6037 EL_CHAR('U'), -1, -1
6040 Xalpha_v, TRUE, FALSE,
6041 EL_CHAR('V'), -1, -1
6044 Xalpha_w, TRUE, FALSE,
6045 EL_CHAR('W'), -1, -1
6048 Xalpha_x, TRUE, FALSE,
6049 EL_CHAR('X'), -1, -1
6052 Xalpha_y, TRUE, FALSE,
6053 EL_CHAR('Y'), -1, -1
6056 Xalpha_z, TRUE, FALSE,
6057 EL_CHAR('Z'), -1, -1
6060 Xalpha_arrow_e, TRUE, FALSE,
6061 EL_CHAR('>'), -1, -1
6064 Xalpha_arrow_w, TRUE, FALSE,
6065 EL_CHAR('<'), -1, -1
6068 Xalpha_copyr, TRUE, FALSE,
6069 EL_CHAR('©'), -1, -1
6073 Xboom_bug, FALSE, FALSE,
6074 EL_BUG, ACTION_EXPLODING, -1
6077 Xboom_bomb, FALSE, FALSE,
6078 EL_BOMB, ACTION_EXPLODING, -1
6081 Xboom_android, FALSE, FALSE,
6082 EL_EMC_ANDROID, ACTION_OTHER, -1
6085 Xboom_1, FALSE, FALSE,
6086 EL_DEFAULT, ACTION_EXPLODING, -1
6089 Xboom_2, FALSE, FALSE,
6090 EL_DEFAULT, ACTION_EXPLODING, -1
6093 Znormal, FALSE, FALSE,
6097 Zdynamite, FALSE, FALSE,
6101 Zplayer, FALSE, FALSE,
6105 ZBORDER, FALSE, FALSE,
6115 static struct Mapping_EM_to_RND_player
6124 em_player_mapping_list[] =
6128 EL_PLAYER_1, ACTION_MOVING, MV_BIT_UP,
6132 EL_PLAYER_1, ACTION_MOVING, MV_BIT_RIGHT,
6136 EL_PLAYER_1, ACTION_MOVING, MV_BIT_DOWN,
6140 EL_PLAYER_1, ACTION_MOVING, MV_BIT_LEFT,
6144 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_UP,
6148 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_RIGHT,
6152 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_DOWN,
6156 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_LEFT,
6160 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_UP,
6164 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_RIGHT,
6168 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_DOWN,
6172 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_LEFT,
6176 EL_PLAYER_2, ACTION_MOVING, MV_BIT_UP,
6180 EL_PLAYER_2, ACTION_MOVING, MV_BIT_RIGHT,
6184 EL_PLAYER_2, ACTION_MOVING, MV_BIT_DOWN,
6188 EL_PLAYER_2, ACTION_MOVING, MV_BIT_LEFT,
6192 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_UP,
6196 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_RIGHT,
6200 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_DOWN,
6204 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_LEFT,
6208 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_UP,
6212 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_RIGHT,
6216 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_DOWN,
6220 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_LEFT,
6224 EL_PLAYER_1, ACTION_DEFAULT, -1,
6228 EL_PLAYER_2, ACTION_DEFAULT, -1,
6232 EL_PLAYER_3, ACTION_MOVING, MV_BIT_UP,
6236 EL_PLAYER_3, ACTION_MOVING, MV_BIT_RIGHT,
6240 EL_PLAYER_3, ACTION_MOVING, MV_BIT_DOWN,
6244 EL_PLAYER_3, ACTION_MOVING, MV_BIT_LEFT,
6248 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_UP,
6252 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_RIGHT,
6256 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_DOWN,
6260 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_LEFT,
6264 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_UP,
6268 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_RIGHT,
6272 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_DOWN,
6276 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_LEFT,
6280 EL_PLAYER_4, ACTION_MOVING, MV_BIT_UP,
6284 EL_PLAYER_4, ACTION_MOVING, MV_BIT_RIGHT,
6288 EL_PLAYER_4, ACTION_MOVING, MV_BIT_DOWN,
6292 EL_PLAYER_4, ACTION_MOVING, MV_BIT_LEFT,
6296 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_UP,
6300 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_RIGHT,
6304 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_DOWN,
6308 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_LEFT,
6312 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_UP,
6316 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_RIGHT,
6320 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_DOWN,
6324 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_LEFT,
6328 EL_PLAYER_3, ACTION_DEFAULT, -1,
6332 EL_PLAYER_4, ACTION_DEFAULT, -1,
6341 int map_element_RND_to_EM(int element_rnd)
6343 static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
6344 static boolean mapping_initialized = FALSE;
6346 if (!mapping_initialized)
6350 /* return "Xalpha_quest" for all undefined elements in mapping array */
6351 for (i = 0; i < NUM_FILE_ELEMENTS; i++)
6352 mapping_RND_to_EM[i] = Xalpha_quest;
6354 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
6355 if (em_object_mapping_list[i].is_rnd_to_em_mapping)
6356 mapping_RND_to_EM[em_object_mapping_list[i].element_rnd] =
6357 em_object_mapping_list[i].element_em;
6359 mapping_initialized = TRUE;
6362 if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
6363 return mapping_RND_to_EM[element_rnd];
6365 Error(ERR_WARN, "invalid RND level element %d", element_rnd);
6370 int map_element_EM_to_RND(int element_em)
6372 static unsigned short mapping_EM_to_RND[TILE_MAX];
6373 static boolean mapping_initialized = FALSE;
6375 if (!mapping_initialized)
6379 /* return "EL_UNKNOWN" for all undefined elements in mapping array */
6380 for (i = 0; i < TILE_MAX; i++)
6381 mapping_EM_to_RND[i] = EL_UNKNOWN;
6383 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
6384 mapping_EM_to_RND[em_object_mapping_list[i].element_em] =
6385 em_object_mapping_list[i].element_rnd;
6387 mapping_initialized = TRUE;
6390 if (element_em >= 0 && element_em < TILE_MAX)
6391 return mapping_EM_to_RND[element_em];
6393 Error(ERR_WARN, "invalid EM level element %d", element_em);
6398 void map_android_clone_elements_RND_to_EM(struct LevelInfo *level)
6400 struct LevelInfo_EM *level_em = level->native_em_level;
6401 struct LEVEL *lev = level_em->lev;
6404 for (i = 0; i < TILE_MAX; i++)
6405 lev->android_array[i] = Xblank;
6407 for (i = 0; i < level->num_android_clone_elements; i++)
6409 int element_rnd = level->android_clone_element[i];
6410 int element_em = map_element_RND_to_EM(element_rnd);
6412 for (j = 0; em_object_mapping_list[j].element_em != -1; j++)
6413 if (em_object_mapping_list[j].element_rnd == element_rnd)
6414 lev->android_array[em_object_mapping_list[j].element_em] = element_em;
6418 void map_android_clone_elements_EM_to_RND(struct LevelInfo *level)
6420 struct LevelInfo_EM *level_em = level->native_em_level;
6421 struct LEVEL *lev = level_em->lev;
6424 level->num_android_clone_elements = 0;
6426 for (i = 0; i < TILE_MAX; i++)
6428 int element_em = lev->android_array[i];
6430 boolean element_found = FALSE;
6432 if (element_em == Xblank)
6435 element_rnd = map_element_EM_to_RND(element_em);
6437 for (j = 0; j < level->num_android_clone_elements; j++)
6438 if (level->android_clone_element[j] == element_rnd)
6439 element_found = TRUE;
6443 level->android_clone_element[level->num_android_clone_elements++] =
6446 if (level->num_android_clone_elements == MAX_ANDROID_ELEMENTS)
6451 if (level->num_android_clone_elements == 0)
6453 level->num_android_clone_elements = 1;
6454 level->android_clone_element[0] = EL_EMPTY;
6458 int map_direction_RND_to_EM(int direction)
6460 return (direction == MV_UP ? 0 :
6461 direction == MV_RIGHT ? 1 :
6462 direction == MV_DOWN ? 2 :
6463 direction == MV_LEFT ? 3 :
6467 int map_direction_EM_to_RND(int direction)
6469 return (direction == 0 ? MV_UP :
6470 direction == 1 ? MV_RIGHT :
6471 direction == 2 ? MV_DOWN :
6472 direction == 3 ? MV_LEFT :
6476 int map_element_RND_to_SP(int element_rnd)
6478 int element_sp = 0x20; /* map unknown elements to yellow "hardware" */
6480 if (element_rnd >= EL_SP_START &&
6481 element_rnd <= EL_SP_END)
6482 element_sp = element_rnd - EL_SP_START;
6483 else if (element_rnd == EL_EMPTY_SPACE)
6485 else if (element_rnd == EL_INVISIBLE_WALL)
6491 int map_element_SP_to_RND(int element_sp)
6493 int element_rnd = EL_UNKNOWN;
6495 if (element_sp >= 0x00 &&
6497 element_rnd = EL_SP_START + element_sp;
6498 else if (element_sp == 0x28)
6499 element_rnd = EL_INVISIBLE_WALL;
6504 int map_action_SP_to_RND(int action_sp)
6508 case actActive: return ACTION_ACTIVE;
6509 case actImpact: return ACTION_IMPACT;
6510 case actExploding: return ACTION_EXPLODING;
6511 case actDigging: return ACTION_DIGGING;
6512 case actSnapping: return ACTION_SNAPPING;
6513 case actCollecting: return ACTION_COLLECTING;
6514 case actPassing: return ACTION_PASSING;
6515 case actPushing: return ACTION_PUSHING;
6516 case actDropping: return ACTION_DROPPING;
6518 default: return ACTION_DEFAULT;
6522 int get_next_element(int element)
6526 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
6527 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
6528 case EL_QUICKSAND_FAST_FILLING: return EL_QUICKSAND_FAST_FULL;
6529 case EL_QUICKSAND_FAST_EMPTYING: return EL_QUICKSAND_FAST_EMPTY;
6530 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
6531 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
6532 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
6533 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
6534 case EL_DC_MAGIC_WALL_FILLING: return EL_DC_MAGIC_WALL_FULL;
6535 case EL_DC_MAGIC_WALL_EMPTYING: return EL_DC_MAGIC_WALL_ACTIVE;
6536 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
6538 default: return element;
6543 int el_act_dir2img(int element, int action, int direction)
6545 element = GFX_ELEMENT(element);
6547 if (direction == MV_NONE)
6548 return element_info[element].graphic[action];
6550 direction = MV_DIR_TO_BIT(direction);
6552 return element_info[element].direction_graphic[action][direction];
6555 int el_act_dir2img(int element, int action, int direction)
6557 element = GFX_ELEMENT(element);
6558 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
6560 /* direction_graphic[][] == graphic[] for undefined direction graphics */
6561 return element_info[element].direction_graphic[action][direction];
6566 static int el_act_dir2crm(int element, int action, int direction)
6568 element = GFX_ELEMENT(element);
6570 if (direction == MV_NONE)
6571 return element_info[element].crumbled[action];
6573 direction = MV_DIR_TO_BIT(direction);
6575 return element_info[element].direction_crumbled[action][direction];
6578 static int el_act_dir2crm(int element, int action, int direction)
6580 element = GFX_ELEMENT(element);
6581 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
6583 /* direction_graphic[][] == graphic[] for undefined direction graphics */
6584 return element_info[element].direction_crumbled[action][direction];
6588 int el_act2img(int element, int action)
6590 element = GFX_ELEMENT(element);
6592 return element_info[element].graphic[action];
6595 int el_act2crm(int element, int action)
6597 element = GFX_ELEMENT(element);
6599 return element_info[element].crumbled[action];
6602 int el_dir2img(int element, int direction)
6604 element = GFX_ELEMENT(element);
6606 return el_act_dir2img(element, ACTION_DEFAULT, direction);
6609 int el2baseimg(int element)
6611 return element_info[element].graphic[ACTION_DEFAULT];
6614 int el2img(int element)
6616 element = GFX_ELEMENT(element);
6618 return element_info[element].graphic[ACTION_DEFAULT];
6621 int el2edimg(int element)
6623 element = GFX_ELEMENT(element);
6625 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
6628 int el2preimg(int element)
6630 element = GFX_ELEMENT(element);
6632 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
6635 int el2panelimg(int element)
6637 element = GFX_ELEMENT(element);
6639 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PANEL];
6642 int font2baseimg(int font_nr)
6644 return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
6647 int getBeltNrFromBeltElement(int element)
6649 return (element < EL_CONVEYOR_BELT_2_LEFT ? 0 :
6650 element < EL_CONVEYOR_BELT_3_LEFT ? 1 :
6651 element < EL_CONVEYOR_BELT_4_LEFT ? 2 : 3);
6654 int getBeltNrFromBeltActiveElement(int element)
6656 return (element < EL_CONVEYOR_BELT_2_LEFT_ACTIVE ? 0 :
6657 element < EL_CONVEYOR_BELT_3_LEFT_ACTIVE ? 1 :
6658 element < EL_CONVEYOR_BELT_4_LEFT_ACTIVE ? 2 : 3);
6661 int getBeltNrFromBeltSwitchElement(int element)
6663 return (element < EL_CONVEYOR_BELT_2_SWITCH_LEFT ? 0 :
6664 element < EL_CONVEYOR_BELT_3_SWITCH_LEFT ? 1 :
6665 element < EL_CONVEYOR_BELT_4_SWITCH_LEFT ? 2 : 3);
6668 int getBeltDirNrFromBeltElement(int element)
6670 static int belt_base_element[4] =
6672 EL_CONVEYOR_BELT_1_LEFT,
6673 EL_CONVEYOR_BELT_2_LEFT,
6674 EL_CONVEYOR_BELT_3_LEFT,
6675 EL_CONVEYOR_BELT_4_LEFT
6678 int belt_nr = getBeltNrFromBeltElement(element);
6679 int belt_dir_nr = element - belt_base_element[belt_nr];
6681 return (belt_dir_nr % 3);
6684 int getBeltDirNrFromBeltSwitchElement(int element)
6686 static int belt_base_element[4] =
6688 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
6689 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
6690 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
6691 EL_CONVEYOR_BELT_4_SWITCH_LEFT
6694 int belt_nr = getBeltNrFromBeltSwitchElement(element);
6695 int belt_dir_nr = element - belt_base_element[belt_nr];
6697 return (belt_dir_nr % 3);
6700 int getBeltDirFromBeltElement(int element)
6702 static int belt_move_dir[3] =
6709 int belt_dir_nr = getBeltDirNrFromBeltElement(element);
6711 return belt_move_dir[belt_dir_nr];
6714 int getBeltDirFromBeltSwitchElement(int element)
6716 static int belt_move_dir[3] =
6723 int belt_dir_nr = getBeltDirNrFromBeltSwitchElement(element);
6725 return belt_move_dir[belt_dir_nr];
6728 int getBeltElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
6730 static int belt_base_element[4] =
6732 EL_CONVEYOR_BELT_1_LEFT,
6733 EL_CONVEYOR_BELT_2_LEFT,
6734 EL_CONVEYOR_BELT_3_LEFT,
6735 EL_CONVEYOR_BELT_4_LEFT
6738 return belt_base_element[belt_nr] + belt_dir_nr;
6741 int getBeltElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
6743 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
6745 return getBeltElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
6748 int getBeltSwitchElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
6750 static int belt_base_element[4] =
6752 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
6753 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
6754 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
6755 EL_CONVEYOR_BELT_4_SWITCH_LEFT
6758 return belt_base_element[belt_nr] + belt_dir_nr;
6761 int getBeltSwitchElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
6763 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
6765 return getBeltSwitchElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
6768 int getNumActivePlayers_EM()
6770 int num_players = 0;
6776 for (i = 0; i < MAX_PLAYERS; i++)
6777 if (tape.player_participates[i])
6783 int getGameFrameDelay_EM(int native_em_game_frame_delay)
6785 int game_frame_delay_value;
6787 game_frame_delay_value =
6788 (tape.playing && tape.fast_forward ? FfwdFrameDelay :
6789 GameFrameDelay == GAME_FRAME_DELAY ? native_em_game_frame_delay :
6792 if (tape.playing && tape.warp_forward && !tape.pausing)
6793 game_frame_delay_value = 0;
6795 return game_frame_delay_value;
6798 unsigned int InitRND(long seed)
6800 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
6801 return InitEngineRandom_EM(seed);
6802 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
6803 return InitEngineRandom_SP(seed);
6805 return InitEngineRandom_RND(seed);
6809 static struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
6810 static struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
6813 inline static int get_effective_element_EM(int tile, int frame_em)
6815 int element = object_mapping[tile].element_rnd;
6816 int action = object_mapping[tile].action;
6817 boolean is_backside = object_mapping[tile].is_backside;
6818 boolean action_removing = (action == ACTION_DIGGING ||
6819 action == ACTION_SNAPPING ||
6820 action == ACTION_COLLECTING);
6826 case Yacid_splash_eB:
6827 case Yacid_splash_wB:
6828 return (frame_em > 5 ? EL_EMPTY : element);
6831 case Ydiamond_stone:
6832 // if (!game.use_native_emc_graphics_engine)
6840 else /* frame_em == 7 */
6844 case Yacid_splash_eB:
6845 case Yacid_splash_wB:
6848 case Yemerald_stone:
6851 case Ydiamond_stone:
6855 case Xdrip_stretchB:
6874 case Xsand_stonein_1:
6875 case Xsand_stonein_2:
6876 case Xsand_stonein_3:
6877 case Xsand_stonein_4:
6881 return (is_backside || action_removing ? EL_EMPTY : element);
6886 inline static boolean check_linear_animation_EM(int tile)
6890 case Xsand_stonesand_1:
6891 case Xsand_stonesand_quickout_1:
6892 case Xsand_sandstone_1:
6893 case Xsand_stonein_1:
6894 case Xsand_stoneout_1:
6914 case Yacid_splash_eB:
6915 case Yacid_splash_wB:
6916 case Yemerald_stone:
6924 inline static void set_crumbled_graphics_EM(struct GraphicInfo_EM *g_em,
6925 boolean has_crumbled_graphics,
6926 int crumbled, int sync_frame)
6928 /* if element can be crumbled, but certain action graphics are just empty
6929 space (like instantly snapping sand to empty space in 1 frame), do not
6930 treat these empty space graphics as crumbled graphics in EMC engine */
6931 if (crumbled == IMG_EMPTY_SPACE)
6932 has_crumbled_graphics = FALSE;
6934 if (has_crumbled_graphics)
6936 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
6937 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
6938 g_crumbled->anim_delay,
6939 g_crumbled->anim_mode,
6940 g_crumbled->anim_start_frame,
6943 getGraphicSource(crumbled, frame_crumbled, &g_em->crumbled_bitmap,
6944 &g_em->crumbled_src_x, &g_em->crumbled_src_y);
6946 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
6948 g_em->has_crumbled_graphics = TRUE;
6952 g_em->crumbled_bitmap = NULL;
6953 g_em->crumbled_src_x = 0;
6954 g_em->crumbled_src_y = 0;
6955 g_em->crumbled_border_size = 0;
6957 g_em->has_crumbled_graphics = FALSE;
6961 void ResetGfxAnimation_EM(int x, int y, int tile)
6966 void SetGfxAnimation_EM(struct GraphicInfo_EM *g_em,
6967 int tile, int frame_em, int x, int y)
6969 int action = object_mapping[tile].action;
6971 int direction = object_mapping[tile].direction;
6972 int effective_element = get_effective_element_EM(tile, frame_em);
6973 int graphic = (direction == MV_NONE ?
6974 el_act2img(effective_element, action) :
6975 el_act_dir2img(effective_element, action, direction));
6976 struct GraphicInfo *g = &graphic_info[graphic];
6979 boolean action_removing = (action == ACTION_DIGGING ||
6980 action == ACTION_SNAPPING ||
6981 action == ACTION_COLLECTING);
6982 boolean action_moving = (action == ACTION_FALLING ||
6983 action == ACTION_MOVING ||
6984 action == ACTION_PUSHING ||
6985 action == ACTION_EATING ||
6986 action == ACTION_FILLING ||
6987 action == ACTION_EMPTYING);
6988 boolean action_falling = (action == ACTION_FALLING ||
6989 action == ACTION_FILLING ||
6990 action == ACTION_EMPTYING);
6992 /* special case: graphic uses "2nd movement tile" and has defined
6993 7 frames for movement animation (or less) => use default graphic
6994 for last (8th) frame which ends the movement animation */
6995 if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
6997 action = ACTION_DEFAULT; /* (keep action_* unchanged for now) */
6998 graphic = (direction == MV_NONE ?
6999 el_act2img(effective_element, action) :
7000 el_act_dir2img(effective_element, action, direction));
7002 g = &graphic_info[graphic];
7006 if (tile == Xsand_stonesand_1 ||
7007 tile == Xsand_stonesand_2 ||
7008 tile == Xsand_stonesand_3 ||
7009 tile == Xsand_stonesand_4)
7010 printf("::: 1: quicksand frame %d [%d]\n", GfxFrame[x][y], tile);
7014 if ((action_removing || check_linear_animation_EM(tile)) && frame_em == 0)
7018 // printf("::: resetting... [%d]\n", tile);
7021 if (action_removing || check_linear_animation_EM(tile))
7023 GfxFrame[x][y] = frame_em;
7025 // printf("::: resetting... [%d]\n", tile);
7028 else if (action_moving)
7030 boolean is_backside = object_mapping[tile].is_backside;
7034 int direction = object_mapping[tile].direction;
7035 int move_dir = (action_falling ? MV_DOWN : direction);
7040 /* !!! TEST !!! NEW !!! DOES NOT WORK RIGHT YET !!! */
7041 if (g->double_movement && frame_em == 0)
7045 // printf("::: resetting... [%d]\n", tile);
7049 if (move_dir == MV_LEFT)
7050 GfxFrame[x - 1][y] = GfxFrame[x][y];
7051 else if (move_dir == MV_RIGHT)
7052 GfxFrame[x + 1][y] = GfxFrame[x][y];
7053 else if (move_dir == MV_UP)
7054 GfxFrame[x][y - 1] = GfxFrame[x][y];
7055 else if (move_dir == MV_DOWN)
7056 GfxFrame[x][y + 1] = GfxFrame[x][y];
7063 /* special case: animation for Xsand_stonesand_quickout_1/2 twice as fast */
7064 if (tile == Xsand_stonesand_quickout_1 ||
7065 tile == Xsand_stonesand_quickout_2)
7070 if (tile == Xsand_stonesand_1 ||
7071 tile == Xsand_stonesand_2 ||
7072 tile == Xsand_stonesand_3 ||
7073 tile == Xsand_stonesand_4)
7074 printf("::: 2: quicksand frame %d [%d]\n", GfxFrame[x][y], tile);
7078 if (graphic_info[graphic].anim_global_sync)
7079 sync_frame = FrameCounter;
7080 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
7081 sync_frame = GfxFrame[x][y];
7083 sync_frame = 0; /* playfield border (pseudo steel) */
7085 SetRandomAnimationValue(x, y);
7087 int frame = getAnimationFrame(g->anim_frames,
7090 g->anim_start_frame,
7093 g_em->unique_identifier =
7094 (graphic << 16) | ((frame % 8) << 12) | (g_em->width << 6) | g_em->height;
7098 void getGraphicSourceObjectExt_EM(struct GraphicInfo_EM *g_em,
7099 int tile, int frame_em, int x, int y)
7101 int action = object_mapping[tile].action;
7102 int direction = object_mapping[tile].direction;
7103 boolean is_backside = object_mapping[tile].is_backside;
7104 int effective_element = get_effective_element_EM(tile, frame_em);
7106 int effective_action = action;
7108 int effective_action = (frame_em < 7 ? action : ACTION_DEFAULT);
7110 int graphic = (direction == MV_NONE ?
7111 el_act2img(effective_element, effective_action) :
7112 el_act_dir2img(effective_element, effective_action,
7114 int crumbled = (direction == MV_NONE ?
7115 el_act2crm(effective_element, effective_action) :
7116 el_act_dir2crm(effective_element, effective_action,
7118 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
7119 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
7120 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
7121 struct GraphicInfo *g = &graphic_info[graphic];
7123 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
7127 /* special case: graphic uses "2nd movement tile" and has defined
7128 7 frames for movement animation (or less) => use default graphic
7129 for last (8th) frame which ends the movement animation */
7130 if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
7132 effective_action = ACTION_DEFAULT;
7133 graphic = (direction == MV_NONE ?
7134 el_act2img(effective_element, effective_action) :
7135 el_act_dir2img(effective_element, effective_action,
7137 crumbled = (direction == MV_NONE ?
7138 el_act2crm(effective_element, effective_action) :
7139 el_act_dir2crm(effective_element, effective_action,
7142 g = &graphic_info[graphic];
7152 if (frame_em == 0) /* reset animation frame for certain elements */
7154 if (check_linear_animation_EM(tile))
7159 if (graphic_info[graphic].anim_global_sync)
7160 sync_frame = FrameCounter;
7161 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
7162 sync_frame = GfxFrame[x][y];
7164 sync_frame = 0; /* playfield border (pseudo steel) */
7166 SetRandomAnimationValue(x, y);
7171 int xxx_sync_frame = (i == Xdrip_stretch ? 7 :
7172 i == Xdrip_stretchB ? 7 :
7173 i == Ydrip_s2 ? j + 8 :
7174 i == Ydrip_s2B ? j + 8 :
7183 i == Xfake_acid_1 ? 0 :
7184 i == Xfake_acid_2 ? 10 :
7185 i == Xfake_acid_3 ? 20 :
7186 i == Xfake_acid_4 ? 30 :
7187 i == Xfake_acid_5 ? 40 :
7188 i == Xfake_acid_6 ? 50 :
7189 i == Xfake_acid_7 ? 60 :
7190 i == Xfake_acid_8 ? 70 :
7192 i == Xball_2B ? j + 8 :
7193 i == Yball_eat ? j + 1 :
7194 i == Ykey_1_eat ? j + 1 :
7195 i == Ykey_2_eat ? j + 1 :
7196 i == Ykey_3_eat ? j + 1 :
7197 i == Ykey_4_eat ? j + 1 :
7198 i == Ykey_5_eat ? j + 1 :
7199 i == Ykey_6_eat ? j + 1 :
7200 i == Ykey_7_eat ? j + 1 :
7201 i == Ykey_8_eat ? j + 1 :
7202 i == Ylenses_eat ? j + 1 :
7203 i == Ymagnify_eat ? j + 1 :
7204 i == Ygrass_eat ? j + 1 :
7205 i == Ydirt_eat ? j + 1 :
7206 i == Xamoeba_1 ? 0 :
7207 i == Xamoeba_2 ? 1 :
7208 i == Xamoeba_3 ? 2 :
7209 i == Xamoeba_4 ? 3 :
7210 i == Xamoeba_5 ? 0 :
7211 i == Xamoeba_6 ? 1 :
7212 i == Xamoeba_7 ? 2 :
7213 i == Xamoeba_8 ? 3 :
7214 i == Xexit_2 ? j + 8 :
7215 i == Xexit_3 ? j + 16 :
7216 i == Xdynamite_1 ? 0 :
7217 i == Xdynamite_2 ? 8 :
7218 i == Xdynamite_3 ? 16 :
7219 i == Xdynamite_4 ? 24 :
7220 i == Xsand_stonein_1 ? j + 1 :
7221 i == Xsand_stonein_2 ? j + 9 :
7222 i == Xsand_stonein_3 ? j + 17 :
7223 i == Xsand_stonein_4 ? j + 25 :
7224 i == Xsand_stoneout_1 && j == 0 ? 0 :
7225 i == Xsand_stoneout_1 && j == 1 ? 0 :
7226 i == Xsand_stoneout_1 && j == 2 ? 1 :
7227 i == Xsand_stoneout_1 && j == 3 ? 2 :
7228 i == Xsand_stoneout_1 && j == 4 ? 2 :
7229 i == Xsand_stoneout_1 && j == 5 ? 3 :
7230 i == Xsand_stoneout_1 && j == 6 ? 4 :
7231 i == Xsand_stoneout_1 && j == 7 ? 4 :
7232 i == Xsand_stoneout_2 && j == 0 ? 5 :
7233 i == Xsand_stoneout_2 && j == 1 ? 6 :
7234 i == Xsand_stoneout_2 && j == 2 ? 7 :
7235 i == Xsand_stoneout_2 && j == 3 ? 8 :
7236 i == Xsand_stoneout_2 && j == 4 ? 9 :
7237 i == Xsand_stoneout_2 && j == 5 ? 11 :
7238 i == Xsand_stoneout_2 && j == 6 ? 13 :
7239 i == Xsand_stoneout_2 && j == 7 ? 15 :
7240 i == Xboom_bug && j == 1 ? 2 :
7241 i == Xboom_bug && j == 2 ? 2 :
7242 i == Xboom_bug && j == 3 ? 4 :
7243 i == Xboom_bug && j == 4 ? 4 :
7244 i == Xboom_bug && j == 5 ? 2 :
7245 i == Xboom_bug && j == 6 ? 2 :
7246 i == Xboom_bug && j == 7 ? 0 :
7247 i == Xboom_bomb && j == 1 ? 2 :
7248 i == Xboom_bomb && j == 2 ? 2 :
7249 i == Xboom_bomb && j == 3 ? 4 :
7250 i == Xboom_bomb && j == 4 ? 4 :
7251 i == Xboom_bomb && j == 5 ? 2 :
7252 i == Xboom_bomb && j == 6 ? 2 :
7253 i == Xboom_bomb && j == 7 ? 0 :
7254 i == Xboom_android && j == 7 ? 6 :
7255 i == Xboom_1 && j == 1 ? 2 :
7256 i == Xboom_1 && j == 2 ? 2 :
7257 i == Xboom_1 && j == 3 ? 4 :
7258 i == Xboom_1 && j == 4 ? 4 :
7259 i == Xboom_1 && j == 5 ? 6 :
7260 i == Xboom_1 && j == 6 ? 6 :
7261 i == Xboom_1 && j == 7 ? 8 :
7262 i == Xboom_2 && j == 0 ? 8 :
7263 i == Xboom_2 && j == 1 ? 8 :
7264 i == Xboom_2 && j == 2 ? 10 :
7265 i == Xboom_2 && j == 3 ? 10 :
7266 i == Xboom_2 && j == 4 ? 10 :
7267 i == Xboom_2 && j == 5 ? 12 :
7268 i == Xboom_2 && j == 6 ? 12 :
7269 i == Xboom_2 && j == 7 ? 12 :
7271 special_animation && j == 4 ? 3 :
7272 effective_action != action ? 0 :
7278 int xxx_effective_action;
7279 int xxx_has_action_graphics;
7282 int element = object_mapping[i].element_rnd;
7283 int action = object_mapping[i].action;
7284 int direction = object_mapping[i].direction;
7285 boolean is_backside = object_mapping[i].is_backside;
7287 boolean action_removing = (action == ACTION_DIGGING ||
7288 action == ACTION_SNAPPING ||
7289 action == ACTION_COLLECTING);
7291 boolean action_exploding = ((action == ACTION_EXPLODING ||
7292 action == ACTION_SMASHED_BY_ROCK ||
7293 action == ACTION_SMASHED_BY_SPRING) &&
7294 element != EL_DIAMOND);
7295 boolean action_active = (action == ACTION_ACTIVE);
7296 boolean action_other = (action == ACTION_OTHER);
7300 int effective_element = get_effective_element_EM(i, j);
7302 int effective_element = (j > 5 && i == Yacid_splash_eB ? EL_EMPTY :
7303 j > 5 && i == Yacid_splash_wB ? EL_EMPTY :
7305 i == Xdrip_stretch ? element :
7306 i == Xdrip_stretchB ? element :
7307 i == Ydrip_s1 ? element :
7308 i == Ydrip_s1B ? element :
7309 i == Xball_1B ? element :
7310 i == Xball_2 ? element :
7311 i == Xball_2B ? element :
7312 i == Yball_eat ? element :
7313 i == Ykey_1_eat ? element :
7314 i == Ykey_2_eat ? element :
7315 i == Ykey_3_eat ? element :
7316 i == Ykey_4_eat ? element :
7317 i == Ykey_5_eat ? element :
7318 i == Ykey_6_eat ? element :
7319 i == Ykey_7_eat ? element :
7320 i == Ykey_8_eat ? element :
7321 i == Ylenses_eat ? element :
7322 i == Ymagnify_eat ? element :
7323 i == Ygrass_eat ? element :
7324 i == Ydirt_eat ? element :
7325 i == Yemerald_stone ? EL_EMERALD :
7326 i == Ydiamond_stone ? EL_ROCK :
7327 i == Xsand_stonein_1 ? element :
7328 i == Xsand_stonein_2 ? element :
7329 i == Xsand_stonein_3 ? element :
7330 i == Xsand_stonein_4 ? element :
7331 is_backside ? EL_EMPTY :
7332 action_removing ? EL_EMPTY :
7335 int effective_action = (j < 7 ? action :
7336 i == Xdrip_stretch ? action :
7337 i == Xdrip_stretchB ? action :
7338 i == Ydrip_s1 ? action :
7339 i == Ydrip_s1B ? action :
7340 i == Xball_1B ? action :
7341 i == Xball_2 ? action :
7342 i == Xball_2B ? action :
7343 i == Yball_eat ? action :
7344 i == Ykey_1_eat ? action :
7345 i == Ykey_2_eat ? action :
7346 i == Ykey_3_eat ? action :
7347 i == Ykey_4_eat ? action :
7348 i == Ykey_5_eat ? action :
7349 i == Ykey_6_eat ? action :
7350 i == Ykey_7_eat ? action :
7351 i == Ykey_8_eat ? action :
7352 i == Ylenses_eat ? action :
7353 i == Ymagnify_eat ? action :
7354 i == Ygrass_eat ? action :
7355 i == Ydirt_eat ? action :
7356 i == Xsand_stonein_1 ? action :
7357 i == Xsand_stonein_2 ? action :
7358 i == Xsand_stonein_3 ? action :
7359 i == Xsand_stonein_4 ? action :
7360 i == Xsand_stoneout_1 ? action :
7361 i == Xsand_stoneout_2 ? action :
7362 i == Xboom_android ? ACTION_EXPLODING :
7363 action_exploding ? ACTION_EXPLODING :
7364 action_active ? action :
7365 action_other ? action :
7367 int graphic = (el_act_dir2img(effective_element, effective_action,
7369 int crumbled = (el_act_dir2crm(effective_element, effective_action,
7371 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
7372 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
7373 boolean has_action_graphics = (graphic != base_graphic);
7374 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
7375 struct GraphicInfo *g = &graphic_info[graphic];
7377 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
7379 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
7382 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
7383 boolean special_animation = (action != ACTION_DEFAULT &&
7384 g->anim_frames == 3 &&
7385 g->anim_delay == 2 &&
7386 g->anim_mode & ANIM_LINEAR);
7387 xxx_sync_frame = (i == Xdrip_stretch ? 7 :
7388 i == Xdrip_stretchB ? 7 :
7389 i == Ydrip_s2 ? j + 8 :
7390 i == Ydrip_s2B ? j + 8 :
7399 i == Xfake_acid_1 ? 0 :
7400 i == Xfake_acid_2 ? 10 :
7401 i == Xfake_acid_3 ? 20 :
7402 i == Xfake_acid_4 ? 30 :
7403 i == Xfake_acid_5 ? 40 :
7404 i == Xfake_acid_6 ? 50 :
7405 i == Xfake_acid_7 ? 60 :
7406 i == Xfake_acid_8 ? 70 :
7408 i == Xball_2B ? j + 8 :
7409 i == Yball_eat ? j + 1 :
7410 i == Ykey_1_eat ? j + 1 :
7411 i == Ykey_2_eat ? j + 1 :
7412 i == Ykey_3_eat ? j + 1 :
7413 i == Ykey_4_eat ? j + 1 :
7414 i == Ykey_5_eat ? j + 1 :
7415 i == Ykey_6_eat ? j + 1 :
7416 i == Ykey_7_eat ? j + 1 :
7417 i == Ykey_8_eat ? j + 1 :
7418 i == Ylenses_eat ? j + 1 :
7419 i == Ymagnify_eat ? j + 1 :
7420 i == Ygrass_eat ? j + 1 :
7421 i == Ydirt_eat ? j + 1 :
7422 i == Xamoeba_1 ? 0 :
7423 i == Xamoeba_2 ? 1 :
7424 i == Xamoeba_3 ? 2 :
7425 i == Xamoeba_4 ? 3 :
7426 i == Xamoeba_5 ? 0 :
7427 i == Xamoeba_6 ? 1 :
7428 i == Xamoeba_7 ? 2 :
7429 i == Xamoeba_8 ? 3 :
7430 i == Xexit_2 ? j + 8 :
7431 i == Xexit_3 ? j + 16 :
7432 i == Xdynamite_1 ? 0 :
7433 i == Xdynamite_2 ? 8 :
7434 i == Xdynamite_3 ? 16 :
7435 i == Xdynamite_4 ? 24 :
7436 i == Xsand_stonein_1 ? j + 1 :
7437 i == Xsand_stonein_2 ? j + 9 :
7438 i == Xsand_stonein_3 ? j + 17 :
7439 i == Xsand_stonein_4 ? j + 25 :
7440 i == Xsand_stoneout_1 && j == 0 ? 0 :
7441 i == Xsand_stoneout_1 && j == 1 ? 0 :
7442 i == Xsand_stoneout_1 && j == 2 ? 1 :
7443 i == Xsand_stoneout_1 && j == 3 ? 2 :
7444 i == Xsand_stoneout_1 && j == 4 ? 2 :
7445 i == Xsand_stoneout_1 && j == 5 ? 3 :
7446 i == Xsand_stoneout_1 && j == 6 ? 4 :
7447 i == Xsand_stoneout_1 && j == 7 ? 4 :
7448 i == Xsand_stoneout_2 && j == 0 ? 5 :
7449 i == Xsand_stoneout_2 && j == 1 ? 6 :
7450 i == Xsand_stoneout_2 && j == 2 ? 7 :
7451 i == Xsand_stoneout_2 && j == 3 ? 8 :
7452 i == Xsand_stoneout_2 && j == 4 ? 9 :
7453 i == Xsand_stoneout_2 && j == 5 ? 11 :
7454 i == Xsand_stoneout_2 && j == 6 ? 13 :
7455 i == Xsand_stoneout_2 && j == 7 ? 15 :
7456 i == Xboom_bug && j == 1 ? 2 :
7457 i == Xboom_bug && j == 2 ? 2 :
7458 i == Xboom_bug && j == 3 ? 4 :
7459 i == Xboom_bug && j == 4 ? 4 :
7460 i == Xboom_bug && j == 5 ? 2 :
7461 i == Xboom_bug && j == 6 ? 2 :
7462 i == Xboom_bug && j == 7 ? 0 :
7463 i == Xboom_bomb && j == 1 ? 2 :
7464 i == Xboom_bomb && j == 2 ? 2 :
7465 i == Xboom_bomb && j == 3 ? 4 :
7466 i == Xboom_bomb && j == 4 ? 4 :
7467 i == Xboom_bomb && j == 5 ? 2 :
7468 i == Xboom_bomb && j == 6 ? 2 :
7469 i == Xboom_bomb && j == 7 ? 0 :
7470 i == Xboom_android && j == 7 ? 6 :
7471 i == Xboom_1 && j == 1 ? 2 :
7472 i == Xboom_1 && j == 2 ? 2 :
7473 i == Xboom_1 && j == 3 ? 4 :
7474 i == Xboom_1 && j == 4 ? 4 :
7475 i == Xboom_1 && j == 5 ? 6 :
7476 i == Xboom_1 && j == 6 ? 6 :
7477 i == Xboom_1 && j == 7 ? 8 :
7478 i == Xboom_2 && j == 0 ? 8 :
7479 i == Xboom_2 && j == 1 ? 8 :
7480 i == Xboom_2 && j == 2 ? 10 :
7481 i == Xboom_2 && j == 3 ? 10 :
7482 i == Xboom_2 && j == 4 ? 10 :
7483 i == Xboom_2 && j == 5 ? 12 :
7484 i == Xboom_2 && j == 6 ? 12 :
7485 i == Xboom_2 && j == 7 ? 12 :
7486 special_animation && j == 4 ? 3 :
7487 effective_action != action ? 0 :
7490 xxx_effective_action = effective_action;
7491 xxx_has_action_graphics = has_action_graphics;
7496 int frame = getAnimationFrame(g->anim_frames,
7499 g->anim_start_frame,
7513 int old_src_x = g_em->src_x;
7514 int old_src_y = g_em->src_y;
7518 getGraphicSourceExt(graphic, frame, &g_em->bitmap, &g_em->src_x, &g_em->src_y,
7519 g->double_movement && is_backside);
7521 getGraphicSourceExt(graphic, frame, &g_em->bitmap,
7522 &g_em->src_x, &g_em->src_y, FALSE);
7527 if (tile == Ydiamond_stone)
7528 printf("::: stone smashing diamond... %d: %d, %d, %d, %d, %d -> %d [%d, %d, %d, %d, %d, %d] [%d]\n",
7533 g->anim_start_frame,
7536 g_em->src_x, g_em->src_y,
7537 g_em->src_offset_x, g_em->src_offset_y,
7538 g_em->dst_offset_x, g_em->dst_offset_y,
7550 if (graphic == IMG_BUG_MOVING_RIGHT)
7551 printf("::: %d, %d, %d: %d, %d [%d, %d -> %d, %d]\n", graphic, x, y,
7552 g->double_movement, is_backside,
7553 old_src_x, old_src_y, g_em->src_x, g_em->src_y);
7561 g_em->src_offset_x = 0;
7562 g_em->src_offset_y = 0;
7563 g_em->dst_offset_x = 0;
7564 g_em->dst_offset_y = 0;
7565 g_em->width = TILEX;
7566 g_em->height = TILEY;
7568 g_em->preserve_background = FALSE;
7571 /* (updating the "crumbled" graphic definitions is probably not really needed,
7572 as animations for crumbled graphics can't be longer than one EMC cycle) */
7574 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
7579 g_em->crumbled_bitmap = NULL;
7580 g_em->crumbled_src_x = 0;
7581 g_em->crumbled_src_y = 0;
7583 g_em->has_crumbled_graphics = FALSE;
7585 if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
7587 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
7588 g_crumbled->anim_delay,
7589 g_crumbled->anim_mode,
7590 g_crumbled->anim_start_frame,
7593 getGraphicSource(crumbled, frame_crumbled, &g_em->crumbled_bitmap,
7594 &g_em->crumbled_src_x, &g_em->crumbled_src_y);
7596 g_em->has_crumbled_graphics = TRUE;
7602 int effective_action = xxx_effective_action;
7603 int has_action_graphics = xxx_has_action_graphics;
7605 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
7606 effective_action == ACTION_MOVING ||
7607 effective_action == ACTION_PUSHING ||
7608 effective_action == ACTION_EATING)) ||
7609 (!has_action_graphics && (effective_action == ACTION_FILLING ||
7610 effective_action == ACTION_EMPTYING)))
7613 (effective_action == ACTION_FALLING ||
7614 effective_action == ACTION_FILLING ||
7615 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
7616 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
7617 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
7618 int num_steps = (i == Ydrip_s1 ? 16 :
7619 i == Ydrip_s1B ? 16 :
7620 i == Ydrip_s2 ? 16 :
7621 i == Ydrip_s2B ? 16 :
7622 i == Xsand_stonein_1 ? 32 :
7623 i == Xsand_stonein_2 ? 32 :
7624 i == Xsand_stonein_3 ? 32 :
7625 i == Xsand_stonein_4 ? 32 :
7626 i == Xsand_stoneout_1 ? 16 :
7627 i == Xsand_stoneout_2 ? 16 : 8);
7628 int cx = ABS(dx) * (TILEX / num_steps);
7629 int cy = ABS(dy) * (TILEY / num_steps);
7630 int step_frame = (i == Ydrip_s2 ? j + 8 :
7631 i == Ydrip_s2B ? j + 8 :
7632 i == Xsand_stonein_2 ? j + 8 :
7633 i == Xsand_stonein_3 ? j + 16 :
7634 i == Xsand_stonein_4 ? j + 24 :
7635 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
7636 int step = (is_backside ? step_frame : num_steps - step_frame);
7638 if (is_backside) /* tile where movement starts */
7640 if (dx < 0 || dy < 0)
7642 g_em->src_offset_x = cx * step;
7643 g_em->src_offset_y = cy * step;
7647 g_em->dst_offset_x = cx * step;
7648 g_em->dst_offset_y = cy * step;
7651 else /* tile where movement ends */
7653 if (dx < 0 || dy < 0)
7655 g_em->dst_offset_x = cx * step;
7656 g_em->dst_offset_y = cy * step;
7660 g_em->src_offset_x = cx * step;
7661 g_em->src_offset_y = cy * step;
7665 g_em->width = TILEX - cx * step;
7666 g_em->height = TILEY - cy * step;
7669 /* create unique graphic identifier to decide if tile must be redrawn */
7670 /* bit 31 - 16 (16 bit): EM style graphic
7671 bit 15 - 12 ( 4 bit): EM style frame
7672 bit 11 - 6 ( 6 bit): graphic width
7673 bit 5 - 0 ( 6 bit): graphic height */
7674 g_em->unique_identifier =
7675 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
7681 void getGraphicSourcePlayerExt_EM(struct GraphicInfo_EM *g_em,
7682 int player_nr, int anim, int frame_em)
7684 int element = player_mapping[player_nr][anim].element_rnd;
7685 int action = player_mapping[player_nr][anim].action;
7686 int direction = player_mapping[player_nr][anim].direction;
7687 int graphic = (direction == MV_NONE ?
7688 el_act2img(element, action) :
7689 el_act_dir2img(element, action, direction));
7690 struct GraphicInfo *g = &graphic_info[graphic];
7693 InitPlayerGfxAnimation(&stored_player[player_nr], action, direction);
7695 stored_player[player_nr].StepFrame = frame_em;
7697 sync_frame = stored_player[player_nr].Frame;
7699 int frame = getAnimationFrame(g->anim_frames,
7702 g->anim_start_frame,
7705 getGraphicSourceExt(graphic, frame, &g_em->bitmap,
7706 &g_em->src_x, &g_em->src_y, FALSE);
7709 printf("::: %d: %d, %d [%d]\n",
7711 stored_player[player_nr].Frame,
7712 stored_player[player_nr].StepFrame,
7717 void InitGraphicInfo_EM(void)
7720 struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
7721 struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
7726 int num_em_gfx_errors = 0;
7728 if (graphic_info_em_object[0][0].bitmap == NULL)
7730 /* EM graphics not yet initialized in em_open_all() */
7735 printf("::: [4 errors can be ignored (1 x 'bomb', 3 x 'em_dynamite']\n");
7738 /* always start with reliable default values */
7739 for (i = 0; i < TILE_MAX; i++)
7741 object_mapping[i].element_rnd = EL_UNKNOWN;
7742 object_mapping[i].is_backside = FALSE;
7743 object_mapping[i].action = ACTION_DEFAULT;
7744 object_mapping[i].direction = MV_NONE;
7747 /* always start with reliable default values */
7748 for (p = 0; p < MAX_PLAYERS; p++)
7750 for (i = 0; i < SPR_MAX; i++)
7752 player_mapping[p][i].element_rnd = EL_UNKNOWN;
7753 player_mapping[p][i].action = ACTION_DEFAULT;
7754 player_mapping[p][i].direction = MV_NONE;
7758 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
7760 int e = em_object_mapping_list[i].element_em;
7762 object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd;
7763 object_mapping[e].is_backside = em_object_mapping_list[i].is_backside;
7765 if (em_object_mapping_list[i].action != -1)
7766 object_mapping[e].action = em_object_mapping_list[i].action;
7768 if (em_object_mapping_list[i].direction != -1)
7769 object_mapping[e].direction =
7770 MV_DIR_FROM_BIT(em_object_mapping_list[i].direction);
7773 for (i = 0; em_player_mapping_list[i].action_em != -1; i++)
7775 int a = em_player_mapping_list[i].action_em;
7776 int p = em_player_mapping_list[i].player_nr;
7778 player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd;
7780 if (em_player_mapping_list[i].action != -1)
7781 player_mapping[p][a].action = em_player_mapping_list[i].action;
7783 if (em_player_mapping_list[i].direction != -1)
7784 player_mapping[p][a].direction =
7785 MV_DIR_FROM_BIT(em_player_mapping_list[i].direction);
7788 for (i = 0; i < TILE_MAX; i++)
7790 int element = object_mapping[i].element_rnd;
7791 int action = object_mapping[i].action;
7792 int direction = object_mapping[i].direction;
7793 boolean is_backside = object_mapping[i].is_backside;
7795 boolean action_removing = (action == ACTION_DIGGING ||
7796 action == ACTION_SNAPPING ||
7797 action == ACTION_COLLECTING);
7799 boolean action_exploding = ((action == ACTION_EXPLODING ||
7800 action == ACTION_SMASHED_BY_ROCK ||
7801 action == ACTION_SMASHED_BY_SPRING) &&
7802 element != EL_DIAMOND);
7803 boolean action_active = (action == ACTION_ACTIVE);
7804 boolean action_other = (action == ACTION_OTHER);
7806 for (j = 0; j < 8; j++)
7809 int effective_element = get_effective_element_EM(i, j);
7811 int effective_element = (j > 5 && i == Yacid_splash_eB ? EL_EMPTY :
7812 j > 5 && i == Yacid_splash_wB ? EL_EMPTY :
7814 i == Xdrip_stretch ? element :
7815 i == Xdrip_stretchB ? element :
7816 i == Ydrip_s1 ? element :
7817 i == Ydrip_s1B ? element :
7818 i == Xball_1B ? element :
7819 i == Xball_2 ? element :
7820 i == Xball_2B ? element :
7821 i == Yball_eat ? element :
7822 i == Ykey_1_eat ? element :
7823 i == Ykey_2_eat ? element :
7824 i == Ykey_3_eat ? element :
7825 i == Ykey_4_eat ? element :
7826 i == Ykey_5_eat ? element :
7827 i == Ykey_6_eat ? element :
7828 i == Ykey_7_eat ? element :
7829 i == Ykey_8_eat ? element :
7830 i == Ylenses_eat ? element :
7831 i == Ymagnify_eat ? element :
7832 i == Ygrass_eat ? element :
7833 i == Ydirt_eat ? element :
7834 i == Yemerald_stone ? EL_EMERALD :
7835 i == Ydiamond_stone ? EL_ROCK :
7836 i == Xsand_stonein_1 ? element :
7837 i == Xsand_stonein_2 ? element :
7838 i == Xsand_stonein_3 ? element :
7839 i == Xsand_stonein_4 ? element :
7840 is_backside ? EL_EMPTY :
7841 action_removing ? EL_EMPTY :
7844 int effective_action = (j < 7 ? action :
7845 i == Xdrip_stretch ? action :
7846 i == Xdrip_stretchB ? action :
7847 i == Ydrip_s1 ? action :
7848 i == Ydrip_s1B ? action :
7849 i == Xball_1B ? action :
7850 i == Xball_2 ? action :
7851 i == Xball_2B ? action :
7852 i == Yball_eat ? action :
7853 i == Ykey_1_eat ? action :
7854 i == Ykey_2_eat ? action :
7855 i == Ykey_3_eat ? action :
7856 i == Ykey_4_eat ? action :
7857 i == Ykey_5_eat ? action :
7858 i == Ykey_6_eat ? action :
7859 i == Ykey_7_eat ? action :
7860 i == Ykey_8_eat ? action :
7861 i == Ylenses_eat ? action :
7862 i == Ymagnify_eat ? action :
7863 i == Ygrass_eat ? action :
7864 i == Ydirt_eat ? action :
7865 i == Xsand_stonein_1 ? action :
7866 i == Xsand_stonein_2 ? action :
7867 i == Xsand_stonein_3 ? action :
7868 i == Xsand_stonein_4 ? action :
7869 i == Xsand_stoneout_1 ? action :
7870 i == Xsand_stoneout_2 ? action :
7871 i == Xboom_android ? ACTION_EXPLODING :
7872 action_exploding ? ACTION_EXPLODING :
7873 action_active ? action :
7874 action_other ? action :
7876 int graphic = (el_act_dir2img(effective_element, effective_action,
7878 int crumbled = (el_act_dir2crm(effective_element, effective_action,
7880 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
7881 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
7882 boolean has_action_graphics = (graphic != base_graphic);
7883 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
7884 struct GraphicInfo *g = &graphic_info[graphic];
7886 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
7888 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
7891 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
7892 boolean special_animation = (action != ACTION_DEFAULT &&
7893 g->anim_frames == 3 &&
7894 g->anim_delay == 2 &&
7895 g->anim_mode & ANIM_LINEAR);
7896 int sync_frame = (i == Xdrip_stretch ? 7 :
7897 i == Xdrip_stretchB ? 7 :
7898 i == Ydrip_s2 ? j + 8 :
7899 i == Ydrip_s2B ? j + 8 :
7908 i == Xfake_acid_1 ? 0 :
7909 i == Xfake_acid_2 ? 10 :
7910 i == Xfake_acid_3 ? 20 :
7911 i == Xfake_acid_4 ? 30 :
7912 i == Xfake_acid_5 ? 40 :
7913 i == Xfake_acid_6 ? 50 :
7914 i == Xfake_acid_7 ? 60 :
7915 i == Xfake_acid_8 ? 70 :
7917 i == Xball_2B ? j + 8 :
7918 i == Yball_eat ? j + 1 :
7919 i == Ykey_1_eat ? j + 1 :
7920 i == Ykey_2_eat ? j + 1 :
7921 i == Ykey_3_eat ? j + 1 :
7922 i == Ykey_4_eat ? j + 1 :
7923 i == Ykey_5_eat ? j + 1 :
7924 i == Ykey_6_eat ? j + 1 :
7925 i == Ykey_7_eat ? j + 1 :
7926 i == Ykey_8_eat ? j + 1 :
7927 i == Ylenses_eat ? j + 1 :
7928 i == Ymagnify_eat ? j + 1 :
7929 i == Ygrass_eat ? j + 1 :
7930 i == Ydirt_eat ? j + 1 :
7931 i == Xamoeba_1 ? 0 :
7932 i == Xamoeba_2 ? 1 :
7933 i == Xamoeba_3 ? 2 :
7934 i == Xamoeba_4 ? 3 :
7935 i == Xamoeba_5 ? 0 :
7936 i == Xamoeba_6 ? 1 :
7937 i == Xamoeba_7 ? 2 :
7938 i == Xamoeba_8 ? 3 :
7939 i == Xexit_2 ? j + 8 :
7940 i == Xexit_3 ? j + 16 :
7941 i == Xdynamite_1 ? 0 :
7942 i == Xdynamite_2 ? 8 :
7943 i == Xdynamite_3 ? 16 :
7944 i == Xdynamite_4 ? 24 :
7945 i == Xsand_stonein_1 ? j + 1 :
7946 i == Xsand_stonein_2 ? j + 9 :
7947 i == Xsand_stonein_3 ? j + 17 :
7948 i == Xsand_stonein_4 ? j + 25 :
7949 i == Xsand_stoneout_1 && j == 0 ? 0 :
7950 i == Xsand_stoneout_1 && j == 1 ? 0 :
7951 i == Xsand_stoneout_1 && j == 2 ? 1 :
7952 i == Xsand_stoneout_1 && j == 3 ? 2 :
7953 i == Xsand_stoneout_1 && j == 4 ? 2 :
7954 i == Xsand_stoneout_1 && j == 5 ? 3 :
7955 i == Xsand_stoneout_1 && j == 6 ? 4 :
7956 i == Xsand_stoneout_1 && j == 7 ? 4 :
7957 i == Xsand_stoneout_2 && j == 0 ? 5 :
7958 i == Xsand_stoneout_2 && j == 1 ? 6 :
7959 i == Xsand_stoneout_2 && j == 2 ? 7 :
7960 i == Xsand_stoneout_2 && j == 3 ? 8 :
7961 i == Xsand_stoneout_2 && j == 4 ? 9 :
7962 i == Xsand_stoneout_2 && j == 5 ? 11 :
7963 i == Xsand_stoneout_2 && j == 6 ? 13 :
7964 i == Xsand_stoneout_2 && j == 7 ? 15 :
7965 i == Xboom_bug && j == 1 ? 2 :
7966 i == Xboom_bug && j == 2 ? 2 :
7967 i == Xboom_bug && j == 3 ? 4 :
7968 i == Xboom_bug && j == 4 ? 4 :
7969 i == Xboom_bug && j == 5 ? 2 :
7970 i == Xboom_bug && j == 6 ? 2 :
7971 i == Xboom_bug && j == 7 ? 0 :
7972 i == Xboom_bomb && j == 1 ? 2 :
7973 i == Xboom_bomb && j == 2 ? 2 :
7974 i == Xboom_bomb && j == 3 ? 4 :
7975 i == Xboom_bomb && j == 4 ? 4 :
7976 i == Xboom_bomb && j == 5 ? 2 :
7977 i == Xboom_bomb && j == 6 ? 2 :
7978 i == Xboom_bomb && j == 7 ? 0 :
7979 i == Xboom_android && j == 7 ? 6 :
7980 i == Xboom_1 && j == 1 ? 2 :
7981 i == Xboom_1 && j == 2 ? 2 :
7982 i == Xboom_1 && j == 3 ? 4 :
7983 i == Xboom_1 && j == 4 ? 4 :
7984 i == Xboom_1 && j == 5 ? 6 :
7985 i == Xboom_1 && j == 6 ? 6 :
7986 i == Xboom_1 && j == 7 ? 8 :
7987 i == Xboom_2 && j == 0 ? 8 :
7988 i == Xboom_2 && j == 1 ? 8 :
7989 i == Xboom_2 && j == 2 ? 10 :
7990 i == Xboom_2 && j == 3 ? 10 :
7991 i == Xboom_2 && j == 4 ? 10 :
7992 i == Xboom_2 && j == 5 ? 12 :
7993 i == Xboom_2 && j == 6 ? 12 :
7994 i == Xboom_2 && j == 7 ? 12 :
7995 special_animation && j == 4 ? 3 :
7996 effective_action != action ? 0 :
8000 Bitmap *debug_bitmap = g_em->bitmap;
8001 int debug_src_x = g_em->src_x;
8002 int debug_src_y = g_em->src_y;
8005 int frame = getAnimationFrame(g->anim_frames,
8008 g->anim_start_frame,
8011 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y,
8012 g->double_movement && is_backside);
8014 g_em->bitmap = src_bitmap;
8015 g_em->src_x = src_x;
8016 g_em->src_y = src_y;
8017 g_em->src_offset_x = 0;
8018 g_em->src_offset_y = 0;
8019 g_em->dst_offset_x = 0;
8020 g_em->dst_offset_y = 0;
8021 g_em->width = TILEX;
8022 g_em->height = TILEY;
8024 g_em->preserve_background = FALSE;
8027 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
8032 g_em->crumbled_bitmap = NULL;
8033 g_em->crumbled_src_x = 0;
8034 g_em->crumbled_src_y = 0;
8035 g_em->crumbled_border_size = 0;
8037 g_em->has_crumbled_graphics = FALSE;
8040 if (has_crumbled_graphics && crumbled == IMG_EMPTY_SPACE)
8041 printf("::: empty crumbled: %d [%s], %d, %d\n",
8042 effective_element, element_info[effective_element].token_name,
8043 effective_action, direction);
8046 /* if element can be crumbled, but certain action graphics are just empty
8047 space (like instantly snapping sand to empty space in 1 frame), do not
8048 treat these empty space graphics as crumbled graphics in EMC engine */
8049 if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
8051 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
8052 g_crumbled->anim_delay,
8053 g_crumbled->anim_mode,
8054 g_crumbled->anim_start_frame,
8057 getGraphicSource(crumbled, frame_crumbled, &src_bitmap, &src_x, &src_y);
8059 g_em->has_crumbled_graphics = TRUE;
8060 g_em->crumbled_bitmap = src_bitmap;
8061 g_em->crumbled_src_x = src_x;
8062 g_em->crumbled_src_y = src_y;
8063 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
8067 if (g_em == &graphic_info_em_object[207][0])
8068 printf("... %d, %d [%d, %d, %d, %d] [%d, %d, %d, %d, %d, %d => %d]\n",
8069 graphic_info_em_object[207][0].crumbled_src_x,
8070 graphic_info_em_object[207][0].crumbled_src_y,
8072 crumbled, frame, src_x, src_y,
8077 g->anim_start_frame,
8079 gfx.anim_random_frame,
8084 printf("::: EMC tile %d is crumbled\n", i);
8090 if (element == EL_ROCK &&
8091 effective_action == ACTION_FILLING)
8092 printf("::: has_action_graphics == %d\n", has_action_graphics);
8095 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
8096 effective_action == ACTION_MOVING ||
8097 effective_action == ACTION_PUSHING ||
8098 effective_action == ACTION_EATING)) ||
8099 (!has_action_graphics && (effective_action == ACTION_FILLING ||
8100 effective_action == ACTION_EMPTYING)))
8103 (effective_action == ACTION_FALLING ||
8104 effective_action == ACTION_FILLING ||
8105 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
8106 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
8107 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
8108 int num_steps = (i == Ydrip_s1 ? 16 :
8109 i == Ydrip_s1B ? 16 :
8110 i == Ydrip_s2 ? 16 :
8111 i == Ydrip_s2B ? 16 :
8112 i == Xsand_stonein_1 ? 32 :
8113 i == Xsand_stonein_2 ? 32 :
8114 i == Xsand_stonein_3 ? 32 :
8115 i == Xsand_stonein_4 ? 32 :
8116 i == Xsand_stoneout_1 ? 16 :
8117 i == Xsand_stoneout_2 ? 16 : 8);
8118 int cx = ABS(dx) * (TILEX / num_steps);
8119 int cy = ABS(dy) * (TILEY / num_steps);
8120 int step_frame = (i == Ydrip_s2 ? j + 8 :
8121 i == Ydrip_s2B ? j + 8 :
8122 i == Xsand_stonein_2 ? j + 8 :
8123 i == Xsand_stonein_3 ? j + 16 :
8124 i == Xsand_stonein_4 ? j + 24 :
8125 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
8126 int step = (is_backside ? step_frame : num_steps - step_frame);
8128 if (is_backside) /* tile where movement starts */
8130 if (dx < 0 || dy < 0)
8132 g_em->src_offset_x = cx * step;
8133 g_em->src_offset_y = cy * step;
8137 g_em->dst_offset_x = cx * step;
8138 g_em->dst_offset_y = cy * step;
8141 else /* tile where movement ends */
8143 if (dx < 0 || dy < 0)
8145 g_em->dst_offset_x = cx * step;
8146 g_em->dst_offset_y = cy * step;
8150 g_em->src_offset_x = cx * step;
8151 g_em->src_offset_y = cy * step;
8155 g_em->width = TILEX - cx * step;
8156 g_em->height = TILEY - cy * step;
8159 /* create unique graphic identifier to decide if tile must be redrawn */
8160 /* bit 31 - 16 (16 bit): EM style graphic
8161 bit 15 - 12 ( 4 bit): EM style frame
8162 bit 11 - 6 ( 6 bit): graphic width
8163 bit 5 - 0 ( 6 bit): graphic height */
8164 g_em->unique_identifier =
8165 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
8169 /* skip check for EMC elements not contained in original EMC artwork */
8170 if (element == EL_EMC_FAKE_ACID)
8173 if (g_em->bitmap != debug_bitmap ||
8174 g_em->src_x != debug_src_x ||
8175 g_em->src_y != debug_src_y ||
8176 g_em->src_offset_x != 0 ||
8177 g_em->src_offset_y != 0 ||
8178 g_em->dst_offset_x != 0 ||
8179 g_em->dst_offset_y != 0 ||
8180 g_em->width != TILEX ||
8181 g_em->height != TILEY)
8183 static int last_i = -1;
8191 printf("::: EMC GFX ERROR for element %d -> %d ('%s', '%s', %d)",
8192 i, element, element_info[element].token_name,
8193 element_action_info[effective_action].suffix, direction);
8195 if (element != effective_element)
8196 printf(" [%d ('%s')]",
8198 element_info[effective_element].token_name);
8202 if (g_em->bitmap != debug_bitmap)
8203 printf(" %d (%d): different bitmap! (0x%08x != 0x%08x)\n",
8204 j, is_backside, (int)(g_em->bitmap), (int)(debug_bitmap));
8206 if (g_em->src_x != debug_src_x ||
8207 g_em->src_y != debug_src_y)
8208 printf(" frame %d (%c): %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
8209 j, (is_backside ? 'B' : 'F'),
8210 g_em->src_x, g_em->src_y,
8211 g_em->src_x / 32, g_em->src_y / 32,
8212 debug_src_x, debug_src_y,
8213 debug_src_x / 32, debug_src_y / 32);
8215 if (g_em->src_offset_x != 0 ||
8216 g_em->src_offset_y != 0 ||
8217 g_em->dst_offset_x != 0 ||
8218 g_em->dst_offset_y != 0)
8219 printf(" %d (%d): offsets %d,%d and %d,%d should be all 0\n",
8221 g_em->src_offset_x, g_em->src_offset_y,
8222 g_em->dst_offset_x, g_em->dst_offset_y);
8224 if (g_em->width != TILEX ||
8225 g_em->height != TILEY)
8226 printf(" %d (%d): size %d,%d should be %d,%d\n",
8228 g_em->width, g_em->height, TILEX, TILEY);
8230 num_em_gfx_errors++;
8237 for (i = 0; i < TILE_MAX; i++)
8239 for (j = 0; j < 8; j++)
8241 int element = object_mapping[i].element_rnd;
8242 int action = object_mapping[i].action;
8243 int direction = object_mapping[i].direction;
8244 boolean is_backside = object_mapping[i].is_backside;
8245 int graphic_action = el_act_dir2img(element, action, direction);
8246 int graphic_default = el_act_dir2img(element, ACTION_DEFAULT, direction);
8248 if ((action == ACTION_SMASHED_BY_ROCK ||
8249 action == ACTION_SMASHED_BY_SPRING ||
8250 action == ACTION_EATING) &&
8251 graphic_action == graphic_default)
8253 int e = (action == ACTION_SMASHED_BY_ROCK ? Ystone_s :
8254 action == ACTION_SMASHED_BY_SPRING ? Yspring_s :
8255 direction == MV_LEFT ? (is_backside? Yspring_wB: Yspring_w) :
8256 direction == MV_RIGHT ? (is_backside? Yspring_eB: Yspring_e) :
8259 /* no separate animation for "smashed by rock" -- use rock instead */
8260 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
8261 struct GraphicInfo_EM *g_xx = &graphic_info_em_object[e][7 - j];
8263 g_em->bitmap = g_xx->bitmap;
8264 g_em->src_x = g_xx->src_x;
8265 g_em->src_y = g_xx->src_y;
8266 g_em->src_offset_x = g_xx->src_offset_x;
8267 g_em->src_offset_y = g_xx->src_offset_y;
8268 g_em->dst_offset_x = g_xx->dst_offset_x;
8269 g_em->dst_offset_y = g_xx->dst_offset_y;
8270 g_em->width = g_xx->width;
8271 g_em->height = g_xx->height;
8272 g_em->unique_identifier = g_xx->unique_identifier;
8275 g_em->preserve_background = TRUE;
8280 for (p = 0; p < MAX_PLAYERS; p++)
8282 for (i = 0; i < SPR_MAX; i++)
8284 int element = player_mapping[p][i].element_rnd;
8285 int action = player_mapping[p][i].action;
8286 int direction = player_mapping[p][i].direction;
8288 for (j = 0; j < 8; j++)
8290 int effective_element = element;
8291 int effective_action = action;
8292 int graphic = (direction == MV_NONE ?
8293 el_act2img(effective_element, effective_action) :
8294 el_act_dir2img(effective_element, effective_action,
8296 struct GraphicInfo *g = &graphic_info[graphic];
8297 struct GraphicInfo_EM *g_em = &graphic_info_em_player[p][i][7 - j];
8303 Bitmap *debug_bitmap = g_em->bitmap;
8304 int debug_src_x = g_em->src_x;
8305 int debug_src_y = g_em->src_y;
8308 int frame = getAnimationFrame(g->anim_frames,
8311 g->anim_start_frame,
8314 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
8316 g_em->bitmap = src_bitmap;
8317 g_em->src_x = src_x;
8318 g_em->src_y = src_y;
8319 g_em->src_offset_x = 0;
8320 g_em->src_offset_y = 0;
8321 g_em->dst_offset_x = 0;
8322 g_em->dst_offset_y = 0;
8323 g_em->width = TILEX;
8324 g_em->height = TILEY;
8328 /* skip check for EMC elements not contained in original EMC artwork */
8329 if (element == EL_PLAYER_3 ||
8330 element == EL_PLAYER_4)
8333 if (g_em->bitmap != debug_bitmap ||
8334 g_em->src_x != debug_src_x ||
8335 g_em->src_y != debug_src_y)
8337 static int last_i = -1;
8345 printf("::: EMC GFX ERROR for p/a %d/%d -> %d ('%s', '%s', %d)",
8346 p, i, element, element_info[element].token_name,
8347 element_action_info[effective_action].suffix, direction);
8349 if (element != effective_element)
8350 printf(" [%d ('%s')]",
8352 element_info[effective_element].token_name);
8356 if (g_em->bitmap != debug_bitmap)
8357 printf(" %d: different bitmap! (0x%08x != 0x%08x)\n",
8358 j, (int)(g_em->bitmap), (int)(debug_bitmap));
8360 if (g_em->src_x != debug_src_x ||
8361 g_em->src_y != debug_src_y)
8362 printf(" frame %d: %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
8364 g_em->src_x, g_em->src_y,
8365 g_em->src_x / 32, g_em->src_y / 32,
8366 debug_src_x, debug_src_y,
8367 debug_src_x / 32, debug_src_y / 32);
8369 num_em_gfx_errors++;
8379 printf("::: [%d errors found]\n", num_em_gfx_errors);
8385 void CheckSingleStepMode_EM(byte action[MAX_PLAYERS], int frame,
8386 boolean any_player_moving,
8387 boolean player_is_dropping)
8391 if (tape.single_step && tape.recording && !tape.pausing)
8393 boolean active_players = FALSE;
8395 for (i = 0; i < MAX_PLAYERS; i++)
8396 if (action[i] != JOY_NO_ACTION)
8397 active_players = TRUE;
8400 if (frame == 0 && !player_is_dropping)
8401 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
8405 void CheckSingleStepMode_SP(boolean murphy_is_waiting,
8406 boolean murphy_is_dropping)
8409 printf("::: waiting: %d, dropping: %d\n",
8410 murphy_is_waiting, murphy_is_dropping);
8413 if (tape.single_step && tape.recording && !tape.pausing)
8415 // if (murphy_is_waiting || murphy_is_dropping)
8416 if (murphy_is_waiting)
8419 printf("::: murphy is waiting -> pause mode\n");
8422 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
8427 void getGraphicSource_SP(struct GraphicInfo_SP *g_sp,
8428 int graphic, int sync_frame, int x, int y)
8430 int frame = getGraphicAnimationFrame(graphic, sync_frame);
8432 getGraphicSource(graphic, frame, &g_sp->bitmap, &g_sp->src_x, &g_sp->src_y);
8435 boolean isNextAnimationFrame_SP(int graphic, int sync_frame)
8437 return (IS_NEXT_FRAME(sync_frame, graphic));
8440 int getGraphicInfo_Delay(int graphic)
8442 return graphic_info[graphic].anim_delay;
8445 void PlayMenuSoundExt(int sound)
8447 if (sound == SND_UNDEFINED)
8450 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
8451 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
8454 if (IS_LOOP_SOUND(sound))
8455 PlaySoundLoop(sound);
8460 void PlayMenuSound()
8462 PlayMenuSoundExt(menu.sound[game_status]);
8465 void PlayMenuSoundStereo(int sound, int stereo_position)
8467 if (sound == SND_UNDEFINED)
8470 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
8471 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
8474 if (IS_LOOP_SOUND(sound))
8475 PlaySoundExt(sound, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_LOOP);
8477 PlaySoundStereo(sound, stereo_position);
8480 void PlayMenuSoundIfLoopExt(int sound)
8482 if (sound == SND_UNDEFINED)
8485 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
8486 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
8489 if (IS_LOOP_SOUND(sound))
8490 PlaySoundLoop(sound);
8493 void PlayMenuSoundIfLoop()
8495 PlayMenuSoundIfLoopExt(menu.sound[game_status]);
8498 void PlayMenuMusicExt(int music)
8500 if (music == MUS_UNDEFINED)
8503 if (!setup.sound_music)
8509 void PlayMenuMusic()
8511 PlayMenuMusicExt(menu.music[game_status]);
8514 void PlaySoundActivating()
8517 PlaySound(SND_MENU_ITEM_ACTIVATING);
8521 void PlaySoundSelecting()
8524 PlaySound(SND_MENU_ITEM_SELECTING);
8528 void ToggleFullscreenIfNeeded()
8530 boolean change_fullscreen = (setup.fullscreen !=
8531 video.fullscreen_enabled);
8532 boolean change_fullscreen_mode = (video.fullscreen_enabled &&
8533 !strEqual(setup.fullscreen_mode,
8534 video.fullscreen_mode_current));
8536 if (!video.fullscreen_available)
8539 if (change_fullscreen || change_fullscreen_mode)
8541 Bitmap *tmp_backbuffer = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
8543 /* save backbuffer content which gets lost when toggling fullscreen mode */
8544 BlitBitmap(backbuffer, tmp_backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
8546 if (change_fullscreen_mode)
8548 /* keep fullscreen, but change fullscreen mode (screen resolution) */
8549 video.fullscreen_enabled = FALSE; /* force new fullscreen mode */
8552 /* toggle fullscreen */
8553 ChangeVideoModeIfNeeded(setup.fullscreen);
8555 setup.fullscreen = video.fullscreen_enabled;
8557 /* restore backbuffer content from temporary backbuffer backup bitmap */
8558 BlitBitmap(tmp_backbuffer, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
8560 FreeBitmap(tmp_backbuffer);
8563 /* update visible window/screen */
8564 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
8566 redraw_mask = REDRAW_ALL;
8571 void ChangeViewportPropertiesIfNeeded()
8573 int *door_1_x = &DX;
8574 int *door_1_y = &DY;
8575 int *door_2_x = (game_status == GAME_MODE_EDITOR ? &EX : &VX);
8576 int *door_2_y = (game_status == GAME_MODE_EDITOR ? &EY : &VY);
8577 int gfx_game_mode = (game_status == GAME_MODE_PLAYING ||
8578 game_status == GAME_MODE_EDITOR ? game_status :
8580 struct RectWithBorder *vp_playfield = &viewport.playfield[gfx_game_mode];
8581 struct RectWithBorder *vp_door_1 = &viewport.door_1[gfx_game_mode];
8582 struct RectWithBorder *vp_door_2 = &viewport.door_2[gfx_game_mode];
8583 int border_size = vp_playfield->border_size;
8584 int new_sx = vp_playfield->x + border_size;
8585 int new_sy = vp_playfield->y + border_size;
8586 int new_scr_fieldx = (vp_playfield->width - 2 * border_size) / TILESIZE;
8587 int new_scr_fieldy = (vp_playfield->height - 2 * border_size) / TILESIZE;
8590 /* !!! TEST ONLY !!! */
8591 // InitGfxBuffers();
8595 if (viewport.window.width != WIN_XSIZE ||
8596 viewport.window.height != WIN_YSIZE)
8598 WIN_XSIZE = viewport.window.width;
8599 WIN_YSIZE = viewport.window.height;
8601 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
8605 SetDrawDeactivationMask(REDRAW_NONE);
8606 SetDrawBackgroundMask(REDRAW_FIELD);
8608 // RedrawBackground();
8612 if (new_scr_fieldx != SCR_FIELDX ||
8613 new_scr_fieldy != SCR_FIELDY ||
8616 vp_playfield->x != REAL_SX ||
8617 vp_playfield->y != REAL_SY ||
8618 vp_door_1->x != *door_1_x ||
8619 vp_door_1->y != *door_1_y ||
8620 vp_door_2->x != *door_2_x ||
8621 vp_door_2->y != *door_2_y)
8623 SCR_FIELDX = new_scr_fieldx;
8624 SCR_FIELDY = new_scr_fieldy;
8627 REAL_SX = vp_playfield->x;
8628 REAL_SY = vp_playfield->y;
8630 *door_1_x = vp_door_1->x;
8631 *door_1_y = vp_door_1->y;
8632 *door_2_x = vp_door_2->x;
8633 *door_2_y = vp_door_2->y;
8637 if (gfx_game_mode == GAME_MODE_MAIN)
8645 printf("::: %d, %d / %d, %d [%d]\n", VX, VY, EX, EY, game_status);