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)
120 drawto_field = fieldbuffer;
122 else /* DRAW_BACKBUFFER */
128 BX2 = SCR_FIELDX - 1;
129 BY2 = SCR_FIELDY - 1;
133 drawto_field = backbuffer;
137 void RedrawPlayfield(boolean force_redraw, int x, int y, int width, int height)
139 if (game_status == GAME_MODE_PLAYING &&
140 level.game_engine_type == GAME_ENGINE_TYPE_EM)
142 /* currently there is no partial redraw -- always redraw whole playfield */
143 RedrawPlayfield_EM(TRUE);
145 /* blit playfield from scroll buffer to normal back buffer for fading in */
146 BlitScreenToBitmap_EM(backbuffer);
148 else if (game_status == GAME_MODE_PLAYING &&
149 level.game_engine_type == GAME_ENGINE_TYPE_SP)
151 /* currently there is no partial redraw -- always redraw whole playfield */
152 RedrawPlayfield_SP(TRUE);
154 /* blit playfield from scroll buffer to normal back buffer for fading in */
155 BlitScreenToBitmap_SP(backbuffer);
157 else if (game_status == GAME_MODE_PLAYING &&
158 !game.envelope_active)
164 width = gfx.sxsize + 2 * TILEX;
165 height = gfx.sysize + 2 * TILEY;
171 int x1 = (x - SX) / TILEX, y1 = (y - SY) / TILEY;
172 int x2 = (x - SX + width) / TILEX, y2 = (y - SY + height) / TILEY;
174 for (xx = BX1; xx <= BX2; xx++)
175 for (yy = BY1; yy <= BY2; yy++)
176 if (xx >= x1 && xx <= x2 && yy >= y1 && yy <= y2)
177 DrawScreenField(xx, yy);
181 if (setup.soft_scrolling)
183 int fx = FX, fy = FY;
185 fx += (ScreenMovDir & (MV_LEFT|MV_RIGHT) ? ScreenGfxPos : 0);
186 fy += (ScreenMovDir & (MV_UP|MV_DOWN) ? ScreenGfxPos : 0);
188 BlitBitmap(fieldbuffer, backbuffer, fx,fy, SXSIZE,SYSIZE, SX,SY);
200 BlitBitmap(drawto, window, x, y, width, height, x, y);
203 void DrawMaskedBorder_Rect(int x, int y, int width, int height)
205 Bitmap *bitmap = graphic_info[IMG_GLOBAL_BORDER].bitmap;
207 SetClipOrigin(bitmap, bitmap->stored_clip_gc, 0, 0);
208 BlitBitmapMasked(bitmap, backbuffer, x, y, width, height, x, y);
211 void DrawMaskedBorder_FIELD()
213 if (global.border_status >= GAME_MODE_TITLE &&
214 global.border_status <= GAME_MODE_PLAYING &&
215 border.draw_masked[global.border_status])
216 DrawMaskedBorder_Rect(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
219 void DrawMaskedBorder_DOOR_1()
221 if (border.draw_masked[GFX_SPECIAL_ARG_DOOR] &&
222 (global.border_status != GAME_MODE_EDITOR ||
223 border.draw_masked[GFX_SPECIAL_ARG_EDITOR]))
224 DrawMaskedBorder_Rect(DX, DY, DXSIZE, DYSIZE);
227 void DrawMaskedBorder_DOOR_2()
229 if (border.draw_masked[GFX_SPECIAL_ARG_DOOR] &&
230 global.border_status != GAME_MODE_EDITOR)
231 DrawMaskedBorder_Rect(VX, VY, VXSIZE, VYSIZE);
234 void DrawMaskedBorder_DOOR_3()
236 /* currently not available */
239 void DrawMaskedBorder_ALL()
241 DrawMaskedBorder_FIELD();
242 DrawMaskedBorder_DOOR_1();
243 DrawMaskedBorder_DOOR_2();
244 DrawMaskedBorder_DOOR_3();
247 void DrawMaskedBorder(int redraw_mask)
249 /* never draw masked screen borders on borderless screens */
250 if (effectiveGameStatus() == GAME_MODE_LOADING ||
251 effectiveGameStatus() == GAME_MODE_TITLE)
254 /* never draw masked screen borders when displaying request outside door */
255 if (effectiveGameStatus() == GAME_MODE_PSEUDO_DOOR &&
256 global.use_envelope_request)
259 if (redraw_mask & REDRAW_ALL)
260 DrawMaskedBorder_ALL();
263 if (redraw_mask & REDRAW_FIELD)
264 DrawMaskedBorder_FIELD();
265 if (redraw_mask & REDRAW_DOOR_1)
266 DrawMaskedBorder_DOOR_1();
267 if (redraw_mask & REDRAW_DOOR_2)
268 DrawMaskedBorder_DOOR_2();
269 if (redraw_mask & REDRAW_DOOR_3)
270 DrawMaskedBorder_DOOR_3();
277 DrawBuffer *buffer = (drawto_field == window ? backbuffer : drawto_field);
280 printf("::: TILES TO REFRESH: %d\n", redraw_tiles);
281 for (x = 0; x < SCR_FIELDX; x++)
282 for (y = 0 ; y < SCR_FIELDY; y++)
283 if (redraw[redraw_x1 + x][redraw_y1 + y])
284 printf("::: - %d, %d [%s]\n",
285 LEVELX(x), LEVELY(y),
286 EL_NAME(Feld[LEVELX(x)][LEVELY(y)]));
289 if (redraw_mask & REDRAW_TILES && redraw_tiles > REDRAWTILES_THRESHOLD)
290 redraw_mask |= REDRAW_FIELD;
292 if (redraw_mask & REDRAW_FIELD)
293 redraw_mask &= ~REDRAW_TILES;
295 if (redraw_mask == REDRAW_NONE)
298 if (redraw_mask & REDRAW_TILES &&
299 game_status == GAME_MODE_PLAYING &&
300 border.draw_masked[GAME_MODE_PLAYING])
301 redraw_mask |= REDRAW_FIELD;
303 if (global.fps_slowdown && game_status == GAME_MODE_PLAYING)
305 static boolean last_frame_skipped = FALSE;
306 boolean skip_even_when_not_scrolling = TRUE;
307 boolean just_scrolling = (ScreenMovDir != 0);
308 boolean verbose = FALSE;
310 if (global.fps_slowdown_factor > 1 &&
311 (FrameCounter % global.fps_slowdown_factor) &&
312 (just_scrolling || skip_even_when_not_scrolling))
314 redraw_mask &= ~REDRAW_MAIN;
316 last_frame_skipped = TRUE;
319 printf("FRAME SKIPPED\n");
323 if (last_frame_skipped)
324 redraw_mask |= REDRAW_FIELD;
326 last_frame_skipped = FALSE;
329 printf("frame not skipped\n");
333 /* synchronize X11 graphics at this point; if we would synchronize the
334 display immediately after the buffer switching (after the XFlush),
335 this could mean that we have to wait for the graphics to complete,
336 although we could go on doing calculations for the next frame */
340 /* never draw masked border to backbuffer when using playfield buffer */
341 if (game_status != GAME_MODE_PLAYING ||
342 redraw_mask & REDRAW_FROM_BACKBUFFER ||
343 buffer == backbuffer)
344 DrawMaskedBorder(redraw_mask);
346 DrawMaskedBorder(redraw_mask & REDRAW_DOORS);
348 if (redraw_mask & REDRAW_ALL)
350 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
352 redraw_mask = REDRAW_NONE;
355 if (redraw_mask & REDRAW_FIELD)
358 printf("::: REDRAW_FIELD\n");
361 if (game_status != GAME_MODE_PLAYING ||
362 redraw_mask & REDRAW_FROM_BACKBUFFER)
364 BlitBitmap(backbuffer, window,
365 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE, REAL_SX, REAL_SY);
369 int fx = FX, fy = FY;
371 if (setup.soft_scrolling)
373 fx += (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
374 fy += (ScreenMovDir & (MV_UP | MV_DOWN) ? ScreenGfxPos : 0);
377 if (setup.soft_scrolling ||
378 ABS(ScreenMovPos) + ScrollStepSize == TILEX ||
379 ABS(ScreenMovPos) == ScrollStepSize ||
380 redraw_tiles > REDRAWTILES_THRESHOLD)
382 if (border.draw_masked[GAME_MODE_PLAYING])
384 if (buffer != backbuffer)
386 /* copy playfield buffer to backbuffer to add masked border */
387 BlitBitmap(buffer, backbuffer, fx, fy, SXSIZE, SYSIZE, SX, SY);
388 DrawMaskedBorder(REDRAW_FIELD);
391 BlitBitmap(backbuffer, window,
392 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
397 BlitBitmap(buffer, window, fx, fy, SXSIZE, SYSIZE, SX, SY);
402 printf("redrawing all (ScreenGfxPos == %d) because %s\n",
404 (setup.soft_scrolling ?
405 "setup.soft_scrolling" :
406 ABS(ScreenGfxPos) + ScrollStepSize == TILEX ?
407 "ABS(ScreenGfxPos) + ScrollStepSize == TILEX" :
408 ABS(ScreenGfxPos) == ScrollStepSize ?
409 "ABS(ScreenGfxPos) == ScrollStepSize" :
410 "redraw_tiles > REDRAWTILES_THRESHOLD"));
416 redraw_mask &= ~REDRAW_MAIN;
419 if (redraw_mask & REDRAW_DOORS)
421 if (redraw_mask & REDRAW_DOOR_1)
422 BlitBitmap(backbuffer, window, DX, DY, DXSIZE, DYSIZE, DX, DY);
424 if (redraw_mask & REDRAW_DOOR_2)
425 BlitBitmap(backbuffer, window, VX, VY, VXSIZE, VYSIZE, VX, VY);
427 if (redraw_mask & REDRAW_DOOR_3)
428 BlitBitmap(backbuffer, window, EX, EY, EXSIZE, EYSIZE, EX, EY);
430 redraw_mask &= ~REDRAW_DOORS;
433 if (redraw_mask & REDRAW_MICROLEVEL)
435 BlitBitmap(backbuffer, window, SX, SY + 10 * TILEY, SXSIZE, 7 * TILEY,
436 SX, SY + 10 * TILEY);
438 redraw_mask &= ~REDRAW_MICROLEVEL;
441 if (redraw_mask & REDRAW_TILES)
444 printf("::: REDRAW_TILES\n");
447 for (x = 0; x < SCR_FIELDX; x++)
448 for (y = 0 ; y < SCR_FIELDY; y++)
449 if (redraw[redraw_x1 + x][redraw_y1 + y])
450 BlitBitmap(buffer, window,
451 FX + x * TILEX, FY + y * TILEY, TILEX, TILEY,
452 SX + x * TILEX, SY + y * TILEY);
455 if (redraw_mask & REDRAW_FPS) /* display frames per second */
460 sprintf(info1, " (only every %d. frame)", global.fps_slowdown_factor);
461 if (!global.fps_slowdown)
464 sprintf(text, "%04.1f fps%s", global.frames_per_second, info1);
466 DrawTextExt(window, SX + SXSIZE + SX, 0, text, FONT_TEXT_2, BLIT_OPAQUE);
468 DrawTextExt(window, SX, SY, text, FONT_TEXT_2, BLIT_OPAQUE);
474 for (x = 0; x < MAX_BUF_XSIZE; x++)
475 for (y = 0; y < MAX_BUF_YSIZE; y++)
478 redraw_mask = REDRAW_NONE;
481 static void FadeCrossSaveBackbuffer()
483 BlitBitmap(backbuffer, bitmap_db_cross, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
486 static void FadeExt(int fade_mask, int fade_mode, int fade_type)
488 static int fade_type_skip = FADE_TYPE_NONE;
489 void (*draw_border_function)(void) = NULL;
490 Bitmap *bitmap = (fade_mode & FADE_TYPE_TRANSFORM ? bitmap_db_cross : NULL);
491 int x, y, width, height;
492 int fade_delay, post_delay;
494 if (fade_type == FADE_TYPE_FADE_OUT)
496 if (fade_type_skip != FADE_TYPE_NONE)
499 printf("::: skipping %d ... [%d] (X)\n", fade_mode, fade_type_skip);
502 /* skip all fade operations until specified fade operation */
503 if (fade_type & fade_type_skip)
504 fade_type_skip = FADE_TYPE_NONE;
509 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
511 FadeCrossSaveBackbuffer();
517 redraw_mask |= fade_mask;
519 if (fade_type == FADE_TYPE_SKIP)
522 printf("::: will skip %d ... [%d]\n", fade_mode, fade_type_skip);
525 fade_type_skip = fade_mode;
531 printf("::: !!! FADING %d ... [%d] [%d]\n", fade_mode, fade_type,
536 fade_delay = fading.fade_delay;
537 post_delay = (fade_mode == FADE_MODE_FADE_OUT ? fading.post_delay : 0);
540 if (fade_type_skip != FADE_TYPE_NONE)
543 printf("::: skipping %d ... [%d]\n", fade_mode, fade_type_skip);
546 /* skip all fade operations until specified fade operation */
547 if (fade_type & fade_type_skip)
548 fade_type_skip = FADE_TYPE_NONE;
558 if (global.autoplay_leveldir)
560 // fading.fade_mode = FADE_MODE_NONE;
567 if (fading.fade_mode == FADE_MODE_NONE)
575 /* !!! what about fade_mask == REDRAW_FIELD | REDRAW_ALL ??? !!! */
578 printf("::: NOW FADING %d ... [%d]\n", fade_mode, fade_type);
582 if (fade_mask == REDRAW_NONE)
583 fade_mask = REDRAW_FIELD;
586 // if (fade_mask & REDRAW_FIELD)
587 if (fade_mask == REDRAW_FIELD)
592 height = FULL_SYSIZE;
595 fade_delay = fading.fade_delay;
596 post_delay = (fade_mode == FADE_MODE_FADE_OUT ? fading.post_delay : 0);
599 if (border.draw_masked_when_fading)
600 draw_border_function = DrawMaskedBorder_FIELD; /* update when fading */
602 DrawMaskedBorder_FIELD(); /* draw once */
604 else /* REDRAW_ALL */
612 fade_delay = fading.fade_delay;
613 post_delay = (fade_mode == FADE_MODE_FADE_OUT ? fading.post_delay : 0);
618 if (!setup.fade_screens ||
620 fading.fade_mode == FADE_MODE_NONE)
622 if (!setup.fade_screens || fade_delay == 0)
625 if (fade_mode == FADE_MODE_FADE_OUT)
629 if (fade_mode == FADE_MODE_FADE_OUT &&
630 fading.fade_mode != FADE_MODE_NONE)
631 ClearRectangle(backbuffer, x, y, width, height);
635 BlitBitmap(backbuffer, window, x, y, width, height, x, y);
636 redraw_mask = REDRAW_NONE;
644 FadeRectangle(bitmap, x, y, width, height, fade_mode, fade_delay, post_delay,
645 draw_border_function);
647 redraw_mask &= ~fade_mask;
650 void FadeIn(int fade_mask)
652 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
653 FadeExt(fade_mask, fading.fade_mode, FADE_TYPE_FADE_IN);
655 FadeExt(fade_mask, FADE_MODE_FADE_IN, FADE_TYPE_FADE_IN);
658 void FadeOut(int fade_mask)
660 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
661 FadeExt(fade_mask, fading.fade_mode, FADE_TYPE_FADE_OUT);
663 FadeExt(fade_mask, FADE_MODE_FADE_OUT, FADE_TYPE_FADE_OUT);
665 global.border_status = game_status;
668 static void FadeSetLeaveNext(struct TitleFadingInfo fading_leave, boolean set)
670 static struct TitleFadingInfo fading_leave_stored;
673 fading_leave_stored = fading_leave;
675 fading = fading_leave_stored;
678 void FadeSetEnterMenu()
680 fading = menu.enter_menu;
683 printf("::: storing enter_menu\n");
686 FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
689 void FadeSetLeaveMenu()
691 fading = menu.leave_menu;
694 printf("::: storing leave_menu\n");
697 FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
700 void FadeSetEnterScreen()
702 fading = menu.enter_screen[game_status];
705 printf("::: storing leave_screen[%d]\n", game_status);
708 FadeSetLeaveNext(menu.leave_screen[game_status], TRUE); /* store */
711 void FadeSetNextScreen()
713 fading = menu.next_screen;
716 printf("::: storing next_screen\n");
719 // (do not overwrite fade mode set by FadeSetEnterScreen)
720 // FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
723 void FadeSetLeaveScreen()
726 printf("::: recalling last stored value\n");
729 FadeSetLeaveNext(menu.leave_screen[game_status], FALSE); /* recall */
732 void FadeSetFromType(int type)
734 if (type & TYPE_ENTER_SCREEN)
735 FadeSetEnterScreen();
736 else if (type & TYPE_ENTER)
738 else if (type & TYPE_LEAVE)
742 void FadeSetDisabled()
744 static struct TitleFadingInfo fading_none = { FADE_MODE_NONE, -1, -1, -1 };
746 fading = fading_none;
749 void FadeSkipNextFadeIn()
751 FadeExt(0, FADE_MODE_SKIP_FADE_IN, FADE_TYPE_SKIP);
754 void FadeSkipNextFadeOut()
756 FadeExt(0, FADE_MODE_SKIP_FADE_OUT, FADE_TYPE_SKIP);
759 void SetWindowBackgroundImageIfDefined(int graphic)
761 if (graphic_info[graphic].bitmap)
762 SetWindowBackgroundBitmap(graphic_info[graphic].bitmap);
765 void SetMainBackgroundImageIfDefined(int graphic)
767 if (graphic_info[graphic].bitmap)
768 SetMainBackgroundBitmap(graphic_info[graphic].bitmap);
771 void SetDoorBackgroundImageIfDefined(int graphic)
773 if (graphic_info[graphic].bitmap)
774 SetDoorBackgroundBitmap(graphic_info[graphic].bitmap);
777 void SetWindowBackgroundImage(int graphic)
779 SetWindowBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
780 graphic_info[graphic].bitmap ?
781 graphic_info[graphic].bitmap :
782 graphic_info[IMG_BACKGROUND].bitmap);
785 void SetMainBackgroundImage(int graphic)
787 SetMainBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
788 graphic_info[graphic].bitmap ?
789 graphic_info[graphic].bitmap :
790 graphic_info[IMG_BACKGROUND].bitmap);
793 void SetDoorBackgroundImage(int graphic)
795 SetDoorBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
796 graphic_info[graphic].bitmap ?
797 graphic_info[graphic].bitmap :
798 graphic_info[IMG_BACKGROUND].bitmap);
801 void SetPanelBackground()
804 struct GraphicInfo *gfx = &graphic_info[IMG_BACKGROUND_PANEL];
807 BlitBitmapTiled(gfx->bitmap, bitmap_db_panel, gfx->src_x, gfx->src_y,
808 gfx->width, gfx->height, 0, 0, DXSIZE, DYSIZE);
810 /* (ClearRectangle() only needed if panel bitmap is smaller than panel) */
811 ClearRectangle(bitmap_db_panel, DX, DY, DXSIZE, DYSIZE);
812 BlitBitmap(gfx->bitmap, bitmap_db_panel, gfx->src_x, gfx->src_y,
813 MIN(gfx->width, DXSIZE), MIN(gfx->height, DYSIZE), 0, 0);
816 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, bitmap_db_panel,
817 DOOR_GFX_PAGEX5, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE, 0, 0);
820 SetDoorBackgroundBitmap(bitmap_db_panel);
823 void DrawBackground(int x, int y, int width, int height)
825 /* !!! "drawto" might still point to playfield buffer here (see below) !!! */
826 /* (when entering hall of fame after playing) */
828 ClearRectangleOnBackground(drawto, x, y, width, height);
830 ClearRectangleOnBackground(backbuffer, x, y, width, height);
833 redraw_mask |= REDRAW_FIELD;
836 void DrawBackgroundForFont(int x, int y, int width, int height, int font_nr)
838 struct FontBitmapInfo *font = getFontBitmapInfo(font_nr);
840 if (font->bitmap == NULL)
843 DrawBackground(x, y, width, height);
846 void DrawBackgroundForGraphic(int x, int y, int width, int height, int graphic)
848 struct GraphicInfo *g = &graphic_info[graphic];
850 if (g->bitmap == NULL)
853 DrawBackground(x, y, width, height);
858 /* !!! "drawto" might still point to playfield buffer here (see above) !!! */
859 /* (when entering hall of fame after playing) */
860 DrawBackground(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
862 /* !!! maybe this should be done before clearing the background !!! */
863 if (setup.soft_scrolling && game_status == GAME_MODE_PLAYING)
865 ClearRectangle(fieldbuffer, 0, 0, FXSIZE, FYSIZE);
866 SetDrawtoField(DRAW_BUFFERED);
869 SetDrawtoField(DRAW_BACKBUFFER);
872 void MarkTileDirty(int x, int y)
874 int xx = redraw_x1 + x;
875 int yy = redraw_y1 + y;
880 redraw[xx][yy] = TRUE;
881 redraw_mask |= REDRAW_TILES;
884 void SetBorderElement()
888 BorderElement = EL_EMPTY;
890 for (y = 0; y < lev_fieldy && BorderElement == EL_EMPTY; y++)
892 for (x = 0; x < lev_fieldx; x++)
894 if (!IS_INDESTRUCTIBLE(Feld[x][y]))
895 BorderElement = EL_STEELWALL;
897 if (y != 0 && y != lev_fieldy - 1 && x != lev_fieldx - 1)
903 void FloodFillLevel(int from_x, int from_y, int fill_element,
904 short field[MAX_LEV_FIELDX][MAX_LEV_FIELDY],
905 int max_fieldx, int max_fieldy)
909 static int check[4][2] = { { -1, 0 }, { 0, -1 }, { 1, 0 }, { 0, 1 } };
910 static int safety = 0;
912 /* check if starting field still has the desired content */
913 if (field[from_x][from_y] == fill_element)
918 if (safety > max_fieldx * max_fieldy)
919 Error(ERR_EXIT, "Something went wrong in 'FloodFill()'. Please debug.");
921 old_element = field[from_x][from_y];
922 field[from_x][from_y] = fill_element;
924 for (i = 0; i < 4; i++)
926 x = from_x + check[i][0];
927 y = from_y + check[i][1];
929 if (IN_FIELD(x, y, max_fieldx, max_fieldy) && field[x][y] == old_element)
930 FloodFillLevel(x, y, fill_element, field, max_fieldx, max_fieldy);
936 void SetRandomAnimationValue(int x, int y)
938 gfx.anim_random_frame = GfxRandom[x][y];
941 inline int getGraphicAnimationFrame(int graphic, int sync_frame)
943 /* animation synchronized with global frame counter, not move position */
944 if (graphic_info[graphic].anim_global_sync || sync_frame < 0)
945 sync_frame = FrameCounter;
947 return getAnimationFrame(graphic_info[graphic].anim_frames,
948 graphic_info[graphic].anim_delay,
949 graphic_info[graphic].anim_mode,
950 graphic_info[graphic].anim_start_frame,
954 void getSizedGraphicSource(int graphic, int frame, int tilesize_raw,
955 Bitmap **bitmap, int *x, int *y)
959 int width_mult, width_div;
960 int height_mult, height_div;
964 { 15, 16, 2, 3 }, /* 1 x 1 */
965 { 7, 8, 2, 3 }, /* 2 x 2 */
966 { 3, 4, 2, 3 }, /* 4 x 4 */
967 { 1, 2, 2, 3 }, /* 8 x 8 */
968 { 0, 1, 2, 3 }, /* 16 x 16 */
969 { 0, 1, 0, 1 }, /* 32 x 32 */
971 struct GraphicInfo *g = &graphic_info[graphic];
972 Bitmap *src_bitmap = g->bitmap;
973 int tilesize = MIN(MAX(1, tilesize_raw), TILESIZE);
974 int offset_calc_pos = log_2(tilesize);
975 int width_mult = offset_calc[offset_calc_pos].width_mult;
976 int width_div = offset_calc[offset_calc_pos].width_div;
977 int height_mult = offset_calc[offset_calc_pos].height_mult;
978 int height_div = offset_calc[offset_calc_pos].height_div;
979 int startx = src_bitmap->width * width_mult / width_div;
980 int starty = src_bitmap->height * height_mult / height_div;
981 int src_x = g->src_x * tilesize / TILESIZE;
982 int src_y = g->src_y * tilesize / TILESIZE;
983 int width = g->width * tilesize / TILESIZE;
984 int height = g->height * tilesize / TILESIZE;
985 int offset_x = g->offset_x * tilesize / TILESIZE;
986 int offset_y = g->offset_y * tilesize / TILESIZE;
988 if (g->offset_y == 0) /* frames are ordered horizontally */
990 int max_width = g->anim_frames_per_line * width;
991 int pos = (src_y / height) * max_width + src_x + frame * offset_x;
993 src_x = pos % max_width;
994 src_y = src_y % height + pos / max_width * height;
996 else if (g->offset_x == 0) /* frames are ordered vertically */
998 int max_height = g->anim_frames_per_line * height;
999 int pos = (src_x / width) * max_height + src_y + frame * offset_y;
1001 src_x = src_x % width + pos / max_height * width;
1002 src_y = pos % max_height;
1004 else /* frames are ordered diagonally */
1006 src_x = src_x + frame * offset_x;
1007 src_y = src_y + frame * offset_y;
1010 *bitmap = src_bitmap;
1011 *x = startx + src_x;
1012 *y = starty + src_y;
1015 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
1018 getSizedGraphicSource(graphic, 0, MINI_TILESIZE, bitmap, x, y);
1020 struct GraphicInfo *g = &graphic_info[graphic];
1021 int mini_startx = 0;
1022 int mini_starty = g->bitmap->height * 2 / 3;
1024 *bitmap = g->bitmap;
1025 *x = mini_startx + g->src_x / 2;
1026 *y = mini_starty + g->src_y / 2;
1030 inline void getGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
1031 int *x, int *y, boolean get_backside)
1033 struct GraphicInfo *g = &graphic_info[graphic];
1034 int src_x = g->src_x + (get_backside ? g->offset2_x : 0);
1035 int src_y = g->src_y + (get_backside ? g->offset2_y : 0);
1037 *bitmap = g->bitmap;
1039 if (g->offset_y == 0) /* frames are ordered horizontally */
1041 int max_width = g->anim_frames_per_line * g->width;
1042 int pos = (src_y / g->height) * max_width + src_x + frame * g->offset_x;
1044 *x = pos % max_width;
1045 *y = src_y % g->height + pos / max_width * g->height;
1047 else if (g->offset_x == 0) /* frames are ordered vertically */
1049 int max_height = g->anim_frames_per_line * g->height;
1050 int pos = (src_x / g->width) * max_height + src_y + frame * g->offset_y;
1052 *x = src_x % g->width + pos / max_height * g->width;
1053 *y = pos % max_height;
1055 else /* frames are ordered diagonally */
1057 *x = src_x + frame * g->offset_x;
1058 *y = src_y + frame * g->offset_y;
1062 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
1064 getGraphicSourceExt(graphic, frame, bitmap, x, y, FALSE);
1067 void DrawGraphic(int x, int y, int graphic, int frame)
1070 if (!IN_SCR_FIELD(x, y))
1072 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
1073 printf("DrawGraphic(): This should never happen!\n");
1078 DrawGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic, frame);
1079 MarkTileDirty(x, y);
1082 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
1088 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1089 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
1092 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
1095 if (!IN_SCR_FIELD(x, y))
1097 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
1098 printf("DrawGraphicThruMask(): This should never happen!\n");
1103 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y *TILEY, graphic,
1105 MarkTileDirty(x, y);
1108 void DrawGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y, int graphic,
1114 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1116 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1117 dst_x - src_x, dst_y - src_y);
1118 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dst_x, dst_y);
1121 void DrawSizedGraphic(int x, int y, int graphic, int frame, int tilesize)
1123 DrawSizedGraphicExt(drawto, SX + x * tilesize, SY + y * tilesize, graphic,
1125 MarkTileDirty(x / tilesize, y / tilesize);
1128 void DrawSizedGraphicExt(DrawBuffer *d, int x, int y, int graphic, int frame,
1134 getSizedGraphicSource(graphic, frame, tilesize, &src_bitmap, &src_x, &src_y);
1135 BlitBitmap(src_bitmap, d, src_x, src_y, tilesize, tilesize, x, y);
1138 void DrawMiniGraphic(int x, int y, int graphic)
1140 DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
1141 MarkTileDirty(x / 2, y / 2);
1144 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
1149 getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1150 BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
1153 inline static void DrawGraphicShiftedNormal(int x, int y, int dx, int dy,
1154 int graphic, int frame,
1155 int cut_mode, int mask_mode)
1160 int width = TILEX, height = TILEY;
1163 if (dx || dy) /* shifted graphic */
1165 if (x < BX1) /* object enters playfield from the left */
1172 else if (x > BX2) /* object enters playfield from the right */
1178 else if (x==BX1 && dx < 0) /* object leaves playfield to the left */
1184 else if (x==BX2 && dx > 0) /* object leaves playfield to the right */
1186 else if (dx) /* general horizontal movement */
1187 MarkTileDirty(x + SIGN(dx), y);
1189 if (y < BY1) /* object enters playfield from the top */
1191 if (cut_mode==CUT_BELOW) /* object completely above top border */
1199 else if (y > BY2) /* object enters playfield from the bottom */
1205 else if (y==BY1 && dy < 0) /* object leaves playfield to the top */
1211 else if (dy > 0 && cut_mode == CUT_ABOVE)
1213 if (y == BY2) /* object completely above bottom border */
1219 MarkTileDirty(x, y + 1);
1220 } /* object leaves playfield to the bottom */
1221 else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
1223 else if (dy) /* general vertical movement */
1224 MarkTileDirty(x, y + SIGN(dy));
1228 if (!IN_SCR_FIELD(x, y))
1230 printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
1231 printf("DrawGraphicShifted(): This should never happen!\n");
1236 if (width > 0 && height > 0)
1238 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1243 dst_x = FX + x * TILEX + dx;
1244 dst_y = FY + y * TILEY + dy;
1246 if (mask_mode == USE_MASKING)
1248 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1249 dst_x - src_x, dst_y - src_y);
1250 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1254 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1257 MarkTileDirty(x, y);
1261 inline static void DrawGraphicShiftedDouble(int x, int y, int dx, int dy,
1262 int graphic, int frame,
1263 int cut_mode, int mask_mode)
1268 int width = TILEX, height = TILEY;
1271 int x2 = x + SIGN(dx);
1272 int y2 = y + SIGN(dy);
1274 /* !!! DOES NOT WORK FOR SLOW MOVEMENT !!! */
1275 int sync_frame = GfxFrame[LEVELX(x)][LEVELY(y)];
1277 /* movement with two-tile animations must be sync'ed with movement position,
1278 not with current GfxFrame (which can be higher when using slow movement) */
1279 int anim_pos = (dx ? ABS(dx) : ABS(dy));
1280 int anim_frames = graphic_info[graphic].anim_frames;
1282 /* (we also need anim_delay here for movement animations with less frames) */
1283 int anim_delay = graphic_info[graphic].anim_delay;
1284 int sync_frame = anim_pos * anim_frames * anim_delay / TILESIZE;
1286 int sync_frame = anim_pos * anim_frames / TILESIZE;
1289 boolean draw_start_tile = (cut_mode != CUT_ABOVE); /* only for falling! */
1290 boolean draw_end_tile = (cut_mode != CUT_BELOW); /* only for falling! */
1292 /* re-calculate animation frame for two-tile movement animation */
1293 frame = getGraphicAnimationFrame(graphic, sync_frame);
1297 printf("::: %d, %d, %d => %d [%d]\n",
1298 anim_pos, anim_frames, anim_delay, sync_frame, graphic);
1300 printf("::: %d, %d => %d\n",
1301 anim_pos, anim_frames, sync_frame);
1306 printf("::: %d [%d, %d] [%d] [%d]\n", frame, sync_frame, dy,
1307 GfxFrame[LEVELX(x)][LEVELY(y)], mask_mode);
1310 /* check if movement start graphic inside screen area and should be drawn */
1311 if (draw_start_tile && IN_SCR_FIELD(x1, y1))
1313 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, TRUE);
1315 dst_x = FX + x1 * TILEX;
1316 dst_y = FY + y1 * TILEY;
1318 if (mask_mode == USE_MASKING)
1320 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1321 dst_x - src_x, dst_y - src_y);
1322 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1326 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1329 MarkTileDirty(x1, y1);
1332 /* check if movement end graphic inside screen area and should be drawn */
1333 if (draw_end_tile && IN_SCR_FIELD(x2, y2))
1335 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
1337 dst_x = FX + x2 * TILEX;
1338 dst_y = FY + y2 * TILEY;
1340 if (mask_mode == USE_MASKING)
1342 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1343 dst_x - src_x, dst_y - src_y);
1344 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1348 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1351 MarkTileDirty(x2, y2);
1355 static void DrawGraphicShifted(int x, int y, int dx, int dy,
1356 int graphic, int frame,
1357 int cut_mode, int mask_mode)
1361 DrawGraphic(x, y, graphic, frame);
1366 if (graphic_info[graphic].double_movement) /* EM style movement images */
1367 DrawGraphicShiftedDouble(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1369 DrawGraphicShiftedNormal(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1372 void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
1373 int frame, int cut_mode)
1375 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, USE_MASKING);
1378 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
1379 int cut_mode, int mask_mode)
1381 int lx = LEVELX(x), ly = LEVELY(y);
1385 if (IN_LEV_FIELD(lx, ly))
1387 SetRandomAnimationValue(lx, ly);
1389 graphic = el_act_dir2img(element, GfxAction[lx][ly], GfxDir[lx][ly]);
1390 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1392 /* do not use double (EM style) movement graphic when not moving */
1393 if (graphic_info[graphic].double_movement && !dx && !dy)
1395 graphic = el_act_dir2img(element, ACTION_DEFAULT, GfxDir[lx][ly]);
1396 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1399 else /* border element */
1401 graphic = el2img(element);
1402 frame = getGraphicAnimationFrame(graphic, -1);
1405 if (element == EL_EXPANDABLE_WALL)
1407 boolean left_stopped = FALSE, right_stopped = FALSE;
1409 if (!IN_LEV_FIELD(lx - 1, ly) || IS_WALL(Feld[lx - 1][ly]))
1410 left_stopped = TRUE;
1411 if (!IN_LEV_FIELD(lx + 1, ly) || IS_WALL(Feld[lx + 1][ly]))
1412 right_stopped = TRUE;
1414 if (left_stopped && right_stopped)
1416 else if (left_stopped)
1418 graphic = IMG_EXPANDABLE_WALL_GROWING_RIGHT;
1419 frame = graphic_info[graphic].anim_frames - 1;
1421 else if (right_stopped)
1423 graphic = IMG_EXPANDABLE_WALL_GROWING_LEFT;
1424 frame = graphic_info[graphic].anim_frames - 1;
1429 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
1430 else if (mask_mode == USE_MASKING)
1431 DrawGraphicThruMask(x, y, graphic, frame);
1433 DrawGraphic(x, y, graphic, frame);
1436 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
1437 int cut_mode, int mask_mode)
1439 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1440 DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
1441 cut_mode, mask_mode);
1444 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
1447 DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1450 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
1453 DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1456 void DrawLevelElementThruMask(int x, int y, int element)
1458 DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1461 void DrawLevelFieldThruMask(int x, int y)
1463 DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
1466 /* !!! implementation of quicksand is totally broken !!! */
1467 #define IS_CRUMBLED_TILE(x, y, e) \
1468 (GFX_CRUMBLED(e) && (!IN_LEV_FIELD(x, y) || \
1469 !IS_MOVING(x, y) || \
1470 (e) == EL_QUICKSAND_EMPTYING || \
1471 (e) == EL_QUICKSAND_FAST_EMPTYING))
1473 static void DrawLevelFieldCrumbledInnerCorners(int x, int y, int dx, int dy,
1478 int width, height, cx, cy;
1479 int sx = SCREENX(x), sy = SCREENY(y);
1480 int crumbled_border_size = graphic_info[graphic].border_size;
1483 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1485 for (i = 1; i < 4; i++)
1487 int dxx = (i & 1 ? dx : 0);
1488 int dyy = (i & 2 ? dy : 0);
1491 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1494 /* check if neighbour field is of same crumble type */
1495 boolean same = (IS_CRUMBLED_TILE(xx, yy, element) &&
1496 graphic_info[graphic].class ==
1497 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class);
1499 /* return if check prevents inner corner */
1500 if (same == (dxx == dx && dyy == dy))
1504 /* if we reach this point, we have an inner corner */
1506 getGraphicSource(graphic, 1, &src_bitmap, &src_x, &src_y);
1508 width = crumbled_border_size;
1509 height = crumbled_border_size;
1510 cx = (dx > 0 ? TILEX - crumbled_border_size : 0);
1511 cy = (dy > 0 ? TILEY - crumbled_border_size : 0);
1513 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1514 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
1517 static void DrawLevelFieldCrumbledBorders(int x, int y, int graphic, int frame,
1522 int width, height, bx, by, cx, cy;
1523 int sx = SCREENX(x), sy = SCREENY(y);
1524 int crumbled_border_size = graphic_info[graphic].border_size;
1527 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1529 /* draw simple, sloppy, non-corner-accurate crumbled border */
1532 width = (dir == 1 || dir == 2 ? crumbled_border_size : TILEX);
1533 height = (dir == 0 || dir == 3 ? crumbled_border_size : TILEY);
1534 cx = (dir == 2 ? TILEX - crumbled_border_size : 0);
1535 cy = (dir == 3 ? TILEY - crumbled_border_size : 0);
1537 if (dir == 1 || dir == 2) /* left or right crumbled border */
1539 width = crumbled_border_size;
1541 cx = (dir == 2 ? TILEX - crumbled_border_size : 0);
1544 else /* top or bottom crumbled border */
1547 height = crumbled_border_size;
1549 cy = (dir == 3 ? TILEY - crumbled_border_size : 0);
1553 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1554 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
1556 /* (remaining middle border part must be at least as big as corner part) */
1557 if (!(graphic_info[graphic].style & STYLE_ACCURATE_BORDERS) ||
1558 crumbled_border_size >= TILESIZE / 3)
1561 /* correct corners of crumbled border, if needed */
1564 for (i = -1; i <= 1; i+=2)
1566 int xx = x + (dir == 0 || dir == 3 ? i : 0);
1567 int yy = y + (dir == 1 || dir == 2 ? i : 0);
1568 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1571 /* check if neighbour field is of same crumble type */
1572 if (IS_CRUMBLED_TILE(xx, yy, element) &&
1573 graphic_info[graphic].class ==
1574 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
1576 /* no crumbled corner, but continued crumbled border */
1578 int c1 = (dir == 2 || dir == 3 ? TILESIZE - crumbled_border_size : 0);
1579 int c2 = (i == 1 ? TILESIZE - crumbled_border_size : 0);
1580 int b1 = (i == 1 ? crumbled_border_size :
1581 TILESIZE - 2 * crumbled_border_size);
1583 width = crumbled_border_size;
1584 height = crumbled_border_size;
1586 if (dir == 1 || dir == 2)
1601 BlitBitmap(src_bitmap, drawto_field, src_x + bx, src_y + by,
1602 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
1606 if (dir == 1 || dir == 2) /* left or right crumbled border */
1608 for (i = -1; i <= 1; i+=2)
1612 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1615 /* check if neighbour field is of same crumble type */
1616 if (IS_CRUMBLED_TILE(xx, yy, element) &&
1617 graphic_info[graphic].class ==
1618 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
1620 /* no crumbled corner, but continued crumbled border */
1622 width = crumbled_border_size;
1623 height = crumbled_border_size;
1624 cx = (dir == 2 ? TILEX - crumbled_border_size : 0);
1625 cy = (i == 1 ? TILEY - crumbled_border_size : 0);
1627 by = (i == 1 ? crumbled_border_size :
1628 TILEY - 2 * crumbled_border_size);
1630 BlitBitmap(src_bitmap, drawto_field, src_x + bx, src_y + by,
1631 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
1635 else /* top or bottom crumbled border */
1637 for (i = -1; i <= 1; i+=2)
1641 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1644 /* check if neighbour field is of same crumble type */
1645 if (IS_CRUMBLED_TILE(xx, yy, element) &&
1646 graphic_info[graphic].class ==
1647 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
1649 /* no crumbled corner, but continued crumbled border */
1651 width = crumbled_border_size;
1652 height = crumbled_border_size;
1653 cx = (i == 1 ? TILEX - crumbled_border_size : 0);
1654 cy = (dir == 3 ? TILEY - crumbled_border_size : 0);
1655 bx = (i == 1 ? crumbled_border_size :
1656 TILEX - 2 * crumbled_border_size);
1659 BlitBitmap(src_bitmap, drawto_field, src_x + bx, src_y + by,
1660 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
1667 static void DrawLevelFieldCrumbledExt(int x, int y, int graphic, int frame)
1669 int sx = SCREENX(x), sy = SCREENY(y);
1672 static int xy[4][2] =
1680 if (!IN_LEV_FIELD(x, y))
1683 element = TILE_GFX_ELEMENT(x, y);
1685 /* crumble field itself */
1686 if (IS_CRUMBLED_TILE(x, y, element))
1688 if (!IN_SCR_FIELD(sx, sy))
1691 for (i = 0; i < 4; i++)
1693 int xx = x + xy[i][0];
1694 int yy = y + xy[i][1];
1696 element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1699 /* check if neighbour field is of same crumble type */
1701 if (IS_CRUMBLED_TILE(xx, yy, element) &&
1702 graphic_info[graphic].class ==
1703 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
1706 if (IS_CRUMBLED_TILE(xx, yy, element))
1710 DrawLevelFieldCrumbledBorders(x, y, graphic, frame, i);
1713 if ((graphic_info[graphic].style & STYLE_INNER_CORNERS) &&
1714 graphic_info[graphic].anim_frames == 2)
1716 for (i = 0; i < 4; i++)
1718 int dx = (i & 1 ? +1 : -1);
1719 int dy = (i & 2 ? +1 : -1);
1721 DrawLevelFieldCrumbledInnerCorners(x, y, dx, dy, graphic);
1725 MarkTileDirty(sx, sy);
1727 else /* center field not crumbled -- crumble neighbour fields */
1729 for (i = 0; i < 4; i++)
1731 int xx = x + xy[i][0];
1732 int yy = y + xy[i][1];
1733 int sxx = sx + xy[i][0];
1734 int syy = sy + xy[i][1];
1736 if (!IN_LEV_FIELD(xx, yy) ||
1737 !IN_SCR_FIELD(sxx, syy))
1740 if (Feld[xx][yy] == EL_ELEMENT_SNAPPING)
1743 element = TILE_GFX_ELEMENT(xx, yy);
1745 if (!IS_CRUMBLED_TILE(xx, yy, element))
1748 graphic = el_act2crm(element, ACTION_DEFAULT);
1750 DrawLevelFieldCrumbledBorders(xx, yy, graphic, 0, 3 - i);
1752 MarkTileDirty(sxx, syy);
1757 void DrawLevelFieldCrumbled(int x, int y)
1761 if (!IN_LEV_FIELD(x, y))
1765 /* !!! CHECK THIS !!! */
1768 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
1769 GFX_CRUMBLED(GfxElement[x][y]))
1772 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
1773 GfxElement[x][y] != EL_UNDEFINED &&
1774 GFX_CRUMBLED(GfxElement[x][y]))
1776 DrawLevelFieldCrumbledDigging(x, y, GfxDir[x][y], GfxFrame[x][y]);
1783 graphic = el_act2crm(TILE_GFX_ELEMENT(x, y), ACTION_DEFAULT);
1785 graphic = el_act2crm(Feld[x][y], ACTION_DEFAULT);
1788 DrawLevelFieldCrumbledExt(x, y, graphic, 0);
1791 void DrawLevelFieldCrumbledDigging(int x, int y, int direction,
1794 int graphic1 = el_act_dir2img(GfxElement[x][y], ACTION_DIGGING, direction);
1795 int graphic2 = el_act_dir2crm(GfxElement[x][y], ACTION_DIGGING, direction);
1796 int frame1 = getGraphicAnimationFrame(graphic1, step_frame);
1797 int frame2 = getGraphicAnimationFrame(graphic2, step_frame);
1798 int sx = SCREENX(x), sy = SCREENY(y);
1800 DrawGraphic(sx, sy, graphic1, frame1);
1801 DrawLevelFieldCrumbledExt(x, y, graphic2, frame2);
1804 void DrawLevelFieldCrumbledNeighbours(int x, int y)
1806 int sx = SCREENX(x), sy = SCREENY(y);
1807 static int xy[4][2] =
1816 for (i = 0; i < 4; i++)
1818 int xx = x + xy[i][0];
1819 int yy = y + xy[i][1];
1820 int sxx = sx + xy[i][0];
1821 int syy = sy + xy[i][1];
1823 if (!IN_LEV_FIELD(xx, yy) ||
1824 !IN_SCR_FIELD(sxx, syy) ||
1825 !GFX_CRUMBLED(Feld[xx][yy]) ||
1829 DrawLevelField(xx, yy);
1833 static int getBorderElement(int x, int y)
1837 { EL_STEELWALL_TOPLEFT, EL_INVISIBLE_STEELWALL_TOPLEFT },
1838 { EL_STEELWALL_TOPRIGHT, EL_INVISIBLE_STEELWALL_TOPRIGHT },
1839 { EL_STEELWALL_BOTTOMLEFT, EL_INVISIBLE_STEELWALL_BOTTOMLEFT },
1840 { EL_STEELWALL_BOTTOMRIGHT, EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
1841 { EL_STEELWALL_VERTICAL, EL_INVISIBLE_STEELWALL_VERTICAL },
1842 { EL_STEELWALL_HORIZONTAL, EL_INVISIBLE_STEELWALL_HORIZONTAL },
1843 { EL_STEELWALL, EL_INVISIBLE_STEELWALL }
1845 int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
1846 int steel_position = (x == -1 && y == -1 ? 0 :
1847 x == lev_fieldx && y == -1 ? 1 :
1848 x == -1 && y == lev_fieldy ? 2 :
1849 x == lev_fieldx && y == lev_fieldy ? 3 :
1850 x == -1 || x == lev_fieldx ? 4 :
1851 y == -1 || y == lev_fieldy ? 5 : 6);
1853 return border[steel_position][steel_type];
1856 void DrawScreenElement(int x, int y, int element)
1858 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
1859 DrawLevelFieldCrumbled(LEVELX(x), LEVELY(y));
1862 void DrawLevelElement(int x, int y, int element)
1864 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1865 DrawScreenElement(SCREENX(x), SCREENY(y), element);
1868 void DrawScreenField(int x, int y)
1870 int lx = LEVELX(x), ly = LEVELY(y);
1871 int element, content;
1873 if (!IN_LEV_FIELD(lx, ly))
1875 if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
1878 element = getBorderElement(lx, ly);
1880 DrawScreenElement(x, y, element);
1885 element = Feld[lx][ly];
1886 content = Store[lx][ly];
1888 if (IS_MOVING(lx, ly))
1890 int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
1891 boolean cut_mode = NO_CUTTING;
1893 if (element == EL_QUICKSAND_EMPTYING ||
1894 element == EL_QUICKSAND_FAST_EMPTYING ||
1895 element == EL_MAGIC_WALL_EMPTYING ||
1896 element == EL_BD_MAGIC_WALL_EMPTYING ||
1897 element == EL_DC_MAGIC_WALL_EMPTYING ||
1898 element == EL_AMOEBA_DROPPING)
1899 cut_mode = CUT_ABOVE;
1900 else if (element == EL_QUICKSAND_FILLING ||
1901 element == EL_QUICKSAND_FAST_FILLING ||
1902 element == EL_MAGIC_WALL_FILLING ||
1903 element == EL_BD_MAGIC_WALL_FILLING ||
1904 element == EL_DC_MAGIC_WALL_FILLING)
1905 cut_mode = CUT_BELOW;
1908 if (lx == 9 && ly == 1)
1909 printf("::: %s [%d] [%d, %d] [%d]\n",
1910 EL_NAME(TILE_GFX_ELEMENT(lx, ly)),
1911 el_act2crm(TILE_GFX_ELEMENT(lx, ly), ACTION_DEFAULT),
1912 element_info[EL_QUICKSAND_EMPTYING].graphic[ACTION_DEFAULT],
1913 element_info[EL_QUICKSAND_EMPTYING].crumbled[ACTION_DEFAULT],
1914 GFX_CRUMBLED(TILE_GFX_ELEMENT(lx, ly)));
1917 if (cut_mode == CUT_ABOVE)
1919 DrawScreenElement(x, y, element);
1921 DrawScreenElementShifted(x, y, 0, 0, element, NO_CUTTING);
1924 DrawScreenElement(x, y, EL_EMPTY);
1927 DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
1928 else if (cut_mode == NO_CUTTING)
1929 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
1932 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
1935 if (cut_mode == CUT_BELOW &&
1936 IN_LEV_FIELD(lx, ly + 1) && IN_SCR_FIELD(x, y + 1))
1937 DrawLevelElement(lx, ly + 1, element);
1941 if (content == EL_ACID)
1943 int dir = MovDir[lx][ly];
1944 int newlx = lx + (dir == MV_LEFT ? -1 : dir == MV_RIGHT ? +1 : 0);
1945 int newly = ly + (dir == MV_UP ? -1 : dir == MV_DOWN ? +1 : 0);
1947 DrawLevelElementThruMask(newlx, newly, EL_ACID);
1950 else if (IS_BLOCKED(lx, ly))
1955 boolean cut_mode = NO_CUTTING;
1956 int element_old, content_old;
1958 Blocked2Moving(lx, ly, &oldx, &oldy);
1961 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
1962 MovDir[oldx][oldy] == MV_RIGHT);
1964 element_old = Feld[oldx][oldy];
1965 content_old = Store[oldx][oldy];
1967 if (element_old == EL_QUICKSAND_EMPTYING ||
1968 element_old == EL_QUICKSAND_FAST_EMPTYING ||
1969 element_old == EL_MAGIC_WALL_EMPTYING ||
1970 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
1971 element_old == EL_DC_MAGIC_WALL_EMPTYING ||
1972 element_old == EL_AMOEBA_DROPPING)
1973 cut_mode = CUT_ABOVE;
1975 DrawScreenElement(x, y, EL_EMPTY);
1978 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
1980 else if (cut_mode == NO_CUTTING)
1981 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
1984 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
1987 else if (IS_DRAWABLE(element))
1988 DrawScreenElement(x, y, element);
1990 DrawScreenElement(x, y, EL_EMPTY);
1993 void DrawLevelField(int x, int y)
1995 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1996 DrawScreenField(SCREENX(x), SCREENY(y));
1997 else if (IS_MOVING(x, y))
2001 Moving2Blocked(x, y, &newx, &newy);
2002 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
2003 DrawScreenField(SCREENX(newx), SCREENY(newy));
2005 else if (IS_BLOCKED(x, y))
2009 Blocked2Moving(x, y, &oldx, &oldy);
2010 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
2011 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
2015 void DrawMiniElement(int x, int y, int element)
2019 graphic = el2edimg(element);
2020 DrawMiniGraphic(x, y, graphic);
2023 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
2025 int x = sx + scroll_x, y = sy + scroll_y;
2027 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
2028 DrawMiniElement(sx, sy, EL_EMPTY);
2029 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
2030 DrawMiniElement(sx, sy, Feld[x][y]);
2032 DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
2035 void DrawEnvelopeBackground(int envelope_nr, int startx, int starty,
2036 int x, int y, int xsize, int ysize, int font_nr)
2038 int font_width = getFontWidth(font_nr);
2039 int font_height = getFontHeight(font_nr);
2040 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2043 int dst_x = SX + startx + x * font_width;
2044 int dst_y = SY + starty + y * font_height;
2045 int width = graphic_info[graphic].width;
2046 int height = graphic_info[graphic].height;
2047 int inner_width = MAX(width - 2 * font_width, font_width);
2048 int inner_height = MAX(height - 2 * font_height, font_height);
2049 int inner_sx = (width >= 3 * font_width ? font_width : 0);
2050 int inner_sy = (height >= 3 * font_height ? font_height : 0);
2051 boolean draw_masked = graphic_info[graphic].draw_masked;
2053 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
2055 if (src_bitmap == NULL || width < font_width || height < font_height)
2057 ClearRectangle(drawto, dst_x, dst_y, font_width, font_height);
2061 src_x += (x == 0 ? 0 : x == xsize - 1 ? width - font_width :
2062 inner_sx + (x - 1) * font_width % inner_width);
2063 src_y += (y == 0 ? 0 : y == ysize - 1 ? height - font_height :
2064 inner_sy + (y - 1) * font_height % inner_height);
2068 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
2069 dst_x - src_x, dst_y - src_y);
2070 BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, font_width, font_height,
2074 BlitBitmap(src_bitmap, drawto, src_x, src_y, font_width, font_height,
2078 void AnimateEnvelope(int envelope_nr, int anim_mode, int action)
2080 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2081 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
2082 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
2083 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2084 boolean no_delay = (tape.warp_forward);
2085 unsigned long anim_delay = 0;
2086 int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
2087 int anim_delay_value = (no_delay ? 0 : frame_delay_value);
2088 int font_nr = FONT_ENVELOPE_1 + envelope_nr;
2089 int font_width = getFontWidth(font_nr);
2090 int font_height = getFontHeight(font_nr);
2091 int max_xsize = level.envelope[envelope_nr].xsize;
2092 int max_ysize = level.envelope[envelope_nr].ysize;
2093 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
2094 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
2095 int xend = max_xsize;
2096 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
2097 int xstep = (xstart < xend ? 1 : 0);
2098 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
2101 for (x = xstart, y = ystart; x <= xend && y <= yend; x += xstep, y += ystep)
2103 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
2104 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
2105 int sx = (SXSIZE - xsize * font_width) / 2;
2106 int sy = (SYSIZE - ysize * font_height) / 2;
2109 SetDrawtoField(DRAW_BUFFERED);
2111 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
2113 SetDrawtoField(DRAW_BACKBUFFER);
2115 for (yy = 0; yy < ysize; yy++) for (xx = 0; xx < xsize; xx++)
2116 DrawEnvelopeBackground(envelope_nr, sx,sy, xx,yy, xsize, ysize, font_nr);
2119 DrawTextBuffer(SX + sx + font_width, SY + sy + font_height,
2120 level.envelope[envelope_nr].text, font_nr, max_xsize,
2121 xsize - 2, ysize - 2, 0, mask_mode,
2122 level.envelope[envelope_nr].autowrap,
2123 level.envelope[envelope_nr].centered, FALSE);
2125 DrawTextToTextArea(SX + sx + font_width, SY + sy + font_height,
2126 level.envelope[envelope_nr].text, font_nr, max_xsize,
2127 xsize - 2, ysize - 2, mask_mode);
2130 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
2133 WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
2137 void AnimateEnvelopeDoor(char *text, int anim_mode, int action)
2140 int envelope_nr = 0;
2142 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2143 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
2144 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
2145 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2146 boolean no_delay = (tape.warp_forward);
2147 unsigned long anim_delay = 0;
2148 int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
2149 int anim_delay_value = (no_delay ? 0 : frame_delay_value);
2151 int max_word_len = maxWordLengthInString(text);
2152 int font_nr = (max_word_len > 7 ? FONT_TEXT_1 : FONT_TEXT_2);
2154 int font_nr = FONT_ENVELOPE_1 + envelope_nr;
2156 int font_width = getFontWidth(font_nr);
2157 int font_height = getFontHeight(font_nr);
2161 int max_xsize = DXSIZE / font_width;
2162 int max_ysize = DYSIZE / font_height;
2164 int max_xsize = 7; /* tools.c: MAX_REQUEST_LINE_FONT1_LEN == 7 */
2165 int max_ysize = 13; /* tools.c: MAX_REQUEST_LINES == 13 */
2169 int max_xsize = level.envelope[envelope_nr].xsize;
2170 int max_ysize = level.envelope[envelope_nr].ysize;
2172 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
2173 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
2174 int xend = max_xsize;
2175 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
2176 int xstep = (xstart < xend ? 1 : 0);
2177 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
2182 char *text_copy = getStringCopy(text);
2185 font_nr = FONT_TEXT_2;
2187 if (maxWordLengthInString(text) > 7) /* MAX_REQUEST_LINE_FONT1_LEN == 7 */
2189 max_xsize = 10; /* tools.c: MAX_REQUEST_LINE_FONT2_LEN == 10 */
2190 font_nr = FONT_TEXT_1;
2193 int max_word_len = 0;
2195 char *text_copy = getStringCopy(text);
2197 font_nr = FONT_TEXT_2;
2199 for (text_ptr = text; *text_ptr; text_ptr++)
2201 max_word_len = (*text_ptr != ' ' ? max_word_len + 1 : 0);
2203 if (max_word_len > 7) /* tools.c: MAX_REQUEST_LINE_FONT1_LEN == 7 */
2205 max_xsize = 10; /* tools.c: MAX_REQUEST_LINE_FONT2_LEN == 10 */
2206 font_nr = FONT_TEXT_1;
2215 for (text_ptr = text_copy; *text_ptr; text_ptr++)
2216 if (*text_ptr == ' ')
2221 dDX = SX + (SXSIZE - DXSIZE) / 2 - DX;
2222 dDY = SY + (SYSIZE - DYSIZE) / 2 - DY;
2224 dDX = SX + SXSIZE / 2 - max_xsize * font_width / 2 - DX;
2225 dDY = SY + SYSIZE / 2 - max_ysize * font_height / 2 - DY;
2228 for (x = xstart, y = ystart; x <= xend && y <= yend; x += xstep, y += ystep)
2230 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
2231 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
2232 int sx = (SXSIZE - xsize * font_width) / 2;
2233 int sy = (SYSIZE - ysize * font_height) / 2;
2237 BlitBitmap(bitmap_db_store, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2239 SetDrawtoField(DRAW_BUFFERED);
2241 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
2243 SetDrawtoField(DRAW_BACKBUFFER);
2246 for (yy = 0; yy < ysize; yy++) for (xx = 0; xx < xsize; xx++)
2247 DrawEnvelopeBackground(envelope_nr, sx,sy, xx,yy, xsize, ysize, font_nr);
2252 DrawTextBuffer(SX + sx + font_width, SY + sy + font_height + 8,
2253 text_copy, font_nr, max_xsize,
2254 xsize - 2, ysize - 2, 2, mask_mode,
2255 FALSE, TRUE, FALSE);
2257 DrawTextBuffer(SX + sx + font_width, SY + sy + font_height,
2258 level.envelope[envelope_nr].text, font_nr, max_xsize,
2259 xsize - 2, ysize - 2, 0, mask_mode,
2260 level.envelope[envelope_nr].autowrap,
2261 level.envelope[envelope_nr].centered, FALSE);
2265 DrawTextToTextArea(SX + sx + font_width, SY + sy + font_height,
2266 level.envelope[envelope_nr].text, font_nr, max_xsize,
2267 xsize - 2, ysize - 2, mask_mode);
2270 /* copy request gadgets to door backbuffer */
2272 if ((ysize - 2) > 13)
2273 BlitBitmap(bitmap_db_door, drawto,
2274 DOOR_GFX_PAGEX1 + (DXSIZE - (xsize - 2) * font_width) / 2,
2275 DOOR_GFX_PAGEY1 + 13 * font_height,
2276 (xsize - 2) * font_width,
2277 (ysize - 2 - 13) * font_height,
2278 SX + sx + font_width,
2279 SY + sy + font_height * (1 + 13));
2281 if ((ysize - 2) > 13)
2282 BlitBitmap(bitmap_db_door, drawto,
2283 DOOR_GFX_PAGEX1 + (DXSIZE - (xsize - 2) * font_width) / 2,
2284 DOOR_GFX_PAGEY1 + 13 * font_height,
2285 (xsize - 2) * font_width,
2286 (ysize - 2 - 13) * font_height,
2287 SX + sx + font_width,
2288 SY + sy + font_height * (1 + 13));
2292 redraw_mask = REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
2293 // redraw_mask |= REDRAW_ALL | REDRAW_FROM_BACKBUFFER;
2295 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
2305 WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
2313 void ShowEnvelope(int envelope_nr)
2315 int element = EL_ENVELOPE_1 + envelope_nr;
2316 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2317 int sound_opening = element_info[element].sound[ACTION_OPENING];
2318 int sound_closing = element_info[element].sound[ACTION_CLOSING];
2319 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2320 boolean no_delay = (tape.warp_forward);
2321 int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
2322 int wait_delay_value = (no_delay ? 0 : normal_delay_value);
2323 int anim_mode = graphic_info[graphic].anim_mode;
2324 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
2325 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
2327 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
2329 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
2331 if (anim_mode == ANIM_DEFAULT)
2332 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_OPENING);
2334 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_OPENING);
2337 Delay(wait_delay_value);
2339 WaitForEventToContinue();
2341 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
2343 if (anim_mode != ANIM_NONE)
2344 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_CLOSING);
2346 if (anim_mode == ANIM_DEFAULT)
2347 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_CLOSING);
2349 game.envelope_active = FALSE;
2351 SetDrawtoField(DRAW_BUFFERED);
2353 redraw_mask |= REDRAW_FIELD;
2357 void ShowEnvelopeDoor(char *text, int action)
2360 int last_game_status = game_status; /* save current game status */
2361 // int last_draw_background_mask = gfx.draw_background_mask;
2362 int envelope_nr = 0;
2364 int element = EL_ENVELOPE_1 + envelope_nr;
2365 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2366 int sound_opening = element_info[element].sound[ACTION_OPENING];
2367 int sound_closing = element_info[element].sound[ACTION_CLOSING];
2369 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2370 boolean no_delay = (tape.warp_forward);
2371 int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
2372 int wait_delay_value = (no_delay ? 0 : normal_delay_value);
2374 int anim_mode = graphic_info[graphic].anim_mode;
2375 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
2376 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
2379 if (game_status == GAME_MODE_PLAYING)
2381 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
2382 BlitScreenToBitmap_EM(backbuffer);
2383 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
2384 BlitScreenToBitmap_SP(backbuffer);
2387 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
2391 SetDrawtoField(DRAW_BACKBUFFER);
2393 // SetDrawBackgroundMask(REDRAW_NONE);
2395 if (action == ACTION_OPENING)
2397 BlitBitmap(backbuffer, bitmap_db_store, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2399 if (game_status != GAME_MODE_MAIN)
2403 /* force DOOR font inside door area */
2404 game_status = GAME_MODE_PSEUDO_DOOR;
2407 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
2409 if (action == ACTION_OPENING)
2411 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
2413 if (anim_mode == ANIM_DEFAULT)
2414 AnimateEnvelopeDoor(text, ANIM_DEFAULT, ACTION_OPENING);
2416 AnimateEnvelopeDoor(text, main_anim_mode, ACTION_OPENING);
2420 Delay(wait_delay_value);
2422 WaitForEventToContinue();
2427 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
2429 if (anim_mode != ANIM_NONE)
2430 AnimateEnvelopeDoor(text, main_anim_mode, ACTION_CLOSING);
2432 if (anim_mode == ANIM_DEFAULT)
2433 AnimateEnvelopeDoor(text, ANIM_DEFAULT, ACTION_CLOSING);
2436 game.envelope_active = FALSE;
2439 // game_status = last_game_status; /* restore current game status */
2441 if (action == ACTION_CLOSING)
2443 if (game_status != GAME_MODE_MAIN)
2446 BlitBitmap(bitmap_db_store, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2449 SetDrawtoField(DRAW_BUFFERED);
2452 // SetDrawBackgroundMask(last_draw_background_mask);
2455 redraw_mask = REDRAW_FIELD;
2456 // redraw_mask |= REDRAW_ALL;
2458 redraw_mask |= REDRAW_FIELD;
2462 if (game_status == GAME_MODE_MAIN)
2467 /* (important: after "BackToFront()", but before "SetDrawtoField()") */
2468 game_status = last_game_status; /* restore current game status */
2470 if (game_status == GAME_MODE_PLAYING &&
2471 level.game_engine_type == GAME_ENGINE_TYPE_RND)
2472 SetDrawtoField(DRAW_BUFFERED);
2478 void DrawPreviewElement(int dst_x, int dst_y, int element, int tilesize)
2482 int graphic = el2preimg(element);
2484 getSizedGraphicSource(graphic, 0, tilesize, &src_bitmap, &src_x, &src_y);
2485 BlitBitmap(src_bitmap, drawto, src_x, src_y, tilesize, tilesize, dst_x,dst_y);
2493 SetMainBackgroundImage(IMG_BACKGROUND_PLAYING);
2494 SetDrawBackgroundMask(REDRAW_FIELD);
2496 SetDrawBackgroundMask(REDRAW_NONE);
2501 for (x = BX1; x <= BX2; x++)
2502 for (y = BY1; y <= BY2; y++)
2503 DrawScreenField(x, y);
2505 redraw_mask |= REDRAW_FIELD;
2508 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
2512 for (x = 0; x < size_x; x++)
2513 for (y = 0; y < size_y; y++)
2514 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
2516 redraw_mask |= REDRAW_FIELD;
2519 static void DrawPreviewLevelExt(int from_x, int from_y)
2521 boolean show_level_border = (BorderElement != EL_EMPTY);
2522 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
2523 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
2524 int tile_size = preview.tile_size;
2525 int preview_width = preview.xsize * tile_size;
2526 int preview_height = preview.ysize * tile_size;
2527 int real_preview_xsize = MIN(level_xsize, preview.xsize);
2528 int real_preview_ysize = MIN(level_ysize, preview.ysize);
2529 int dst_x = SX + ALIGNED_XPOS(preview.x, preview_width, preview.align);
2530 int dst_y = SY + ALIGNED_YPOS(preview.y, preview_height, preview.valign);
2533 DrawBackground(dst_x, dst_y, preview_width, preview_height);
2535 dst_x += (preview_width - real_preview_xsize * tile_size) / 2;
2536 dst_y += (preview_height - real_preview_ysize * tile_size) / 2;
2538 for (x = 0; x < real_preview_xsize; x++)
2540 for (y = 0; y < real_preview_ysize; y++)
2542 int lx = from_x + x + (show_level_border ? -1 : 0);
2543 int ly = from_y + y + (show_level_border ? -1 : 0);
2544 int element = (IN_LEV_FIELD(lx, ly) ? level.field[lx][ly] :
2545 getBorderElement(lx, ly));
2547 DrawPreviewElement(dst_x + x * tile_size, dst_y + y * tile_size,
2548 element, tile_size);
2552 redraw_mask |= REDRAW_MICROLEVEL;
2555 #define MICROLABEL_EMPTY 0
2556 #define MICROLABEL_LEVEL_NAME 1
2557 #define MICROLABEL_LEVEL_AUTHOR_HEAD 2
2558 #define MICROLABEL_LEVEL_AUTHOR 3
2559 #define MICROLABEL_IMPORTED_FROM_HEAD 4
2560 #define MICROLABEL_IMPORTED_FROM 5
2561 #define MICROLABEL_IMPORTED_BY_HEAD 6
2562 #define MICROLABEL_IMPORTED_BY 7
2564 static int getMaxTextLength(struct TextPosInfo *pos, int font_nr)
2566 int max_text_width = SXSIZE;
2567 int font_width = getFontWidth(font_nr);
2569 if (pos->align == ALIGN_CENTER)
2570 max_text_width = (pos->x < SXSIZE / 2 ? pos->x * 2 : (SXSIZE - pos->x) * 2);
2571 else if (pos->align == ALIGN_RIGHT)
2572 max_text_width = pos->x;
2574 max_text_width = SXSIZE - pos->x;
2576 return max_text_width / font_width;
2579 static void DrawPreviewLevelLabelExt(int mode)
2581 struct TextPosInfo *pos = &menu.main.text.level_info_2;
2582 char label_text[MAX_OUTPUT_LINESIZE + 1];
2583 int max_len_label_text;
2585 int font_nr = pos->font;
2588 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
2589 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
2590 mode == MICROLABEL_IMPORTED_BY_HEAD)
2591 font_nr = pos->font_alt;
2593 int font_nr = FONT_TEXT_2;
2596 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
2597 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
2598 mode == MICROLABEL_IMPORTED_BY_HEAD)
2599 font_nr = FONT_TEXT_3;
2603 max_len_label_text = getMaxTextLength(pos, font_nr);
2605 max_len_label_text = SXSIZE / getFontWidth(font_nr);
2609 if (pos->size != -1)
2610 max_len_label_text = pos->size;
2613 for (i = 0; i < max_len_label_text; i++)
2614 label_text[i] = ' ';
2615 label_text[max_len_label_text] = '\0';
2617 if (strlen(label_text) > 0)
2620 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2622 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
2623 int lypos = MICROLABEL2_YPOS;
2625 DrawText(lxpos, lypos, label_text, font_nr);
2630 (mode == MICROLABEL_LEVEL_NAME ? level.name :
2631 mode == MICROLABEL_LEVEL_AUTHOR_HEAD ? "created by" :
2632 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
2633 mode == MICROLABEL_IMPORTED_FROM_HEAD ? "imported from" :
2634 mode == MICROLABEL_IMPORTED_FROM ? leveldir_current->imported_from :
2635 mode == MICROLABEL_IMPORTED_BY_HEAD ? "imported by" :
2636 mode == MICROLABEL_IMPORTED_BY ? leveldir_current->imported_by :""),
2637 max_len_label_text);
2638 label_text[max_len_label_text] = '\0';
2640 if (strlen(label_text) > 0)
2643 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2645 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
2646 int lypos = MICROLABEL2_YPOS;
2648 DrawText(lxpos, lypos, label_text, font_nr);
2652 redraw_mask |= REDRAW_MICROLEVEL;
2655 void DrawPreviewLevel(boolean restart)
2657 static unsigned long scroll_delay = 0;
2658 static unsigned long label_delay = 0;
2659 static int from_x, from_y, scroll_direction;
2660 static int label_state, label_counter;
2661 unsigned long scroll_delay_value = preview.step_delay;
2662 boolean show_level_border = (BorderElement != EL_EMPTY);
2663 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
2664 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
2665 int last_game_status = game_status; /* save current game status */
2668 /* force PREVIEW font on preview level */
2669 game_status = GAME_MODE_PSEUDO_PREVIEW;
2677 if (preview.anim_mode == ANIM_CENTERED)
2679 if (level_xsize > preview.xsize)
2680 from_x = (level_xsize - preview.xsize) / 2;
2681 if (level_ysize > preview.ysize)
2682 from_y = (level_ysize - preview.ysize) / 2;
2685 from_x += preview.xoffset;
2686 from_y += preview.yoffset;
2688 scroll_direction = MV_RIGHT;
2692 DrawPreviewLevelExt(from_x, from_y);
2693 DrawPreviewLevelLabelExt(label_state);
2695 /* initialize delay counters */
2696 DelayReached(&scroll_delay, 0);
2697 DelayReached(&label_delay, 0);
2699 if (leveldir_current->name)
2701 struct TextPosInfo *pos = &menu.main.text.level_info_1;
2702 char label_text[MAX_OUTPUT_LINESIZE + 1];
2704 int font_nr = pos->font;
2706 int font_nr = FONT_TEXT_1;
2709 int max_len_label_text = getMaxTextLength(pos, font_nr);
2711 int max_len_label_text = SXSIZE / getFontWidth(font_nr);
2719 if (pos->size != -1)
2720 max_len_label_text = pos->size;
2723 strncpy(label_text, leveldir_current->name, max_len_label_text);
2724 label_text[max_len_label_text] = '\0';
2727 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2729 lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
2730 lypos = SY + MICROLABEL1_YPOS;
2732 DrawText(lxpos, lypos, label_text, font_nr);
2736 game_status = last_game_status; /* restore current game status */
2741 /* scroll preview level, if needed */
2742 if (preview.anim_mode != ANIM_NONE &&
2743 (level_xsize > preview.xsize || level_ysize > preview.ysize) &&
2744 DelayReached(&scroll_delay, scroll_delay_value))
2746 switch (scroll_direction)
2751 from_x -= preview.step_offset;
2752 from_x = (from_x < 0 ? 0 : from_x);
2755 scroll_direction = MV_UP;
2759 if (from_x < level_xsize - preview.xsize)
2761 from_x += preview.step_offset;
2762 from_x = (from_x > level_xsize - preview.xsize ?
2763 level_xsize - preview.xsize : from_x);
2766 scroll_direction = MV_DOWN;
2772 from_y -= preview.step_offset;
2773 from_y = (from_y < 0 ? 0 : from_y);
2776 scroll_direction = MV_RIGHT;
2780 if (from_y < level_ysize - preview.ysize)
2782 from_y += preview.step_offset;
2783 from_y = (from_y > level_ysize - preview.ysize ?
2784 level_ysize - preview.ysize : from_y);
2787 scroll_direction = MV_LEFT;
2794 DrawPreviewLevelExt(from_x, from_y);
2797 /* !!! THIS ALL SUCKS -- SHOULD BE CLEANLY REWRITTEN !!! */
2798 /* redraw micro level label, if needed */
2799 if (!strEqual(level.name, NAMELESS_LEVEL_NAME) &&
2800 !strEqual(level.author, ANONYMOUS_NAME) &&
2801 !strEqual(level.author, leveldir_current->name) &&
2802 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
2804 int max_label_counter = 23;
2806 if (leveldir_current->imported_from != NULL &&
2807 strlen(leveldir_current->imported_from) > 0)
2808 max_label_counter += 14;
2809 if (leveldir_current->imported_by != NULL &&
2810 strlen(leveldir_current->imported_by) > 0)
2811 max_label_counter += 14;
2813 label_counter = (label_counter + 1) % max_label_counter;
2814 label_state = (label_counter >= 0 && label_counter <= 7 ?
2815 MICROLABEL_LEVEL_NAME :
2816 label_counter >= 9 && label_counter <= 12 ?
2817 MICROLABEL_LEVEL_AUTHOR_HEAD :
2818 label_counter >= 14 && label_counter <= 21 ?
2819 MICROLABEL_LEVEL_AUTHOR :
2820 label_counter >= 23 && label_counter <= 26 ?
2821 MICROLABEL_IMPORTED_FROM_HEAD :
2822 label_counter >= 28 && label_counter <= 35 ?
2823 MICROLABEL_IMPORTED_FROM :
2824 label_counter >= 37 && label_counter <= 40 ?
2825 MICROLABEL_IMPORTED_BY_HEAD :
2826 label_counter >= 42 && label_counter <= 49 ?
2827 MICROLABEL_IMPORTED_BY : MICROLABEL_EMPTY);
2829 if (leveldir_current->imported_from == NULL &&
2830 (label_state == MICROLABEL_IMPORTED_FROM_HEAD ||
2831 label_state == MICROLABEL_IMPORTED_FROM))
2832 label_state = (label_state == MICROLABEL_IMPORTED_FROM_HEAD ?
2833 MICROLABEL_IMPORTED_BY_HEAD : MICROLABEL_IMPORTED_BY);
2835 DrawPreviewLevelLabelExt(label_state);
2838 game_status = last_game_status; /* restore current game status */
2841 inline void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
2842 int graphic, int sync_frame, int mask_mode)
2844 int frame = getGraphicAnimationFrame(graphic, sync_frame);
2846 if (mask_mode == USE_MASKING)
2847 DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
2849 DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
2852 inline void DrawGraphicAnimation(int x, int y, int graphic)
2854 int lx = LEVELX(x), ly = LEVELY(y);
2856 if (!IN_SCR_FIELD(x, y))
2859 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
2860 graphic, GfxFrame[lx][ly], NO_MASKING);
2861 MarkTileDirty(x, y);
2864 void DrawLevelGraphicAnimation(int x, int y, int graphic)
2866 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
2869 void DrawLevelElementAnimation(int x, int y, int element)
2871 int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
2873 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
2876 inline void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
2878 int sx = SCREENX(x), sy = SCREENY(y);
2880 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
2883 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
2886 DrawGraphicAnimation(sx, sy, graphic);
2889 if (GFX_CRUMBLED(TILE_GFX_ELEMENT(x, y)))
2890 DrawLevelFieldCrumbled(x, y);
2892 if (GFX_CRUMBLED(Feld[x][y]))
2893 DrawLevelFieldCrumbled(x, y);
2897 void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
2899 int sx = SCREENX(x), sy = SCREENY(y);
2902 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
2905 graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
2907 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
2910 DrawGraphicAnimation(sx, sy, graphic);
2912 if (GFX_CRUMBLED(element))
2913 DrawLevelFieldCrumbled(x, y);
2916 static int getPlayerGraphic(struct PlayerInfo *player, int move_dir)
2918 if (player->use_murphy)
2920 /* this works only because currently only one player can be "murphy" ... */
2921 static int last_horizontal_dir = MV_LEFT;
2922 int graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir);
2924 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
2925 last_horizontal_dir = move_dir;
2927 if (graphic == IMG_SP_MURPHY) /* undefined => use special graphic */
2929 int direction = (player->is_snapping ? move_dir : last_horizontal_dir);
2931 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
2937 return el_act_dir2img(player->artwork_element, player->GfxAction,move_dir);
2940 static boolean equalGraphics(int graphic1, int graphic2)
2942 struct GraphicInfo *g1 = &graphic_info[graphic1];
2943 struct GraphicInfo *g2 = &graphic_info[graphic2];
2945 return (g1->bitmap == g2->bitmap &&
2946 g1->src_x == g2->src_x &&
2947 g1->src_y == g2->src_y &&
2948 g1->anim_frames == g2->anim_frames &&
2949 g1->anim_delay == g2->anim_delay &&
2950 g1->anim_mode == g2->anim_mode);
2953 void DrawAllPlayers()
2957 for (i = 0; i < MAX_PLAYERS; i++)
2958 if (stored_player[i].active)
2959 DrawPlayer(&stored_player[i]);
2962 void DrawPlayerField(int x, int y)
2964 if (!IS_PLAYER(x, y))
2967 DrawPlayer(PLAYERINFO(x, y));
2970 #define DRAW_PLAYER_OVER_PUSHED_ELEMENT 1
2972 void DrawPlayer(struct PlayerInfo *player)
2974 int jx = player->jx;
2975 int jy = player->jy;
2976 int move_dir = player->MovDir;
2977 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? +1 : 0);
2978 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? +1 : 0);
2979 int last_jx = (player->is_moving ? jx - dx : jx);
2980 int last_jy = (player->is_moving ? jy - dy : jy);
2981 int next_jx = jx + dx;
2982 int next_jy = jy + dy;
2983 boolean player_is_moving = (player->MovPos ? TRUE : FALSE);
2984 boolean player_is_opaque = FALSE;
2985 int sx = SCREENX(jx), sy = SCREENY(jy);
2986 int sxx = 0, syy = 0;
2987 int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
2989 int action = ACTION_DEFAULT;
2990 int last_player_graphic = getPlayerGraphic(player, move_dir);
2991 int last_player_frame = player->Frame;
2994 /* GfxElement[][] is set to the element the player is digging or collecting;
2995 remove also for off-screen player if the player is not moving anymore */
2996 if (IN_LEV_FIELD(jx, jy) && !player_is_moving)
2997 GfxElement[jx][jy] = EL_UNDEFINED;
2999 if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
3003 if (!IN_LEV_FIELD(jx, jy))
3005 printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
3006 printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
3007 printf("DrawPlayerField(): This should never happen!\n");
3012 if (element == EL_EXPLOSION)
3015 action = (player->is_pushing ? ACTION_PUSHING :
3016 player->is_digging ? ACTION_DIGGING :
3017 player->is_collecting ? ACTION_COLLECTING :
3018 player->is_moving ? ACTION_MOVING :
3019 player->is_snapping ? ACTION_SNAPPING :
3020 player->is_dropping ? ACTION_DROPPING :
3021 player->is_waiting ? player->action_waiting : ACTION_DEFAULT);
3023 if (player->is_waiting)
3024 move_dir = player->dir_waiting;
3026 InitPlayerGfxAnimation(player, action, move_dir);
3028 /* ----------------------------------------------------------------------- */
3029 /* draw things in the field the player is leaving, if needed */
3030 /* ----------------------------------------------------------------------- */
3032 if (player->is_moving)
3034 if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
3036 DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
3038 if (last_element == EL_DYNAMITE_ACTIVE ||
3039 last_element == EL_EM_DYNAMITE_ACTIVE ||
3040 last_element == EL_SP_DISK_RED_ACTIVE)
3041 DrawDynamite(last_jx, last_jy);
3043 DrawLevelFieldThruMask(last_jx, last_jy);
3045 else if (last_element == EL_DYNAMITE_ACTIVE ||
3046 last_element == EL_EM_DYNAMITE_ACTIVE ||
3047 last_element == EL_SP_DISK_RED_ACTIVE)
3048 DrawDynamite(last_jx, last_jy);
3050 /* !!! this is not enough to prevent flickering of players which are
3051 moving next to each others without a free tile between them -- this
3052 can only be solved by drawing all players layer by layer (first the
3053 background, then the foreground etc.) !!! => TODO */
3054 else if (!IS_PLAYER(last_jx, last_jy))
3055 DrawLevelField(last_jx, last_jy);
3058 DrawLevelField(last_jx, last_jy);
3061 if (player->is_pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
3062 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
3065 if (!IN_SCR_FIELD(sx, sy))
3068 /* ----------------------------------------------------------------------- */
3069 /* draw things behind the player, if needed */
3070 /* ----------------------------------------------------------------------- */
3073 DrawLevelElement(jx, jy, Back[jx][jy]);
3074 else if (IS_ACTIVE_BOMB(element))
3075 DrawLevelElement(jx, jy, EL_EMPTY);
3078 if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
3080 int old_element = GfxElement[jx][jy];
3081 int old_graphic = el_act_dir2img(old_element, action, move_dir);
3082 int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
3084 if (GFX_CRUMBLED(old_element))
3085 DrawLevelFieldCrumbledDigging(jx, jy, move_dir, player->StepFrame);
3087 DrawGraphic(sx, sy, old_graphic, frame);
3089 if (graphic_info[old_graphic].anim_mode & ANIM_OPAQUE_PLAYER)
3090 player_is_opaque = TRUE;
3094 GfxElement[jx][jy] = EL_UNDEFINED;
3096 /* make sure that pushed elements are drawn with correct frame rate */
3098 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
3100 if (player->is_pushing && player->is_moving && !IS_ANIM_MODE_CE(graphic))
3101 GfxFrame[jx][jy] = player->StepFrame;
3103 if (player->is_pushing && player->is_moving)
3104 GfxFrame[jx][jy] = player->StepFrame;
3107 DrawLevelField(jx, jy);
3111 #if !DRAW_PLAYER_OVER_PUSHED_ELEMENT
3112 /* ----------------------------------------------------------------------- */
3113 /* draw player himself */
3114 /* ----------------------------------------------------------------------- */
3116 graphic = getPlayerGraphic(player, move_dir);
3118 /* in the case of changed player action or direction, prevent the current
3119 animation frame from being restarted for identical animations */
3120 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
3121 player->Frame = last_player_frame;
3123 frame = getGraphicAnimationFrame(graphic, player->Frame);
3127 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3128 sxx = player->GfxPos;
3130 syy = player->GfxPos;
3133 if (!setup.soft_scrolling && ScreenMovPos)
3136 if (player_is_opaque)
3137 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
3139 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3141 if (SHIELD_ON(player))
3143 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
3144 IMG_SHIELD_NORMAL_ACTIVE);
3145 int frame = getGraphicAnimationFrame(graphic, -1);
3147 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3151 #if DRAW_PLAYER_OVER_PUSHED_ELEMENT
3154 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3155 sxx = player->GfxPos;
3157 syy = player->GfxPos;
3161 /* ----------------------------------------------------------------------- */
3162 /* draw things the player is pushing, if needed */
3163 /* ----------------------------------------------------------------------- */
3166 printf("::: %d, %d [%d, %d] [%d]\n",
3167 player->is_pushing, player_is_moving, player->GfxAction,
3168 player->is_moving, player_is_moving);
3172 if (player->is_pushing && player->is_moving)
3174 int px = SCREENX(jx), py = SCREENY(jy);
3175 int pxx = (TILEX - ABS(sxx)) * dx;
3176 int pyy = (TILEY - ABS(syy)) * dy;
3177 int gfx_frame = GfxFrame[jx][jy];
3183 if (!IS_MOVING(jx, jy)) /* push movement already finished */
3185 element = Feld[next_jx][next_jy];
3186 gfx_frame = GfxFrame[next_jx][next_jy];
3189 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
3192 sync_frame = (IS_ANIM_MODE_CE(graphic) ? gfx_frame : player->StepFrame);
3193 frame = getGraphicAnimationFrame(graphic, sync_frame);
3195 frame = getGraphicAnimationFrame(graphic, player->StepFrame);
3198 /* draw background element under pushed element (like the Sokoban field) */
3200 if (game.use_masked_pushing && IS_MOVING(jx, jy))
3202 /* this allows transparent pushing animation over non-black background */
3205 DrawLevelElement(jx, jy, Back[jx][jy]);
3207 DrawLevelElement(jx, jy, EL_EMPTY);
3209 if (Back[next_jx][next_jy])
3210 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
3212 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
3214 else if (Back[next_jx][next_jy])
3215 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
3217 if (Back[next_jx][next_jy])
3218 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
3222 printf("::: %d, %d, %d, %d [%d] [%d, %d, %d] [%d] [%d, %d] [%d, %d]\n",
3223 jx, px, player->GfxPos, player->StepFrame,
3228 GfxFrame[jx][jy], GfxFrame[next_jx][next_jy]);
3232 /* do not draw (EM style) pushing animation when pushing is finished */
3233 /* (two-tile animations usually do not contain start and end frame) */
3234 if (graphic_info[graphic].double_movement && !IS_MOVING(jx, jy))
3235 DrawLevelElement(next_jx, next_jy, Feld[next_jx][next_jy]);
3237 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
3239 /* masked drawing is needed for EMC style (double) movement graphics */
3240 /* !!! (ONLY WHEN DRAWING PUSHED ELEMENT OVER THE PLAYER) !!! */
3241 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
3246 #if DRAW_PLAYER_OVER_PUSHED_ELEMENT
3247 /* ----------------------------------------------------------------------- */
3248 /* draw player himself */
3249 /* ----------------------------------------------------------------------- */
3251 graphic = getPlayerGraphic(player, move_dir);
3253 /* in the case of changed player action or direction, prevent the current
3254 animation frame from being restarted for identical animations */
3255 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
3256 player->Frame = last_player_frame;
3258 frame = getGraphicAnimationFrame(graphic, player->Frame);
3262 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3263 sxx = player->GfxPos;
3265 syy = player->GfxPos;
3268 if (!setup.soft_scrolling && ScreenMovPos)
3271 if (player_is_opaque)
3272 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
3274 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3276 if (SHIELD_ON(player))
3278 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
3279 IMG_SHIELD_NORMAL_ACTIVE);
3280 int frame = getGraphicAnimationFrame(graphic, -1);
3282 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3286 /* ----------------------------------------------------------------------- */
3287 /* draw things in front of player (active dynamite or dynabombs) */
3288 /* ----------------------------------------------------------------------- */
3290 if (IS_ACTIVE_BOMB(element))
3292 graphic = el2img(element);
3293 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
3295 if (game.emulation == EMU_SUPAPLEX)
3296 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
3298 DrawGraphicThruMask(sx, sy, graphic, frame);
3301 if (player_is_moving && last_element == EL_EXPLOSION)
3303 int element = (GfxElement[last_jx][last_jy] != EL_UNDEFINED ?
3304 GfxElement[last_jx][last_jy] : EL_EMPTY);
3305 int graphic = el_act2img(element, ACTION_EXPLODING);
3306 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
3307 int phase = ExplodePhase[last_jx][last_jy] - 1;
3308 int frame = getGraphicAnimationFrame(graphic, phase - delay);
3311 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
3314 /* ----------------------------------------------------------------------- */
3315 /* draw elements the player is just walking/passing through/under */
3316 /* ----------------------------------------------------------------------- */
3318 if (player_is_moving)
3320 /* handle the field the player is leaving ... */
3321 if (IS_ACCESSIBLE_INSIDE(last_element))
3322 DrawLevelField(last_jx, last_jy);
3323 else if (IS_ACCESSIBLE_UNDER(last_element))
3324 DrawLevelFieldThruMask(last_jx, last_jy);
3327 /* do not redraw accessible elements if the player is just pushing them */
3328 if (!player_is_moving || !player->is_pushing)
3330 /* ... and the field the player is entering */
3331 if (IS_ACCESSIBLE_INSIDE(element))
3332 DrawLevelField(jx, jy);
3333 else if (IS_ACCESSIBLE_UNDER(element))
3334 DrawLevelFieldThruMask(jx, jy);
3337 MarkTileDirty(sx, sy);
3340 /* ------------------------------------------------------------------------- */
3342 void WaitForEventToContinue()
3344 boolean still_wait = TRUE;
3346 /* simulate releasing mouse button over last gadget, if still pressed */
3348 HandleGadgets(-1, -1, 0);
3350 button_status = MB_RELEASED;
3366 case EVENT_BUTTONPRESS:
3367 case EVENT_KEYPRESS:
3371 case EVENT_KEYRELEASE:
3372 ClearPlayerAction();
3376 HandleOtherEvents(&event);
3380 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
3387 /* don't eat all CPU time */
3392 #define MAX_REQUEST_LINES 13
3393 #define MAX_REQUEST_LINE_FONT1_LEN 7
3394 #define MAX_REQUEST_LINE_FONT2_LEN 10
3396 boolean Request(char *text, unsigned int req_state)
3398 int mx, my, ty, result = -1;
3399 unsigned int old_door_state;
3400 int last_game_status = game_status; /* save current game status */
3401 int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
3402 int font_nr = FONT_TEXT_2;
3404 int max_word_len = 0;
3409 global.use_envelope_request = TRUE * 1;
3412 if (maxWordLengthInString(text) > MAX_REQUEST_LINE_FONT1_LEN)
3414 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
3415 font_nr = FONT_TEXT_1;
3418 for (text_ptr = text; *text_ptr; text_ptr++)
3420 max_word_len = (*text_ptr != ' ' ? max_word_len + 1 : 0);
3422 if (max_word_len > MAX_REQUEST_LINE_FONT1_LEN)
3424 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
3426 font_nr = FONT_TEXT_1;
3428 font_nr = FONT_LEVEL_NUMBER;
3436 if (game_status == GAME_MODE_PLAYING)
3438 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
3439 BlitScreenToBitmap_EM(backbuffer);
3440 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
3441 BlitScreenToBitmap_SP(backbuffer);
3444 /* disable deactivated drawing when quick-loading level tape recording */
3445 if (tape.playing && tape.deactivate_display)
3446 TapeDeactivateDisplayOff(TRUE);
3448 SetMouseCursor(CURSOR_DEFAULT);
3450 #if defined(NETWORK_AVALIABLE)
3451 /* pause network game while waiting for request to answer */
3452 if (options.network &&
3453 game_status == GAME_MODE_PLAYING &&
3454 req_state & REQUEST_WAIT_FOR_INPUT)
3455 SendToServer_PausePlaying();
3458 old_door_state = GetDoorState();
3460 /* simulate releasing mouse button over last gadget, if still pressed */
3462 HandleGadgets(-1, -1, 0);
3466 /* draw released gadget before proceeding */
3470 if (old_door_state & DOOR_OPEN_1 && !global.use_envelope_request)
3472 if (old_door_state & DOOR_OPEN_1)
3476 if (!global.use_envelope_request)
3477 CloseDoor(DOOR_CLOSE_1);
3479 CloseDoor(DOOR_CLOSE_1);
3482 /* save old door content */
3483 BlitBitmap(bitmap_db_door, bitmap_db_door,
3484 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
3485 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
3489 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
3492 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3494 /* clear door drawing field */
3495 DrawBackground(DX, DY, DXSIZE, DYSIZE);
3497 /* force DOOR font inside door area */
3498 game_status = GAME_MODE_PSEUDO_DOOR;
3500 /* write text for request */
3501 for (text_ptr = text, ty = 0; ty < MAX_REQUEST_LINES; ty++)
3503 char text_line[max_request_line_len + 1];
3509 for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
3511 tc = *(text_ptr + tx);
3512 if (!tc || tc == ' ')
3523 strncpy(text_line, text_ptr, tl);
3526 DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
3527 DY + 8 + ty * (getFontHeight(font_nr) + 2),
3528 text_line, font_nr);
3530 text_ptr += tl + (tc == ' ' ? 1 : 0);
3533 game_status = last_game_status; /* restore current game status */
3536 if (global.use_envelope_request)
3540 CreateToolButtons();
3544 if (req_state & REQ_ASK)
3546 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
3547 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
3549 else if (req_state & REQ_CONFIRM)
3551 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
3553 else if (req_state & REQ_PLAYER)
3555 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
3556 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
3557 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
3558 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
3561 /* copy request gadgets to door backbuffer */
3562 BlitBitmap(drawto, bitmap_db_door,
3563 DX, DY, DXSIZE, DYSIZE,
3564 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
3567 if (global.use_envelope_request)
3569 ShowEnvelopeDoor(text, ACTION_OPENING);
3571 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3573 if ((req_state & REQ_ASK && (i == TOOL_CTRL_ID_YES ||
3574 i == TOOL_CTRL_ID_NO)) ||
3575 (req_state & REQ_CONFIRM && i == TOOL_CTRL_ID_CONFIRM) ||
3576 (req_state & REQ_PLAYER && (i == TOOL_CTRL_ID_PLAYER_1 &&
3577 i == TOOL_CTRL_ID_PLAYER_2 &&
3578 i == TOOL_CTRL_ID_PLAYER_3 &&
3579 i == TOOL_CTRL_ID_PLAYER_4)))
3581 int x = tool_gadget[i]->x + dDX;
3582 int y = tool_gadget[i]->y + dDY;
3584 ModifyGadget(tool_gadget[i], GDI_X, x, GDI_Y, y, GDI_END);
3591 if (!global.use_envelope_request)
3592 OpenDoor(DOOR_OPEN_1);
3594 OpenDoor(DOOR_OPEN_1);
3597 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
3599 if (game_status == GAME_MODE_PLAYING)
3601 SetPanelBackground();
3602 SetDrawBackgroundMask(REDRAW_DOOR_1);
3606 SetDrawBackgroundMask(REDRAW_FIELD);
3613 if (game_status != GAME_MODE_MAIN && !global.use_envelope_request)
3616 if (game_status != GAME_MODE_MAIN)
3620 button_status = MB_RELEASED;
3622 request_gadget_id = -1;
3624 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3636 case EVENT_BUTTONPRESS:
3637 case EVENT_BUTTONRELEASE:
3638 case EVENT_MOTIONNOTIFY:
3640 if (event.type == EVENT_MOTIONNOTIFY)
3642 if (!PointerInWindow(window))
3643 continue; /* window and pointer are on different screens */
3648 motion_status = TRUE;
3649 mx = ((MotionEvent *) &event)->x;
3650 my = ((MotionEvent *) &event)->y;
3654 motion_status = FALSE;
3655 mx = ((ButtonEvent *) &event)->x;
3656 my = ((ButtonEvent *) &event)->y;
3657 if (event.type == EVENT_BUTTONPRESS)
3658 button_status = ((ButtonEvent *) &event)->button;
3660 button_status = MB_RELEASED;
3663 /* this sets 'request_gadget_id' */
3664 HandleGadgets(mx, my, button_status);
3666 switch (request_gadget_id)
3668 case TOOL_CTRL_ID_YES:
3671 case TOOL_CTRL_ID_NO:
3674 case TOOL_CTRL_ID_CONFIRM:
3675 result = TRUE | FALSE;
3678 case TOOL_CTRL_ID_PLAYER_1:
3681 case TOOL_CTRL_ID_PLAYER_2:
3684 case TOOL_CTRL_ID_PLAYER_3:
3687 case TOOL_CTRL_ID_PLAYER_4:
3698 case EVENT_KEYPRESS:
3699 switch (GetEventKey((KeyEvent *)&event, TRUE))
3702 if (req_state & REQ_CONFIRM)
3718 if (req_state & REQ_PLAYER)
3722 case EVENT_KEYRELEASE:
3723 ClearPlayerAction();
3727 HandleOtherEvents(&event);
3731 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
3733 int joy = AnyJoystick();
3735 if (joy & JOY_BUTTON_1)
3737 else if (joy & JOY_BUTTON_2)
3743 if (game_status == GAME_MODE_PLAYING && local_player->LevelSolved_GameEnd)
3745 HandleGameActions();
3751 if (!PendingEvent()) /* delay only if no pending events */
3756 game_status = GAME_MODE_PSEUDO_DOOR;
3762 game_status = last_game_status; /* restore current game status */
3770 if (!PendingEvent()) /* delay only if no pending events */
3773 /* don't eat all CPU time */
3780 if (game_status != GAME_MODE_MAIN)
3786 if (global.use_envelope_request)
3787 ShowEnvelopeDoor(text, ACTION_CLOSING);
3791 if (!(req_state & REQ_STAY_OPEN) && !global.use_envelope_request)
3793 if (!(req_state & REQ_STAY_OPEN))
3796 CloseDoor(DOOR_CLOSE_1);
3798 if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
3799 (req_state & REQ_REOPEN))
3800 OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
3805 if (game_status == GAME_MODE_PLAYING)
3807 SetPanelBackground();
3808 SetDrawBackgroundMask(REDRAW_DOOR_1);
3812 SetDrawBackgroundMask(REDRAW_FIELD);
3815 #if defined(NETWORK_AVALIABLE)
3816 /* continue network game after request */
3817 if (options.network &&
3818 game_status == GAME_MODE_PLAYING &&
3819 req_state & REQUEST_WAIT_FOR_INPUT)
3820 SendToServer_ContinuePlaying();
3823 /* restore deactivated drawing when quick-loading level tape recording */
3824 if (tape.playing && tape.deactivate_display)
3825 TapeDeactivateDisplayOn();
3830 unsigned int OpenDoor(unsigned int door_state)
3832 if (door_state & DOOR_COPY_BACK)
3834 if (door_state & DOOR_OPEN_1)
3835 BlitBitmap(bitmap_db_door, bitmap_db_door,
3836 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
3837 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
3839 if (door_state & DOOR_OPEN_2)
3840 BlitBitmap(bitmap_db_door, bitmap_db_door,
3841 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY2, VXSIZE, VYSIZE,
3842 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
3844 door_state &= ~DOOR_COPY_BACK;
3847 return MoveDoor(door_state);
3850 unsigned int CloseDoor(unsigned int door_state)
3852 unsigned int old_door_state = GetDoorState();
3854 if (!(door_state & DOOR_NO_COPY_BACK))
3856 if (old_door_state & DOOR_OPEN_1)
3857 BlitBitmap(backbuffer, bitmap_db_door,
3858 DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
3860 if (old_door_state & DOOR_OPEN_2)
3861 BlitBitmap(backbuffer, bitmap_db_door,
3862 VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
3864 door_state &= ~DOOR_NO_COPY_BACK;
3867 return MoveDoor(door_state);
3870 unsigned int GetDoorState()
3872 return MoveDoor(DOOR_GET_STATE);
3875 unsigned int SetDoorState(unsigned int door_state)
3877 return MoveDoor(door_state | DOOR_SET_STATE);
3880 unsigned int MoveDoor(unsigned int door_state)
3882 static int door1 = DOOR_OPEN_1;
3883 static int door2 = DOOR_CLOSE_2;
3884 unsigned long door_delay = 0;
3885 unsigned long door_delay_value;
3888 if (door_1.width < 0 || door_1.width > DXSIZE)
3889 door_1.width = DXSIZE;
3890 if (door_1.height < 0 || door_1.height > DYSIZE)
3891 door_1.height = DYSIZE;
3892 if (door_2.width < 0 || door_2.width > VXSIZE)
3893 door_2.width = VXSIZE;
3894 if (door_2.height < 0 || door_2.height > VYSIZE)
3895 door_2.height = VYSIZE;
3897 if (door_state == DOOR_GET_STATE)
3898 return (door1 | door2);
3900 if (door_state & DOOR_SET_STATE)
3902 if (door_state & DOOR_ACTION_1)
3903 door1 = door_state & DOOR_ACTION_1;
3904 if (door_state & DOOR_ACTION_2)
3905 door2 = door_state & DOOR_ACTION_2;
3907 return (door1 | door2);
3910 if (!(door_state & DOOR_FORCE_REDRAW))
3912 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
3913 door_state &= ~DOOR_OPEN_1;
3914 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
3915 door_state &= ~DOOR_CLOSE_1;
3916 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
3917 door_state &= ~DOOR_OPEN_2;
3918 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
3919 door_state &= ~DOOR_CLOSE_2;
3922 door_delay_value = (door_state & DOOR_ACTION_1 ? door_1.step_delay :
3925 if (setup.quick_doors)
3927 stepsize = 20; /* must be chosen to always draw last frame */
3928 door_delay_value = 0;
3931 if (global.autoplay_leveldir)
3933 door_state |= DOOR_NO_DELAY;
3934 door_state &= ~DOOR_CLOSE_ALL;
3938 if (game_status == GAME_MODE_EDITOR)
3939 door_state |= DOOR_NO_DELAY;
3942 if (door_state & DOOR_ACTION)
3944 boolean handle_door_1 = (door_state & DOOR_ACTION_1);
3945 boolean handle_door_2 = (door_state & DOOR_ACTION_2);
3946 boolean door_1_done = (!handle_door_1);
3947 boolean door_2_done = (!handle_door_2);
3948 boolean door_1_vertical = (door_1.anim_mode & ANIM_VERTICAL);
3949 boolean door_2_vertical = (door_2.anim_mode & ANIM_VERTICAL);
3950 int door_size_1 = (door_1_vertical ? door_1.height : door_1.width);
3951 int door_size_2 = (door_2_vertical ? door_2.height : door_2.width);
3952 int max_door_size_1 = (door_1_vertical ? DYSIZE : DXSIZE);
3953 int max_door_size_2 = (door_2_vertical ? VYSIZE : VXSIZE);
3954 int door_size = (handle_door_1 ? door_size_1 : door_size_2);
3955 int max_door_size = (handle_door_1 ? max_door_size_1 : max_door_size_2);
3956 int door_skip = max_door_size - door_size;
3957 int end = door_size;
3958 int start = ((door_state & DOOR_NO_DELAY) ? end : 0);
3961 if (!(door_state & DOOR_NO_DELAY) && !setup.quick_doors)
3963 /* opening door sound has priority over simultaneously closing door */
3964 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
3965 PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
3966 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
3967 PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
3970 for (k = start; k <= end && !(door_1_done && door_2_done); k += stepsize)
3973 Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
3974 GC gc = bitmap->stored_clip_gc;
3976 if (door_state & DOOR_ACTION_1)
3978 int a = MIN(x * door_1.step_offset, end);
3979 int p = (door_state & DOOR_OPEN_1 ? end - a : a);
3980 int i = p + door_skip;
3982 if (door_1.anim_mode & ANIM_STATIC_PANEL)
3984 BlitBitmap(bitmap_db_door, drawto,
3985 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1,
3986 DXSIZE, DYSIZE, DX, DY);
3990 BlitBitmap(bitmap_db_door, drawto,
3991 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + p / 2,
3992 DXSIZE, DYSIZE - p / 2, DX, DY);
3994 ClearRectangle(drawto, DX, DY + DYSIZE - p / 2, DXSIZE, p / 2);
3997 if (door_1.anim_mode & ANIM_HORIZONTAL && x <= DXSIZE)
3999 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
4000 int dst1_x = DX + DXSIZE - i, dst1_y = DY;
4001 int src2_x = DXSIZE - i, src2_y = DOOR_GFX_PAGEY1;
4002 int dst2_x = DX, dst2_y = DY;
4003 int width = i, height = DYSIZE;
4005 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
4006 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
4009 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
4010 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
4013 else if (door_1.anim_mode & ANIM_VERTICAL && x <= DYSIZE)
4015 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
4016 int dst1_x = DX, dst1_y = DY + DYSIZE - i;
4017 int src2_x = 0, src2_y = DOOR_GFX_PAGEY1 + DYSIZE - i;
4018 int dst2_x = DX, dst2_y = DY;
4019 int width = DXSIZE, height = i;
4021 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
4022 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
4025 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
4026 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
4029 else if (x <= DXSIZE) /* ANIM_DEFAULT */
4031 int j = (door_1.anim_mode == ANIM_DEFAULT ? (DXSIZE - i) / 3 : 0);
4033 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
4034 BlitBitmapMasked(bitmap, drawto,
4035 DXSIZE, DOOR_GFX_PAGEY1, i, 77,
4036 DX + DXSIZE - i, DY + j);
4037 BlitBitmapMasked(bitmap, drawto,
4038 DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
4039 DX + DXSIZE - i, DY + 140 + j);
4040 SetClipOrigin(bitmap, gc, DX - DXSIZE + i,
4041 DY - (DOOR_GFX_PAGEY1 + j));
4042 BlitBitmapMasked(bitmap, drawto,
4043 DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
4045 BlitBitmapMasked(bitmap, drawto,
4046 DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
4049 BlitBitmapMasked(bitmap, drawto,
4050 DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
4052 BlitBitmapMasked(bitmap, drawto,
4053 DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
4055 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
4056 BlitBitmapMasked(bitmap, drawto,
4057 DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
4058 DX + DXSIZE - i, DY + 77 + j);
4059 BlitBitmapMasked(bitmap, drawto,
4060 DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
4061 DX + DXSIZE - i, DY + 203 + j);
4064 redraw_mask |= REDRAW_DOOR_1;
4065 door_1_done = (a == end);
4068 if (door_state & DOOR_ACTION_2)
4070 int a = MIN(x * door_2.step_offset, door_size);
4071 int p = (door_state & DOOR_OPEN_2 ? door_size - a : a);
4072 int i = p + door_skip;
4074 if (door_2.anim_mode & ANIM_STATIC_PANEL)
4076 BlitBitmap(bitmap_db_door, drawto,
4077 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2,
4078 VXSIZE, VYSIZE, VX, VY);
4080 else if (x <= VYSIZE)
4082 BlitBitmap(bitmap_db_door, drawto,
4083 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + p / 2,
4084 VXSIZE, VYSIZE - p / 2, VX, VY);
4086 ClearRectangle(drawto, VX, VY + VYSIZE - p / 2, VXSIZE, p / 2);
4089 if (door_2.anim_mode & ANIM_HORIZONTAL && x <= VXSIZE)
4091 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
4092 int dst1_x = VX + VXSIZE - i, dst1_y = VY;
4093 int src2_x = VXSIZE - i, src2_y = DOOR_GFX_PAGEY2;
4094 int dst2_x = VX, dst2_y = VY;
4095 int width = i, height = VYSIZE;
4097 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
4098 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
4101 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
4102 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
4105 else if (door_2.anim_mode & ANIM_VERTICAL && x <= VYSIZE)
4107 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
4108 int dst1_x = VX, dst1_y = VY + VYSIZE - i;
4109 int src2_x = 0, src2_y = DOOR_GFX_PAGEY2 + VYSIZE - i;
4110 int dst2_x = VX, dst2_y = VY;
4111 int width = VXSIZE, height = i;
4113 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
4114 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
4117 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
4118 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
4121 else if (x <= VXSIZE) /* ANIM_DEFAULT */
4123 int j = (door_2.anim_mode == ANIM_DEFAULT ? (VXSIZE - i) / 3 : 0);
4125 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
4126 BlitBitmapMasked(bitmap, drawto,
4127 VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
4128 VX + VXSIZE - i, VY + j);
4129 SetClipOrigin(bitmap, gc,
4130 VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
4131 BlitBitmapMasked(bitmap, drawto,
4132 VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
4135 BlitBitmapMasked(bitmap, drawto,
4136 VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
4137 i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
4138 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
4139 BlitBitmapMasked(bitmap, drawto,
4140 VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
4142 VX + VXSIZE - i, VY + VYSIZE / 2 + j);
4145 redraw_mask |= REDRAW_DOOR_2;
4146 door_2_done = (a == VXSIZE);
4149 if (!(door_state & DOOR_NO_DELAY))
4153 if (game_status == GAME_MODE_MAIN)
4156 WaitUntilDelayReached(&door_delay, door_delay_value);
4161 if (door_state & DOOR_ACTION_1)
4162 door1 = door_state & DOOR_ACTION_1;
4163 if (door_state & DOOR_ACTION_2)
4164 door2 = door_state & DOOR_ACTION_2;
4166 return (door1 | door2);
4169 void DrawSpecialEditorDoor()
4171 /* draw bigger toolbox window */
4172 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
4173 DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
4175 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
4176 EX - 6, VY - 4, EXSIZE + 12, EYSIZE - VYSIZE + 4,
4179 redraw_mask |= REDRAW_ALL;
4182 void UndrawSpecialEditorDoor()
4184 /* draw normal tape recorder window */
4185 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
4186 EX - 6, EY - 12, EXSIZE + 12, EYSIZE - VYSIZE + 12,
4189 redraw_mask |= REDRAW_ALL;
4193 /* ---------- new tool button stuff ---------------------------------------- */
4195 /* graphic position values for tool buttons */
4196 #define TOOL_BUTTON_YES_XPOS 2
4197 #define TOOL_BUTTON_YES_YPOS 250
4198 #define TOOL_BUTTON_YES_GFX_YPOS 0
4199 #define TOOL_BUTTON_YES_XSIZE 46
4200 #define TOOL_BUTTON_YES_YSIZE 28
4201 #define TOOL_BUTTON_NO_XPOS 52
4202 #define TOOL_BUTTON_NO_YPOS TOOL_BUTTON_YES_YPOS
4203 #define TOOL_BUTTON_NO_GFX_YPOS TOOL_BUTTON_YES_GFX_YPOS
4204 #define TOOL_BUTTON_NO_XSIZE TOOL_BUTTON_YES_XSIZE
4205 #define TOOL_BUTTON_NO_YSIZE TOOL_BUTTON_YES_YSIZE
4206 #define TOOL_BUTTON_CONFIRM_XPOS TOOL_BUTTON_YES_XPOS
4207 #define TOOL_BUTTON_CONFIRM_YPOS TOOL_BUTTON_YES_YPOS
4208 #define TOOL_BUTTON_CONFIRM_GFX_YPOS 30
4209 #define TOOL_BUTTON_CONFIRM_XSIZE 96
4210 #define TOOL_BUTTON_CONFIRM_YSIZE TOOL_BUTTON_YES_YSIZE
4211 #define TOOL_BUTTON_PLAYER_XSIZE 30
4212 #define TOOL_BUTTON_PLAYER_YSIZE 30
4213 #define TOOL_BUTTON_PLAYER_GFX_XPOS 5
4214 #define TOOL_BUTTON_PLAYER_GFX_YPOS 185
4215 #define TOOL_BUTTON_PLAYER_XPOS (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
4216 #define TOOL_BUTTON_PLAYER_YPOS (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
4217 #define TOOL_BUTTON_PLAYER1_XPOS (TOOL_BUTTON_PLAYER_XPOS \
4218 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
4219 #define TOOL_BUTTON_PLAYER2_XPOS (TOOL_BUTTON_PLAYER_XPOS \
4220 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
4221 #define TOOL_BUTTON_PLAYER3_XPOS (TOOL_BUTTON_PLAYER_XPOS \
4222 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
4223 #define TOOL_BUTTON_PLAYER4_XPOS (TOOL_BUTTON_PLAYER_XPOS \
4224 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
4225 #define TOOL_BUTTON_PLAYER1_YPOS (TOOL_BUTTON_PLAYER_YPOS \
4226 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
4227 #define TOOL_BUTTON_PLAYER2_YPOS (TOOL_BUTTON_PLAYER_YPOS \
4228 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
4229 #define TOOL_BUTTON_PLAYER3_YPOS (TOOL_BUTTON_PLAYER_YPOS \
4230 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
4231 #define TOOL_BUTTON_PLAYER4_YPOS (TOOL_BUTTON_PLAYER_YPOS \
4232 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
4241 } toolbutton_info[NUM_TOOL_BUTTONS] =
4244 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_GFX_YPOS,
4245 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_YPOS,
4246 TOOL_BUTTON_YES_XSIZE, TOOL_BUTTON_YES_YSIZE,
4251 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_GFX_YPOS,
4252 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_YPOS,
4253 TOOL_BUTTON_NO_XSIZE, TOOL_BUTTON_NO_YSIZE,
4258 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_GFX_YPOS,
4259 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_YPOS,
4260 TOOL_BUTTON_CONFIRM_XSIZE, TOOL_BUTTON_CONFIRM_YSIZE,
4261 TOOL_CTRL_ID_CONFIRM,
4265 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
4266 TOOL_BUTTON_PLAYER1_XPOS, TOOL_BUTTON_PLAYER1_YPOS,
4267 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
4268 TOOL_CTRL_ID_PLAYER_1,
4272 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
4273 TOOL_BUTTON_PLAYER2_XPOS, TOOL_BUTTON_PLAYER2_YPOS,
4274 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
4275 TOOL_CTRL_ID_PLAYER_2,
4279 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
4280 TOOL_BUTTON_PLAYER3_XPOS, TOOL_BUTTON_PLAYER3_YPOS,
4281 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
4282 TOOL_CTRL_ID_PLAYER_3,
4286 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
4287 TOOL_BUTTON_PLAYER4_XPOS, TOOL_BUTTON_PLAYER4_YPOS,
4288 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
4289 TOOL_CTRL_ID_PLAYER_4,
4294 void CreateToolButtons()
4298 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4300 Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
4301 Bitmap *deco_bitmap = None;
4302 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
4303 struct GadgetInfo *gi;
4304 unsigned long event_mask;
4305 int gd_xoffset, gd_yoffset;
4306 int gd_x1, gd_x2, gd_y;
4309 event_mask = GD_EVENT_RELEASED;
4311 gd_xoffset = toolbutton_info[i].xpos;
4312 gd_yoffset = toolbutton_info[i].ypos;
4313 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
4314 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
4315 gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
4317 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
4319 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
4321 getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr),
4322 &deco_bitmap, &deco_x, &deco_y);
4323 deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
4324 deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
4327 gi = CreateGadget(GDI_CUSTOM_ID, id,
4328 GDI_INFO_TEXT, toolbutton_info[i].infotext,
4329 GDI_X, DX + toolbutton_info[i].x,
4330 GDI_Y, DY + toolbutton_info[i].y,
4331 GDI_WIDTH, toolbutton_info[i].width,
4332 GDI_HEIGHT, toolbutton_info[i].height,
4333 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
4334 GDI_STATE, GD_BUTTON_UNPRESSED,
4335 GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
4336 GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
4337 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
4338 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
4339 GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
4340 GDI_DECORATION_SHIFTING, 1, 1,
4341 GDI_DIRECT_DRAW, FALSE,
4342 GDI_EVENT_MASK, event_mask,
4343 GDI_CALLBACK_ACTION, HandleToolButtons,
4347 Error(ERR_EXIT, "cannot create gadget");
4349 tool_gadget[id] = gi;
4353 void FreeToolButtons()
4357 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4358 FreeGadget(tool_gadget[i]);
4361 static void UnmapToolButtons()
4365 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4366 UnmapGadget(tool_gadget[i]);
4369 static void HandleToolButtons(struct GadgetInfo *gi)
4371 request_gadget_id = gi->custom_id;
4374 static struct Mapping_EM_to_RND_object
4377 boolean is_rnd_to_em_mapping; /* unique mapping EM <-> RND */
4378 boolean is_backside; /* backside of moving element */
4384 em_object_mapping_list[] =
4387 Xblank, TRUE, FALSE,
4391 Yacid_splash_eB, FALSE, FALSE,
4392 EL_ACID_SPLASH_RIGHT, -1, -1
4395 Yacid_splash_wB, FALSE, FALSE,
4396 EL_ACID_SPLASH_LEFT, -1, -1
4399 #ifdef EM_ENGINE_BAD_ROLL
4401 Xstone_force_e, FALSE, FALSE,
4402 EL_ROCK, -1, MV_BIT_RIGHT
4405 Xstone_force_w, FALSE, FALSE,
4406 EL_ROCK, -1, MV_BIT_LEFT
4409 Xnut_force_e, FALSE, FALSE,
4410 EL_NUT, -1, MV_BIT_RIGHT
4413 Xnut_force_w, FALSE, FALSE,
4414 EL_NUT, -1, MV_BIT_LEFT
4417 Xspring_force_e, FALSE, FALSE,
4418 EL_SPRING, -1, MV_BIT_RIGHT
4421 Xspring_force_w, FALSE, FALSE,
4422 EL_SPRING, -1, MV_BIT_LEFT
4425 Xemerald_force_e, FALSE, FALSE,
4426 EL_EMERALD, -1, MV_BIT_RIGHT
4429 Xemerald_force_w, FALSE, FALSE,
4430 EL_EMERALD, -1, MV_BIT_LEFT
4433 Xdiamond_force_e, FALSE, FALSE,
4434 EL_DIAMOND, -1, MV_BIT_RIGHT
4437 Xdiamond_force_w, FALSE, FALSE,
4438 EL_DIAMOND, -1, MV_BIT_LEFT
4441 Xbomb_force_e, FALSE, FALSE,
4442 EL_BOMB, -1, MV_BIT_RIGHT
4445 Xbomb_force_w, FALSE, FALSE,
4446 EL_BOMB, -1, MV_BIT_LEFT
4448 #endif /* EM_ENGINE_BAD_ROLL */
4451 Xstone, TRUE, FALSE,
4455 Xstone_pause, FALSE, FALSE,
4459 Xstone_fall, FALSE, FALSE,
4463 Ystone_s, FALSE, FALSE,
4464 EL_ROCK, ACTION_FALLING, -1
4467 Ystone_sB, FALSE, TRUE,
4468 EL_ROCK, ACTION_FALLING, -1
4471 Ystone_e, FALSE, FALSE,
4472 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
4475 Ystone_eB, FALSE, TRUE,
4476 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
4479 Ystone_w, FALSE, FALSE,
4480 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
4483 Ystone_wB, FALSE, TRUE,
4484 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
4491 Xnut_pause, FALSE, FALSE,
4495 Xnut_fall, FALSE, FALSE,
4499 Ynut_s, FALSE, FALSE,
4500 EL_NUT, ACTION_FALLING, -1
4503 Ynut_sB, FALSE, TRUE,
4504 EL_NUT, ACTION_FALLING, -1
4507 Ynut_e, FALSE, FALSE,
4508 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
4511 Ynut_eB, FALSE, TRUE,
4512 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
4515 Ynut_w, FALSE, FALSE,
4516 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
4519 Ynut_wB, FALSE, TRUE,
4520 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
4523 Xbug_n, TRUE, FALSE,
4527 Xbug_e, TRUE, FALSE,
4528 EL_BUG_RIGHT, -1, -1
4531 Xbug_s, TRUE, FALSE,
4535 Xbug_w, TRUE, FALSE,
4539 Xbug_gon, FALSE, FALSE,
4543 Xbug_goe, FALSE, FALSE,
4544 EL_BUG_RIGHT, -1, -1
4547 Xbug_gos, FALSE, FALSE,
4551 Xbug_gow, FALSE, FALSE,
4555 Ybug_n, FALSE, FALSE,
4556 EL_BUG, ACTION_MOVING, MV_BIT_UP
4559 Ybug_nB, FALSE, TRUE,
4560 EL_BUG, ACTION_MOVING, MV_BIT_UP
4563 Ybug_e, FALSE, FALSE,
4564 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
4567 Ybug_eB, FALSE, TRUE,
4568 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
4571 Ybug_s, FALSE, FALSE,
4572 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
4575 Ybug_sB, FALSE, TRUE,
4576 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
4579 Ybug_w, FALSE, FALSE,
4580 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
4583 Ybug_wB, FALSE, TRUE,
4584 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
4587 Ybug_w_n, FALSE, FALSE,
4588 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
4591 Ybug_n_e, FALSE, FALSE,
4592 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
4595 Ybug_e_s, FALSE, FALSE,
4596 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
4599 Ybug_s_w, FALSE, FALSE,
4600 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
4603 Ybug_e_n, FALSE, FALSE,
4604 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
4607 Ybug_s_e, FALSE, FALSE,
4608 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
4611 Ybug_w_s, FALSE, FALSE,
4612 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
4615 Ybug_n_w, FALSE, FALSE,
4616 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
4619 Ybug_stone, FALSE, FALSE,
4620 EL_BUG, ACTION_SMASHED_BY_ROCK, -1
4623 Ybug_spring, FALSE, FALSE,
4624 EL_BUG, ACTION_SMASHED_BY_SPRING, -1
4627 Xtank_n, TRUE, FALSE,
4628 EL_SPACESHIP_UP, -1, -1
4631 Xtank_e, TRUE, FALSE,
4632 EL_SPACESHIP_RIGHT, -1, -1
4635 Xtank_s, TRUE, FALSE,
4636 EL_SPACESHIP_DOWN, -1, -1
4639 Xtank_w, TRUE, FALSE,
4640 EL_SPACESHIP_LEFT, -1, -1
4643 Xtank_gon, FALSE, FALSE,
4644 EL_SPACESHIP_UP, -1, -1
4647 Xtank_goe, FALSE, FALSE,
4648 EL_SPACESHIP_RIGHT, -1, -1
4651 Xtank_gos, FALSE, FALSE,
4652 EL_SPACESHIP_DOWN, -1, -1
4655 Xtank_gow, FALSE, FALSE,
4656 EL_SPACESHIP_LEFT, -1, -1
4659 Ytank_n, FALSE, FALSE,
4660 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
4663 Ytank_nB, FALSE, TRUE,
4664 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
4667 Ytank_e, FALSE, FALSE,
4668 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
4671 Ytank_eB, FALSE, TRUE,
4672 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
4675 Ytank_s, FALSE, FALSE,
4676 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
4679 Ytank_sB, FALSE, TRUE,
4680 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
4683 Ytank_w, FALSE, FALSE,
4684 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
4687 Ytank_wB, FALSE, TRUE,
4688 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
4691 Ytank_w_n, FALSE, FALSE,
4692 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
4695 Ytank_n_e, FALSE, FALSE,
4696 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
4699 Ytank_e_s, FALSE, FALSE,
4700 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
4703 Ytank_s_w, FALSE, FALSE,
4704 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
4707 Ytank_e_n, FALSE, FALSE,
4708 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
4711 Ytank_s_e, FALSE, FALSE,
4712 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
4715 Ytank_w_s, FALSE, FALSE,
4716 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
4719 Ytank_n_w, FALSE, FALSE,
4720 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
4723 Ytank_stone, FALSE, FALSE,
4724 EL_SPACESHIP, ACTION_SMASHED_BY_ROCK, -1
4727 Ytank_spring, FALSE, FALSE,
4728 EL_SPACESHIP, ACTION_SMASHED_BY_SPRING, -1
4731 Xandroid, TRUE, FALSE,
4732 EL_EMC_ANDROID, ACTION_ACTIVE, -1
4735 Xandroid_1_n, FALSE, FALSE,
4736 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
4739 Xandroid_2_n, FALSE, FALSE,
4740 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
4743 Xandroid_1_e, FALSE, FALSE,
4744 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
4747 Xandroid_2_e, FALSE, FALSE,
4748 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
4751 Xandroid_1_w, FALSE, FALSE,
4752 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
4755 Xandroid_2_w, FALSE, FALSE,
4756 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
4759 Xandroid_1_s, FALSE, FALSE,
4760 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
4763 Xandroid_2_s, FALSE, FALSE,
4764 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
4767 Yandroid_n, FALSE, FALSE,
4768 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
4771 Yandroid_nB, FALSE, TRUE,
4772 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
4775 Yandroid_ne, FALSE, FALSE,
4776 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPRIGHT
4779 Yandroid_neB, FALSE, TRUE,
4780 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPRIGHT
4783 Yandroid_e, FALSE, FALSE,
4784 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
4787 Yandroid_eB, FALSE, TRUE,
4788 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
4791 Yandroid_se, FALSE, FALSE,
4792 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNRIGHT
4795 Yandroid_seB, FALSE, TRUE,
4796 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNRIGHT
4799 Yandroid_s, FALSE, FALSE,
4800 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
4803 Yandroid_sB, FALSE, TRUE,
4804 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
4807 Yandroid_sw, FALSE, FALSE,
4808 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNLEFT
4811 Yandroid_swB, FALSE, TRUE,
4812 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNLEFT
4815 Yandroid_w, FALSE, FALSE,
4816 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
4819 Yandroid_wB, FALSE, TRUE,
4820 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
4823 Yandroid_nw, FALSE, FALSE,
4824 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPLEFT
4827 Yandroid_nwB, FALSE, TRUE,
4828 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPLEFT
4831 Xspring, TRUE, FALSE,
4835 Xspring_pause, FALSE, FALSE,
4839 Xspring_e, FALSE, FALSE,
4843 Xspring_w, FALSE, FALSE,
4847 Xspring_fall, FALSE, FALSE,
4851 Yspring_s, FALSE, FALSE,
4852 EL_SPRING, ACTION_FALLING, -1
4855 Yspring_sB, FALSE, TRUE,
4856 EL_SPRING, ACTION_FALLING, -1
4859 Yspring_e, FALSE, FALSE,
4860 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
4863 Yspring_eB, FALSE, TRUE,
4864 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
4867 Yspring_w, FALSE, FALSE,
4868 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
4871 Yspring_wB, FALSE, TRUE,
4872 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
4875 Yspring_kill_e, FALSE, FALSE,
4876 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
4879 Yspring_kill_eB, FALSE, TRUE,
4880 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
4883 Yspring_kill_w, FALSE, FALSE,
4884 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
4887 Yspring_kill_wB, FALSE, TRUE,
4888 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
4891 Xeater_n, TRUE, FALSE,
4892 EL_YAMYAM_UP, -1, -1
4895 Xeater_e, TRUE, FALSE,
4896 EL_YAMYAM_RIGHT, -1, -1
4899 Xeater_w, TRUE, FALSE,
4900 EL_YAMYAM_LEFT, -1, -1
4903 Xeater_s, TRUE, FALSE,
4904 EL_YAMYAM_DOWN, -1, -1
4907 Yeater_n, FALSE, FALSE,
4908 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
4911 Yeater_nB, FALSE, TRUE,
4912 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
4915 Yeater_e, FALSE, FALSE,
4916 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
4919 Yeater_eB, FALSE, TRUE,
4920 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
4923 Yeater_s, FALSE, FALSE,
4924 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
4927 Yeater_sB, FALSE, TRUE,
4928 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
4931 Yeater_w, FALSE, FALSE,
4932 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
4935 Yeater_wB, FALSE, TRUE,
4936 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
4939 Yeater_stone, FALSE, FALSE,
4940 EL_YAMYAM, ACTION_SMASHED_BY_ROCK, -1
4943 Yeater_spring, FALSE, FALSE,
4944 EL_YAMYAM, ACTION_SMASHED_BY_SPRING, -1
4947 Xalien, TRUE, FALSE,
4951 Xalien_pause, FALSE, FALSE,
4955 Yalien_n, FALSE, FALSE,
4956 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
4959 Yalien_nB, FALSE, TRUE,
4960 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
4963 Yalien_e, FALSE, FALSE,
4964 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
4967 Yalien_eB, FALSE, TRUE,
4968 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
4971 Yalien_s, FALSE, FALSE,
4972 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
4975 Yalien_sB, FALSE, TRUE,
4976 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
4979 Yalien_w, FALSE, FALSE,
4980 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
4983 Yalien_wB, FALSE, TRUE,
4984 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
4987 Yalien_stone, FALSE, FALSE,
4988 EL_ROBOT, ACTION_SMASHED_BY_ROCK, -1
4991 Yalien_spring, FALSE, FALSE,
4992 EL_ROBOT, ACTION_SMASHED_BY_SPRING, -1
4995 Xemerald, TRUE, FALSE,
4999 Xemerald_pause, FALSE, FALSE,
5003 Xemerald_fall, FALSE, FALSE,
5007 Xemerald_shine, FALSE, FALSE,
5008 EL_EMERALD, ACTION_TWINKLING, -1
5011 Yemerald_s, FALSE, FALSE,
5012 EL_EMERALD, ACTION_FALLING, -1
5015 Yemerald_sB, FALSE, TRUE,
5016 EL_EMERALD, ACTION_FALLING, -1
5019 Yemerald_e, FALSE, FALSE,
5020 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
5023 Yemerald_eB, FALSE, TRUE,
5024 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
5027 Yemerald_w, FALSE, FALSE,
5028 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
5031 Yemerald_wB, FALSE, TRUE,
5032 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
5035 Yemerald_eat, FALSE, FALSE,
5036 EL_EMERALD, ACTION_COLLECTING, -1
5039 Yemerald_stone, FALSE, FALSE,
5040 EL_NUT, ACTION_BREAKING, -1
5043 Xdiamond, TRUE, FALSE,
5047 Xdiamond_pause, FALSE, FALSE,
5051 Xdiamond_fall, FALSE, FALSE,
5055 Xdiamond_shine, FALSE, FALSE,
5056 EL_DIAMOND, ACTION_TWINKLING, -1
5059 Ydiamond_s, FALSE, FALSE,
5060 EL_DIAMOND, ACTION_FALLING, -1
5063 Ydiamond_sB, FALSE, TRUE,
5064 EL_DIAMOND, ACTION_FALLING, -1
5067 Ydiamond_e, FALSE, FALSE,
5068 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
5071 Ydiamond_eB, FALSE, TRUE,
5072 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
5075 Ydiamond_w, FALSE, FALSE,
5076 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
5079 Ydiamond_wB, FALSE, TRUE,
5080 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
5083 Ydiamond_eat, FALSE, FALSE,
5084 EL_DIAMOND, ACTION_COLLECTING, -1
5087 Ydiamond_stone, FALSE, FALSE,
5088 EL_DIAMOND, ACTION_SMASHED_BY_ROCK, -1
5091 Xdrip_fall, TRUE, FALSE,
5092 EL_AMOEBA_DROP, -1, -1
5095 Xdrip_stretch, FALSE, FALSE,
5096 EL_AMOEBA_DROP, ACTION_FALLING, -1
5099 Xdrip_stretchB, FALSE, TRUE,
5100 EL_AMOEBA_DROP, ACTION_FALLING, -1
5103 Xdrip_eat, FALSE, FALSE,
5104 EL_AMOEBA_DROP, ACTION_GROWING, -1
5107 Ydrip_s1, FALSE, FALSE,
5108 EL_AMOEBA_DROP, ACTION_FALLING, -1
5111 Ydrip_s1B, FALSE, TRUE,
5112 EL_AMOEBA_DROP, ACTION_FALLING, -1
5115 Ydrip_s2, FALSE, FALSE,
5116 EL_AMOEBA_DROP, ACTION_FALLING, -1
5119 Ydrip_s2B, FALSE, TRUE,
5120 EL_AMOEBA_DROP, ACTION_FALLING, -1
5127 Xbomb_pause, FALSE, FALSE,
5131 Xbomb_fall, FALSE, FALSE,
5135 Ybomb_s, FALSE, FALSE,
5136 EL_BOMB, ACTION_FALLING, -1
5139 Ybomb_sB, FALSE, TRUE,
5140 EL_BOMB, ACTION_FALLING, -1
5143 Ybomb_e, FALSE, FALSE,
5144 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
5147 Ybomb_eB, FALSE, TRUE,
5148 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
5151 Ybomb_w, FALSE, FALSE,
5152 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
5155 Ybomb_wB, FALSE, TRUE,
5156 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
5159 Ybomb_eat, FALSE, FALSE,
5160 EL_BOMB, ACTION_ACTIVATING, -1
5163 Xballoon, TRUE, FALSE,
5167 Yballoon_n, FALSE, FALSE,
5168 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
5171 Yballoon_nB, FALSE, TRUE,
5172 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
5175 Yballoon_e, FALSE, FALSE,
5176 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
5179 Yballoon_eB, FALSE, TRUE,
5180 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
5183 Yballoon_s, FALSE, FALSE,
5184 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
5187 Yballoon_sB, FALSE, TRUE,
5188 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
5191 Yballoon_w, FALSE, FALSE,
5192 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
5195 Yballoon_wB, FALSE, TRUE,
5196 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
5199 Xgrass, TRUE, FALSE,
5200 EL_EMC_GRASS, -1, -1
5203 Ygrass_nB, FALSE, FALSE,
5204 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_UP
5207 Ygrass_eB, FALSE, FALSE,
5208 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_RIGHT
5211 Ygrass_sB, FALSE, FALSE,
5212 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_DOWN
5215 Ygrass_wB, FALSE, FALSE,
5216 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_LEFT
5223 Ydirt_nB, FALSE, FALSE,
5224 EL_SAND, ACTION_DIGGING, MV_BIT_UP
5227 Ydirt_eB, FALSE, FALSE,
5228 EL_SAND, ACTION_DIGGING, MV_BIT_RIGHT
5231 Ydirt_sB, FALSE, FALSE,
5232 EL_SAND, ACTION_DIGGING, MV_BIT_DOWN
5235 Ydirt_wB, FALSE, FALSE,
5236 EL_SAND, ACTION_DIGGING, MV_BIT_LEFT
5239 Xacid_ne, TRUE, FALSE,
5240 EL_ACID_POOL_TOPRIGHT, -1, -1
5243 Xacid_se, TRUE, FALSE,
5244 EL_ACID_POOL_BOTTOMRIGHT, -1, -1
5247 Xacid_s, TRUE, FALSE,
5248 EL_ACID_POOL_BOTTOM, -1, -1
5251 Xacid_sw, TRUE, FALSE,
5252 EL_ACID_POOL_BOTTOMLEFT, -1, -1
5255 Xacid_nw, TRUE, FALSE,
5256 EL_ACID_POOL_TOPLEFT, -1, -1
5259 Xacid_1, TRUE, FALSE,
5263 Xacid_2, FALSE, FALSE,
5267 Xacid_3, FALSE, FALSE,
5271 Xacid_4, FALSE, FALSE,
5275 Xacid_5, FALSE, FALSE,
5279 Xacid_6, FALSE, FALSE,
5283 Xacid_7, FALSE, FALSE,
5287 Xacid_8, FALSE, FALSE,
5291 Xball_1, TRUE, FALSE,
5292 EL_EMC_MAGIC_BALL, -1, -1
5295 Xball_1B, FALSE, FALSE,
5296 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
5299 Xball_2, FALSE, FALSE,
5300 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
5303 Xball_2B, FALSE, FALSE,
5304 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
5307 Yball_eat, FALSE, FALSE,
5308 EL_EMC_MAGIC_BALL, ACTION_DROPPING, -1
5311 Ykey_1_eat, FALSE, FALSE,
5312 EL_EM_KEY_1, ACTION_COLLECTING, -1
5315 Ykey_2_eat, FALSE, FALSE,
5316 EL_EM_KEY_2, ACTION_COLLECTING, -1
5319 Ykey_3_eat, FALSE, FALSE,
5320 EL_EM_KEY_3, ACTION_COLLECTING, -1
5323 Ykey_4_eat, FALSE, FALSE,
5324 EL_EM_KEY_4, ACTION_COLLECTING, -1
5327 Ykey_5_eat, FALSE, FALSE,
5328 EL_EMC_KEY_5, ACTION_COLLECTING, -1
5331 Ykey_6_eat, FALSE, FALSE,
5332 EL_EMC_KEY_6, ACTION_COLLECTING, -1
5335 Ykey_7_eat, FALSE, FALSE,
5336 EL_EMC_KEY_7, ACTION_COLLECTING, -1
5339 Ykey_8_eat, FALSE, FALSE,
5340 EL_EMC_KEY_8, ACTION_COLLECTING, -1
5343 Ylenses_eat, FALSE, FALSE,
5344 EL_EMC_LENSES, ACTION_COLLECTING, -1
5347 Ymagnify_eat, FALSE, FALSE,
5348 EL_EMC_MAGNIFIER, ACTION_COLLECTING, -1
5351 Ygrass_eat, FALSE, FALSE,
5352 EL_EMC_GRASS, ACTION_SNAPPING, -1
5355 Ydirt_eat, FALSE, FALSE,
5356 EL_SAND, ACTION_SNAPPING, -1
5359 Xgrow_ns, TRUE, FALSE,
5360 EL_EXPANDABLE_WALL_VERTICAL, -1, -1
5363 Ygrow_ns_eat, FALSE, FALSE,
5364 EL_EXPANDABLE_WALL_VERTICAL, ACTION_GROWING, -1
5367 Xgrow_ew, TRUE, FALSE,
5368 EL_EXPANDABLE_WALL_HORIZONTAL, -1, -1
5371 Ygrow_ew_eat, FALSE, FALSE,
5372 EL_EXPANDABLE_WALL_HORIZONTAL, ACTION_GROWING, -1
5375 Xwonderwall, TRUE, FALSE,
5376 EL_MAGIC_WALL, -1, -1
5379 XwonderwallB, FALSE, FALSE,
5380 EL_MAGIC_WALL, ACTION_ACTIVE, -1
5383 Xamoeba_1, TRUE, FALSE,
5384 EL_AMOEBA_DRY, ACTION_OTHER, -1
5387 Xamoeba_2, FALSE, FALSE,
5388 EL_AMOEBA_DRY, ACTION_OTHER, -1
5391 Xamoeba_3, FALSE, FALSE,
5392 EL_AMOEBA_DRY, ACTION_OTHER, -1
5395 Xamoeba_4, FALSE, FALSE,
5396 EL_AMOEBA_DRY, ACTION_OTHER, -1
5399 Xamoeba_5, TRUE, FALSE,
5400 EL_AMOEBA_WET, ACTION_OTHER, -1
5403 Xamoeba_6, FALSE, FALSE,
5404 EL_AMOEBA_WET, ACTION_OTHER, -1
5407 Xamoeba_7, FALSE, FALSE,
5408 EL_AMOEBA_WET, ACTION_OTHER, -1
5411 Xamoeba_8, FALSE, FALSE,
5412 EL_AMOEBA_WET, ACTION_OTHER, -1
5415 Xdoor_1, TRUE, FALSE,
5416 EL_EM_GATE_1, -1, -1
5419 Xdoor_2, TRUE, FALSE,
5420 EL_EM_GATE_2, -1, -1
5423 Xdoor_3, TRUE, FALSE,
5424 EL_EM_GATE_3, -1, -1
5427 Xdoor_4, TRUE, FALSE,
5428 EL_EM_GATE_4, -1, -1
5431 Xdoor_5, TRUE, FALSE,
5432 EL_EMC_GATE_5, -1, -1
5435 Xdoor_6, TRUE, FALSE,
5436 EL_EMC_GATE_6, -1, -1
5439 Xdoor_7, TRUE, FALSE,
5440 EL_EMC_GATE_7, -1, -1
5443 Xdoor_8, TRUE, FALSE,
5444 EL_EMC_GATE_8, -1, -1
5447 Xkey_1, TRUE, FALSE,
5451 Xkey_2, TRUE, FALSE,
5455 Xkey_3, TRUE, FALSE,
5459 Xkey_4, TRUE, FALSE,
5463 Xkey_5, TRUE, FALSE,
5464 EL_EMC_KEY_5, -1, -1
5467 Xkey_6, TRUE, FALSE,
5468 EL_EMC_KEY_6, -1, -1
5471 Xkey_7, TRUE, FALSE,
5472 EL_EMC_KEY_7, -1, -1
5475 Xkey_8, TRUE, FALSE,
5476 EL_EMC_KEY_8, -1, -1
5479 Xwind_n, TRUE, FALSE,
5480 EL_BALLOON_SWITCH_UP, -1, -1
5483 Xwind_e, TRUE, FALSE,
5484 EL_BALLOON_SWITCH_RIGHT, -1, -1
5487 Xwind_s, TRUE, FALSE,
5488 EL_BALLOON_SWITCH_DOWN, -1, -1
5491 Xwind_w, TRUE, FALSE,
5492 EL_BALLOON_SWITCH_LEFT, -1, -1
5495 Xwind_nesw, TRUE, FALSE,
5496 EL_BALLOON_SWITCH_ANY, -1, -1
5499 Xwind_stop, TRUE, FALSE,
5500 EL_BALLOON_SWITCH_NONE, -1, -1
5504 EL_EM_EXIT_CLOSED, -1, -1
5507 Xexit_1, TRUE, FALSE,
5508 EL_EM_EXIT_OPEN, -1, -1
5511 Xexit_2, FALSE, FALSE,
5512 EL_EM_EXIT_OPEN, -1, -1
5515 Xexit_3, FALSE, FALSE,
5516 EL_EM_EXIT_OPEN, -1, -1
5519 Xdynamite, TRUE, FALSE,
5520 EL_EM_DYNAMITE, -1, -1
5523 Ydynamite_eat, FALSE, FALSE,
5524 EL_EM_DYNAMITE, ACTION_COLLECTING, -1
5527 Xdynamite_1, TRUE, FALSE,
5528 EL_EM_DYNAMITE_ACTIVE, -1, -1
5531 Xdynamite_2, FALSE, FALSE,
5532 EL_EM_DYNAMITE_ACTIVE, -1, -1
5535 Xdynamite_3, FALSE, FALSE,
5536 EL_EM_DYNAMITE_ACTIVE, -1, -1
5539 Xdynamite_4, FALSE, FALSE,
5540 EL_EM_DYNAMITE_ACTIVE, -1, -1
5543 Xbumper, TRUE, FALSE,
5544 EL_EMC_SPRING_BUMPER, -1, -1
5547 XbumperB, FALSE, FALSE,
5548 EL_EMC_SPRING_BUMPER, ACTION_ACTIVE, -1
5551 Xwheel, TRUE, FALSE,
5552 EL_ROBOT_WHEEL, -1, -1
5555 XwheelB, FALSE, FALSE,
5556 EL_ROBOT_WHEEL, ACTION_ACTIVE, -1
5559 Xswitch, TRUE, FALSE,
5560 EL_EMC_MAGIC_BALL_SWITCH, -1, -1
5563 XswitchB, FALSE, FALSE,
5564 EL_EMC_MAGIC_BALL_SWITCH, ACTION_ACTIVE, -1
5568 EL_QUICKSAND_EMPTY, -1, -1
5571 Xsand_stone, TRUE, FALSE,
5572 EL_QUICKSAND_FULL, -1, -1
5575 Xsand_stonein_1, FALSE, TRUE,
5576 EL_ROCK, ACTION_FILLING, -1
5579 Xsand_stonein_2, FALSE, TRUE,
5580 EL_ROCK, ACTION_FILLING, -1
5583 Xsand_stonein_3, FALSE, TRUE,
5584 EL_ROCK, ACTION_FILLING, -1
5587 Xsand_stonein_4, FALSE, TRUE,
5588 EL_ROCK, ACTION_FILLING, -1
5592 Xsand_stonesand_1, FALSE, FALSE,
5593 EL_QUICKSAND_EMPTYING, -1, -1
5596 Xsand_stonesand_2, FALSE, FALSE,
5597 EL_QUICKSAND_EMPTYING, -1, -1
5600 Xsand_stonesand_3, FALSE, FALSE,
5601 EL_QUICKSAND_EMPTYING, -1, -1
5604 Xsand_stonesand_4, FALSE, FALSE,
5605 EL_QUICKSAND_EMPTYING, -1, -1
5608 Xsand_stonesand_quickout_1, FALSE, FALSE,
5609 EL_QUICKSAND_EMPTYING, -1, -1
5612 Xsand_stonesand_quickout_2, FALSE, FALSE,
5613 EL_QUICKSAND_EMPTYING, -1, -1
5617 Xsand_stonesand_1, FALSE, FALSE,
5618 EL_QUICKSAND_FULL, -1, -1
5621 Xsand_stonesand_2, FALSE, FALSE,
5622 EL_QUICKSAND_FULL, -1, -1
5625 Xsand_stonesand_3, FALSE, FALSE,
5626 EL_QUICKSAND_FULL, -1, -1
5629 Xsand_stonesand_4, FALSE, FALSE,
5630 EL_QUICKSAND_FULL, -1, -1
5634 Xsand_stoneout_1, FALSE, FALSE,
5635 EL_ROCK, ACTION_EMPTYING, -1
5638 Xsand_stoneout_2, FALSE, FALSE,
5639 EL_ROCK, ACTION_EMPTYING, -1
5643 Xsand_sandstone_1, FALSE, FALSE,
5644 EL_QUICKSAND_FILLING, -1, -1
5647 Xsand_sandstone_2, FALSE, FALSE,
5648 EL_QUICKSAND_FILLING, -1, -1
5651 Xsand_sandstone_3, FALSE, FALSE,
5652 EL_QUICKSAND_FILLING, -1, -1
5655 Xsand_sandstone_4, FALSE, FALSE,
5656 EL_QUICKSAND_FILLING, -1, -1
5660 Xsand_sandstone_1, FALSE, FALSE,
5661 EL_QUICKSAND_FULL, -1, -1
5664 Xsand_sandstone_2, FALSE, FALSE,
5665 EL_QUICKSAND_FULL, -1, -1
5668 Xsand_sandstone_3, FALSE, FALSE,
5669 EL_QUICKSAND_FULL, -1, -1
5672 Xsand_sandstone_4, FALSE, FALSE,
5673 EL_QUICKSAND_FULL, -1, -1
5677 Xplant, TRUE, FALSE,
5678 EL_EMC_PLANT, -1, -1
5681 Yplant, FALSE, FALSE,
5682 EL_EMC_PLANT, -1, -1
5685 Xlenses, TRUE, FALSE,
5686 EL_EMC_LENSES, -1, -1
5689 Xmagnify, TRUE, FALSE,
5690 EL_EMC_MAGNIFIER, -1, -1
5693 Xdripper, TRUE, FALSE,
5694 EL_EMC_DRIPPER, -1, -1
5697 XdripperB, FALSE, FALSE,
5698 EL_EMC_DRIPPER, ACTION_ACTIVE, -1
5701 Xfake_blank, TRUE, FALSE,
5702 EL_INVISIBLE_WALL, -1, -1
5705 Xfake_blankB, FALSE, FALSE,
5706 EL_INVISIBLE_WALL, ACTION_ACTIVE, -1
5709 Xfake_grass, TRUE, FALSE,
5710 EL_EMC_FAKE_GRASS, -1, -1
5713 Xfake_grassB, FALSE, FALSE,
5714 EL_EMC_FAKE_GRASS, ACTION_ACTIVE, -1
5717 Xfake_door_1, TRUE, FALSE,
5718 EL_EM_GATE_1_GRAY, -1, -1
5721 Xfake_door_2, TRUE, FALSE,
5722 EL_EM_GATE_2_GRAY, -1, -1
5725 Xfake_door_3, TRUE, FALSE,
5726 EL_EM_GATE_3_GRAY, -1, -1
5729 Xfake_door_4, TRUE, FALSE,
5730 EL_EM_GATE_4_GRAY, -1, -1
5733 Xfake_door_5, TRUE, FALSE,
5734 EL_EMC_GATE_5_GRAY, -1, -1
5737 Xfake_door_6, TRUE, FALSE,
5738 EL_EMC_GATE_6_GRAY, -1, -1
5741 Xfake_door_7, TRUE, FALSE,
5742 EL_EMC_GATE_7_GRAY, -1, -1
5745 Xfake_door_8, TRUE, FALSE,
5746 EL_EMC_GATE_8_GRAY, -1, -1
5749 Xfake_acid_1, TRUE, FALSE,
5750 EL_EMC_FAKE_ACID, -1, -1
5753 Xfake_acid_2, FALSE, FALSE,
5754 EL_EMC_FAKE_ACID, -1, -1
5757 Xfake_acid_3, FALSE, FALSE,
5758 EL_EMC_FAKE_ACID, -1, -1
5761 Xfake_acid_4, FALSE, FALSE,
5762 EL_EMC_FAKE_ACID, -1, -1
5765 Xfake_acid_5, FALSE, FALSE,
5766 EL_EMC_FAKE_ACID, -1, -1
5769 Xfake_acid_6, FALSE, FALSE,
5770 EL_EMC_FAKE_ACID, -1, -1
5773 Xfake_acid_7, FALSE, FALSE,
5774 EL_EMC_FAKE_ACID, -1, -1
5777 Xfake_acid_8, FALSE, FALSE,
5778 EL_EMC_FAKE_ACID, -1, -1
5781 Xsteel_1, TRUE, FALSE,
5782 EL_STEELWALL, -1, -1
5785 Xsteel_2, TRUE, FALSE,
5786 EL_EMC_STEELWALL_2, -1, -1
5789 Xsteel_3, TRUE, FALSE,
5790 EL_EMC_STEELWALL_3, -1, -1
5793 Xsteel_4, TRUE, FALSE,
5794 EL_EMC_STEELWALL_4, -1, -1
5797 Xwall_1, TRUE, FALSE,
5801 Xwall_2, TRUE, FALSE,
5802 EL_EMC_WALL_14, -1, -1
5805 Xwall_3, TRUE, FALSE,
5806 EL_EMC_WALL_15, -1, -1
5809 Xwall_4, TRUE, FALSE,
5810 EL_EMC_WALL_16, -1, -1
5813 Xround_wall_1, TRUE, FALSE,
5814 EL_WALL_SLIPPERY, -1, -1
5817 Xround_wall_2, TRUE, FALSE,
5818 EL_EMC_WALL_SLIPPERY_2, -1, -1
5821 Xround_wall_3, TRUE, FALSE,
5822 EL_EMC_WALL_SLIPPERY_3, -1, -1
5825 Xround_wall_4, TRUE, FALSE,
5826 EL_EMC_WALL_SLIPPERY_4, -1, -1
5829 Xdecor_1, TRUE, FALSE,
5830 EL_EMC_WALL_8, -1, -1
5833 Xdecor_2, TRUE, FALSE,
5834 EL_EMC_WALL_6, -1, -1
5837 Xdecor_3, TRUE, FALSE,
5838 EL_EMC_WALL_4, -1, -1
5841 Xdecor_4, TRUE, FALSE,
5842 EL_EMC_WALL_7, -1, -1
5845 Xdecor_5, TRUE, FALSE,
5846 EL_EMC_WALL_5, -1, -1
5849 Xdecor_6, TRUE, FALSE,
5850 EL_EMC_WALL_9, -1, -1
5853 Xdecor_7, TRUE, FALSE,
5854 EL_EMC_WALL_10, -1, -1
5857 Xdecor_8, TRUE, FALSE,
5858 EL_EMC_WALL_1, -1, -1
5861 Xdecor_9, TRUE, FALSE,
5862 EL_EMC_WALL_2, -1, -1
5865 Xdecor_10, TRUE, FALSE,
5866 EL_EMC_WALL_3, -1, -1
5869 Xdecor_11, TRUE, FALSE,
5870 EL_EMC_WALL_11, -1, -1
5873 Xdecor_12, TRUE, FALSE,
5874 EL_EMC_WALL_12, -1, -1
5877 Xalpha_0, TRUE, FALSE,
5878 EL_CHAR('0'), -1, -1
5881 Xalpha_1, TRUE, FALSE,
5882 EL_CHAR('1'), -1, -1
5885 Xalpha_2, TRUE, FALSE,
5886 EL_CHAR('2'), -1, -1
5889 Xalpha_3, TRUE, FALSE,
5890 EL_CHAR('3'), -1, -1
5893 Xalpha_4, TRUE, FALSE,
5894 EL_CHAR('4'), -1, -1
5897 Xalpha_5, TRUE, FALSE,
5898 EL_CHAR('5'), -1, -1
5901 Xalpha_6, TRUE, FALSE,
5902 EL_CHAR('6'), -1, -1
5905 Xalpha_7, TRUE, FALSE,
5906 EL_CHAR('7'), -1, -1
5909 Xalpha_8, TRUE, FALSE,
5910 EL_CHAR('8'), -1, -1
5913 Xalpha_9, TRUE, FALSE,
5914 EL_CHAR('9'), -1, -1
5917 Xalpha_excla, TRUE, FALSE,
5918 EL_CHAR('!'), -1, -1
5921 Xalpha_quote, TRUE, FALSE,
5922 EL_CHAR('"'), -1, -1
5925 Xalpha_comma, TRUE, FALSE,
5926 EL_CHAR(','), -1, -1
5929 Xalpha_minus, TRUE, FALSE,
5930 EL_CHAR('-'), -1, -1
5933 Xalpha_perio, TRUE, FALSE,
5934 EL_CHAR('.'), -1, -1
5937 Xalpha_colon, TRUE, FALSE,
5938 EL_CHAR(':'), -1, -1
5941 Xalpha_quest, TRUE, FALSE,
5942 EL_CHAR('?'), -1, -1
5945 Xalpha_a, TRUE, FALSE,
5946 EL_CHAR('A'), -1, -1
5949 Xalpha_b, TRUE, FALSE,
5950 EL_CHAR('B'), -1, -1
5953 Xalpha_c, TRUE, FALSE,
5954 EL_CHAR('C'), -1, -1
5957 Xalpha_d, TRUE, FALSE,
5958 EL_CHAR('D'), -1, -1
5961 Xalpha_e, TRUE, FALSE,
5962 EL_CHAR('E'), -1, -1
5965 Xalpha_f, TRUE, FALSE,
5966 EL_CHAR('F'), -1, -1
5969 Xalpha_g, TRUE, FALSE,
5970 EL_CHAR('G'), -1, -1
5973 Xalpha_h, TRUE, FALSE,
5974 EL_CHAR('H'), -1, -1
5977 Xalpha_i, TRUE, FALSE,
5978 EL_CHAR('I'), -1, -1
5981 Xalpha_j, TRUE, FALSE,
5982 EL_CHAR('J'), -1, -1
5985 Xalpha_k, TRUE, FALSE,
5986 EL_CHAR('K'), -1, -1
5989 Xalpha_l, TRUE, FALSE,
5990 EL_CHAR('L'), -1, -1
5993 Xalpha_m, TRUE, FALSE,
5994 EL_CHAR('M'), -1, -1
5997 Xalpha_n, TRUE, FALSE,
5998 EL_CHAR('N'), -1, -1
6001 Xalpha_o, TRUE, FALSE,
6002 EL_CHAR('O'), -1, -1
6005 Xalpha_p, TRUE, FALSE,
6006 EL_CHAR('P'), -1, -1
6009 Xalpha_q, TRUE, FALSE,
6010 EL_CHAR('Q'), -1, -1
6013 Xalpha_r, TRUE, FALSE,
6014 EL_CHAR('R'), -1, -1
6017 Xalpha_s, TRUE, FALSE,
6018 EL_CHAR('S'), -1, -1
6021 Xalpha_t, TRUE, FALSE,
6022 EL_CHAR('T'), -1, -1
6025 Xalpha_u, TRUE, FALSE,
6026 EL_CHAR('U'), -1, -1
6029 Xalpha_v, TRUE, FALSE,
6030 EL_CHAR('V'), -1, -1
6033 Xalpha_w, TRUE, FALSE,
6034 EL_CHAR('W'), -1, -1
6037 Xalpha_x, TRUE, FALSE,
6038 EL_CHAR('X'), -1, -1
6041 Xalpha_y, TRUE, FALSE,
6042 EL_CHAR('Y'), -1, -1
6045 Xalpha_z, TRUE, FALSE,
6046 EL_CHAR('Z'), -1, -1
6049 Xalpha_arrow_e, TRUE, FALSE,
6050 EL_CHAR('>'), -1, -1
6053 Xalpha_arrow_w, TRUE, FALSE,
6054 EL_CHAR('<'), -1, -1
6057 Xalpha_copyr, TRUE, FALSE,
6058 EL_CHAR('©'), -1, -1
6062 Xboom_bug, FALSE, FALSE,
6063 EL_BUG, ACTION_EXPLODING, -1
6066 Xboom_bomb, FALSE, FALSE,
6067 EL_BOMB, ACTION_EXPLODING, -1
6070 Xboom_android, FALSE, FALSE,
6071 EL_EMC_ANDROID, ACTION_OTHER, -1
6074 Xboom_1, FALSE, FALSE,
6075 EL_DEFAULT, ACTION_EXPLODING, -1
6078 Xboom_2, FALSE, FALSE,
6079 EL_DEFAULT, ACTION_EXPLODING, -1
6082 Znormal, FALSE, FALSE,
6086 Zdynamite, FALSE, FALSE,
6090 Zplayer, FALSE, FALSE,
6094 ZBORDER, FALSE, FALSE,
6104 static struct Mapping_EM_to_RND_player
6113 em_player_mapping_list[] =
6117 EL_PLAYER_1, ACTION_MOVING, MV_BIT_UP,
6121 EL_PLAYER_1, ACTION_MOVING, MV_BIT_RIGHT,
6125 EL_PLAYER_1, ACTION_MOVING, MV_BIT_DOWN,
6129 EL_PLAYER_1, ACTION_MOVING, MV_BIT_LEFT,
6133 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_UP,
6137 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_RIGHT,
6141 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_DOWN,
6145 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_LEFT,
6149 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_UP,
6153 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_RIGHT,
6157 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_DOWN,
6161 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_LEFT,
6165 EL_PLAYER_2, ACTION_MOVING, MV_BIT_UP,
6169 EL_PLAYER_2, ACTION_MOVING, MV_BIT_RIGHT,
6173 EL_PLAYER_2, ACTION_MOVING, MV_BIT_DOWN,
6177 EL_PLAYER_2, ACTION_MOVING, MV_BIT_LEFT,
6181 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_UP,
6185 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_RIGHT,
6189 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_DOWN,
6193 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_LEFT,
6197 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_UP,
6201 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_RIGHT,
6205 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_DOWN,
6209 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_LEFT,
6213 EL_PLAYER_1, ACTION_DEFAULT, -1,
6217 EL_PLAYER_2, ACTION_DEFAULT, -1,
6221 EL_PLAYER_3, ACTION_MOVING, MV_BIT_UP,
6225 EL_PLAYER_3, ACTION_MOVING, MV_BIT_RIGHT,
6229 EL_PLAYER_3, ACTION_MOVING, MV_BIT_DOWN,
6233 EL_PLAYER_3, ACTION_MOVING, MV_BIT_LEFT,
6237 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_UP,
6241 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_RIGHT,
6245 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_DOWN,
6249 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_LEFT,
6253 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_UP,
6257 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_RIGHT,
6261 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_DOWN,
6265 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_LEFT,
6269 EL_PLAYER_4, ACTION_MOVING, MV_BIT_UP,
6273 EL_PLAYER_4, ACTION_MOVING, MV_BIT_RIGHT,
6277 EL_PLAYER_4, ACTION_MOVING, MV_BIT_DOWN,
6281 EL_PLAYER_4, ACTION_MOVING, MV_BIT_LEFT,
6285 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_UP,
6289 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_RIGHT,
6293 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_DOWN,
6297 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_LEFT,
6301 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_UP,
6305 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_RIGHT,
6309 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_DOWN,
6313 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_LEFT,
6317 EL_PLAYER_3, ACTION_DEFAULT, -1,
6321 EL_PLAYER_4, ACTION_DEFAULT, -1,
6330 int map_element_RND_to_EM(int element_rnd)
6332 static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
6333 static boolean mapping_initialized = FALSE;
6335 if (!mapping_initialized)
6339 /* return "Xalpha_quest" for all undefined elements in mapping array */
6340 for (i = 0; i < NUM_FILE_ELEMENTS; i++)
6341 mapping_RND_to_EM[i] = Xalpha_quest;
6343 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
6344 if (em_object_mapping_list[i].is_rnd_to_em_mapping)
6345 mapping_RND_to_EM[em_object_mapping_list[i].element_rnd] =
6346 em_object_mapping_list[i].element_em;
6348 mapping_initialized = TRUE;
6351 if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
6352 return mapping_RND_to_EM[element_rnd];
6354 Error(ERR_WARN, "invalid RND level element %d", element_rnd);
6359 int map_element_EM_to_RND(int element_em)
6361 static unsigned short mapping_EM_to_RND[TILE_MAX];
6362 static boolean mapping_initialized = FALSE;
6364 if (!mapping_initialized)
6368 /* return "EL_UNKNOWN" for all undefined elements in mapping array */
6369 for (i = 0; i < TILE_MAX; i++)
6370 mapping_EM_to_RND[i] = EL_UNKNOWN;
6372 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
6373 mapping_EM_to_RND[em_object_mapping_list[i].element_em] =
6374 em_object_mapping_list[i].element_rnd;
6376 mapping_initialized = TRUE;
6379 if (element_em >= 0 && element_em < TILE_MAX)
6380 return mapping_EM_to_RND[element_em];
6382 Error(ERR_WARN, "invalid EM level element %d", element_em);
6387 void map_android_clone_elements_RND_to_EM(struct LevelInfo *level)
6389 struct LevelInfo_EM *level_em = level->native_em_level;
6390 struct LEVEL *lev = level_em->lev;
6393 for (i = 0; i < TILE_MAX; i++)
6394 lev->android_array[i] = Xblank;
6396 for (i = 0; i < level->num_android_clone_elements; i++)
6398 int element_rnd = level->android_clone_element[i];
6399 int element_em = map_element_RND_to_EM(element_rnd);
6401 for (j = 0; em_object_mapping_list[j].element_em != -1; j++)
6402 if (em_object_mapping_list[j].element_rnd == element_rnd)
6403 lev->android_array[em_object_mapping_list[j].element_em] = element_em;
6407 void map_android_clone_elements_EM_to_RND(struct LevelInfo *level)
6409 struct LevelInfo_EM *level_em = level->native_em_level;
6410 struct LEVEL *lev = level_em->lev;
6413 level->num_android_clone_elements = 0;
6415 for (i = 0; i < TILE_MAX; i++)
6417 int element_em = lev->android_array[i];
6419 boolean element_found = FALSE;
6421 if (element_em == Xblank)
6424 element_rnd = map_element_EM_to_RND(element_em);
6426 for (j = 0; j < level->num_android_clone_elements; j++)
6427 if (level->android_clone_element[j] == element_rnd)
6428 element_found = TRUE;
6432 level->android_clone_element[level->num_android_clone_elements++] =
6435 if (level->num_android_clone_elements == MAX_ANDROID_ELEMENTS)
6440 if (level->num_android_clone_elements == 0)
6442 level->num_android_clone_elements = 1;
6443 level->android_clone_element[0] = EL_EMPTY;
6447 int map_direction_RND_to_EM(int direction)
6449 return (direction == MV_UP ? 0 :
6450 direction == MV_RIGHT ? 1 :
6451 direction == MV_DOWN ? 2 :
6452 direction == MV_LEFT ? 3 :
6456 int map_direction_EM_to_RND(int direction)
6458 return (direction == 0 ? MV_UP :
6459 direction == 1 ? MV_RIGHT :
6460 direction == 2 ? MV_DOWN :
6461 direction == 3 ? MV_LEFT :
6465 int map_element_RND_to_SP(int element_rnd)
6467 int element_sp = 0x20; /* map unknown elements to yellow "hardware" */
6469 if (element_rnd >= EL_SP_START &&
6470 element_rnd <= EL_SP_END)
6471 element_sp = element_rnd - EL_SP_START;
6472 else if (element_rnd == EL_EMPTY_SPACE)
6474 else if (element_rnd == EL_INVISIBLE_WALL)
6480 int map_element_SP_to_RND(int element_sp)
6482 int element_rnd = EL_UNKNOWN;
6484 if (element_sp >= 0x00 &&
6486 element_rnd = EL_SP_START + element_sp;
6487 else if (element_sp == 0x28)
6488 element_rnd = EL_INVISIBLE_WALL;
6493 int map_action_SP_to_RND(int action_sp)
6497 case actActive: return ACTION_ACTIVE;
6498 case actImpact: return ACTION_IMPACT;
6499 case actExploding: return ACTION_EXPLODING;
6500 case actDigging: return ACTION_DIGGING;
6501 case actSnapping: return ACTION_SNAPPING;
6502 case actCollecting: return ACTION_COLLECTING;
6503 case actPassing: return ACTION_PASSING;
6504 case actPushing: return ACTION_PUSHING;
6505 case actDropping: return ACTION_DROPPING;
6507 default: return ACTION_DEFAULT;
6511 int get_next_element(int element)
6515 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
6516 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
6517 case EL_QUICKSAND_FAST_FILLING: return EL_QUICKSAND_FAST_FULL;
6518 case EL_QUICKSAND_FAST_EMPTYING: return EL_QUICKSAND_FAST_EMPTY;
6519 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
6520 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
6521 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
6522 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
6523 case EL_DC_MAGIC_WALL_FILLING: return EL_DC_MAGIC_WALL_FULL;
6524 case EL_DC_MAGIC_WALL_EMPTYING: return EL_DC_MAGIC_WALL_ACTIVE;
6525 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
6527 default: return element;
6532 int el_act_dir2img(int element, int action, int direction)
6534 element = GFX_ELEMENT(element);
6536 if (direction == MV_NONE)
6537 return element_info[element].graphic[action];
6539 direction = MV_DIR_TO_BIT(direction);
6541 return element_info[element].direction_graphic[action][direction];
6544 int el_act_dir2img(int element, int action, int direction)
6546 element = GFX_ELEMENT(element);
6547 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
6549 /* direction_graphic[][] == graphic[] for undefined direction graphics */
6550 return element_info[element].direction_graphic[action][direction];
6555 static int el_act_dir2crm(int element, int action, int direction)
6557 element = GFX_ELEMENT(element);
6559 if (direction == MV_NONE)
6560 return element_info[element].crumbled[action];
6562 direction = MV_DIR_TO_BIT(direction);
6564 return element_info[element].direction_crumbled[action][direction];
6567 static int el_act_dir2crm(int element, int action, int direction)
6569 element = GFX_ELEMENT(element);
6570 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
6572 /* direction_graphic[][] == graphic[] for undefined direction graphics */
6573 return element_info[element].direction_crumbled[action][direction];
6577 int el_act2img(int element, int action)
6579 element = GFX_ELEMENT(element);
6581 return element_info[element].graphic[action];
6584 int el_act2crm(int element, int action)
6586 element = GFX_ELEMENT(element);
6588 return element_info[element].crumbled[action];
6591 int el_dir2img(int element, int direction)
6593 element = GFX_ELEMENT(element);
6595 return el_act_dir2img(element, ACTION_DEFAULT, direction);
6598 int el2baseimg(int element)
6600 return element_info[element].graphic[ACTION_DEFAULT];
6603 int el2img(int element)
6605 element = GFX_ELEMENT(element);
6607 return element_info[element].graphic[ACTION_DEFAULT];
6610 int el2edimg(int element)
6612 element = GFX_ELEMENT(element);
6614 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
6617 int el2preimg(int element)
6619 element = GFX_ELEMENT(element);
6621 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
6624 int el2panelimg(int element)
6626 element = GFX_ELEMENT(element);
6628 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PANEL];
6631 int font2baseimg(int font_nr)
6633 return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
6636 int getBeltNrFromBeltElement(int element)
6638 return (element < EL_CONVEYOR_BELT_2_LEFT ? 0 :
6639 element < EL_CONVEYOR_BELT_3_LEFT ? 1 :
6640 element < EL_CONVEYOR_BELT_4_LEFT ? 2 : 3);
6643 int getBeltNrFromBeltActiveElement(int element)
6645 return (element < EL_CONVEYOR_BELT_2_LEFT_ACTIVE ? 0 :
6646 element < EL_CONVEYOR_BELT_3_LEFT_ACTIVE ? 1 :
6647 element < EL_CONVEYOR_BELT_4_LEFT_ACTIVE ? 2 : 3);
6650 int getBeltNrFromBeltSwitchElement(int element)
6652 return (element < EL_CONVEYOR_BELT_2_SWITCH_LEFT ? 0 :
6653 element < EL_CONVEYOR_BELT_3_SWITCH_LEFT ? 1 :
6654 element < EL_CONVEYOR_BELT_4_SWITCH_LEFT ? 2 : 3);
6657 int getBeltDirNrFromBeltElement(int element)
6659 static int belt_base_element[4] =
6661 EL_CONVEYOR_BELT_1_LEFT,
6662 EL_CONVEYOR_BELT_2_LEFT,
6663 EL_CONVEYOR_BELT_3_LEFT,
6664 EL_CONVEYOR_BELT_4_LEFT
6667 int belt_nr = getBeltNrFromBeltElement(element);
6668 int belt_dir_nr = element - belt_base_element[belt_nr];
6670 return (belt_dir_nr % 3);
6673 int getBeltDirNrFromBeltSwitchElement(int element)
6675 static int belt_base_element[4] =
6677 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
6678 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
6679 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
6680 EL_CONVEYOR_BELT_4_SWITCH_LEFT
6683 int belt_nr = getBeltNrFromBeltSwitchElement(element);
6684 int belt_dir_nr = element - belt_base_element[belt_nr];
6686 return (belt_dir_nr % 3);
6689 int getBeltDirFromBeltElement(int element)
6691 static int belt_move_dir[3] =
6698 int belt_dir_nr = getBeltDirNrFromBeltElement(element);
6700 return belt_move_dir[belt_dir_nr];
6703 int getBeltDirFromBeltSwitchElement(int element)
6705 static int belt_move_dir[3] =
6712 int belt_dir_nr = getBeltDirNrFromBeltSwitchElement(element);
6714 return belt_move_dir[belt_dir_nr];
6717 int getBeltElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
6719 static int belt_base_element[4] =
6721 EL_CONVEYOR_BELT_1_LEFT,
6722 EL_CONVEYOR_BELT_2_LEFT,
6723 EL_CONVEYOR_BELT_3_LEFT,
6724 EL_CONVEYOR_BELT_4_LEFT
6727 return belt_base_element[belt_nr] + belt_dir_nr;
6730 int getBeltElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
6732 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
6734 return getBeltElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
6737 int getBeltSwitchElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
6739 static int belt_base_element[4] =
6741 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
6742 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
6743 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
6744 EL_CONVEYOR_BELT_4_SWITCH_LEFT
6747 return belt_base_element[belt_nr] + belt_dir_nr;
6750 int getBeltSwitchElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
6752 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
6754 return getBeltSwitchElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
6757 int getNumActivePlayers_EM()
6759 int num_players = 0;
6765 for (i = 0; i < MAX_PLAYERS; i++)
6766 if (tape.player_participates[i])
6772 int getGameFrameDelay_EM(int native_em_game_frame_delay)
6774 int game_frame_delay_value;
6776 game_frame_delay_value =
6777 (tape.playing && tape.fast_forward ? FfwdFrameDelay :
6778 GameFrameDelay == GAME_FRAME_DELAY ? native_em_game_frame_delay :
6781 if (tape.playing && tape.warp_forward && !tape.pausing)
6782 game_frame_delay_value = 0;
6784 return game_frame_delay_value;
6787 unsigned int InitRND(long seed)
6789 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
6790 return InitEngineRandom_EM(seed);
6791 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
6792 return InitEngineRandom_SP(seed);
6794 return InitEngineRandom_RND(seed);
6798 static struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
6799 static struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
6802 inline static int get_effective_element_EM(int tile, int frame_em)
6804 int element = object_mapping[tile].element_rnd;
6805 int action = object_mapping[tile].action;
6806 boolean is_backside = object_mapping[tile].is_backside;
6807 boolean action_removing = (action == ACTION_DIGGING ||
6808 action == ACTION_SNAPPING ||
6809 action == ACTION_COLLECTING);
6815 case Yacid_splash_eB:
6816 case Yacid_splash_wB:
6817 return (frame_em > 5 ? EL_EMPTY : element);
6820 case Ydiamond_stone:
6821 // if (!game.use_native_emc_graphics_engine)
6829 else /* frame_em == 7 */
6833 case Yacid_splash_eB:
6834 case Yacid_splash_wB:
6837 case Yemerald_stone:
6840 case Ydiamond_stone:
6844 case Xdrip_stretchB:
6863 case Xsand_stonein_1:
6864 case Xsand_stonein_2:
6865 case Xsand_stonein_3:
6866 case Xsand_stonein_4:
6870 return (is_backside || action_removing ? EL_EMPTY : element);
6875 inline static boolean check_linear_animation_EM(int tile)
6879 case Xsand_stonesand_1:
6880 case Xsand_stonesand_quickout_1:
6881 case Xsand_sandstone_1:
6882 case Xsand_stonein_1:
6883 case Xsand_stoneout_1:
6903 case Yacid_splash_eB:
6904 case Yacid_splash_wB:
6905 case Yemerald_stone:
6913 inline static void set_crumbled_graphics_EM(struct GraphicInfo_EM *g_em,
6914 boolean has_crumbled_graphics,
6915 int crumbled, int sync_frame)
6917 /* if element can be crumbled, but certain action graphics are just empty
6918 space (like instantly snapping sand to empty space in 1 frame), do not
6919 treat these empty space graphics as crumbled graphics in EMC engine */
6920 if (crumbled == IMG_EMPTY_SPACE)
6921 has_crumbled_graphics = FALSE;
6923 if (has_crumbled_graphics)
6925 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
6926 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
6927 g_crumbled->anim_delay,
6928 g_crumbled->anim_mode,
6929 g_crumbled->anim_start_frame,
6932 getGraphicSource(crumbled, frame_crumbled, &g_em->crumbled_bitmap,
6933 &g_em->crumbled_src_x, &g_em->crumbled_src_y);
6935 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
6937 g_em->has_crumbled_graphics = TRUE;
6941 g_em->crumbled_bitmap = NULL;
6942 g_em->crumbled_src_x = 0;
6943 g_em->crumbled_src_y = 0;
6944 g_em->crumbled_border_size = 0;
6946 g_em->has_crumbled_graphics = FALSE;
6950 void ResetGfxAnimation_EM(int x, int y, int tile)
6955 void SetGfxAnimation_EM(struct GraphicInfo_EM *g_em,
6956 int tile, int frame_em, int x, int y)
6958 int action = object_mapping[tile].action;
6960 int direction = object_mapping[tile].direction;
6961 int effective_element = get_effective_element_EM(tile, frame_em);
6962 int graphic = (direction == MV_NONE ?
6963 el_act2img(effective_element, action) :
6964 el_act_dir2img(effective_element, action, direction));
6965 struct GraphicInfo *g = &graphic_info[graphic];
6968 boolean action_removing = (action == ACTION_DIGGING ||
6969 action == ACTION_SNAPPING ||
6970 action == ACTION_COLLECTING);
6971 boolean action_moving = (action == ACTION_FALLING ||
6972 action == ACTION_MOVING ||
6973 action == ACTION_PUSHING ||
6974 action == ACTION_EATING ||
6975 action == ACTION_FILLING ||
6976 action == ACTION_EMPTYING);
6977 boolean action_falling = (action == ACTION_FALLING ||
6978 action == ACTION_FILLING ||
6979 action == ACTION_EMPTYING);
6981 /* special case: graphic uses "2nd movement tile" and has defined
6982 7 frames for movement animation (or less) => use default graphic
6983 for last (8th) frame which ends the movement animation */
6984 if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
6986 action = ACTION_DEFAULT; /* (keep action_* unchanged for now) */
6987 graphic = (direction == MV_NONE ?
6988 el_act2img(effective_element, action) :
6989 el_act_dir2img(effective_element, action, direction));
6991 g = &graphic_info[graphic];
6995 if (tile == Xsand_stonesand_1 ||
6996 tile == Xsand_stonesand_2 ||
6997 tile == Xsand_stonesand_3 ||
6998 tile == Xsand_stonesand_4)
6999 printf("::: 1: quicksand frame %d [%d]\n", GfxFrame[x][y], tile);
7003 if ((action_removing || check_linear_animation_EM(tile)) && frame_em == 0)
7007 // printf("::: resetting... [%d]\n", tile);
7010 if (action_removing || check_linear_animation_EM(tile))
7012 GfxFrame[x][y] = frame_em;
7014 // printf("::: resetting... [%d]\n", tile);
7017 else if (action_moving)
7019 boolean is_backside = object_mapping[tile].is_backside;
7023 int direction = object_mapping[tile].direction;
7024 int move_dir = (action_falling ? MV_DOWN : direction);
7029 /* !!! TEST !!! NEW !!! DOES NOT WORK RIGHT YET !!! */
7030 if (g->double_movement && frame_em == 0)
7034 // printf("::: resetting... [%d]\n", tile);
7038 if (move_dir == MV_LEFT)
7039 GfxFrame[x - 1][y] = GfxFrame[x][y];
7040 else if (move_dir == MV_RIGHT)
7041 GfxFrame[x + 1][y] = GfxFrame[x][y];
7042 else if (move_dir == MV_UP)
7043 GfxFrame[x][y - 1] = GfxFrame[x][y];
7044 else if (move_dir == MV_DOWN)
7045 GfxFrame[x][y + 1] = GfxFrame[x][y];
7052 /* special case: animation for Xsand_stonesand_quickout_1/2 twice as fast */
7053 if (tile == Xsand_stonesand_quickout_1 ||
7054 tile == Xsand_stonesand_quickout_2)
7059 if (tile == Xsand_stonesand_1 ||
7060 tile == Xsand_stonesand_2 ||
7061 tile == Xsand_stonesand_3 ||
7062 tile == Xsand_stonesand_4)
7063 printf("::: 2: quicksand frame %d [%d]\n", GfxFrame[x][y], tile);
7067 if (graphic_info[graphic].anim_global_sync)
7068 sync_frame = FrameCounter;
7069 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
7070 sync_frame = GfxFrame[x][y];
7072 sync_frame = 0; /* playfield border (pseudo steel) */
7074 SetRandomAnimationValue(x, y);
7076 int frame = getAnimationFrame(g->anim_frames,
7079 g->anim_start_frame,
7082 g_em->unique_identifier =
7083 (graphic << 16) | ((frame % 8) << 12) | (g_em->width << 6) | g_em->height;
7087 void getGraphicSourceObjectExt_EM(struct GraphicInfo_EM *g_em,
7088 int tile, int frame_em, int x, int y)
7090 int action = object_mapping[tile].action;
7091 int direction = object_mapping[tile].direction;
7092 boolean is_backside = object_mapping[tile].is_backside;
7093 int effective_element = get_effective_element_EM(tile, frame_em);
7095 int effective_action = action;
7097 int effective_action = (frame_em < 7 ? action : ACTION_DEFAULT);
7099 int graphic = (direction == MV_NONE ?
7100 el_act2img(effective_element, effective_action) :
7101 el_act_dir2img(effective_element, effective_action,
7103 int crumbled = (direction == MV_NONE ?
7104 el_act2crm(effective_element, effective_action) :
7105 el_act_dir2crm(effective_element, effective_action,
7107 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
7108 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
7109 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
7110 struct GraphicInfo *g = &graphic_info[graphic];
7112 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
7116 /* special case: graphic uses "2nd movement tile" and has defined
7117 7 frames for movement animation (or less) => use default graphic
7118 for last (8th) frame which ends the movement animation */
7119 if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
7121 effective_action = ACTION_DEFAULT;
7122 graphic = (direction == MV_NONE ?
7123 el_act2img(effective_element, effective_action) :
7124 el_act_dir2img(effective_element, effective_action,
7126 crumbled = (direction == MV_NONE ?
7127 el_act2crm(effective_element, effective_action) :
7128 el_act_dir2crm(effective_element, effective_action,
7131 g = &graphic_info[graphic];
7141 if (frame_em == 0) /* reset animation frame for certain elements */
7143 if (check_linear_animation_EM(tile))
7148 if (graphic_info[graphic].anim_global_sync)
7149 sync_frame = FrameCounter;
7150 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
7151 sync_frame = GfxFrame[x][y];
7153 sync_frame = 0; /* playfield border (pseudo steel) */
7155 SetRandomAnimationValue(x, y);
7160 int xxx_sync_frame = (i == Xdrip_stretch ? 7 :
7161 i == Xdrip_stretchB ? 7 :
7162 i == Ydrip_s2 ? j + 8 :
7163 i == Ydrip_s2B ? j + 8 :
7172 i == Xfake_acid_1 ? 0 :
7173 i == Xfake_acid_2 ? 10 :
7174 i == Xfake_acid_3 ? 20 :
7175 i == Xfake_acid_4 ? 30 :
7176 i == Xfake_acid_5 ? 40 :
7177 i == Xfake_acid_6 ? 50 :
7178 i == Xfake_acid_7 ? 60 :
7179 i == Xfake_acid_8 ? 70 :
7181 i == Xball_2B ? j + 8 :
7182 i == Yball_eat ? j + 1 :
7183 i == Ykey_1_eat ? j + 1 :
7184 i == Ykey_2_eat ? j + 1 :
7185 i == Ykey_3_eat ? j + 1 :
7186 i == Ykey_4_eat ? j + 1 :
7187 i == Ykey_5_eat ? j + 1 :
7188 i == Ykey_6_eat ? j + 1 :
7189 i == Ykey_7_eat ? j + 1 :
7190 i == Ykey_8_eat ? j + 1 :
7191 i == Ylenses_eat ? j + 1 :
7192 i == Ymagnify_eat ? j + 1 :
7193 i == Ygrass_eat ? j + 1 :
7194 i == Ydirt_eat ? j + 1 :
7195 i == Xamoeba_1 ? 0 :
7196 i == Xamoeba_2 ? 1 :
7197 i == Xamoeba_3 ? 2 :
7198 i == Xamoeba_4 ? 3 :
7199 i == Xamoeba_5 ? 0 :
7200 i == Xamoeba_6 ? 1 :
7201 i == Xamoeba_7 ? 2 :
7202 i == Xamoeba_8 ? 3 :
7203 i == Xexit_2 ? j + 8 :
7204 i == Xexit_3 ? j + 16 :
7205 i == Xdynamite_1 ? 0 :
7206 i == Xdynamite_2 ? 8 :
7207 i == Xdynamite_3 ? 16 :
7208 i == Xdynamite_4 ? 24 :
7209 i == Xsand_stonein_1 ? j + 1 :
7210 i == Xsand_stonein_2 ? j + 9 :
7211 i == Xsand_stonein_3 ? j + 17 :
7212 i == Xsand_stonein_4 ? j + 25 :
7213 i == Xsand_stoneout_1 && j == 0 ? 0 :
7214 i == Xsand_stoneout_1 && j == 1 ? 0 :
7215 i == Xsand_stoneout_1 && j == 2 ? 1 :
7216 i == Xsand_stoneout_1 && j == 3 ? 2 :
7217 i == Xsand_stoneout_1 && j == 4 ? 2 :
7218 i == Xsand_stoneout_1 && j == 5 ? 3 :
7219 i == Xsand_stoneout_1 && j == 6 ? 4 :
7220 i == Xsand_stoneout_1 && j == 7 ? 4 :
7221 i == Xsand_stoneout_2 && j == 0 ? 5 :
7222 i == Xsand_stoneout_2 && j == 1 ? 6 :
7223 i == Xsand_stoneout_2 && j == 2 ? 7 :
7224 i == Xsand_stoneout_2 && j == 3 ? 8 :
7225 i == Xsand_stoneout_2 && j == 4 ? 9 :
7226 i == Xsand_stoneout_2 && j == 5 ? 11 :
7227 i == Xsand_stoneout_2 && j == 6 ? 13 :
7228 i == Xsand_stoneout_2 && j == 7 ? 15 :
7229 i == Xboom_bug && j == 1 ? 2 :
7230 i == Xboom_bug && j == 2 ? 2 :
7231 i == Xboom_bug && j == 3 ? 4 :
7232 i == Xboom_bug && j == 4 ? 4 :
7233 i == Xboom_bug && j == 5 ? 2 :
7234 i == Xboom_bug && j == 6 ? 2 :
7235 i == Xboom_bug && j == 7 ? 0 :
7236 i == Xboom_bomb && j == 1 ? 2 :
7237 i == Xboom_bomb && j == 2 ? 2 :
7238 i == Xboom_bomb && j == 3 ? 4 :
7239 i == Xboom_bomb && j == 4 ? 4 :
7240 i == Xboom_bomb && j == 5 ? 2 :
7241 i == Xboom_bomb && j == 6 ? 2 :
7242 i == Xboom_bomb && j == 7 ? 0 :
7243 i == Xboom_android && j == 7 ? 6 :
7244 i == Xboom_1 && j == 1 ? 2 :
7245 i == Xboom_1 && j == 2 ? 2 :
7246 i == Xboom_1 && j == 3 ? 4 :
7247 i == Xboom_1 && j == 4 ? 4 :
7248 i == Xboom_1 && j == 5 ? 6 :
7249 i == Xboom_1 && j == 6 ? 6 :
7250 i == Xboom_1 && j == 7 ? 8 :
7251 i == Xboom_2 && j == 0 ? 8 :
7252 i == Xboom_2 && j == 1 ? 8 :
7253 i == Xboom_2 && j == 2 ? 10 :
7254 i == Xboom_2 && j == 3 ? 10 :
7255 i == Xboom_2 && j == 4 ? 10 :
7256 i == Xboom_2 && j == 5 ? 12 :
7257 i == Xboom_2 && j == 6 ? 12 :
7258 i == Xboom_2 && j == 7 ? 12 :
7260 special_animation && j == 4 ? 3 :
7261 effective_action != action ? 0 :
7267 int xxx_effective_action;
7268 int xxx_has_action_graphics;
7271 int element = object_mapping[i].element_rnd;
7272 int action = object_mapping[i].action;
7273 int direction = object_mapping[i].direction;
7274 boolean is_backside = object_mapping[i].is_backside;
7276 boolean action_removing = (action == ACTION_DIGGING ||
7277 action == ACTION_SNAPPING ||
7278 action == ACTION_COLLECTING);
7280 boolean action_exploding = ((action == ACTION_EXPLODING ||
7281 action == ACTION_SMASHED_BY_ROCK ||
7282 action == ACTION_SMASHED_BY_SPRING) &&
7283 element != EL_DIAMOND);
7284 boolean action_active = (action == ACTION_ACTIVE);
7285 boolean action_other = (action == ACTION_OTHER);
7289 int effective_element = get_effective_element_EM(i, j);
7291 int effective_element = (j > 5 && i == Yacid_splash_eB ? EL_EMPTY :
7292 j > 5 && i == Yacid_splash_wB ? EL_EMPTY :
7294 i == Xdrip_stretch ? element :
7295 i == Xdrip_stretchB ? element :
7296 i == Ydrip_s1 ? element :
7297 i == Ydrip_s1B ? element :
7298 i == Xball_1B ? element :
7299 i == Xball_2 ? element :
7300 i == Xball_2B ? element :
7301 i == Yball_eat ? element :
7302 i == Ykey_1_eat ? element :
7303 i == Ykey_2_eat ? element :
7304 i == Ykey_3_eat ? element :
7305 i == Ykey_4_eat ? element :
7306 i == Ykey_5_eat ? element :
7307 i == Ykey_6_eat ? element :
7308 i == Ykey_7_eat ? element :
7309 i == Ykey_8_eat ? element :
7310 i == Ylenses_eat ? element :
7311 i == Ymagnify_eat ? element :
7312 i == Ygrass_eat ? element :
7313 i == Ydirt_eat ? element :
7314 i == Yemerald_stone ? EL_EMERALD :
7315 i == Ydiamond_stone ? EL_ROCK :
7316 i == Xsand_stonein_1 ? element :
7317 i == Xsand_stonein_2 ? element :
7318 i == Xsand_stonein_3 ? element :
7319 i == Xsand_stonein_4 ? element :
7320 is_backside ? EL_EMPTY :
7321 action_removing ? EL_EMPTY :
7324 int effective_action = (j < 7 ? action :
7325 i == Xdrip_stretch ? action :
7326 i == Xdrip_stretchB ? action :
7327 i == Ydrip_s1 ? action :
7328 i == Ydrip_s1B ? action :
7329 i == Xball_1B ? action :
7330 i == Xball_2 ? action :
7331 i == Xball_2B ? action :
7332 i == Yball_eat ? action :
7333 i == Ykey_1_eat ? action :
7334 i == Ykey_2_eat ? action :
7335 i == Ykey_3_eat ? action :
7336 i == Ykey_4_eat ? action :
7337 i == Ykey_5_eat ? action :
7338 i == Ykey_6_eat ? action :
7339 i == Ykey_7_eat ? action :
7340 i == Ykey_8_eat ? action :
7341 i == Ylenses_eat ? action :
7342 i == Ymagnify_eat ? action :
7343 i == Ygrass_eat ? action :
7344 i == Ydirt_eat ? action :
7345 i == Xsand_stonein_1 ? action :
7346 i == Xsand_stonein_2 ? action :
7347 i == Xsand_stonein_3 ? action :
7348 i == Xsand_stonein_4 ? action :
7349 i == Xsand_stoneout_1 ? action :
7350 i == Xsand_stoneout_2 ? action :
7351 i == Xboom_android ? ACTION_EXPLODING :
7352 action_exploding ? ACTION_EXPLODING :
7353 action_active ? action :
7354 action_other ? action :
7356 int graphic = (el_act_dir2img(effective_element, effective_action,
7358 int crumbled = (el_act_dir2crm(effective_element, effective_action,
7360 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
7361 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
7362 boolean has_action_graphics = (graphic != base_graphic);
7363 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
7364 struct GraphicInfo *g = &graphic_info[graphic];
7366 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
7368 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
7371 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
7372 boolean special_animation = (action != ACTION_DEFAULT &&
7373 g->anim_frames == 3 &&
7374 g->anim_delay == 2 &&
7375 g->anim_mode & ANIM_LINEAR);
7376 xxx_sync_frame = (i == Xdrip_stretch ? 7 :
7377 i == Xdrip_stretchB ? 7 :
7378 i == Ydrip_s2 ? j + 8 :
7379 i == Ydrip_s2B ? j + 8 :
7388 i == Xfake_acid_1 ? 0 :
7389 i == Xfake_acid_2 ? 10 :
7390 i == Xfake_acid_3 ? 20 :
7391 i == Xfake_acid_4 ? 30 :
7392 i == Xfake_acid_5 ? 40 :
7393 i == Xfake_acid_6 ? 50 :
7394 i == Xfake_acid_7 ? 60 :
7395 i == Xfake_acid_8 ? 70 :
7397 i == Xball_2B ? j + 8 :
7398 i == Yball_eat ? j + 1 :
7399 i == Ykey_1_eat ? j + 1 :
7400 i == Ykey_2_eat ? j + 1 :
7401 i == Ykey_3_eat ? j + 1 :
7402 i == Ykey_4_eat ? j + 1 :
7403 i == Ykey_5_eat ? j + 1 :
7404 i == Ykey_6_eat ? j + 1 :
7405 i == Ykey_7_eat ? j + 1 :
7406 i == Ykey_8_eat ? j + 1 :
7407 i == Ylenses_eat ? j + 1 :
7408 i == Ymagnify_eat ? j + 1 :
7409 i == Ygrass_eat ? j + 1 :
7410 i == Ydirt_eat ? j + 1 :
7411 i == Xamoeba_1 ? 0 :
7412 i == Xamoeba_2 ? 1 :
7413 i == Xamoeba_3 ? 2 :
7414 i == Xamoeba_4 ? 3 :
7415 i == Xamoeba_5 ? 0 :
7416 i == Xamoeba_6 ? 1 :
7417 i == Xamoeba_7 ? 2 :
7418 i == Xamoeba_8 ? 3 :
7419 i == Xexit_2 ? j + 8 :
7420 i == Xexit_3 ? j + 16 :
7421 i == Xdynamite_1 ? 0 :
7422 i == Xdynamite_2 ? 8 :
7423 i == Xdynamite_3 ? 16 :
7424 i == Xdynamite_4 ? 24 :
7425 i == Xsand_stonein_1 ? j + 1 :
7426 i == Xsand_stonein_2 ? j + 9 :
7427 i == Xsand_stonein_3 ? j + 17 :
7428 i == Xsand_stonein_4 ? j + 25 :
7429 i == Xsand_stoneout_1 && j == 0 ? 0 :
7430 i == Xsand_stoneout_1 && j == 1 ? 0 :
7431 i == Xsand_stoneout_1 && j == 2 ? 1 :
7432 i == Xsand_stoneout_1 && j == 3 ? 2 :
7433 i == Xsand_stoneout_1 && j == 4 ? 2 :
7434 i == Xsand_stoneout_1 && j == 5 ? 3 :
7435 i == Xsand_stoneout_1 && j == 6 ? 4 :
7436 i == Xsand_stoneout_1 && j == 7 ? 4 :
7437 i == Xsand_stoneout_2 && j == 0 ? 5 :
7438 i == Xsand_stoneout_2 && j == 1 ? 6 :
7439 i == Xsand_stoneout_2 && j == 2 ? 7 :
7440 i == Xsand_stoneout_2 && j == 3 ? 8 :
7441 i == Xsand_stoneout_2 && j == 4 ? 9 :
7442 i == Xsand_stoneout_2 && j == 5 ? 11 :
7443 i == Xsand_stoneout_2 && j == 6 ? 13 :
7444 i == Xsand_stoneout_2 && j == 7 ? 15 :
7445 i == Xboom_bug && j == 1 ? 2 :
7446 i == Xboom_bug && j == 2 ? 2 :
7447 i == Xboom_bug && j == 3 ? 4 :
7448 i == Xboom_bug && j == 4 ? 4 :
7449 i == Xboom_bug && j == 5 ? 2 :
7450 i == Xboom_bug && j == 6 ? 2 :
7451 i == Xboom_bug && j == 7 ? 0 :
7452 i == Xboom_bomb && j == 1 ? 2 :
7453 i == Xboom_bomb && j == 2 ? 2 :
7454 i == Xboom_bomb && j == 3 ? 4 :
7455 i == Xboom_bomb && j == 4 ? 4 :
7456 i == Xboom_bomb && j == 5 ? 2 :
7457 i == Xboom_bomb && j == 6 ? 2 :
7458 i == Xboom_bomb && j == 7 ? 0 :
7459 i == Xboom_android && j == 7 ? 6 :
7460 i == Xboom_1 && j == 1 ? 2 :
7461 i == Xboom_1 && j == 2 ? 2 :
7462 i == Xboom_1 && j == 3 ? 4 :
7463 i == Xboom_1 && j == 4 ? 4 :
7464 i == Xboom_1 && j == 5 ? 6 :
7465 i == Xboom_1 && j == 6 ? 6 :
7466 i == Xboom_1 && j == 7 ? 8 :
7467 i == Xboom_2 && j == 0 ? 8 :
7468 i == Xboom_2 && j == 1 ? 8 :
7469 i == Xboom_2 && j == 2 ? 10 :
7470 i == Xboom_2 && j == 3 ? 10 :
7471 i == Xboom_2 && j == 4 ? 10 :
7472 i == Xboom_2 && j == 5 ? 12 :
7473 i == Xboom_2 && j == 6 ? 12 :
7474 i == Xboom_2 && j == 7 ? 12 :
7475 special_animation && j == 4 ? 3 :
7476 effective_action != action ? 0 :
7479 xxx_effective_action = effective_action;
7480 xxx_has_action_graphics = has_action_graphics;
7485 int frame = getAnimationFrame(g->anim_frames,
7488 g->anim_start_frame,
7502 int old_src_x = g_em->src_x;
7503 int old_src_y = g_em->src_y;
7507 getGraphicSourceExt(graphic, frame, &g_em->bitmap, &g_em->src_x, &g_em->src_y,
7508 g->double_movement && is_backside);
7510 getGraphicSourceExt(graphic, frame, &g_em->bitmap,
7511 &g_em->src_x, &g_em->src_y, FALSE);
7516 if (tile == Ydiamond_stone)
7517 printf("::: stone smashing diamond... %d: %d, %d, %d, %d, %d -> %d [%d, %d, %d, %d, %d, %d] [%d]\n",
7522 g->anim_start_frame,
7525 g_em->src_x, g_em->src_y,
7526 g_em->src_offset_x, g_em->src_offset_y,
7527 g_em->dst_offset_x, g_em->dst_offset_y,
7539 if (graphic == IMG_BUG_MOVING_RIGHT)
7540 printf("::: %d, %d, %d: %d, %d [%d, %d -> %d, %d]\n", graphic, x, y,
7541 g->double_movement, is_backside,
7542 old_src_x, old_src_y, g_em->src_x, g_em->src_y);
7550 g_em->src_offset_x = 0;
7551 g_em->src_offset_y = 0;
7552 g_em->dst_offset_x = 0;
7553 g_em->dst_offset_y = 0;
7554 g_em->width = TILEX;
7555 g_em->height = TILEY;
7557 g_em->preserve_background = FALSE;
7560 /* (updating the "crumbled" graphic definitions is probably not really needed,
7561 as animations for crumbled graphics can't be longer than one EMC cycle) */
7563 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
7568 g_em->crumbled_bitmap = NULL;
7569 g_em->crumbled_src_x = 0;
7570 g_em->crumbled_src_y = 0;
7572 g_em->has_crumbled_graphics = FALSE;
7574 if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
7576 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
7577 g_crumbled->anim_delay,
7578 g_crumbled->anim_mode,
7579 g_crumbled->anim_start_frame,
7582 getGraphicSource(crumbled, frame_crumbled, &g_em->crumbled_bitmap,
7583 &g_em->crumbled_src_x, &g_em->crumbled_src_y);
7585 g_em->has_crumbled_graphics = TRUE;
7591 int effective_action = xxx_effective_action;
7592 int has_action_graphics = xxx_has_action_graphics;
7594 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
7595 effective_action == ACTION_MOVING ||
7596 effective_action == ACTION_PUSHING ||
7597 effective_action == ACTION_EATING)) ||
7598 (!has_action_graphics && (effective_action == ACTION_FILLING ||
7599 effective_action == ACTION_EMPTYING)))
7602 (effective_action == ACTION_FALLING ||
7603 effective_action == ACTION_FILLING ||
7604 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
7605 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
7606 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
7607 int num_steps = (i == Ydrip_s1 ? 16 :
7608 i == Ydrip_s1B ? 16 :
7609 i == Ydrip_s2 ? 16 :
7610 i == Ydrip_s2B ? 16 :
7611 i == Xsand_stonein_1 ? 32 :
7612 i == Xsand_stonein_2 ? 32 :
7613 i == Xsand_stonein_3 ? 32 :
7614 i == Xsand_stonein_4 ? 32 :
7615 i == Xsand_stoneout_1 ? 16 :
7616 i == Xsand_stoneout_2 ? 16 : 8);
7617 int cx = ABS(dx) * (TILEX / num_steps);
7618 int cy = ABS(dy) * (TILEY / num_steps);
7619 int step_frame = (i == Ydrip_s2 ? j + 8 :
7620 i == Ydrip_s2B ? j + 8 :
7621 i == Xsand_stonein_2 ? j + 8 :
7622 i == Xsand_stonein_3 ? j + 16 :
7623 i == Xsand_stonein_4 ? j + 24 :
7624 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
7625 int step = (is_backside ? step_frame : num_steps - step_frame);
7627 if (is_backside) /* tile where movement starts */
7629 if (dx < 0 || dy < 0)
7631 g_em->src_offset_x = cx * step;
7632 g_em->src_offset_y = cy * step;
7636 g_em->dst_offset_x = cx * step;
7637 g_em->dst_offset_y = cy * step;
7640 else /* tile where movement ends */
7642 if (dx < 0 || dy < 0)
7644 g_em->dst_offset_x = cx * step;
7645 g_em->dst_offset_y = cy * step;
7649 g_em->src_offset_x = cx * step;
7650 g_em->src_offset_y = cy * step;
7654 g_em->width = TILEX - cx * step;
7655 g_em->height = TILEY - cy * step;
7658 /* create unique graphic identifier to decide if tile must be redrawn */
7659 /* bit 31 - 16 (16 bit): EM style graphic
7660 bit 15 - 12 ( 4 bit): EM style frame
7661 bit 11 - 6 ( 6 bit): graphic width
7662 bit 5 - 0 ( 6 bit): graphic height */
7663 g_em->unique_identifier =
7664 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
7670 void getGraphicSourcePlayerExt_EM(struct GraphicInfo_EM *g_em,
7671 int player_nr, int anim, int frame_em)
7673 int element = player_mapping[player_nr][anim].element_rnd;
7674 int action = player_mapping[player_nr][anim].action;
7675 int direction = player_mapping[player_nr][anim].direction;
7676 int graphic = (direction == MV_NONE ?
7677 el_act2img(element, action) :
7678 el_act_dir2img(element, action, direction));
7679 struct GraphicInfo *g = &graphic_info[graphic];
7682 InitPlayerGfxAnimation(&stored_player[player_nr], action, direction);
7684 stored_player[player_nr].StepFrame = frame_em;
7686 sync_frame = stored_player[player_nr].Frame;
7688 int frame = getAnimationFrame(g->anim_frames,
7691 g->anim_start_frame,
7694 getGraphicSourceExt(graphic, frame, &g_em->bitmap,
7695 &g_em->src_x, &g_em->src_y, FALSE);
7698 printf("::: %d: %d, %d [%d]\n",
7700 stored_player[player_nr].Frame,
7701 stored_player[player_nr].StepFrame,
7706 void InitGraphicInfo_EM(void)
7709 struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
7710 struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
7715 int num_em_gfx_errors = 0;
7717 if (graphic_info_em_object[0][0].bitmap == NULL)
7719 /* EM graphics not yet initialized in em_open_all() */
7724 printf("::: [4 errors can be ignored (1 x 'bomb', 3 x 'em_dynamite']\n");
7727 /* always start with reliable default values */
7728 for (i = 0; i < TILE_MAX; i++)
7730 object_mapping[i].element_rnd = EL_UNKNOWN;
7731 object_mapping[i].is_backside = FALSE;
7732 object_mapping[i].action = ACTION_DEFAULT;
7733 object_mapping[i].direction = MV_NONE;
7736 /* always start with reliable default values */
7737 for (p = 0; p < MAX_PLAYERS; p++)
7739 for (i = 0; i < SPR_MAX; i++)
7741 player_mapping[p][i].element_rnd = EL_UNKNOWN;
7742 player_mapping[p][i].action = ACTION_DEFAULT;
7743 player_mapping[p][i].direction = MV_NONE;
7747 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
7749 int e = em_object_mapping_list[i].element_em;
7751 object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd;
7752 object_mapping[e].is_backside = em_object_mapping_list[i].is_backside;
7754 if (em_object_mapping_list[i].action != -1)
7755 object_mapping[e].action = em_object_mapping_list[i].action;
7757 if (em_object_mapping_list[i].direction != -1)
7758 object_mapping[e].direction =
7759 MV_DIR_FROM_BIT(em_object_mapping_list[i].direction);
7762 for (i = 0; em_player_mapping_list[i].action_em != -1; i++)
7764 int a = em_player_mapping_list[i].action_em;
7765 int p = em_player_mapping_list[i].player_nr;
7767 player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd;
7769 if (em_player_mapping_list[i].action != -1)
7770 player_mapping[p][a].action = em_player_mapping_list[i].action;
7772 if (em_player_mapping_list[i].direction != -1)
7773 player_mapping[p][a].direction =
7774 MV_DIR_FROM_BIT(em_player_mapping_list[i].direction);
7777 for (i = 0; i < TILE_MAX; i++)
7779 int element = object_mapping[i].element_rnd;
7780 int action = object_mapping[i].action;
7781 int direction = object_mapping[i].direction;
7782 boolean is_backside = object_mapping[i].is_backside;
7784 boolean action_removing = (action == ACTION_DIGGING ||
7785 action == ACTION_SNAPPING ||
7786 action == ACTION_COLLECTING);
7788 boolean action_exploding = ((action == ACTION_EXPLODING ||
7789 action == ACTION_SMASHED_BY_ROCK ||
7790 action == ACTION_SMASHED_BY_SPRING) &&
7791 element != EL_DIAMOND);
7792 boolean action_active = (action == ACTION_ACTIVE);
7793 boolean action_other = (action == ACTION_OTHER);
7795 for (j = 0; j < 8; j++)
7798 int effective_element = get_effective_element_EM(i, j);
7800 int effective_element = (j > 5 && i == Yacid_splash_eB ? EL_EMPTY :
7801 j > 5 && i == Yacid_splash_wB ? EL_EMPTY :
7803 i == Xdrip_stretch ? element :
7804 i == Xdrip_stretchB ? element :
7805 i == Ydrip_s1 ? element :
7806 i == Ydrip_s1B ? element :
7807 i == Xball_1B ? element :
7808 i == Xball_2 ? element :
7809 i == Xball_2B ? element :
7810 i == Yball_eat ? element :
7811 i == Ykey_1_eat ? element :
7812 i == Ykey_2_eat ? element :
7813 i == Ykey_3_eat ? element :
7814 i == Ykey_4_eat ? element :
7815 i == Ykey_5_eat ? element :
7816 i == Ykey_6_eat ? element :
7817 i == Ykey_7_eat ? element :
7818 i == Ykey_8_eat ? element :
7819 i == Ylenses_eat ? element :
7820 i == Ymagnify_eat ? element :
7821 i == Ygrass_eat ? element :
7822 i == Ydirt_eat ? element :
7823 i == Yemerald_stone ? EL_EMERALD :
7824 i == Ydiamond_stone ? EL_ROCK :
7825 i == Xsand_stonein_1 ? element :
7826 i == Xsand_stonein_2 ? element :
7827 i == Xsand_stonein_3 ? element :
7828 i == Xsand_stonein_4 ? element :
7829 is_backside ? EL_EMPTY :
7830 action_removing ? EL_EMPTY :
7833 int effective_action = (j < 7 ? action :
7834 i == Xdrip_stretch ? action :
7835 i == Xdrip_stretchB ? action :
7836 i == Ydrip_s1 ? action :
7837 i == Ydrip_s1B ? action :
7838 i == Xball_1B ? action :
7839 i == Xball_2 ? action :
7840 i == Xball_2B ? action :
7841 i == Yball_eat ? action :
7842 i == Ykey_1_eat ? action :
7843 i == Ykey_2_eat ? action :
7844 i == Ykey_3_eat ? action :
7845 i == Ykey_4_eat ? action :
7846 i == Ykey_5_eat ? action :
7847 i == Ykey_6_eat ? action :
7848 i == Ykey_7_eat ? action :
7849 i == Ykey_8_eat ? action :
7850 i == Ylenses_eat ? action :
7851 i == Ymagnify_eat ? action :
7852 i == Ygrass_eat ? action :
7853 i == Ydirt_eat ? action :
7854 i == Xsand_stonein_1 ? action :
7855 i == Xsand_stonein_2 ? action :
7856 i == Xsand_stonein_3 ? action :
7857 i == Xsand_stonein_4 ? action :
7858 i == Xsand_stoneout_1 ? action :
7859 i == Xsand_stoneout_2 ? action :
7860 i == Xboom_android ? ACTION_EXPLODING :
7861 action_exploding ? ACTION_EXPLODING :
7862 action_active ? action :
7863 action_other ? action :
7865 int graphic = (el_act_dir2img(effective_element, effective_action,
7867 int crumbled = (el_act_dir2crm(effective_element, effective_action,
7869 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
7870 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
7871 boolean has_action_graphics = (graphic != base_graphic);
7872 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
7873 struct GraphicInfo *g = &graphic_info[graphic];
7875 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
7877 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
7880 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
7881 boolean special_animation = (action != ACTION_DEFAULT &&
7882 g->anim_frames == 3 &&
7883 g->anim_delay == 2 &&
7884 g->anim_mode & ANIM_LINEAR);
7885 int sync_frame = (i == Xdrip_stretch ? 7 :
7886 i == Xdrip_stretchB ? 7 :
7887 i == Ydrip_s2 ? j + 8 :
7888 i == Ydrip_s2B ? j + 8 :
7897 i == Xfake_acid_1 ? 0 :
7898 i == Xfake_acid_2 ? 10 :
7899 i == Xfake_acid_3 ? 20 :
7900 i == Xfake_acid_4 ? 30 :
7901 i == Xfake_acid_5 ? 40 :
7902 i == Xfake_acid_6 ? 50 :
7903 i == Xfake_acid_7 ? 60 :
7904 i == Xfake_acid_8 ? 70 :
7906 i == Xball_2B ? j + 8 :
7907 i == Yball_eat ? j + 1 :
7908 i == Ykey_1_eat ? j + 1 :
7909 i == Ykey_2_eat ? j + 1 :
7910 i == Ykey_3_eat ? j + 1 :
7911 i == Ykey_4_eat ? j + 1 :
7912 i == Ykey_5_eat ? j + 1 :
7913 i == Ykey_6_eat ? j + 1 :
7914 i == Ykey_7_eat ? j + 1 :
7915 i == Ykey_8_eat ? j + 1 :
7916 i == Ylenses_eat ? j + 1 :
7917 i == Ymagnify_eat ? j + 1 :
7918 i == Ygrass_eat ? j + 1 :
7919 i == Ydirt_eat ? j + 1 :
7920 i == Xamoeba_1 ? 0 :
7921 i == Xamoeba_2 ? 1 :
7922 i == Xamoeba_3 ? 2 :
7923 i == Xamoeba_4 ? 3 :
7924 i == Xamoeba_5 ? 0 :
7925 i == Xamoeba_6 ? 1 :
7926 i == Xamoeba_7 ? 2 :
7927 i == Xamoeba_8 ? 3 :
7928 i == Xexit_2 ? j + 8 :
7929 i == Xexit_3 ? j + 16 :
7930 i == Xdynamite_1 ? 0 :
7931 i == Xdynamite_2 ? 8 :
7932 i == Xdynamite_3 ? 16 :
7933 i == Xdynamite_4 ? 24 :
7934 i == Xsand_stonein_1 ? j + 1 :
7935 i == Xsand_stonein_2 ? j + 9 :
7936 i == Xsand_stonein_3 ? j + 17 :
7937 i == Xsand_stonein_4 ? j + 25 :
7938 i == Xsand_stoneout_1 && j == 0 ? 0 :
7939 i == Xsand_stoneout_1 && j == 1 ? 0 :
7940 i == Xsand_stoneout_1 && j == 2 ? 1 :
7941 i == Xsand_stoneout_1 && j == 3 ? 2 :
7942 i == Xsand_stoneout_1 && j == 4 ? 2 :
7943 i == Xsand_stoneout_1 && j == 5 ? 3 :
7944 i == Xsand_stoneout_1 && j == 6 ? 4 :
7945 i == Xsand_stoneout_1 && j == 7 ? 4 :
7946 i == Xsand_stoneout_2 && j == 0 ? 5 :
7947 i == Xsand_stoneout_2 && j == 1 ? 6 :
7948 i == Xsand_stoneout_2 && j == 2 ? 7 :
7949 i == Xsand_stoneout_2 && j == 3 ? 8 :
7950 i == Xsand_stoneout_2 && j == 4 ? 9 :
7951 i == Xsand_stoneout_2 && j == 5 ? 11 :
7952 i == Xsand_stoneout_2 && j == 6 ? 13 :
7953 i == Xsand_stoneout_2 && j == 7 ? 15 :
7954 i == Xboom_bug && j == 1 ? 2 :
7955 i == Xboom_bug && j == 2 ? 2 :
7956 i == Xboom_bug && j == 3 ? 4 :
7957 i == Xboom_bug && j == 4 ? 4 :
7958 i == Xboom_bug && j == 5 ? 2 :
7959 i == Xboom_bug && j == 6 ? 2 :
7960 i == Xboom_bug && j == 7 ? 0 :
7961 i == Xboom_bomb && j == 1 ? 2 :
7962 i == Xboom_bomb && j == 2 ? 2 :
7963 i == Xboom_bomb && j == 3 ? 4 :
7964 i == Xboom_bomb && j == 4 ? 4 :
7965 i == Xboom_bomb && j == 5 ? 2 :
7966 i == Xboom_bomb && j == 6 ? 2 :
7967 i == Xboom_bomb && j == 7 ? 0 :
7968 i == Xboom_android && j == 7 ? 6 :
7969 i == Xboom_1 && j == 1 ? 2 :
7970 i == Xboom_1 && j == 2 ? 2 :
7971 i == Xboom_1 && j == 3 ? 4 :
7972 i == Xboom_1 && j == 4 ? 4 :
7973 i == Xboom_1 && j == 5 ? 6 :
7974 i == Xboom_1 && j == 6 ? 6 :
7975 i == Xboom_1 && j == 7 ? 8 :
7976 i == Xboom_2 && j == 0 ? 8 :
7977 i == Xboom_2 && j == 1 ? 8 :
7978 i == Xboom_2 && j == 2 ? 10 :
7979 i == Xboom_2 && j == 3 ? 10 :
7980 i == Xboom_2 && j == 4 ? 10 :
7981 i == Xboom_2 && j == 5 ? 12 :
7982 i == Xboom_2 && j == 6 ? 12 :
7983 i == Xboom_2 && j == 7 ? 12 :
7984 special_animation && j == 4 ? 3 :
7985 effective_action != action ? 0 :
7989 Bitmap *debug_bitmap = g_em->bitmap;
7990 int debug_src_x = g_em->src_x;
7991 int debug_src_y = g_em->src_y;
7994 int frame = getAnimationFrame(g->anim_frames,
7997 g->anim_start_frame,
8000 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y,
8001 g->double_movement && is_backside);
8003 g_em->bitmap = src_bitmap;
8004 g_em->src_x = src_x;
8005 g_em->src_y = src_y;
8006 g_em->src_offset_x = 0;
8007 g_em->src_offset_y = 0;
8008 g_em->dst_offset_x = 0;
8009 g_em->dst_offset_y = 0;
8010 g_em->width = TILEX;
8011 g_em->height = TILEY;
8013 g_em->preserve_background = FALSE;
8016 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
8021 g_em->crumbled_bitmap = NULL;
8022 g_em->crumbled_src_x = 0;
8023 g_em->crumbled_src_y = 0;
8024 g_em->crumbled_border_size = 0;
8026 g_em->has_crumbled_graphics = FALSE;
8029 if (has_crumbled_graphics && crumbled == IMG_EMPTY_SPACE)
8030 printf("::: empty crumbled: %d [%s], %d, %d\n",
8031 effective_element, element_info[effective_element].token_name,
8032 effective_action, direction);
8035 /* if element can be crumbled, but certain action graphics are just empty
8036 space (like instantly snapping sand to empty space in 1 frame), do not
8037 treat these empty space graphics as crumbled graphics in EMC engine */
8038 if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
8040 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
8041 g_crumbled->anim_delay,
8042 g_crumbled->anim_mode,
8043 g_crumbled->anim_start_frame,
8046 getGraphicSource(crumbled, frame_crumbled, &src_bitmap, &src_x, &src_y);
8048 g_em->has_crumbled_graphics = TRUE;
8049 g_em->crumbled_bitmap = src_bitmap;
8050 g_em->crumbled_src_x = src_x;
8051 g_em->crumbled_src_y = src_y;
8052 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
8056 if (g_em == &graphic_info_em_object[207][0])
8057 printf("... %d, %d [%d, %d, %d, %d] [%d, %d, %d, %d, %d, %d => %d]\n",
8058 graphic_info_em_object[207][0].crumbled_src_x,
8059 graphic_info_em_object[207][0].crumbled_src_y,
8061 crumbled, frame, src_x, src_y,
8066 g->anim_start_frame,
8068 gfx.anim_random_frame,
8073 printf("::: EMC tile %d is crumbled\n", i);
8079 if (element == EL_ROCK &&
8080 effective_action == ACTION_FILLING)
8081 printf("::: has_action_graphics == %d\n", has_action_graphics);
8084 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
8085 effective_action == ACTION_MOVING ||
8086 effective_action == ACTION_PUSHING ||
8087 effective_action == ACTION_EATING)) ||
8088 (!has_action_graphics && (effective_action == ACTION_FILLING ||
8089 effective_action == ACTION_EMPTYING)))
8092 (effective_action == ACTION_FALLING ||
8093 effective_action == ACTION_FILLING ||
8094 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
8095 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
8096 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
8097 int num_steps = (i == Ydrip_s1 ? 16 :
8098 i == Ydrip_s1B ? 16 :
8099 i == Ydrip_s2 ? 16 :
8100 i == Ydrip_s2B ? 16 :
8101 i == Xsand_stonein_1 ? 32 :
8102 i == Xsand_stonein_2 ? 32 :
8103 i == Xsand_stonein_3 ? 32 :
8104 i == Xsand_stonein_4 ? 32 :
8105 i == Xsand_stoneout_1 ? 16 :
8106 i == Xsand_stoneout_2 ? 16 : 8);
8107 int cx = ABS(dx) * (TILEX / num_steps);
8108 int cy = ABS(dy) * (TILEY / num_steps);
8109 int step_frame = (i == Ydrip_s2 ? j + 8 :
8110 i == Ydrip_s2B ? j + 8 :
8111 i == Xsand_stonein_2 ? j + 8 :
8112 i == Xsand_stonein_3 ? j + 16 :
8113 i == Xsand_stonein_4 ? j + 24 :
8114 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
8115 int step = (is_backside ? step_frame : num_steps - step_frame);
8117 if (is_backside) /* tile where movement starts */
8119 if (dx < 0 || dy < 0)
8121 g_em->src_offset_x = cx * step;
8122 g_em->src_offset_y = cy * step;
8126 g_em->dst_offset_x = cx * step;
8127 g_em->dst_offset_y = cy * step;
8130 else /* tile where movement ends */
8132 if (dx < 0 || dy < 0)
8134 g_em->dst_offset_x = cx * step;
8135 g_em->dst_offset_y = cy * step;
8139 g_em->src_offset_x = cx * step;
8140 g_em->src_offset_y = cy * step;
8144 g_em->width = TILEX - cx * step;
8145 g_em->height = TILEY - cy * step;
8148 /* create unique graphic identifier to decide if tile must be redrawn */
8149 /* bit 31 - 16 (16 bit): EM style graphic
8150 bit 15 - 12 ( 4 bit): EM style frame
8151 bit 11 - 6 ( 6 bit): graphic width
8152 bit 5 - 0 ( 6 bit): graphic height */
8153 g_em->unique_identifier =
8154 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
8158 /* skip check for EMC elements not contained in original EMC artwork */
8159 if (element == EL_EMC_FAKE_ACID)
8162 if (g_em->bitmap != debug_bitmap ||
8163 g_em->src_x != debug_src_x ||
8164 g_em->src_y != debug_src_y ||
8165 g_em->src_offset_x != 0 ||
8166 g_em->src_offset_y != 0 ||
8167 g_em->dst_offset_x != 0 ||
8168 g_em->dst_offset_y != 0 ||
8169 g_em->width != TILEX ||
8170 g_em->height != TILEY)
8172 static int last_i = -1;
8180 printf("::: EMC GFX ERROR for element %d -> %d ('%s', '%s', %d)",
8181 i, element, element_info[element].token_name,
8182 element_action_info[effective_action].suffix, direction);
8184 if (element != effective_element)
8185 printf(" [%d ('%s')]",
8187 element_info[effective_element].token_name);
8191 if (g_em->bitmap != debug_bitmap)
8192 printf(" %d (%d): different bitmap! (0x%08x != 0x%08x)\n",
8193 j, is_backside, (int)(g_em->bitmap), (int)(debug_bitmap));
8195 if (g_em->src_x != debug_src_x ||
8196 g_em->src_y != debug_src_y)
8197 printf(" frame %d (%c): %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
8198 j, (is_backside ? 'B' : 'F'),
8199 g_em->src_x, g_em->src_y,
8200 g_em->src_x / 32, g_em->src_y / 32,
8201 debug_src_x, debug_src_y,
8202 debug_src_x / 32, debug_src_y / 32);
8204 if (g_em->src_offset_x != 0 ||
8205 g_em->src_offset_y != 0 ||
8206 g_em->dst_offset_x != 0 ||
8207 g_em->dst_offset_y != 0)
8208 printf(" %d (%d): offsets %d,%d and %d,%d should be all 0\n",
8210 g_em->src_offset_x, g_em->src_offset_y,
8211 g_em->dst_offset_x, g_em->dst_offset_y);
8213 if (g_em->width != TILEX ||
8214 g_em->height != TILEY)
8215 printf(" %d (%d): size %d,%d should be %d,%d\n",
8217 g_em->width, g_em->height, TILEX, TILEY);
8219 num_em_gfx_errors++;
8226 for (i = 0; i < TILE_MAX; i++)
8228 for (j = 0; j < 8; j++)
8230 int element = object_mapping[i].element_rnd;
8231 int action = object_mapping[i].action;
8232 int direction = object_mapping[i].direction;
8233 boolean is_backside = object_mapping[i].is_backside;
8234 int graphic_action = el_act_dir2img(element, action, direction);
8235 int graphic_default = el_act_dir2img(element, ACTION_DEFAULT, direction);
8237 if ((action == ACTION_SMASHED_BY_ROCK ||
8238 action == ACTION_SMASHED_BY_SPRING ||
8239 action == ACTION_EATING) &&
8240 graphic_action == graphic_default)
8242 int e = (action == ACTION_SMASHED_BY_ROCK ? Ystone_s :
8243 action == ACTION_SMASHED_BY_SPRING ? Yspring_s :
8244 direction == MV_LEFT ? (is_backside? Yspring_wB: Yspring_w) :
8245 direction == MV_RIGHT ? (is_backside? Yspring_eB: Yspring_e) :
8248 /* no separate animation for "smashed by rock" -- use rock instead */
8249 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
8250 struct GraphicInfo_EM *g_xx = &graphic_info_em_object[e][7 - j];
8252 g_em->bitmap = g_xx->bitmap;
8253 g_em->src_x = g_xx->src_x;
8254 g_em->src_y = g_xx->src_y;
8255 g_em->src_offset_x = g_xx->src_offset_x;
8256 g_em->src_offset_y = g_xx->src_offset_y;
8257 g_em->dst_offset_x = g_xx->dst_offset_x;
8258 g_em->dst_offset_y = g_xx->dst_offset_y;
8259 g_em->width = g_xx->width;
8260 g_em->height = g_xx->height;
8261 g_em->unique_identifier = g_xx->unique_identifier;
8264 g_em->preserve_background = TRUE;
8269 for (p = 0; p < MAX_PLAYERS; p++)
8271 for (i = 0; i < SPR_MAX; i++)
8273 int element = player_mapping[p][i].element_rnd;
8274 int action = player_mapping[p][i].action;
8275 int direction = player_mapping[p][i].direction;
8277 for (j = 0; j < 8; j++)
8279 int effective_element = element;
8280 int effective_action = action;
8281 int graphic = (direction == MV_NONE ?
8282 el_act2img(effective_element, effective_action) :
8283 el_act_dir2img(effective_element, effective_action,
8285 struct GraphicInfo *g = &graphic_info[graphic];
8286 struct GraphicInfo_EM *g_em = &graphic_info_em_player[p][i][7 - j];
8292 Bitmap *debug_bitmap = g_em->bitmap;
8293 int debug_src_x = g_em->src_x;
8294 int debug_src_y = g_em->src_y;
8297 int frame = getAnimationFrame(g->anim_frames,
8300 g->anim_start_frame,
8303 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
8305 g_em->bitmap = src_bitmap;
8306 g_em->src_x = src_x;
8307 g_em->src_y = src_y;
8308 g_em->src_offset_x = 0;
8309 g_em->src_offset_y = 0;
8310 g_em->dst_offset_x = 0;
8311 g_em->dst_offset_y = 0;
8312 g_em->width = TILEX;
8313 g_em->height = TILEY;
8317 /* skip check for EMC elements not contained in original EMC artwork */
8318 if (element == EL_PLAYER_3 ||
8319 element == EL_PLAYER_4)
8322 if (g_em->bitmap != debug_bitmap ||
8323 g_em->src_x != debug_src_x ||
8324 g_em->src_y != debug_src_y)
8326 static int last_i = -1;
8334 printf("::: EMC GFX ERROR for p/a %d/%d -> %d ('%s', '%s', %d)",
8335 p, i, element, element_info[element].token_name,
8336 element_action_info[effective_action].suffix, direction);
8338 if (element != effective_element)
8339 printf(" [%d ('%s')]",
8341 element_info[effective_element].token_name);
8345 if (g_em->bitmap != debug_bitmap)
8346 printf(" %d: different bitmap! (0x%08x != 0x%08x)\n",
8347 j, (int)(g_em->bitmap), (int)(debug_bitmap));
8349 if (g_em->src_x != debug_src_x ||
8350 g_em->src_y != debug_src_y)
8351 printf(" frame %d: %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
8353 g_em->src_x, g_em->src_y,
8354 g_em->src_x / 32, g_em->src_y / 32,
8355 debug_src_x, debug_src_y,
8356 debug_src_x / 32, debug_src_y / 32);
8358 num_em_gfx_errors++;
8368 printf("::: [%d errors found]\n", num_em_gfx_errors);
8374 void CheckSingleStepMode_EM(byte action[MAX_PLAYERS], int frame,
8375 boolean any_player_moving,
8376 boolean player_is_dropping)
8380 if (tape.single_step && tape.recording && !tape.pausing)
8382 boolean active_players = FALSE;
8384 for (i = 0; i < MAX_PLAYERS; i++)
8385 if (action[i] != JOY_NO_ACTION)
8386 active_players = TRUE;
8389 if (frame == 0 && !player_is_dropping)
8390 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
8394 void CheckSingleStepMode_SP(boolean murphy_is_waiting,
8395 boolean murphy_is_dropping)
8398 printf("::: waiting: %d, dropping: %d\n",
8399 murphy_is_waiting, murphy_is_dropping);
8402 if (tape.single_step && tape.recording && !tape.pausing)
8404 // if (murphy_is_waiting || murphy_is_dropping)
8405 if (murphy_is_waiting)
8408 printf("::: murphy is waiting -> pause mode\n");
8411 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
8416 void getGraphicSource_SP(struct GraphicInfo_SP *g_sp,
8417 int graphic, int sync_frame, int x, int y)
8419 int frame = getGraphicAnimationFrame(graphic, sync_frame);
8421 getGraphicSource(graphic, frame, &g_sp->bitmap, &g_sp->src_x, &g_sp->src_y);
8424 boolean isNextAnimationFrame_SP(int graphic, int sync_frame)
8426 return (IS_NEXT_FRAME(sync_frame, graphic));
8429 int getGraphicInfo_Delay(int graphic)
8431 return graphic_info[graphic].anim_delay;
8434 void PlayMenuSoundExt(int sound)
8436 if (sound == SND_UNDEFINED)
8439 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
8440 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
8443 if (IS_LOOP_SOUND(sound))
8444 PlaySoundLoop(sound);
8449 void PlayMenuSound()
8451 PlayMenuSoundExt(menu.sound[game_status]);
8454 void PlayMenuSoundStereo(int sound, int stereo_position)
8456 if (sound == SND_UNDEFINED)
8459 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
8460 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
8463 if (IS_LOOP_SOUND(sound))
8464 PlaySoundExt(sound, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_LOOP);
8466 PlaySoundStereo(sound, stereo_position);
8469 void PlayMenuSoundIfLoopExt(int sound)
8471 if (sound == SND_UNDEFINED)
8474 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
8475 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
8478 if (IS_LOOP_SOUND(sound))
8479 PlaySoundLoop(sound);
8482 void PlayMenuSoundIfLoop()
8484 PlayMenuSoundIfLoopExt(menu.sound[game_status]);
8487 void PlayMenuMusicExt(int music)
8489 if (music == MUS_UNDEFINED)
8492 if (!setup.sound_music)
8498 void PlayMenuMusic()
8500 PlayMenuMusicExt(menu.music[game_status]);
8503 void PlaySoundActivating()
8506 PlaySound(SND_MENU_ITEM_ACTIVATING);
8510 void PlaySoundSelecting()
8513 PlaySound(SND_MENU_ITEM_SELECTING);
8517 void ToggleFullscreenIfNeeded()
8519 boolean change_fullscreen = (setup.fullscreen !=
8520 video.fullscreen_enabled);
8521 boolean change_fullscreen_mode = (video.fullscreen_enabled &&
8522 !strEqual(setup.fullscreen_mode,
8523 video.fullscreen_mode_current));
8525 if (!video.fullscreen_available)
8528 if (change_fullscreen || change_fullscreen_mode)
8530 Bitmap *tmp_backbuffer = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
8532 /* save backbuffer content which gets lost when toggling fullscreen mode */
8533 BlitBitmap(backbuffer, tmp_backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
8535 if (change_fullscreen_mode)
8537 /* keep fullscreen, but change fullscreen mode (screen resolution) */
8538 video.fullscreen_enabled = FALSE; /* force new fullscreen mode */
8541 /* toggle fullscreen */
8542 ChangeVideoModeIfNeeded(setup.fullscreen);
8544 setup.fullscreen = video.fullscreen_enabled;
8546 /* restore backbuffer content from temporary backbuffer backup bitmap */
8547 BlitBitmap(tmp_backbuffer, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
8549 FreeBitmap(tmp_backbuffer);
8552 /* update visible window/screen */
8553 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
8555 redraw_mask = REDRAW_ALL;
8560 void ChangeViewportPropertiesIfNeeded()
8562 int *door_1_x = &DX;
8563 int *door_1_y = &DY;
8564 int *door_2_x = (game_status == GAME_MODE_EDITOR ? &EX : &VX);
8565 int *door_2_y = (game_status == GAME_MODE_EDITOR ? &EY : &VY);
8566 int gfx_game_mode = (game_status == GAME_MODE_PLAYING ||
8567 game_status == GAME_MODE_EDITOR ? game_status :
8569 struct RectWithBorder *vp_playfield = &viewport.playfield[gfx_game_mode];
8570 struct RectWithBorder *vp_door_1 = &viewport.door_1[gfx_game_mode];
8571 struct RectWithBorder *vp_door_2 = &viewport.door_2[gfx_game_mode];
8572 int border_size = vp_playfield->border_size;
8573 int new_sx = vp_playfield->x + border_size;
8574 int new_sy = vp_playfield->y + border_size;
8575 int new_scr_fieldx = (vp_playfield->width - 2 * border_size) / TILESIZE;
8576 int new_scr_fieldy = (vp_playfield->height - 2 * border_size) / TILESIZE;
8579 /* !!! TEST ONLY !!! */
8580 // InitGfxBuffers();
8584 if (viewport.window.width != WIN_XSIZE ||
8585 viewport.window.height != WIN_YSIZE)
8587 WIN_XSIZE = viewport.window.width;
8588 WIN_YSIZE = viewport.window.height;
8590 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
8594 SetDrawDeactivationMask(REDRAW_NONE);
8595 SetDrawBackgroundMask(REDRAW_FIELD);
8597 // RedrawBackground();
8601 if (new_scr_fieldx != SCR_FIELDX ||
8602 new_scr_fieldy != SCR_FIELDY ||
8605 vp_playfield->x != REAL_SX ||
8606 vp_playfield->y != REAL_SY ||
8607 vp_door_1->x != *door_1_x ||
8608 vp_door_1->y != *door_1_y ||
8609 vp_door_2->x != *door_2_x ||
8610 vp_door_2->y != *door_2_y)
8612 SCR_FIELDX = new_scr_fieldx;
8613 SCR_FIELDY = new_scr_fieldy;
8616 REAL_SX = vp_playfield->x;
8617 REAL_SY = vp_playfield->y;
8619 *door_1_x = vp_door_1->x;
8620 *door_1_y = vp_door_1->y;
8621 *door_2_x = vp_door_2->x;
8622 *door_2_y = vp_door_2->y;
8626 if (gfx_game_mode == GAME_MODE_MAIN)
8634 printf("::: %d, %d / %d, %d [%d]\n", VX, VY, EX, EY, game_status);