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)
117 BX2 = SCR_FIELDX + 1;
118 BY2 = SCR_FIELDY + 1;
137 BX2 = SCR_FIELDX + 1;
138 BY2 = SCR_FIELDY + 1;
153 drawto_field = fieldbuffer;
155 else /* DRAW_BACKBUFFER */
161 BX2 = SCR_FIELDX - 1;
162 BY2 = SCR_FIELDY - 1;
166 drawto_field = backbuffer;
170 void RedrawPlayfield(boolean force_redraw, int x, int y, int width, int height)
172 if (game_status == GAME_MODE_PLAYING &&
173 level.game_engine_type == GAME_ENGINE_TYPE_EM)
175 /* currently there is no partial redraw -- always redraw whole playfield */
176 RedrawPlayfield_EM(TRUE);
178 /* blit playfield from scroll buffer to normal back buffer for fading in */
179 BlitScreenToBitmap_EM(backbuffer);
181 else if (game_status == GAME_MODE_PLAYING &&
182 level.game_engine_type == GAME_ENGINE_TYPE_SP)
184 /* currently there is no partial redraw -- always redraw whole playfield */
185 RedrawPlayfield_SP(TRUE);
187 /* blit playfield from scroll buffer to normal back buffer for fading in */
188 BlitScreenToBitmap_SP(backbuffer);
190 else if (game_status == GAME_MODE_PLAYING &&
191 !game.envelope_active)
197 width = gfx.sxsize + 2 * TILEX;
198 height = gfx.sysize + 2 * TILEY;
204 int x1 = (x - SX) / TILEX, y1 = (y - SY) / TILEY;
205 int x2 = (x - SX + width) / TILEX, y2 = (y - SY + height) / TILEY;
207 for (xx = BX1; xx <= BX2; xx++)
208 for (yy = BY1; yy <= BY2; yy++)
209 if (xx >= x1 && xx <= x2 && yy >= y1 && yy <= y2)
210 DrawScreenField(xx, yy);
214 if (setup.soft_scrolling)
216 int fx = FX, fy = FY;
218 fx += (ScreenMovDir & (MV_LEFT|MV_RIGHT) ? ScreenGfxPos : 0);
219 fy += (ScreenMovDir & (MV_UP|MV_DOWN) ? ScreenGfxPos : 0);
221 BlitBitmap(fieldbuffer, backbuffer, fx,fy, SXSIZE,SYSIZE, SX,SY);
233 BlitBitmap(drawto, window, x, y, width, height, x, y);
236 void DrawMaskedBorder_Rect(int x, int y, int width, int height)
238 Bitmap *bitmap = graphic_info[IMG_GLOBAL_BORDER].bitmap;
240 SetClipOrigin(bitmap, bitmap->stored_clip_gc, 0, 0);
241 BlitBitmapMasked(bitmap, backbuffer, x, y, width, height, x, y);
244 void DrawMaskedBorder_FIELD()
246 if (global.border_status >= GAME_MODE_TITLE &&
247 global.border_status <= GAME_MODE_PLAYING &&
248 border.draw_masked[global.border_status])
249 DrawMaskedBorder_Rect(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
252 void DrawMaskedBorder_DOOR_1()
254 if (border.draw_masked[GFX_SPECIAL_ARG_DOOR] &&
255 (global.border_status != GAME_MODE_EDITOR ||
256 border.draw_masked[GFX_SPECIAL_ARG_EDITOR]))
257 DrawMaskedBorder_Rect(DX, DY, DXSIZE, DYSIZE);
260 void DrawMaskedBorder_DOOR_2()
262 if (border.draw_masked[GFX_SPECIAL_ARG_DOOR] &&
263 global.border_status != GAME_MODE_EDITOR)
264 DrawMaskedBorder_Rect(VX, VY, VXSIZE, VYSIZE);
267 void DrawMaskedBorder_DOOR_3()
269 /* currently not available */
272 void DrawMaskedBorder_ALL()
274 DrawMaskedBorder_FIELD();
275 DrawMaskedBorder_DOOR_1();
276 DrawMaskedBorder_DOOR_2();
277 DrawMaskedBorder_DOOR_3();
280 void DrawMaskedBorder(int redraw_mask)
282 /* never draw masked screen borders on borderless screens */
283 if (effectiveGameStatus() == GAME_MODE_LOADING ||
284 effectiveGameStatus() == GAME_MODE_TITLE)
287 /* never draw masked screen borders when displaying request outside door */
288 if (effectiveGameStatus() == GAME_MODE_PSEUDO_DOOR &&
289 global.use_envelope_request)
292 if (redraw_mask & REDRAW_ALL)
293 DrawMaskedBorder_ALL();
296 if (redraw_mask & REDRAW_FIELD)
297 DrawMaskedBorder_FIELD();
298 if (redraw_mask & REDRAW_DOOR_1)
299 DrawMaskedBorder_DOOR_1();
300 if (redraw_mask & REDRAW_DOOR_2)
301 DrawMaskedBorder_DOOR_2();
302 if (redraw_mask & REDRAW_DOOR_3)
303 DrawMaskedBorder_DOOR_3();
310 DrawBuffer *buffer = (drawto_field == window ? backbuffer : drawto_field);
313 printf("::: TILES TO REFRESH: %d\n", redraw_tiles);
314 for (x = 0; x < SCR_FIELDX; x++)
315 for (y = 0 ; y < SCR_FIELDY; y++)
316 if (redraw[redraw_x1 + x][redraw_y1 + y])
317 printf("::: - %d, %d [%s]\n",
318 LEVELX(x), LEVELY(y),
319 EL_NAME(Feld[LEVELX(x)][LEVELY(y)]));
322 if (redraw_mask & REDRAW_TILES && redraw_tiles > REDRAWTILES_THRESHOLD)
323 redraw_mask |= REDRAW_FIELD;
325 if (redraw_mask & REDRAW_FIELD)
326 redraw_mask &= ~REDRAW_TILES;
328 if (redraw_mask == REDRAW_NONE)
331 if (redraw_mask & REDRAW_TILES &&
332 game_status == GAME_MODE_PLAYING &&
333 border.draw_masked[GAME_MODE_PLAYING])
334 redraw_mask |= REDRAW_FIELD;
336 if (global.fps_slowdown && game_status == GAME_MODE_PLAYING)
338 static boolean last_frame_skipped = FALSE;
339 boolean skip_even_when_not_scrolling = TRUE;
340 boolean just_scrolling = (ScreenMovDir != 0);
341 boolean verbose = FALSE;
343 if (global.fps_slowdown_factor > 1 &&
344 (FrameCounter % global.fps_slowdown_factor) &&
345 (just_scrolling || skip_even_when_not_scrolling))
347 redraw_mask &= ~REDRAW_MAIN;
349 last_frame_skipped = TRUE;
352 printf("FRAME SKIPPED\n");
356 if (last_frame_skipped)
357 redraw_mask |= REDRAW_FIELD;
359 last_frame_skipped = FALSE;
362 printf("frame not skipped\n");
366 /* synchronize X11 graphics at this point; if we would synchronize the
367 display immediately after the buffer switching (after the XFlush),
368 this could mean that we have to wait for the graphics to complete,
369 although we could go on doing calculations for the next frame */
373 /* never draw masked border to backbuffer when using playfield buffer */
374 if (game_status != GAME_MODE_PLAYING ||
375 redraw_mask & REDRAW_FROM_BACKBUFFER ||
376 buffer == backbuffer)
377 DrawMaskedBorder(redraw_mask);
379 DrawMaskedBorder(redraw_mask & REDRAW_DOORS);
381 if (redraw_mask & REDRAW_ALL)
383 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
385 redraw_mask = REDRAW_NONE;
388 if (redraw_mask & REDRAW_FIELD)
391 printf("::: REDRAW_FIELD\n");
394 if (game_status != GAME_MODE_PLAYING ||
395 redraw_mask & REDRAW_FROM_BACKBUFFER)
397 BlitBitmap(backbuffer, window,
398 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE, REAL_SX, REAL_SY);
402 int fx = FX, fy = FY;
404 if (setup.soft_scrolling)
407 int dx = (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
408 int dy = (ScreenMovDir & (MV_UP | MV_DOWN) ? ScreenGfxPos : 0);
410 int bx1, bx2, ffx, ffy;
412 // fx += dx * TILESIZE_VAR / TILESIZE;
413 // fy += dy * TILESIZE_VAR / TILESIZE;
415 fx += (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
416 fy += (ScreenMovDir & (MV_UP | MV_DOWN) ? ScreenGfxPos : 0);
422 bx1 = SBX_Left * TILEX_VAR + TILEX_VAR / 2;
423 // bx1 = SBX_Left * TILEX_VAR;
424 bx2 = SBX_Right * TILEX_VAR - TILEX_VAR / 2;
425 ffx = scroll_x * TILEX_VAR + dx * TILESIZE_VAR / TILESIZE;
427 if (ffx > bx1) // && ffx < bx2)
428 fx += dx * TILESIZE_VAR / TILESIZE;
430 // fx += TILEX_VAR - (ffx - bx1) % TILEX_VAR;
432 printf("::: %d (%d, %d) (%d)\n", ffx, bx1, bx2, dx);
435 if (ffx > SBX_Left * TILEX_VAR)
436 fx -= MIN(ffx, TILEX_VAR / 2);
437 if (ffx > SBX_Left * TILEX_VAR && ffx < (SBX_Right + 1) * TILEX_VAR)
438 fx -= MIN(ffx, TILEX_VAR / 2);
442 ffx = (scroll_x - SBX_Left) * TILEX_VAR + dx * TILESIZE_VAR / TILESIZE;
444 if (EVEN(SCR_FIELDX))
446 if (ffx < SBX_Right * TILEX_VAR + TILEX_VAR / 2)
447 fx = fx + dx * TILESIZE_VAR / TILESIZE - MIN(ffx, TILEX_VAR / 2);
449 fx = fx - (dx <= 0 ? TILEX_VAR : 0);
451 printf("::: %d (%d, %d) [%d] [%d] => %d\n",
452 ffx, SBX_Left * TILEX_VAR, SBX_Right * TILEX_VAR, dx, FX, fx);
457 printf("::: %d, %d [%d, %d] [%d, %d] [%d, %d] [%d] [%d, %d]\n",
458 fx, fy, FX, FY, ScreenMovDir, ScreenGfxPos,
461 SBX_Left, SBX_Right);
468 fx = fx * TILESIZE_VAR / TILESIZE;
469 fy = fy * TILESIZE_VAR / TILESIZE;
474 if (setup.soft_scrolling ||
475 ABS(ScreenMovPos) + ScrollStepSize == TILEX ||
476 ABS(ScreenMovPos) == ScrollStepSize ||
477 redraw_tiles > REDRAWTILES_THRESHOLD)
479 if (border.draw_masked[GAME_MODE_PLAYING])
481 if (buffer != backbuffer)
483 /* copy playfield buffer to backbuffer to add masked border */
484 BlitBitmap(buffer, backbuffer, fx, fy, SXSIZE, SYSIZE, SX, SY);
485 DrawMaskedBorder(REDRAW_FIELD);
488 BlitBitmap(backbuffer, window,
489 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
494 BlitBitmap(buffer, window, fx, fy, SXSIZE, SYSIZE, SX, SY);
499 printf("redrawing all (ScreenGfxPos == %d) because %s\n",
501 (setup.soft_scrolling ?
502 "setup.soft_scrolling" :
503 ABS(ScreenGfxPos) + ScrollStepSize == TILEX ?
504 "ABS(ScreenGfxPos) + ScrollStepSize == TILEX" :
505 ABS(ScreenGfxPos) == ScrollStepSize ?
506 "ABS(ScreenGfxPos) == ScrollStepSize" :
507 "redraw_tiles > REDRAWTILES_THRESHOLD"));
513 redraw_mask &= ~REDRAW_MAIN;
516 if (redraw_mask & REDRAW_DOORS)
518 if (redraw_mask & REDRAW_DOOR_1)
519 BlitBitmap(backbuffer, window, DX, DY, DXSIZE, DYSIZE, DX, DY);
521 if (redraw_mask & REDRAW_DOOR_2)
522 BlitBitmap(backbuffer, window, VX, VY, VXSIZE, VYSIZE, VX, VY);
524 if (redraw_mask & REDRAW_DOOR_3)
525 BlitBitmap(backbuffer, window, EX, EY, EXSIZE, EYSIZE, EX, EY);
527 redraw_mask &= ~REDRAW_DOORS;
530 if (redraw_mask & REDRAW_MICROLEVEL)
532 BlitBitmap(backbuffer, window, SX, SY + 10 * TILEY, SXSIZE, 7 * TILEY,
533 SX, SY + 10 * TILEY);
535 redraw_mask &= ~REDRAW_MICROLEVEL;
538 if (redraw_mask & REDRAW_TILES)
541 printf("::: REDRAW_TILES\n");
545 for (x = 0; x < SCR_FIELDX; x++)
546 for (y = 0 ; y < SCR_FIELDY; y++)
547 if (redraw[redraw_x1 + x][redraw_y1 + y])
548 BlitBitmap(buffer, window,
549 FX + x * TILEX_VAR, FY + y * TILEY_VAR,
550 TILEX_VAR, TILEY_VAR,
551 SX + x * TILEX_VAR, SY + y * TILEY_VAR);
553 for (x = 0; x < SCR_FIELDX; x++)
554 for (y = 0 ; y < SCR_FIELDY; y++)
555 if (redraw[redraw_x1 + x][redraw_y1 + y])
556 BlitBitmap(buffer, window,
557 FX + x * TILEX, FY + y * TILEY, TILEX, TILEY,
558 SX + x * TILEX, SY + y * TILEY);
562 if (redraw_mask & REDRAW_FPS) /* display frames per second */
567 sprintf(info1, " (only every %d. frame)", global.fps_slowdown_factor);
568 if (!global.fps_slowdown)
571 sprintf(text, "%04.1f fps%s", global.frames_per_second, info1);
573 DrawTextExt(window, SX + SXSIZE + SX, 0, text, FONT_TEXT_2, BLIT_OPAQUE);
575 DrawTextExt(window, SX, SY, text, FONT_TEXT_2, BLIT_OPAQUE);
581 for (x = 0; x < MAX_BUF_XSIZE; x++)
582 for (y = 0; y < MAX_BUF_YSIZE; y++)
585 redraw_mask = REDRAW_NONE;
588 static void FadeCrossSaveBackbuffer()
590 BlitBitmap(backbuffer, bitmap_db_cross, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
593 static void FadeExt(int fade_mask, int fade_mode, int fade_type)
595 static int fade_type_skip = FADE_TYPE_NONE;
596 void (*draw_border_function)(void) = NULL;
597 Bitmap *bitmap = (fade_mode & FADE_TYPE_TRANSFORM ? bitmap_db_cross : NULL);
598 int x, y, width, height;
599 int fade_delay, post_delay;
601 if (fade_type == FADE_TYPE_FADE_OUT)
603 if (fade_type_skip != FADE_TYPE_NONE)
606 printf("::: skipping %d ... [%d] (X)\n", fade_mode, fade_type_skip);
609 /* skip all fade operations until specified fade operation */
610 if (fade_type & fade_type_skip)
611 fade_type_skip = FADE_TYPE_NONE;
616 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
618 FadeCrossSaveBackbuffer();
624 redraw_mask |= fade_mask;
626 if (fade_type == FADE_TYPE_SKIP)
629 printf("::: will skip %d ... [%d]\n", fade_mode, fade_type_skip);
632 fade_type_skip = fade_mode;
638 printf("::: !!! FADING %d ... [%d] [%d]\n", fade_mode, fade_type,
643 fade_delay = fading.fade_delay;
644 post_delay = (fade_mode == FADE_MODE_FADE_OUT ? fading.post_delay : 0);
647 if (fade_type_skip != FADE_TYPE_NONE)
650 printf("::: skipping %d ... [%d]\n", fade_mode, fade_type_skip);
653 /* skip all fade operations until specified fade operation */
654 if (fade_type & fade_type_skip)
655 fade_type_skip = FADE_TYPE_NONE;
665 if (global.autoplay_leveldir)
667 // fading.fade_mode = FADE_MODE_NONE;
674 if (fading.fade_mode == FADE_MODE_NONE)
682 /* !!! what about fade_mask == REDRAW_FIELD | REDRAW_ALL ??? !!! */
685 printf("::: NOW FADING %d ... [%d]\n", fade_mode, fade_type);
689 if (fade_mask == REDRAW_NONE)
690 fade_mask = REDRAW_FIELD;
693 // if (fade_mask & REDRAW_FIELD)
694 if (fade_mask == REDRAW_FIELD)
699 height = FULL_SYSIZE;
702 fade_delay = fading.fade_delay;
703 post_delay = (fade_mode == FADE_MODE_FADE_OUT ? fading.post_delay : 0);
706 if (border.draw_masked_when_fading)
707 draw_border_function = DrawMaskedBorder_FIELD; /* update when fading */
709 DrawMaskedBorder_FIELD(); /* draw once */
711 else /* REDRAW_ALL */
719 fade_delay = fading.fade_delay;
720 post_delay = (fade_mode == FADE_MODE_FADE_OUT ? fading.post_delay : 0);
725 if (!setup.fade_screens ||
727 fading.fade_mode == FADE_MODE_NONE)
729 if (!setup.fade_screens || fade_delay == 0)
732 if (fade_mode == FADE_MODE_FADE_OUT)
736 if (fade_mode == FADE_MODE_FADE_OUT &&
737 fading.fade_mode != FADE_MODE_NONE)
738 ClearRectangle(backbuffer, x, y, width, height);
742 BlitBitmap(backbuffer, window, x, y, width, height, x, y);
743 redraw_mask = REDRAW_NONE;
751 FadeRectangle(bitmap, x, y, width, height, fade_mode, fade_delay, post_delay,
752 draw_border_function);
754 redraw_mask &= ~fade_mask;
757 void FadeIn(int fade_mask)
759 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
760 FadeExt(fade_mask, fading.fade_mode, FADE_TYPE_FADE_IN);
762 FadeExt(fade_mask, FADE_MODE_FADE_IN, FADE_TYPE_FADE_IN);
765 void FadeOut(int fade_mask)
767 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
768 FadeExt(fade_mask, fading.fade_mode, FADE_TYPE_FADE_OUT);
770 FadeExt(fade_mask, FADE_MODE_FADE_OUT, FADE_TYPE_FADE_OUT);
772 global.border_status = game_status;
775 static void FadeSetLeaveNext(struct TitleFadingInfo fading_leave, boolean set)
777 static struct TitleFadingInfo fading_leave_stored;
780 fading_leave_stored = fading_leave;
782 fading = fading_leave_stored;
785 void FadeSetEnterMenu()
787 fading = menu.enter_menu;
790 printf("::: storing enter_menu\n");
793 FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
796 void FadeSetLeaveMenu()
798 fading = menu.leave_menu;
801 printf("::: storing leave_menu\n");
804 FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
807 void FadeSetEnterScreen()
809 fading = menu.enter_screen[game_status];
812 printf("::: storing leave_screen[%d]\n", game_status);
815 FadeSetLeaveNext(menu.leave_screen[game_status], TRUE); /* store */
818 void FadeSetNextScreen()
820 fading = menu.next_screen;
823 printf("::: storing next_screen\n");
826 // (do not overwrite fade mode set by FadeSetEnterScreen)
827 // FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
830 void FadeSetLeaveScreen()
833 printf("::: recalling last stored value\n");
836 FadeSetLeaveNext(menu.leave_screen[game_status], FALSE); /* recall */
839 void FadeSetFromType(int type)
841 if (type & TYPE_ENTER_SCREEN)
842 FadeSetEnterScreen();
843 else if (type & TYPE_ENTER)
845 else if (type & TYPE_LEAVE)
849 void FadeSetDisabled()
851 static struct TitleFadingInfo fading_none = { FADE_MODE_NONE, -1, -1, -1 };
853 fading = fading_none;
856 void FadeSkipNextFadeIn()
858 FadeExt(0, FADE_MODE_SKIP_FADE_IN, FADE_TYPE_SKIP);
861 void FadeSkipNextFadeOut()
863 FadeExt(0, FADE_MODE_SKIP_FADE_OUT, FADE_TYPE_SKIP);
866 void SetWindowBackgroundImageIfDefined(int graphic)
868 if (graphic_info[graphic].bitmap)
869 SetWindowBackgroundBitmap(graphic_info[graphic].bitmap);
872 void SetMainBackgroundImageIfDefined(int graphic)
874 if (graphic_info[graphic].bitmap)
875 SetMainBackgroundBitmap(graphic_info[graphic].bitmap);
878 void SetDoorBackgroundImageIfDefined(int graphic)
880 if (graphic_info[graphic].bitmap)
881 SetDoorBackgroundBitmap(graphic_info[graphic].bitmap);
884 void SetWindowBackgroundImage(int graphic)
886 SetWindowBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
887 graphic_info[graphic].bitmap ?
888 graphic_info[graphic].bitmap :
889 graphic_info[IMG_BACKGROUND].bitmap);
892 void SetMainBackgroundImage(int graphic)
894 SetMainBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
895 graphic_info[graphic].bitmap ?
896 graphic_info[graphic].bitmap :
897 graphic_info[IMG_BACKGROUND].bitmap);
900 void SetDoorBackgroundImage(int graphic)
902 SetDoorBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
903 graphic_info[graphic].bitmap ?
904 graphic_info[graphic].bitmap :
905 graphic_info[IMG_BACKGROUND].bitmap);
908 void SetPanelBackground()
911 struct GraphicInfo *gfx = &graphic_info[IMG_BACKGROUND_PANEL];
914 BlitBitmapTiled(gfx->bitmap, bitmap_db_panel, gfx->src_x, gfx->src_y,
915 gfx->width, gfx->height, 0, 0, DXSIZE, DYSIZE);
917 /* (ClearRectangle() only needed if panel bitmap is smaller than panel) */
918 ClearRectangle(bitmap_db_panel, DX, DY, DXSIZE, DYSIZE);
919 BlitBitmap(gfx->bitmap, bitmap_db_panel, gfx->src_x, gfx->src_y,
920 MIN(gfx->width, DXSIZE), MIN(gfx->height, DYSIZE), 0, 0);
923 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, bitmap_db_panel,
924 DOOR_GFX_PAGEX5, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE, 0, 0);
927 SetDoorBackgroundBitmap(bitmap_db_panel);
930 void DrawBackground(int x, int y, int width, int height)
932 /* !!! "drawto" might still point to playfield buffer here (see below) !!! */
933 /* (when entering hall of fame after playing) */
935 ClearRectangleOnBackground(drawto, x, y, width, height);
937 ClearRectangleOnBackground(backbuffer, x, y, width, height);
940 redraw_mask |= REDRAW_FIELD;
943 void DrawBackgroundForFont(int x, int y, int width, int height, int font_nr)
945 struct FontBitmapInfo *font = getFontBitmapInfo(font_nr);
947 if (font->bitmap == NULL)
950 DrawBackground(x, y, width, height);
953 void DrawBackgroundForGraphic(int x, int y, int width, int height, int graphic)
955 struct GraphicInfo *g = &graphic_info[graphic];
957 if (g->bitmap == NULL)
960 DrawBackground(x, y, width, height);
965 /* !!! "drawto" might still point to playfield buffer here (see above) !!! */
966 /* (when entering hall of fame after playing) */
967 DrawBackground(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
969 /* !!! maybe this should be done before clearing the background !!! */
970 if (setup.soft_scrolling && game_status == GAME_MODE_PLAYING)
972 ClearRectangle(fieldbuffer, 0, 0, FXSIZE, FYSIZE);
973 SetDrawtoField(DRAW_BUFFERED);
976 SetDrawtoField(DRAW_BACKBUFFER);
979 void MarkTileDirty(int x, int y)
981 int xx = redraw_x1 + x;
982 int yy = redraw_y1 + y;
987 redraw[xx][yy] = TRUE;
988 redraw_mask |= REDRAW_TILES;
991 void SetBorderElement()
995 BorderElement = EL_EMPTY;
997 for (y = 0; y < lev_fieldy && BorderElement == EL_EMPTY; y++)
999 for (x = 0; x < lev_fieldx; x++)
1001 if (!IS_INDESTRUCTIBLE(Feld[x][y]))
1002 BorderElement = EL_STEELWALL;
1004 if (y != 0 && y != lev_fieldy - 1 && x != lev_fieldx - 1)
1010 void FloodFillLevel(int from_x, int from_y, int fill_element,
1011 short field[MAX_LEV_FIELDX][MAX_LEV_FIELDY],
1012 int max_fieldx, int max_fieldy)
1016 static int check[4][2] = { { -1, 0 }, { 0, -1 }, { 1, 0 }, { 0, 1 } };
1017 static int safety = 0;
1019 /* check if starting field still has the desired content */
1020 if (field[from_x][from_y] == fill_element)
1025 if (safety > max_fieldx * max_fieldy)
1026 Error(ERR_EXIT, "Something went wrong in 'FloodFill()'. Please debug.");
1028 old_element = field[from_x][from_y];
1029 field[from_x][from_y] = fill_element;
1031 for (i = 0; i < 4; i++)
1033 x = from_x + check[i][0];
1034 y = from_y + check[i][1];
1036 if (IN_FIELD(x, y, max_fieldx, max_fieldy) && field[x][y] == old_element)
1037 FloodFillLevel(x, y, fill_element, field, max_fieldx, max_fieldy);
1043 void SetRandomAnimationValue(int x, int y)
1045 gfx.anim_random_frame = GfxRandom[x][y];
1048 inline int getGraphicAnimationFrame(int graphic, int sync_frame)
1050 /* animation synchronized with global frame counter, not move position */
1051 if (graphic_info[graphic].anim_global_sync || sync_frame < 0)
1052 sync_frame = FrameCounter;
1054 return getAnimationFrame(graphic_info[graphic].anim_frames,
1055 graphic_info[graphic].anim_delay,
1056 graphic_info[graphic].anim_mode,
1057 graphic_info[graphic].anim_start_frame,
1061 void getSizedGraphicSourceExt(int graphic, int frame, int tilesize_raw,
1062 Bitmap **bitmap, int *x, int *y,
1063 boolean get_backside)
1067 int width_mult, width_div;
1068 int height_mult, height_div;
1072 { 15, 16, 2, 3 }, /* 1 x 1 */
1073 { 7, 8, 2, 3 }, /* 2 x 2 */
1074 { 3, 4, 2, 3 }, /* 4 x 4 */
1075 { 1, 2, 2, 3 }, /* 8 x 8 */
1076 { 0, 1, 2, 3 }, /* 16 x 16 */
1077 { 0, 1, 0, 1 }, /* 32 x 32 */
1079 struct GraphicInfo *g = &graphic_info[graphic];
1080 Bitmap *src_bitmap = g->bitmap;
1081 int tilesize = MIN(MAX(1, tilesize_raw), TILESIZE);
1082 int offset_calc_pos = log_2(tilesize);
1083 int width_mult = offset_calc[offset_calc_pos].width_mult;
1084 int width_div = offset_calc[offset_calc_pos].width_div;
1085 int height_mult = offset_calc[offset_calc_pos].height_mult;
1086 int height_div = offset_calc[offset_calc_pos].height_div;
1087 int startx = src_bitmap->width * width_mult / width_div;
1088 int starty = src_bitmap->height * height_mult / height_div;
1090 int src_x = (g->src_x + (get_backside ? g->offset2_x : 0)) *
1091 tilesize / TILESIZE;
1092 int src_y = (g->src_y + (get_backside ? g->offset2_y : 0)) *
1093 tilesize / TILESIZE;
1095 int src_x = g->src_x * tilesize / TILESIZE;
1096 int src_y = g->src_y * tilesize / TILESIZE;
1098 int width = g->width * tilesize / TILESIZE;
1099 int height = g->height * tilesize / TILESIZE;
1100 int offset_x = g->offset_x * tilesize / TILESIZE;
1101 int offset_y = g->offset_y * tilesize / TILESIZE;
1103 if (g->offset_y == 0) /* frames are ordered horizontally */
1105 int max_width = g->anim_frames_per_line * width;
1106 int pos = (src_y / height) * max_width + src_x + frame * offset_x;
1108 src_x = pos % max_width;
1109 src_y = src_y % height + pos / max_width * height;
1111 else if (g->offset_x == 0) /* frames are ordered vertically */
1113 int max_height = g->anim_frames_per_line * height;
1114 int pos = (src_x / width) * max_height + src_y + frame * offset_y;
1116 src_x = src_x % width + pos / max_height * width;
1117 src_y = pos % max_height;
1119 else /* frames are ordered diagonally */
1121 src_x = src_x + frame * offset_x;
1122 src_y = src_y + frame * offset_y;
1125 *bitmap = src_bitmap;
1126 *x = startx + src_x;
1127 *y = starty + src_y;
1130 void getFixedGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
1131 int *x, int *y, boolean get_backside)
1133 getSizedGraphicSourceExt(graphic, frame, TILESIZE, bitmap, x, y,
1137 void getSizedGraphicSource(int graphic, int frame, int tilesize_raw,
1138 Bitmap **bitmap, int *x, int *y)
1140 getSizedGraphicSourceExt(graphic, frame, tilesize_raw, bitmap, x, y, FALSE);
1143 void getFixedGraphicSource(int graphic, int frame,
1144 Bitmap **bitmap, int *x, int *y)
1146 getSizedGraphicSourceExt(graphic, frame, TILESIZE, bitmap, x, y, FALSE);
1149 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
1152 getSizedGraphicSource(graphic, 0, MINI_TILESIZE, bitmap, x, y);
1154 struct GraphicInfo *g = &graphic_info[graphic];
1155 int mini_startx = 0;
1156 int mini_starty = g->bitmap->height * 2 / 3;
1158 *bitmap = g->bitmap;
1159 *x = mini_startx + g->src_x / 2;
1160 *y = mini_starty + g->src_y / 2;
1164 inline void getGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
1165 int *x, int *y, boolean get_backside)
1167 struct GraphicInfo *g = &graphic_info[graphic];
1168 int src_x = g->src_x + (get_backside ? g->offset2_x : 0);
1169 int src_y = g->src_y + (get_backside ? g->offset2_y : 0);
1172 if (TILESIZE_VAR != TILESIZE)
1173 return getSizedGraphicSourceExt(graphic, frame, TILESIZE_VAR, bitmap, x, y,
1177 *bitmap = g->bitmap;
1179 if (g->offset_y == 0) /* frames are ordered horizontally */
1181 int max_width = g->anim_frames_per_line * g->width;
1182 int pos = (src_y / g->height) * max_width + src_x + frame * g->offset_x;
1184 *x = pos % max_width;
1185 *y = src_y % g->height + pos / max_width * g->height;
1187 else if (g->offset_x == 0) /* frames are ordered vertically */
1189 int max_height = g->anim_frames_per_line * g->height;
1190 int pos = (src_x / g->width) * max_height + src_y + frame * g->offset_y;
1192 *x = src_x % g->width + pos / max_height * g->width;
1193 *y = pos % max_height;
1195 else /* frames are ordered diagonally */
1197 *x = src_x + frame * g->offset_x;
1198 *y = src_y + frame * g->offset_y;
1202 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
1204 getGraphicSourceExt(graphic, frame, bitmap, x, y, FALSE);
1207 void DrawGraphic(int x, int y, int graphic, int frame)
1210 if (!IN_SCR_FIELD(x, y))
1212 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
1213 printf("DrawGraphic(): This should never happen!\n");
1219 DrawGraphicExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR, graphic,
1222 DrawGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic, frame);
1224 MarkTileDirty(x, y);
1227 void DrawFixedGraphic(int x, int y, int graphic, int frame)
1230 if (!IN_SCR_FIELD(x, y))
1232 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
1233 printf("DrawGraphic(): This should never happen!\n");
1238 DrawFixedGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic,
1240 MarkTileDirty(x, y);
1243 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
1249 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1251 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX_VAR, TILEY_VAR, x, y);
1253 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
1257 void DrawFixedGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
1263 getFixedGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1264 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
1267 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
1270 if (!IN_SCR_FIELD(x, y))
1272 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
1273 printf("DrawGraphicThruMask(): This should never happen!\n");
1279 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR,
1282 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic,
1285 MarkTileDirty(x, y);
1288 void DrawFixedGraphicThruMask(int x, int y, int graphic, int frame)
1291 if (!IN_SCR_FIELD(x, y))
1293 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
1294 printf("DrawGraphicThruMask(): This should never happen!\n");
1299 DrawFixedGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
1301 MarkTileDirty(x, y);
1304 void DrawGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y, int graphic,
1310 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1312 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1313 dst_x - src_x, dst_y - src_y);
1315 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX_VAR, TILEY_VAR,
1318 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dst_x, dst_y);
1322 void DrawFixedGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y,
1323 int graphic, int frame)
1328 getFixedGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1330 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1331 dst_x - src_x, dst_y - src_y);
1332 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dst_x, dst_y);
1335 void DrawSizedGraphic(int x, int y, int graphic, int frame, int tilesize)
1337 DrawSizedGraphicExt(drawto, SX + x * tilesize, SY + y * tilesize, graphic,
1339 MarkTileDirty(x / tilesize, y / tilesize);
1342 void DrawSizedGraphicExt(DrawBuffer *d, int x, int y, int graphic, int frame,
1348 getSizedGraphicSource(graphic, frame, tilesize, &src_bitmap, &src_x, &src_y);
1349 BlitBitmap(src_bitmap, d, src_x, src_y, tilesize, tilesize, x, y);
1352 void DrawMiniGraphic(int x, int y, int graphic)
1354 DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
1355 MarkTileDirty(x / 2, y / 2);
1358 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
1363 getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1364 BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
1367 inline static void DrawGraphicShiftedNormal(int x, int y, int dx, int dy,
1368 int graphic, int frame,
1369 int cut_mode, int mask_mode)
1374 int width = TILEX, height = TILEY;
1377 if (dx || dy) /* shifted graphic */
1379 if (x < BX1) /* object enters playfield from the left */
1386 else if (x > BX2) /* object enters playfield from the right */
1392 else if (x==BX1 && dx < 0) /* object leaves playfield to the left */
1398 else if (x==BX2 && dx > 0) /* object leaves playfield to the right */
1400 else if (dx) /* general horizontal movement */
1401 MarkTileDirty(x + SIGN(dx), y);
1403 if (y < BY1) /* object enters playfield from the top */
1405 if (cut_mode==CUT_BELOW) /* object completely above top border */
1413 else if (y > BY2) /* object enters playfield from the bottom */
1419 else if (y==BY1 && dy < 0) /* object leaves playfield to the top */
1425 else if (dy > 0 && cut_mode == CUT_ABOVE)
1427 if (y == BY2) /* object completely above bottom border */
1433 MarkTileDirty(x, y + 1);
1434 } /* object leaves playfield to the bottom */
1435 else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
1437 else if (dy) /* general vertical movement */
1438 MarkTileDirty(x, y + SIGN(dy));
1442 if (!IN_SCR_FIELD(x, y))
1444 printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
1445 printf("DrawGraphicShifted(): This should never happen!\n");
1451 width = width * TILESIZE_VAR / TILESIZE;
1452 height = height * TILESIZE_VAR / TILESIZE;
1453 cx = cx * TILESIZE_VAR / TILESIZE;
1454 cy = cy * TILESIZE_VAR / TILESIZE;
1455 dx = dx * TILESIZE_VAR / TILESIZE;
1456 dy = dy * TILESIZE_VAR / TILESIZE;
1459 if (width > 0 && height > 0)
1461 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1467 dst_x = FX + x * TILEX_VAR + dx;
1468 dst_y = FY + y * TILEY_VAR + dy;
1470 dst_x = FX + x * TILEX + dx;
1471 dst_y = FY + y * TILEY + dy;
1474 if (mask_mode == USE_MASKING)
1476 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1477 dst_x - src_x, dst_y - src_y);
1478 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1482 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1485 MarkTileDirty(x, y);
1489 inline static void DrawGraphicShiftedDouble(int x, int y, int dx, int dy,
1490 int graphic, int frame,
1491 int cut_mode, int mask_mode)
1497 int width = TILEX_VAR, height = TILEY_VAR;
1499 int width = TILEX, height = TILEY;
1503 int x2 = x + SIGN(dx);
1504 int y2 = y + SIGN(dy);
1506 /* !!! DOES NOT WORK FOR SLOW MOVEMENT !!! */
1507 int sync_frame = GfxFrame[LEVELX(x)][LEVELY(y)];
1509 /* movement with two-tile animations must be sync'ed with movement position,
1510 not with current GfxFrame (which can be higher when using slow movement) */
1511 int anim_pos = (dx ? ABS(dx) : ABS(dy));
1512 int anim_frames = graphic_info[graphic].anim_frames;
1514 /* (we also need anim_delay here for movement animations with less frames) */
1515 int anim_delay = graphic_info[graphic].anim_delay;
1516 int sync_frame = anim_pos * anim_frames * anim_delay / TILESIZE;
1518 int sync_frame = anim_pos * anim_frames / TILESIZE;
1521 boolean draw_start_tile = (cut_mode != CUT_ABOVE); /* only for falling! */
1522 boolean draw_end_tile = (cut_mode != CUT_BELOW); /* only for falling! */
1524 /* re-calculate animation frame for two-tile movement animation */
1525 frame = getGraphicAnimationFrame(graphic, sync_frame);
1529 printf("::: %d, %d, %d => %d [%d]\n",
1530 anim_pos, anim_frames, anim_delay, sync_frame, graphic);
1532 printf("::: %d, %d => %d\n",
1533 anim_pos, anim_frames, sync_frame);
1538 printf("::: %d [%d, %d] [%d] [%d]\n", frame, sync_frame, dy,
1539 GfxFrame[LEVELX(x)][LEVELY(y)], mask_mode);
1542 /* check if movement start graphic inside screen area and should be drawn */
1543 if (draw_start_tile && IN_SCR_FIELD(x1, y1))
1545 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, TRUE);
1548 dst_x = FX + x1 * TILEX_VAR;
1549 dst_y = FY + y1 * TILEY_VAR;
1551 dst_x = FX + x1 * TILEX;
1552 dst_y = FY + y1 * TILEY;
1555 if (mask_mode == USE_MASKING)
1557 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1558 dst_x - src_x, dst_y - src_y);
1559 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1563 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1566 MarkTileDirty(x1, y1);
1569 /* check if movement end graphic inside screen area and should be drawn */
1570 if (draw_end_tile && IN_SCR_FIELD(x2, y2))
1572 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
1575 dst_x = FX + x2 * TILEX_VAR;
1576 dst_y = FY + y2 * TILEY_VAR;
1578 dst_x = FX + x2 * TILEX;
1579 dst_y = FY + y2 * TILEY;
1582 if (mask_mode == USE_MASKING)
1584 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1585 dst_x - src_x, dst_y - src_y);
1586 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1590 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1593 MarkTileDirty(x2, y2);
1597 static void DrawGraphicShifted(int x, int y, int dx, int dy,
1598 int graphic, int frame,
1599 int cut_mode, int mask_mode)
1603 DrawGraphic(x, y, graphic, frame);
1608 if (graphic_info[graphic].double_movement) /* EM style movement images */
1609 DrawGraphicShiftedDouble(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1611 DrawGraphicShiftedNormal(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1614 void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
1615 int frame, int cut_mode)
1617 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, USE_MASKING);
1620 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
1621 int cut_mode, int mask_mode)
1623 int lx = LEVELX(x), ly = LEVELY(y);
1627 if (IN_LEV_FIELD(lx, ly))
1629 SetRandomAnimationValue(lx, ly);
1631 graphic = el_act_dir2img(element, GfxAction[lx][ly], GfxDir[lx][ly]);
1632 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1634 /* do not use double (EM style) movement graphic when not moving */
1635 if (graphic_info[graphic].double_movement && !dx && !dy)
1637 graphic = el_act_dir2img(element, ACTION_DEFAULT, GfxDir[lx][ly]);
1638 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1641 else /* border element */
1643 graphic = el2img(element);
1644 frame = getGraphicAnimationFrame(graphic, -1);
1647 if (element == EL_EXPANDABLE_WALL)
1649 boolean left_stopped = FALSE, right_stopped = FALSE;
1651 if (!IN_LEV_FIELD(lx - 1, ly) || IS_WALL(Feld[lx - 1][ly]))
1652 left_stopped = TRUE;
1653 if (!IN_LEV_FIELD(lx + 1, ly) || IS_WALL(Feld[lx + 1][ly]))
1654 right_stopped = TRUE;
1656 if (left_stopped && right_stopped)
1658 else if (left_stopped)
1660 graphic = IMG_EXPANDABLE_WALL_GROWING_RIGHT;
1661 frame = graphic_info[graphic].anim_frames - 1;
1663 else if (right_stopped)
1665 graphic = IMG_EXPANDABLE_WALL_GROWING_LEFT;
1666 frame = graphic_info[graphic].anim_frames - 1;
1671 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
1672 else if (mask_mode == USE_MASKING)
1673 DrawGraphicThruMask(x, y, graphic, frame);
1675 DrawGraphic(x, y, graphic, frame);
1678 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
1679 int cut_mode, int mask_mode)
1681 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1682 DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
1683 cut_mode, mask_mode);
1686 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
1689 DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1692 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
1695 DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1698 void DrawLevelElementThruMask(int x, int y, int element)
1700 DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1703 void DrawLevelFieldThruMask(int x, int y)
1705 DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
1708 /* !!! implementation of quicksand is totally broken !!! */
1709 #define IS_CRUMBLED_TILE(x, y, e) \
1710 (GFX_CRUMBLED(e) && (!IN_LEV_FIELD(x, y) || \
1711 !IS_MOVING(x, y) || \
1712 (e) == EL_QUICKSAND_EMPTYING || \
1713 (e) == EL_QUICKSAND_FAST_EMPTYING))
1715 static void DrawLevelFieldCrumbledInnerCorners(int x, int y, int dx, int dy,
1720 int width, height, cx, cy;
1721 int sx = SCREENX(x), sy = SCREENY(y);
1722 int crumbled_border_size = graphic_info[graphic].border_size;
1725 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1727 for (i = 1; i < 4; i++)
1729 int dxx = (i & 1 ? dx : 0);
1730 int dyy = (i & 2 ? dy : 0);
1733 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1736 /* check if neighbour field is of same crumble type */
1737 boolean same = (IS_CRUMBLED_TILE(xx, yy, element) &&
1738 graphic_info[graphic].class ==
1739 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class);
1741 /* return if check prevents inner corner */
1742 if (same == (dxx == dx && dyy == dy))
1746 /* if we reach this point, we have an inner corner */
1748 getGraphicSource(graphic, 1, &src_bitmap, &src_x, &src_y);
1751 width = crumbled_border_size * TILESIZE_VAR / TILESIZE;
1752 height = crumbled_border_size * TILESIZE_VAR / TILESIZE;
1753 cx = (dx > 0 ? TILEX - crumbled_border_size : 0) * TILESIZE_VAR / TILESIZE;
1754 cy = (dy > 0 ? TILEY - crumbled_border_size : 0) * TILESIZE_VAR / TILESIZE;
1756 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1757 width, height, FX + sx * TILEX_VAR + cx, FY + sy * TILEY_VAR + cy);
1759 width = crumbled_border_size;
1760 height = crumbled_border_size;
1761 cx = (dx > 0 ? TILEX - crumbled_border_size : 0);
1762 cy = (dy > 0 ? TILEY - crumbled_border_size : 0);
1764 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1765 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
1769 static void DrawLevelFieldCrumbledBorders(int x, int y, int graphic, int frame,
1774 int width, height, bx, by, cx, cy;
1775 int sx = SCREENX(x), sy = SCREENY(y);
1776 int crumbled_border_size = graphic_info[graphic].border_size;
1779 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1781 /* draw simple, sloppy, non-corner-accurate crumbled border */
1784 width = (dir == 1 || dir == 2 ? crumbled_border_size : TILEX);
1785 height = (dir == 0 || dir == 3 ? crumbled_border_size : TILEY);
1786 cx = (dir == 2 ? TILEX - crumbled_border_size : 0);
1787 cy = (dir == 3 ? TILEY - crumbled_border_size : 0);
1789 if (dir == 1 || dir == 2) /* left or right crumbled border */
1791 width = crumbled_border_size;
1793 cx = (dir == 2 ? TILEX - crumbled_border_size : 0);
1796 else /* top or bottom crumbled border */
1799 height = crumbled_border_size;
1801 cy = (dir == 3 ? TILEY - crumbled_border_size : 0);
1806 BlitBitmap(src_bitmap, drawto_field,
1807 src_x + cx * TILESIZE_VAR / TILESIZE,
1808 src_y + cy * TILESIZE_VAR / TILESIZE,
1809 width * TILESIZE_VAR / TILESIZE,
1810 height * TILESIZE_VAR / TILESIZE,
1811 FX + sx * TILEX_VAR + cx * TILESIZE_VAR / TILESIZE,
1812 FY + sy * TILEY_VAR + cy * TILESIZE_VAR / TILESIZE);
1814 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1815 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
1818 /* (remaining middle border part must be at least as big as corner part) */
1819 if (!(graphic_info[graphic].style & STYLE_ACCURATE_BORDERS) ||
1820 crumbled_border_size >= TILESIZE / 3)
1823 /* correct corners of crumbled border, if needed */
1826 for (i = -1; i <= 1; i+=2)
1828 int xx = x + (dir == 0 || dir == 3 ? i : 0);
1829 int yy = y + (dir == 1 || dir == 2 ? i : 0);
1830 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1833 /* check if neighbour field is of same crumble type */
1834 if (IS_CRUMBLED_TILE(xx, yy, element) &&
1835 graphic_info[graphic].class ==
1836 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
1838 /* no crumbled corner, but continued crumbled border */
1840 int c1 = (dir == 2 || dir == 3 ? TILESIZE - crumbled_border_size : 0);
1841 int c2 = (i == 1 ? TILESIZE - crumbled_border_size : 0);
1842 int b1 = (i == 1 ? crumbled_border_size :
1843 TILESIZE - 2 * crumbled_border_size);
1845 width = crumbled_border_size;
1846 height = crumbled_border_size;
1848 if (dir == 1 || dir == 2)
1864 BlitBitmap(src_bitmap, drawto_field,
1865 src_x + bx * TILESIZE_VAR / TILESIZE,
1866 src_y + by * TILESIZE_VAR / TILESIZE,
1867 width * TILESIZE_VAR / TILESIZE,
1868 height * TILESIZE_VAR / TILESIZE,
1869 FX + sx * TILEX_VAR + cx * TILESIZE_VAR / TILESIZE,
1870 FY + sy * TILEY_VAR + cy * TILESIZE_VAR / TILESIZE);
1872 BlitBitmap(src_bitmap, drawto_field, src_x + bx, src_y + by,
1873 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
1878 if (dir == 1 || dir == 2) /* left or right crumbled border */
1880 for (i = -1; i <= 1; i+=2)
1884 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1887 /* check if neighbour field is of same crumble type */
1888 if (IS_CRUMBLED_TILE(xx, yy, element) &&
1889 graphic_info[graphic].class ==
1890 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
1892 /* no crumbled corner, but continued crumbled border */
1894 width = crumbled_border_size;
1895 height = crumbled_border_size;
1896 cx = (dir == 2 ? TILEX - crumbled_border_size : 0);
1897 cy = (i == 1 ? TILEY - crumbled_border_size : 0);
1899 by = (i == 1 ? crumbled_border_size :
1900 TILEY - 2 * crumbled_border_size);
1902 BlitBitmap(src_bitmap, drawto_field, src_x + bx, src_y + by,
1903 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
1907 else /* top or bottom crumbled border */
1909 for (i = -1; i <= 1; i+=2)
1913 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1916 /* check if neighbour field is of same crumble type */
1917 if (IS_CRUMBLED_TILE(xx, yy, element) &&
1918 graphic_info[graphic].class ==
1919 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
1921 /* no crumbled corner, but continued crumbled border */
1923 width = crumbled_border_size;
1924 height = crumbled_border_size;
1925 cx = (i == 1 ? TILEX - crumbled_border_size : 0);
1926 cy = (dir == 3 ? TILEY - crumbled_border_size : 0);
1927 bx = (i == 1 ? crumbled_border_size :
1928 TILEX - 2 * crumbled_border_size);
1931 BlitBitmap(src_bitmap, drawto_field, src_x + bx, src_y + by,
1932 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
1939 static void DrawLevelFieldCrumbledExt(int x, int y, int graphic, int frame)
1941 int sx = SCREENX(x), sy = SCREENY(y);
1944 static int xy[4][2] =
1952 if (!IN_LEV_FIELD(x, y))
1955 element = TILE_GFX_ELEMENT(x, y);
1957 /* crumble field itself */
1958 if (IS_CRUMBLED_TILE(x, y, element))
1960 if (!IN_SCR_FIELD(sx, sy))
1963 for (i = 0; i < 4; i++)
1965 int xx = x + xy[i][0];
1966 int yy = y + xy[i][1];
1968 element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1971 /* check if neighbour field is of same crumble type */
1973 if (IS_CRUMBLED_TILE(xx, yy, element) &&
1974 graphic_info[graphic].class ==
1975 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
1978 if (IS_CRUMBLED_TILE(xx, yy, element))
1982 DrawLevelFieldCrumbledBorders(x, y, graphic, frame, i);
1985 if ((graphic_info[graphic].style & STYLE_INNER_CORNERS) &&
1986 graphic_info[graphic].anim_frames == 2)
1988 for (i = 0; i < 4; i++)
1990 int dx = (i & 1 ? +1 : -1);
1991 int dy = (i & 2 ? +1 : -1);
1993 DrawLevelFieldCrumbledInnerCorners(x, y, dx, dy, graphic);
1997 MarkTileDirty(sx, sy);
1999 else /* center field not crumbled -- crumble neighbour fields */
2001 for (i = 0; i < 4; i++)
2003 int xx = x + xy[i][0];
2004 int yy = y + xy[i][1];
2005 int sxx = sx + xy[i][0];
2006 int syy = sy + xy[i][1];
2008 if (!IN_LEV_FIELD(xx, yy) ||
2009 !IN_SCR_FIELD(sxx, syy))
2012 if (Feld[xx][yy] == EL_ELEMENT_SNAPPING)
2015 element = TILE_GFX_ELEMENT(xx, yy);
2017 if (!IS_CRUMBLED_TILE(xx, yy, element))
2020 graphic = el_act2crm(element, ACTION_DEFAULT);
2022 DrawLevelFieldCrumbledBorders(xx, yy, graphic, 0, 3 - i);
2024 MarkTileDirty(sxx, syy);
2029 void DrawLevelFieldCrumbled(int x, int y)
2033 if (!IN_LEV_FIELD(x, y))
2037 /* !!! CHECK THIS !!! */
2040 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
2041 GFX_CRUMBLED(GfxElement[x][y]))
2044 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
2045 GfxElement[x][y] != EL_UNDEFINED &&
2046 GFX_CRUMBLED(GfxElement[x][y]))
2048 DrawLevelFieldCrumbledDigging(x, y, GfxDir[x][y], GfxFrame[x][y]);
2055 graphic = el_act2crm(TILE_GFX_ELEMENT(x, y), ACTION_DEFAULT);
2057 graphic = el_act2crm(Feld[x][y], ACTION_DEFAULT);
2060 DrawLevelFieldCrumbledExt(x, y, graphic, 0);
2063 void DrawLevelFieldCrumbledDigging(int x, int y, int direction,
2066 int graphic1 = el_act_dir2img(GfxElement[x][y], ACTION_DIGGING, direction);
2067 int graphic2 = el_act_dir2crm(GfxElement[x][y], ACTION_DIGGING, direction);
2068 int frame1 = getGraphicAnimationFrame(graphic1, step_frame);
2069 int frame2 = getGraphicAnimationFrame(graphic2, step_frame);
2070 int sx = SCREENX(x), sy = SCREENY(y);
2072 DrawGraphic(sx, sy, graphic1, frame1);
2073 DrawLevelFieldCrumbledExt(x, y, graphic2, frame2);
2076 void DrawLevelFieldCrumbledNeighbours(int x, int y)
2078 int sx = SCREENX(x), sy = SCREENY(y);
2079 static int xy[4][2] =
2088 for (i = 0; i < 4; i++)
2090 int xx = x + xy[i][0];
2091 int yy = y + xy[i][1];
2092 int sxx = sx + xy[i][0];
2093 int syy = sy + xy[i][1];
2095 if (!IN_LEV_FIELD(xx, yy) ||
2096 !IN_SCR_FIELD(sxx, syy) ||
2097 !GFX_CRUMBLED(Feld[xx][yy]) ||
2101 DrawLevelField(xx, yy);
2105 static int getBorderElement(int x, int y)
2109 { EL_STEELWALL_TOPLEFT, EL_INVISIBLE_STEELWALL_TOPLEFT },
2110 { EL_STEELWALL_TOPRIGHT, EL_INVISIBLE_STEELWALL_TOPRIGHT },
2111 { EL_STEELWALL_BOTTOMLEFT, EL_INVISIBLE_STEELWALL_BOTTOMLEFT },
2112 { EL_STEELWALL_BOTTOMRIGHT, EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
2113 { EL_STEELWALL_VERTICAL, EL_INVISIBLE_STEELWALL_VERTICAL },
2114 { EL_STEELWALL_HORIZONTAL, EL_INVISIBLE_STEELWALL_HORIZONTAL },
2115 { EL_STEELWALL, EL_INVISIBLE_STEELWALL }
2117 int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
2118 int steel_position = (x == -1 && y == -1 ? 0 :
2119 x == lev_fieldx && y == -1 ? 1 :
2120 x == -1 && y == lev_fieldy ? 2 :
2121 x == lev_fieldx && y == lev_fieldy ? 3 :
2122 x == -1 || x == lev_fieldx ? 4 :
2123 y == -1 || y == lev_fieldy ? 5 : 6);
2125 return border[steel_position][steel_type];
2128 void DrawScreenElement(int x, int y, int element)
2130 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
2131 DrawLevelFieldCrumbled(LEVELX(x), LEVELY(y));
2134 void DrawLevelElement(int x, int y, int element)
2136 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
2137 DrawScreenElement(SCREENX(x), SCREENY(y), element);
2140 void DrawScreenField(int x, int y)
2142 int lx = LEVELX(x), ly = LEVELY(y);
2143 int element, content;
2145 if (!IN_LEV_FIELD(lx, ly))
2147 if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
2150 element = getBorderElement(lx, ly);
2152 DrawScreenElement(x, y, element);
2157 element = Feld[lx][ly];
2158 content = Store[lx][ly];
2160 if (IS_MOVING(lx, ly))
2162 int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
2163 boolean cut_mode = NO_CUTTING;
2165 if (element == EL_QUICKSAND_EMPTYING ||
2166 element == EL_QUICKSAND_FAST_EMPTYING ||
2167 element == EL_MAGIC_WALL_EMPTYING ||
2168 element == EL_BD_MAGIC_WALL_EMPTYING ||
2169 element == EL_DC_MAGIC_WALL_EMPTYING ||
2170 element == EL_AMOEBA_DROPPING)
2171 cut_mode = CUT_ABOVE;
2172 else if (element == EL_QUICKSAND_FILLING ||
2173 element == EL_QUICKSAND_FAST_FILLING ||
2174 element == EL_MAGIC_WALL_FILLING ||
2175 element == EL_BD_MAGIC_WALL_FILLING ||
2176 element == EL_DC_MAGIC_WALL_FILLING)
2177 cut_mode = CUT_BELOW;
2180 if (lx == 9 && ly == 1)
2181 printf("::: %s [%d] [%d, %d] [%d]\n",
2182 EL_NAME(TILE_GFX_ELEMENT(lx, ly)),
2183 el_act2crm(TILE_GFX_ELEMENT(lx, ly), ACTION_DEFAULT),
2184 element_info[EL_QUICKSAND_EMPTYING].graphic[ACTION_DEFAULT],
2185 element_info[EL_QUICKSAND_EMPTYING].crumbled[ACTION_DEFAULT],
2186 GFX_CRUMBLED(TILE_GFX_ELEMENT(lx, ly)));
2189 if (cut_mode == CUT_ABOVE)
2191 DrawScreenElement(x, y, element);
2193 DrawScreenElementShifted(x, y, 0, 0, element, NO_CUTTING);
2196 DrawScreenElement(x, y, EL_EMPTY);
2199 DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
2200 else if (cut_mode == NO_CUTTING)
2201 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
2204 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
2207 if (cut_mode == CUT_BELOW &&
2208 IN_LEV_FIELD(lx, ly + 1) && IN_SCR_FIELD(x, y + 1))
2209 DrawLevelElement(lx, ly + 1, element);
2213 if (content == EL_ACID)
2215 int dir = MovDir[lx][ly];
2216 int newlx = lx + (dir == MV_LEFT ? -1 : dir == MV_RIGHT ? +1 : 0);
2217 int newly = ly + (dir == MV_UP ? -1 : dir == MV_DOWN ? +1 : 0);
2219 DrawLevelElementThruMask(newlx, newly, EL_ACID);
2222 else if (IS_BLOCKED(lx, ly))
2227 boolean cut_mode = NO_CUTTING;
2228 int element_old, content_old;
2230 Blocked2Moving(lx, ly, &oldx, &oldy);
2233 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
2234 MovDir[oldx][oldy] == MV_RIGHT);
2236 element_old = Feld[oldx][oldy];
2237 content_old = Store[oldx][oldy];
2239 if (element_old == EL_QUICKSAND_EMPTYING ||
2240 element_old == EL_QUICKSAND_FAST_EMPTYING ||
2241 element_old == EL_MAGIC_WALL_EMPTYING ||
2242 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
2243 element_old == EL_DC_MAGIC_WALL_EMPTYING ||
2244 element_old == EL_AMOEBA_DROPPING)
2245 cut_mode = CUT_ABOVE;
2247 DrawScreenElement(x, y, EL_EMPTY);
2250 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
2252 else if (cut_mode == NO_CUTTING)
2253 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
2256 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
2259 else if (IS_DRAWABLE(element))
2260 DrawScreenElement(x, y, element);
2262 DrawScreenElement(x, y, EL_EMPTY);
2265 void DrawLevelField(int x, int y)
2267 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
2268 DrawScreenField(SCREENX(x), SCREENY(y));
2269 else if (IS_MOVING(x, y))
2273 Moving2Blocked(x, y, &newx, &newy);
2274 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
2275 DrawScreenField(SCREENX(newx), SCREENY(newy));
2277 else if (IS_BLOCKED(x, y))
2281 Blocked2Moving(x, y, &oldx, &oldy);
2282 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
2283 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
2287 void DrawMiniElement(int x, int y, int element)
2291 graphic = el2edimg(element);
2292 DrawMiniGraphic(x, y, graphic);
2295 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
2297 int x = sx + scroll_x, y = sy + scroll_y;
2299 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
2300 DrawMiniElement(sx, sy, EL_EMPTY);
2301 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
2302 DrawMiniElement(sx, sy, Feld[x][y]);
2304 DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
2307 void DrawEnvelopeBackground(int envelope_nr, int startx, int starty,
2308 int x, int y, int xsize, int ysize, int font_nr)
2310 int font_width = getFontWidth(font_nr);
2311 int font_height = getFontHeight(font_nr);
2312 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2315 int dst_x = SX + startx + x * font_width;
2316 int dst_y = SY + starty + y * font_height;
2317 int width = graphic_info[graphic].width;
2318 int height = graphic_info[graphic].height;
2319 int inner_width = MAX(width - 2 * font_width, font_width);
2320 int inner_height = MAX(height - 2 * font_height, font_height);
2321 int inner_sx = (width >= 3 * font_width ? font_width : 0);
2322 int inner_sy = (height >= 3 * font_height ? font_height : 0);
2323 boolean draw_masked = graphic_info[graphic].draw_masked;
2325 getFixedGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
2327 if (src_bitmap == NULL || width < font_width || height < font_height)
2329 ClearRectangle(drawto, dst_x, dst_y, font_width, font_height);
2333 src_x += (x == 0 ? 0 : x == xsize - 1 ? width - font_width :
2334 inner_sx + (x - 1) * font_width % inner_width);
2335 src_y += (y == 0 ? 0 : y == ysize - 1 ? height - font_height :
2336 inner_sy + (y - 1) * font_height % inner_height);
2340 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
2341 dst_x - src_x, dst_y - src_y);
2342 BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, font_width, font_height,
2346 BlitBitmap(src_bitmap, drawto, src_x, src_y, font_width, font_height,
2350 void AnimateEnvelope(int envelope_nr, int anim_mode, int action)
2352 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2353 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
2354 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
2355 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2356 boolean no_delay = (tape.warp_forward);
2357 unsigned long anim_delay = 0;
2358 int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
2359 int anim_delay_value = (no_delay ? 0 : frame_delay_value);
2360 int font_nr = FONT_ENVELOPE_1 + envelope_nr;
2361 int font_width = getFontWidth(font_nr);
2362 int font_height = getFontHeight(font_nr);
2363 int max_xsize = level.envelope[envelope_nr].xsize;
2364 int max_ysize = level.envelope[envelope_nr].ysize;
2365 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
2366 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
2367 int xend = max_xsize;
2368 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
2369 int xstep = (xstart < xend ? 1 : 0);
2370 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
2373 for (x = xstart, y = ystart; x <= xend && y <= yend; x += xstep, y += ystep)
2375 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
2376 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
2377 int sx = (SXSIZE - xsize * font_width) / 2;
2378 int sy = (SYSIZE - ysize * font_height) / 2;
2381 SetDrawtoField(DRAW_BUFFERED);
2383 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
2385 SetDrawtoField(DRAW_BACKBUFFER);
2387 for (yy = 0; yy < ysize; yy++) for (xx = 0; xx < xsize; xx++)
2388 DrawEnvelopeBackground(envelope_nr, sx,sy, xx,yy, xsize, ysize, font_nr);
2391 DrawTextBuffer(SX + sx + font_width, SY + sy + font_height,
2392 level.envelope[envelope_nr].text, font_nr, max_xsize,
2393 xsize - 2, ysize - 2, 0, mask_mode,
2394 level.envelope[envelope_nr].autowrap,
2395 level.envelope[envelope_nr].centered, FALSE);
2397 DrawTextToTextArea(SX + sx + font_width, SY + sy + font_height,
2398 level.envelope[envelope_nr].text, font_nr, max_xsize,
2399 xsize - 2, ysize - 2, mask_mode);
2402 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
2405 WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
2409 void AnimateEnvelopeDoor(char *text, int anim_mode, int action)
2412 int envelope_nr = 0;
2414 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2415 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
2416 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
2417 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2418 boolean no_delay = (tape.warp_forward);
2419 unsigned long anim_delay = 0;
2420 int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
2421 int anim_delay_value = (no_delay ? 0 : frame_delay_value);
2423 int max_word_len = maxWordLengthInString(text);
2424 int font_nr = (max_word_len > 7 ? FONT_TEXT_1 : FONT_TEXT_2);
2426 int font_nr = FONT_ENVELOPE_1 + envelope_nr;
2428 int font_width = getFontWidth(font_nr);
2429 int font_height = getFontHeight(font_nr);
2433 int max_xsize = DXSIZE / font_width;
2434 int max_ysize = DYSIZE / font_height;
2436 int max_xsize = 7; /* tools.c: MAX_REQUEST_LINE_FONT1_LEN == 7 */
2437 int max_ysize = 13; /* tools.c: MAX_REQUEST_LINES == 13 */
2441 int max_xsize = level.envelope[envelope_nr].xsize;
2442 int max_ysize = level.envelope[envelope_nr].ysize;
2444 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
2445 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
2446 int xend = max_xsize;
2447 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
2448 int xstep = (xstart < xend ? 1 : 0);
2449 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
2454 char *text_copy = getStringCopy(text);
2457 font_nr = FONT_TEXT_2;
2459 if (maxWordLengthInString(text) > 7) /* MAX_REQUEST_LINE_FONT1_LEN == 7 */
2461 max_xsize = 10; /* tools.c: MAX_REQUEST_LINE_FONT2_LEN == 10 */
2462 font_nr = FONT_TEXT_1;
2465 int max_word_len = 0;
2467 char *text_copy = getStringCopy(text);
2469 font_nr = FONT_TEXT_2;
2471 for (text_ptr = text; *text_ptr; text_ptr++)
2473 max_word_len = (*text_ptr != ' ' ? max_word_len + 1 : 0);
2475 if (max_word_len > 7) /* tools.c: MAX_REQUEST_LINE_FONT1_LEN == 7 */
2477 max_xsize = 10; /* tools.c: MAX_REQUEST_LINE_FONT2_LEN == 10 */
2478 font_nr = FONT_TEXT_1;
2487 for (text_ptr = text_copy; *text_ptr; text_ptr++)
2488 if (*text_ptr == ' ')
2493 dDX = SX + (SXSIZE - DXSIZE) / 2 - DX;
2494 dDY = SY + (SYSIZE - DYSIZE) / 2 - DY;
2496 dDX = SX + SXSIZE / 2 - max_xsize * font_width / 2 - DX;
2497 dDY = SY + SYSIZE / 2 - max_ysize * font_height / 2 - DY;
2500 for (x = xstart, y = ystart; x <= xend && y <= yend; x += xstep, y += ystep)
2502 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
2503 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
2504 int sx = (SXSIZE - xsize * font_width) / 2;
2505 int sy = (SYSIZE - ysize * font_height) / 2;
2509 BlitBitmap(bitmap_db_store, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2511 SetDrawtoField(DRAW_BUFFERED);
2513 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
2515 SetDrawtoField(DRAW_BACKBUFFER);
2518 for (yy = 0; yy < ysize; yy++) for (xx = 0; xx < xsize; xx++)
2519 DrawEnvelopeBackground(envelope_nr, sx,sy, xx,yy, xsize, ysize, font_nr);
2524 DrawTextBuffer(SX + sx + font_width, SY + sy + font_height + 8,
2525 text_copy, font_nr, max_xsize,
2526 xsize - 2, ysize - 2, 2, mask_mode,
2527 FALSE, TRUE, FALSE);
2529 DrawTextBuffer(SX + sx + font_width, SY + sy + font_height,
2530 level.envelope[envelope_nr].text, font_nr, max_xsize,
2531 xsize - 2, ysize - 2, 0, mask_mode,
2532 level.envelope[envelope_nr].autowrap,
2533 level.envelope[envelope_nr].centered, FALSE);
2537 DrawTextToTextArea(SX + sx + font_width, SY + sy + font_height,
2538 level.envelope[envelope_nr].text, font_nr, max_xsize,
2539 xsize - 2, ysize - 2, mask_mode);
2542 /* copy request gadgets to door backbuffer */
2544 if ((ysize - 2) > 13)
2545 BlitBitmap(bitmap_db_door, drawto,
2546 DOOR_GFX_PAGEX1 + (DXSIZE - (xsize - 2) * font_width) / 2,
2547 DOOR_GFX_PAGEY1 + 13 * font_height,
2548 (xsize - 2) * font_width,
2549 (ysize - 2 - 13) * font_height,
2550 SX + sx + font_width,
2551 SY + sy + font_height * (1 + 13));
2553 if ((ysize - 2) > 13)
2554 BlitBitmap(bitmap_db_door, drawto,
2555 DOOR_GFX_PAGEX1 + (DXSIZE - (xsize - 2) * font_width) / 2,
2556 DOOR_GFX_PAGEY1 + 13 * font_height,
2557 (xsize - 2) * font_width,
2558 (ysize - 2 - 13) * font_height,
2559 SX + sx + font_width,
2560 SY + sy + font_height * (1 + 13));
2564 redraw_mask = REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
2565 // redraw_mask |= REDRAW_ALL | REDRAW_FROM_BACKBUFFER;
2567 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
2577 WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
2585 void ShowEnvelope(int envelope_nr)
2587 int element = EL_ENVELOPE_1 + envelope_nr;
2588 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2589 int sound_opening = element_info[element].sound[ACTION_OPENING];
2590 int sound_closing = element_info[element].sound[ACTION_CLOSING];
2591 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2592 boolean no_delay = (tape.warp_forward);
2593 int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
2594 int wait_delay_value = (no_delay ? 0 : normal_delay_value);
2595 int anim_mode = graphic_info[graphic].anim_mode;
2596 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
2597 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
2599 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
2601 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
2603 if (anim_mode == ANIM_DEFAULT)
2604 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_OPENING);
2606 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_OPENING);
2609 Delay(wait_delay_value);
2611 WaitForEventToContinue();
2613 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
2615 if (anim_mode != ANIM_NONE)
2616 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_CLOSING);
2618 if (anim_mode == ANIM_DEFAULT)
2619 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_CLOSING);
2621 game.envelope_active = FALSE;
2623 SetDrawtoField(DRAW_BUFFERED);
2625 redraw_mask |= REDRAW_FIELD;
2629 void ShowEnvelopeDoor(char *text, int action)
2632 int last_game_status = game_status; /* save current game status */
2633 // int last_draw_background_mask = gfx.draw_background_mask;
2634 int envelope_nr = 0;
2636 int element = EL_ENVELOPE_1 + envelope_nr;
2637 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2638 int sound_opening = element_info[element].sound[ACTION_OPENING];
2639 int sound_closing = element_info[element].sound[ACTION_CLOSING];
2641 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2642 boolean no_delay = (tape.warp_forward);
2643 int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
2644 int wait_delay_value = (no_delay ? 0 : normal_delay_value);
2646 int anim_mode = graphic_info[graphic].anim_mode;
2647 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
2648 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
2651 if (game_status == GAME_MODE_PLAYING)
2653 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
2654 BlitScreenToBitmap_EM(backbuffer);
2655 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
2656 BlitScreenToBitmap_SP(backbuffer);
2659 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
2663 SetDrawtoField(DRAW_BACKBUFFER);
2665 // SetDrawBackgroundMask(REDRAW_NONE);
2667 if (action == ACTION_OPENING)
2669 BlitBitmap(backbuffer, bitmap_db_store, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2671 if (game_status != GAME_MODE_MAIN)
2675 /* force DOOR font inside door area */
2676 game_status = GAME_MODE_PSEUDO_DOOR;
2679 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
2681 if (action == ACTION_OPENING)
2683 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
2685 if (anim_mode == ANIM_DEFAULT)
2686 AnimateEnvelopeDoor(text, ANIM_DEFAULT, ACTION_OPENING);
2688 AnimateEnvelopeDoor(text, main_anim_mode, ACTION_OPENING);
2692 Delay(wait_delay_value);
2694 WaitForEventToContinue();
2699 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
2701 if (anim_mode != ANIM_NONE)
2702 AnimateEnvelopeDoor(text, main_anim_mode, ACTION_CLOSING);
2704 if (anim_mode == ANIM_DEFAULT)
2705 AnimateEnvelopeDoor(text, ANIM_DEFAULT, ACTION_CLOSING);
2708 game.envelope_active = FALSE;
2711 // game_status = last_game_status; /* restore current game status */
2713 if (action == ACTION_CLOSING)
2715 if (game_status != GAME_MODE_MAIN)
2718 BlitBitmap(bitmap_db_store, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2721 SetDrawtoField(DRAW_BUFFERED);
2724 // SetDrawBackgroundMask(last_draw_background_mask);
2727 redraw_mask = REDRAW_FIELD;
2728 // redraw_mask |= REDRAW_ALL;
2730 redraw_mask |= REDRAW_FIELD;
2734 if (game_status == GAME_MODE_MAIN)
2739 /* (important: after "BackToFront()", but before "SetDrawtoField()") */
2740 game_status = last_game_status; /* restore current game status */
2742 if (game_status == GAME_MODE_PLAYING &&
2743 level.game_engine_type == GAME_ENGINE_TYPE_RND)
2744 SetDrawtoField(DRAW_BUFFERED);
2750 void DrawPreviewElement(int dst_x, int dst_y, int element, int tilesize)
2754 int graphic = el2preimg(element);
2756 getSizedGraphicSource(graphic, 0, tilesize, &src_bitmap, &src_x, &src_y);
2757 BlitBitmap(src_bitmap, drawto, src_x, src_y, tilesize, tilesize, dst_x,dst_y);
2765 SetMainBackgroundImage(IMG_BACKGROUND_PLAYING);
2766 SetDrawBackgroundMask(REDRAW_FIELD);
2768 SetDrawBackgroundMask(REDRAW_NONE);
2773 for (x = BX1; x <= BX2; x++)
2774 for (y = BY1; y <= BY2; y++)
2775 DrawScreenField(x, y);
2777 redraw_mask |= REDRAW_FIELD;
2780 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
2784 for (x = 0; x < size_x; x++)
2785 for (y = 0; y < size_y; y++)
2786 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
2788 redraw_mask |= REDRAW_FIELD;
2791 static void DrawPreviewLevelExt(int from_x, int from_y)
2793 boolean show_level_border = (BorderElement != EL_EMPTY);
2794 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
2795 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
2796 int tile_size = preview.tile_size;
2797 int preview_width = preview.xsize * tile_size;
2798 int preview_height = preview.ysize * tile_size;
2799 int real_preview_xsize = MIN(level_xsize, preview.xsize);
2800 int real_preview_ysize = MIN(level_ysize, preview.ysize);
2801 int dst_x = SX + ALIGNED_XPOS(preview.x, preview_width, preview.align);
2802 int dst_y = SY + ALIGNED_YPOS(preview.y, preview_height, preview.valign);
2805 DrawBackground(dst_x, dst_y, preview_width, preview_height);
2807 dst_x += (preview_width - real_preview_xsize * tile_size) / 2;
2808 dst_y += (preview_height - real_preview_ysize * tile_size) / 2;
2810 for (x = 0; x < real_preview_xsize; x++)
2812 for (y = 0; y < real_preview_ysize; y++)
2814 int lx = from_x + x + (show_level_border ? -1 : 0);
2815 int ly = from_y + y + (show_level_border ? -1 : 0);
2816 int element = (IN_LEV_FIELD(lx, ly) ? level.field[lx][ly] :
2817 getBorderElement(lx, ly));
2819 DrawPreviewElement(dst_x + x * tile_size, dst_y + y * tile_size,
2820 element, tile_size);
2824 redraw_mask |= REDRAW_MICROLEVEL;
2827 #define MICROLABEL_EMPTY 0
2828 #define MICROLABEL_LEVEL_NAME 1
2829 #define MICROLABEL_LEVEL_AUTHOR_HEAD 2
2830 #define MICROLABEL_LEVEL_AUTHOR 3
2831 #define MICROLABEL_IMPORTED_FROM_HEAD 4
2832 #define MICROLABEL_IMPORTED_FROM 5
2833 #define MICROLABEL_IMPORTED_BY_HEAD 6
2834 #define MICROLABEL_IMPORTED_BY 7
2836 static int getMaxTextLength(struct TextPosInfo *pos, int font_nr)
2838 int max_text_width = SXSIZE;
2839 int font_width = getFontWidth(font_nr);
2841 if (pos->align == ALIGN_CENTER)
2842 max_text_width = (pos->x < SXSIZE / 2 ? pos->x * 2 : (SXSIZE - pos->x) * 2);
2843 else if (pos->align == ALIGN_RIGHT)
2844 max_text_width = pos->x;
2846 max_text_width = SXSIZE - pos->x;
2848 return max_text_width / font_width;
2851 static void DrawPreviewLevelLabelExt(int mode)
2853 struct TextPosInfo *pos = &menu.main.text.level_info_2;
2854 char label_text[MAX_OUTPUT_LINESIZE + 1];
2855 int max_len_label_text;
2857 int font_nr = pos->font;
2860 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
2861 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
2862 mode == MICROLABEL_IMPORTED_BY_HEAD)
2863 font_nr = pos->font_alt;
2865 int font_nr = FONT_TEXT_2;
2868 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
2869 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
2870 mode == MICROLABEL_IMPORTED_BY_HEAD)
2871 font_nr = FONT_TEXT_3;
2875 max_len_label_text = getMaxTextLength(pos, font_nr);
2877 max_len_label_text = SXSIZE / getFontWidth(font_nr);
2881 if (pos->size != -1)
2882 max_len_label_text = pos->size;
2885 for (i = 0; i < max_len_label_text; i++)
2886 label_text[i] = ' ';
2887 label_text[max_len_label_text] = '\0';
2889 if (strlen(label_text) > 0)
2892 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2894 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
2895 int lypos = MICROLABEL2_YPOS;
2897 DrawText(lxpos, lypos, label_text, font_nr);
2902 (mode == MICROLABEL_LEVEL_NAME ? level.name :
2903 mode == MICROLABEL_LEVEL_AUTHOR_HEAD ? "created by" :
2904 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
2905 mode == MICROLABEL_IMPORTED_FROM_HEAD ? "imported from" :
2906 mode == MICROLABEL_IMPORTED_FROM ? leveldir_current->imported_from :
2907 mode == MICROLABEL_IMPORTED_BY_HEAD ? "imported by" :
2908 mode == MICROLABEL_IMPORTED_BY ? leveldir_current->imported_by :""),
2909 max_len_label_text);
2910 label_text[max_len_label_text] = '\0';
2912 if (strlen(label_text) > 0)
2915 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2917 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
2918 int lypos = MICROLABEL2_YPOS;
2920 DrawText(lxpos, lypos, label_text, font_nr);
2924 redraw_mask |= REDRAW_MICROLEVEL;
2927 void DrawPreviewLevel(boolean restart)
2929 static unsigned long scroll_delay = 0;
2930 static unsigned long label_delay = 0;
2931 static int from_x, from_y, scroll_direction;
2932 static int label_state, label_counter;
2933 unsigned long scroll_delay_value = preview.step_delay;
2934 boolean show_level_border = (BorderElement != EL_EMPTY);
2935 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
2936 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
2937 int last_game_status = game_status; /* save current game status */
2940 /* force PREVIEW font on preview level */
2941 game_status = GAME_MODE_PSEUDO_PREVIEW;
2949 if (preview.anim_mode == ANIM_CENTERED)
2951 if (level_xsize > preview.xsize)
2952 from_x = (level_xsize - preview.xsize) / 2;
2953 if (level_ysize > preview.ysize)
2954 from_y = (level_ysize - preview.ysize) / 2;
2957 from_x += preview.xoffset;
2958 from_y += preview.yoffset;
2960 scroll_direction = MV_RIGHT;
2964 DrawPreviewLevelExt(from_x, from_y);
2965 DrawPreviewLevelLabelExt(label_state);
2967 /* initialize delay counters */
2968 DelayReached(&scroll_delay, 0);
2969 DelayReached(&label_delay, 0);
2971 if (leveldir_current->name)
2973 struct TextPosInfo *pos = &menu.main.text.level_info_1;
2974 char label_text[MAX_OUTPUT_LINESIZE + 1];
2976 int font_nr = pos->font;
2978 int font_nr = FONT_TEXT_1;
2981 int max_len_label_text = getMaxTextLength(pos, font_nr);
2983 int max_len_label_text = SXSIZE / getFontWidth(font_nr);
2991 if (pos->size != -1)
2992 max_len_label_text = pos->size;
2995 strncpy(label_text, leveldir_current->name, max_len_label_text);
2996 label_text[max_len_label_text] = '\0';
2999 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
3001 lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
3002 lypos = SY + MICROLABEL1_YPOS;
3004 DrawText(lxpos, lypos, label_text, font_nr);
3008 game_status = last_game_status; /* restore current game status */
3013 /* scroll preview level, if needed */
3014 if (preview.anim_mode != ANIM_NONE &&
3015 (level_xsize > preview.xsize || level_ysize > preview.ysize) &&
3016 DelayReached(&scroll_delay, scroll_delay_value))
3018 switch (scroll_direction)
3023 from_x -= preview.step_offset;
3024 from_x = (from_x < 0 ? 0 : from_x);
3027 scroll_direction = MV_UP;
3031 if (from_x < level_xsize - preview.xsize)
3033 from_x += preview.step_offset;
3034 from_x = (from_x > level_xsize - preview.xsize ?
3035 level_xsize - preview.xsize : from_x);
3038 scroll_direction = MV_DOWN;
3044 from_y -= preview.step_offset;
3045 from_y = (from_y < 0 ? 0 : from_y);
3048 scroll_direction = MV_RIGHT;
3052 if (from_y < level_ysize - preview.ysize)
3054 from_y += preview.step_offset;
3055 from_y = (from_y > level_ysize - preview.ysize ?
3056 level_ysize - preview.ysize : from_y);
3059 scroll_direction = MV_LEFT;
3066 DrawPreviewLevelExt(from_x, from_y);
3069 /* !!! THIS ALL SUCKS -- SHOULD BE CLEANLY REWRITTEN !!! */
3070 /* redraw micro level label, if needed */
3071 if (!strEqual(level.name, NAMELESS_LEVEL_NAME) &&
3072 !strEqual(level.author, ANONYMOUS_NAME) &&
3073 !strEqual(level.author, leveldir_current->name) &&
3074 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
3076 int max_label_counter = 23;
3078 if (leveldir_current->imported_from != NULL &&
3079 strlen(leveldir_current->imported_from) > 0)
3080 max_label_counter += 14;
3081 if (leveldir_current->imported_by != NULL &&
3082 strlen(leveldir_current->imported_by) > 0)
3083 max_label_counter += 14;
3085 label_counter = (label_counter + 1) % max_label_counter;
3086 label_state = (label_counter >= 0 && label_counter <= 7 ?
3087 MICROLABEL_LEVEL_NAME :
3088 label_counter >= 9 && label_counter <= 12 ?
3089 MICROLABEL_LEVEL_AUTHOR_HEAD :
3090 label_counter >= 14 && label_counter <= 21 ?
3091 MICROLABEL_LEVEL_AUTHOR :
3092 label_counter >= 23 && label_counter <= 26 ?
3093 MICROLABEL_IMPORTED_FROM_HEAD :
3094 label_counter >= 28 && label_counter <= 35 ?
3095 MICROLABEL_IMPORTED_FROM :
3096 label_counter >= 37 && label_counter <= 40 ?
3097 MICROLABEL_IMPORTED_BY_HEAD :
3098 label_counter >= 42 && label_counter <= 49 ?
3099 MICROLABEL_IMPORTED_BY : MICROLABEL_EMPTY);
3101 if (leveldir_current->imported_from == NULL &&
3102 (label_state == MICROLABEL_IMPORTED_FROM_HEAD ||
3103 label_state == MICROLABEL_IMPORTED_FROM))
3104 label_state = (label_state == MICROLABEL_IMPORTED_FROM_HEAD ?
3105 MICROLABEL_IMPORTED_BY_HEAD : MICROLABEL_IMPORTED_BY);
3107 DrawPreviewLevelLabelExt(label_state);
3110 game_status = last_game_status; /* restore current game status */
3113 inline void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
3114 int graphic, int sync_frame, int mask_mode)
3116 int frame = getGraphicAnimationFrame(graphic, sync_frame);
3118 if (mask_mode == USE_MASKING)
3119 DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
3121 DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
3124 inline void DrawFixedGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
3125 int graphic, int sync_frame,
3128 int frame = getGraphicAnimationFrame(graphic, sync_frame);
3130 if (mask_mode == USE_MASKING)
3131 DrawFixedGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
3133 DrawFixedGraphicExt(dst_bitmap, x, y, graphic, frame);
3136 inline void DrawGraphicAnimation(int x, int y, int graphic)
3138 int lx = LEVELX(x), ly = LEVELY(y);
3140 if (!IN_SCR_FIELD(x, y))
3144 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR,
3145 graphic, GfxFrame[lx][ly], NO_MASKING);
3147 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
3148 graphic, GfxFrame[lx][ly], NO_MASKING);
3150 MarkTileDirty(x, y);
3153 inline void DrawFixedGraphicAnimation(int x, int y, int graphic)
3155 int lx = LEVELX(x), ly = LEVELY(y);
3157 if (!IN_SCR_FIELD(x, y))
3160 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
3161 graphic, GfxFrame[lx][ly], NO_MASKING);
3162 MarkTileDirty(x, y);
3165 void DrawLevelGraphicAnimation(int x, int y, int graphic)
3167 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
3170 void DrawLevelElementAnimation(int x, int y, int element)
3172 int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
3174 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
3177 inline void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
3179 int sx = SCREENX(x), sy = SCREENY(y);
3181 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
3184 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
3187 DrawGraphicAnimation(sx, sy, graphic);
3190 if (GFX_CRUMBLED(TILE_GFX_ELEMENT(x, y)))
3191 DrawLevelFieldCrumbled(x, y);
3193 if (GFX_CRUMBLED(Feld[x][y]))
3194 DrawLevelFieldCrumbled(x, y);
3198 void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
3200 int sx = SCREENX(x), sy = SCREENY(y);
3203 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
3206 graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
3208 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
3211 DrawGraphicAnimation(sx, sy, graphic);
3213 if (GFX_CRUMBLED(element))
3214 DrawLevelFieldCrumbled(x, y);
3217 static int getPlayerGraphic(struct PlayerInfo *player, int move_dir)
3219 if (player->use_murphy)
3221 /* this works only because currently only one player can be "murphy" ... */
3222 static int last_horizontal_dir = MV_LEFT;
3223 int graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir);
3225 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3226 last_horizontal_dir = move_dir;
3228 if (graphic == IMG_SP_MURPHY) /* undefined => use special graphic */
3230 int direction = (player->is_snapping ? move_dir : last_horizontal_dir);
3232 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
3238 return el_act_dir2img(player->artwork_element, player->GfxAction,move_dir);
3241 static boolean equalGraphics(int graphic1, int graphic2)
3243 struct GraphicInfo *g1 = &graphic_info[graphic1];
3244 struct GraphicInfo *g2 = &graphic_info[graphic2];
3246 return (g1->bitmap == g2->bitmap &&
3247 g1->src_x == g2->src_x &&
3248 g1->src_y == g2->src_y &&
3249 g1->anim_frames == g2->anim_frames &&
3250 g1->anim_delay == g2->anim_delay &&
3251 g1->anim_mode == g2->anim_mode);
3254 void DrawAllPlayers()
3258 for (i = 0; i < MAX_PLAYERS; i++)
3259 if (stored_player[i].active)
3260 DrawPlayer(&stored_player[i]);
3263 void DrawPlayerField(int x, int y)
3265 if (!IS_PLAYER(x, y))
3268 DrawPlayer(PLAYERINFO(x, y));
3271 #define DRAW_PLAYER_OVER_PUSHED_ELEMENT 1
3273 void DrawPlayer(struct PlayerInfo *player)
3275 int jx = player->jx;
3276 int jy = player->jy;
3277 int move_dir = player->MovDir;
3278 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? +1 : 0);
3279 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? +1 : 0);
3280 int last_jx = (player->is_moving ? jx - dx : jx);
3281 int last_jy = (player->is_moving ? jy - dy : jy);
3282 int next_jx = jx + dx;
3283 int next_jy = jy + dy;
3284 boolean player_is_moving = (player->MovPos ? TRUE : FALSE);
3285 boolean player_is_opaque = FALSE;
3286 int sx = SCREENX(jx), sy = SCREENY(jy);
3287 int sxx = 0, syy = 0;
3288 int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
3290 int action = ACTION_DEFAULT;
3291 int last_player_graphic = getPlayerGraphic(player, move_dir);
3292 int last_player_frame = player->Frame;
3295 /* GfxElement[][] is set to the element the player is digging or collecting;
3296 remove also for off-screen player if the player is not moving anymore */
3297 if (IN_LEV_FIELD(jx, jy) && !player_is_moving)
3298 GfxElement[jx][jy] = EL_UNDEFINED;
3300 if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
3304 if (!IN_LEV_FIELD(jx, jy))
3306 printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
3307 printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
3308 printf("DrawPlayerField(): This should never happen!\n");
3313 if (element == EL_EXPLOSION)
3316 action = (player->is_pushing ? ACTION_PUSHING :
3317 player->is_digging ? ACTION_DIGGING :
3318 player->is_collecting ? ACTION_COLLECTING :
3319 player->is_moving ? ACTION_MOVING :
3320 player->is_snapping ? ACTION_SNAPPING :
3321 player->is_dropping ? ACTION_DROPPING :
3322 player->is_waiting ? player->action_waiting : ACTION_DEFAULT);
3324 if (player->is_waiting)
3325 move_dir = player->dir_waiting;
3327 InitPlayerGfxAnimation(player, action, move_dir);
3329 /* ----------------------------------------------------------------------- */
3330 /* draw things in the field the player is leaving, if needed */
3331 /* ----------------------------------------------------------------------- */
3333 if (player->is_moving)
3335 if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
3337 DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
3339 if (last_element == EL_DYNAMITE_ACTIVE ||
3340 last_element == EL_EM_DYNAMITE_ACTIVE ||
3341 last_element == EL_SP_DISK_RED_ACTIVE)
3342 DrawDynamite(last_jx, last_jy);
3344 DrawLevelFieldThruMask(last_jx, last_jy);
3346 else if (last_element == EL_DYNAMITE_ACTIVE ||
3347 last_element == EL_EM_DYNAMITE_ACTIVE ||
3348 last_element == EL_SP_DISK_RED_ACTIVE)
3349 DrawDynamite(last_jx, last_jy);
3351 /* !!! this is not enough to prevent flickering of players which are
3352 moving next to each others without a free tile between them -- this
3353 can only be solved by drawing all players layer by layer (first the
3354 background, then the foreground etc.) !!! => TODO */
3355 else if (!IS_PLAYER(last_jx, last_jy))
3356 DrawLevelField(last_jx, last_jy);
3359 DrawLevelField(last_jx, last_jy);
3362 if (player->is_pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
3363 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
3366 if (!IN_SCR_FIELD(sx, sy))
3369 /* ----------------------------------------------------------------------- */
3370 /* draw things behind the player, if needed */
3371 /* ----------------------------------------------------------------------- */
3374 DrawLevelElement(jx, jy, Back[jx][jy]);
3375 else if (IS_ACTIVE_BOMB(element))
3376 DrawLevelElement(jx, jy, EL_EMPTY);
3379 if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
3381 int old_element = GfxElement[jx][jy];
3382 int old_graphic = el_act_dir2img(old_element, action, move_dir);
3383 int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
3385 if (GFX_CRUMBLED(old_element))
3386 DrawLevelFieldCrumbledDigging(jx, jy, move_dir, player->StepFrame);
3388 DrawGraphic(sx, sy, old_graphic, frame);
3390 if (graphic_info[old_graphic].anim_mode & ANIM_OPAQUE_PLAYER)
3391 player_is_opaque = TRUE;
3395 GfxElement[jx][jy] = EL_UNDEFINED;
3397 /* make sure that pushed elements are drawn with correct frame rate */
3399 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
3401 if (player->is_pushing && player->is_moving && !IS_ANIM_MODE_CE(graphic))
3402 GfxFrame[jx][jy] = player->StepFrame;
3404 if (player->is_pushing && player->is_moving)
3405 GfxFrame[jx][jy] = player->StepFrame;
3408 DrawLevelField(jx, jy);
3412 #if !DRAW_PLAYER_OVER_PUSHED_ELEMENT
3413 /* ----------------------------------------------------------------------- */
3414 /* draw player himself */
3415 /* ----------------------------------------------------------------------- */
3417 graphic = getPlayerGraphic(player, move_dir);
3419 /* in the case of changed player action or direction, prevent the current
3420 animation frame from being restarted for identical animations */
3421 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
3422 player->Frame = last_player_frame;
3424 frame = getGraphicAnimationFrame(graphic, player->Frame);
3428 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3429 sxx = player->GfxPos;
3431 syy = player->GfxPos;
3434 if (!setup.soft_scrolling && ScreenMovPos)
3437 if (player_is_opaque)
3438 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
3440 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3442 if (SHIELD_ON(player))
3444 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
3445 IMG_SHIELD_NORMAL_ACTIVE);
3446 int frame = getGraphicAnimationFrame(graphic, -1);
3448 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3452 #if DRAW_PLAYER_OVER_PUSHED_ELEMENT
3455 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3456 sxx = player->GfxPos;
3458 syy = player->GfxPos;
3462 /* ----------------------------------------------------------------------- */
3463 /* draw things the player is pushing, if needed */
3464 /* ----------------------------------------------------------------------- */
3467 printf("::: %d, %d [%d, %d] [%d]\n",
3468 player->is_pushing, player_is_moving, player->GfxAction,
3469 player->is_moving, player_is_moving);
3473 if (player->is_pushing && player->is_moving)
3475 int px = SCREENX(jx), py = SCREENY(jy);
3476 int pxx = (TILEX - ABS(sxx)) * dx;
3477 int pyy = (TILEY - ABS(syy)) * dy;
3478 int gfx_frame = GfxFrame[jx][jy];
3484 if (!IS_MOVING(jx, jy)) /* push movement already finished */
3486 element = Feld[next_jx][next_jy];
3487 gfx_frame = GfxFrame[next_jx][next_jy];
3490 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
3493 sync_frame = (IS_ANIM_MODE_CE(graphic) ? gfx_frame : player->StepFrame);
3494 frame = getGraphicAnimationFrame(graphic, sync_frame);
3496 frame = getGraphicAnimationFrame(graphic, player->StepFrame);
3499 /* draw background element under pushed element (like the Sokoban field) */
3501 if (game.use_masked_pushing && IS_MOVING(jx, jy))
3503 /* this allows transparent pushing animation over non-black background */
3506 DrawLevelElement(jx, jy, Back[jx][jy]);
3508 DrawLevelElement(jx, jy, EL_EMPTY);
3510 if (Back[next_jx][next_jy])
3511 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
3513 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
3515 else if (Back[next_jx][next_jy])
3516 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
3518 if (Back[next_jx][next_jy])
3519 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
3523 printf("::: %d, %d, %d, %d [%d] [%d, %d, %d] [%d] [%d, %d] [%d, %d]\n",
3524 jx, px, player->GfxPos, player->StepFrame,
3529 GfxFrame[jx][jy], GfxFrame[next_jx][next_jy]);
3533 /* do not draw (EM style) pushing animation when pushing is finished */
3534 /* (two-tile animations usually do not contain start and end frame) */
3535 if (graphic_info[graphic].double_movement && !IS_MOVING(jx, jy))
3536 DrawLevelElement(next_jx, next_jy, Feld[next_jx][next_jy]);
3538 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
3540 /* masked drawing is needed for EMC style (double) movement graphics */
3541 /* !!! (ONLY WHEN DRAWING PUSHED ELEMENT OVER THE PLAYER) !!! */
3542 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
3547 #if DRAW_PLAYER_OVER_PUSHED_ELEMENT
3548 /* ----------------------------------------------------------------------- */
3549 /* draw player himself */
3550 /* ----------------------------------------------------------------------- */
3552 graphic = getPlayerGraphic(player, move_dir);
3554 /* in the case of changed player action or direction, prevent the current
3555 animation frame from being restarted for identical animations */
3556 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
3557 player->Frame = last_player_frame;
3559 frame = getGraphicAnimationFrame(graphic, player->Frame);
3563 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3564 sxx = player->GfxPos;
3566 syy = player->GfxPos;
3569 if (!setup.soft_scrolling && ScreenMovPos)
3572 if (player_is_opaque)
3573 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
3575 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3577 if (SHIELD_ON(player))
3579 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
3580 IMG_SHIELD_NORMAL_ACTIVE);
3581 int frame = getGraphicAnimationFrame(graphic, -1);
3583 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3587 /* ----------------------------------------------------------------------- */
3588 /* draw things in front of player (active dynamite or dynabombs) */
3589 /* ----------------------------------------------------------------------- */
3591 if (IS_ACTIVE_BOMB(element))
3593 graphic = el2img(element);
3594 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
3596 if (game.emulation == EMU_SUPAPLEX)
3597 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
3599 DrawGraphicThruMask(sx, sy, graphic, frame);
3602 if (player_is_moving && last_element == EL_EXPLOSION)
3604 int element = (GfxElement[last_jx][last_jy] != EL_UNDEFINED ?
3605 GfxElement[last_jx][last_jy] : EL_EMPTY);
3606 int graphic = el_act2img(element, ACTION_EXPLODING);
3607 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
3608 int phase = ExplodePhase[last_jx][last_jy] - 1;
3609 int frame = getGraphicAnimationFrame(graphic, phase - delay);
3612 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
3615 /* ----------------------------------------------------------------------- */
3616 /* draw elements the player is just walking/passing through/under */
3617 /* ----------------------------------------------------------------------- */
3619 if (player_is_moving)
3621 /* handle the field the player is leaving ... */
3622 if (IS_ACCESSIBLE_INSIDE(last_element))
3623 DrawLevelField(last_jx, last_jy);
3624 else if (IS_ACCESSIBLE_UNDER(last_element))
3625 DrawLevelFieldThruMask(last_jx, last_jy);
3628 /* do not redraw accessible elements if the player is just pushing them */
3629 if (!player_is_moving || !player->is_pushing)
3631 /* ... and the field the player is entering */
3632 if (IS_ACCESSIBLE_INSIDE(element))
3633 DrawLevelField(jx, jy);
3634 else if (IS_ACCESSIBLE_UNDER(element))
3635 DrawLevelFieldThruMask(jx, jy);
3638 MarkTileDirty(sx, sy);
3641 /* ------------------------------------------------------------------------- */
3643 void WaitForEventToContinue()
3645 boolean still_wait = TRUE;
3647 /* simulate releasing mouse button over last gadget, if still pressed */
3649 HandleGadgets(-1, -1, 0);
3651 button_status = MB_RELEASED;
3667 case EVENT_BUTTONPRESS:
3668 case EVENT_KEYPRESS:
3672 case EVENT_KEYRELEASE:
3673 ClearPlayerAction();
3677 HandleOtherEvents(&event);
3681 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
3688 /* don't eat all CPU time */
3693 #define MAX_REQUEST_LINES 13
3694 #define MAX_REQUEST_LINE_FONT1_LEN 7
3695 #define MAX_REQUEST_LINE_FONT2_LEN 10
3697 boolean Request(char *text, unsigned int req_state)
3699 int mx, my, ty, result = -1;
3700 unsigned int old_door_state;
3701 int last_game_status = game_status; /* save current game status */
3702 int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
3703 int font_nr = FONT_TEXT_2;
3705 int max_word_len = 0;
3711 global.use_envelope_request = 0;
3715 if (maxWordLengthInString(text) > MAX_REQUEST_LINE_FONT1_LEN)
3717 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
3718 font_nr = FONT_TEXT_1;
3721 for (text_ptr = text; *text_ptr; text_ptr++)
3723 max_word_len = (*text_ptr != ' ' ? max_word_len + 1 : 0);
3725 if (max_word_len > MAX_REQUEST_LINE_FONT1_LEN)
3727 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
3729 font_nr = FONT_TEXT_1;
3731 font_nr = FONT_LEVEL_NUMBER;
3739 if (game_status == GAME_MODE_PLAYING)
3741 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
3742 BlitScreenToBitmap_EM(backbuffer);
3743 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
3744 BlitScreenToBitmap_SP(backbuffer);
3747 /* disable deactivated drawing when quick-loading level tape recording */
3748 if (tape.playing && tape.deactivate_display)
3749 TapeDeactivateDisplayOff(TRUE);
3751 SetMouseCursor(CURSOR_DEFAULT);
3753 #if defined(NETWORK_AVALIABLE)
3754 /* pause network game while waiting for request to answer */
3755 if (options.network &&
3756 game_status == GAME_MODE_PLAYING &&
3757 req_state & REQUEST_WAIT_FOR_INPUT)
3758 SendToServer_PausePlaying();
3761 old_door_state = GetDoorState();
3763 /* simulate releasing mouse button over last gadget, if still pressed */
3765 HandleGadgets(-1, -1, 0);
3769 /* draw released gadget before proceeding */
3773 if (old_door_state & DOOR_OPEN_1 && !global.use_envelope_request)
3775 if (old_door_state & DOOR_OPEN_1)
3779 if (!global.use_envelope_request)
3780 CloseDoor(DOOR_CLOSE_1);
3782 CloseDoor(DOOR_CLOSE_1);
3785 /* save old door content */
3786 BlitBitmap(bitmap_db_door, bitmap_db_door,
3787 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
3788 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
3792 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
3795 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3797 /* clear door drawing field */
3798 DrawBackground(DX, DY, DXSIZE, DYSIZE);
3800 /* force DOOR font inside door area */
3801 game_status = GAME_MODE_PSEUDO_DOOR;
3803 /* write text for request */
3804 for (text_ptr = text, ty = 0; ty < MAX_REQUEST_LINES; ty++)
3806 char text_line[max_request_line_len + 1];
3812 for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
3814 tc = *(text_ptr + tx);
3815 if (!tc || tc == ' ')
3826 strncpy(text_line, text_ptr, tl);
3829 DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
3830 DY + 8 + ty * (getFontHeight(font_nr) + 2),
3831 text_line, font_nr);
3833 text_ptr += tl + (tc == ' ' ? 1 : 0);
3836 game_status = last_game_status; /* restore current game status */
3839 if (global.use_envelope_request)
3843 CreateToolButtons();
3847 if (req_state & REQ_ASK)
3849 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
3850 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
3852 else if (req_state & REQ_CONFIRM)
3854 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
3856 else if (req_state & REQ_PLAYER)
3858 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
3859 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
3860 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
3861 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
3864 /* copy request gadgets to door backbuffer */
3865 BlitBitmap(drawto, bitmap_db_door,
3866 DX, DY, DXSIZE, DYSIZE,
3867 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
3870 if (global.use_envelope_request)
3872 ShowEnvelopeDoor(text, ACTION_OPENING);
3874 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3876 if ((req_state & REQ_ASK && (i == TOOL_CTRL_ID_YES ||
3877 i == TOOL_CTRL_ID_NO)) ||
3878 (req_state & REQ_CONFIRM && i == TOOL_CTRL_ID_CONFIRM) ||
3879 (req_state & REQ_PLAYER && (i == TOOL_CTRL_ID_PLAYER_1 &&
3880 i == TOOL_CTRL_ID_PLAYER_2 &&
3881 i == TOOL_CTRL_ID_PLAYER_3 &&
3882 i == TOOL_CTRL_ID_PLAYER_4)))
3884 int x = tool_gadget[i]->x + dDX;
3885 int y = tool_gadget[i]->y + dDY;
3887 ModifyGadget(tool_gadget[i], GDI_X, x, GDI_Y, y, GDI_END);
3894 if (!global.use_envelope_request)
3895 OpenDoor(DOOR_OPEN_1);
3897 OpenDoor(DOOR_OPEN_1);
3900 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
3902 if (game_status == GAME_MODE_PLAYING)
3904 SetPanelBackground();
3905 SetDrawBackgroundMask(REDRAW_DOOR_1);
3909 SetDrawBackgroundMask(REDRAW_FIELD);
3916 if (game_status != GAME_MODE_MAIN && !global.use_envelope_request)
3919 if (game_status != GAME_MODE_MAIN)
3923 button_status = MB_RELEASED;
3925 request_gadget_id = -1;
3927 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3939 case EVENT_BUTTONPRESS:
3940 case EVENT_BUTTONRELEASE:
3941 case EVENT_MOTIONNOTIFY:
3943 if (event.type == EVENT_MOTIONNOTIFY)
3945 if (!PointerInWindow(window))
3946 continue; /* window and pointer are on different screens */
3951 motion_status = TRUE;
3952 mx = ((MotionEvent *) &event)->x;
3953 my = ((MotionEvent *) &event)->y;
3957 motion_status = FALSE;
3958 mx = ((ButtonEvent *) &event)->x;
3959 my = ((ButtonEvent *) &event)->y;
3960 if (event.type == EVENT_BUTTONPRESS)
3961 button_status = ((ButtonEvent *) &event)->button;
3963 button_status = MB_RELEASED;
3966 /* this sets 'request_gadget_id' */
3967 HandleGadgets(mx, my, button_status);
3969 switch (request_gadget_id)
3971 case TOOL_CTRL_ID_YES:
3974 case TOOL_CTRL_ID_NO:
3977 case TOOL_CTRL_ID_CONFIRM:
3978 result = TRUE | FALSE;
3981 case TOOL_CTRL_ID_PLAYER_1:
3984 case TOOL_CTRL_ID_PLAYER_2:
3987 case TOOL_CTRL_ID_PLAYER_3:
3990 case TOOL_CTRL_ID_PLAYER_4:
4001 case EVENT_KEYPRESS:
4002 switch (GetEventKey((KeyEvent *)&event, TRUE))
4005 if (req_state & REQ_CONFIRM)
4021 if (req_state & REQ_PLAYER)
4025 case EVENT_KEYRELEASE:
4026 ClearPlayerAction();
4030 HandleOtherEvents(&event);
4034 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
4036 int joy = AnyJoystick();
4038 if (joy & JOY_BUTTON_1)
4040 else if (joy & JOY_BUTTON_2)
4046 if (game_status == GAME_MODE_PLAYING && local_player->LevelSolved_GameEnd)
4048 HandleGameActions();
4054 if (!PendingEvent()) /* delay only if no pending events */
4059 game_status = GAME_MODE_PSEUDO_DOOR;
4065 game_status = last_game_status; /* restore current game status */
4073 if (!PendingEvent()) /* delay only if no pending events */
4076 /* don't eat all CPU time */
4083 if (game_status != GAME_MODE_MAIN)
4089 if (global.use_envelope_request)
4090 ShowEnvelopeDoor(text, ACTION_CLOSING);
4094 if (!(req_state & REQ_STAY_OPEN) && !global.use_envelope_request)
4096 if (!(req_state & REQ_STAY_OPEN))
4099 CloseDoor(DOOR_CLOSE_1);
4101 if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
4102 (req_state & REQ_REOPEN))
4103 OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
4108 if (game_status == GAME_MODE_PLAYING)
4110 SetPanelBackground();
4111 SetDrawBackgroundMask(REDRAW_DOOR_1);
4115 SetDrawBackgroundMask(REDRAW_FIELD);
4118 #if defined(NETWORK_AVALIABLE)
4119 /* continue network game after request */
4120 if (options.network &&
4121 game_status == GAME_MODE_PLAYING &&
4122 req_state & REQUEST_WAIT_FOR_INPUT)
4123 SendToServer_ContinuePlaying();
4126 /* restore deactivated drawing when quick-loading level tape recording */
4127 if (tape.playing && tape.deactivate_display)
4128 TapeDeactivateDisplayOn();
4133 unsigned int OpenDoor(unsigned int door_state)
4135 if (door_state & DOOR_COPY_BACK)
4137 if (door_state & DOOR_OPEN_1)
4138 BlitBitmap(bitmap_db_door, bitmap_db_door,
4139 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
4140 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
4142 if (door_state & DOOR_OPEN_2)
4143 BlitBitmap(bitmap_db_door, bitmap_db_door,
4144 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY2, VXSIZE, VYSIZE,
4145 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
4147 door_state &= ~DOOR_COPY_BACK;
4150 return MoveDoor(door_state);
4153 unsigned int CloseDoor(unsigned int door_state)
4155 unsigned int old_door_state = GetDoorState();
4157 if (!(door_state & DOOR_NO_COPY_BACK))
4159 if (old_door_state & DOOR_OPEN_1)
4160 BlitBitmap(backbuffer, bitmap_db_door,
4161 DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
4163 if (old_door_state & DOOR_OPEN_2)
4164 BlitBitmap(backbuffer, bitmap_db_door,
4165 VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
4167 door_state &= ~DOOR_NO_COPY_BACK;
4170 return MoveDoor(door_state);
4173 unsigned int GetDoorState()
4175 return MoveDoor(DOOR_GET_STATE);
4178 unsigned int SetDoorState(unsigned int door_state)
4180 return MoveDoor(door_state | DOOR_SET_STATE);
4183 unsigned int MoveDoor(unsigned int door_state)
4185 static int door1 = DOOR_OPEN_1;
4186 static int door2 = DOOR_CLOSE_2;
4187 unsigned long door_delay = 0;
4188 unsigned long door_delay_value;
4191 if (door_1.width < 0 || door_1.width > DXSIZE)
4192 door_1.width = DXSIZE;
4193 if (door_1.height < 0 || door_1.height > DYSIZE)
4194 door_1.height = DYSIZE;
4195 if (door_2.width < 0 || door_2.width > VXSIZE)
4196 door_2.width = VXSIZE;
4197 if (door_2.height < 0 || door_2.height > VYSIZE)
4198 door_2.height = VYSIZE;
4200 if (door_state == DOOR_GET_STATE)
4201 return (door1 | door2);
4203 if (door_state & DOOR_SET_STATE)
4205 if (door_state & DOOR_ACTION_1)
4206 door1 = door_state & DOOR_ACTION_1;
4207 if (door_state & DOOR_ACTION_2)
4208 door2 = door_state & DOOR_ACTION_2;
4210 return (door1 | door2);
4213 if (!(door_state & DOOR_FORCE_REDRAW))
4215 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
4216 door_state &= ~DOOR_OPEN_1;
4217 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
4218 door_state &= ~DOOR_CLOSE_1;
4219 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
4220 door_state &= ~DOOR_OPEN_2;
4221 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
4222 door_state &= ~DOOR_CLOSE_2;
4225 door_delay_value = (door_state & DOOR_ACTION_1 ? door_1.step_delay :
4228 if (setup.quick_doors)
4230 stepsize = 20; /* must be chosen to always draw last frame */
4231 door_delay_value = 0;
4234 if (global.autoplay_leveldir)
4236 door_state |= DOOR_NO_DELAY;
4237 door_state &= ~DOOR_CLOSE_ALL;
4241 if (game_status == GAME_MODE_EDITOR)
4242 door_state |= DOOR_NO_DELAY;
4245 if (door_state & DOOR_ACTION)
4247 boolean handle_door_1 = (door_state & DOOR_ACTION_1);
4248 boolean handle_door_2 = (door_state & DOOR_ACTION_2);
4249 boolean door_1_done = (!handle_door_1);
4250 boolean door_2_done = (!handle_door_2);
4251 boolean door_1_vertical = (door_1.anim_mode & ANIM_VERTICAL);
4252 boolean door_2_vertical = (door_2.anim_mode & ANIM_VERTICAL);
4253 int door_size_1 = (door_1_vertical ? door_1.height : door_1.width);
4254 int door_size_2 = (door_2_vertical ? door_2.height : door_2.width);
4255 int max_door_size_1 = (door_1_vertical ? DYSIZE : DXSIZE);
4256 int max_door_size_2 = (door_2_vertical ? VYSIZE : VXSIZE);
4257 int door_size = (handle_door_1 ? door_size_1 : door_size_2);
4258 int max_door_size = (handle_door_1 ? max_door_size_1 : max_door_size_2);
4259 int door_skip = max_door_size - door_size;
4260 int end = door_size;
4261 int start = ((door_state & DOOR_NO_DELAY) ? end : 0);
4264 if (!(door_state & DOOR_NO_DELAY) && !setup.quick_doors)
4266 /* opening door sound has priority over simultaneously closing door */
4267 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
4268 PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
4269 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
4270 PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
4273 for (k = start; k <= end && !(door_1_done && door_2_done); k += stepsize)
4276 Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
4277 GC gc = bitmap->stored_clip_gc;
4279 if (door_state & DOOR_ACTION_1)
4281 int a = MIN(x * door_1.step_offset, end);
4282 int p = (door_state & DOOR_OPEN_1 ? end - a : a);
4283 int i = p + door_skip;
4285 if (door_1.anim_mode & ANIM_STATIC_PANEL)
4287 BlitBitmap(bitmap_db_door, drawto,
4288 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1,
4289 DXSIZE, DYSIZE, DX, DY);
4293 BlitBitmap(bitmap_db_door, drawto,
4294 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + p / 2,
4295 DXSIZE, DYSIZE - p / 2, DX, DY);
4297 ClearRectangle(drawto, DX, DY + DYSIZE - p / 2, DXSIZE, p / 2);
4300 if (door_1.anim_mode & ANIM_HORIZONTAL && x <= DXSIZE)
4302 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
4303 int dst1_x = DX + DXSIZE - i, dst1_y = DY;
4304 int src2_x = DXSIZE - i, src2_y = DOOR_GFX_PAGEY1;
4305 int dst2_x = DX, dst2_y = DY;
4306 int width = i, height = DYSIZE;
4308 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
4309 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
4312 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
4313 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
4316 else if (door_1.anim_mode & ANIM_VERTICAL && x <= DYSIZE)
4318 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
4319 int dst1_x = DX, dst1_y = DY + DYSIZE - i;
4320 int src2_x = 0, src2_y = DOOR_GFX_PAGEY1 + DYSIZE - i;
4321 int dst2_x = DX, dst2_y = DY;
4322 int width = DXSIZE, height = i;
4324 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
4325 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
4328 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
4329 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
4332 else if (x <= DXSIZE) /* ANIM_DEFAULT */
4334 int j = (door_1.anim_mode == ANIM_DEFAULT ? (DXSIZE - i) / 3 : 0);
4336 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
4337 BlitBitmapMasked(bitmap, drawto,
4338 DXSIZE, DOOR_GFX_PAGEY1, i, 77,
4339 DX + DXSIZE - i, DY + j);
4340 BlitBitmapMasked(bitmap, drawto,
4341 DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
4342 DX + DXSIZE - i, DY + 140 + j);
4343 SetClipOrigin(bitmap, gc, DX - DXSIZE + i,
4344 DY - (DOOR_GFX_PAGEY1 + j));
4345 BlitBitmapMasked(bitmap, drawto,
4346 DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
4348 BlitBitmapMasked(bitmap, drawto,
4349 DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
4352 BlitBitmapMasked(bitmap, drawto,
4353 DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
4355 BlitBitmapMasked(bitmap, drawto,
4356 DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
4358 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
4359 BlitBitmapMasked(bitmap, drawto,
4360 DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
4361 DX + DXSIZE - i, DY + 77 + j);
4362 BlitBitmapMasked(bitmap, drawto,
4363 DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
4364 DX + DXSIZE - i, DY + 203 + j);
4367 redraw_mask |= REDRAW_DOOR_1;
4368 door_1_done = (a == end);
4371 if (door_state & DOOR_ACTION_2)
4373 int a = MIN(x * door_2.step_offset, door_size);
4374 int p = (door_state & DOOR_OPEN_2 ? door_size - a : a);
4375 int i = p + door_skip;
4377 if (door_2.anim_mode & ANIM_STATIC_PANEL)
4379 BlitBitmap(bitmap_db_door, drawto,
4380 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2,
4381 VXSIZE, VYSIZE, VX, VY);
4383 else if (x <= VYSIZE)
4385 BlitBitmap(bitmap_db_door, drawto,
4386 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + p / 2,
4387 VXSIZE, VYSIZE - p / 2, VX, VY);
4389 ClearRectangle(drawto, VX, VY + VYSIZE - p / 2, VXSIZE, p / 2);
4392 if (door_2.anim_mode & ANIM_HORIZONTAL && x <= VXSIZE)
4394 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
4395 int dst1_x = VX + VXSIZE - i, dst1_y = VY;
4396 int src2_x = VXSIZE - i, src2_y = DOOR_GFX_PAGEY2;
4397 int dst2_x = VX, dst2_y = VY;
4398 int width = i, height = VYSIZE;
4400 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
4401 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
4404 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
4405 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
4408 else if (door_2.anim_mode & ANIM_VERTICAL && x <= VYSIZE)
4410 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
4411 int dst1_x = VX, dst1_y = VY + VYSIZE - i;
4412 int src2_x = 0, src2_y = DOOR_GFX_PAGEY2 + VYSIZE - i;
4413 int dst2_x = VX, dst2_y = VY;
4414 int width = VXSIZE, height = i;
4416 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
4417 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
4420 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
4421 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
4424 else if (x <= VXSIZE) /* ANIM_DEFAULT */
4426 int j = (door_2.anim_mode == ANIM_DEFAULT ? (VXSIZE - i) / 3 : 0);
4428 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
4429 BlitBitmapMasked(bitmap, drawto,
4430 VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
4431 VX + VXSIZE - i, VY + j);
4432 SetClipOrigin(bitmap, gc,
4433 VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
4434 BlitBitmapMasked(bitmap, drawto,
4435 VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
4438 BlitBitmapMasked(bitmap, drawto,
4439 VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
4440 i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
4441 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
4442 BlitBitmapMasked(bitmap, drawto,
4443 VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
4445 VX + VXSIZE - i, VY + VYSIZE / 2 + j);
4448 redraw_mask |= REDRAW_DOOR_2;
4449 door_2_done = (a == VXSIZE);
4452 if (!(door_state & DOOR_NO_DELAY))
4456 if (game_status == GAME_MODE_MAIN)
4459 WaitUntilDelayReached(&door_delay, door_delay_value);
4464 if (door_state & DOOR_ACTION_1)
4465 door1 = door_state & DOOR_ACTION_1;
4466 if (door_state & DOOR_ACTION_2)
4467 door2 = door_state & DOOR_ACTION_2;
4469 return (door1 | door2);
4472 void DrawSpecialEditorDoor()
4474 /* draw bigger toolbox window */
4475 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
4476 DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
4478 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
4479 EX - 6, VY - 4, EXSIZE + 12, EYSIZE - VYSIZE + 4,
4482 redraw_mask |= REDRAW_ALL;
4485 void UndrawSpecialEditorDoor()
4487 /* draw normal tape recorder window */
4488 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
4489 EX - 6, EY - 12, EXSIZE + 12, EYSIZE - VYSIZE + 12,
4492 redraw_mask |= REDRAW_ALL;
4496 /* ---------- new tool button stuff ---------------------------------------- */
4498 /* graphic position values for tool buttons */
4499 #define TOOL_BUTTON_YES_XPOS 2
4500 #define TOOL_BUTTON_YES_YPOS 250
4501 #define TOOL_BUTTON_YES_GFX_YPOS 0
4502 #define TOOL_BUTTON_YES_XSIZE 46
4503 #define TOOL_BUTTON_YES_YSIZE 28
4504 #define TOOL_BUTTON_NO_XPOS 52
4505 #define TOOL_BUTTON_NO_YPOS TOOL_BUTTON_YES_YPOS
4506 #define TOOL_BUTTON_NO_GFX_YPOS TOOL_BUTTON_YES_GFX_YPOS
4507 #define TOOL_BUTTON_NO_XSIZE TOOL_BUTTON_YES_XSIZE
4508 #define TOOL_BUTTON_NO_YSIZE TOOL_BUTTON_YES_YSIZE
4509 #define TOOL_BUTTON_CONFIRM_XPOS TOOL_BUTTON_YES_XPOS
4510 #define TOOL_BUTTON_CONFIRM_YPOS TOOL_BUTTON_YES_YPOS
4511 #define TOOL_BUTTON_CONFIRM_GFX_YPOS 30
4512 #define TOOL_BUTTON_CONFIRM_XSIZE 96
4513 #define TOOL_BUTTON_CONFIRM_YSIZE TOOL_BUTTON_YES_YSIZE
4514 #define TOOL_BUTTON_PLAYER_XSIZE 30
4515 #define TOOL_BUTTON_PLAYER_YSIZE 30
4516 #define TOOL_BUTTON_PLAYER_GFX_XPOS 5
4517 #define TOOL_BUTTON_PLAYER_GFX_YPOS 185
4518 #define TOOL_BUTTON_PLAYER_XPOS (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
4519 #define TOOL_BUTTON_PLAYER_YPOS (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
4520 #define TOOL_BUTTON_PLAYER1_XPOS (TOOL_BUTTON_PLAYER_XPOS \
4521 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
4522 #define TOOL_BUTTON_PLAYER2_XPOS (TOOL_BUTTON_PLAYER_XPOS \
4523 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
4524 #define TOOL_BUTTON_PLAYER3_XPOS (TOOL_BUTTON_PLAYER_XPOS \
4525 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
4526 #define TOOL_BUTTON_PLAYER4_XPOS (TOOL_BUTTON_PLAYER_XPOS \
4527 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
4528 #define TOOL_BUTTON_PLAYER1_YPOS (TOOL_BUTTON_PLAYER_YPOS \
4529 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
4530 #define TOOL_BUTTON_PLAYER2_YPOS (TOOL_BUTTON_PLAYER_YPOS \
4531 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
4532 #define TOOL_BUTTON_PLAYER3_YPOS (TOOL_BUTTON_PLAYER_YPOS \
4533 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
4534 #define TOOL_BUTTON_PLAYER4_YPOS (TOOL_BUTTON_PLAYER_YPOS \
4535 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
4544 } toolbutton_info[NUM_TOOL_BUTTONS] =
4547 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_GFX_YPOS,
4548 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_YPOS,
4549 TOOL_BUTTON_YES_XSIZE, TOOL_BUTTON_YES_YSIZE,
4554 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_GFX_YPOS,
4555 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_YPOS,
4556 TOOL_BUTTON_NO_XSIZE, TOOL_BUTTON_NO_YSIZE,
4561 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_GFX_YPOS,
4562 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_YPOS,
4563 TOOL_BUTTON_CONFIRM_XSIZE, TOOL_BUTTON_CONFIRM_YSIZE,
4564 TOOL_CTRL_ID_CONFIRM,
4568 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
4569 TOOL_BUTTON_PLAYER1_XPOS, TOOL_BUTTON_PLAYER1_YPOS,
4570 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
4571 TOOL_CTRL_ID_PLAYER_1,
4575 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
4576 TOOL_BUTTON_PLAYER2_XPOS, TOOL_BUTTON_PLAYER2_YPOS,
4577 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
4578 TOOL_CTRL_ID_PLAYER_2,
4582 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
4583 TOOL_BUTTON_PLAYER3_XPOS, TOOL_BUTTON_PLAYER3_YPOS,
4584 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
4585 TOOL_CTRL_ID_PLAYER_3,
4589 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
4590 TOOL_BUTTON_PLAYER4_XPOS, TOOL_BUTTON_PLAYER4_YPOS,
4591 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
4592 TOOL_CTRL_ID_PLAYER_4,
4597 void CreateToolButtons()
4601 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4603 Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
4604 Bitmap *deco_bitmap = None;
4605 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
4606 struct GadgetInfo *gi;
4607 unsigned long event_mask;
4608 int gd_xoffset, gd_yoffset;
4609 int gd_x1, gd_x2, gd_y;
4612 event_mask = GD_EVENT_RELEASED;
4614 gd_xoffset = toolbutton_info[i].xpos;
4615 gd_yoffset = toolbutton_info[i].ypos;
4616 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
4617 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
4618 gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
4620 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
4622 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
4624 getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr),
4625 &deco_bitmap, &deco_x, &deco_y);
4626 deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
4627 deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
4630 gi = CreateGadget(GDI_CUSTOM_ID, id,
4631 GDI_INFO_TEXT, toolbutton_info[i].infotext,
4632 GDI_X, DX + toolbutton_info[i].x,
4633 GDI_Y, DY + toolbutton_info[i].y,
4634 GDI_WIDTH, toolbutton_info[i].width,
4635 GDI_HEIGHT, toolbutton_info[i].height,
4636 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
4637 GDI_STATE, GD_BUTTON_UNPRESSED,
4638 GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
4639 GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
4640 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
4641 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
4642 GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
4643 GDI_DECORATION_SHIFTING, 1, 1,
4644 GDI_DIRECT_DRAW, FALSE,
4645 GDI_EVENT_MASK, event_mask,
4646 GDI_CALLBACK_ACTION, HandleToolButtons,
4650 Error(ERR_EXIT, "cannot create gadget");
4652 tool_gadget[id] = gi;
4656 void FreeToolButtons()
4660 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4661 FreeGadget(tool_gadget[i]);
4664 static void UnmapToolButtons()
4668 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4669 UnmapGadget(tool_gadget[i]);
4672 static void HandleToolButtons(struct GadgetInfo *gi)
4674 request_gadget_id = gi->custom_id;
4677 static struct Mapping_EM_to_RND_object
4680 boolean is_rnd_to_em_mapping; /* unique mapping EM <-> RND */
4681 boolean is_backside; /* backside of moving element */
4687 em_object_mapping_list[] =
4690 Xblank, TRUE, FALSE,
4694 Yacid_splash_eB, FALSE, FALSE,
4695 EL_ACID_SPLASH_RIGHT, -1, -1
4698 Yacid_splash_wB, FALSE, FALSE,
4699 EL_ACID_SPLASH_LEFT, -1, -1
4702 #ifdef EM_ENGINE_BAD_ROLL
4704 Xstone_force_e, FALSE, FALSE,
4705 EL_ROCK, -1, MV_BIT_RIGHT
4708 Xstone_force_w, FALSE, FALSE,
4709 EL_ROCK, -1, MV_BIT_LEFT
4712 Xnut_force_e, FALSE, FALSE,
4713 EL_NUT, -1, MV_BIT_RIGHT
4716 Xnut_force_w, FALSE, FALSE,
4717 EL_NUT, -1, MV_BIT_LEFT
4720 Xspring_force_e, FALSE, FALSE,
4721 EL_SPRING, -1, MV_BIT_RIGHT
4724 Xspring_force_w, FALSE, FALSE,
4725 EL_SPRING, -1, MV_BIT_LEFT
4728 Xemerald_force_e, FALSE, FALSE,
4729 EL_EMERALD, -1, MV_BIT_RIGHT
4732 Xemerald_force_w, FALSE, FALSE,
4733 EL_EMERALD, -1, MV_BIT_LEFT
4736 Xdiamond_force_e, FALSE, FALSE,
4737 EL_DIAMOND, -1, MV_BIT_RIGHT
4740 Xdiamond_force_w, FALSE, FALSE,
4741 EL_DIAMOND, -1, MV_BIT_LEFT
4744 Xbomb_force_e, FALSE, FALSE,
4745 EL_BOMB, -1, MV_BIT_RIGHT
4748 Xbomb_force_w, FALSE, FALSE,
4749 EL_BOMB, -1, MV_BIT_LEFT
4751 #endif /* EM_ENGINE_BAD_ROLL */
4754 Xstone, TRUE, FALSE,
4758 Xstone_pause, FALSE, FALSE,
4762 Xstone_fall, FALSE, FALSE,
4766 Ystone_s, FALSE, FALSE,
4767 EL_ROCK, ACTION_FALLING, -1
4770 Ystone_sB, FALSE, TRUE,
4771 EL_ROCK, ACTION_FALLING, -1
4774 Ystone_e, FALSE, FALSE,
4775 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
4778 Ystone_eB, FALSE, TRUE,
4779 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
4782 Ystone_w, FALSE, FALSE,
4783 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
4786 Ystone_wB, FALSE, TRUE,
4787 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
4794 Xnut_pause, FALSE, FALSE,
4798 Xnut_fall, FALSE, FALSE,
4802 Ynut_s, FALSE, FALSE,
4803 EL_NUT, ACTION_FALLING, -1
4806 Ynut_sB, FALSE, TRUE,
4807 EL_NUT, ACTION_FALLING, -1
4810 Ynut_e, FALSE, FALSE,
4811 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
4814 Ynut_eB, FALSE, TRUE,
4815 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
4818 Ynut_w, FALSE, FALSE,
4819 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
4822 Ynut_wB, FALSE, TRUE,
4823 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
4826 Xbug_n, TRUE, FALSE,
4830 Xbug_e, TRUE, FALSE,
4831 EL_BUG_RIGHT, -1, -1
4834 Xbug_s, TRUE, FALSE,
4838 Xbug_w, TRUE, FALSE,
4842 Xbug_gon, FALSE, FALSE,
4846 Xbug_goe, FALSE, FALSE,
4847 EL_BUG_RIGHT, -1, -1
4850 Xbug_gos, FALSE, FALSE,
4854 Xbug_gow, FALSE, FALSE,
4858 Ybug_n, FALSE, FALSE,
4859 EL_BUG, ACTION_MOVING, MV_BIT_UP
4862 Ybug_nB, FALSE, TRUE,
4863 EL_BUG, ACTION_MOVING, MV_BIT_UP
4866 Ybug_e, FALSE, FALSE,
4867 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
4870 Ybug_eB, FALSE, TRUE,
4871 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
4874 Ybug_s, FALSE, FALSE,
4875 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
4878 Ybug_sB, FALSE, TRUE,
4879 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
4882 Ybug_w, FALSE, FALSE,
4883 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
4886 Ybug_wB, FALSE, TRUE,
4887 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
4890 Ybug_w_n, FALSE, FALSE,
4891 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
4894 Ybug_n_e, FALSE, FALSE,
4895 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
4898 Ybug_e_s, FALSE, FALSE,
4899 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
4902 Ybug_s_w, FALSE, FALSE,
4903 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
4906 Ybug_e_n, FALSE, FALSE,
4907 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
4910 Ybug_s_e, FALSE, FALSE,
4911 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
4914 Ybug_w_s, FALSE, FALSE,
4915 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
4918 Ybug_n_w, FALSE, FALSE,
4919 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
4922 Ybug_stone, FALSE, FALSE,
4923 EL_BUG, ACTION_SMASHED_BY_ROCK, -1
4926 Ybug_spring, FALSE, FALSE,
4927 EL_BUG, ACTION_SMASHED_BY_SPRING, -1
4930 Xtank_n, TRUE, FALSE,
4931 EL_SPACESHIP_UP, -1, -1
4934 Xtank_e, TRUE, FALSE,
4935 EL_SPACESHIP_RIGHT, -1, -1
4938 Xtank_s, TRUE, FALSE,
4939 EL_SPACESHIP_DOWN, -1, -1
4942 Xtank_w, TRUE, FALSE,
4943 EL_SPACESHIP_LEFT, -1, -1
4946 Xtank_gon, FALSE, FALSE,
4947 EL_SPACESHIP_UP, -1, -1
4950 Xtank_goe, FALSE, FALSE,
4951 EL_SPACESHIP_RIGHT, -1, -1
4954 Xtank_gos, FALSE, FALSE,
4955 EL_SPACESHIP_DOWN, -1, -1
4958 Xtank_gow, FALSE, FALSE,
4959 EL_SPACESHIP_LEFT, -1, -1
4962 Ytank_n, FALSE, FALSE,
4963 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
4966 Ytank_nB, FALSE, TRUE,
4967 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
4970 Ytank_e, FALSE, FALSE,
4971 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
4974 Ytank_eB, FALSE, TRUE,
4975 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
4978 Ytank_s, FALSE, FALSE,
4979 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
4982 Ytank_sB, FALSE, TRUE,
4983 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
4986 Ytank_w, FALSE, FALSE,
4987 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
4990 Ytank_wB, FALSE, TRUE,
4991 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
4994 Ytank_w_n, FALSE, FALSE,
4995 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
4998 Ytank_n_e, FALSE, FALSE,
4999 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
5002 Ytank_e_s, FALSE, FALSE,
5003 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
5006 Ytank_s_w, FALSE, FALSE,
5007 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
5010 Ytank_e_n, FALSE, FALSE,
5011 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
5014 Ytank_s_e, FALSE, FALSE,
5015 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
5018 Ytank_w_s, FALSE, FALSE,
5019 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
5022 Ytank_n_w, FALSE, FALSE,
5023 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
5026 Ytank_stone, FALSE, FALSE,
5027 EL_SPACESHIP, ACTION_SMASHED_BY_ROCK, -1
5030 Ytank_spring, FALSE, FALSE,
5031 EL_SPACESHIP, ACTION_SMASHED_BY_SPRING, -1
5034 Xandroid, TRUE, FALSE,
5035 EL_EMC_ANDROID, ACTION_ACTIVE, -1
5038 Xandroid_1_n, FALSE, FALSE,
5039 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
5042 Xandroid_2_n, FALSE, FALSE,
5043 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
5046 Xandroid_1_e, FALSE, FALSE,
5047 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
5050 Xandroid_2_e, FALSE, FALSE,
5051 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
5054 Xandroid_1_w, FALSE, FALSE,
5055 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
5058 Xandroid_2_w, FALSE, FALSE,
5059 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
5062 Xandroid_1_s, FALSE, FALSE,
5063 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
5066 Xandroid_2_s, FALSE, FALSE,
5067 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
5070 Yandroid_n, FALSE, FALSE,
5071 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
5074 Yandroid_nB, FALSE, TRUE,
5075 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
5078 Yandroid_ne, FALSE, FALSE,
5079 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPRIGHT
5082 Yandroid_neB, FALSE, TRUE,
5083 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPRIGHT
5086 Yandroid_e, FALSE, FALSE,
5087 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
5090 Yandroid_eB, FALSE, TRUE,
5091 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
5094 Yandroid_se, FALSE, FALSE,
5095 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNRIGHT
5098 Yandroid_seB, FALSE, TRUE,
5099 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNRIGHT
5102 Yandroid_s, FALSE, FALSE,
5103 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
5106 Yandroid_sB, FALSE, TRUE,
5107 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
5110 Yandroid_sw, FALSE, FALSE,
5111 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNLEFT
5114 Yandroid_swB, FALSE, TRUE,
5115 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNLEFT
5118 Yandroid_w, FALSE, FALSE,
5119 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
5122 Yandroid_wB, FALSE, TRUE,
5123 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
5126 Yandroid_nw, FALSE, FALSE,
5127 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPLEFT
5130 Yandroid_nwB, FALSE, TRUE,
5131 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPLEFT
5134 Xspring, TRUE, FALSE,
5138 Xspring_pause, FALSE, FALSE,
5142 Xspring_e, FALSE, FALSE,
5146 Xspring_w, FALSE, FALSE,
5150 Xspring_fall, FALSE, FALSE,
5154 Yspring_s, FALSE, FALSE,
5155 EL_SPRING, ACTION_FALLING, -1
5158 Yspring_sB, FALSE, TRUE,
5159 EL_SPRING, ACTION_FALLING, -1
5162 Yspring_e, FALSE, FALSE,
5163 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
5166 Yspring_eB, FALSE, TRUE,
5167 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
5170 Yspring_w, FALSE, FALSE,
5171 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
5174 Yspring_wB, FALSE, TRUE,
5175 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
5178 Yspring_kill_e, FALSE, FALSE,
5179 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
5182 Yspring_kill_eB, FALSE, TRUE,
5183 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
5186 Yspring_kill_w, FALSE, FALSE,
5187 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
5190 Yspring_kill_wB, FALSE, TRUE,
5191 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
5194 Xeater_n, TRUE, FALSE,
5195 EL_YAMYAM_UP, -1, -1
5198 Xeater_e, TRUE, FALSE,
5199 EL_YAMYAM_RIGHT, -1, -1
5202 Xeater_w, TRUE, FALSE,
5203 EL_YAMYAM_LEFT, -1, -1
5206 Xeater_s, TRUE, FALSE,
5207 EL_YAMYAM_DOWN, -1, -1
5210 Yeater_n, FALSE, FALSE,
5211 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
5214 Yeater_nB, FALSE, TRUE,
5215 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
5218 Yeater_e, FALSE, FALSE,
5219 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
5222 Yeater_eB, FALSE, TRUE,
5223 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
5226 Yeater_s, FALSE, FALSE,
5227 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
5230 Yeater_sB, FALSE, TRUE,
5231 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
5234 Yeater_w, FALSE, FALSE,
5235 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
5238 Yeater_wB, FALSE, TRUE,
5239 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
5242 Yeater_stone, FALSE, FALSE,
5243 EL_YAMYAM, ACTION_SMASHED_BY_ROCK, -1
5246 Yeater_spring, FALSE, FALSE,
5247 EL_YAMYAM, ACTION_SMASHED_BY_SPRING, -1
5250 Xalien, TRUE, FALSE,
5254 Xalien_pause, FALSE, FALSE,
5258 Yalien_n, FALSE, FALSE,
5259 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
5262 Yalien_nB, FALSE, TRUE,
5263 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
5266 Yalien_e, FALSE, FALSE,
5267 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
5270 Yalien_eB, FALSE, TRUE,
5271 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
5274 Yalien_s, FALSE, FALSE,
5275 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
5278 Yalien_sB, FALSE, TRUE,
5279 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
5282 Yalien_w, FALSE, FALSE,
5283 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
5286 Yalien_wB, FALSE, TRUE,
5287 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
5290 Yalien_stone, FALSE, FALSE,
5291 EL_ROBOT, ACTION_SMASHED_BY_ROCK, -1
5294 Yalien_spring, FALSE, FALSE,
5295 EL_ROBOT, ACTION_SMASHED_BY_SPRING, -1
5298 Xemerald, TRUE, FALSE,
5302 Xemerald_pause, FALSE, FALSE,
5306 Xemerald_fall, FALSE, FALSE,
5310 Xemerald_shine, FALSE, FALSE,
5311 EL_EMERALD, ACTION_TWINKLING, -1
5314 Yemerald_s, FALSE, FALSE,
5315 EL_EMERALD, ACTION_FALLING, -1
5318 Yemerald_sB, FALSE, TRUE,
5319 EL_EMERALD, ACTION_FALLING, -1
5322 Yemerald_e, FALSE, FALSE,
5323 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
5326 Yemerald_eB, FALSE, TRUE,
5327 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
5330 Yemerald_w, FALSE, FALSE,
5331 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
5334 Yemerald_wB, FALSE, TRUE,
5335 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
5338 Yemerald_eat, FALSE, FALSE,
5339 EL_EMERALD, ACTION_COLLECTING, -1
5342 Yemerald_stone, FALSE, FALSE,
5343 EL_NUT, ACTION_BREAKING, -1
5346 Xdiamond, TRUE, FALSE,
5350 Xdiamond_pause, FALSE, FALSE,
5354 Xdiamond_fall, FALSE, FALSE,
5358 Xdiamond_shine, FALSE, FALSE,
5359 EL_DIAMOND, ACTION_TWINKLING, -1
5362 Ydiamond_s, FALSE, FALSE,
5363 EL_DIAMOND, ACTION_FALLING, -1
5366 Ydiamond_sB, FALSE, TRUE,
5367 EL_DIAMOND, ACTION_FALLING, -1
5370 Ydiamond_e, FALSE, FALSE,
5371 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
5374 Ydiamond_eB, FALSE, TRUE,
5375 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
5378 Ydiamond_w, FALSE, FALSE,
5379 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
5382 Ydiamond_wB, FALSE, TRUE,
5383 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
5386 Ydiamond_eat, FALSE, FALSE,
5387 EL_DIAMOND, ACTION_COLLECTING, -1
5390 Ydiamond_stone, FALSE, FALSE,
5391 EL_DIAMOND, ACTION_SMASHED_BY_ROCK, -1
5394 Xdrip_fall, TRUE, FALSE,
5395 EL_AMOEBA_DROP, -1, -1
5398 Xdrip_stretch, FALSE, FALSE,
5399 EL_AMOEBA_DROP, ACTION_FALLING, -1
5402 Xdrip_stretchB, FALSE, TRUE,
5403 EL_AMOEBA_DROP, ACTION_FALLING, -1
5406 Xdrip_eat, FALSE, FALSE,
5407 EL_AMOEBA_DROP, ACTION_GROWING, -1
5410 Ydrip_s1, FALSE, FALSE,
5411 EL_AMOEBA_DROP, ACTION_FALLING, -1
5414 Ydrip_s1B, FALSE, TRUE,
5415 EL_AMOEBA_DROP, ACTION_FALLING, -1
5418 Ydrip_s2, FALSE, FALSE,
5419 EL_AMOEBA_DROP, ACTION_FALLING, -1
5422 Ydrip_s2B, FALSE, TRUE,
5423 EL_AMOEBA_DROP, ACTION_FALLING, -1
5430 Xbomb_pause, FALSE, FALSE,
5434 Xbomb_fall, FALSE, FALSE,
5438 Ybomb_s, FALSE, FALSE,
5439 EL_BOMB, ACTION_FALLING, -1
5442 Ybomb_sB, FALSE, TRUE,
5443 EL_BOMB, ACTION_FALLING, -1
5446 Ybomb_e, FALSE, FALSE,
5447 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
5450 Ybomb_eB, FALSE, TRUE,
5451 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
5454 Ybomb_w, FALSE, FALSE,
5455 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
5458 Ybomb_wB, FALSE, TRUE,
5459 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
5462 Ybomb_eat, FALSE, FALSE,
5463 EL_BOMB, ACTION_ACTIVATING, -1
5466 Xballoon, TRUE, FALSE,
5470 Yballoon_n, FALSE, FALSE,
5471 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
5474 Yballoon_nB, FALSE, TRUE,
5475 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
5478 Yballoon_e, FALSE, FALSE,
5479 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
5482 Yballoon_eB, FALSE, TRUE,
5483 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
5486 Yballoon_s, FALSE, FALSE,
5487 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
5490 Yballoon_sB, FALSE, TRUE,
5491 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
5494 Yballoon_w, FALSE, FALSE,
5495 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
5498 Yballoon_wB, FALSE, TRUE,
5499 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
5502 Xgrass, TRUE, FALSE,
5503 EL_EMC_GRASS, -1, -1
5506 Ygrass_nB, FALSE, FALSE,
5507 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_UP
5510 Ygrass_eB, FALSE, FALSE,
5511 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_RIGHT
5514 Ygrass_sB, FALSE, FALSE,
5515 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_DOWN
5518 Ygrass_wB, FALSE, FALSE,
5519 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_LEFT
5526 Ydirt_nB, FALSE, FALSE,
5527 EL_SAND, ACTION_DIGGING, MV_BIT_UP
5530 Ydirt_eB, FALSE, FALSE,
5531 EL_SAND, ACTION_DIGGING, MV_BIT_RIGHT
5534 Ydirt_sB, FALSE, FALSE,
5535 EL_SAND, ACTION_DIGGING, MV_BIT_DOWN
5538 Ydirt_wB, FALSE, FALSE,
5539 EL_SAND, ACTION_DIGGING, MV_BIT_LEFT
5542 Xacid_ne, TRUE, FALSE,
5543 EL_ACID_POOL_TOPRIGHT, -1, -1
5546 Xacid_se, TRUE, FALSE,
5547 EL_ACID_POOL_BOTTOMRIGHT, -1, -1
5550 Xacid_s, TRUE, FALSE,
5551 EL_ACID_POOL_BOTTOM, -1, -1
5554 Xacid_sw, TRUE, FALSE,
5555 EL_ACID_POOL_BOTTOMLEFT, -1, -1
5558 Xacid_nw, TRUE, FALSE,
5559 EL_ACID_POOL_TOPLEFT, -1, -1
5562 Xacid_1, TRUE, FALSE,
5566 Xacid_2, FALSE, FALSE,
5570 Xacid_3, FALSE, FALSE,
5574 Xacid_4, FALSE, FALSE,
5578 Xacid_5, FALSE, FALSE,
5582 Xacid_6, FALSE, FALSE,
5586 Xacid_7, FALSE, FALSE,
5590 Xacid_8, FALSE, FALSE,
5594 Xball_1, TRUE, FALSE,
5595 EL_EMC_MAGIC_BALL, -1, -1
5598 Xball_1B, FALSE, FALSE,
5599 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
5602 Xball_2, FALSE, FALSE,
5603 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
5606 Xball_2B, FALSE, FALSE,
5607 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
5610 Yball_eat, FALSE, FALSE,
5611 EL_EMC_MAGIC_BALL, ACTION_DROPPING, -1
5614 Ykey_1_eat, FALSE, FALSE,
5615 EL_EM_KEY_1, ACTION_COLLECTING, -1
5618 Ykey_2_eat, FALSE, FALSE,
5619 EL_EM_KEY_2, ACTION_COLLECTING, -1
5622 Ykey_3_eat, FALSE, FALSE,
5623 EL_EM_KEY_3, ACTION_COLLECTING, -1
5626 Ykey_4_eat, FALSE, FALSE,
5627 EL_EM_KEY_4, ACTION_COLLECTING, -1
5630 Ykey_5_eat, FALSE, FALSE,
5631 EL_EMC_KEY_5, ACTION_COLLECTING, -1
5634 Ykey_6_eat, FALSE, FALSE,
5635 EL_EMC_KEY_6, ACTION_COLLECTING, -1
5638 Ykey_7_eat, FALSE, FALSE,
5639 EL_EMC_KEY_7, ACTION_COLLECTING, -1
5642 Ykey_8_eat, FALSE, FALSE,
5643 EL_EMC_KEY_8, ACTION_COLLECTING, -1
5646 Ylenses_eat, FALSE, FALSE,
5647 EL_EMC_LENSES, ACTION_COLLECTING, -1
5650 Ymagnify_eat, FALSE, FALSE,
5651 EL_EMC_MAGNIFIER, ACTION_COLLECTING, -1
5654 Ygrass_eat, FALSE, FALSE,
5655 EL_EMC_GRASS, ACTION_SNAPPING, -1
5658 Ydirt_eat, FALSE, FALSE,
5659 EL_SAND, ACTION_SNAPPING, -1
5662 Xgrow_ns, TRUE, FALSE,
5663 EL_EXPANDABLE_WALL_VERTICAL, -1, -1
5666 Ygrow_ns_eat, FALSE, FALSE,
5667 EL_EXPANDABLE_WALL_VERTICAL, ACTION_GROWING, -1
5670 Xgrow_ew, TRUE, FALSE,
5671 EL_EXPANDABLE_WALL_HORIZONTAL, -1, -1
5674 Ygrow_ew_eat, FALSE, FALSE,
5675 EL_EXPANDABLE_WALL_HORIZONTAL, ACTION_GROWING, -1
5678 Xwonderwall, TRUE, FALSE,
5679 EL_MAGIC_WALL, -1, -1
5682 XwonderwallB, FALSE, FALSE,
5683 EL_MAGIC_WALL, ACTION_ACTIVE, -1
5686 Xamoeba_1, TRUE, FALSE,
5687 EL_AMOEBA_DRY, ACTION_OTHER, -1
5690 Xamoeba_2, FALSE, FALSE,
5691 EL_AMOEBA_DRY, ACTION_OTHER, -1
5694 Xamoeba_3, FALSE, FALSE,
5695 EL_AMOEBA_DRY, ACTION_OTHER, -1
5698 Xamoeba_4, FALSE, FALSE,
5699 EL_AMOEBA_DRY, ACTION_OTHER, -1
5702 Xamoeba_5, TRUE, FALSE,
5703 EL_AMOEBA_WET, ACTION_OTHER, -1
5706 Xamoeba_6, FALSE, FALSE,
5707 EL_AMOEBA_WET, ACTION_OTHER, -1
5710 Xamoeba_7, FALSE, FALSE,
5711 EL_AMOEBA_WET, ACTION_OTHER, -1
5714 Xamoeba_8, FALSE, FALSE,
5715 EL_AMOEBA_WET, ACTION_OTHER, -1
5718 Xdoor_1, TRUE, FALSE,
5719 EL_EM_GATE_1, -1, -1
5722 Xdoor_2, TRUE, FALSE,
5723 EL_EM_GATE_2, -1, -1
5726 Xdoor_3, TRUE, FALSE,
5727 EL_EM_GATE_3, -1, -1
5730 Xdoor_4, TRUE, FALSE,
5731 EL_EM_GATE_4, -1, -1
5734 Xdoor_5, TRUE, FALSE,
5735 EL_EMC_GATE_5, -1, -1
5738 Xdoor_6, TRUE, FALSE,
5739 EL_EMC_GATE_6, -1, -1
5742 Xdoor_7, TRUE, FALSE,
5743 EL_EMC_GATE_7, -1, -1
5746 Xdoor_8, TRUE, FALSE,
5747 EL_EMC_GATE_8, -1, -1
5750 Xkey_1, TRUE, FALSE,
5754 Xkey_2, TRUE, FALSE,
5758 Xkey_3, TRUE, FALSE,
5762 Xkey_4, TRUE, FALSE,
5766 Xkey_5, TRUE, FALSE,
5767 EL_EMC_KEY_5, -1, -1
5770 Xkey_6, TRUE, FALSE,
5771 EL_EMC_KEY_6, -1, -1
5774 Xkey_7, TRUE, FALSE,
5775 EL_EMC_KEY_7, -1, -1
5778 Xkey_8, TRUE, FALSE,
5779 EL_EMC_KEY_8, -1, -1
5782 Xwind_n, TRUE, FALSE,
5783 EL_BALLOON_SWITCH_UP, -1, -1
5786 Xwind_e, TRUE, FALSE,
5787 EL_BALLOON_SWITCH_RIGHT, -1, -1
5790 Xwind_s, TRUE, FALSE,
5791 EL_BALLOON_SWITCH_DOWN, -1, -1
5794 Xwind_w, TRUE, FALSE,
5795 EL_BALLOON_SWITCH_LEFT, -1, -1
5798 Xwind_nesw, TRUE, FALSE,
5799 EL_BALLOON_SWITCH_ANY, -1, -1
5802 Xwind_stop, TRUE, FALSE,
5803 EL_BALLOON_SWITCH_NONE, -1, -1
5807 EL_EM_EXIT_CLOSED, -1, -1
5810 Xexit_1, TRUE, FALSE,
5811 EL_EM_EXIT_OPEN, -1, -1
5814 Xexit_2, FALSE, FALSE,
5815 EL_EM_EXIT_OPEN, -1, -1
5818 Xexit_3, FALSE, FALSE,
5819 EL_EM_EXIT_OPEN, -1, -1
5822 Xdynamite, TRUE, FALSE,
5823 EL_EM_DYNAMITE, -1, -1
5826 Ydynamite_eat, FALSE, FALSE,
5827 EL_EM_DYNAMITE, ACTION_COLLECTING, -1
5830 Xdynamite_1, TRUE, FALSE,
5831 EL_EM_DYNAMITE_ACTIVE, -1, -1
5834 Xdynamite_2, FALSE, FALSE,
5835 EL_EM_DYNAMITE_ACTIVE, -1, -1
5838 Xdynamite_3, FALSE, FALSE,
5839 EL_EM_DYNAMITE_ACTIVE, -1, -1
5842 Xdynamite_4, FALSE, FALSE,
5843 EL_EM_DYNAMITE_ACTIVE, -1, -1
5846 Xbumper, TRUE, FALSE,
5847 EL_EMC_SPRING_BUMPER, -1, -1
5850 XbumperB, FALSE, FALSE,
5851 EL_EMC_SPRING_BUMPER, ACTION_ACTIVE, -1
5854 Xwheel, TRUE, FALSE,
5855 EL_ROBOT_WHEEL, -1, -1
5858 XwheelB, FALSE, FALSE,
5859 EL_ROBOT_WHEEL, ACTION_ACTIVE, -1
5862 Xswitch, TRUE, FALSE,
5863 EL_EMC_MAGIC_BALL_SWITCH, -1, -1
5866 XswitchB, FALSE, FALSE,
5867 EL_EMC_MAGIC_BALL_SWITCH, ACTION_ACTIVE, -1
5871 EL_QUICKSAND_EMPTY, -1, -1
5874 Xsand_stone, TRUE, FALSE,
5875 EL_QUICKSAND_FULL, -1, -1
5878 Xsand_stonein_1, FALSE, TRUE,
5879 EL_ROCK, ACTION_FILLING, -1
5882 Xsand_stonein_2, FALSE, TRUE,
5883 EL_ROCK, ACTION_FILLING, -1
5886 Xsand_stonein_3, FALSE, TRUE,
5887 EL_ROCK, ACTION_FILLING, -1
5890 Xsand_stonein_4, FALSE, TRUE,
5891 EL_ROCK, ACTION_FILLING, -1
5895 Xsand_stonesand_1, FALSE, FALSE,
5896 EL_QUICKSAND_EMPTYING, -1, -1
5899 Xsand_stonesand_2, FALSE, FALSE,
5900 EL_QUICKSAND_EMPTYING, -1, -1
5903 Xsand_stonesand_3, FALSE, FALSE,
5904 EL_QUICKSAND_EMPTYING, -1, -1
5907 Xsand_stonesand_4, FALSE, FALSE,
5908 EL_QUICKSAND_EMPTYING, -1, -1
5911 Xsand_stonesand_quickout_1, FALSE, FALSE,
5912 EL_QUICKSAND_EMPTYING, -1, -1
5915 Xsand_stonesand_quickout_2, FALSE, FALSE,
5916 EL_QUICKSAND_EMPTYING, -1, -1
5920 Xsand_stonesand_1, FALSE, FALSE,
5921 EL_QUICKSAND_FULL, -1, -1
5924 Xsand_stonesand_2, FALSE, FALSE,
5925 EL_QUICKSAND_FULL, -1, -1
5928 Xsand_stonesand_3, FALSE, FALSE,
5929 EL_QUICKSAND_FULL, -1, -1
5932 Xsand_stonesand_4, FALSE, FALSE,
5933 EL_QUICKSAND_FULL, -1, -1
5937 Xsand_stoneout_1, FALSE, FALSE,
5938 EL_ROCK, ACTION_EMPTYING, -1
5941 Xsand_stoneout_2, FALSE, FALSE,
5942 EL_ROCK, ACTION_EMPTYING, -1
5946 Xsand_sandstone_1, FALSE, FALSE,
5947 EL_QUICKSAND_FILLING, -1, -1
5950 Xsand_sandstone_2, FALSE, FALSE,
5951 EL_QUICKSAND_FILLING, -1, -1
5954 Xsand_sandstone_3, FALSE, FALSE,
5955 EL_QUICKSAND_FILLING, -1, -1
5958 Xsand_sandstone_4, FALSE, FALSE,
5959 EL_QUICKSAND_FILLING, -1, -1
5963 Xsand_sandstone_1, FALSE, FALSE,
5964 EL_QUICKSAND_FULL, -1, -1
5967 Xsand_sandstone_2, FALSE, FALSE,
5968 EL_QUICKSAND_FULL, -1, -1
5971 Xsand_sandstone_3, FALSE, FALSE,
5972 EL_QUICKSAND_FULL, -1, -1
5975 Xsand_sandstone_4, FALSE, FALSE,
5976 EL_QUICKSAND_FULL, -1, -1
5980 Xplant, TRUE, FALSE,
5981 EL_EMC_PLANT, -1, -1
5984 Yplant, FALSE, FALSE,
5985 EL_EMC_PLANT, -1, -1
5988 Xlenses, TRUE, FALSE,
5989 EL_EMC_LENSES, -1, -1
5992 Xmagnify, TRUE, FALSE,
5993 EL_EMC_MAGNIFIER, -1, -1
5996 Xdripper, TRUE, FALSE,
5997 EL_EMC_DRIPPER, -1, -1
6000 XdripperB, FALSE, FALSE,
6001 EL_EMC_DRIPPER, ACTION_ACTIVE, -1
6004 Xfake_blank, TRUE, FALSE,
6005 EL_INVISIBLE_WALL, -1, -1
6008 Xfake_blankB, FALSE, FALSE,
6009 EL_INVISIBLE_WALL, ACTION_ACTIVE, -1
6012 Xfake_grass, TRUE, FALSE,
6013 EL_EMC_FAKE_GRASS, -1, -1
6016 Xfake_grassB, FALSE, FALSE,
6017 EL_EMC_FAKE_GRASS, ACTION_ACTIVE, -1
6020 Xfake_door_1, TRUE, FALSE,
6021 EL_EM_GATE_1_GRAY, -1, -1
6024 Xfake_door_2, TRUE, FALSE,
6025 EL_EM_GATE_2_GRAY, -1, -1
6028 Xfake_door_3, TRUE, FALSE,
6029 EL_EM_GATE_3_GRAY, -1, -1
6032 Xfake_door_4, TRUE, FALSE,
6033 EL_EM_GATE_4_GRAY, -1, -1
6036 Xfake_door_5, TRUE, FALSE,
6037 EL_EMC_GATE_5_GRAY, -1, -1
6040 Xfake_door_6, TRUE, FALSE,
6041 EL_EMC_GATE_6_GRAY, -1, -1
6044 Xfake_door_7, TRUE, FALSE,
6045 EL_EMC_GATE_7_GRAY, -1, -1
6048 Xfake_door_8, TRUE, FALSE,
6049 EL_EMC_GATE_8_GRAY, -1, -1
6052 Xfake_acid_1, TRUE, FALSE,
6053 EL_EMC_FAKE_ACID, -1, -1
6056 Xfake_acid_2, FALSE, FALSE,
6057 EL_EMC_FAKE_ACID, -1, -1
6060 Xfake_acid_3, FALSE, FALSE,
6061 EL_EMC_FAKE_ACID, -1, -1
6064 Xfake_acid_4, FALSE, FALSE,
6065 EL_EMC_FAKE_ACID, -1, -1
6068 Xfake_acid_5, FALSE, FALSE,
6069 EL_EMC_FAKE_ACID, -1, -1
6072 Xfake_acid_6, FALSE, FALSE,
6073 EL_EMC_FAKE_ACID, -1, -1
6076 Xfake_acid_7, FALSE, FALSE,
6077 EL_EMC_FAKE_ACID, -1, -1
6080 Xfake_acid_8, FALSE, FALSE,
6081 EL_EMC_FAKE_ACID, -1, -1
6084 Xsteel_1, TRUE, FALSE,
6085 EL_STEELWALL, -1, -1
6088 Xsteel_2, TRUE, FALSE,
6089 EL_EMC_STEELWALL_2, -1, -1
6092 Xsteel_3, TRUE, FALSE,
6093 EL_EMC_STEELWALL_3, -1, -1
6096 Xsteel_4, TRUE, FALSE,
6097 EL_EMC_STEELWALL_4, -1, -1
6100 Xwall_1, TRUE, FALSE,
6104 Xwall_2, TRUE, FALSE,
6105 EL_EMC_WALL_14, -1, -1
6108 Xwall_3, TRUE, FALSE,
6109 EL_EMC_WALL_15, -1, -1
6112 Xwall_4, TRUE, FALSE,
6113 EL_EMC_WALL_16, -1, -1
6116 Xround_wall_1, TRUE, FALSE,
6117 EL_WALL_SLIPPERY, -1, -1
6120 Xround_wall_2, TRUE, FALSE,
6121 EL_EMC_WALL_SLIPPERY_2, -1, -1
6124 Xround_wall_3, TRUE, FALSE,
6125 EL_EMC_WALL_SLIPPERY_3, -1, -1
6128 Xround_wall_4, TRUE, FALSE,
6129 EL_EMC_WALL_SLIPPERY_4, -1, -1
6132 Xdecor_1, TRUE, FALSE,
6133 EL_EMC_WALL_8, -1, -1
6136 Xdecor_2, TRUE, FALSE,
6137 EL_EMC_WALL_6, -1, -1
6140 Xdecor_3, TRUE, FALSE,
6141 EL_EMC_WALL_4, -1, -1
6144 Xdecor_4, TRUE, FALSE,
6145 EL_EMC_WALL_7, -1, -1
6148 Xdecor_5, TRUE, FALSE,
6149 EL_EMC_WALL_5, -1, -1
6152 Xdecor_6, TRUE, FALSE,
6153 EL_EMC_WALL_9, -1, -1
6156 Xdecor_7, TRUE, FALSE,
6157 EL_EMC_WALL_10, -1, -1
6160 Xdecor_8, TRUE, FALSE,
6161 EL_EMC_WALL_1, -1, -1
6164 Xdecor_9, TRUE, FALSE,
6165 EL_EMC_WALL_2, -1, -1
6168 Xdecor_10, TRUE, FALSE,
6169 EL_EMC_WALL_3, -1, -1
6172 Xdecor_11, TRUE, FALSE,
6173 EL_EMC_WALL_11, -1, -1
6176 Xdecor_12, TRUE, FALSE,
6177 EL_EMC_WALL_12, -1, -1
6180 Xalpha_0, TRUE, FALSE,
6181 EL_CHAR('0'), -1, -1
6184 Xalpha_1, TRUE, FALSE,
6185 EL_CHAR('1'), -1, -1
6188 Xalpha_2, TRUE, FALSE,
6189 EL_CHAR('2'), -1, -1
6192 Xalpha_3, TRUE, FALSE,
6193 EL_CHAR('3'), -1, -1
6196 Xalpha_4, TRUE, FALSE,
6197 EL_CHAR('4'), -1, -1
6200 Xalpha_5, TRUE, FALSE,
6201 EL_CHAR('5'), -1, -1
6204 Xalpha_6, TRUE, FALSE,
6205 EL_CHAR('6'), -1, -1
6208 Xalpha_7, TRUE, FALSE,
6209 EL_CHAR('7'), -1, -1
6212 Xalpha_8, TRUE, FALSE,
6213 EL_CHAR('8'), -1, -1
6216 Xalpha_9, TRUE, FALSE,
6217 EL_CHAR('9'), -1, -1
6220 Xalpha_excla, TRUE, FALSE,
6221 EL_CHAR('!'), -1, -1
6224 Xalpha_quote, TRUE, FALSE,
6225 EL_CHAR('"'), -1, -1
6228 Xalpha_comma, TRUE, FALSE,
6229 EL_CHAR(','), -1, -1
6232 Xalpha_minus, TRUE, FALSE,
6233 EL_CHAR('-'), -1, -1
6236 Xalpha_perio, TRUE, FALSE,
6237 EL_CHAR('.'), -1, -1
6240 Xalpha_colon, TRUE, FALSE,
6241 EL_CHAR(':'), -1, -1
6244 Xalpha_quest, TRUE, FALSE,
6245 EL_CHAR('?'), -1, -1
6248 Xalpha_a, TRUE, FALSE,
6249 EL_CHAR('A'), -1, -1
6252 Xalpha_b, TRUE, FALSE,
6253 EL_CHAR('B'), -1, -1
6256 Xalpha_c, TRUE, FALSE,
6257 EL_CHAR('C'), -1, -1
6260 Xalpha_d, TRUE, FALSE,
6261 EL_CHAR('D'), -1, -1
6264 Xalpha_e, TRUE, FALSE,
6265 EL_CHAR('E'), -1, -1
6268 Xalpha_f, TRUE, FALSE,
6269 EL_CHAR('F'), -1, -1
6272 Xalpha_g, TRUE, FALSE,
6273 EL_CHAR('G'), -1, -1
6276 Xalpha_h, TRUE, FALSE,
6277 EL_CHAR('H'), -1, -1
6280 Xalpha_i, TRUE, FALSE,
6281 EL_CHAR('I'), -1, -1
6284 Xalpha_j, TRUE, FALSE,
6285 EL_CHAR('J'), -1, -1
6288 Xalpha_k, TRUE, FALSE,
6289 EL_CHAR('K'), -1, -1
6292 Xalpha_l, TRUE, FALSE,
6293 EL_CHAR('L'), -1, -1
6296 Xalpha_m, TRUE, FALSE,
6297 EL_CHAR('M'), -1, -1
6300 Xalpha_n, TRUE, FALSE,
6301 EL_CHAR('N'), -1, -1
6304 Xalpha_o, TRUE, FALSE,
6305 EL_CHAR('O'), -1, -1
6308 Xalpha_p, TRUE, FALSE,
6309 EL_CHAR('P'), -1, -1
6312 Xalpha_q, TRUE, FALSE,
6313 EL_CHAR('Q'), -1, -1
6316 Xalpha_r, TRUE, FALSE,
6317 EL_CHAR('R'), -1, -1
6320 Xalpha_s, TRUE, FALSE,
6321 EL_CHAR('S'), -1, -1
6324 Xalpha_t, TRUE, FALSE,
6325 EL_CHAR('T'), -1, -1
6328 Xalpha_u, TRUE, FALSE,
6329 EL_CHAR('U'), -1, -1
6332 Xalpha_v, TRUE, FALSE,
6333 EL_CHAR('V'), -1, -1
6336 Xalpha_w, TRUE, FALSE,
6337 EL_CHAR('W'), -1, -1
6340 Xalpha_x, TRUE, FALSE,
6341 EL_CHAR('X'), -1, -1
6344 Xalpha_y, TRUE, FALSE,
6345 EL_CHAR('Y'), -1, -1
6348 Xalpha_z, TRUE, FALSE,
6349 EL_CHAR('Z'), -1, -1
6352 Xalpha_arrow_e, TRUE, FALSE,
6353 EL_CHAR('>'), -1, -1
6356 Xalpha_arrow_w, TRUE, FALSE,
6357 EL_CHAR('<'), -1, -1
6360 Xalpha_copyr, TRUE, FALSE,
6361 EL_CHAR('©'), -1, -1
6365 Xboom_bug, FALSE, FALSE,
6366 EL_BUG, ACTION_EXPLODING, -1
6369 Xboom_bomb, FALSE, FALSE,
6370 EL_BOMB, ACTION_EXPLODING, -1
6373 Xboom_android, FALSE, FALSE,
6374 EL_EMC_ANDROID, ACTION_OTHER, -1
6377 Xboom_1, FALSE, FALSE,
6378 EL_DEFAULT, ACTION_EXPLODING, -1
6381 Xboom_2, FALSE, FALSE,
6382 EL_DEFAULT, ACTION_EXPLODING, -1
6385 Znormal, FALSE, FALSE,
6389 Zdynamite, FALSE, FALSE,
6393 Zplayer, FALSE, FALSE,
6397 ZBORDER, FALSE, FALSE,
6407 static struct Mapping_EM_to_RND_player
6416 em_player_mapping_list[] =
6420 EL_PLAYER_1, ACTION_MOVING, MV_BIT_UP,
6424 EL_PLAYER_1, ACTION_MOVING, MV_BIT_RIGHT,
6428 EL_PLAYER_1, ACTION_MOVING, MV_BIT_DOWN,
6432 EL_PLAYER_1, ACTION_MOVING, MV_BIT_LEFT,
6436 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_UP,
6440 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_RIGHT,
6444 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_DOWN,
6448 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_LEFT,
6452 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_UP,
6456 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_RIGHT,
6460 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_DOWN,
6464 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_LEFT,
6468 EL_PLAYER_2, ACTION_MOVING, MV_BIT_UP,
6472 EL_PLAYER_2, ACTION_MOVING, MV_BIT_RIGHT,
6476 EL_PLAYER_2, ACTION_MOVING, MV_BIT_DOWN,
6480 EL_PLAYER_2, ACTION_MOVING, MV_BIT_LEFT,
6484 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_UP,
6488 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_RIGHT,
6492 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_DOWN,
6496 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_LEFT,
6500 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_UP,
6504 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_RIGHT,
6508 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_DOWN,
6512 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_LEFT,
6516 EL_PLAYER_1, ACTION_DEFAULT, -1,
6520 EL_PLAYER_2, ACTION_DEFAULT, -1,
6524 EL_PLAYER_3, ACTION_MOVING, MV_BIT_UP,
6528 EL_PLAYER_3, ACTION_MOVING, MV_BIT_RIGHT,
6532 EL_PLAYER_3, ACTION_MOVING, MV_BIT_DOWN,
6536 EL_PLAYER_3, ACTION_MOVING, MV_BIT_LEFT,
6540 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_UP,
6544 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_RIGHT,
6548 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_DOWN,
6552 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_LEFT,
6556 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_UP,
6560 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_RIGHT,
6564 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_DOWN,
6568 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_LEFT,
6572 EL_PLAYER_4, ACTION_MOVING, MV_BIT_UP,
6576 EL_PLAYER_4, ACTION_MOVING, MV_BIT_RIGHT,
6580 EL_PLAYER_4, ACTION_MOVING, MV_BIT_DOWN,
6584 EL_PLAYER_4, ACTION_MOVING, MV_BIT_LEFT,
6588 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_UP,
6592 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_RIGHT,
6596 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_DOWN,
6600 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_LEFT,
6604 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_UP,
6608 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_RIGHT,
6612 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_DOWN,
6616 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_LEFT,
6620 EL_PLAYER_3, ACTION_DEFAULT, -1,
6624 EL_PLAYER_4, ACTION_DEFAULT, -1,
6633 int map_element_RND_to_EM(int element_rnd)
6635 static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
6636 static boolean mapping_initialized = FALSE;
6638 if (!mapping_initialized)
6642 /* return "Xalpha_quest" for all undefined elements in mapping array */
6643 for (i = 0; i < NUM_FILE_ELEMENTS; i++)
6644 mapping_RND_to_EM[i] = Xalpha_quest;
6646 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
6647 if (em_object_mapping_list[i].is_rnd_to_em_mapping)
6648 mapping_RND_to_EM[em_object_mapping_list[i].element_rnd] =
6649 em_object_mapping_list[i].element_em;
6651 mapping_initialized = TRUE;
6654 if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
6655 return mapping_RND_to_EM[element_rnd];
6657 Error(ERR_WARN, "invalid RND level element %d", element_rnd);
6662 int map_element_EM_to_RND(int element_em)
6664 static unsigned short mapping_EM_to_RND[TILE_MAX];
6665 static boolean mapping_initialized = FALSE;
6667 if (!mapping_initialized)
6671 /* return "EL_UNKNOWN" for all undefined elements in mapping array */
6672 for (i = 0; i < TILE_MAX; i++)
6673 mapping_EM_to_RND[i] = EL_UNKNOWN;
6675 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
6676 mapping_EM_to_RND[em_object_mapping_list[i].element_em] =
6677 em_object_mapping_list[i].element_rnd;
6679 mapping_initialized = TRUE;
6682 if (element_em >= 0 && element_em < TILE_MAX)
6683 return mapping_EM_to_RND[element_em];
6685 Error(ERR_WARN, "invalid EM level element %d", element_em);
6690 void map_android_clone_elements_RND_to_EM(struct LevelInfo *level)
6692 struct LevelInfo_EM *level_em = level->native_em_level;
6693 struct LEVEL *lev = level_em->lev;
6696 for (i = 0; i < TILE_MAX; i++)
6697 lev->android_array[i] = Xblank;
6699 for (i = 0; i < level->num_android_clone_elements; i++)
6701 int element_rnd = level->android_clone_element[i];
6702 int element_em = map_element_RND_to_EM(element_rnd);
6704 for (j = 0; em_object_mapping_list[j].element_em != -1; j++)
6705 if (em_object_mapping_list[j].element_rnd == element_rnd)
6706 lev->android_array[em_object_mapping_list[j].element_em] = element_em;
6710 void map_android_clone_elements_EM_to_RND(struct LevelInfo *level)
6712 struct LevelInfo_EM *level_em = level->native_em_level;
6713 struct LEVEL *lev = level_em->lev;
6716 level->num_android_clone_elements = 0;
6718 for (i = 0; i < TILE_MAX; i++)
6720 int element_em = lev->android_array[i];
6722 boolean element_found = FALSE;
6724 if (element_em == Xblank)
6727 element_rnd = map_element_EM_to_RND(element_em);
6729 for (j = 0; j < level->num_android_clone_elements; j++)
6730 if (level->android_clone_element[j] == element_rnd)
6731 element_found = TRUE;
6735 level->android_clone_element[level->num_android_clone_elements++] =
6738 if (level->num_android_clone_elements == MAX_ANDROID_ELEMENTS)
6743 if (level->num_android_clone_elements == 0)
6745 level->num_android_clone_elements = 1;
6746 level->android_clone_element[0] = EL_EMPTY;
6750 int map_direction_RND_to_EM(int direction)
6752 return (direction == MV_UP ? 0 :
6753 direction == MV_RIGHT ? 1 :
6754 direction == MV_DOWN ? 2 :
6755 direction == MV_LEFT ? 3 :
6759 int map_direction_EM_to_RND(int direction)
6761 return (direction == 0 ? MV_UP :
6762 direction == 1 ? MV_RIGHT :
6763 direction == 2 ? MV_DOWN :
6764 direction == 3 ? MV_LEFT :
6768 int map_element_RND_to_SP(int element_rnd)
6770 int element_sp = 0x20; /* map unknown elements to yellow "hardware" */
6772 if (element_rnd >= EL_SP_START &&
6773 element_rnd <= EL_SP_END)
6774 element_sp = element_rnd - EL_SP_START;
6775 else if (element_rnd == EL_EMPTY_SPACE)
6777 else if (element_rnd == EL_INVISIBLE_WALL)
6783 int map_element_SP_to_RND(int element_sp)
6785 int element_rnd = EL_UNKNOWN;
6787 if (element_sp >= 0x00 &&
6789 element_rnd = EL_SP_START + element_sp;
6790 else if (element_sp == 0x28)
6791 element_rnd = EL_INVISIBLE_WALL;
6796 int map_action_SP_to_RND(int action_sp)
6800 case actActive: return ACTION_ACTIVE;
6801 case actImpact: return ACTION_IMPACT;
6802 case actExploding: return ACTION_EXPLODING;
6803 case actDigging: return ACTION_DIGGING;
6804 case actSnapping: return ACTION_SNAPPING;
6805 case actCollecting: return ACTION_COLLECTING;
6806 case actPassing: return ACTION_PASSING;
6807 case actPushing: return ACTION_PUSHING;
6808 case actDropping: return ACTION_DROPPING;
6810 default: return ACTION_DEFAULT;
6814 int get_next_element(int element)
6818 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
6819 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
6820 case EL_QUICKSAND_FAST_FILLING: return EL_QUICKSAND_FAST_FULL;
6821 case EL_QUICKSAND_FAST_EMPTYING: return EL_QUICKSAND_FAST_EMPTY;
6822 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
6823 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
6824 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
6825 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
6826 case EL_DC_MAGIC_WALL_FILLING: return EL_DC_MAGIC_WALL_FULL;
6827 case EL_DC_MAGIC_WALL_EMPTYING: return EL_DC_MAGIC_WALL_ACTIVE;
6828 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
6830 default: return element;
6835 int el_act_dir2img(int element, int action, int direction)
6837 element = GFX_ELEMENT(element);
6839 if (direction == MV_NONE)
6840 return element_info[element].graphic[action];
6842 direction = MV_DIR_TO_BIT(direction);
6844 return element_info[element].direction_graphic[action][direction];
6847 int el_act_dir2img(int element, int action, int direction)
6849 element = GFX_ELEMENT(element);
6850 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
6852 /* direction_graphic[][] == graphic[] for undefined direction graphics */
6853 return element_info[element].direction_graphic[action][direction];
6858 static int el_act_dir2crm(int element, int action, int direction)
6860 element = GFX_ELEMENT(element);
6862 if (direction == MV_NONE)
6863 return element_info[element].crumbled[action];
6865 direction = MV_DIR_TO_BIT(direction);
6867 return element_info[element].direction_crumbled[action][direction];
6870 static int el_act_dir2crm(int element, int action, int direction)
6872 element = GFX_ELEMENT(element);
6873 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
6875 /* direction_graphic[][] == graphic[] for undefined direction graphics */
6876 return element_info[element].direction_crumbled[action][direction];
6880 int el_act2img(int element, int action)
6882 element = GFX_ELEMENT(element);
6884 return element_info[element].graphic[action];
6887 int el_act2crm(int element, int action)
6889 element = GFX_ELEMENT(element);
6891 return element_info[element].crumbled[action];
6894 int el_dir2img(int element, int direction)
6896 element = GFX_ELEMENT(element);
6898 return el_act_dir2img(element, ACTION_DEFAULT, direction);
6901 int el2baseimg(int element)
6903 return element_info[element].graphic[ACTION_DEFAULT];
6906 int el2img(int element)
6908 element = GFX_ELEMENT(element);
6910 return element_info[element].graphic[ACTION_DEFAULT];
6913 int el2edimg(int element)
6915 element = GFX_ELEMENT(element);
6917 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
6920 int el2preimg(int element)
6922 element = GFX_ELEMENT(element);
6924 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
6927 int el2panelimg(int element)
6929 element = GFX_ELEMENT(element);
6931 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PANEL];
6934 int font2baseimg(int font_nr)
6936 return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
6939 int getBeltNrFromBeltElement(int element)
6941 return (element < EL_CONVEYOR_BELT_2_LEFT ? 0 :
6942 element < EL_CONVEYOR_BELT_3_LEFT ? 1 :
6943 element < EL_CONVEYOR_BELT_4_LEFT ? 2 : 3);
6946 int getBeltNrFromBeltActiveElement(int element)
6948 return (element < EL_CONVEYOR_BELT_2_LEFT_ACTIVE ? 0 :
6949 element < EL_CONVEYOR_BELT_3_LEFT_ACTIVE ? 1 :
6950 element < EL_CONVEYOR_BELT_4_LEFT_ACTIVE ? 2 : 3);
6953 int getBeltNrFromBeltSwitchElement(int element)
6955 return (element < EL_CONVEYOR_BELT_2_SWITCH_LEFT ? 0 :
6956 element < EL_CONVEYOR_BELT_3_SWITCH_LEFT ? 1 :
6957 element < EL_CONVEYOR_BELT_4_SWITCH_LEFT ? 2 : 3);
6960 int getBeltDirNrFromBeltElement(int element)
6962 static int belt_base_element[4] =
6964 EL_CONVEYOR_BELT_1_LEFT,
6965 EL_CONVEYOR_BELT_2_LEFT,
6966 EL_CONVEYOR_BELT_3_LEFT,
6967 EL_CONVEYOR_BELT_4_LEFT
6970 int belt_nr = getBeltNrFromBeltElement(element);
6971 int belt_dir_nr = element - belt_base_element[belt_nr];
6973 return (belt_dir_nr % 3);
6976 int getBeltDirNrFromBeltSwitchElement(int element)
6978 static int belt_base_element[4] =
6980 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
6981 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
6982 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
6983 EL_CONVEYOR_BELT_4_SWITCH_LEFT
6986 int belt_nr = getBeltNrFromBeltSwitchElement(element);
6987 int belt_dir_nr = element - belt_base_element[belt_nr];
6989 return (belt_dir_nr % 3);
6992 int getBeltDirFromBeltElement(int element)
6994 static int belt_move_dir[3] =
7001 int belt_dir_nr = getBeltDirNrFromBeltElement(element);
7003 return belt_move_dir[belt_dir_nr];
7006 int getBeltDirFromBeltSwitchElement(int element)
7008 static int belt_move_dir[3] =
7015 int belt_dir_nr = getBeltDirNrFromBeltSwitchElement(element);
7017 return belt_move_dir[belt_dir_nr];
7020 int getBeltElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
7022 static int belt_base_element[4] =
7024 EL_CONVEYOR_BELT_1_LEFT,
7025 EL_CONVEYOR_BELT_2_LEFT,
7026 EL_CONVEYOR_BELT_3_LEFT,
7027 EL_CONVEYOR_BELT_4_LEFT
7030 return belt_base_element[belt_nr] + belt_dir_nr;
7033 int getBeltElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
7035 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
7037 return getBeltElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
7040 int getBeltSwitchElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
7042 static int belt_base_element[4] =
7044 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
7045 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
7046 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
7047 EL_CONVEYOR_BELT_4_SWITCH_LEFT
7050 return belt_base_element[belt_nr] + belt_dir_nr;
7053 int getBeltSwitchElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
7055 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
7057 return getBeltSwitchElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
7060 int getNumActivePlayers_EM()
7062 int num_players = 0;
7068 for (i = 0; i < MAX_PLAYERS; i++)
7069 if (tape.player_participates[i])
7075 int getGameFrameDelay_EM(int native_em_game_frame_delay)
7077 int game_frame_delay_value;
7079 game_frame_delay_value =
7080 (tape.playing && tape.fast_forward ? FfwdFrameDelay :
7081 GameFrameDelay == GAME_FRAME_DELAY ? native_em_game_frame_delay :
7084 if (tape.playing && tape.warp_forward && !tape.pausing)
7085 game_frame_delay_value = 0;
7087 return game_frame_delay_value;
7090 unsigned int InitRND(long seed)
7092 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
7093 return InitEngineRandom_EM(seed);
7094 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
7095 return InitEngineRandom_SP(seed);
7097 return InitEngineRandom_RND(seed);
7101 static struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
7102 static struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
7105 inline static int get_effective_element_EM(int tile, int frame_em)
7107 int element = object_mapping[tile].element_rnd;
7108 int action = object_mapping[tile].action;
7109 boolean is_backside = object_mapping[tile].is_backside;
7110 boolean action_removing = (action == ACTION_DIGGING ||
7111 action == ACTION_SNAPPING ||
7112 action == ACTION_COLLECTING);
7118 case Yacid_splash_eB:
7119 case Yacid_splash_wB:
7120 return (frame_em > 5 ? EL_EMPTY : element);
7123 case Ydiamond_stone:
7124 // if (!game.use_native_emc_graphics_engine)
7132 else /* frame_em == 7 */
7136 case Yacid_splash_eB:
7137 case Yacid_splash_wB:
7140 case Yemerald_stone:
7143 case Ydiamond_stone:
7147 case Xdrip_stretchB:
7166 case Xsand_stonein_1:
7167 case Xsand_stonein_2:
7168 case Xsand_stonein_3:
7169 case Xsand_stonein_4:
7173 return (is_backside || action_removing ? EL_EMPTY : element);
7178 inline static boolean check_linear_animation_EM(int tile)
7182 case Xsand_stonesand_1:
7183 case Xsand_stonesand_quickout_1:
7184 case Xsand_sandstone_1:
7185 case Xsand_stonein_1:
7186 case Xsand_stoneout_1:
7206 case Yacid_splash_eB:
7207 case Yacid_splash_wB:
7208 case Yemerald_stone:
7216 inline static void set_crumbled_graphics_EM(struct GraphicInfo_EM *g_em,
7217 boolean has_crumbled_graphics,
7218 int crumbled, int sync_frame)
7220 /* if element can be crumbled, but certain action graphics are just empty
7221 space (like instantly snapping sand to empty space in 1 frame), do not
7222 treat these empty space graphics as crumbled graphics in EMC engine */
7223 if (crumbled == IMG_EMPTY_SPACE)
7224 has_crumbled_graphics = FALSE;
7226 if (has_crumbled_graphics)
7228 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
7229 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
7230 g_crumbled->anim_delay,
7231 g_crumbled->anim_mode,
7232 g_crumbled->anim_start_frame,
7235 getGraphicSource(crumbled, frame_crumbled, &g_em->crumbled_bitmap,
7236 &g_em->crumbled_src_x, &g_em->crumbled_src_y);
7238 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
7240 g_em->has_crumbled_graphics = TRUE;
7244 g_em->crumbled_bitmap = NULL;
7245 g_em->crumbled_src_x = 0;
7246 g_em->crumbled_src_y = 0;
7247 g_em->crumbled_border_size = 0;
7249 g_em->has_crumbled_graphics = FALSE;
7253 void ResetGfxAnimation_EM(int x, int y, int tile)
7258 void SetGfxAnimation_EM(struct GraphicInfo_EM *g_em,
7259 int tile, int frame_em, int x, int y)
7261 int action = object_mapping[tile].action;
7263 int direction = object_mapping[tile].direction;
7264 int effective_element = get_effective_element_EM(tile, frame_em);
7265 int graphic = (direction == MV_NONE ?
7266 el_act2img(effective_element, action) :
7267 el_act_dir2img(effective_element, action, direction));
7268 struct GraphicInfo *g = &graphic_info[graphic];
7271 boolean action_removing = (action == ACTION_DIGGING ||
7272 action == ACTION_SNAPPING ||
7273 action == ACTION_COLLECTING);
7274 boolean action_moving = (action == ACTION_FALLING ||
7275 action == ACTION_MOVING ||
7276 action == ACTION_PUSHING ||
7277 action == ACTION_EATING ||
7278 action == ACTION_FILLING ||
7279 action == ACTION_EMPTYING);
7280 boolean action_falling = (action == ACTION_FALLING ||
7281 action == ACTION_FILLING ||
7282 action == ACTION_EMPTYING);
7284 /* special case: graphic uses "2nd movement tile" and has defined
7285 7 frames for movement animation (or less) => use default graphic
7286 for last (8th) frame which ends the movement animation */
7287 if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
7289 action = ACTION_DEFAULT; /* (keep action_* unchanged for now) */
7290 graphic = (direction == MV_NONE ?
7291 el_act2img(effective_element, action) :
7292 el_act_dir2img(effective_element, action, direction));
7294 g = &graphic_info[graphic];
7298 if (tile == Xsand_stonesand_1 ||
7299 tile == Xsand_stonesand_2 ||
7300 tile == Xsand_stonesand_3 ||
7301 tile == Xsand_stonesand_4)
7302 printf("::: 1: quicksand frame %d [%d]\n", GfxFrame[x][y], tile);
7306 if ((action_removing || check_linear_animation_EM(tile)) && frame_em == 0)
7310 // printf("::: resetting... [%d]\n", tile);
7313 if (action_removing || check_linear_animation_EM(tile))
7315 GfxFrame[x][y] = frame_em;
7317 // printf("::: resetting... [%d]\n", tile);
7320 else if (action_moving)
7322 boolean is_backside = object_mapping[tile].is_backside;
7326 int direction = object_mapping[tile].direction;
7327 int move_dir = (action_falling ? MV_DOWN : direction);
7332 /* !!! TEST !!! NEW !!! DOES NOT WORK RIGHT YET !!! */
7333 if (g->double_movement && frame_em == 0)
7337 // printf("::: resetting... [%d]\n", tile);
7341 if (move_dir == MV_LEFT)
7342 GfxFrame[x - 1][y] = GfxFrame[x][y];
7343 else if (move_dir == MV_RIGHT)
7344 GfxFrame[x + 1][y] = GfxFrame[x][y];
7345 else if (move_dir == MV_UP)
7346 GfxFrame[x][y - 1] = GfxFrame[x][y];
7347 else if (move_dir == MV_DOWN)
7348 GfxFrame[x][y + 1] = GfxFrame[x][y];
7355 /* special case: animation for Xsand_stonesand_quickout_1/2 twice as fast */
7356 if (tile == Xsand_stonesand_quickout_1 ||
7357 tile == Xsand_stonesand_quickout_2)
7362 if (tile == Xsand_stonesand_1 ||
7363 tile == Xsand_stonesand_2 ||
7364 tile == Xsand_stonesand_3 ||
7365 tile == Xsand_stonesand_4)
7366 printf("::: 2: quicksand frame %d [%d]\n", GfxFrame[x][y], tile);
7370 if (graphic_info[graphic].anim_global_sync)
7371 sync_frame = FrameCounter;
7372 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
7373 sync_frame = GfxFrame[x][y];
7375 sync_frame = 0; /* playfield border (pseudo steel) */
7377 SetRandomAnimationValue(x, y);
7379 int frame = getAnimationFrame(g->anim_frames,
7382 g->anim_start_frame,
7385 g_em->unique_identifier =
7386 (graphic << 16) | ((frame % 8) << 12) | (g_em->width << 6) | g_em->height;
7390 void getGraphicSourceObjectExt_EM(struct GraphicInfo_EM *g_em,
7391 int tile, int frame_em, int x, int y)
7393 int action = object_mapping[tile].action;
7394 int direction = object_mapping[tile].direction;
7395 boolean is_backside = object_mapping[tile].is_backside;
7396 int effective_element = get_effective_element_EM(tile, frame_em);
7398 int effective_action = action;
7400 int effective_action = (frame_em < 7 ? action : ACTION_DEFAULT);
7402 int graphic = (direction == MV_NONE ?
7403 el_act2img(effective_element, effective_action) :
7404 el_act_dir2img(effective_element, effective_action,
7406 int crumbled = (direction == MV_NONE ?
7407 el_act2crm(effective_element, effective_action) :
7408 el_act_dir2crm(effective_element, effective_action,
7410 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
7411 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
7412 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
7413 struct GraphicInfo *g = &graphic_info[graphic];
7415 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
7419 /* special case: graphic uses "2nd movement tile" and has defined
7420 7 frames for movement animation (or less) => use default graphic
7421 for last (8th) frame which ends the movement animation */
7422 if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
7424 effective_action = ACTION_DEFAULT;
7425 graphic = (direction == MV_NONE ?
7426 el_act2img(effective_element, effective_action) :
7427 el_act_dir2img(effective_element, effective_action,
7429 crumbled = (direction == MV_NONE ?
7430 el_act2crm(effective_element, effective_action) :
7431 el_act_dir2crm(effective_element, effective_action,
7434 g = &graphic_info[graphic];
7444 if (frame_em == 0) /* reset animation frame for certain elements */
7446 if (check_linear_animation_EM(tile))
7451 if (graphic_info[graphic].anim_global_sync)
7452 sync_frame = FrameCounter;
7453 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
7454 sync_frame = GfxFrame[x][y];
7456 sync_frame = 0; /* playfield border (pseudo steel) */
7458 SetRandomAnimationValue(x, y);
7463 int xxx_sync_frame = (i == Xdrip_stretch ? 7 :
7464 i == Xdrip_stretchB ? 7 :
7465 i == Ydrip_s2 ? j + 8 :
7466 i == Ydrip_s2B ? j + 8 :
7475 i == Xfake_acid_1 ? 0 :
7476 i == Xfake_acid_2 ? 10 :
7477 i == Xfake_acid_3 ? 20 :
7478 i == Xfake_acid_4 ? 30 :
7479 i == Xfake_acid_5 ? 40 :
7480 i == Xfake_acid_6 ? 50 :
7481 i == Xfake_acid_7 ? 60 :
7482 i == Xfake_acid_8 ? 70 :
7484 i == Xball_2B ? j + 8 :
7485 i == Yball_eat ? j + 1 :
7486 i == Ykey_1_eat ? j + 1 :
7487 i == Ykey_2_eat ? j + 1 :
7488 i == Ykey_3_eat ? j + 1 :
7489 i == Ykey_4_eat ? j + 1 :
7490 i == Ykey_5_eat ? j + 1 :
7491 i == Ykey_6_eat ? j + 1 :
7492 i == Ykey_7_eat ? j + 1 :
7493 i == Ykey_8_eat ? j + 1 :
7494 i == Ylenses_eat ? j + 1 :
7495 i == Ymagnify_eat ? j + 1 :
7496 i == Ygrass_eat ? j + 1 :
7497 i == Ydirt_eat ? j + 1 :
7498 i == Xamoeba_1 ? 0 :
7499 i == Xamoeba_2 ? 1 :
7500 i == Xamoeba_3 ? 2 :
7501 i == Xamoeba_4 ? 3 :
7502 i == Xamoeba_5 ? 0 :
7503 i == Xamoeba_6 ? 1 :
7504 i == Xamoeba_7 ? 2 :
7505 i == Xamoeba_8 ? 3 :
7506 i == Xexit_2 ? j + 8 :
7507 i == Xexit_3 ? j + 16 :
7508 i == Xdynamite_1 ? 0 :
7509 i == Xdynamite_2 ? 8 :
7510 i == Xdynamite_3 ? 16 :
7511 i == Xdynamite_4 ? 24 :
7512 i == Xsand_stonein_1 ? j + 1 :
7513 i == Xsand_stonein_2 ? j + 9 :
7514 i == Xsand_stonein_3 ? j + 17 :
7515 i == Xsand_stonein_4 ? j + 25 :
7516 i == Xsand_stoneout_1 && j == 0 ? 0 :
7517 i == Xsand_stoneout_1 && j == 1 ? 0 :
7518 i == Xsand_stoneout_1 && j == 2 ? 1 :
7519 i == Xsand_stoneout_1 && j == 3 ? 2 :
7520 i == Xsand_stoneout_1 && j == 4 ? 2 :
7521 i == Xsand_stoneout_1 && j == 5 ? 3 :
7522 i == Xsand_stoneout_1 && j == 6 ? 4 :
7523 i == Xsand_stoneout_1 && j == 7 ? 4 :
7524 i == Xsand_stoneout_2 && j == 0 ? 5 :
7525 i == Xsand_stoneout_2 && j == 1 ? 6 :
7526 i == Xsand_stoneout_2 && j == 2 ? 7 :
7527 i == Xsand_stoneout_2 && j == 3 ? 8 :
7528 i == Xsand_stoneout_2 && j == 4 ? 9 :
7529 i == Xsand_stoneout_2 && j == 5 ? 11 :
7530 i == Xsand_stoneout_2 && j == 6 ? 13 :
7531 i == Xsand_stoneout_2 && j == 7 ? 15 :
7532 i == Xboom_bug && j == 1 ? 2 :
7533 i == Xboom_bug && j == 2 ? 2 :
7534 i == Xboom_bug && j == 3 ? 4 :
7535 i == Xboom_bug && j == 4 ? 4 :
7536 i == Xboom_bug && j == 5 ? 2 :
7537 i == Xboom_bug && j == 6 ? 2 :
7538 i == Xboom_bug && j == 7 ? 0 :
7539 i == Xboom_bomb && j == 1 ? 2 :
7540 i == Xboom_bomb && j == 2 ? 2 :
7541 i == Xboom_bomb && j == 3 ? 4 :
7542 i == Xboom_bomb && j == 4 ? 4 :
7543 i == Xboom_bomb && j == 5 ? 2 :
7544 i == Xboom_bomb && j == 6 ? 2 :
7545 i == Xboom_bomb && j == 7 ? 0 :
7546 i == Xboom_android && j == 7 ? 6 :
7547 i == Xboom_1 && j == 1 ? 2 :
7548 i == Xboom_1 && j == 2 ? 2 :
7549 i == Xboom_1 && j == 3 ? 4 :
7550 i == Xboom_1 && j == 4 ? 4 :
7551 i == Xboom_1 && j == 5 ? 6 :
7552 i == Xboom_1 && j == 6 ? 6 :
7553 i == Xboom_1 && j == 7 ? 8 :
7554 i == Xboom_2 && j == 0 ? 8 :
7555 i == Xboom_2 && j == 1 ? 8 :
7556 i == Xboom_2 && j == 2 ? 10 :
7557 i == Xboom_2 && j == 3 ? 10 :
7558 i == Xboom_2 && j == 4 ? 10 :
7559 i == Xboom_2 && j == 5 ? 12 :
7560 i == Xboom_2 && j == 6 ? 12 :
7561 i == Xboom_2 && j == 7 ? 12 :
7563 special_animation && j == 4 ? 3 :
7564 effective_action != action ? 0 :
7570 int xxx_effective_action;
7571 int xxx_has_action_graphics;
7574 int element = object_mapping[i].element_rnd;
7575 int action = object_mapping[i].action;
7576 int direction = object_mapping[i].direction;
7577 boolean is_backside = object_mapping[i].is_backside;
7579 boolean action_removing = (action == ACTION_DIGGING ||
7580 action == ACTION_SNAPPING ||
7581 action == ACTION_COLLECTING);
7583 boolean action_exploding = ((action == ACTION_EXPLODING ||
7584 action == ACTION_SMASHED_BY_ROCK ||
7585 action == ACTION_SMASHED_BY_SPRING) &&
7586 element != EL_DIAMOND);
7587 boolean action_active = (action == ACTION_ACTIVE);
7588 boolean action_other = (action == ACTION_OTHER);
7592 int effective_element = get_effective_element_EM(i, j);
7594 int effective_element = (j > 5 && i == Yacid_splash_eB ? EL_EMPTY :
7595 j > 5 && i == Yacid_splash_wB ? EL_EMPTY :
7597 i == Xdrip_stretch ? element :
7598 i == Xdrip_stretchB ? element :
7599 i == Ydrip_s1 ? element :
7600 i == Ydrip_s1B ? element :
7601 i == Xball_1B ? element :
7602 i == Xball_2 ? element :
7603 i == Xball_2B ? element :
7604 i == Yball_eat ? element :
7605 i == Ykey_1_eat ? element :
7606 i == Ykey_2_eat ? element :
7607 i == Ykey_3_eat ? element :
7608 i == Ykey_4_eat ? element :
7609 i == Ykey_5_eat ? element :
7610 i == Ykey_6_eat ? element :
7611 i == Ykey_7_eat ? element :
7612 i == Ykey_8_eat ? element :
7613 i == Ylenses_eat ? element :
7614 i == Ymagnify_eat ? element :
7615 i == Ygrass_eat ? element :
7616 i == Ydirt_eat ? element :
7617 i == Yemerald_stone ? EL_EMERALD :
7618 i == Ydiamond_stone ? EL_ROCK :
7619 i == Xsand_stonein_1 ? element :
7620 i == Xsand_stonein_2 ? element :
7621 i == Xsand_stonein_3 ? element :
7622 i == Xsand_stonein_4 ? element :
7623 is_backside ? EL_EMPTY :
7624 action_removing ? EL_EMPTY :
7627 int effective_action = (j < 7 ? action :
7628 i == Xdrip_stretch ? action :
7629 i == Xdrip_stretchB ? action :
7630 i == Ydrip_s1 ? action :
7631 i == Ydrip_s1B ? action :
7632 i == Xball_1B ? action :
7633 i == Xball_2 ? action :
7634 i == Xball_2B ? action :
7635 i == Yball_eat ? action :
7636 i == Ykey_1_eat ? action :
7637 i == Ykey_2_eat ? action :
7638 i == Ykey_3_eat ? action :
7639 i == Ykey_4_eat ? action :
7640 i == Ykey_5_eat ? action :
7641 i == Ykey_6_eat ? action :
7642 i == Ykey_7_eat ? action :
7643 i == Ykey_8_eat ? action :
7644 i == Ylenses_eat ? action :
7645 i == Ymagnify_eat ? action :
7646 i == Ygrass_eat ? action :
7647 i == Ydirt_eat ? action :
7648 i == Xsand_stonein_1 ? action :
7649 i == Xsand_stonein_2 ? action :
7650 i == Xsand_stonein_3 ? action :
7651 i == Xsand_stonein_4 ? action :
7652 i == Xsand_stoneout_1 ? action :
7653 i == Xsand_stoneout_2 ? action :
7654 i == Xboom_android ? ACTION_EXPLODING :
7655 action_exploding ? ACTION_EXPLODING :
7656 action_active ? action :
7657 action_other ? action :
7659 int graphic = (el_act_dir2img(effective_element, effective_action,
7661 int crumbled = (el_act_dir2crm(effective_element, effective_action,
7663 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
7664 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
7665 boolean has_action_graphics = (graphic != base_graphic);
7666 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
7667 struct GraphicInfo *g = &graphic_info[graphic];
7669 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
7671 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
7674 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
7675 boolean special_animation = (action != ACTION_DEFAULT &&
7676 g->anim_frames == 3 &&
7677 g->anim_delay == 2 &&
7678 g->anim_mode & ANIM_LINEAR);
7679 xxx_sync_frame = (i == Xdrip_stretch ? 7 :
7680 i == Xdrip_stretchB ? 7 :
7681 i == Ydrip_s2 ? j + 8 :
7682 i == Ydrip_s2B ? j + 8 :
7691 i == Xfake_acid_1 ? 0 :
7692 i == Xfake_acid_2 ? 10 :
7693 i == Xfake_acid_3 ? 20 :
7694 i == Xfake_acid_4 ? 30 :
7695 i == Xfake_acid_5 ? 40 :
7696 i == Xfake_acid_6 ? 50 :
7697 i == Xfake_acid_7 ? 60 :
7698 i == Xfake_acid_8 ? 70 :
7700 i == Xball_2B ? j + 8 :
7701 i == Yball_eat ? j + 1 :
7702 i == Ykey_1_eat ? j + 1 :
7703 i == Ykey_2_eat ? j + 1 :
7704 i == Ykey_3_eat ? j + 1 :
7705 i == Ykey_4_eat ? j + 1 :
7706 i == Ykey_5_eat ? j + 1 :
7707 i == Ykey_6_eat ? j + 1 :
7708 i == Ykey_7_eat ? j + 1 :
7709 i == Ykey_8_eat ? j + 1 :
7710 i == Ylenses_eat ? j + 1 :
7711 i == Ymagnify_eat ? j + 1 :
7712 i == Ygrass_eat ? j + 1 :
7713 i == Ydirt_eat ? j + 1 :
7714 i == Xamoeba_1 ? 0 :
7715 i == Xamoeba_2 ? 1 :
7716 i == Xamoeba_3 ? 2 :
7717 i == Xamoeba_4 ? 3 :
7718 i == Xamoeba_5 ? 0 :
7719 i == Xamoeba_6 ? 1 :
7720 i == Xamoeba_7 ? 2 :
7721 i == Xamoeba_8 ? 3 :
7722 i == Xexit_2 ? j + 8 :
7723 i == Xexit_3 ? j + 16 :
7724 i == Xdynamite_1 ? 0 :
7725 i == Xdynamite_2 ? 8 :
7726 i == Xdynamite_3 ? 16 :
7727 i == Xdynamite_4 ? 24 :
7728 i == Xsand_stonein_1 ? j + 1 :
7729 i == Xsand_stonein_2 ? j + 9 :
7730 i == Xsand_stonein_3 ? j + 17 :
7731 i == Xsand_stonein_4 ? j + 25 :
7732 i == Xsand_stoneout_1 && j == 0 ? 0 :
7733 i == Xsand_stoneout_1 && j == 1 ? 0 :
7734 i == Xsand_stoneout_1 && j == 2 ? 1 :
7735 i == Xsand_stoneout_1 && j == 3 ? 2 :
7736 i == Xsand_stoneout_1 && j == 4 ? 2 :
7737 i == Xsand_stoneout_1 && j == 5 ? 3 :
7738 i == Xsand_stoneout_1 && j == 6 ? 4 :
7739 i == Xsand_stoneout_1 && j == 7 ? 4 :
7740 i == Xsand_stoneout_2 && j == 0 ? 5 :
7741 i == Xsand_stoneout_2 && j == 1 ? 6 :
7742 i == Xsand_stoneout_2 && j == 2 ? 7 :
7743 i == Xsand_stoneout_2 && j == 3 ? 8 :
7744 i == Xsand_stoneout_2 && j == 4 ? 9 :
7745 i == Xsand_stoneout_2 && j == 5 ? 11 :
7746 i == Xsand_stoneout_2 && j == 6 ? 13 :
7747 i == Xsand_stoneout_2 && j == 7 ? 15 :
7748 i == Xboom_bug && j == 1 ? 2 :
7749 i == Xboom_bug && j == 2 ? 2 :
7750 i == Xboom_bug && j == 3 ? 4 :
7751 i == Xboom_bug && j == 4 ? 4 :
7752 i == Xboom_bug && j == 5 ? 2 :
7753 i == Xboom_bug && j == 6 ? 2 :
7754 i == Xboom_bug && j == 7 ? 0 :
7755 i == Xboom_bomb && j == 1 ? 2 :
7756 i == Xboom_bomb && j == 2 ? 2 :
7757 i == Xboom_bomb && j == 3 ? 4 :
7758 i == Xboom_bomb && j == 4 ? 4 :
7759 i == Xboom_bomb && j == 5 ? 2 :
7760 i == Xboom_bomb && j == 6 ? 2 :
7761 i == Xboom_bomb && j == 7 ? 0 :
7762 i == Xboom_android && j == 7 ? 6 :
7763 i == Xboom_1 && j == 1 ? 2 :
7764 i == Xboom_1 && j == 2 ? 2 :
7765 i == Xboom_1 && j == 3 ? 4 :
7766 i == Xboom_1 && j == 4 ? 4 :
7767 i == Xboom_1 && j == 5 ? 6 :
7768 i == Xboom_1 && j == 6 ? 6 :
7769 i == Xboom_1 && j == 7 ? 8 :
7770 i == Xboom_2 && j == 0 ? 8 :
7771 i == Xboom_2 && j == 1 ? 8 :
7772 i == Xboom_2 && j == 2 ? 10 :
7773 i == Xboom_2 && j == 3 ? 10 :
7774 i == Xboom_2 && j == 4 ? 10 :
7775 i == Xboom_2 && j == 5 ? 12 :
7776 i == Xboom_2 && j == 6 ? 12 :
7777 i == Xboom_2 && j == 7 ? 12 :
7778 special_animation && j == 4 ? 3 :
7779 effective_action != action ? 0 :
7782 xxx_effective_action = effective_action;
7783 xxx_has_action_graphics = has_action_graphics;
7788 int frame = getAnimationFrame(g->anim_frames,
7791 g->anim_start_frame,
7805 int old_src_x = g_em->src_x;
7806 int old_src_y = g_em->src_y;
7810 getGraphicSourceExt(graphic, frame, &g_em->bitmap, &g_em->src_x, &g_em->src_y,
7811 g->double_movement && is_backside);
7813 getGraphicSourceExt(graphic, frame, &g_em->bitmap,
7814 &g_em->src_x, &g_em->src_y, FALSE);
7819 if (tile == Ydiamond_stone)
7820 printf("::: stone smashing diamond... %d: %d, %d, %d, %d, %d -> %d [%d, %d, %d, %d, %d, %d] [%d]\n",
7825 g->anim_start_frame,
7828 g_em->src_x, g_em->src_y,
7829 g_em->src_offset_x, g_em->src_offset_y,
7830 g_em->dst_offset_x, g_em->dst_offset_y,
7842 if (graphic == IMG_BUG_MOVING_RIGHT)
7843 printf("::: %d, %d, %d: %d, %d [%d, %d -> %d, %d]\n", graphic, x, y,
7844 g->double_movement, is_backside,
7845 old_src_x, old_src_y, g_em->src_x, g_em->src_y);
7853 g_em->src_offset_x = 0;
7854 g_em->src_offset_y = 0;
7855 g_em->dst_offset_x = 0;
7856 g_em->dst_offset_y = 0;
7857 g_em->width = TILEX;
7858 g_em->height = TILEY;
7860 g_em->preserve_background = FALSE;
7863 /* (updating the "crumbled" graphic definitions is probably not really needed,
7864 as animations for crumbled graphics can't be longer than one EMC cycle) */
7866 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
7871 g_em->crumbled_bitmap = NULL;
7872 g_em->crumbled_src_x = 0;
7873 g_em->crumbled_src_y = 0;
7875 g_em->has_crumbled_graphics = FALSE;
7877 if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
7879 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
7880 g_crumbled->anim_delay,
7881 g_crumbled->anim_mode,
7882 g_crumbled->anim_start_frame,
7885 getGraphicSource(crumbled, frame_crumbled, &g_em->crumbled_bitmap,
7886 &g_em->crumbled_src_x, &g_em->crumbled_src_y);
7888 g_em->has_crumbled_graphics = TRUE;
7894 int effective_action = xxx_effective_action;
7895 int has_action_graphics = xxx_has_action_graphics;
7897 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
7898 effective_action == ACTION_MOVING ||
7899 effective_action == ACTION_PUSHING ||
7900 effective_action == ACTION_EATING)) ||
7901 (!has_action_graphics && (effective_action == ACTION_FILLING ||
7902 effective_action == ACTION_EMPTYING)))
7905 (effective_action == ACTION_FALLING ||
7906 effective_action == ACTION_FILLING ||
7907 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
7908 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
7909 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
7910 int num_steps = (i == Ydrip_s1 ? 16 :
7911 i == Ydrip_s1B ? 16 :
7912 i == Ydrip_s2 ? 16 :
7913 i == Ydrip_s2B ? 16 :
7914 i == Xsand_stonein_1 ? 32 :
7915 i == Xsand_stonein_2 ? 32 :
7916 i == Xsand_stonein_3 ? 32 :
7917 i == Xsand_stonein_4 ? 32 :
7918 i == Xsand_stoneout_1 ? 16 :
7919 i == Xsand_stoneout_2 ? 16 : 8);
7920 int cx = ABS(dx) * (TILEX / num_steps);
7921 int cy = ABS(dy) * (TILEY / num_steps);
7922 int step_frame = (i == Ydrip_s2 ? j + 8 :
7923 i == Ydrip_s2B ? j + 8 :
7924 i == Xsand_stonein_2 ? j + 8 :
7925 i == Xsand_stonein_3 ? j + 16 :
7926 i == Xsand_stonein_4 ? j + 24 :
7927 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
7928 int step = (is_backside ? step_frame : num_steps - step_frame);
7930 if (is_backside) /* tile where movement starts */
7932 if (dx < 0 || dy < 0)
7934 g_em->src_offset_x = cx * step;
7935 g_em->src_offset_y = cy * step;
7939 g_em->dst_offset_x = cx * step;
7940 g_em->dst_offset_y = cy * step;
7943 else /* tile where movement ends */
7945 if (dx < 0 || dy < 0)
7947 g_em->dst_offset_x = cx * step;
7948 g_em->dst_offset_y = cy * step;
7952 g_em->src_offset_x = cx * step;
7953 g_em->src_offset_y = cy * step;
7957 g_em->width = TILEX - cx * step;
7958 g_em->height = TILEY - cy * step;
7961 /* create unique graphic identifier to decide if tile must be redrawn */
7962 /* bit 31 - 16 (16 bit): EM style graphic
7963 bit 15 - 12 ( 4 bit): EM style frame
7964 bit 11 - 6 ( 6 bit): graphic width
7965 bit 5 - 0 ( 6 bit): graphic height */
7966 g_em->unique_identifier =
7967 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
7973 void getGraphicSourcePlayerExt_EM(struct GraphicInfo_EM *g_em,
7974 int player_nr, int anim, int frame_em)
7976 int element = player_mapping[player_nr][anim].element_rnd;
7977 int action = player_mapping[player_nr][anim].action;
7978 int direction = player_mapping[player_nr][anim].direction;
7979 int graphic = (direction == MV_NONE ?
7980 el_act2img(element, action) :
7981 el_act_dir2img(element, action, direction));
7982 struct GraphicInfo *g = &graphic_info[graphic];
7985 InitPlayerGfxAnimation(&stored_player[player_nr], action, direction);
7987 stored_player[player_nr].StepFrame = frame_em;
7989 sync_frame = stored_player[player_nr].Frame;
7991 int frame = getAnimationFrame(g->anim_frames,
7994 g->anim_start_frame,
7997 getGraphicSourceExt(graphic, frame, &g_em->bitmap,
7998 &g_em->src_x, &g_em->src_y, FALSE);
8001 printf("::: %d: %d, %d [%d]\n",
8003 stored_player[player_nr].Frame,
8004 stored_player[player_nr].StepFrame,
8009 void InitGraphicInfo_EM(void)
8012 struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
8013 struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
8018 int num_em_gfx_errors = 0;
8020 if (graphic_info_em_object[0][0].bitmap == NULL)
8022 /* EM graphics not yet initialized in em_open_all() */
8027 printf("::: [4 errors can be ignored (1 x 'bomb', 3 x 'em_dynamite']\n");
8030 /* always start with reliable default values */
8031 for (i = 0; i < TILE_MAX; i++)
8033 object_mapping[i].element_rnd = EL_UNKNOWN;
8034 object_mapping[i].is_backside = FALSE;
8035 object_mapping[i].action = ACTION_DEFAULT;
8036 object_mapping[i].direction = MV_NONE;
8039 /* always start with reliable default values */
8040 for (p = 0; p < MAX_PLAYERS; p++)
8042 for (i = 0; i < SPR_MAX; i++)
8044 player_mapping[p][i].element_rnd = EL_UNKNOWN;
8045 player_mapping[p][i].action = ACTION_DEFAULT;
8046 player_mapping[p][i].direction = MV_NONE;
8050 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
8052 int e = em_object_mapping_list[i].element_em;
8054 object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd;
8055 object_mapping[e].is_backside = em_object_mapping_list[i].is_backside;
8057 if (em_object_mapping_list[i].action != -1)
8058 object_mapping[e].action = em_object_mapping_list[i].action;
8060 if (em_object_mapping_list[i].direction != -1)
8061 object_mapping[e].direction =
8062 MV_DIR_FROM_BIT(em_object_mapping_list[i].direction);
8065 for (i = 0; em_player_mapping_list[i].action_em != -1; i++)
8067 int a = em_player_mapping_list[i].action_em;
8068 int p = em_player_mapping_list[i].player_nr;
8070 player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd;
8072 if (em_player_mapping_list[i].action != -1)
8073 player_mapping[p][a].action = em_player_mapping_list[i].action;
8075 if (em_player_mapping_list[i].direction != -1)
8076 player_mapping[p][a].direction =
8077 MV_DIR_FROM_BIT(em_player_mapping_list[i].direction);
8080 for (i = 0; i < TILE_MAX; i++)
8082 int element = object_mapping[i].element_rnd;
8083 int action = object_mapping[i].action;
8084 int direction = object_mapping[i].direction;
8085 boolean is_backside = object_mapping[i].is_backside;
8087 boolean action_removing = (action == ACTION_DIGGING ||
8088 action == ACTION_SNAPPING ||
8089 action == ACTION_COLLECTING);
8091 boolean action_exploding = ((action == ACTION_EXPLODING ||
8092 action == ACTION_SMASHED_BY_ROCK ||
8093 action == ACTION_SMASHED_BY_SPRING) &&
8094 element != EL_DIAMOND);
8095 boolean action_active = (action == ACTION_ACTIVE);
8096 boolean action_other = (action == ACTION_OTHER);
8098 for (j = 0; j < 8; j++)
8101 int effective_element = get_effective_element_EM(i, j);
8103 int effective_element = (j > 5 && i == Yacid_splash_eB ? EL_EMPTY :
8104 j > 5 && i == Yacid_splash_wB ? EL_EMPTY :
8106 i == Xdrip_stretch ? element :
8107 i == Xdrip_stretchB ? element :
8108 i == Ydrip_s1 ? element :
8109 i == Ydrip_s1B ? element :
8110 i == Xball_1B ? element :
8111 i == Xball_2 ? element :
8112 i == Xball_2B ? element :
8113 i == Yball_eat ? element :
8114 i == Ykey_1_eat ? element :
8115 i == Ykey_2_eat ? element :
8116 i == Ykey_3_eat ? element :
8117 i == Ykey_4_eat ? element :
8118 i == Ykey_5_eat ? element :
8119 i == Ykey_6_eat ? element :
8120 i == Ykey_7_eat ? element :
8121 i == Ykey_8_eat ? element :
8122 i == Ylenses_eat ? element :
8123 i == Ymagnify_eat ? element :
8124 i == Ygrass_eat ? element :
8125 i == Ydirt_eat ? element :
8126 i == Yemerald_stone ? EL_EMERALD :
8127 i == Ydiamond_stone ? EL_ROCK :
8128 i == Xsand_stonein_1 ? element :
8129 i == Xsand_stonein_2 ? element :
8130 i == Xsand_stonein_3 ? element :
8131 i == Xsand_stonein_4 ? element :
8132 is_backside ? EL_EMPTY :
8133 action_removing ? EL_EMPTY :
8136 int effective_action = (j < 7 ? action :
8137 i == Xdrip_stretch ? action :
8138 i == Xdrip_stretchB ? action :
8139 i == Ydrip_s1 ? action :
8140 i == Ydrip_s1B ? action :
8141 i == Xball_1B ? action :
8142 i == Xball_2 ? action :
8143 i == Xball_2B ? action :
8144 i == Yball_eat ? action :
8145 i == Ykey_1_eat ? action :
8146 i == Ykey_2_eat ? action :
8147 i == Ykey_3_eat ? action :
8148 i == Ykey_4_eat ? action :
8149 i == Ykey_5_eat ? action :
8150 i == Ykey_6_eat ? action :
8151 i == Ykey_7_eat ? action :
8152 i == Ykey_8_eat ? action :
8153 i == Ylenses_eat ? action :
8154 i == Ymagnify_eat ? action :
8155 i == Ygrass_eat ? action :
8156 i == Ydirt_eat ? action :
8157 i == Xsand_stonein_1 ? action :
8158 i == Xsand_stonein_2 ? action :
8159 i == Xsand_stonein_3 ? action :
8160 i == Xsand_stonein_4 ? action :
8161 i == Xsand_stoneout_1 ? action :
8162 i == Xsand_stoneout_2 ? action :
8163 i == Xboom_android ? ACTION_EXPLODING :
8164 action_exploding ? ACTION_EXPLODING :
8165 action_active ? action :
8166 action_other ? action :
8168 int graphic = (el_act_dir2img(effective_element, effective_action,
8170 int crumbled = (el_act_dir2crm(effective_element, effective_action,
8172 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
8173 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
8174 boolean has_action_graphics = (graphic != base_graphic);
8175 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
8176 struct GraphicInfo *g = &graphic_info[graphic];
8178 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
8180 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
8183 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
8184 boolean special_animation = (action != ACTION_DEFAULT &&
8185 g->anim_frames == 3 &&
8186 g->anim_delay == 2 &&
8187 g->anim_mode & ANIM_LINEAR);
8188 int sync_frame = (i == Xdrip_stretch ? 7 :
8189 i == Xdrip_stretchB ? 7 :
8190 i == Ydrip_s2 ? j + 8 :
8191 i == Ydrip_s2B ? j + 8 :
8200 i == Xfake_acid_1 ? 0 :
8201 i == Xfake_acid_2 ? 10 :
8202 i == Xfake_acid_3 ? 20 :
8203 i == Xfake_acid_4 ? 30 :
8204 i == Xfake_acid_5 ? 40 :
8205 i == Xfake_acid_6 ? 50 :
8206 i == Xfake_acid_7 ? 60 :
8207 i == Xfake_acid_8 ? 70 :
8209 i == Xball_2B ? j + 8 :
8210 i == Yball_eat ? j + 1 :
8211 i == Ykey_1_eat ? j + 1 :
8212 i == Ykey_2_eat ? j + 1 :
8213 i == Ykey_3_eat ? j + 1 :
8214 i == Ykey_4_eat ? j + 1 :
8215 i == Ykey_5_eat ? j + 1 :
8216 i == Ykey_6_eat ? j + 1 :
8217 i == Ykey_7_eat ? j + 1 :
8218 i == Ykey_8_eat ? j + 1 :
8219 i == Ylenses_eat ? j + 1 :
8220 i == Ymagnify_eat ? j + 1 :
8221 i == Ygrass_eat ? j + 1 :
8222 i == Ydirt_eat ? j + 1 :
8223 i == Xamoeba_1 ? 0 :
8224 i == Xamoeba_2 ? 1 :
8225 i == Xamoeba_3 ? 2 :
8226 i == Xamoeba_4 ? 3 :
8227 i == Xamoeba_5 ? 0 :
8228 i == Xamoeba_6 ? 1 :
8229 i == Xamoeba_7 ? 2 :
8230 i == Xamoeba_8 ? 3 :
8231 i == Xexit_2 ? j + 8 :
8232 i == Xexit_3 ? j + 16 :
8233 i == Xdynamite_1 ? 0 :
8234 i == Xdynamite_2 ? 8 :
8235 i == Xdynamite_3 ? 16 :
8236 i == Xdynamite_4 ? 24 :
8237 i == Xsand_stonein_1 ? j + 1 :
8238 i == Xsand_stonein_2 ? j + 9 :
8239 i == Xsand_stonein_3 ? j + 17 :
8240 i == Xsand_stonein_4 ? j + 25 :
8241 i == Xsand_stoneout_1 && j == 0 ? 0 :
8242 i == Xsand_stoneout_1 && j == 1 ? 0 :
8243 i == Xsand_stoneout_1 && j == 2 ? 1 :
8244 i == Xsand_stoneout_1 && j == 3 ? 2 :
8245 i == Xsand_stoneout_1 && j == 4 ? 2 :
8246 i == Xsand_stoneout_1 && j == 5 ? 3 :
8247 i == Xsand_stoneout_1 && j == 6 ? 4 :
8248 i == Xsand_stoneout_1 && j == 7 ? 4 :
8249 i == Xsand_stoneout_2 && j == 0 ? 5 :
8250 i == Xsand_stoneout_2 && j == 1 ? 6 :
8251 i == Xsand_stoneout_2 && j == 2 ? 7 :
8252 i == Xsand_stoneout_2 && j == 3 ? 8 :
8253 i == Xsand_stoneout_2 && j == 4 ? 9 :
8254 i == Xsand_stoneout_2 && j == 5 ? 11 :
8255 i == Xsand_stoneout_2 && j == 6 ? 13 :
8256 i == Xsand_stoneout_2 && j == 7 ? 15 :
8257 i == Xboom_bug && j == 1 ? 2 :
8258 i == Xboom_bug && j == 2 ? 2 :
8259 i == Xboom_bug && j == 3 ? 4 :
8260 i == Xboom_bug && j == 4 ? 4 :
8261 i == Xboom_bug && j == 5 ? 2 :
8262 i == Xboom_bug && j == 6 ? 2 :
8263 i == Xboom_bug && j == 7 ? 0 :
8264 i == Xboom_bomb && j == 1 ? 2 :
8265 i == Xboom_bomb && j == 2 ? 2 :
8266 i == Xboom_bomb && j == 3 ? 4 :
8267 i == Xboom_bomb && j == 4 ? 4 :
8268 i == Xboom_bomb && j == 5 ? 2 :
8269 i == Xboom_bomb && j == 6 ? 2 :
8270 i == Xboom_bomb && j == 7 ? 0 :
8271 i == Xboom_android && j == 7 ? 6 :
8272 i == Xboom_1 && j == 1 ? 2 :
8273 i == Xboom_1 && j == 2 ? 2 :
8274 i == Xboom_1 && j == 3 ? 4 :
8275 i == Xboom_1 && j == 4 ? 4 :
8276 i == Xboom_1 && j == 5 ? 6 :
8277 i == Xboom_1 && j == 6 ? 6 :
8278 i == Xboom_1 && j == 7 ? 8 :
8279 i == Xboom_2 && j == 0 ? 8 :
8280 i == Xboom_2 && j == 1 ? 8 :
8281 i == Xboom_2 && j == 2 ? 10 :
8282 i == Xboom_2 && j == 3 ? 10 :
8283 i == Xboom_2 && j == 4 ? 10 :
8284 i == Xboom_2 && j == 5 ? 12 :
8285 i == Xboom_2 && j == 6 ? 12 :
8286 i == Xboom_2 && j == 7 ? 12 :
8287 special_animation && j == 4 ? 3 :
8288 effective_action != action ? 0 :
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,
8304 g->double_movement && is_backside);
8306 g_em->bitmap = src_bitmap;
8307 g_em->src_x = src_x;
8308 g_em->src_y = src_y;
8309 g_em->src_offset_x = 0;
8310 g_em->src_offset_y = 0;
8311 g_em->dst_offset_x = 0;
8312 g_em->dst_offset_y = 0;
8313 g_em->width = TILEX;
8314 g_em->height = TILEY;
8316 g_em->preserve_background = FALSE;
8319 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
8324 g_em->crumbled_bitmap = NULL;
8325 g_em->crumbled_src_x = 0;
8326 g_em->crumbled_src_y = 0;
8327 g_em->crumbled_border_size = 0;
8329 g_em->has_crumbled_graphics = FALSE;
8332 if (has_crumbled_graphics && crumbled == IMG_EMPTY_SPACE)
8333 printf("::: empty crumbled: %d [%s], %d, %d\n",
8334 effective_element, element_info[effective_element].token_name,
8335 effective_action, direction);
8338 /* if element can be crumbled, but certain action graphics are just empty
8339 space (like instantly snapping sand to empty space in 1 frame), do not
8340 treat these empty space graphics as crumbled graphics in EMC engine */
8341 if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
8343 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
8344 g_crumbled->anim_delay,
8345 g_crumbled->anim_mode,
8346 g_crumbled->anim_start_frame,
8349 getGraphicSource(crumbled, frame_crumbled, &src_bitmap, &src_x, &src_y);
8351 g_em->has_crumbled_graphics = TRUE;
8352 g_em->crumbled_bitmap = src_bitmap;
8353 g_em->crumbled_src_x = src_x;
8354 g_em->crumbled_src_y = src_y;
8355 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
8359 if (g_em == &graphic_info_em_object[207][0])
8360 printf("... %d, %d [%d, %d, %d, %d] [%d, %d, %d, %d, %d, %d => %d]\n",
8361 graphic_info_em_object[207][0].crumbled_src_x,
8362 graphic_info_em_object[207][0].crumbled_src_y,
8364 crumbled, frame, src_x, src_y,
8369 g->anim_start_frame,
8371 gfx.anim_random_frame,
8376 printf("::: EMC tile %d is crumbled\n", i);
8382 if (element == EL_ROCK &&
8383 effective_action == ACTION_FILLING)
8384 printf("::: has_action_graphics == %d\n", has_action_graphics);
8387 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
8388 effective_action == ACTION_MOVING ||
8389 effective_action == ACTION_PUSHING ||
8390 effective_action == ACTION_EATING)) ||
8391 (!has_action_graphics && (effective_action == ACTION_FILLING ||
8392 effective_action == ACTION_EMPTYING)))
8395 (effective_action == ACTION_FALLING ||
8396 effective_action == ACTION_FILLING ||
8397 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
8398 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
8399 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
8400 int num_steps = (i == Ydrip_s1 ? 16 :
8401 i == Ydrip_s1B ? 16 :
8402 i == Ydrip_s2 ? 16 :
8403 i == Ydrip_s2B ? 16 :
8404 i == Xsand_stonein_1 ? 32 :
8405 i == Xsand_stonein_2 ? 32 :
8406 i == Xsand_stonein_3 ? 32 :
8407 i == Xsand_stonein_4 ? 32 :
8408 i == Xsand_stoneout_1 ? 16 :
8409 i == Xsand_stoneout_2 ? 16 : 8);
8410 int cx = ABS(dx) * (TILEX / num_steps);
8411 int cy = ABS(dy) * (TILEY / num_steps);
8412 int step_frame = (i == Ydrip_s2 ? j + 8 :
8413 i == Ydrip_s2B ? j + 8 :
8414 i == Xsand_stonein_2 ? j + 8 :
8415 i == Xsand_stonein_3 ? j + 16 :
8416 i == Xsand_stonein_4 ? j + 24 :
8417 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
8418 int step = (is_backside ? step_frame : num_steps - step_frame);
8420 if (is_backside) /* tile where movement starts */
8422 if (dx < 0 || dy < 0)
8424 g_em->src_offset_x = cx * step;
8425 g_em->src_offset_y = cy * step;
8429 g_em->dst_offset_x = cx * step;
8430 g_em->dst_offset_y = cy * step;
8433 else /* tile where movement ends */
8435 if (dx < 0 || dy < 0)
8437 g_em->dst_offset_x = cx * step;
8438 g_em->dst_offset_y = cy * step;
8442 g_em->src_offset_x = cx * step;
8443 g_em->src_offset_y = cy * step;
8447 g_em->width = TILEX - cx * step;
8448 g_em->height = TILEY - cy * step;
8451 /* create unique graphic identifier to decide if tile must be redrawn */
8452 /* bit 31 - 16 (16 bit): EM style graphic
8453 bit 15 - 12 ( 4 bit): EM style frame
8454 bit 11 - 6 ( 6 bit): graphic width
8455 bit 5 - 0 ( 6 bit): graphic height */
8456 g_em->unique_identifier =
8457 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
8461 /* skip check for EMC elements not contained in original EMC artwork */
8462 if (element == EL_EMC_FAKE_ACID)
8465 if (g_em->bitmap != debug_bitmap ||
8466 g_em->src_x != debug_src_x ||
8467 g_em->src_y != debug_src_y ||
8468 g_em->src_offset_x != 0 ||
8469 g_em->src_offset_y != 0 ||
8470 g_em->dst_offset_x != 0 ||
8471 g_em->dst_offset_y != 0 ||
8472 g_em->width != TILEX ||
8473 g_em->height != TILEY)
8475 static int last_i = -1;
8483 printf("::: EMC GFX ERROR for element %d -> %d ('%s', '%s', %d)",
8484 i, element, element_info[element].token_name,
8485 element_action_info[effective_action].suffix, direction);
8487 if (element != effective_element)
8488 printf(" [%d ('%s')]",
8490 element_info[effective_element].token_name);
8494 if (g_em->bitmap != debug_bitmap)
8495 printf(" %d (%d): different bitmap! (0x%08x != 0x%08x)\n",
8496 j, is_backside, (int)(g_em->bitmap), (int)(debug_bitmap));
8498 if (g_em->src_x != debug_src_x ||
8499 g_em->src_y != debug_src_y)
8500 printf(" frame %d (%c): %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
8501 j, (is_backside ? 'B' : 'F'),
8502 g_em->src_x, g_em->src_y,
8503 g_em->src_x / 32, g_em->src_y / 32,
8504 debug_src_x, debug_src_y,
8505 debug_src_x / 32, debug_src_y / 32);
8507 if (g_em->src_offset_x != 0 ||
8508 g_em->src_offset_y != 0 ||
8509 g_em->dst_offset_x != 0 ||
8510 g_em->dst_offset_y != 0)
8511 printf(" %d (%d): offsets %d,%d and %d,%d should be all 0\n",
8513 g_em->src_offset_x, g_em->src_offset_y,
8514 g_em->dst_offset_x, g_em->dst_offset_y);
8516 if (g_em->width != TILEX ||
8517 g_em->height != TILEY)
8518 printf(" %d (%d): size %d,%d should be %d,%d\n",
8520 g_em->width, g_em->height, TILEX, TILEY);
8522 num_em_gfx_errors++;
8529 for (i = 0; i < TILE_MAX; i++)
8531 for (j = 0; j < 8; j++)
8533 int element = object_mapping[i].element_rnd;
8534 int action = object_mapping[i].action;
8535 int direction = object_mapping[i].direction;
8536 boolean is_backside = object_mapping[i].is_backside;
8537 int graphic_action = el_act_dir2img(element, action, direction);
8538 int graphic_default = el_act_dir2img(element, ACTION_DEFAULT, direction);
8540 if ((action == ACTION_SMASHED_BY_ROCK ||
8541 action == ACTION_SMASHED_BY_SPRING ||
8542 action == ACTION_EATING) &&
8543 graphic_action == graphic_default)
8545 int e = (action == ACTION_SMASHED_BY_ROCK ? Ystone_s :
8546 action == ACTION_SMASHED_BY_SPRING ? Yspring_s :
8547 direction == MV_LEFT ? (is_backside? Yspring_wB: Yspring_w) :
8548 direction == MV_RIGHT ? (is_backside? Yspring_eB: Yspring_e) :
8551 /* no separate animation for "smashed by rock" -- use rock instead */
8552 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
8553 struct GraphicInfo_EM *g_xx = &graphic_info_em_object[e][7 - j];
8555 g_em->bitmap = g_xx->bitmap;
8556 g_em->src_x = g_xx->src_x;
8557 g_em->src_y = g_xx->src_y;
8558 g_em->src_offset_x = g_xx->src_offset_x;
8559 g_em->src_offset_y = g_xx->src_offset_y;
8560 g_em->dst_offset_x = g_xx->dst_offset_x;
8561 g_em->dst_offset_y = g_xx->dst_offset_y;
8562 g_em->width = g_xx->width;
8563 g_em->height = g_xx->height;
8564 g_em->unique_identifier = g_xx->unique_identifier;
8567 g_em->preserve_background = TRUE;
8572 for (p = 0; p < MAX_PLAYERS; p++)
8574 for (i = 0; i < SPR_MAX; i++)
8576 int element = player_mapping[p][i].element_rnd;
8577 int action = player_mapping[p][i].action;
8578 int direction = player_mapping[p][i].direction;
8580 for (j = 0; j < 8; j++)
8582 int effective_element = element;
8583 int effective_action = action;
8584 int graphic = (direction == MV_NONE ?
8585 el_act2img(effective_element, effective_action) :
8586 el_act_dir2img(effective_element, effective_action,
8588 struct GraphicInfo *g = &graphic_info[graphic];
8589 struct GraphicInfo_EM *g_em = &graphic_info_em_player[p][i][7 - j];
8595 Bitmap *debug_bitmap = g_em->bitmap;
8596 int debug_src_x = g_em->src_x;
8597 int debug_src_y = g_em->src_y;
8600 int frame = getAnimationFrame(g->anim_frames,
8603 g->anim_start_frame,
8606 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
8608 g_em->bitmap = src_bitmap;
8609 g_em->src_x = src_x;
8610 g_em->src_y = src_y;
8611 g_em->src_offset_x = 0;
8612 g_em->src_offset_y = 0;
8613 g_em->dst_offset_x = 0;
8614 g_em->dst_offset_y = 0;
8615 g_em->width = TILEX;
8616 g_em->height = TILEY;
8620 /* skip check for EMC elements not contained in original EMC artwork */
8621 if (element == EL_PLAYER_3 ||
8622 element == EL_PLAYER_4)
8625 if (g_em->bitmap != debug_bitmap ||
8626 g_em->src_x != debug_src_x ||
8627 g_em->src_y != debug_src_y)
8629 static int last_i = -1;
8637 printf("::: EMC GFX ERROR for p/a %d/%d -> %d ('%s', '%s', %d)",
8638 p, i, element, element_info[element].token_name,
8639 element_action_info[effective_action].suffix, direction);
8641 if (element != effective_element)
8642 printf(" [%d ('%s')]",
8644 element_info[effective_element].token_name);
8648 if (g_em->bitmap != debug_bitmap)
8649 printf(" %d: different bitmap! (0x%08x != 0x%08x)\n",
8650 j, (int)(g_em->bitmap), (int)(debug_bitmap));
8652 if (g_em->src_x != debug_src_x ||
8653 g_em->src_y != debug_src_y)
8654 printf(" frame %d: %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
8656 g_em->src_x, g_em->src_y,
8657 g_em->src_x / 32, g_em->src_y / 32,
8658 debug_src_x, debug_src_y,
8659 debug_src_x / 32, debug_src_y / 32);
8661 num_em_gfx_errors++;
8671 printf("::: [%d errors found]\n", num_em_gfx_errors);
8677 void CheckSingleStepMode_EM(byte action[MAX_PLAYERS], int frame,
8678 boolean any_player_moving,
8679 boolean player_is_dropping)
8683 if (tape.single_step && tape.recording && !tape.pausing)
8685 boolean active_players = FALSE;
8687 for (i = 0; i < MAX_PLAYERS; i++)
8688 if (action[i] != JOY_NO_ACTION)
8689 active_players = TRUE;
8692 if (frame == 0 && !player_is_dropping)
8693 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
8697 void CheckSingleStepMode_SP(boolean murphy_is_waiting,
8698 boolean murphy_is_dropping)
8701 printf("::: waiting: %d, dropping: %d\n",
8702 murphy_is_waiting, murphy_is_dropping);
8705 if (tape.single_step && tape.recording && !tape.pausing)
8707 // if (murphy_is_waiting || murphy_is_dropping)
8708 if (murphy_is_waiting)
8711 printf("::: murphy is waiting -> pause mode\n");
8714 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
8719 void getGraphicSource_SP(struct GraphicInfo_SP *g_sp,
8720 int graphic, int sync_frame, int x, int y)
8722 int frame = getGraphicAnimationFrame(graphic, sync_frame);
8724 getGraphicSource(graphic, frame, &g_sp->bitmap, &g_sp->src_x, &g_sp->src_y);
8727 boolean isNextAnimationFrame_SP(int graphic, int sync_frame)
8729 return (IS_NEXT_FRAME(sync_frame, graphic));
8732 int getGraphicInfo_Delay(int graphic)
8734 return graphic_info[graphic].anim_delay;
8737 void PlayMenuSoundExt(int sound)
8739 if (sound == SND_UNDEFINED)
8742 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
8743 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
8746 if (IS_LOOP_SOUND(sound))
8747 PlaySoundLoop(sound);
8752 void PlayMenuSound()
8754 PlayMenuSoundExt(menu.sound[game_status]);
8757 void PlayMenuSoundStereo(int sound, int stereo_position)
8759 if (sound == SND_UNDEFINED)
8762 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
8763 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
8766 if (IS_LOOP_SOUND(sound))
8767 PlaySoundExt(sound, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_LOOP);
8769 PlaySoundStereo(sound, stereo_position);
8772 void PlayMenuSoundIfLoopExt(int sound)
8774 if (sound == SND_UNDEFINED)
8777 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
8778 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
8781 if (IS_LOOP_SOUND(sound))
8782 PlaySoundLoop(sound);
8785 void PlayMenuSoundIfLoop()
8787 PlayMenuSoundIfLoopExt(menu.sound[game_status]);
8790 void PlayMenuMusicExt(int music)
8792 if (music == MUS_UNDEFINED)
8795 if (!setup.sound_music)
8801 void PlayMenuMusic()
8803 PlayMenuMusicExt(menu.music[game_status]);
8806 void PlaySoundActivating()
8809 PlaySound(SND_MENU_ITEM_ACTIVATING);
8813 void PlaySoundSelecting()
8816 PlaySound(SND_MENU_ITEM_SELECTING);
8820 void ToggleFullscreenIfNeeded()
8822 boolean change_fullscreen = (setup.fullscreen !=
8823 video.fullscreen_enabled);
8824 boolean change_fullscreen_mode = (video.fullscreen_enabled &&
8825 !strEqual(setup.fullscreen_mode,
8826 video.fullscreen_mode_current));
8828 if (!video.fullscreen_available)
8831 if (change_fullscreen || change_fullscreen_mode)
8833 Bitmap *tmp_backbuffer = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
8835 /* save backbuffer content which gets lost when toggling fullscreen mode */
8836 BlitBitmap(backbuffer, tmp_backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
8838 if (change_fullscreen_mode)
8840 /* keep fullscreen, but change fullscreen mode (screen resolution) */
8841 video.fullscreen_enabled = FALSE; /* force new fullscreen mode */
8844 /* toggle fullscreen */
8845 ChangeVideoModeIfNeeded(setup.fullscreen);
8847 setup.fullscreen = video.fullscreen_enabled;
8849 /* restore backbuffer content from temporary backbuffer backup bitmap */
8850 BlitBitmap(tmp_backbuffer, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
8852 FreeBitmap(tmp_backbuffer);
8855 /* update visible window/screen */
8856 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
8858 redraw_mask = REDRAW_ALL;
8863 void ChangeViewportPropertiesIfNeeded()
8865 int *door_1_x = &DX;
8866 int *door_1_y = &DY;
8867 int *door_2_x = (game_status == GAME_MODE_EDITOR ? &EX : &VX);
8868 int *door_2_y = (game_status == GAME_MODE_EDITOR ? &EY : &VY);
8869 int gfx_game_mode = (game_status == GAME_MODE_PLAYING ||
8870 game_status == GAME_MODE_EDITOR ? game_status :
8872 struct RectWithBorder *vp_playfield = &viewport.playfield[gfx_game_mode];
8873 struct RectWithBorder *vp_door_1 = &viewport.door_1[gfx_game_mode];
8874 struct RectWithBorder *vp_door_2 = &viewport.door_2[gfx_game_mode];
8875 int border_size = vp_playfield->border_size;
8876 int new_sx = vp_playfield->x + border_size;
8877 int new_sy = vp_playfield->y + border_size;
8878 int new_sxsize = vp_playfield->width - 2 * border_size;
8879 int new_sysize = vp_playfield->height - 2 * border_size;
8880 int new_real_sx = vp_playfield->x;
8881 int new_real_sy = vp_playfield->y;
8882 int new_full_sxsize = vp_playfield->width;
8883 int new_full_sysize = vp_playfield->height;
8885 int new_tilesize_var = TILESIZE / (setup.small_game_graphics ? 2 : 1);
8886 int tilesize = (gfx_game_mode == GAME_MODE_PLAYING ? new_tilesize_var :
8887 gfx_game_mode == GAME_MODE_EDITOR ? MINI_TILESIZE : TILESIZE);
8888 int new_scr_fieldx = new_sxsize / tilesize;
8889 int new_scr_fieldy = new_sysize / tilesize;
8890 int new_scr_fieldx_buffers = new_sxsize / new_tilesize_var;
8891 int new_scr_fieldy_buffers = new_sysize / new_tilesize_var;
8893 int new_scr_fieldx = (vp_playfield->width - 2 * border_size) / TILESIZE;
8894 int new_scr_fieldy = (vp_playfield->height - 2 * border_size) / TILESIZE;
8896 boolean init_gfx_buffers = FALSE;
8897 boolean init_video_buffer = FALSE;
8898 boolean init_gadgets_and_toons = FALSE;
8901 /* !!! TEST ONLY !!! */
8902 // InitGfxBuffers();
8906 if (viewport.window.width != WIN_XSIZE ||
8907 viewport.window.height != WIN_YSIZE)
8909 WIN_XSIZE = viewport.window.width;
8910 WIN_YSIZE = viewport.window.height;
8913 init_video_buffer = TRUE;
8914 init_gfx_buffers = TRUE;
8916 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
8920 SetDrawDeactivationMask(REDRAW_NONE);
8921 SetDrawBackgroundMask(REDRAW_FIELD);
8923 // RedrawBackground();
8927 // printf("::: video: init_video_buffer, init_gfx_buffers\n");
8930 if (new_scr_fieldx != SCR_FIELDX ||
8931 new_scr_fieldy != SCR_FIELDY)
8933 /* this always toggles between MAIN and GAME when using small tile size */
8935 SCR_FIELDX = new_scr_fieldx;
8936 SCR_FIELDY = new_scr_fieldy;
8938 // printf("::: new_scr_fieldx != SCR_FIELDX ...\n");
8942 if (new_tilesize_var != TILESIZE_VAR &&
8943 gfx_game_mode == GAME_MODE_PLAYING)
8945 /* doing this outside GAME_MODE_PLAYING would give wrong playfield size */
8947 TILESIZE_VAR = new_tilesize_var;
8949 init_gfx_buffers = TRUE;
8951 // printf("::: tilesize: init_gfx_buffers\n");
8957 new_sxsize != SXSIZE ||
8958 new_sysize != SYSIZE ||
8959 new_real_sx != REAL_SX ||
8960 new_real_sy != REAL_SY ||
8961 new_full_sxsize != FULL_SXSIZE ||
8962 new_full_sysize != FULL_SYSIZE ||
8963 new_tilesize_var != TILESIZE_VAR ||
8964 vp_door_1->x != *door_1_x ||
8965 vp_door_1->y != *door_1_y ||
8966 vp_door_2->x != *door_2_x ||
8967 vp_door_2->y != *door_2_y)
8971 SXSIZE = new_sxsize;
8972 SYSIZE = new_sysize;
8973 REAL_SX = new_real_sx;
8974 REAL_SY = new_real_sy;
8975 FULL_SXSIZE = new_full_sxsize;
8976 FULL_SYSIZE = new_full_sysize;
8977 TILESIZE_VAR = new_tilesize_var;
8980 printf("::: %d, %d, %d [%d]\n",
8981 SCR_FIELDX, SCR_FIELDY, TILESIZE_VAR,
8982 setup.small_game_graphics);
8985 *door_1_x = vp_door_1->x;
8986 *door_1_y = vp_door_1->y;
8987 *door_2_x = vp_door_2->x;
8988 *door_2_y = vp_door_2->y;
8991 init_gfx_buffers = TRUE;
8993 // printf("::: viewports: init_gfx_buffers\n");
8998 if (gfx_game_mode == GAME_MODE_MAIN)
9001 init_gadgets_and_toons = TRUE;
9003 // printf("::: viewports: init_gadgets_and_toons\n");
9011 if (init_gfx_buffers)
9013 // printf("::: init_gfx_buffers\n");
9015 SCR_FIELDX = new_scr_fieldx_buffers;
9016 SCR_FIELDY = new_scr_fieldy_buffers;
9020 SCR_FIELDX = new_scr_fieldx;
9021 SCR_FIELDY = new_scr_fieldy;
9024 if (init_video_buffer)
9026 // printf("::: init_video_buffer\n");
9028 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
9030 SetDrawDeactivationMask(REDRAW_NONE);
9031 SetDrawBackgroundMask(REDRAW_FIELD);
9034 if (init_gadgets_and_toons)
9036 // printf("::: init_gadgets_and_toons\n");
9043 printf("::: %d, %d / %d, %d [%d]\n", VX, VY, EX, EY, game_status);