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();
307 void BlitScreenToBitmap(Bitmap *target_bitmap)
309 DrawBuffer *buffer = (drawto_field == window ? backbuffer : drawto_field);
310 int fx = FX, fy = FY;
313 int dx = (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
314 int dy = (ScreenMovDir & (MV_UP | MV_DOWN) ? ScreenGfxPos : 0);
315 int dx_var = dx * TILESIZE_VAR / TILESIZE;
316 int dy_var = dy * TILESIZE_VAR / TILESIZE;
319 // fx += dx * TILESIZE_VAR / TILESIZE;
320 // fy += dy * TILESIZE_VAR / TILESIZE;
322 fx += (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
323 fy += (ScreenMovDir & (MV_UP | MV_DOWN) ? ScreenGfxPos : 0);
326 ffx = (scroll_x - SBX_Left) * TILEX_VAR + dx_var;
327 ffy = (scroll_y - SBY_Upper) * TILEY_VAR + dy_var;
329 if (EVEN(SCR_FIELDX))
331 if (ffx < SBX_Right * TILEX_VAR + TILEX_VAR / 2 + TILEX_VAR)
332 fx += dx_var - MIN(ffx, TILEX_VAR / 2) + TILEX_VAR;
334 fx += (dx_var > 0 ? TILEX_VAR : 0);
341 if (EVEN(SCR_FIELDY))
343 if (ffy < SBY_Lower * TILEY_VAR + TILEY_VAR / 2 + TILEY_VAR)
344 fy += dy_var - MIN(ffy, TILEY_VAR / 2) + TILEY_VAR;
346 fy += (dy_var > 0 ? TILEY_VAR : 0);
354 printf("::: (%d, %d) [(%d / %d, %d / %d)] => %d, %d\n",
357 SBY_Upper, SBY_Lower,
361 if (border.draw_masked[GAME_MODE_PLAYING])
363 if (buffer != backbuffer)
365 /* copy playfield buffer to backbuffer to add masked border */
366 BlitBitmap(buffer, backbuffer, fx, fy, SXSIZE, SYSIZE, SX, SY);
367 DrawMaskedBorder(REDRAW_FIELD);
370 BlitBitmap(backbuffer, target_bitmap,
371 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
376 BlitBitmap(buffer, target_bitmap, fx, fy, SXSIZE, SYSIZE, SX, SY);
383 DrawBuffer *buffer = (drawto_field == window ? backbuffer : drawto_field);
386 printf("::: TILES TO REFRESH: %d\n", redraw_tiles);
387 for (x = 0; x < SCR_FIELDX; x++)
388 for (y = 0 ; y < SCR_FIELDY; y++)
389 if (redraw[redraw_x1 + x][redraw_y1 + y])
390 printf("::: - %d, %d [%s]\n",
391 LEVELX(x), LEVELY(y),
392 EL_NAME(Feld[LEVELX(x)][LEVELY(y)]));
395 if (redraw_mask & REDRAW_TILES && redraw_tiles > REDRAWTILES_THRESHOLD)
396 redraw_mask |= REDRAW_FIELD;
399 // never redraw single tiles, always redraw the whole field
400 // (redrawing single tiles up to a certain threshold was faster on old,
401 // now legacy graphics, but slows things down on modern graphics now)
402 // UPDATE: this is now globally defined by value of REDRAWTILES_THRESHOLD
403 if (redraw_mask & REDRAW_TILES)
404 redraw_mask |= REDRAW_FIELD;
408 /* !!! TEST ONLY !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */
409 /* (force full redraw) */
410 if (game_status == GAME_MODE_PLAYING)
411 redraw_mask |= REDRAW_FIELD;
414 if (redraw_mask & REDRAW_FIELD)
415 redraw_mask &= ~REDRAW_TILES;
417 if (redraw_mask == REDRAW_NONE)
422 if (redraw_mask & REDRAW_ALL)
423 printf("[REDRAW_ALL]");
424 if (redraw_mask & REDRAW_FIELD)
425 printf("[REDRAW_FIELD]");
426 if (redraw_mask & REDRAW_TILES)
427 printf("[REDRAW_TILES]");
428 if (redraw_mask & REDRAW_DOOR_1)
429 printf("[REDRAW_DOOR_1]");
430 if (redraw_mask & REDRAW_DOOR_2)
431 printf("[REDRAW_DOOR_2]");
432 if (redraw_mask & REDRAW_FROM_BACKBUFFER)
433 printf("[REDRAW_FROM_BACKBUFFER]");
434 printf(" [%d]\n", FrameCounter);
437 if (redraw_mask & REDRAW_TILES &&
438 game_status == GAME_MODE_PLAYING &&
439 border.draw_masked[GAME_MODE_PLAYING])
440 redraw_mask |= REDRAW_FIELD;
442 if (global.fps_slowdown && game_status == GAME_MODE_PLAYING)
444 static boolean last_frame_skipped = FALSE;
445 boolean skip_even_when_not_scrolling = TRUE;
446 boolean just_scrolling = (ScreenMovDir != 0);
447 boolean verbose = FALSE;
449 if (global.fps_slowdown_factor > 1 &&
450 (FrameCounter % global.fps_slowdown_factor) &&
451 (just_scrolling || skip_even_when_not_scrolling))
453 redraw_mask &= ~REDRAW_MAIN;
455 last_frame_skipped = TRUE;
458 printf("FRAME SKIPPED\n");
462 if (last_frame_skipped)
463 redraw_mask |= REDRAW_FIELD;
465 last_frame_skipped = FALSE;
468 printf("frame not skipped\n");
472 /* synchronize X11 graphics at this point; if we would synchronize the
473 display immediately after the buffer switching (after the XFlush),
474 this could mean that we have to wait for the graphics to complete,
475 although we could go on doing calculations for the next frame */
479 /* never draw masked border to backbuffer when using playfield buffer */
480 if (game_status != GAME_MODE_PLAYING ||
481 redraw_mask & REDRAW_FROM_BACKBUFFER ||
482 buffer == backbuffer)
483 DrawMaskedBorder(redraw_mask);
485 DrawMaskedBorder(redraw_mask & REDRAW_DOORS);
487 if (redraw_mask & REDRAW_ALL)
489 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
491 redraw_mask = REDRAW_NONE;
494 if (redraw_mask & REDRAW_FIELD)
497 printf("::: REDRAW_FIELD\n");
500 if (game_status != GAME_MODE_PLAYING ||
501 redraw_mask & REDRAW_FROM_BACKBUFFER)
503 BlitBitmap(backbuffer, window,
504 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE, REAL_SX, REAL_SY);
509 BlitScreenToBitmap(window);
511 int fx = FX, fy = FY;
514 int dx = (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
515 int dy = (ScreenMovDir & (MV_UP | MV_DOWN) ? ScreenGfxPos : 0);
516 int dx_var = dx * TILESIZE_VAR / TILESIZE;
517 int dy_var = dy * TILESIZE_VAR / TILESIZE;
520 // fx += dx * TILESIZE_VAR / TILESIZE;
521 // fy += dy * TILESIZE_VAR / TILESIZE;
523 fx += (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
524 fy += (ScreenMovDir & (MV_UP | MV_DOWN) ? ScreenGfxPos : 0);
527 /* !!! THIS WORKS !!! */
529 printf("::: %d, %d\n", scroll_x, scroll_y);
531 ffx = (scroll_x - SBX_Left) * TILEX_VAR + dx_var;
532 ffy = (scroll_y - SBY_Upper) * TILEY_VAR + dy_var;
534 if (EVEN(SCR_FIELDX))
536 if (ffx < SBX_Right * TILEX_VAR + TILEX_VAR / 2 + TILEX_VAR)
537 fx += dx_var - MIN(ffx, TILEX_VAR / 2) + TILEX_VAR;
539 fx += (dx > 0 ? TILEX_VAR : 0);
546 if (EVEN(SCR_FIELDY))
548 if (ffy < SBY_Lower * TILEY_VAR + TILEY_VAR / 2 + TILEY_VAR)
549 fy += dy_var - MIN(ffy, TILEY_VAR / 2) + TILEY_VAR;
551 fy += (dy > 0 ? TILEY_VAR : 0);
558 if (border.draw_masked[GAME_MODE_PLAYING])
560 if (buffer != backbuffer)
562 /* copy playfield buffer to backbuffer to add masked border */
563 BlitBitmap(buffer, backbuffer, fx, fy, SXSIZE, SYSIZE, SX, SY);
564 DrawMaskedBorder(REDRAW_FIELD);
567 BlitBitmap(backbuffer, window,
568 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
573 BlitBitmap(buffer, window, fx, fy, SXSIZE, SYSIZE, SX, SY);
579 printf("redrawing all (ScreenGfxPos == %d) because %s\n",
581 (setup.soft_scrolling ?
582 "setup.soft_scrolling" :
583 ABS(ScreenGfxPos) + ScrollStepSize == TILEX ?
584 "ABS(ScreenGfxPos) + ScrollStepSize == TILEX" :
585 ABS(ScreenGfxPos) == ScrollStepSize ?
586 "ABS(ScreenGfxPos) == ScrollStepSize" :
587 "redraw_tiles > REDRAWTILES_THRESHOLD"));
592 redraw_mask &= ~REDRAW_MAIN;
595 if (redraw_mask & REDRAW_DOORS)
597 if (redraw_mask & REDRAW_DOOR_1)
598 BlitBitmap(backbuffer, window, DX, DY, DXSIZE, DYSIZE, DX, DY);
600 if (redraw_mask & REDRAW_DOOR_2)
601 BlitBitmap(backbuffer, window, VX, VY, VXSIZE, VYSIZE, VX, VY);
603 if (redraw_mask & REDRAW_DOOR_3)
604 BlitBitmap(backbuffer, window, EX, EY, EXSIZE, EYSIZE, EX, EY);
606 redraw_mask &= ~REDRAW_DOORS;
609 if (redraw_mask & REDRAW_MICROLEVEL)
611 BlitBitmap(backbuffer, window, SX, SY + 10 * TILEY, SXSIZE, 7 * TILEY,
612 SX, SY + 10 * TILEY);
614 redraw_mask &= ~REDRAW_MICROLEVEL;
617 if (redraw_mask & REDRAW_TILES)
620 printf("::: REDRAW_TILES\n");
626 InitGfxClipRegion(TRUE, SX, SY, SXSIZE, SYSIZE);
629 int sx = SX; // - (EVEN(SCR_FIELDX) ? TILEX_VAR / 2 : 0);
630 int sy = SY; // + (EVEN(SCR_FIELDY) ? TILEY_VAR / 2 : 0);
633 int dx_var = dx * TILESIZE_VAR / TILESIZE;
634 int dy_var = dy * TILESIZE_VAR / TILESIZE;
636 int fx = FX, fy = FY;
638 int scr_fieldx = SCR_FIELDX + (EVEN(SCR_FIELDX) ? 2 : 0);
639 int scr_fieldy = SCR_FIELDY + (EVEN(SCR_FIELDY) ? 2 : 0);
641 ffx = (scroll_x - SBX_Left) * TILEX_VAR + dx_var;
642 ffy = (scroll_y - SBY_Upper) * TILEY_VAR + dy_var;
644 if (EVEN(SCR_FIELDX))
646 if (ffx < SBX_Right * TILEX_VAR + TILEX_VAR / 2 + TILEX_VAR)
648 fx += dx_var - MIN(ffx, TILEX_VAR / 2) + TILEX_VAR;
657 fx += (dx_var > 0 ? TILEX_VAR : 0);
661 if (EVEN(SCR_FIELDY))
663 if (ffy < SBY_Lower * TILEY_VAR + TILEY_VAR / 2 + TILEY_VAR)
665 fy += dy_var - MIN(ffy, TILEY_VAR / 2) + TILEY_VAR;
674 fy += (dy_var > 0 ? TILEY_VAR : 0);
679 printf("::: %d, %d, %d, %d\n", sx, sy, SCR_FIELDX, SCR_FIELDY);
682 for (x = 0; x < scr_fieldx; x++)
683 for (y = 0 ; y < scr_fieldy; y++)
684 if (redraw[redraw_x1 + x][redraw_y1 + y])
685 BlitBitmap(buffer, window,
686 FX + x * TILEX_VAR, FY + y * TILEY_VAR,
687 TILEX_VAR, TILEY_VAR,
688 sx + x * TILEX_VAR, sy + y * TILEY_VAR);
691 InitGfxClipRegion(FALSE, -1, -1, -1, -1);
693 for (x = 0; x < SCR_FIELDX; x++)
694 for (y = 0 ; y < SCR_FIELDY; y++)
695 if (redraw[redraw_x1 + x][redraw_y1 + y])
696 BlitBitmap(buffer, window,
697 FX + x * TILEX_VAR, FY + y * TILEY_VAR,
698 TILEX_VAR, TILEY_VAR,
699 SX + x * TILEX_VAR, SY + y * TILEY_VAR);
703 for (x = 0; x < SCR_FIELDX; x++)
704 for (y = 0 ; y < SCR_FIELDY; y++)
705 if (redraw[redraw_x1 + x][redraw_y1 + y])
706 BlitBitmap(buffer, window,
707 FX + x * TILEX, FY + y * TILEY, TILEX, TILEY,
708 SX + x * TILEX, SY + y * TILEY);
712 if (redraw_mask & REDRAW_FPS) /* display frames per second */
717 sprintf(info1, " (only every %d. frame)", global.fps_slowdown_factor);
718 if (!global.fps_slowdown)
721 sprintf(text, "%04.1f fps%s", global.frames_per_second, info1);
723 DrawTextExt(window, SX + SXSIZE + SX, 0, text, FONT_TEXT_2, BLIT_OPAQUE);
725 DrawTextExt(window, SX, SY, text, FONT_TEXT_2, BLIT_OPAQUE);
731 for (x = 0; x < MAX_BUF_XSIZE; x++)
732 for (y = 0; y < MAX_BUF_YSIZE; y++)
735 redraw_mask = REDRAW_NONE;
738 static void FadeCrossSaveBackbuffer()
740 BlitBitmap(backbuffer, bitmap_db_cross, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
743 static void FadeExt(int fade_mask, int fade_mode, int fade_type)
745 static int fade_type_skip = FADE_TYPE_NONE;
746 void (*draw_border_function)(void) = NULL;
747 Bitmap *bitmap = (fade_mode & FADE_TYPE_TRANSFORM ? bitmap_db_cross : NULL);
748 int x, y, width, height;
749 int fade_delay, post_delay;
751 if (fade_type == FADE_TYPE_FADE_OUT)
753 if (fade_type_skip != FADE_TYPE_NONE)
756 printf("::: skipping %d ... [%d] (X)\n", fade_mode, fade_type_skip);
759 /* skip all fade operations until specified fade operation */
760 if (fade_type & fade_type_skip)
761 fade_type_skip = FADE_TYPE_NONE;
766 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
768 FadeCrossSaveBackbuffer();
774 redraw_mask |= fade_mask;
776 if (fade_type == FADE_TYPE_SKIP)
779 printf("::: will skip %d ... [%d]\n", fade_mode, fade_type_skip);
782 fade_type_skip = fade_mode;
788 printf("::: !!! FADING %d ... [%d] [%d]\n", fade_mode, fade_type,
793 fade_delay = fading.fade_delay;
794 post_delay = (fade_mode == FADE_MODE_FADE_OUT ? fading.post_delay : 0);
797 if (fade_type_skip != FADE_TYPE_NONE)
800 printf("::: skipping %d ... [%d]\n", fade_mode, fade_type_skip);
803 /* skip all fade operations until specified fade operation */
804 if (fade_type & fade_type_skip)
805 fade_type_skip = FADE_TYPE_NONE;
815 if (global.autoplay_leveldir)
817 // fading.fade_mode = FADE_MODE_NONE;
824 if (fading.fade_mode == FADE_MODE_NONE)
832 /* !!! what about fade_mask == REDRAW_FIELD | REDRAW_ALL ??? !!! */
835 printf("::: NOW FADING %d ... [%d]\n", fade_mode, fade_type);
839 if (fade_mask == REDRAW_NONE)
840 fade_mask = REDRAW_FIELD;
843 // if (fade_mask & REDRAW_FIELD)
844 if (fade_mask == REDRAW_FIELD)
849 height = FULL_SYSIZE;
852 fade_delay = fading.fade_delay;
853 post_delay = (fade_mode == FADE_MODE_FADE_OUT ? fading.post_delay : 0);
856 if (border.draw_masked_when_fading)
857 draw_border_function = DrawMaskedBorder_FIELD; /* update when fading */
859 DrawMaskedBorder_FIELD(); /* draw once */
861 else /* REDRAW_ALL */
869 fade_delay = fading.fade_delay;
870 post_delay = (fade_mode == FADE_MODE_FADE_OUT ? fading.post_delay : 0);
875 if (!setup.fade_screens ||
877 fading.fade_mode == FADE_MODE_NONE)
879 if (!setup.fade_screens || fade_delay == 0)
882 if (fade_mode == FADE_MODE_FADE_OUT)
886 if (fade_mode == FADE_MODE_FADE_OUT &&
887 fading.fade_mode != FADE_MODE_NONE)
888 ClearRectangle(backbuffer, x, y, width, height);
892 BlitBitmap(backbuffer, window, x, y, width, height, x, y);
893 redraw_mask = REDRAW_NONE;
901 FadeRectangle(bitmap, x, y, width, height, fade_mode, fade_delay, post_delay,
902 draw_border_function);
904 redraw_mask &= ~fade_mask;
907 void FadeIn(int fade_mask)
909 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
910 FadeExt(fade_mask, fading.fade_mode, FADE_TYPE_FADE_IN);
912 FadeExt(fade_mask, FADE_MODE_FADE_IN, FADE_TYPE_FADE_IN);
915 void FadeOut(int fade_mask)
917 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
918 FadeExt(fade_mask, fading.fade_mode, FADE_TYPE_FADE_OUT);
920 FadeExt(fade_mask, FADE_MODE_FADE_OUT, FADE_TYPE_FADE_OUT);
922 global.border_status = game_status;
925 static void FadeSetLeaveNext(struct TitleFadingInfo fading_leave, boolean set)
927 static struct TitleFadingInfo fading_leave_stored;
930 fading_leave_stored = fading_leave;
932 fading = fading_leave_stored;
935 void FadeSetEnterMenu()
937 fading = menu.enter_menu;
940 printf("::: storing enter_menu\n");
943 FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
946 void FadeSetLeaveMenu()
948 fading = menu.leave_menu;
951 printf("::: storing leave_menu\n");
954 FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
957 void FadeSetEnterScreen()
959 fading = menu.enter_screen[game_status];
962 printf("::: storing leave_screen[%d]\n", game_status);
965 FadeSetLeaveNext(menu.leave_screen[game_status], TRUE); /* store */
968 void FadeSetNextScreen()
970 fading = menu.next_screen;
973 printf("::: storing next_screen\n");
976 // (do not overwrite fade mode set by FadeSetEnterScreen)
977 // FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
980 void FadeSetLeaveScreen()
983 printf("::: recalling last stored value\n");
986 FadeSetLeaveNext(menu.leave_screen[game_status], FALSE); /* recall */
989 void FadeSetFromType(int type)
991 if (type & TYPE_ENTER_SCREEN)
992 FadeSetEnterScreen();
993 else if (type & TYPE_ENTER)
995 else if (type & TYPE_LEAVE)
999 void FadeSetDisabled()
1001 static struct TitleFadingInfo fading_none = { FADE_MODE_NONE, -1, -1, -1 };
1003 fading = fading_none;
1006 void FadeSkipNextFadeIn()
1008 FadeExt(0, FADE_MODE_SKIP_FADE_IN, FADE_TYPE_SKIP);
1011 void FadeSkipNextFadeOut()
1013 FadeExt(0, FADE_MODE_SKIP_FADE_OUT, FADE_TYPE_SKIP);
1016 void SetWindowBackgroundImageIfDefined(int graphic)
1018 if (graphic_info[graphic].bitmap)
1019 SetWindowBackgroundBitmap(graphic_info[graphic].bitmap);
1022 void SetMainBackgroundImageIfDefined(int graphic)
1024 if (graphic_info[graphic].bitmap)
1025 SetMainBackgroundBitmap(graphic_info[graphic].bitmap);
1028 void SetDoorBackgroundImageIfDefined(int graphic)
1030 if (graphic_info[graphic].bitmap)
1031 SetDoorBackgroundBitmap(graphic_info[graphic].bitmap);
1034 void SetWindowBackgroundImage(int graphic)
1036 SetWindowBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
1037 graphic_info[graphic].bitmap ?
1038 graphic_info[graphic].bitmap :
1039 graphic_info[IMG_BACKGROUND].bitmap);
1042 void SetMainBackgroundImage(int graphic)
1044 SetMainBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
1045 graphic_info[graphic].bitmap ?
1046 graphic_info[graphic].bitmap :
1047 graphic_info[IMG_BACKGROUND].bitmap);
1050 void SetDoorBackgroundImage(int graphic)
1052 SetDoorBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
1053 graphic_info[graphic].bitmap ?
1054 graphic_info[graphic].bitmap :
1055 graphic_info[IMG_BACKGROUND].bitmap);
1058 void SetPanelBackground()
1061 struct GraphicInfo *gfx = &graphic_info[IMG_BACKGROUND_PANEL];
1064 BlitBitmapTiled(gfx->bitmap, bitmap_db_panel, gfx->src_x, gfx->src_y,
1065 gfx->width, gfx->height, 0, 0, DXSIZE, DYSIZE);
1067 /* (ClearRectangle() only needed if panel bitmap is smaller than panel) */
1068 ClearRectangle(bitmap_db_panel, DX, DY, DXSIZE, DYSIZE);
1069 BlitBitmap(gfx->bitmap, bitmap_db_panel, gfx->src_x, gfx->src_y,
1070 MIN(gfx->width, DXSIZE), MIN(gfx->height, DYSIZE), 0, 0);
1073 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, bitmap_db_panel,
1074 DOOR_GFX_PAGEX5, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE, 0, 0);
1077 SetDoorBackgroundBitmap(bitmap_db_panel);
1080 void DrawBackground(int x, int y, int width, int height)
1082 /* !!! "drawto" might still point to playfield buffer here (see below) !!! */
1083 /* (when entering hall of fame after playing) */
1085 ClearRectangleOnBackground(drawto, x, y, width, height);
1087 ClearRectangleOnBackground(backbuffer, x, y, width, height);
1091 /* (this only works for the current arrangement of playfield and panels) */
1093 redraw_mask |= REDRAW_FIELD;
1094 else if (y < gfx.vy)
1095 redraw_mask |= REDRAW_DOOR_1;
1097 redraw_mask |= REDRAW_DOOR_2;
1099 /* (this is just wrong (when drawing to one of the two door panel areas)) */
1100 redraw_mask |= REDRAW_FIELD;
1104 void DrawBackgroundForFont(int x, int y, int width, int height, int font_nr)
1106 struct FontBitmapInfo *font = getFontBitmapInfo(font_nr);
1108 if (font->bitmap == NULL)
1111 DrawBackground(x, y, width, height);
1114 void DrawBackgroundForGraphic(int x, int y, int width, int height, int graphic)
1116 struct GraphicInfo *g = &graphic_info[graphic];
1118 if (g->bitmap == NULL)
1121 DrawBackground(x, y, width, height);
1126 /* !!! "drawto" might still point to playfield buffer here (see above) !!! */
1127 /* (when entering hall of fame after playing) */
1128 DrawBackground(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
1130 /* !!! maybe this should be done before clearing the background !!! */
1131 if (setup.soft_scrolling && game_status == GAME_MODE_PLAYING)
1133 ClearRectangle(fieldbuffer, 0, 0, FXSIZE, FYSIZE);
1134 SetDrawtoField(DRAW_BUFFERED);
1137 SetDrawtoField(DRAW_BACKBUFFER);
1140 void MarkTileDirty(int x, int y)
1142 int xx = redraw_x1 + x;
1143 int yy = redraw_y1 + y;
1145 if (!redraw[xx][yy])
1148 redraw[xx][yy] = TRUE;
1149 redraw_mask |= REDRAW_TILES;
1152 void SetBorderElement()
1156 BorderElement = EL_EMPTY;
1158 for (y = 0; y < lev_fieldy && BorderElement == EL_EMPTY; y++)
1160 for (x = 0; x < lev_fieldx; x++)
1162 if (!IS_INDESTRUCTIBLE(Feld[x][y]))
1163 BorderElement = EL_STEELWALL;
1165 if (y != 0 && y != lev_fieldy - 1 && x != lev_fieldx - 1)
1171 void FloodFillLevel(int from_x, int from_y, int fill_element,
1172 short field[MAX_LEV_FIELDX][MAX_LEV_FIELDY],
1173 int max_fieldx, int max_fieldy)
1177 static int check[4][2] = { { -1, 0 }, { 0, -1 }, { 1, 0 }, { 0, 1 } };
1178 static int safety = 0;
1180 /* check if starting field still has the desired content */
1181 if (field[from_x][from_y] == fill_element)
1186 if (safety > max_fieldx * max_fieldy)
1187 Error(ERR_EXIT, "Something went wrong in 'FloodFill()'. Please debug.");
1189 old_element = field[from_x][from_y];
1190 field[from_x][from_y] = fill_element;
1192 for (i = 0; i < 4; i++)
1194 x = from_x + check[i][0];
1195 y = from_y + check[i][1];
1197 if (IN_FIELD(x, y, max_fieldx, max_fieldy) && field[x][y] == old_element)
1198 FloodFillLevel(x, y, fill_element, field, max_fieldx, max_fieldy);
1204 void SetRandomAnimationValue(int x, int y)
1206 gfx.anim_random_frame = GfxRandom[x][y];
1209 inline int getGraphicAnimationFrame(int graphic, int sync_frame)
1211 /* animation synchronized with global frame counter, not move position */
1212 if (graphic_info[graphic].anim_global_sync || sync_frame < 0)
1213 sync_frame = FrameCounter;
1215 return getAnimationFrame(graphic_info[graphic].anim_frames,
1216 graphic_info[graphic].anim_delay,
1217 graphic_info[graphic].anim_mode,
1218 graphic_info[graphic].anim_start_frame,
1222 void getSizedGraphicSourceExt(int graphic, int frame, int tilesize_raw,
1223 Bitmap **bitmap, int *x, int *y,
1224 boolean get_backside)
1228 int width_mult, width_div;
1229 int height_mult, height_div;
1233 { 15, 16, 2, 3 }, /* 1 x 1 */
1234 { 7, 8, 2, 3 }, /* 2 x 2 */
1235 { 3, 4, 2, 3 }, /* 4 x 4 */
1236 { 1, 2, 2, 3 }, /* 8 x 8 */
1237 { 0, 1, 2, 3 }, /* 16 x 16 */
1238 { 0, 1, 0, 1 }, /* 32 x 32 */
1240 struct GraphicInfo *g = &graphic_info[graphic];
1241 Bitmap *src_bitmap = g->bitmap;
1242 int tilesize = MIN(MAX(1, tilesize_raw), TILESIZE);
1243 int offset_calc_pos = log_2(tilesize);
1244 int width_mult = offset_calc[offset_calc_pos].width_mult;
1245 int width_div = offset_calc[offset_calc_pos].width_div;
1246 int height_mult = offset_calc[offset_calc_pos].height_mult;
1247 int height_div = offset_calc[offset_calc_pos].height_div;
1248 int startx = src_bitmap->width * width_mult / width_div;
1249 int starty = src_bitmap->height * height_mult / height_div;
1251 int src_x = (g->src_x + (get_backside ? g->offset2_x : 0)) *
1252 tilesize / TILESIZE;
1253 int src_y = (g->src_y + (get_backside ? g->offset2_y : 0)) *
1254 tilesize / TILESIZE;
1256 int src_x = g->src_x * tilesize / TILESIZE;
1257 int src_y = g->src_y * tilesize / TILESIZE;
1259 int width = g->width * tilesize / TILESIZE;
1260 int height = g->height * tilesize / TILESIZE;
1261 int offset_x = g->offset_x * tilesize / TILESIZE;
1262 int offset_y = g->offset_y * tilesize / TILESIZE;
1264 if (g->offset_y == 0) /* frames are ordered horizontally */
1266 int max_width = g->anim_frames_per_line * width;
1267 int pos = (src_y / height) * max_width + src_x + frame * offset_x;
1269 src_x = pos % max_width;
1270 src_y = src_y % height + pos / max_width * height;
1272 else if (g->offset_x == 0) /* frames are ordered vertically */
1274 int max_height = g->anim_frames_per_line * height;
1275 int pos = (src_x / width) * max_height + src_y + frame * offset_y;
1277 src_x = src_x % width + pos / max_height * width;
1278 src_y = pos % max_height;
1280 else /* frames are ordered diagonally */
1282 src_x = src_x + frame * offset_x;
1283 src_y = src_y + frame * offset_y;
1286 *bitmap = src_bitmap;
1287 *x = startx + src_x;
1288 *y = starty + src_y;
1291 void getFixedGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
1292 int *x, int *y, boolean get_backside)
1294 getSizedGraphicSourceExt(graphic, frame, TILESIZE, bitmap, x, y,
1298 void getSizedGraphicSource(int graphic, int frame, int tilesize_raw,
1299 Bitmap **bitmap, int *x, int *y)
1301 getSizedGraphicSourceExt(graphic, frame, tilesize_raw, bitmap, x, y, FALSE);
1304 void getFixedGraphicSource(int graphic, int frame,
1305 Bitmap **bitmap, int *x, int *y)
1307 getSizedGraphicSourceExt(graphic, frame, TILESIZE, bitmap, x, y, FALSE);
1310 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
1313 getSizedGraphicSource(graphic, 0, MINI_TILESIZE, bitmap, x, y);
1315 struct GraphicInfo *g = &graphic_info[graphic];
1316 int mini_startx = 0;
1317 int mini_starty = g->bitmap->height * 2 / 3;
1319 *bitmap = g->bitmap;
1320 *x = mini_startx + g->src_x / 2;
1321 *y = mini_starty + g->src_y / 2;
1325 inline void getGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
1326 int *x, int *y, boolean get_backside)
1328 struct GraphicInfo *g = &graphic_info[graphic];
1329 int src_x = g->src_x + (get_backside ? g->offset2_x : 0);
1330 int src_y = g->src_y + (get_backside ? g->offset2_y : 0);
1333 if (TILESIZE_VAR != TILESIZE)
1334 return getSizedGraphicSourceExt(graphic, frame, TILESIZE_VAR, bitmap, x, y,
1338 *bitmap = g->bitmap;
1340 if (g->offset_y == 0) /* frames are ordered horizontally */
1342 int max_width = g->anim_frames_per_line * g->width;
1343 int pos = (src_y / g->height) * max_width + src_x + frame * g->offset_x;
1345 *x = pos % max_width;
1346 *y = src_y % g->height + pos / max_width * g->height;
1348 else if (g->offset_x == 0) /* frames are ordered vertically */
1350 int max_height = g->anim_frames_per_line * g->height;
1351 int pos = (src_x / g->width) * max_height + src_y + frame * g->offset_y;
1353 *x = src_x % g->width + pos / max_height * g->width;
1354 *y = pos % max_height;
1356 else /* frames are ordered diagonally */
1358 *x = src_x + frame * g->offset_x;
1359 *y = src_y + frame * g->offset_y;
1363 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
1365 getGraphicSourceExt(graphic, frame, bitmap, x, y, FALSE);
1368 void DrawGraphic(int x, int y, int graphic, int frame)
1371 if (!IN_SCR_FIELD(x, y))
1373 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
1374 printf("DrawGraphic(): This should never happen!\n");
1380 DrawGraphicExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR, graphic,
1383 DrawGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic, frame);
1385 MarkTileDirty(x, y);
1388 void DrawFixedGraphic(int x, int y, int graphic, int frame)
1391 if (!IN_SCR_FIELD(x, y))
1393 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
1394 printf("DrawGraphic(): This should never happen!\n");
1399 DrawFixedGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic,
1401 MarkTileDirty(x, y);
1404 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
1410 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1412 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX_VAR, TILEY_VAR, x, y);
1414 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
1418 void DrawFixedGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
1424 getFixedGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1425 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
1428 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
1431 if (!IN_SCR_FIELD(x, y))
1433 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
1434 printf("DrawGraphicThruMask(): This should never happen!\n");
1440 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR,
1443 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic,
1446 MarkTileDirty(x, y);
1449 void DrawFixedGraphicThruMask(int x, int y, int graphic, int frame)
1452 if (!IN_SCR_FIELD(x, y))
1454 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
1455 printf("DrawGraphicThruMask(): This should never happen!\n");
1460 DrawFixedGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
1462 MarkTileDirty(x, y);
1465 void DrawGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y, int graphic,
1471 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1473 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1474 dst_x - src_x, dst_y - src_y);
1476 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX_VAR, TILEY_VAR,
1479 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dst_x, dst_y);
1483 void DrawFixedGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y,
1484 int graphic, int frame)
1489 getFixedGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1491 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1492 dst_x - src_x, dst_y - src_y);
1493 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dst_x, dst_y);
1496 void DrawSizedGraphic(int x, int y, int graphic, int frame, int tilesize)
1498 DrawSizedGraphicExt(drawto, SX + x * tilesize, SY + y * tilesize, graphic,
1500 MarkTileDirty(x / tilesize, y / tilesize);
1503 void DrawSizedGraphicExt(DrawBuffer *d, int x, int y, int graphic, int frame,
1509 getSizedGraphicSource(graphic, frame, tilesize, &src_bitmap, &src_x, &src_y);
1510 BlitBitmap(src_bitmap, d, src_x, src_y, tilesize, tilesize, x, y);
1513 void DrawMiniGraphic(int x, int y, int graphic)
1515 DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
1516 MarkTileDirty(x / 2, y / 2);
1519 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
1524 getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1525 BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
1528 inline static void DrawGraphicShiftedNormal(int x, int y, int dx, int dy,
1529 int graphic, int frame,
1530 int cut_mode, int mask_mode)
1535 int width = TILEX, height = TILEY;
1538 if (dx || dy) /* shifted graphic */
1540 if (x < BX1) /* object enters playfield from the left */
1547 else if (x > BX2) /* object enters playfield from the right */
1553 else if (x==BX1 && dx < 0) /* object leaves playfield to the left */
1559 else if (x==BX2 && dx > 0) /* object leaves playfield to the right */
1561 else if (dx) /* general horizontal movement */
1562 MarkTileDirty(x + SIGN(dx), y);
1564 if (y < BY1) /* object enters playfield from the top */
1566 if (cut_mode==CUT_BELOW) /* object completely above top border */
1574 else if (y > BY2) /* object enters playfield from the bottom */
1580 else if (y==BY1 && dy < 0) /* object leaves playfield to the top */
1586 else if (dy > 0 && cut_mode == CUT_ABOVE)
1588 if (y == BY2) /* object completely above bottom border */
1594 MarkTileDirty(x, y + 1);
1595 } /* object leaves playfield to the bottom */
1596 else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
1598 else if (dy) /* general vertical movement */
1599 MarkTileDirty(x, y + SIGN(dy));
1603 if (!IN_SCR_FIELD(x, y))
1605 printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
1606 printf("DrawGraphicShifted(): This should never happen!\n");
1612 width = width * TILESIZE_VAR / TILESIZE;
1613 height = height * TILESIZE_VAR / TILESIZE;
1614 cx = cx * TILESIZE_VAR / TILESIZE;
1615 cy = cy * TILESIZE_VAR / TILESIZE;
1616 dx = dx * TILESIZE_VAR / TILESIZE;
1617 dy = dy * TILESIZE_VAR / TILESIZE;
1620 if (width > 0 && height > 0)
1622 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1628 dst_x = FX + x * TILEX_VAR + dx;
1629 dst_y = FY + y * TILEY_VAR + dy;
1631 dst_x = FX + x * TILEX + dx;
1632 dst_y = FY + y * TILEY + dy;
1635 if (mask_mode == USE_MASKING)
1637 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1638 dst_x - src_x, dst_y - src_y);
1639 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1643 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1646 MarkTileDirty(x, y);
1650 inline static void DrawGraphicShiftedDouble(int x, int y, int dx, int dy,
1651 int graphic, int frame,
1652 int cut_mode, int mask_mode)
1658 int width = TILEX_VAR, height = TILEY_VAR;
1660 int width = TILEX, height = TILEY;
1664 int x2 = x + SIGN(dx);
1665 int y2 = y + SIGN(dy);
1667 /* !!! DOES NOT WORK FOR SLOW MOVEMENT !!! */
1668 int sync_frame = GfxFrame[LEVELX(x)][LEVELY(y)];
1670 /* movement with two-tile animations must be sync'ed with movement position,
1671 not with current GfxFrame (which can be higher when using slow movement) */
1672 int anim_pos = (dx ? ABS(dx) : ABS(dy));
1673 int anim_frames = graphic_info[graphic].anim_frames;
1675 /* (we also need anim_delay here for movement animations with less frames) */
1676 int anim_delay = graphic_info[graphic].anim_delay;
1677 int sync_frame = anim_pos * anim_frames * anim_delay / TILESIZE;
1679 int sync_frame = anim_pos * anim_frames / TILESIZE;
1682 boolean draw_start_tile = (cut_mode != CUT_ABOVE); /* only for falling! */
1683 boolean draw_end_tile = (cut_mode != CUT_BELOW); /* only for falling! */
1685 /* re-calculate animation frame for two-tile movement animation */
1686 frame = getGraphicAnimationFrame(graphic, sync_frame);
1690 printf("::: %d, %d, %d => %d [%d]\n",
1691 anim_pos, anim_frames, anim_delay, sync_frame, graphic);
1693 printf("::: %d, %d => %d\n",
1694 anim_pos, anim_frames, sync_frame);
1699 printf("::: %d [%d, %d] [%d] [%d]\n", frame, sync_frame, dy,
1700 GfxFrame[LEVELX(x)][LEVELY(y)], mask_mode);
1703 /* check if movement start graphic inside screen area and should be drawn */
1704 if (draw_start_tile && IN_SCR_FIELD(x1, y1))
1706 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, TRUE);
1709 dst_x = FX + x1 * TILEX_VAR;
1710 dst_y = FY + y1 * TILEY_VAR;
1712 dst_x = FX + x1 * TILEX;
1713 dst_y = FY + y1 * TILEY;
1716 if (mask_mode == USE_MASKING)
1718 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1719 dst_x - src_x, dst_y - src_y);
1720 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1724 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1727 MarkTileDirty(x1, y1);
1730 /* check if movement end graphic inside screen area and should be drawn */
1731 if (draw_end_tile && IN_SCR_FIELD(x2, y2))
1733 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
1736 dst_x = FX + x2 * TILEX_VAR;
1737 dst_y = FY + y2 * TILEY_VAR;
1739 dst_x = FX + x2 * TILEX;
1740 dst_y = FY + y2 * TILEY;
1743 if (mask_mode == USE_MASKING)
1745 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1746 dst_x - src_x, dst_y - src_y);
1747 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1751 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1754 MarkTileDirty(x2, y2);
1758 static void DrawGraphicShifted(int x, int y, int dx, int dy,
1759 int graphic, int frame,
1760 int cut_mode, int mask_mode)
1764 DrawGraphic(x, y, graphic, frame);
1769 if (graphic_info[graphic].double_movement) /* EM style movement images */
1770 DrawGraphicShiftedDouble(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1772 DrawGraphicShiftedNormal(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1775 void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
1776 int frame, int cut_mode)
1778 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, USE_MASKING);
1781 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
1782 int cut_mode, int mask_mode)
1784 int lx = LEVELX(x), ly = LEVELY(y);
1788 if (IN_LEV_FIELD(lx, ly))
1790 SetRandomAnimationValue(lx, ly);
1792 graphic = el_act_dir2img(element, GfxAction[lx][ly], GfxDir[lx][ly]);
1793 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1795 /* do not use double (EM style) movement graphic when not moving */
1796 if (graphic_info[graphic].double_movement && !dx && !dy)
1798 graphic = el_act_dir2img(element, ACTION_DEFAULT, GfxDir[lx][ly]);
1799 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1802 else /* border element */
1804 graphic = el2img(element);
1805 frame = getGraphicAnimationFrame(graphic, -1);
1808 if (element == EL_EXPANDABLE_WALL)
1810 boolean left_stopped = FALSE, right_stopped = FALSE;
1812 if (!IN_LEV_FIELD(lx - 1, ly) || IS_WALL(Feld[lx - 1][ly]))
1813 left_stopped = TRUE;
1814 if (!IN_LEV_FIELD(lx + 1, ly) || IS_WALL(Feld[lx + 1][ly]))
1815 right_stopped = TRUE;
1817 if (left_stopped && right_stopped)
1819 else if (left_stopped)
1821 graphic = IMG_EXPANDABLE_WALL_GROWING_RIGHT;
1822 frame = graphic_info[graphic].anim_frames - 1;
1824 else if (right_stopped)
1826 graphic = IMG_EXPANDABLE_WALL_GROWING_LEFT;
1827 frame = graphic_info[graphic].anim_frames - 1;
1832 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
1833 else if (mask_mode == USE_MASKING)
1834 DrawGraphicThruMask(x, y, graphic, frame);
1836 DrawGraphic(x, y, graphic, frame);
1839 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
1840 int cut_mode, int mask_mode)
1842 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1843 DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
1844 cut_mode, mask_mode);
1847 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
1850 DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1853 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
1856 DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1859 void DrawLevelElementThruMask(int x, int y, int element)
1861 DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1864 void DrawLevelFieldThruMask(int x, int y)
1866 DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
1869 /* !!! implementation of quicksand is totally broken !!! */
1870 #define IS_CRUMBLED_TILE(x, y, e) \
1871 (GFX_CRUMBLED(e) && (!IN_LEV_FIELD(x, y) || \
1872 !IS_MOVING(x, y) || \
1873 (e) == EL_QUICKSAND_EMPTYING || \
1874 (e) == EL_QUICKSAND_FAST_EMPTYING))
1876 static void DrawLevelFieldCrumbledInnerCorners(int x, int y, int dx, int dy,
1881 int width, height, cx, cy;
1882 int sx = SCREENX(x), sy = SCREENY(y);
1883 int crumbled_border_size = graphic_info[graphic].border_size;
1886 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1888 for (i = 1; i < 4; i++)
1890 int dxx = (i & 1 ? dx : 0);
1891 int dyy = (i & 2 ? dy : 0);
1894 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1897 /* check if neighbour field is of same crumble type */
1898 boolean same = (IS_CRUMBLED_TILE(xx, yy, element) &&
1899 graphic_info[graphic].class ==
1900 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class);
1902 /* return if check prevents inner corner */
1903 if (same == (dxx == dx && dyy == dy))
1907 /* if we reach this point, we have an inner corner */
1909 getGraphicSource(graphic, 1, &src_bitmap, &src_x, &src_y);
1912 width = crumbled_border_size * TILESIZE_VAR / TILESIZE;
1913 height = crumbled_border_size * TILESIZE_VAR / TILESIZE;
1914 cx = (dx > 0 ? TILEX - crumbled_border_size : 0) * TILESIZE_VAR / TILESIZE;
1915 cy = (dy > 0 ? TILEY - crumbled_border_size : 0) * TILESIZE_VAR / TILESIZE;
1917 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1918 width, height, FX + sx * TILEX_VAR + cx, FY + sy * TILEY_VAR + cy);
1920 width = crumbled_border_size;
1921 height = crumbled_border_size;
1922 cx = (dx > 0 ? TILEX - crumbled_border_size : 0);
1923 cy = (dy > 0 ? TILEY - crumbled_border_size : 0);
1925 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1926 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
1930 static void DrawLevelFieldCrumbledBorders(int x, int y, int graphic, int frame,
1935 int width, height, bx, by, cx, cy;
1936 int sx = SCREENX(x), sy = SCREENY(y);
1937 int crumbled_border_size = graphic_info[graphic].border_size;
1940 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1942 /* draw simple, sloppy, non-corner-accurate crumbled border */
1945 width = (dir == 1 || dir == 2 ? crumbled_border_size : TILEX);
1946 height = (dir == 0 || dir == 3 ? crumbled_border_size : TILEY);
1947 cx = (dir == 2 ? TILEX - crumbled_border_size : 0);
1948 cy = (dir == 3 ? TILEY - crumbled_border_size : 0);
1950 if (dir == 1 || dir == 2) /* left or right crumbled border */
1952 width = crumbled_border_size;
1954 cx = (dir == 2 ? TILEX - crumbled_border_size : 0);
1957 else /* top or bottom crumbled border */
1960 height = crumbled_border_size;
1962 cy = (dir == 3 ? TILEY - crumbled_border_size : 0);
1967 BlitBitmap(src_bitmap, drawto_field,
1968 src_x + cx * TILESIZE_VAR / TILESIZE,
1969 src_y + cy * TILESIZE_VAR / TILESIZE,
1970 width * TILESIZE_VAR / TILESIZE,
1971 height * TILESIZE_VAR / TILESIZE,
1972 FX + sx * TILEX_VAR + cx * TILESIZE_VAR / TILESIZE,
1973 FY + sy * TILEY_VAR + cy * TILESIZE_VAR / TILESIZE);
1975 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1976 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
1979 /* (remaining middle border part must be at least as big as corner part) */
1980 if (!(graphic_info[graphic].style & STYLE_ACCURATE_BORDERS) ||
1981 crumbled_border_size >= TILESIZE / 3)
1984 /* correct corners of crumbled border, if needed */
1987 for (i = -1; i <= 1; i+=2)
1989 int xx = x + (dir == 0 || dir == 3 ? i : 0);
1990 int yy = y + (dir == 1 || dir == 2 ? i : 0);
1991 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1994 /* check if neighbour field is of same crumble type */
1995 if (IS_CRUMBLED_TILE(xx, yy, element) &&
1996 graphic_info[graphic].class ==
1997 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
1999 /* no crumbled corner, but continued crumbled border */
2001 int c1 = (dir == 2 || dir == 3 ? TILESIZE - crumbled_border_size : 0);
2002 int c2 = (i == 1 ? TILESIZE - crumbled_border_size : 0);
2003 int b1 = (i == 1 ? crumbled_border_size :
2004 TILESIZE - 2 * crumbled_border_size);
2006 width = crumbled_border_size;
2007 height = crumbled_border_size;
2009 if (dir == 1 || dir == 2)
2025 BlitBitmap(src_bitmap, drawto_field,
2026 src_x + bx * TILESIZE_VAR / TILESIZE,
2027 src_y + by * TILESIZE_VAR / TILESIZE,
2028 width * TILESIZE_VAR / TILESIZE,
2029 height * TILESIZE_VAR / TILESIZE,
2030 FX + sx * TILEX_VAR + cx * TILESIZE_VAR / TILESIZE,
2031 FY + sy * TILEY_VAR + cy * TILESIZE_VAR / TILESIZE);
2033 BlitBitmap(src_bitmap, drawto_field, src_x + bx, src_y + by,
2034 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
2039 if (dir == 1 || dir == 2) /* left or right crumbled border */
2041 for (i = -1; i <= 1; i+=2)
2045 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
2048 /* check if neighbour field is of same crumble type */
2049 if (IS_CRUMBLED_TILE(xx, yy, element) &&
2050 graphic_info[graphic].class ==
2051 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
2053 /* no crumbled corner, but continued crumbled border */
2055 width = crumbled_border_size;
2056 height = crumbled_border_size;
2057 cx = (dir == 2 ? TILEX - crumbled_border_size : 0);
2058 cy = (i == 1 ? TILEY - crumbled_border_size : 0);
2060 by = (i == 1 ? crumbled_border_size :
2061 TILEY - 2 * crumbled_border_size);
2063 BlitBitmap(src_bitmap, drawto_field, src_x + bx, src_y + by,
2064 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
2068 else /* top or bottom crumbled border */
2070 for (i = -1; i <= 1; i+=2)
2074 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
2077 /* check if neighbour field is of same crumble type */
2078 if (IS_CRUMBLED_TILE(xx, yy, element) &&
2079 graphic_info[graphic].class ==
2080 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
2082 /* no crumbled corner, but continued crumbled border */
2084 width = crumbled_border_size;
2085 height = crumbled_border_size;
2086 cx = (i == 1 ? TILEX - crumbled_border_size : 0);
2087 cy = (dir == 3 ? TILEY - crumbled_border_size : 0);
2088 bx = (i == 1 ? crumbled_border_size :
2089 TILEX - 2 * crumbled_border_size);
2092 BlitBitmap(src_bitmap, drawto_field, src_x + bx, src_y + by,
2093 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
2100 static void DrawLevelFieldCrumbledExt(int x, int y, int graphic, int frame)
2102 int sx = SCREENX(x), sy = SCREENY(y);
2105 static int xy[4][2] =
2113 if (!IN_LEV_FIELD(x, y))
2116 element = TILE_GFX_ELEMENT(x, y);
2118 /* crumble field itself */
2119 if (IS_CRUMBLED_TILE(x, y, element))
2121 if (!IN_SCR_FIELD(sx, sy))
2124 for (i = 0; i < 4; i++)
2126 int xx = x + xy[i][0];
2127 int yy = y + xy[i][1];
2129 element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
2132 /* check if neighbour field is of same crumble type */
2134 if (IS_CRUMBLED_TILE(xx, yy, element) &&
2135 graphic_info[graphic].class ==
2136 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
2139 if (IS_CRUMBLED_TILE(xx, yy, element))
2143 DrawLevelFieldCrumbledBorders(x, y, graphic, frame, i);
2146 if ((graphic_info[graphic].style & STYLE_INNER_CORNERS) &&
2147 graphic_info[graphic].anim_frames == 2)
2149 for (i = 0; i < 4; i++)
2151 int dx = (i & 1 ? +1 : -1);
2152 int dy = (i & 2 ? +1 : -1);
2154 DrawLevelFieldCrumbledInnerCorners(x, y, dx, dy, graphic);
2158 MarkTileDirty(sx, sy);
2160 else /* center field not crumbled -- crumble neighbour fields */
2162 for (i = 0; i < 4; i++)
2164 int xx = x + xy[i][0];
2165 int yy = y + xy[i][1];
2166 int sxx = sx + xy[i][0];
2167 int syy = sy + xy[i][1];
2169 if (!IN_LEV_FIELD(xx, yy) ||
2170 !IN_SCR_FIELD(sxx, syy))
2173 if (Feld[xx][yy] == EL_ELEMENT_SNAPPING)
2176 element = TILE_GFX_ELEMENT(xx, yy);
2178 if (!IS_CRUMBLED_TILE(xx, yy, element))
2181 graphic = el_act2crm(element, ACTION_DEFAULT);
2183 DrawLevelFieldCrumbledBorders(xx, yy, graphic, 0, 3 - i);
2185 MarkTileDirty(sxx, syy);
2190 void DrawLevelFieldCrumbled(int x, int y)
2194 if (!IN_LEV_FIELD(x, y))
2198 /* !!! CHECK THIS !!! */
2201 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
2202 GFX_CRUMBLED(GfxElement[x][y]))
2205 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
2206 GfxElement[x][y] != EL_UNDEFINED &&
2207 GFX_CRUMBLED(GfxElement[x][y]))
2209 DrawLevelFieldCrumbledDigging(x, y, GfxDir[x][y], GfxFrame[x][y]);
2216 graphic = el_act2crm(TILE_GFX_ELEMENT(x, y), ACTION_DEFAULT);
2218 graphic = el_act2crm(Feld[x][y], ACTION_DEFAULT);
2221 DrawLevelFieldCrumbledExt(x, y, graphic, 0);
2224 void DrawLevelFieldCrumbledDigging(int x, int y, int direction,
2227 int graphic1 = el_act_dir2img(GfxElement[x][y], ACTION_DIGGING, direction);
2228 int graphic2 = el_act_dir2crm(GfxElement[x][y], ACTION_DIGGING, direction);
2229 int frame1 = getGraphicAnimationFrame(graphic1, step_frame);
2230 int frame2 = getGraphicAnimationFrame(graphic2, step_frame);
2231 int sx = SCREENX(x), sy = SCREENY(y);
2233 DrawGraphic(sx, sy, graphic1, frame1);
2234 DrawLevelFieldCrumbledExt(x, y, graphic2, frame2);
2237 void DrawLevelFieldCrumbledNeighbours(int x, int y)
2239 int sx = SCREENX(x), sy = SCREENY(y);
2240 static int xy[4][2] =
2249 for (i = 0; i < 4; i++)
2251 int xx = x + xy[i][0];
2252 int yy = y + xy[i][1];
2253 int sxx = sx + xy[i][0];
2254 int syy = sy + xy[i][1];
2256 if (!IN_LEV_FIELD(xx, yy) ||
2257 !IN_SCR_FIELD(sxx, syy) ||
2258 !GFX_CRUMBLED(Feld[xx][yy]) ||
2262 DrawLevelField(xx, yy);
2266 static int getBorderElement(int x, int y)
2270 { EL_STEELWALL_TOPLEFT, EL_INVISIBLE_STEELWALL_TOPLEFT },
2271 { EL_STEELWALL_TOPRIGHT, EL_INVISIBLE_STEELWALL_TOPRIGHT },
2272 { EL_STEELWALL_BOTTOMLEFT, EL_INVISIBLE_STEELWALL_BOTTOMLEFT },
2273 { EL_STEELWALL_BOTTOMRIGHT, EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
2274 { EL_STEELWALL_VERTICAL, EL_INVISIBLE_STEELWALL_VERTICAL },
2275 { EL_STEELWALL_HORIZONTAL, EL_INVISIBLE_STEELWALL_HORIZONTAL },
2276 { EL_STEELWALL, EL_INVISIBLE_STEELWALL }
2278 int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
2279 int steel_position = (x == -1 && y == -1 ? 0 :
2280 x == lev_fieldx && y == -1 ? 1 :
2281 x == -1 && y == lev_fieldy ? 2 :
2282 x == lev_fieldx && y == lev_fieldy ? 3 :
2283 x == -1 || x == lev_fieldx ? 4 :
2284 y == -1 || y == lev_fieldy ? 5 : 6);
2286 return border[steel_position][steel_type];
2289 void DrawScreenElement(int x, int y, int element)
2291 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
2292 DrawLevelFieldCrumbled(LEVELX(x), LEVELY(y));
2295 void DrawLevelElement(int x, int y, int element)
2297 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
2298 DrawScreenElement(SCREENX(x), SCREENY(y), element);
2301 void DrawScreenField(int x, int y)
2303 int lx = LEVELX(x), ly = LEVELY(y);
2304 int element, content;
2306 if (!IN_LEV_FIELD(lx, ly))
2308 if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
2311 element = getBorderElement(lx, ly);
2313 DrawScreenElement(x, y, element);
2318 element = Feld[lx][ly];
2319 content = Store[lx][ly];
2321 if (IS_MOVING(lx, ly))
2323 int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
2324 boolean cut_mode = NO_CUTTING;
2326 if (element == EL_QUICKSAND_EMPTYING ||
2327 element == EL_QUICKSAND_FAST_EMPTYING ||
2328 element == EL_MAGIC_WALL_EMPTYING ||
2329 element == EL_BD_MAGIC_WALL_EMPTYING ||
2330 element == EL_DC_MAGIC_WALL_EMPTYING ||
2331 element == EL_AMOEBA_DROPPING)
2332 cut_mode = CUT_ABOVE;
2333 else if (element == EL_QUICKSAND_FILLING ||
2334 element == EL_QUICKSAND_FAST_FILLING ||
2335 element == EL_MAGIC_WALL_FILLING ||
2336 element == EL_BD_MAGIC_WALL_FILLING ||
2337 element == EL_DC_MAGIC_WALL_FILLING)
2338 cut_mode = CUT_BELOW;
2341 if (lx == 9 && ly == 1)
2342 printf("::: %s [%d] [%d, %d] [%d]\n",
2343 EL_NAME(TILE_GFX_ELEMENT(lx, ly)),
2344 el_act2crm(TILE_GFX_ELEMENT(lx, ly), ACTION_DEFAULT),
2345 element_info[EL_QUICKSAND_EMPTYING].graphic[ACTION_DEFAULT],
2346 element_info[EL_QUICKSAND_EMPTYING].crumbled[ACTION_DEFAULT],
2347 GFX_CRUMBLED(TILE_GFX_ELEMENT(lx, ly)));
2350 if (cut_mode == CUT_ABOVE)
2352 DrawScreenElement(x, y, element);
2354 DrawScreenElementShifted(x, y, 0, 0, element, NO_CUTTING);
2357 DrawScreenElement(x, y, EL_EMPTY);
2360 DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
2361 else if (cut_mode == NO_CUTTING)
2362 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
2365 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
2368 if (cut_mode == CUT_BELOW &&
2369 IN_LEV_FIELD(lx, ly + 1) && IN_SCR_FIELD(x, y + 1))
2370 DrawLevelElement(lx, ly + 1, element);
2374 if (content == EL_ACID)
2376 int dir = MovDir[lx][ly];
2377 int newlx = lx + (dir == MV_LEFT ? -1 : dir == MV_RIGHT ? +1 : 0);
2378 int newly = ly + (dir == MV_UP ? -1 : dir == MV_DOWN ? +1 : 0);
2380 DrawLevelElementThruMask(newlx, newly, EL_ACID);
2383 else if (IS_BLOCKED(lx, ly))
2388 boolean cut_mode = NO_CUTTING;
2389 int element_old, content_old;
2391 Blocked2Moving(lx, ly, &oldx, &oldy);
2394 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
2395 MovDir[oldx][oldy] == MV_RIGHT);
2397 element_old = Feld[oldx][oldy];
2398 content_old = Store[oldx][oldy];
2400 if (element_old == EL_QUICKSAND_EMPTYING ||
2401 element_old == EL_QUICKSAND_FAST_EMPTYING ||
2402 element_old == EL_MAGIC_WALL_EMPTYING ||
2403 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
2404 element_old == EL_DC_MAGIC_WALL_EMPTYING ||
2405 element_old == EL_AMOEBA_DROPPING)
2406 cut_mode = CUT_ABOVE;
2408 DrawScreenElement(x, y, EL_EMPTY);
2411 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
2413 else if (cut_mode == NO_CUTTING)
2414 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
2417 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
2420 else if (IS_DRAWABLE(element))
2421 DrawScreenElement(x, y, element);
2423 DrawScreenElement(x, y, EL_EMPTY);
2426 void DrawLevelField(int x, int y)
2428 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
2429 DrawScreenField(SCREENX(x), SCREENY(y));
2430 else if (IS_MOVING(x, y))
2434 Moving2Blocked(x, y, &newx, &newy);
2435 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
2436 DrawScreenField(SCREENX(newx), SCREENY(newy));
2438 else if (IS_BLOCKED(x, y))
2442 Blocked2Moving(x, y, &oldx, &oldy);
2443 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
2444 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
2448 void DrawMiniElement(int x, int y, int element)
2452 graphic = el2edimg(element);
2453 DrawMiniGraphic(x, y, graphic);
2456 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
2458 int x = sx + scroll_x, y = sy + scroll_y;
2460 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
2461 DrawMiniElement(sx, sy, EL_EMPTY);
2462 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
2463 DrawMiniElement(sx, sy, Feld[x][y]);
2465 DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
2468 void DrawEnvelopeBackground(int envelope_nr, int startx, int starty,
2469 int x, int y, int xsize, int ysize, int font_nr)
2471 int font_width = getFontWidth(font_nr);
2472 int font_height = getFontHeight(font_nr);
2473 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2476 int dst_x = SX + startx + x * font_width;
2477 int dst_y = SY + starty + y * font_height;
2478 int width = graphic_info[graphic].width;
2479 int height = graphic_info[graphic].height;
2480 int inner_width = MAX(width - 2 * font_width, font_width);
2481 int inner_height = MAX(height - 2 * font_height, font_height);
2482 int inner_sx = (width >= 3 * font_width ? font_width : 0);
2483 int inner_sy = (height >= 3 * font_height ? font_height : 0);
2484 boolean draw_masked = graphic_info[graphic].draw_masked;
2486 getFixedGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
2488 if (src_bitmap == NULL || width < font_width || height < font_height)
2490 ClearRectangle(drawto, dst_x, dst_y, font_width, font_height);
2494 src_x += (x == 0 ? 0 : x == xsize - 1 ? width - font_width :
2495 inner_sx + (x - 1) * font_width % inner_width);
2496 src_y += (y == 0 ? 0 : y == ysize - 1 ? height - font_height :
2497 inner_sy + (y - 1) * font_height % inner_height);
2501 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
2502 dst_x - src_x, dst_y - src_y);
2503 BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, font_width, font_height,
2507 BlitBitmap(src_bitmap, drawto, src_x, src_y, font_width, font_height,
2511 void AnimateEnvelope(int envelope_nr, int anim_mode, int action)
2513 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2514 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
2515 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
2516 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2517 boolean no_delay = (tape.warp_forward);
2518 unsigned int anim_delay = 0;
2519 int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
2520 int anim_delay_value = (no_delay ? 0 : frame_delay_value);
2521 int font_nr = FONT_ENVELOPE_1 + envelope_nr;
2522 int font_width = getFontWidth(font_nr);
2523 int font_height = getFontHeight(font_nr);
2524 int max_xsize = level.envelope[envelope_nr].xsize;
2525 int max_ysize = level.envelope[envelope_nr].ysize;
2526 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
2527 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
2528 int xend = max_xsize;
2529 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
2530 int xstep = (xstart < xend ? 1 : 0);
2531 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
2534 for (x = xstart, y = ystart; x <= xend && y <= yend; x += xstep, y += ystep)
2536 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
2537 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
2538 int sx = (SXSIZE - xsize * font_width) / 2;
2539 int sy = (SYSIZE - ysize * font_height) / 2;
2542 SetDrawtoField(DRAW_BUFFERED);
2545 BlitScreenToBitmap(backbuffer);
2547 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
2550 SetDrawtoField(DRAW_BACKBUFFER);
2552 for (yy = 0; yy < ysize; yy++) for (xx = 0; xx < xsize; xx++)
2553 DrawEnvelopeBackground(envelope_nr, sx,sy, xx,yy, xsize, ysize, font_nr);
2556 DrawTextBuffer(SX + sx + font_width, SY + sy + font_height,
2557 level.envelope[envelope_nr].text, font_nr, max_xsize,
2558 xsize - 2, ysize - 2, 0, mask_mode,
2559 level.envelope[envelope_nr].autowrap,
2560 level.envelope[envelope_nr].centered, FALSE);
2562 DrawTextToTextArea(SX + sx + font_width, SY + sy + font_height,
2563 level.envelope[envelope_nr].text, font_nr, max_xsize,
2564 xsize - 2, ysize - 2, mask_mode);
2567 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
2570 WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
2574 void AnimateEnvelopeDoor(char *text, int anim_mode, int action)
2577 int envelope_nr = 0;
2579 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2580 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
2581 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
2582 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2583 boolean no_delay = (tape.warp_forward);
2584 unsigned int anim_delay = 0;
2585 int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
2586 int anim_delay_value = (no_delay ? 0 : frame_delay_value);
2588 int max_word_len = maxWordLengthInString(text);
2589 int font_nr = (max_word_len > 7 ? FONT_TEXT_1 : FONT_TEXT_2);
2591 int font_nr = FONT_ENVELOPE_1 + envelope_nr;
2593 int font_width = getFontWidth(font_nr);
2594 int font_height = getFontHeight(font_nr);
2598 int max_xsize = DXSIZE / font_width;
2599 int max_ysize = DYSIZE / font_height;
2601 int max_xsize = 7; /* tools.c: MAX_REQUEST_LINE_FONT1_LEN == 7 */
2602 int max_ysize = 13; /* tools.c: MAX_REQUEST_LINES == 13 */
2606 int max_xsize = level.envelope[envelope_nr].xsize;
2607 int max_ysize = level.envelope[envelope_nr].ysize;
2609 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
2610 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
2611 int xend = max_xsize;
2612 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
2613 int xstep = (xstart < xend ? 1 : 0);
2614 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
2619 char *text_copy = getStringCopy(text);
2622 font_nr = FONT_TEXT_2;
2624 if (maxWordLengthInString(text) > 7) /* MAX_REQUEST_LINE_FONT1_LEN == 7 */
2626 max_xsize = 10; /* tools.c: MAX_REQUEST_LINE_FONT2_LEN == 10 */
2627 font_nr = FONT_TEXT_1;
2630 int max_word_len = 0;
2632 char *text_copy = getStringCopy(text);
2634 font_nr = FONT_TEXT_2;
2636 for (text_ptr = text; *text_ptr; text_ptr++)
2638 max_word_len = (*text_ptr != ' ' ? max_word_len + 1 : 0);
2640 if (max_word_len > 7) /* tools.c: MAX_REQUEST_LINE_FONT1_LEN == 7 */
2642 max_xsize = 10; /* tools.c: MAX_REQUEST_LINE_FONT2_LEN == 10 */
2643 font_nr = FONT_TEXT_1;
2652 for (text_ptr = text_copy; *text_ptr; text_ptr++)
2653 if (*text_ptr == ' ')
2658 dDX = SX + (SXSIZE - DXSIZE) / 2 - DX;
2659 dDY = SY + (SYSIZE - DYSIZE) / 2 - DY;
2661 dDX = SX + SXSIZE / 2 - max_xsize * font_width / 2 - DX;
2662 dDY = SY + SYSIZE / 2 - max_ysize * font_height / 2 - DY;
2665 for (x = xstart, y = ystart; x <= xend && y <= yend; x += xstep, y += ystep)
2667 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
2668 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
2669 int sx = (SXSIZE - xsize * font_width) / 2;
2670 int sy = (SYSIZE - ysize * font_height) / 2;
2674 BlitBitmap(bitmap_db_store, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2676 SetDrawtoField(DRAW_BUFFERED);
2679 BlitScreenToBitmap(backbuffer);
2681 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
2684 SetDrawtoField(DRAW_BACKBUFFER);
2687 for (yy = 0; yy < ysize; yy++) for (xx = 0; xx < xsize; xx++)
2688 DrawEnvelopeBackground(envelope_nr, sx,sy, xx,yy, xsize, ysize, font_nr);
2693 DrawTextBuffer(SX + sx + font_width, SY + sy + font_height + 8,
2694 text_copy, font_nr, max_xsize,
2695 xsize - 2, ysize - 2, 2, mask_mode,
2696 FALSE, TRUE, FALSE);
2698 DrawTextBuffer(SX + sx + font_width, SY + sy + font_height,
2699 level.envelope[envelope_nr].text, font_nr, max_xsize,
2700 xsize - 2, ysize - 2, 0, mask_mode,
2701 level.envelope[envelope_nr].autowrap,
2702 level.envelope[envelope_nr].centered, FALSE);
2706 DrawTextToTextArea(SX + sx + font_width, SY + sy + font_height,
2707 level.envelope[envelope_nr].text, font_nr, max_xsize,
2708 xsize - 2, ysize - 2, mask_mode);
2711 /* copy request gadgets to door backbuffer */
2713 if ((ysize - 2) > 13)
2714 BlitBitmap(bitmap_db_door, drawto,
2715 DOOR_GFX_PAGEX1 + (DXSIZE - (xsize - 2) * font_width) / 2,
2716 DOOR_GFX_PAGEY1 + 13 * font_height,
2717 (xsize - 2) * font_width,
2718 (ysize - 2 - 13) * font_height,
2719 SX + sx + font_width,
2720 SY + sy + font_height * (1 + 13));
2722 if ((ysize - 2) > 13)
2723 BlitBitmap(bitmap_db_door, drawto,
2724 DOOR_GFX_PAGEX1 + (DXSIZE - (xsize - 2) * font_width) / 2,
2725 DOOR_GFX_PAGEY1 + 13 * font_height,
2726 (xsize - 2) * font_width,
2727 (ysize - 2 - 13) * font_height,
2728 SX + sx + font_width,
2729 SY + sy + font_height * (1 + 13));
2733 redraw_mask = REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
2734 // redraw_mask |= REDRAW_ALL | REDRAW_FROM_BACKBUFFER;
2736 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
2746 WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
2754 void ShowEnvelope(int envelope_nr)
2756 int element = EL_ENVELOPE_1 + envelope_nr;
2757 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2758 int sound_opening = element_info[element].sound[ACTION_OPENING];
2759 int sound_closing = element_info[element].sound[ACTION_CLOSING];
2760 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2761 boolean no_delay = (tape.warp_forward);
2762 int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
2763 int wait_delay_value = (no_delay ? 0 : normal_delay_value);
2764 int anim_mode = graphic_info[graphic].anim_mode;
2765 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
2766 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
2768 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
2770 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
2772 if (anim_mode == ANIM_DEFAULT)
2773 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_OPENING);
2775 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_OPENING);
2778 Delay(wait_delay_value);
2780 WaitForEventToContinue();
2782 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
2784 if (anim_mode != ANIM_NONE)
2785 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_CLOSING);
2787 if (anim_mode == ANIM_DEFAULT)
2788 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_CLOSING);
2790 game.envelope_active = FALSE;
2792 SetDrawtoField(DRAW_BUFFERED);
2794 redraw_mask |= REDRAW_FIELD;
2798 void ShowEnvelopeDoor(char *text, int action)
2801 int last_game_status = game_status; /* save current game status */
2802 // int last_draw_background_mask = gfx.draw_background_mask;
2803 int envelope_nr = 0;
2805 int element = EL_ENVELOPE_1 + envelope_nr;
2806 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2807 int sound_opening = element_info[element].sound[ACTION_OPENING];
2808 int sound_closing = element_info[element].sound[ACTION_CLOSING];
2810 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2811 boolean no_delay = (tape.warp_forward);
2812 int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
2813 int wait_delay_value = (no_delay ? 0 : normal_delay_value);
2815 int anim_mode = graphic_info[graphic].anim_mode;
2816 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
2817 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
2820 if (game_status == GAME_MODE_PLAYING)
2822 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
2823 BlitScreenToBitmap_EM(backbuffer);
2824 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
2825 BlitScreenToBitmap_SP(backbuffer);
2828 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
2832 SetDrawtoField(DRAW_BACKBUFFER);
2834 // SetDrawBackgroundMask(REDRAW_NONE);
2836 if (action == ACTION_OPENING)
2838 BlitBitmap(backbuffer, bitmap_db_store, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2840 if (game_status != GAME_MODE_MAIN)
2844 /* force DOOR font inside door area */
2845 game_status = GAME_MODE_PSEUDO_DOOR;
2848 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
2850 if (action == ACTION_OPENING)
2852 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
2854 if (anim_mode == ANIM_DEFAULT)
2855 AnimateEnvelopeDoor(text, ANIM_DEFAULT, ACTION_OPENING);
2857 AnimateEnvelopeDoor(text, main_anim_mode, ACTION_OPENING);
2861 Delay(wait_delay_value);
2863 WaitForEventToContinue();
2868 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
2870 if (anim_mode != ANIM_NONE)
2871 AnimateEnvelopeDoor(text, main_anim_mode, ACTION_CLOSING);
2873 if (anim_mode == ANIM_DEFAULT)
2874 AnimateEnvelopeDoor(text, ANIM_DEFAULT, ACTION_CLOSING);
2877 game.envelope_active = FALSE;
2880 // game_status = last_game_status; /* restore current game status */
2882 if (action == ACTION_CLOSING)
2884 if (game_status != GAME_MODE_MAIN)
2887 BlitBitmap(bitmap_db_store, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2890 SetDrawtoField(DRAW_BUFFERED);
2893 // SetDrawBackgroundMask(last_draw_background_mask);
2896 redraw_mask = REDRAW_FIELD;
2897 // redraw_mask |= REDRAW_ALL;
2899 redraw_mask |= REDRAW_FIELD;
2903 if (game_status == GAME_MODE_MAIN)
2908 /* (important: after "BackToFront()", but before "SetDrawtoField()") */
2909 game_status = last_game_status; /* restore current game status */
2911 if (game_status == GAME_MODE_PLAYING &&
2912 level.game_engine_type == GAME_ENGINE_TYPE_RND)
2913 SetDrawtoField(DRAW_BUFFERED);
2919 void DrawPreviewElement(int dst_x, int dst_y, int element, int tilesize)
2923 int graphic = el2preimg(element);
2925 getSizedGraphicSource(graphic, 0, tilesize, &src_bitmap, &src_x, &src_y);
2926 BlitBitmap(src_bitmap, drawto, src_x, src_y, tilesize, tilesize, dst_x,dst_y);
2934 SetMainBackgroundImage(IMG_BACKGROUND_PLAYING);
2935 SetDrawBackgroundMask(REDRAW_FIELD);
2937 SetDrawBackgroundMask(REDRAW_NONE);
2942 for (x = BX1; x <= BX2; x++)
2943 for (y = BY1; y <= BY2; y++)
2944 DrawScreenField(x, y);
2946 redraw_mask |= REDRAW_FIELD;
2949 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
2953 for (x = 0; x < size_x; x++)
2954 for (y = 0; y < size_y; y++)
2955 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
2957 redraw_mask |= REDRAW_FIELD;
2960 static void DrawPreviewLevelPlayfieldExt(int from_x, int from_y)
2962 boolean show_level_border = (BorderElement != EL_EMPTY);
2963 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
2964 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
2965 int tile_size = preview.tile_size;
2966 int preview_width = preview.xsize * tile_size;
2967 int preview_height = preview.ysize * tile_size;
2968 int real_preview_xsize = MIN(level_xsize, preview.xsize);
2969 int real_preview_ysize = MIN(level_ysize, preview.ysize);
2970 int dst_x = SX + ALIGNED_XPOS(preview.x, preview_width, preview.align);
2971 int dst_y = SY + ALIGNED_YPOS(preview.y, preview_height, preview.valign);
2974 DrawBackground(dst_x, dst_y, preview_width, preview_height);
2976 dst_x += (preview_width - real_preview_xsize * tile_size) / 2;
2977 dst_y += (preview_height - real_preview_ysize * tile_size) / 2;
2979 for (x = 0; x < real_preview_xsize; x++)
2981 for (y = 0; y < real_preview_ysize; y++)
2983 int lx = from_x + x + (show_level_border ? -1 : 0);
2984 int ly = from_y + y + (show_level_border ? -1 : 0);
2985 int element = (IN_LEV_FIELD(lx, ly) ? level.field[lx][ly] :
2986 getBorderElement(lx, ly));
2988 DrawPreviewElement(dst_x + x * tile_size, dst_y + y * tile_size,
2989 element, tile_size);
2993 redraw_mask |= REDRAW_MICROLEVEL;
2996 #define MICROLABEL_EMPTY 0
2997 #define MICROLABEL_LEVEL_NAME 1
2998 #define MICROLABEL_LEVEL_AUTHOR_HEAD 2
2999 #define MICROLABEL_LEVEL_AUTHOR 3
3000 #define MICROLABEL_IMPORTED_FROM_HEAD 4
3001 #define MICROLABEL_IMPORTED_FROM 5
3002 #define MICROLABEL_IMPORTED_BY_HEAD 6
3003 #define MICROLABEL_IMPORTED_BY 7
3005 static int getMaxTextLength(struct TextPosInfo *pos, int font_nr)
3007 int max_text_width = SXSIZE;
3008 int font_width = getFontWidth(font_nr);
3010 if (pos->align == ALIGN_CENTER)
3011 max_text_width = (pos->x < SXSIZE / 2 ? pos->x * 2 : (SXSIZE - pos->x) * 2);
3012 else if (pos->align == ALIGN_RIGHT)
3013 max_text_width = pos->x;
3015 max_text_width = SXSIZE - pos->x;
3017 return max_text_width / font_width;
3020 static void DrawPreviewLevelLabelExt(int mode)
3022 struct TextPosInfo *pos = &menu.main.text.level_info_2;
3023 char label_text[MAX_OUTPUT_LINESIZE + 1];
3024 int max_len_label_text;
3026 int font_nr = pos->font;
3029 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
3030 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
3031 mode == MICROLABEL_IMPORTED_BY_HEAD)
3032 font_nr = pos->font_alt;
3034 int font_nr = FONT_TEXT_2;
3037 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
3038 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
3039 mode == MICROLABEL_IMPORTED_BY_HEAD)
3040 font_nr = FONT_TEXT_3;
3044 max_len_label_text = getMaxTextLength(pos, font_nr);
3046 max_len_label_text = SXSIZE / getFontWidth(font_nr);
3050 if (pos->size != -1)
3051 max_len_label_text = pos->size;
3054 for (i = 0; i < max_len_label_text; i++)
3055 label_text[i] = ' ';
3056 label_text[max_len_label_text] = '\0';
3058 if (strlen(label_text) > 0)
3061 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
3063 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
3064 int lypos = MICROLABEL2_YPOS;
3066 DrawText(lxpos, lypos, label_text, font_nr);
3071 (mode == MICROLABEL_LEVEL_NAME ? level.name :
3072 mode == MICROLABEL_LEVEL_AUTHOR_HEAD ? "created by" :
3073 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
3074 mode == MICROLABEL_IMPORTED_FROM_HEAD ? "imported from" :
3075 mode == MICROLABEL_IMPORTED_FROM ? leveldir_current->imported_from :
3076 mode == MICROLABEL_IMPORTED_BY_HEAD ? "imported by" :
3077 mode == MICROLABEL_IMPORTED_BY ? leveldir_current->imported_by :""),
3078 max_len_label_text);
3079 label_text[max_len_label_text] = '\0';
3081 if (strlen(label_text) > 0)
3084 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
3086 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
3087 int lypos = MICROLABEL2_YPOS;
3089 DrawText(lxpos, lypos, label_text, font_nr);
3093 redraw_mask |= REDRAW_MICROLEVEL;
3096 static void DrawPreviewLevelExt(boolean restart)
3098 static unsigned int scroll_delay = 0;
3099 static unsigned int label_delay = 0;
3100 static int from_x, from_y, scroll_direction;
3101 static int label_state, label_counter;
3102 unsigned int scroll_delay_value = preview.step_delay;
3103 boolean show_level_border = (BorderElement != EL_EMPTY);
3104 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
3105 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
3106 int last_game_status = game_status; /* save current game status */
3109 /* force PREVIEW font on preview level */
3110 game_status = GAME_MODE_PSEUDO_PREVIEW;
3118 if (preview.anim_mode == ANIM_CENTERED)
3120 if (level_xsize > preview.xsize)
3121 from_x = (level_xsize - preview.xsize) / 2;
3122 if (level_ysize > preview.ysize)
3123 from_y = (level_ysize - preview.ysize) / 2;
3126 from_x += preview.xoffset;
3127 from_y += preview.yoffset;
3129 scroll_direction = MV_RIGHT;
3133 DrawPreviewLevelPlayfieldExt(from_x, from_y);
3134 DrawPreviewLevelLabelExt(label_state);
3136 /* initialize delay counters */
3137 DelayReached(&scroll_delay, 0);
3138 DelayReached(&label_delay, 0);
3140 if (leveldir_current->name)
3142 struct TextPosInfo *pos = &menu.main.text.level_info_1;
3143 char label_text[MAX_OUTPUT_LINESIZE + 1];
3145 int font_nr = pos->font;
3147 int font_nr = FONT_TEXT_1;
3150 int max_len_label_text = getMaxTextLength(pos, font_nr);
3152 int max_len_label_text = SXSIZE / getFontWidth(font_nr);
3160 if (pos->size != -1)
3161 max_len_label_text = pos->size;
3164 strncpy(label_text, leveldir_current->name, max_len_label_text);
3165 label_text[max_len_label_text] = '\0';
3168 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
3170 lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
3171 lypos = SY + MICROLABEL1_YPOS;
3173 DrawText(lxpos, lypos, label_text, font_nr);
3177 game_status = last_game_status; /* restore current game status */
3182 /* scroll preview level, if needed */
3183 if (preview.anim_mode != ANIM_NONE &&
3184 (level_xsize > preview.xsize || level_ysize > preview.ysize) &&
3185 DelayReached(&scroll_delay, scroll_delay_value))
3187 switch (scroll_direction)
3192 from_x -= preview.step_offset;
3193 from_x = (from_x < 0 ? 0 : from_x);
3196 scroll_direction = MV_UP;
3200 if (from_x < level_xsize - preview.xsize)
3202 from_x += preview.step_offset;
3203 from_x = (from_x > level_xsize - preview.xsize ?
3204 level_xsize - preview.xsize : from_x);
3207 scroll_direction = MV_DOWN;
3213 from_y -= preview.step_offset;
3214 from_y = (from_y < 0 ? 0 : from_y);
3217 scroll_direction = MV_RIGHT;
3221 if (from_y < level_ysize - preview.ysize)
3223 from_y += preview.step_offset;
3224 from_y = (from_y > level_ysize - preview.ysize ?
3225 level_ysize - preview.ysize : from_y);
3228 scroll_direction = MV_LEFT;
3235 DrawPreviewLevelPlayfieldExt(from_x, from_y);
3238 /* !!! THIS ALL SUCKS -- SHOULD BE CLEANLY REWRITTEN !!! */
3239 /* redraw micro level label, if needed */
3240 if (!strEqual(level.name, NAMELESS_LEVEL_NAME) &&
3241 !strEqual(level.author, ANONYMOUS_NAME) &&
3242 !strEqual(level.author, leveldir_current->name) &&
3243 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
3245 int max_label_counter = 23;
3247 if (leveldir_current->imported_from != NULL &&
3248 strlen(leveldir_current->imported_from) > 0)
3249 max_label_counter += 14;
3250 if (leveldir_current->imported_by != NULL &&
3251 strlen(leveldir_current->imported_by) > 0)
3252 max_label_counter += 14;
3254 label_counter = (label_counter + 1) % max_label_counter;
3255 label_state = (label_counter >= 0 && label_counter <= 7 ?
3256 MICROLABEL_LEVEL_NAME :
3257 label_counter >= 9 && label_counter <= 12 ?
3258 MICROLABEL_LEVEL_AUTHOR_HEAD :
3259 label_counter >= 14 && label_counter <= 21 ?
3260 MICROLABEL_LEVEL_AUTHOR :
3261 label_counter >= 23 && label_counter <= 26 ?
3262 MICROLABEL_IMPORTED_FROM_HEAD :
3263 label_counter >= 28 && label_counter <= 35 ?
3264 MICROLABEL_IMPORTED_FROM :
3265 label_counter >= 37 && label_counter <= 40 ?
3266 MICROLABEL_IMPORTED_BY_HEAD :
3267 label_counter >= 42 && label_counter <= 49 ?
3268 MICROLABEL_IMPORTED_BY : MICROLABEL_EMPTY);
3270 if (leveldir_current->imported_from == NULL &&
3271 (label_state == MICROLABEL_IMPORTED_FROM_HEAD ||
3272 label_state == MICROLABEL_IMPORTED_FROM))
3273 label_state = (label_state == MICROLABEL_IMPORTED_FROM_HEAD ?
3274 MICROLABEL_IMPORTED_BY_HEAD : MICROLABEL_IMPORTED_BY);
3276 DrawPreviewLevelLabelExt(label_state);
3279 game_status = last_game_status; /* restore current game status */
3282 void DrawPreviewLevelInitial()
3284 DrawPreviewLevelExt(TRUE);
3287 void DrawPreviewLevelAnimation()
3289 DrawPreviewLevelExt(FALSE);
3292 inline void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
3293 int graphic, int sync_frame, int mask_mode)
3295 int frame = getGraphicAnimationFrame(graphic, sync_frame);
3297 if (mask_mode == USE_MASKING)
3298 DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
3300 DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
3303 inline void DrawFixedGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
3304 int graphic, int sync_frame,
3307 int frame = getGraphicAnimationFrame(graphic, sync_frame);
3309 if (mask_mode == USE_MASKING)
3310 DrawFixedGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
3312 DrawFixedGraphicExt(dst_bitmap, x, y, graphic, frame);
3315 inline void DrawGraphicAnimation(int x, int y, int graphic)
3317 int lx = LEVELX(x), ly = LEVELY(y);
3319 if (!IN_SCR_FIELD(x, y))
3323 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR,
3324 graphic, GfxFrame[lx][ly], NO_MASKING);
3326 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
3327 graphic, GfxFrame[lx][ly], NO_MASKING);
3329 MarkTileDirty(x, y);
3332 inline void DrawFixedGraphicAnimation(int x, int y, int graphic)
3334 int lx = LEVELX(x), ly = LEVELY(y);
3336 if (!IN_SCR_FIELD(x, y))
3339 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
3340 graphic, GfxFrame[lx][ly], NO_MASKING);
3341 MarkTileDirty(x, y);
3344 void DrawLevelGraphicAnimation(int x, int y, int graphic)
3346 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
3349 void DrawLevelElementAnimation(int x, int y, int element)
3351 int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
3353 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
3356 inline void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
3358 int sx = SCREENX(x), sy = SCREENY(y);
3360 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
3363 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
3366 DrawGraphicAnimation(sx, sy, graphic);
3369 if (GFX_CRUMBLED(TILE_GFX_ELEMENT(x, y)))
3370 DrawLevelFieldCrumbled(x, y);
3372 if (GFX_CRUMBLED(Feld[x][y]))
3373 DrawLevelFieldCrumbled(x, y);
3377 void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
3379 int sx = SCREENX(x), sy = SCREENY(y);
3382 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
3385 graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
3387 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
3390 DrawGraphicAnimation(sx, sy, graphic);
3392 if (GFX_CRUMBLED(element))
3393 DrawLevelFieldCrumbled(x, y);
3396 static int getPlayerGraphic(struct PlayerInfo *player, int move_dir)
3398 if (player->use_murphy)
3400 /* this works only because currently only one player can be "murphy" ... */
3401 static int last_horizontal_dir = MV_LEFT;
3402 int graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir);
3404 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3405 last_horizontal_dir = move_dir;
3407 if (graphic == IMG_SP_MURPHY) /* undefined => use special graphic */
3409 int direction = (player->is_snapping ? move_dir : last_horizontal_dir);
3411 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
3417 return el_act_dir2img(player->artwork_element, player->GfxAction,move_dir);
3420 static boolean equalGraphics(int graphic1, int graphic2)
3422 struct GraphicInfo *g1 = &graphic_info[graphic1];
3423 struct GraphicInfo *g2 = &graphic_info[graphic2];
3425 return (g1->bitmap == g2->bitmap &&
3426 g1->src_x == g2->src_x &&
3427 g1->src_y == g2->src_y &&
3428 g1->anim_frames == g2->anim_frames &&
3429 g1->anim_delay == g2->anim_delay &&
3430 g1->anim_mode == g2->anim_mode);
3433 void DrawAllPlayers()
3437 for (i = 0; i < MAX_PLAYERS; i++)
3438 if (stored_player[i].active)
3439 DrawPlayer(&stored_player[i]);
3442 void DrawPlayerField(int x, int y)
3444 if (!IS_PLAYER(x, y))
3447 DrawPlayer(PLAYERINFO(x, y));
3450 #define DRAW_PLAYER_OVER_PUSHED_ELEMENT 1
3452 void DrawPlayer(struct PlayerInfo *player)
3454 int jx = player->jx;
3455 int jy = player->jy;
3456 int move_dir = player->MovDir;
3457 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? +1 : 0);
3458 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? +1 : 0);
3459 int last_jx = (player->is_moving ? jx - dx : jx);
3460 int last_jy = (player->is_moving ? jy - dy : jy);
3461 int next_jx = jx + dx;
3462 int next_jy = jy + dy;
3463 boolean player_is_moving = (player->MovPos ? TRUE : FALSE);
3464 boolean player_is_opaque = FALSE;
3465 int sx = SCREENX(jx), sy = SCREENY(jy);
3466 int sxx = 0, syy = 0;
3467 int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
3469 int action = ACTION_DEFAULT;
3470 int last_player_graphic = getPlayerGraphic(player, move_dir);
3471 int last_player_frame = player->Frame;
3474 /* GfxElement[][] is set to the element the player is digging or collecting;
3475 remove also for off-screen player if the player is not moving anymore */
3476 if (IN_LEV_FIELD(jx, jy) && !player_is_moving)
3477 GfxElement[jx][jy] = EL_UNDEFINED;
3479 if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
3483 if (!IN_LEV_FIELD(jx, jy))
3485 printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
3486 printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
3487 printf("DrawPlayerField(): This should never happen!\n");
3492 if (element == EL_EXPLOSION)
3495 action = (player->is_pushing ? ACTION_PUSHING :
3496 player->is_digging ? ACTION_DIGGING :
3497 player->is_collecting ? ACTION_COLLECTING :
3498 player->is_moving ? ACTION_MOVING :
3499 player->is_snapping ? ACTION_SNAPPING :
3500 player->is_dropping ? ACTION_DROPPING :
3501 player->is_waiting ? player->action_waiting : ACTION_DEFAULT);
3503 if (player->is_waiting)
3504 move_dir = player->dir_waiting;
3506 InitPlayerGfxAnimation(player, action, move_dir);
3508 /* ----------------------------------------------------------------------- */
3509 /* draw things in the field the player is leaving, if needed */
3510 /* ----------------------------------------------------------------------- */
3512 if (player->is_moving)
3514 if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
3516 DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
3518 if (last_element == EL_DYNAMITE_ACTIVE ||
3519 last_element == EL_EM_DYNAMITE_ACTIVE ||
3520 last_element == EL_SP_DISK_RED_ACTIVE)
3521 DrawDynamite(last_jx, last_jy);
3523 DrawLevelFieldThruMask(last_jx, last_jy);
3525 else if (last_element == EL_DYNAMITE_ACTIVE ||
3526 last_element == EL_EM_DYNAMITE_ACTIVE ||
3527 last_element == EL_SP_DISK_RED_ACTIVE)
3528 DrawDynamite(last_jx, last_jy);
3530 /* !!! this is not enough to prevent flickering of players which are
3531 moving next to each others without a free tile between them -- this
3532 can only be solved by drawing all players layer by layer (first the
3533 background, then the foreground etc.) !!! => TODO */
3534 else if (!IS_PLAYER(last_jx, last_jy))
3535 DrawLevelField(last_jx, last_jy);
3538 DrawLevelField(last_jx, last_jy);
3541 if (player->is_pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
3542 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
3545 if (!IN_SCR_FIELD(sx, sy))
3548 /* ----------------------------------------------------------------------- */
3549 /* draw things behind the player, if needed */
3550 /* ----------------------------------------------------------------------- */
3553 DrawLevelElement(jx, jy, Back[jx][jy]);
3554 else if (IS_ACTIVE_BOMB(element))
3555 DrawLevelElement(jx, jy, EL_EMPTY);
3558 if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
3560 int old_element = GfxElement[jx][jy];
3561 int old_graphic = el_act_dir2img(old_element, action, move_dir);
3562 int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
3564 if (GFX_CRUMBLED(old_element))
3565 DrawLevelFieldCrumbledDigging(jx, jy, move_dir, player->StepFrame);
3567 DrawGraphic(sx, sy, old_graphic, frame);
3569 if (graphic_info[old_graphic].anim_mode & ANIM_OPAQUE_PLAYER)
3570 player_is_opaque = TRUE;
3574 GfxElement[jx][jy] = EL_UNDEFINED;
3576 /* make sure that pushed elements are drawn with correct frame rate */
3578 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
3580 if (player->is_pushing && player->is_moving && !IS_ANIM_MODE_CE(graphic))
3581 GfxFrame[jx][jy] = player->StepFrame;
3583 if (player->is_pushing && player->is_moving)
3584 GfxFrame[jx][jy] = player->StepFrame;
3587 DrawLevelField(jx, jy);
3591 #if !DRAW_PLAYER_OVER_PUSHED_ELEMENT
3592 /* ----------------------------------------------------------------------- */
3593 /* draw player himself */
3594 /* ----------------------------------------------------------------------- */
3596 graphic = getPlayerGraphic(player, move_dir);
3598 /* in the case of changed player action or direction, prevent the current
3599 animation frame from being restarted for identical animations */
3600 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
3601 player->Frame = last_player_frame;
3603 frame = getGraphicAnimationFrame(graphic, player->Frame);
3607 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3608 sxx = player->GfxPos;
3610 syy = player->GfxPos;
3613 if (!setup.soft_scrolling && ScreenMovPos)
3616 if (player_is_opaque)
3617 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
3619 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3621 if (SHIELD_ON(player))
3623 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
3624 IMG_SHIELD_NORMAL_ACTIVE);
3625 int frame = getGraphicAnimationFrame(graphic, -1);
3627 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3631 #if DRAW_PLAYER_OVER_PUSHED_ELEMENT
3634 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3635 sxx = player->GfxPos;
3637 syy = player->GfxPos;
3641 /* ----------------------------------------------------------------------- */
3642 /* draw things the player is pushing, if needed */
3643 /* ----------------------------------------------------------------------- */
3646 printf("::: %d, %d [%d, %d] [%d]\n",
3647 player->is_pushing, player_is_moving, player->GfxAction,
3648 player->is_moving, player_is_moving);
3652 if (player->is_pushing && player->is_moving)
3654 int px = SCREENX(jx), py = SCREENY(jy);
3655 int pxx = (TILEX - ABS(sxx)) * dx;
3656 int pyy = (TILEY - ABS(syy)) * dy;
3657 int gfx_frame = GfxFrame[jx][jy];
3663 if (!IS_MOVING(jx, jy)) /* push movement already finished */
3665 element = Feld[next_jx][next_jy];
3666 gfx_frame = GfxFrame[next_jx][next_jy];
3669 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
3672 sync_frame = (IS_ANIM_MODE_CE(graphic) ? gfx_frame : player->StepFrame);
3673 frame = getGraphicAnimationFrame(graphic, sync_frame);
3675 frame = getGraphicAnimationFrame(graphic, player->StepFrame);
3678 /* draw background element under pushed element (like the Sokoban field) */
3680 if (game.use_masked_pushing && IS_MOVING(jx, jy))
3682 /* this allows transparent pushing animation over non-black background */
3685 DrawLevelElement(jx, jy, Back[jx][jy]);
3687 DrawLevelElement(jx, jy, EL_EMPTY);
3689 if (Back[next_jx][next_jy])
3690 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
3692 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
3694 else if (Back[next_jx][next_jy])
3695 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
3697 if (Back[next_jx][next_jy])
3698 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
3702 printf("::: %d, %d, %d, %d [%d] [%d, %d, %d] [%d] [%d, %d] [%d, %d]\n",
3703 jx, px, player->GfxPos, player->StepFrame,
3708 GfxFrame[jx][jy], GfxFrame[next_jx][next_jy]);
3712 /* do not draw (EM style) pushing animation when pushing is finished */
3713 /* (two-tile animations usually do not contain start and end frame) */
3714 if (graphic_info[graphic].double_movement && !IS_MOVING(jx, jy))
3715 DrawLevelElement(next_jx, next_jy, Feld[next_jx][next_jy]);
3717 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
3719 /* masked drawing is needed for EMC style (double) movement graphics */
3720 /* !!! (ONLY WHEN DRAWING PUSHED ELEMENT OVER THE PLAYER) !!! */
3721 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
3726 #if DRAW_PLAYER_OVER_PUSHED_ELEMENT
3727 /* ----------------------------------------------------------------------- */
3728 /* draw player himself */
3729 /* ----------------------------------------------------------------------- */
3731 graphic = getPlayerGraphic(player, move_dir);
3733 /* in the case of changed player action or direction, prevent the current
3734 animation frame from being restarted for identical animations */
3735 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
3736 player->Frame = last_player_frame;
3738 frame = getGraphicAnimationFrame(graphic, player->Frame);
3742 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3743 sxx = player->GfxPos;
3745 syy = player->GfxPos;
3748 if (!setup.soft_scrolling && ScreenMovPos)
3751 if (player_is_opaque)
3752 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
3754 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3756 if (SHIELD_ON(player))
3758 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
3759 IMG_SHIELD_NORMAL_ACTIVE);
3760 int frame = getGraphicAnimationFrame(graphic, -1);
3762 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3766 /* ----------------------------------------------------------------------- */
3767 /* draw things in front of player (active dynamite or dynabombs) */
3768 /* ----------------------------------------------------------------------- */
3770 if (IS_ACTIVE_BOMB(element))
3772 graphic = el2img(element);
3773 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
3775 if (game.emulation == EMU_SUPAPLEX)
3776 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
3778 DrawGraphicThruMask(sx, sy, graphic, frame);
3781 if (player_is_moving && last_element == EL_EXPLOSION)
3783 int element = (GfxElement[last_jx][last_jy] != EL_UNDEFINED ?
3784 GfxElement[last_jx][last_jy] : EL_EMPTY);
3785 int graphic = el_act2img(element, ACTION_EXPLODING);
3786 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
3787 int phase = ExplodePhase[last_jx][last_jy] - 1;
3788 int frame = getGraphicAnimationFrame(graphic, phase - delay);
3791 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
3794 /* ----------------------------------------------------------------------- */
3795 /* draw elements the player is just walking/passing through/under */
3796 /* ----------------------------------------------------------------------- */
3798 if (player_is_moving)
3800 /* handle the field the player is leaving ... */
3801 if (IS_ACCESSIBLE_INSIDE(last_element))
3802 DrawLevelField(last_jx, last_jy);
3803 else if (IS_ACCESSIBLE_UNDER(last_element))
3804 DrawLevelFieldThruMask(last_jx, last_jy);
3807 /* do not redraw accessible elements if the player is just pushing them */
3808 if (!player_is_moving || !player->is_pushing)
3810 /* ... and the field the player is entering */
3811 if (IS_ACCESSIBLE_INSIDE(element))
3812 DrawLevelField(jx, jy);
3813 else if (IS_ACCESSIBLE_UNDER(element))
3814 DrawLevelFieldThruMask(jx, jy);
3817 MarkTileDirty(sx, sy);
3820 /* ------------------------------------------------------------------------- */
3822 void WaitForEventToContinue()
3824 boolean still_wait = TRUE;
3826 /* simulate releasing mouse button over last gadget, if still pressed */
3828 HandleGadgets(-1, -1, 0);
3830 button_status = MB_RELEASED;
3846 case EVENT_BUTTONPRESS:
3847 case EVENT_KEYPRESS:
3851 case EVENT_KEYRELEASE:
3852 ClearPlayerAction();
3856 HandleOtherEvents(&event);
3860 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
3867 /* don't eat all CPU time */
3872 #define MAX_REQUEST_LINES 13
3873 #define MAX_REQUEST_LINE_FONT1_LEN 7
3874 #define MAX_REQUEST_LINE_FONT2_LEN 10
3876 boolean Request(char *text, unsigned int req_state)
3878 int mx, my, ty, result = -1;
3879 unsigned int old_door_state;
3880 int last_game_status = game_status; /* save current game status */
3881 int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
3882 int font_nr = FONT_TEXT_2;
3884 int max_word_len = 0;
3890 global.use_envelope_request = 0;
3894 if (maxWordLengthInString(text) > MAX_REQUEST_LINE_FONT1_LEN)
3896 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
3897 font_nr = FONT_TEXT_1;
3900 for (text_ptr = text; *text_ptr; text_ptr++)
3902 max_word_len = (*text_ptr != ' ' ? max_word_len + 1 : 0);
3904 if (max_word_len > MAX_REQUEST_LINE_FONT1_LEN)
3906 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
3908 font_nr = FONT_TEXT_1;
3910 font_nr = FONT_LEVEL_NUMBER;
3918 if (game_status == GAME_MODE_PLAYING)
3920 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
3921 BlitScreenToBitmap_EM(backbuffer);
3922 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
3923 BlitScreenToBitmap_SP(backbuffer);
3926 /* disable deactivated drawing when quick-loading level tape recording */
3927 if (tape.playing && tape.deactivate_display)
3928 TapeDeactivateDisplayOff(TRUE);
3930 SetMouseCursor(CURSOR_DEFAULT);
3932 #if defined(NETWORK_AVALIABLE)
3933 /* pause network game while waiting for request to answer */
3934 if (options.network &&
3935 game_status == GAME_MODE_PLAYING &&
3936 req_state & REQUEST_WAIT_FOR_INPUT)
3937 SendToServer_PausePlaying();
3940 old_door_state = GetDoorState();
3942 /* simulate releasing mouse button over last gadget, if still pressed */
3944 HandleGadgets(-1, -1, 0);
3948 /* draw released gadget before proceeding */
3952 if (old_door_state & DOOR_OPEN_1 && !global.use_envelope_request)
3954 if (old_door_state & DOOR_OPEN_1)
3958 if (!global.use_envelope_request)
3959 CloseDoor(DOOR_CLOSE_1);
3961 CloseDoor(DOOR_CLOSE_1);
3964 /* save old door content */
3965 BlitBitmap(bitmap_db_door, bitmap_db_door,
3966 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
3967 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
3971 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
3974 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3976 /* clear door drawing field */
3977 DrawBackground(DX, DY, DXSIZE, DYSIZE);
3979 /* force DOOR font inside door area */
3980 game_status = GAME_MODE_PSEUDO_DOOR;
3982 /* write text for request */
3983 for (text_ptr = text, ty = 0; ty < MAX_REQUEST_LINES; ty++)
3985 char text_line[max_request_line_len + 1];
3991 for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
3993 tc = *(text_ptr + tx);
3994 if (!tc || tc == ' ')
4005 strncpy(text_line, text_ptr, tl);
4008 DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
4009 DY + 8 + ty * (getFontHeight(font_nr) + 2),
4010 text_line, font_nr);
4012 text_ptr += tl + (tc == ' ' ? 1 : 0);
4015 game_status = last_game_status; /* restore current game status */
4018 if (global.use_envelope_request)
4022 CreateToolButtons();
4026 if (req_state & REQ_ASK)
4028 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
4029 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
4031 else if (req_state & REQ_CONFIRM)
4033 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
4035 else if (req_state & REQ_PLAYER)
4037 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
4038 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
4039 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
4040 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
4043 /* copy request gadgets to door backbuffer */
4044 BlitBitmap(drawto, bitmap_db_door,
4045 DX, DY, DXSIZE, DYSIZE,
4046 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
4049 if (global.use_envelope_request)
4051 ShowEnvelopeDoor(text, ACTION_OPENING);
4053 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4055 if ((req_state & REQ_ASK && (i == TOOL_CTRL_ID_YES ||
4056 i == TOOL_CTRL_ID_NO)) ||
4057 (req_state & REQ_CONFIRM && i == TOOL_CTRL_ID_CONFIRM) ||
4058 (req_state & REQ_PLAYER && (i == TOOL_CTRL_ID_PLAYER_1 &&
4059 i == TOOL_CTRL_ID_PLAYER_2 &&
4060 i == TOOL_CTRL_ID_PLAYER_3 &&
4061 i == TOOL_CTRL_ID_PLAYER_4)))
4063 int x = tool_gadget[i]->x + dDX;
4064 int y = tool_gadget[i]->y + dDY;
4066 ModifyGadget(tool_gadget[i], GDI_X, x, GDI_Y, y, GDI_END);
4073 if (!global.use_envelope_request)
4074 OpenDoor(DOOR_OPEN_1);
4076 OpenDoor(DOOR_OPEN_1);
4079 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
4081 if (game_status == GAME_MODE_PLAYING)
4083 SetPanelBackground();
4084 SetDrawBackgroundMask(REDRAW_DOOR_1);
4088 SetDrawBackgroundMask(REDRAW_FIELD);
4095 if (game_status != GAME_MODE_MAIN && !global.use_envelope_request)
4098 if (game_status != GAME_MODE_MAIN)
4102 button_status = MB_RELEASED;
4104 request_gadget_id = -1;
4106 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
4118 case EVENT_BUTTONPRESS:
4119 case EVENT_BUTTONRELEASE:
4120 case EVENT_MOTIONNOTIFY:
4122 if (event.type == EVENT_MOTIONNOTIFY)
4124 if (!PointerInWindow(window))
4125 continue; /* window and pointer are on different screens */
4130 motion_status = TRUE;
4131 mx = ((MotionEvent *) &event)->x;
4132 my = ((MotionEvent *) &event)->y;
4136 motion_status = FALSE;
4137 mx = ((ButtonEvent *) &event)->x;
4138 my = ((ButtonEvent *) &event)->y;
4139 if (event.type == EVENT_BUTTONPRESS)
4140 button_status = ((ButtonEvent *) &event)->button;
4142 button_status = MB_RELEASED;
4145 /* this sets 'request_gadget_id' */
4146 HandleGadgets(mx, my, button_status);
4148 switch (request_gadget_id)
4150 case TOOL_CTRL_ID_YES:
4153 case TOOL_CTRL_ID_NO:
4156 case TOOL_CTRL_ID_CONFIRM:
4157 result = TRUE | FALSE;
4160 case TOOL_CTRL_ID_PLAYER_1:
4163 case TOOL_CTRL_ID_PLAYER_2:
4166 case TOOL_CTRL_ID_PLAYER_3:
4169 case TOOL_CTRL_ID_PLAYER_4:
4180 case EVENT_KEYPRESS:
4181 switch (GetEventKey((KeyEvent *)&event, TRUE))
4184 if (req_state & REQ_CONFIRM)
4193 #if defined(TARGET_SDL2)
4203 if (req_state & REQ_PLAYER)
4207 case EVENT_KEYRELEASE:
4208 ClearPlayerAction();
4212 HandleOtherEvents(&event);
4216 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
4218 int joy = AnyJoystick();
4220 if (joy & JOY_BUTTON_1)
4222 else if (joy & JOY_BUTTON_2)
4228 if (game_status == GAME_MODE_PLAYING && local_player->LevelSolved_GameEnd)
4230 HandleGameActions();
4236 if (!PendingEvent()) /* delay only if no pending events */
4241 game_status = GAME_MODE_PSEUDO_DOOR;
4247 game_status = last_game_status; /* restore current game status */
4255 if (!PendingEvent()) /* delay only if no pending events */
4258 /* don't eat all CPU time */
4265 if (game_status != GAME_MODE_MAIN)
4271 if (global.use_envelope_request)
4272 ShowEnvelopeDoor(text, ACTION_CLOSING);
4276 if (!(req_state & REQ_STAY_OPEN) && !global.use_envelope_request)
4278 if (!(req_state & REQ_STAY_OPEN))
4281 CloseDoor(DOOR_CLOSE_1);
4283 if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
4284 (req_state & REQ_REOPEN))
4285 OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
4290 if (game_status == GAME_MODE_PLAYING)
4292 SetPanelBackground();
4293 SetDrawBackgroundMask(REDRAW_DOOR_1);
4297 SetDrawBackgroundMask(REDRAW_FIELD);
4300 #if defined(NETWORK_AVALIABLE)
4301 /* continue network game after request */
4302 if (options.network &&
4303 game_status == GAME_MODE_PLAYING &&
4304 req_state & REQUEST_WAIT_FOR_INPUT)
4305 SendToServer_ContinuePlaying();
4308 /* restore deactivated drawing when quick-loading level tape recording */
4309 if (tape.playing && tape.deactivate_display)
4310 TapeDeactivateDisplayOn();
4315 unsigned int OpenDoor(unsigned int door_state)
4317 if (door_state & DOOR_COPY_BACK)
4319 if (door_state & DOOR_OPEN_1)
4320 BlitBitmap(bitmap_db_door, bitmap_db_door,
4321 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
4322 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
4324 if (door_state & DOOR_OPEN_2)
4325 BlitBitmap(bitmap_db_door, bitmap_db_door,
4326 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY2, VXSIZE, VYSIZE,
4327 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
4329 door_state &= ~DOOR_COPY_BACK;
4332 return MoveDoor(door_state);
4335 unsigned int CloseDoor(unsigned int door_state)
4337 unsigned int old_door_state = GetDoorState();
4339 if (!(door_state & DOOR_NO_COPY_BACK))
4341 if (old_door_state & DOOR_OPEN_1)
4342 BlitBitmap(backbuffer, bitmap_db_door,
4343 DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
4345 if (old_door_state & DOOR_OPEN_2)
4346 BlitBitmap(backbuffer, bitmap_db_door,
4347 VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
4349 door_state &= ~DOOR_NO_COPY_BACK;
4352 return MoveDoor(door_state);
4355 unsigned int GetDoorState()
4357 return MoveDoor(DOOR_GET_STATE);
4360 unsigned int SetDoorState(unsigned int door_state)
4362 return MoveDoor(door_state | DOOR_SET_STATE);
4365 unsigned int MoveDoor(unsigned int door_state)
4367 static int door1 = DOOR_OPEN_1;
4368 static int door2 = DOOR_CLOSE_2;
4369 unsigned int door_delay = 0;
4370 unsigned int door_delay_value;
4373 if (door_1.width < 0 || door_1.width > DXSIZE)
4374 door_1.width = DXSIZE;
4375 if (door_1.height < 0 || door_1.height > DYSIZE)
4376 door_1.height = DYSIZE;
4377 if (door_2.width < 0 || door_2.width > VXSIZE)
4378 door_2.width = VXSIZE;
4379 if (door_2.height < 0 || door_2.height > VYSIZE)
4380 door_2.height = VYSIZE;
4382 if (door_state == DOOR_GET_STATE)
4383 return (door1 | door2);
4385 if (door_state & DOOR_SET_STATE)
4387 if (door_state & DOOR_ACTION_1)
4388 door1 = door_state & DOOR_ACTION_1;
4389 if (door_state & DOOR_ACTION_2)
4390 door2 = door_state & DOOR_ACTION_2;
4392 return (door1 | door2);
4395 if (!(door_state & DOOR_FORCE_REDRAW))
4397 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
4398 door_state &= ~DOOR_OPEN_1;
4399 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
4400 door_state &= ~DOOR_CLOSE_1;
4401 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
4402 door_state &= ~DOOR_OPEN_2;
4403 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
4404 door_state &= ~DOOR_CLOSE_2;
4407 door_delay_value = (door_state & DOOR_ACTION_1 ? door_1.step_delay :
4410 if (setup.quick_doors)
4412 stepsize = 20; /* must be chosen to always draw last frame */
4413 door_delay_value = 0;
4416 if (global.autoplay_leveldir)
4418 door_state |= DOOR_NO_DELAY;
4419 door_state &= ~DOOR_CLOSE_ALL;
4423 if (game_status == GAME_MODE_EDITOR)
4424 door_state |= DOOR_NO_DELAY;
4427 if (door_state & DOOR_ACTION)
4429 boolean handle_door_1 = (door_state & DOOR_ACTION_1);
4430 boolean handle_door_2 = (door_state & DOOR_ACTION_2);
4431 boolean door_1_done = (!handle_door_1);
4432 boolean door_2_done = (!handle_door_2);
4433 boolean door_1_vertical = (door_1.anim_mode & ANIM_VERTICAL);
4434 boolean door_2_vertical = (door_2.anim_mode & ANIM_VERTICAL);
4435 int door_size_1 = (door_1_vertical ? door_1.height : door_1.width);
4436 int door_size_2 = (door_2_vertical ? door_2.height : door_2.width);
4437 int max_door_size_1 = (door_1_vertical ? DYSIZE : DXSIZE);
4438 int max_door_size_2 = (door_2_vertical ? VYSIZE : VXSIZE);
4439 int door_size = (handle_door_1 ? door_size_1 : door_size_2);
4440 int max_door_size = (handle_door_1 ? max_door_size_1 : max_door_size_2);
4441 int door_skip = max_door_size - door_size;
4442 int end = door_size;
4443 int start = ((door_state & DOOR_NO_DELAY) ? end : 0);
4446 if (!(door_state & DOOR_NO_DELAY) && !setup.quick_doors)
4448 /* opening door sound has priority over simultaneously closing door */
4449 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
4450 PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
4451 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
4452 PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
4455 for (k = start; k <= end && !(door_1_done && door_2_done); k += stepsize)
4458 Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
4459 GC gc = bitmap->stored_clip_gc;
4461 if (door_state & DOOR_ACTION_1)
4463 int a = MIN(x * door_1.step_offset, end);
4464 int p = (door_state & DOOR_OPEN_1 ? end - a : a);
4465 int i = p + door_skip;
4467 if (door_1.anim_mode & ANIM_STATIC_PANEL)
4469 BlitBitmap(bitmap_db_door, drawto,
4470 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1,
4471 DXSIZE, DYSIZE, DX, DY);
4475 BlitBitmap(bitmap_db_door, drawto,
4476 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + p / 2,
4477 DXSIZE, DYSIZE - p / 2, DX, DY);
4479 ClearRectangle(drawto, DX, DY + DYSIZE - p / 2, DXSIZE, p / 2);
4482 if (door_1.anim_mode & ANIM_HORIZONTAL && x <= DXSIZE)
4484 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
4485 int dst1_x = DX + DXSIZE - i, dst1_y = DY;
4486 int src2_x = DXSIZE - i, src2_y = DOOR_GFX_PAGEY1;
4487 int dst2_x = DX, dst2_y = DY;
4488 int width = i, height = DYSIZE;
4490 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
4491 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
4494 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
4495 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
4498 else if (door_1.anim_mode & ANIM_VERTICAL && x <= DYSIZE)
4500 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
4501 int dst1_x = DX, dst1_y = DY + DYSIZE - i;
4502 int src2_x = 0, src2_y = DOOR_GFX_PAGEY1 + DYSIZE - i;
4503 int dst2_x = DX, dst2_y = DY;
4504 int width = DXSIZE, height = i;
4506 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
4507 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
4510 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
4511 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
4514 else if (x <= DXSIZE) /* ANIM_DEFAULT */
4516 int j = (door_1.anim_mode == ANIM_DEFAULT ? (DXSIZE - i) / 3 : 0);
4518 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
4519 BlitBitmapMasked(bitmap, drawto,
4520 DXSIZE, DOOR_GFX_PAGEY1, i, 77,
4521 DX + DXSIZE - i, DY + j);
4522 BlitBitmapMasked(bitmap, drawto,
4523 DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
4524 DX + DXSIZE - i, DY + 140 + j);
4525 SetClipOrigin(bitmap, gc, DX - DXSIZE + i,
4526 DY - (DOOR_GFX_PAGEY1 + j));
4527 BlitBitmapMasked(bitmap, drawto,
4528 DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
4530 BlitBitmapMasked(bitmap, drawto,
4531 DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
4534 BlitBitmapMasked(bitmap, drawto,
4535 DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
4537 BlitBitmapMasked(bitmap, drawto,
4538 DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
4540 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
4541 BlitBitmapMasked(bitmap, drawto,
4542 DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
4543 DX + DXSIZE - i, DY + 77 + j);
4544 BlitBitmapMasked(bitmap, drawto,
4545 DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
4546 DX + DXSIZE - i, DY + 203 + j);
4549 redraw_mask |= REDRAW_DOOR_1;
4550 door_1_done = (a == end);
4553 if (door_state & DOOR_ACTION_2)
4555 int a = MIN(x * door_2.step_offset, door_size);
4556 int p = (door_state & DOOR_OPEN_2 ? door_size - a : a);
4557 int i = p + door_skip;
4559 if (door_2.anim_mode & ANIM_STATIC_PANEL)
4561 BlitBitmap(bitmap_db_door, drawto,
4562 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2,
4563 VXSIZE, VYSIZE, VX, VY);
4565 else if (x <= VYSIZE)
4567 BlitBitmap(bitmap_db_door, drawto,
4568 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + p / 2,
4569 VXSIZE, VYSIZE - p / 2, VX, VY);
4571 ClearRectangle(drawto, VX, VY + VYSIZE - p / 2, VXSIZE, p / 2);
4574 if (door_2.anim_mode & ANIM_HORIZONTAL && x <= VXSIZE)
4576 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
4577 int dst1_x = VX + VXSIZE - i, dst1_y = VY;
4578 int src2_x = VXSIZE - i, src2_y = DOOR_GFX_PAGEY2;
4579 int dst2_x = VX, dst2_y = VY;
4580 int width = i, height = VYSIZE;
4582 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
4583 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
4586 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
4587 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
4590 else if (door_2.anim_mode & ANIM_VERTICAL && x <= VYSIZE)
4592 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
4593 int dst1_x = VX, dst1_y = VY + VYSIZE - i;
4594 int src2_x = 0, src2_y = DOOR_GFX_PAGEY2 + VYSIZE - i;
4595 int dst2_x = VX, dst2_y = VY;
4596 int width = VXSIZE, height = i;
4598 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
4599 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
4602 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
4603 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
4606 else if (x <= VXSIZE) /* ANIM_DEFAULT */
4608 int j = (door_2.anim_mode == ANIM_DEFAULT ? (VXSIZE - i) / 3 : 0);
4610 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
4611 BlitBitmapMasked(bitmap, drawto,
4612 VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
4613 VX + VXSIZE - i, VY + j);
4614 SetClipOrigin(bitmap, gc,
4615 VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
4616 BlitBitmapMasked(bitmap, drawto,
4617 VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
4620 BlitBitmapMasked(bitmap, drawto,
4621 VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
4622 i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
4623 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
4624 BlitBitmapMasked(bitmap, drawto,
4625 VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
4627 VX + VXSIZE - i, VY + VYSIZE / 2 + j);
4630 redraw_mask |= REDRAW_DOOR_2;
4631 door_2_done = (a == VXSIZE);
4634 if (!(door_state & DOOR_NO_DELAY))
4638 if (game_status == GAME_MODE_MAIN)
4641 WaitUntilDelayReached(&door_delay, door_delay_value);
4646 if (door_state & DOOR_ACTION_1)
4647 door1 = door_state & DOOR_ACTION_1;
4648 if (door_state & DOOR_ACTION_2)
4649 door2 = door_state & DOOR_ACTION_2;
4651 return (door1 | door2);
4654 void DrawSpecialEditorDoor()
4656 /* draw bigger toolbox window */
4657 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
4658 DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
4660 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
4661 EX - 6, VY - 4, EXSIZE + 12, EYSIZE - VYSIZE + 4,
4664 redraw_mask |= REDRAW_ALL;
4667 void UndrawSpecialEditorDoor()
4669 /* draw normal tape recorder window */
4670 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
4671 EX - 6, EY - 12, EXSIZE + 12, EYSIZE - VYSIZE + 12,
4674 redraw_mask |= REDRAW_ALL;
4678 /* ---------- new tool button stuff ---------------------------------------- */
4685 struct TextPosInfo *pos;
4688 } toolbutton_info[NUM_TOOL_BUTTONS] =
4691 IMG_REQUEST_BUTTON_GFX_YES, &request.button.yes,
4692 TOOL_CTRL_ID_YES, "yes"
4695 IMG_REQUEST_BUTTON_GFX_NO, &request.button.no,
4696 TOOL_CTRL_ID_NO, "no"
4699 IMG_REQUEST_BUTTON_GFX_CONFIRM, &request.button.confirm,
4700 TOOL_CTRL_ID_CONFIRM, "confirm"
4703 IMG_REQUEST_BUTTON_GFX_PLAYER_1, &request.button.player_1,
4704 TOOL_CTRL_ID_PLAYER_1, "player 1"
4707 IMG_REQUEST_BUTTON_GFX_PLAYER_2, &request.button.player_2,
4708 TOOL_CTRL_ID_PLAYER_2, "player 2"
4711 IMG_REQUEST_BUTTON_GFX_PLAYER_3, &request.button.player_3,
4712 TOOL_CTRL_ID_PLAYER_3, "player 3"
4715 IMG_REQUEST_BUTTON_GFX_PLAYER_4, &request.button.player_4,
4716 TOOL_CTRL_ID_PLAYER_4, "player 4"
4720 void CreateToolButtons()
4724 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4726 struct GraphicInfo *gfx = &graphic_info[toolbutton_info[i].graphic];
4727 struct TextPosInfo *pos = toolbutton_info[i].pos;
4728 struct GadgetInfo *gi;
4729 Bitmap *deco_bitmap = None;
4730 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
4731 unsigned int event_mask = GD_EVENT_RELEASED;
4732 int gd_x = gfx->src_x;
4733 int gd_y = gfx->src_y;
4734 int gd_xp = gfx->src_x + gfx->pressed_xoffset;
4735 int gd_yp = gfx->src_y + gfx->pressed_yoffset;
4738 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
4740 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
4742 getSizedGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr), 0,
4743 pos->size, &deco_bitmap, &deco_x, &deco_y);
4744 deco_xpos = (gfx->width - pos->size) / 2;
4745 deco_ypos = (gfx->height - pos->size) / 2;
4748 gi = CreateGadget(GDI_CUSTOM_ID, id,
4749 GDI_INFO_TEXT, toolbutton_info[i].infotext,
4752 GDI_WIDTH, gfx->width,
4753 GDI_HEIGHT, gfx->height,
4754 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
4755 GDI_STATE, GD_BUTTON_UNPRESSED,
4756 GDI_DESIGN_UNPRESSED, gfx->bitmap, gd_x, gd_y,
4757 GDI_DESIGN_PRESSED, gfx->bitmap, gd_xp, gd_yp,
4758 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
4759 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
4760 GDI_DECORATION_SIZE, pos->size, pos->size,
4761 GDI_DECORATION_SHIFTING, 1, 1,
4762 GDI_DIRECT_DRAW, FALSE,
4763 GDI_EVENT_MASK, event_mask,
4764 GDI_CALLBACK_ACTION, HandleToolButtons,
4768 Error(ERR_EXIT, "cannot create gadget");
4770 tool_gadget[id] = gi;
4776 /* graphic position values for tool buttons */
4777 #define TOOL_BUTTON_YES_XPOS 2
4778 #define TOOL_BUTTON_YES_YPOS 250
4779 #define TOOL_BUTTON_YES_GFX_YPOS 0
4780 #define TOOL_BUTTON_YES_XSIZE 46
4781 #define TOOL_BUTTON_YES_YSIZE 28
4782 #define TOOL_BUTTON_NO_XPOS 52
4783 #define TOOL_BUTTON_NO_YPOS TOOL_BUTTON_YES_YPOS
4784 #define TOOL_BUTTON_NO_GFX_YPOS TOOL_BUTTON_YES_GFX_YPOS
4785 #define TOOL_BUTTON_NO_XSIZE TOOL_BUTTON_YES_XSIZE
4786 #define TOOL_BUTTON_NO_YSIZE TOOL_BUTTON_YES_YSIZE
4787 #define TOOL_BUTTON_CONFIRM_XPOS TOOL_BUTTON_YES_XPOS
4788 #define TOOL_BUTTON_CONFIRM_YPOS TOOL_BUTTON_YES_YPOS
4789 #define TOOL_BUTTON_CONFIRM_GFX_YPOS 30
4790 #define TOOL_BUTTON_CONFIRM_XSIZE 96
4791 #define TOOL_BUTTON_CONFIRM_YSIZE TOOL_BUTTON_YES_YSIZE
4792 #define TOOL_BUTTON_PLAYER_XSIZE 30
4793 #define TOOL_BUTTON_PLAYER_YSIZE 30
4794 #define TOOL_BUTTON_PLAYER_GFX_XPOS 5
4795 #define TOOL_BUTTON_PLAYER_GFX_YPOS 185
4796 #define TOOL_BUTTON_PLAYER_XPOS (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
4797 #define TOOL_BUTTON_PLAYER_YPOS (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
4798 #define TOOL_BUTTON_PLAYER1_XPOS (TOOL_BUTTON_PLAYER_XPOS \
4799 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
4800 #define TOOL_BUTTON_PLAYER2_XPOS (TOOL_BUTTON_PLAYER_XPOS \
4801 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
4802 #define TOOL_BUTTON_PLAYER3_XPOS (TOOL_BUTTON_PLAYER_XPOS \
4803 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
4804 #define TOOL_BUTTON_PLAYER4_XPOS (TOOL_BUTTON_PLAYER_XPOS \
4805 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
4806 #define TOOL_BUTTON_PLAYER1_YPOS (TOOL_BUTTON_PLAYER_YPOS \
4807 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
4808 #define TOOL_BUTTON_PLAYER2_YPOS (TOOL_BUTTON_PLAYER_YPOS \
4809 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
4810 #define TOOL_BUTTON_PLAYER3_YPOS (TOOL_BUTTON_PLAYER_YPOS \
4811 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
4812 #define TOOL_BUTTON_PLAYER4_YPOS (TOOL_BUTTON_PLAYER_YPOS \
4813 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
4822 } toolbutton_info[NUM_TOOL_BUTTONS] =
4825 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_GFX_YPOS,
4826 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_YPOS,
4827 TOOL_BUTTON_YES_XSIZE, TOOL_BUTTON_YES_YSIZE,
4832 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_GFX_YPOS,
4833 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_YPOS,
4834 TOOL_BUTTON_NO_XSIZE, TOOL_BUTTON_NO_YSIZE,
4839 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_GFX_YPOS,
4840 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_YPOS,
4841 TOOL_BUTTON_CONFIRM_XSIZE, TOOL_BUTTON_CONFIRM_YSIZE,
4842 TOOL_CTRL_ID_CONFIRM,
4846 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
4847 TOOL_BUTTON_PLAYER1_XPOS, TOOL_BUTTON_PLAYER1_YPOS,
4848 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
4849 TOOL_CTRL_ID_PLAYER_1,
4853 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
4854 TOOL_BUTTON_PLAYER2_XPOS, TOOL_BUTTON_PLAYER2_YPOS,
4855 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
4856 TOOL_CTRL_ID_PLAYER_2,
4860 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
4861 TOOL_BUTTON_PLAYER3_XPOS, TOOL_BUTTON_PLAYER3_YPOS,
4862 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
4863 TOOL_CTRL_ID_PLAYER_3,
4867 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
4868 TOOL_BUTTON_PLAYER4_XPOS, TOOL_BUTTON_PLAYER4_YPOS,
4869 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
4870 TOOL_CTRL_ID_PLAYER_4,
4875 void CreateToolButtons()
4879 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4881 Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
4882 Bitmap *deco_bitmap = None;
4883 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
4884 struct GadgetInfo *gi;
4885 unsigned int event_mask;
4886 int gd_xoffset, gd_yoffset;
4887 int gd_x1, gd_x2, gd_y;
4890 event_mask = GD_EVENT_RELEASED;
4892 gd_xoffset = toolbutton_info[i].xpos;
4893 gd_yoffset = toolbutton_info[i].ypos;
4894 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
4895 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
4896 gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
4898 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
4900 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
4902 getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr),
4903 &deco_bitmap, &deco_x, &deco_y);
4904 deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
4905 deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
4908 gi = CreateGadget(GDI_CUSTOM_ID, id,
4909 GDI_INFO_TEXT, toolbutton_info[i].infotext,
4910 GDI_X, DX + toolbutton_info[i].x,
4911 GDI_Y, DY + toolbutton_info[i].y,
4912 GDI_WIDTH, toolbutton_info[i].width,
4913 GDI_HEIGHT, toolbutton_info[i].height,
4914 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
4915 GDI_STATE, GD_BUTTON_UNPRESSED,
4916 GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
4917 GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
4918 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
4919 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
4920 GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
4921 GDI_DECORATION_SHIFTING, 1, 1,
4922 GDI_DIRECT_DRAW, FALSE,
4923 GDI_EVENT_MASK, event_mask,
4924 GDI_CALLBACK_ACTION, HandleToolButtons,
4928 Error(ERR_EXIT, "cannot create gadget");
4930 tool_gadget[id] = gi;
4936 void FreeToolButtons()
4940 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4941 FreeGadget(tool_gadget[i]);
4944 static void UnmapToolButtons()
4948 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4949 UnmapGadget(tool_gadget[i]);
4952 static void HandleToolButtons(struct GadgetInfo *gi)
4954 request_gadget_id = gi->custom_id;
4957 static struct Mapping_EM_to_RND_object
4960 boolean is_rnd_to_em_mapping; /* unique mapping EM <-> RND */
4961 boolean is_backside; /* backside of moving element */
4967 em_object_mapping_list[] =
4970 Xblank, TRUE, FALSE,
4974 Yacid_splash_eB, FALSE, FALSE,
4975 EL_ACID_SPLASH_RIGHT, -1, -1
4978 Yacid_splash_wB, FALSE, FALSE,
4979 EL_ACID_SPLASH_LEFT, -1, -1
4982 #ifdef EM_ENGINE_BAD_ROLL
4984 Xstone_force_e, FALSE, FALSE,
4985 EL_ROCK, -1, MV_BIT_RIGHT
4988 Xstone_force_w, FALSE, FALSE,
4989 EL_ROCK, -1, MV_BIT_LEFT
4992 Xnut_force_e, FALSE, FALSE,
4993 EL_NUT, -1, MV_BIT_RIGHT
4996 Xnut_force_w, FALSE, FALSE,
4997 EL_NUT, -1, MV_BIT_LEFT
5000 Xspring_force_e, FALSE, FALSE,
5001 EL_SPRING, -1, MV_BIT_RIGHT
5004 Xspring_force_w, FALSE, FALSE,
5005 EL_SPRING, -1, MV_BIT_LEFT
5008 Xemerald_force_e, FALSE, FALSE,
5009 EL_EMERALD, -1, MV_BIT_RIGHT
5012 Xemerald_force_w, FALSE, FALSE,
5013 EL_EMERALD, -1, MV_BIT_LEFT
5016 Xdiamond_force_e, FALSE, FALSE,
5017 EL_DIAMOND, -1, MV_BIT_RIGHT
5020 Xdiamond_force_w, FALSE, FALSE,
5021 EL_DIAMOND, -1, MV_BIT_LEFT
5024 Xbomb_force_e, FALSE, FALSE,
5025 EL_BOMB, -1, MV_BIT_RIGHT
5028 Xbomb_force_w, FALSE, FALSE,
5029 EL_BOMB, -1, MV_BIT_LEFT
5031 #endif /* EM_ENGINE_BAD_ROLL */
5034 Xstone, TRUE, FALSE,
5038 Xstone_pause, FALSE, FALSE,
5042 Xstone_fall, FALSE, FALSE,
5046 Ystone_s, FALSE, FALSE,
5047 EL_ROCK, ACTION_FALLING, -1
5050 Ystone_sB, FALSE, TRUE,
5051 EL_ROCK, ACTION_FALLING, -1
5054 Ystone_e, FALSE, FALSE,
5055 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
5058 Ystone_eB, FALSE, TRUE,
5059 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
5062 Ystone_w, FALSE, FALSE,
5063 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
5066 Ystone_wB, FALSE, TRUE,
5067 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
5074 Xnut_pause, FALSE, FALSE,
5078 Xnut_fall, FALSE, FALSE,
5082 Ynut_s, FALSE, FALSE,
5083 EL_NUT, ACTION_FALLING, -1
5086 Ynut_sB, FALSE, TRUE,
5087 EL_NUT, ACTION_FALLING, -1
5090 Ynut_e, FALSE, FALSE,
5091 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
5094 Ynut_eB, FALSE, TRUE,
5095 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
5098 Ynut_w, FALSE, FALSE,
5099 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
5102 Ynut_wB, FALSE, TRUE,
5103 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
5106 Xbug_n, TRUE, FALSE,
5110 Xbug_e, TRUE, FALSE,
5111 EL_BUG_RIGHT, -1, -1
5114 Xbug_s, TRUE, FALSE,
5118 Xbug_w, TRUE, FALSE,
5122 Xbug_gon, FALSE, FALSE,
5126 Xbug_goe, FALSE, FALSE,
5127 EL_BUG_RIGHT, -1, -1
5130 Xbug_gos, FALSE, FALSE,
5134 Xbug_gow, FALSE, FALSE,
5138 Ybug_n, FALSE, FALSE,
5139 EL_BUG, ACTION_MOVING, MV_BIT_UP
5142 Ybug_nB, FALSE, TRUE,
5143 EL_BUG, ACTION_MOVING, MV_BIT_UP
5146 Ybug_e, FALSE, FALSE,
5147 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
5150 Ybug_eB, FALSE, TRUE,
5151 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
5154 Ybug_s, FALSE, FALSE,
5155 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
5158 Ybug_sB, FALSE, TRUE,
5159 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
5162 Ybug_w, FALSE, FALSE,
5163 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
5166 Ybug_wB, FALSE, TRUE,
5167 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
5170 Ybug_w_n, FALSE, FALSE,
5171 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
5174 Ybug_n_e, FALSE, FALSE,
5175 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
5178 Ybug_e_s, FALSE, FALSE,
5179 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
5182 Ybug_s_w, FALSE, FALSE,
5183 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
5186 Ybug_e_n, FALSE, FALSE,
5187 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
5190 Ybug_s_e, FALSE, FALSE,
5191 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
5194 Ybug_w_s, FALSE, FALSE,
5195 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
5198 Ybug_n_w, FALSE, FALSE,
5199 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
5202 Ybug_stone, FALSE, FALSE,
5203 EL_BUG, ACTION_SMASHED_BY_ROCK, -1
5206 Ybug_spring, FALSE, FALSE,
5207 EL_BUG, ACTION_SMASHED_BY_SPRING, -1
5210 Xtank_n, TRUE, FALSE,
5211 EL_SPACESHIP_UP, -1, -1
5214 Xtank_e, TRUE, FALSE,
5215 EL_SPACESHIP_RIGHT, -1, -1
5218 Xtank_s, TRUE, FALSE,
5219 EL_SPACESHIP_DOWN, -1, -1
5222 Xtank_w, TRUE, FALSE,
5223 EL_SPACESHIP_LEFT, -1, -1
5226 Xtank_gon, FALSE, FALSE,
5227 EL_SPACESHIP_UP, -1, -1
5230 Xtank_goe, FALSE, FALSE,
5231 EL_SPACESHIP_RIGHT, -1, -1
5234 Xtank_gos, FALSE, FALSE,
5235 EL_SPACESHIP_DOWN, -1, -1
5238 Xtank_gow, FALSE, FALSE,
5239 EL_SPACESHIP_LEFT, -1, -1
5242 Ytank_n, FALSE, FALSE,
5243 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
5246 Ytank_nB, FALSE, TRUE,
5247 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
5250 Ytank_e, FALSE, FALSE,
5251 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
5254 Ytank_eB, FALSE, TRUE,
5255 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
5258 Ytank_s, FALSE, FALSE,
5259 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
5262 Ytank_sB, FALSE, TRUE,
5263 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
5266 Ytank_w, FALSE, FALSE,
5267 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
5270 Ytank_wB, FALSE, TRUE,
5271 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
5274 Ytank_w_n, FALSE, FALSE,
5275 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
5278 Ytank_n_e, FALSE, FALSE,
5279 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
5282 Ytank_e_s, FALSE, FALSE,
5283 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
5286 Ytank_s_w, FALSE, FALSE,
5287 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
5290 Ytank_e_n, FALSE, FALSE,
5291 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
5294 Ytank_s_e, FALSE, FALSE,
5295 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
5298 Ytank_w_s, FALSE, FALSE,
5299 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
5302 Ytank_n_w, FALSE, FALSE,
5303 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
5306 Ytank_stone, FALSE, FALSE,
5307 EL_SPACESHIP, ACTION_SMASHED_BY_ROCK, -1
5310 Ytank_spring, FALSE, FALSE,
5311 EL_SPACESHIP, ACTION_SMASHED_BY_SPRING, -1
5314 Xandroid, TRUE, FALSE,
5315 EL_EMC_ANDROID, ACTION_ACTIVE, -1
5318 Xandroid_1_n, FALSE, FALSE,
5319 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
5322 Xandroid_2_n, FALSE, FALSE,
5323 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
5326 Xandroid_1_e, FALSE, FALSE,
5327 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
5330 Xandroid_2_e, FALSE, FALSE,
5331 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
5334 Xandroid_1_w, FALSE, FALSE,
5335 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
5338 Xandroid_2_w, FALSE, FALSE,
5339 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
5342 Xandroid_1_s, FALSE, FALSE,
5343 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
5346 Xandroid_2_s, FALSE, FALSE,
5347 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
5350 Yandroid_n, FALSE, FALSE,
5351 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
5354 Yandroid_nB, FALSE, TRUE,
5355 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
5358 Yandroid_ne, FALSE, FALSE,
5359 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPRIGHT
5362 Yandroid_neB, FALSE, TRUE,
5363 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPRIGHT
5366 Yandroid_e, FALSE, FALSE,
5367 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
5370 Yandroid_eB, FALSE, TRUE,
5371 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
5374 Yandroid_se, FALSE, FALSE,
5375 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNRIGHT
5378 Yandroid_seB, FALSE, TRUE,
5379 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNRIGHT
5382 Yandroid_s, FALSE, FALSE,
5383 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
5386 Yandroid_sB, FALSE, TRUE,
5387 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
5390 Yandroid_sw, FALSE, FALSE,
5391 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNLEFT
5394 Yandroid_swB, FALSE, TRUE,
5395 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNLEFT
5398 Yandroid_w, FALSE, FALSE,
5399 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
5402 Yandroid_wB, FALSE, TRUE,
5403 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
5406 Yandroid_nw, FALSE, FALSE,
5407 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPLEFT
5410 Yandroid_nwB, FALSE, TRUE,
5411 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPLEFT
5414 Xspring, TRUE, FALSE,
5418 Xspring_pause, FALSE, FALSE,
5422 Xspring_e, FALSE, FALSE,
5426 Xspring_w, FALSE, FALSE,
5430 Xspring_fall, FALSE, FALSE,
5434 Yspring_s, FALSE, FALSE,
5435 EL_SPRING, ACTION_FALLING, -1
5438 Yspring_sB, FALSE, TRUE,
5439 EL_SPRING, ACTION_FALLING, -1
5442 Yspring_e, FALSE, FALSE,
5443 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
5446 Yspring_eB, FALSE, TRUE,
5447 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
5450 Yspring_w, FALSE, FALSE,
5451 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
5454 Yspring_wB, FALSE, TRUE,
5455 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
5458 Yspring_kill_e, FALSE, FALSE,
5459 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
5462 Yspring_kill_eB, FALSE, TRUE,
5463 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
5466 Yspring_kill_w, FALSE, FALSE,
5467 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
5470 Yspring_kill_wB, FALSE, TRUE,
5471 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
5474 Xeater_n, TRUE, FALSE,
5475 EL_YAMYAM_UP, -1, -1
5478 Xeater_e, TRUE, FALSE,
5479 EL_YAMYAM_RIGHT, -1, -1
5482 Xeater_w, TRUE, FALSE,
5483 EL_YAMYAM_LEFT, -1, -1
5486 Xeater_s, TRUE, FALSE,
5487 EL_YAMYAM_DOWN, -1, -1
5490 Yeater_n, FALSE, FALSE,
5491 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
5494 Yeater_nB, FALSE, TRUE,
5495 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
5498 Yeater_e, FALSE, FALSE,
5499 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
5502 Yeater_eB, FALSE, TRUE,
5503 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
5506 Yeater_s, FALSE, FALSE,
5507 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
5510 Yeater_sB, FALSE, TRUE,
5511 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
5514 Yeater_w, FALSE, FALSE,
5515 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
5518 Yeater_wB, FALSE, TRUE,
5519 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
5522 Yeater_stone, FALSE, FALSE,
5523 EL_YAMYAM, ACTION_SMASHED_BY_ROCK, -1
5526 Yeater_spring, FALSE, FALSE,
5527 EL_YAMYAM, ACTION_SMASHED_BY_SPRING, -1
5530 Xalien, TRUE, FALSE,
5534 Xalien_pause, FALSE, FALSE,
5538 Yalien_n, FALSE, FALSE,
5539 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
5542 Yalien_nB, FALSE, TRUE,
5543 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
5546 Yalien_e, FALSE, FALSE,
5547 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
5550 Yalien_eB, FALSE, TRUE,
5551 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
5554 Yalien_s, FALSE, FALSE,
5555 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
5558 Yalien_sB, FALSE, TRUE,
5559 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
5562 Yalien_w, FALSE, FALSE,
5563 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
5566 Yalien_wB, FALSE, TRUE,
5567 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
5570 Yalien_stone, FALSE, FALSE,
5571 EL_ROBOT, ACTION_SMASHED_BY_ROCK, -1
5574 Yalien_spring, FALSE, FALSE,
5575 EL_ROBOT, ACTION_SMASHED_BY_SPRING, -1
5578 Xemerald, TRUE, FALSE,
5582 Xemerald_pause, FALSE, FALSE,
5586 Xemerald_fall, FALSE, FALSE,
5590 Xemerald_shine, FALSE, FALSE,
5591 EL_EMERALD, ACTION_TWINKLING, -1
5594 Yemerald_s, FALSE, FALSE,
5595 EL_EMERALD, ACTION_FALLING, -1
5598 Yemerald_sB, FALSE, TRUE,
5599 EL_EMERALD, ACTION_FALLING, -1
5602 Yemerald_e, FALSE, FALSE,
5603 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
5606 Yemerald_eB, FALSE, TRUE,
5607 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
5610 Yemerald_w, FALSE, FALSE,
5611 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
5614 Yemerald_wB, FALSE, TRUE,
5615 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
5618 Yemerald_eat, FALSE, FALSE,
5619 EL_EMERALD, ACTION_COLLECTING, -1
5622 Yemerald_stone, FALSE, FALSE,
5623 EL_NUT, ACTION_BREAKING, -1
5626 Xdiamond, TRUE, FALSE,
5630 Xdiamond_pause, FALSE, FALSE,
5634 Xdiamond_fall, FALSE, FALSE,
5638 Xdiamond_shine, FALSE, FALSE,
5639 EL_DIAMOND, ACTION_TWINKLING, -1
5642 Ydiamond_s, FALSE, FALSE,
5643 EL_DIAMOND, ACTION_FALLING, -1
5646 Ydiamond_sB, FALSE, TRUE,
5647 EL_DIAMOND, ACTION_FALLING, -1
5650 Ydiamond_e, FALSE, FALSE,
5651 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
5654 Ydiamond_eB, FALSE, TRUE,
5655 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
5658 Ydiamond_w, FALSE, FALSE,
5659 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
5662 Ydiamond_wB, FALSE, TRUE,
5663 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
5666 Ydiamond_eat, FALSE, FALSE,
5667 EL_DIAMOND, ACTION_COLLECTING, -1
5670 Ydiamond_stone, FALSE, FALSE,
5671 EL_DIAMOND, ACTION_SMASHED_BY_ROCK, -1
5674 Xdrip_fall, TRUE, FALSE,
5675 EL_AMOEBA_DROP, -1, -1
5678 Xdrip_stretch, FALSE, FALSE,
5679 EL_AMOEBA_DROP, ACTION_FALLING, -1
5682 Xdrip_stretchB, FALSE, TRUE,
5683 EL_AMOEBA_DROP, ACTION_FALLING, -1
5686 Xdrip_eat, FALSE, FALSE,
5687 EL_AMOEBA_DROP, ACTION_GROWING, -1
5690 Ydrip_s1, FALSE, FALSE,
5691 EL_AMOEBA_DROP, ACTION_FALLING, -1
5694 Ydrip_s1B, FALSE, TRUE,
5695 EL_AMOEBA_DROP, ACTION_FALLING, -1
5698 Ydrip_s2, FALSE, FALSE,
5699 EL_AMOEBA_DROP, ACTION_FALLING, -1
5702 Ydrip_s2B, FALSE, TRUE,
5703 EL_AMOEBA_DROP, ACTION_FALLING, -1
5710 Xbomb_pause, FALSE, FALSE,
5714 Xbomb_fall, FALSE, FALSE,
5718 Ybomb_s, FALSE, FALSE,
5719 EL_BOMB, ACTION_FALLING, -1
5722 Ybomb_sB, FALSE, TRUE,
5723 EL_BOMB, ACTION_FALLING, -1
5726 Ybomb_e, FALSE, FALSE,
5727 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
5730 Ybomb_eB, FALSE, TRUE,
5731 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
5734 Ybomb_w, FALSE, FALSE,
5735 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
5738 Ybomb_wB, FALSE, TRUE,
5739 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
5742 Ybomb_eat, FALSE, FALSE,
5743 EL_BOMB, ACTION_ACTIVATING, -1
5746 Xballoon, TRUE, FALSE,
5750 Yballoon_n, FALSE, FALSE,
5751 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
5754 Yballoon_nB, FALSE, TRUE,
5755 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
5758 Yballoon_e, FALSE, FALSE,
5759 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
5762 Yballoon_eB, FALSE, TRUE,
5763 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
5766 Yballoon_s, FALSE, FALSE,
5767 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
5770 Yballoon_sB, FALSE, TRUE,
5771 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
5774 Yballoon_w, FALSE, FALSE,
5775 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
5778 Yballoon_wB, FALSE, TRUE,
5779 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
5782 Xgrass, TRUE, FALSE,
5783 EL_EMC_GRASS, -1, -1
5786 Ygrass_nB, FALSE, FALSE,
5787 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_UP
5790 Ygrass_eB, FALSE, FALSE,
5791 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_RIGHT
5794 Ygrass_sB, FALSE, FALSE,
5795 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_DOWN
5798 Ygrass_wB, FALSE, FALSE,
5799 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_LEFT
5806 Ydirt_nB, FALSE, FALSE,
5807 EL_SAND, ACTION_DIGGING, MV_BIT_UP
5810 Ydirt_eB, FALSE, FALSE,
5811 EL_SAND, ACTION_DIGGING, MV_BIT_RIGHT
5814 Ydirt_sB, FALSE, FALSE,
5815 EL_SAND, ACTION_DIGGING, MV_BIT_DOWN
5818 Ydirt_wB, FALSE, FALSE,
5819 EL_SAND, ACTION_DIGGING, MV_BIT_LEFT
5822 Xacid_ne, TRUE, FALSE,
5823 EL_ACID_POOL_TOPRIGHT, -1, -1
5826 Xacid_se, TRUE, FALSE,
5827 EL_ACID_POOL_BOTTOMRIGHT, -1, -1
5830 Xacid_s, TRUE, FALSE,
5831 EL_ACID_POOL_BOTTOM, -1, -1
5834 Xacid_sw, TRUE, FALSE,
5835 EL_ACID_POOL_BOTTOMLEFT, -1, -1
5838 Xacid_nw, TRUE, FALSE,
5839 EL_ACID_POOL_TOPLEFT, -1, -1
5842 Xacid_1, TRUE, FALSE,
5846 Xacid_2, FALSE, FALSE,
5850 Xacid_3, FALSE, FALSE,
5854 Xacid_4, FALSE, FALSE,
5858 Xacid_5, FALSE, FALSE,
5862 Xacid_6, FALSE, FALSE,
5866 Xacid_7, FALSE, FALSE,
5870 Xacid_8, FALSE, FALSE,
5874 Xball_1, TRUE, FALSE,
5875 EL_EMC_MAGIC_BALL, -1, -1
5878 Xball_1B, FALSE, FALSE,
5879 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
5882 Xball_2, FALSE, FALSE,
5883 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
5886 Xball_2B, FALSE, FALSE,
5887 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
5890 Yball_eat, FALSE, FALSE,
5891 EL_EMC_MAGIC_BALL, ACTION_DROPPING, -1
5894 Ykey_1_eat, FALSE, FALSE,
5895 EL_EM_KEY_1, ACTION_COLLECTING, -1
5898 Ykey_2_eat, FALSE, FALSE,
5899 EL_EM_KEY_2, ACTION_COLLECTING, -1
5902 Ykey_3_eat, FALSE, FALSE,
5903 EL_EM_KEY_3, ACTION_COLLECTING, -1
5906 Ykey_4_eat, FALSE, FALSE,
5907 EL_EM_KEY_4, ACTION_COLLECTING, -1
5910 Ykey_5_eat, FALSE, FALSE,
5911 EL_EMC_KEY_5, ACTION_COLLECTING, -1
5914 Ykey_6_eat, FALSE, FALSE,
5915 EL_EMC_KEY_6, ACTION_COLLECTING, -1
5918 Ykey_7_eat, FALSE, FALSE,
5919 EL_EMC_KEY_7, ACTION_COLLECTING, -1
5922 Ykey_8_eat, FALSE, FALSE,
5923 EL_EMC_KEY_8, ACTION_COLLECTING, -1
5926 Ylenses_eat, FALSE, FALSE,
5927 EL_EMC_LENSES, ACTION_COLLECTING, -1
5930 Ymagnify_eat, FALSE, FALSE,
5931 EL_EMC_MAGNIFIER, ACTION_COLLECTING, -1
5934 Ygrass_eat, FALSE, FALSE,
5935 EL_EMC_GRASS, ACTION_SNAPPING, -1
5938 Ydirt_eat, FALSE, FALSE,
5939 EL_SAND, ACTION_SNAPPING, -1
5942 Xgrow_ns, TRUE, FALSE,
5943 EL_EXPANDABLE_WALL_VERTICAL, -1, -1
5946 Ygrow_ns_eat, FALSE, FALSE,
5947 EL_EXPANDABLE_WALL_VERTICAL, ACTION_GROWING, -1
5950 Xgrow_ew, TRUE, FALSE,
5951 EL_EXPANDABLE_WALL_HORIZONTAL, -1, -1
5954 Ygrow_ew_eat, FALSE, FALSE,
5955 EL_EXPANDABLE_WALL_HORIZONTAL, ACTION_GROWING, -1
5958 Xwonderwall, TRUE, FALSE,
5959 EL_MAGIC_WALL, -1, -1
5962 XwonderwallB, FALSE, FALSE,
5963 EL_MAGIC_WALL, ACTION_ACTIVE, -1
5966 Xamoeba_1, TRUE, FALSE,
5967 EL_AMOEBA_DRY, ACTION_OTHER, -1
5970 Xamoeba_2, FALSE, FALSE,
5971 EL_AMOEBA_DRY, ACTION_OTHER, -1
5974 Xamoeba_3, FALSE, FALSE,
5975 EL_AMOEBA_DRY, ACTION_OTHER, -1
5978 Xamoeba_4, FALSE, FALSE,
5979 EL_AMOEBA_DRY, ACTION_OTHER, -1
5982 Xamoeba_5, TRUE, FALSE,
5983 EL_AMOEBA_WET, ACTION_OTHER, -1
5986 Xamoeba_6, FALSE, FALSE,
5987 EL_AMOEBA_WET, ACTION_OTHER, -1
5990 Xamoeba_7, FALSE, FALSE,
5991 EL_AMOEBA_WET, ACTION_OTHER, -1
5994 Xamoeba_8, FALSE, FALSE,
5995 EL_AMOEBA_WET, ACTION_OTHER, -1
5998 Xdoor_1, TRUE, FALSE,
5999 EL_EM_GATE_1, -1, -1
6002 Xdoor_2, TRUE, FALSE,
6003 EL_EM_GATE_2, -1, -1
6006 Xdoor_3, TRUE, FALSE,
6007 EL_EM_GATE_3, -1, -1
6010 Xdoor_4, TRUE, FALSE,
6011 EL_EM_GATE_4, -1, -1
6014 Xdoor_5, TRUE, FALSE,
6015 EL_EMC_GATE_5, -1, -1
6018 Xdoor_6, TRUE, FALSE,
6019 EL_EMC_GATE_6, -1, -1
6022 Xdoor_7, TRUE, FALSE,
6023 EL_EMC_GATE_7, -1, -1
6026 Xdoor_8, TRUE, FALSE,
6027 EL_EMC_GATE_8, -1, -1
6030 Xkey_1, TRUE, FALSE,
6034 Xkey_2, TRUE, FALSE,
6038 Xkey_3, TRUE, FALSE,
6042 Xkey_4, TRUE, FALSE,
6046 Xkey_5, TRUE, FALSE,
6047 EL_EMC_KEY_5, -1, -1
6050 Xkey_6, TRUE, FALSE,
6051 EL_EMC_KEY_6, -1, -1
6054 Xkey_7, TRUE, FALSE,
6055 EL_EMC_KEY_7, -1, -1
6058 Xkey_8, TRUE, FALSE,
6059 EL_EMC_KEY_8, -1, -1
6062 Xwind_n, TRUE, FALSE,
6063 EL_BALLOON_SWITCH_UP, -1, -1
6066 Xwind_e, TRUE, FALSE,
6067 EL_BALLOON_SWITCH_RIGHT, -1, -1
6070 Xwind_s, TRUE, FALSE,
6071 EL_BALLOON_SWITCH_DOWN, -1, -1
6074 Xwind_w, TRUE, FALSE,
6075 EL_BALLOON_SWITCH_LEFT, -1, -1
6078 Xwind_nesw, TRUE, FALSE,
6079 EL_BALLOON_SWITCH_ANY, -1, -1
6082 Xwind_stop, TRUE, FALSE,
6083 EL_BALLOON_SWITCH_NONE, -1, -1
6087 EL_EM_EXIT_CLOSED, -1, -1
6090 Xexit_1, TRUE, FALSE,
6091 EL_EM_EXIT_OPEN, -1, -1
6094 Xexit_2, FALSE, FALSE,
6095 EL_EM_EXIT_OPEN, -1, -1
6098 Xexit_3, FALSE, FALSE,
6099 EL_EM_EXIT_OPEN, -1, -1
6102 Xdynamite, TRUE, FALSE,
6103 EL_EM_DYNAMITE, -1, -1
6106 Ydynamite_eat, FALSE, FALSE,
6107 EL_EM_DYNAMITE, ACTION_COLLECTING, -1
6110 Xdynamite_1, TRUE, FALSE,
6111 EL_EM_DYNAMITE_ACTIVE, -1, -1
6114 Xdynamite_2, FALSE, FALSE,
6115 EL_EM_DYNAMITE_ACTIVE, -1, -1
6118 Xdynamite_3, FALSE, FALSE,
6119 EL_EM_DYNAMITE_ACTIVE, -1, -1
6122 Xdynamite_4, FALSE, FALSE,
6123 EL_EM_DYNAMITE_ACTIVE, -1, -1
6126 Xbumper, TRUE, FALSE,
6127 EL_EMC_SPRING_BUMPER, -1, -1
6130 XbumperB, FALSE, FALSE,
6131 EL_EMC_SPRING_BUMPER, ACTION_ACTIVE, -1
6134 Xwheel, TRUE, FALSE,
6135 EL_ROBOT_WHEEL, -1, -1
6138 XwheelB, FALSE, FALSE,
6139 EL_ROBOT_WHEEL, ACTION_ACTIVE, -1
6142 Xswitch, TRUE, FALSE,
6143 EL_EMC_MAGIC_BALL_SWITCH, -1, -1
6146 XswitchB, FALSE, FALSE,
6147 EL_EMC_MAGIC_BALL_SWITCH, ACTION_ACTIVE, -1
6151 EL_QUICKSAND_EMPTY, -1, -1
6154 Xsand_stone, TRUE, FALSE,
6155 EL_QUICKSAND_FULL, -1, -1
6158 Xsand_stonein_1, FALSE, TRUE,
6159 EL_ROCK, ACTION_FILLING, -1
6162 Xsand_stonein_2, FALSE, TRUE,
6163 EL_ROCK, ACTION_FILLING, -1
6166 Xsand_stonein_3, FALSE, TRUE,
6167 EL_ROCK, ACTION_FILLING, -1
6170 Xsand_stonein_4, FALSE, TRUE,
6171 EL_ROCK, ACTION_FILLING, -1
6175 Xsand_stonesand_1, FALSE, FALSE,
6176 EL_QUICKSAND_EMPTYING, -1, -1
6179 Xsand_stonesand_2, FALSE, FALSE,
6180 EL_QUICKSAND_EMPTYING, -1, -1
6183 Xsand_stonesand_3, FALSE, FALSE,
6184 EL_QUICKSAND_EMPTYING, -1, -1
6187 Xsand_stonesand_4, FALSE, FALSE,
6188 EL_QUICKSAND_EMPTYING, -1, -1
6191 Xsand_stonesand_quickout_1, FALSE, FALSE,
6192 EL_QUICKSAND_EMPTYING, -1, -1
6195 Xsand_stonesand_quickout_2, FALSE, FALSE,
6196 EL_QUICKSAND_EMPTYING, -1, -1
6200 Xsand_stonesand_1, FALSE, FALSE,
6201 EL_QUICKSAND_FULL, -1, -1
6204 Xsand_stonesand_2, FALSE, FALSE,
6205 EL_QUICKSAND_FULL, -1, -1
6208 Xsand_stonesand_3, FALSE, FALSE,
6209 EL_QUICKSAND_FULL, -1, -1
6212 Xsand_stonesand_4, FALSE, FALSE,
6213 EL_QUICKSAND_FULL, -1, -1
6217 Xsand_stoneout_1, FALSE, FALSE,
6218 EL_ROCK, ACTION_EMPTYING, -1
6221 Xsand_stoneout_2, FALSE, FALSE,
6222 EL_ROCK, ACTION_EMPTYING, -1
6226 Xsand_sandstone_1, FALSE, FALSE,
6227 EL_QUICKSAND_FILLING, -1, -1
6230 Xsand_sandstone_2, FALSE, FALSE,
6231 EL_QUICKSAND_FILLING, -1, -1
6234 Xsand_sandstone_3, FALSE, FALSE,
6235 EL_QUICKSAND_FILLING, -1, -1
6238 Xsand_sandstone_4, FALSE, FALSE,
6239 EL_QUICKSAND_FILLING, -1, -1
6243 Xsand_sandstone_1, FALSE, FALSE,
6244 EL_QUICKSAND_FULL, -1, -1
6247 Xsand_sandstone_2, FALSE, FALSE,
6248 EL_QUICKSAND_FULL, -1, -1
6251 Xsand_sandstone_3, FALSE, FALSE,
6252 EL_QUICKSAND_FULL, -1, -1
6255 Xsand_sandstone_4, FALSE, FALSE,
6256 EL_QUICKSAND_FULL, -1, -1
6260 Xplant, TRUE, FALSE,
6261 EL_EMC_PLANT, -1, -1
6264 Yplant, FALSE, FALSE,
6265 EL_EMC_PLANT, -1, -1
6268 Xlenses, TRUE, FALSE,
6269 EL_EMC_LENSES, -1, -1
6272 Xmagnify, TRUE, FALSE,
6273 EL_EMC_MAGNIFIER, -1, -1
6276 Xdripper, TRUE, FALSE,
6277 EL_EMC_DRIPPER, -1, -1
6280 XdripperB, FALSE, FALSE,
6281 EL_EMC_DRIPPER, ACTION_ACTIVE, -1
6284 Xfake_blank, TRUE, FALSE,
6285 EL_INVISIBLE_WALL, -1, -1
6288 Xfake_blankB, FALSE, FALSE,
6289 EL_INVISIBLE_WALL, ACTION_ACTIVE, -1
6292 Xfake_grass, TRUE, FALSE,
6293 EL_EMC_FAKE_GRASS, -1, -1
6296 Xfake_grassB, FALSE, FALSE,
6297 EL_EMC_FAKE_GRASS, ACTION_ACTIVE, -1
6300 Xfake_door_1, TRUE, FALSE,
6301 EL_EM_GATE_1_GRAY, -1, -1
6304 Xfake_door_2, TRUE, FALSE,
6305 EL_EM_GATE_2_GRAY, -1, -1
6308 Xfake_door_3, TRUE, FALSE,
6309 EL_EM_GATE_3_GRAY, -1, -1
6312 Xfake_door_4, TRUE, FALSE,
6313 EL_EM_GATE_4_GRAY, -1, -1
6316 Xfake_door_5, TRUE, FALSE,
6317 EL_EMC_GATE_5_GRAY, -1, -1
6320 Xfake_door_6, TRUE, FALSE,
6321 EL_EMC_GATE_6_GRAY, -1, -1
6324 Xfake_door_7, TRUE, FALSE,
6325 EL_EMC_GATE_7_GRAY, -1, -1
6328 Xfake_door_8, TRUE, FALSE,
6329 EL_EMC_GATE_8_GRAY, -1, -1
6332 Xfake_acid_1, TRUE, FALSE,
6333 EL_EMC_FAKE_ACID, -1, -1
6336 Xfake_acid_2, FALSE, FALSE,
6337 EL_EMC_FAKE_ACID, -1, -1
6340 Xfake_acid_3, FALSE, FALSE,
6341 EL_EMC_FAKE_ACID, -1, -1
6344 Xfake_acid_4, FALSE, FALSE,
6345 EL_EMC_FAKE_ACID, -1, -1
6348 Xfake_acid_5, FALSE, FALSE,
6349 EL_EMC_FAKE_ACID, -1, -1
6352 Xfake_acid_6, FALSE, FALSE,
6353 EL_EMC_FAKE_ACID, -1, -1
6356 Xfake_acid_7, FALSE, FALSE,
6357 EL_EMC_FAKE_ACID, -1, -1
6360 Xfake_acid_8, FALSE, FALSE,
6361 EL_EMC_FAKE_ACID, -1, -1
6364 Xsteel_1, TRUE, FALSE,
6365 EL_STEELWALL, -1, -1
6368 Xsteel_2, TRUE, FALSE,
6369 EL_EMC_STEELWALL_2, -1, -1
6372 Xsteel_3, TRUE, FALSE,
6373 EL_EMC_STEELWALL_3, -1, -1
6376 Xsteel_4, TRUE, FALSE,
6377 EL_EMC_STEELWALL_4, -1, -1
6380 Xwall_1, TRUE, FALSE,
6384 Xwall_2, TRUE, FALSE,
6385 EL_EMC_WALL_14, -1, -1
6388 Xwall_3, TRUE, FALSE,
6389 EL_EMC_WALL_15, -1, -1
6392 Xwall_4, TRUE, FALSE,
6393 EL_EMC_WALL_16, -1, -1
6396 Xround_wall_1, TRUE, FALSE,
6397 EL_WALL_SLIPPERY, -1, -1
6400 Xround_wall_2, TRUE, FALSE,
6401 EL_EMC_WALL_SLIPPERY_2, -1, -1
6404 Xround_wall_3, TRUE, FALSE,
6405 EL_EMC_WALL_SLIPPERY_3, -1, -1
6408 Xround_wall_4, TRUE, FALSE,
6409 EL_EMC_WALL_SLIPPERY_4, -1, -1
6412 Xdecor_1, TRUE, FALSE,
6413 EL_EMC_WALL_8, -1, -1
6416 Xdecor_2, TRUE, FALSE,
6417 EL_EMC_WALL_6, -1, -1
6420 Xdecor_3, TRUE, FALSE,
6421 EL_EMC_WALL_4, -1, -1
6424 Xdecor_4, TRUE, FALSE,
6425 EL_EMC_WALL_7, -1, -1
6428 Xdecor_5, TRUE, FALSE,
6429 EL_EMC_WALL_5, -1, -1
6432 Xdecor_6, TRUE, FALSE,
6433 EL_EMC_WALL_9, -1, -1
6436 Xdecor_7, TRUE, FALSE,
6437 EL_EMC_WALL_10, -1, -1
6440 Xdecor_8, TRUE, FALSE,
6441 EL_EMC_WALL_1, -1, -1
6444 Xdecor_9, TRUE, FALSE,
6445 EL_EMC_WALL_2, -1, -1
6448 Xdecor_10, TRUE, FALSE,
6449 EL_EMC_WALL_3, -1, -1
6452 Xdecor_11, TRUE, FALSE,
6453 EL_EMC_WALL_11, -1, -1
6456 Xdecor_12, TRUE, FALSE,
6457 EL_EMC_WALL_12, -1, -1
6460 Xalpha_0, TRUE, FALSE,
6461 EL_CHAR('0'), -1, -1
6464 Xalpha_1, TRUE, FALSE,
6465 EL_CHAR('1'), -1, -1
6468 Xalpha_2, TRUE, FALSE,
6469 EL_CHAR('2'), -1, -1
6472 Xalpha_3, TRUE, FALSE,
6473 EL_CHAR('3'), -1, -1
6476 Xalpha_4, TRUE, FALSE,
6477 EL_CHAR('4'), -1, -1
6480 Xalpha_5, TRUE, FALSE,
6481 EL_CHAR('5'), -1, -1
6484 Xalpha_6, TRUE, FALSE,
6485 EL_CHAR('6'), -1, -1
6488 Xalpha_7, TRUE, FALSE,
6489 EL_CHAR('7'), -1, -1
6492 Xalpha_8, TRUE, FALSE,
6493 EL_CHAR('8'), -1, -1
6496 Xalpha_9, TRUE, FALSE,
6497 EL_CHAR('9'), -1, -1
6500 Xalpha_excla, TRUE, FALSE,
6501 EL_CHAR('!'), -1, -1
6504 Xalpha_quote, TRUE, FALSE,
6505 EL_CHAR('"'), -1, -1
6508 Xalpha_comma, TRUE, FALSE,
6509 EL_CHAR(','), -1, -1
6512 Xalpha_minus, TRUE, FALSE,
6513 EL_CHAR('-'), -1, -1
6516 Xalpha_perio, TRUE, FALSE,
6517 EL_CHAR('.'), -1, -1
6520 Xalpha_colon, TRUE, FALSE,
6521 EL_CHAR(':'), -1, -1
6524 Xalpha_quest, TRUE, FALSE,
6525 EL_CHAR('?'), -1, -1
6528 Xalpha_a, TRUE, FALSE,
6529 EL_CHAR('A'), -1, -1
6532 Xalpha_b, TRUE, FALSE,
6533 EL_CHAR('B'), -1, -1
6536 Xalpha_c, TRUE, FALSE,
6537 EL_CHAR('C'), -1, -1
6540 Xalpha_d, TRUE, FALSE,
6541 EL_CHAR('D'), -1, -1
6544 Xalpha_e, TRUE, FALSE,
6545 EL_CHAR('E'), -1, -1
6548 Xalpha_f, TRUE, FALSE,
6549 EL_CHAR('F'), -1, -1
6552 Xalpha_g, TRUE, FALSE,
6553 EL_CHAR('G'), -1, -1
6556 Xalpha_h, TRUE, FALSE,
6557 EL_CHAR('H'), -1, -1
6560 Xalpha_i, TRUE, FALSE,
6561 EL_CHAR('I'), -1, -1
6564 Xalpha_j, TRUE, FALSE,
6565 EL_CHAR('J'), -1, -1
6568 Xalpha_k, TRUE, FALSE,
6569 EL_CHAR('K'), -1, -1
6572 Xalpha_l, TRUE, FALSE,
6573 EL_CHAR('L'), -1, -1
6576 Xalpha_m, TRUE, FALSE,
6577 EL_CHAR('M'), -1, -1
6580 Xalpha_n, TRUE, FALSE,
6581 EL_CHAR('N'), -1, -1
6584 Xalpha_o, TRUE, FALSE,
6585 EL_CHAR('O'), -1, -1
6588 Xalpha_p, TRUE, FALSE,
6589 EL_CHAR('P'), -1, -1
6592 Xalpha_q, TRUE, FALSE,
6593 EL_CHAR('Q'), -1, -1
6596 Xalpha_r, TRUE, FALSE,
6597 EL_CHAR('R'), -1, -1
6600 Xalpha_s, TRUE, FALSE,
6601 EL_CHAR('S'), -1, -1
6604 Xalpha_t, TRUE, FALSE,
6605 EL_CHAR('T'), -1, -1
6608 Xalpha_u, TRUE, FALSE,
6609 EL_CHAR('U'), -1, -1
6612 Xalpha_v, TRUE, FALSE,
6613 EL_CHAR('V'), -1, -1
6616 Xalpha_w, TRUE, FALSE,
6617 EL_CHAR('W'), -1, -1
6620 Xalpha_x, TRUE, FALSE,
6621 EL_CHAR('X'), -1, -1
6624 Xalpha_y, TRUE, FALSE,
6625 EL_CHAR('Y'), -1, -1
6628 Xalpha_z, TRUE, FALSE,
6629 EL_CHAR('Z'), -1, -1
6632 Xalpha_arrow_e, TRUE, FALSE,
6633 EL_CHAR('>'), -1, -1
6636 Xalpha_arrow_w, TRUE, FALSE,
6637 EL_CHAR('<'), -1, -1
6640 Xalpha_copyr, TRUE, FALSE,
6641 EL_CHAR('©'), -1, -1
6645 Xboom_bug, FALSE, FALSE,
6646 EL_BUG, ACTION_EXPLODING, -1
6649 Xboom_bomb, FALSE, FALSE,
6650 EL_BOMB, ACTION_EXPLODING, -1
6653 Xboom_android, FALSE, FALSE,
6654 EL_EMC_ANDROID, ACTION_OTHER, -1
6657 Xboom_1, FALSE, FALSE,
6658 EL_DEFAULT, ACTION_EXPLODING, -1
6661 Xboom_2, FALSE, FALSE,
6662 EL_DEFAULT, ACTION_EXPLODING, -1
6665 Znormal, FALSE, FALSE,
6669 Zdynamite, FALSE, FALSE,
6673 Zplayer, FALSE, FALSE,
6677 ZBORDER, FALSE, FALSE,
6687 static struct Mapping_EM_to_RND_player
6696 em_player_mapping_list[] =
6700 EL_PLAYER_1, ACTION_MOVING, MV_BIT_UP,
6704 EL_PLAYER_1, ACTION_MOVING, MV_BIT_RIGHT,
6708 EL_PLAYER_1, ACTION_MOVING, MV_BIT_DOWN,
6712 EL_PLAYER_1, ACTION_MOVING, MV_BIT_LEFT,
6716 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_UP,
6720 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_RIGHT,
6724 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_DOWN,
6728 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_LEFT,
6732 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_UP,
6736 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_RIGHT,
6740 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_DOWN,
6744 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_LEFT,
6748 EL_PLAYER_2, ACTION_MOVING, MV_BIT_UP,
6752 EL_PLAYER_2, ACTION_MOVING, MV_BIT_RIGHT,
6756 EL_PLAYER_2, ACTION_MOVING, MV_BIT_DOWN,
6760 EL_PLAYER_2, ACTION_MOVING, MV_BIT_LEFT,
6764 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_UP,
6768 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_RIGHT,
6772 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_DOWN,
6776 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_LEFT,
6780 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_UP,
6784 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_RIGHT,
6788 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_DOWN,
6792 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_LEFT,
6796 EL_PLAYER_1, ACTION_DEFAULT, -1,
6800 EL_PLAYER_2, ACTION_DEFAULT, -1,
6804 EL_PLAYER_3, ACTION_MOVING, MV_BIT_UP,
6808 EL_PLAYER_3, ACTION_MOVING, MV_BIT_RIGHT,
6812 EL_PLAYER_3, ACTION_MOVING, MV_BIT_DOWN,
6816 EL_PLAYER_3, ACTION_MOVING, MV_BIT_LEFT,
6820 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_UP,
6824 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_RIGHT,
6828 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_DOWN,
6832 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_LEFT,
6836 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_UP,
6840 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_RIGHT,
6844 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_DOWN,
6848 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_LEFT,
6852 EL_PLAYER_4, ACTION_MOVING, MV_BIT_UP,
6856 EL_PLAYER_4, ACTION_MOVING, MV_BIT_RIGHT,
6860 EL_PLAYER_4, ACTION_MOVING, MV_BIT_DOWN,
6864 EL_PLAYER_4, ACTION_MOVING, MV_BIT_LEFT,
6868 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_UP,
6872 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_RIGHT,
6876 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_DOWN,
6880 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_LEFT,
6884 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_UP,
6888 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_RIGHT,
6892 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_DOWN,
6896 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_LEFT,
6900 EL_PLAYER_3, ACTION_DEFAULT, -1,
6904 EL_PLAYER_4, ACTION_DEFAULT, -1,
6913 int map_element_RND_to_EM(int element_rnd)
6915 static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
6916 static boolean mapping_initialized = FALSE;
6918 if (!mapping_initialized)
6922 /* return "Xalpha_quest" for all undefined elements in mapping array */
6923 for (i = 0; i < NUM_FILE_ELEMENTS; i++)
6924 mapping_RND_to_EM[i] = Xalpha_quest;
6926 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
6927 if (em_object_mapping_list[i].is_rnd_to_em_mapping)
6928 mapping_RND_to_EM[em_object_mapping_list[i].element_rnd] =
6929 em_object_mapping_list[i].element_em;
6931 mapping_initialized = TRUE;
6934 if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
6935 return mapping_RND_to_EM[element_rnd];
6937 Error(ERR_WARN, "invalid RND level element %d", element_rnd);
6942 int map_element_EM_to_RND(int element_em)
6944 static unsigned short mapping_EM_to_RND[TILE_MAX];
6945 static boolean mapping_initialized = FALSE;
6947 if (!mapping_initialized)
6951 /* return "EL_UNKNOWN" for all undefined elements in mapping array */
6952 for (i = 0; i < TILE_MAX; i++)
6953 mapping_EM_to_RND[i] = EL_UNKNOWN;
6955 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
6956 mapping_EM_to_RND[em_object_mapping_list[i].element_em] =
6957 em_object_mapping_list[i].element_rnd;
6959 mapping_initialized = TRUE;
6962 if (element_em >= 0 && element_em < TILE_MAX)
6963 return mapping_EM_to_RND[element_em];
6965 Error(ERR_WARN, "invalid EM level element %d", element_em);
6970 void map_android_clone_elements_RND_to_EM(struct LevelInfo *level)
6972 struct LevelInfo_EM *level_em = level->native_em_level;
6973 struct LEVEL *lev = level_em->lev;
6976 for (i = 0; i < TILE_MAX; i++)
6977 lev->android_array[i] = Xblank;
6979 for (i = 0; i < level->num_android_clone_elements; i++)
6981 int element_rnd = level->android_clone_element[i];
6982 int element_em = map_element_RND_to_EM(element_rnd);
6984 for (j = 0; em_object_mapping_list[j].element_em != -1; j++)
6985 if (em_object_mapping_list[j].element_rnd == element_rnd)
6986 lev->android_array[em_object_mapping_list[j].element_em] = element_em;
6990 void map_android_clone_elements_EM_to_RND(struct LevelInfo *level)
6992 struct LevelInfo_EM *level_em = level->native_em_level;
6993 struct LEVEL *lev = level_em->lev;
6996 level->num_android_clone_elements = 0;
6998 for (i = 0; i < TILE_MAX; i++)
7000 int element_em = lev->android_array[i];
7002 boolean element_found = FALSE;
7004 if (element_em == Xblank)
7007 element_rnd = map_element_EM_to_RND(element_em);
7009 for (j = 0; j < level->num_android_clone_elements; j++)
7010 if (level->android_clone_element[j] == element_rnd)
7011 element_found = TRUE;
7015 level->android_clone_element[level->num_android_clone_elements++] =
7018 if (level->num_android_clone_elements == MAX_ANDROID_ELEMENTS)
7023 if (level->num_android_clone_elements == 0)
7025 level->num_android_clone_elements = 1;
7026 level->android_clone_element[0] = EL_EMPTY;
7030 int map_direction_RND_to_EM(int direction)
7032 return (direction == MV_UP ? 0 :
7033 direction == MV_RIGHT ? 1 :
7034 direction == MV_DOWN ? 2 :
7035 direction == MV_LEFT ? 3 :
7039 int map_direction_EM_to_RND(int direction)
7041 return (direction == 0 ? MV_UP :
7042 direction == 1 ? MV_RIGHT :
7043 direction == 2 ? MV_DOWN :
7044 direction == 3 ? MV_LEFT :
7048 int map_element_RND_to_SP(int element_rnd)
7050 int element_sp = 0x20; /* map unknown elements to yellow "hardware" */
7052 if (element_rnd >= EL_SP_START &&
7053 element_rnd <= EL_SP_END)
7054 element_sp = element_rnd - EL_SP_START;
7055 else if (element_rnd == EL_EMPTY_SPACE)
7057 else if (element_rnd == EL_INVISIBLE_WALL)
7063 int map_element_SP_to_RND(int element_sp)
7065 int element_rnd = EL_UNKNOWN;
7067 if (element_sp >= 0x00 &&
7069 element_rnd = EL_SP_START + element_sp;
7070 else if (element_sp == 0x28)
7071 element_rnd = EL_INVISIBLE_WALL;
7076 int map_action_SP_to_RND(int action_sp)
7080 case actActive: return ACTION_ACTIVE;
7081 case actImpact: return ACTION_IMPACT;
7082 case actExploding: return ACTION_EXPLODING;
7083 case actDigging: return ACTION_DIGGING;
7084 case actSnapping: return ACTION_SNAPPING;
7085 case actCollecting: return ACTION_COLLECTING;
7086 case actPassing: return ACTION_PASSING;
7087 case actPushing: return ACTION_PUSHING;
7088 case actDropping: return ACTION_DROPPING;
7090 default: return ACTION_DEFAULT;
7094 int get_next_element(int element)
7098 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
7099 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
7100 case EL_QUICKSAND_FAST_FILLING: return EL_QUICKSAND_FAST_FULL;
7101 case EL_QUICKSAND_FAST_EMPTYING: return EL_QUICKSAND_FAST_EMPTY;
7102 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
7103 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
7104 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
7105 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
7106 case EL_DC_MAGIC_WALL_FILLING: return EL_DC_MAGIC_WALL_FULL;
7107 case EL_DC_MAGIC_WALL_EMPTYING: return EL_DC_MAGIC_WALL_ACTIVE;
7108 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
7110 default: return element;
7115 int el_act_dir2img(int element, int action, int direction)
7117 element = GFX_ELEMENT(element);
7119 if (direction == MV_NONE)
7120 return element_info[element].graphic[action];
7122 direction = MV_DIR_TO_BIT(direction);
7124 return element_info[element].direction_graphic[action][direction];
7127 int el_act_dir2img(int element, int action, int direction)
7129 element = GFX_ELEMENT(element);
7130 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
7132 /* direction_graphic[][] == graphic[] for undefined direction graphics */
7133 return element_info[element].direction_graphic[action][direction];
7138 static int el_act_dir2crm(int element, int action, int direction)
7140 element = GFX_ELEMENT(element);
7142 if (direction == MV_NONE)
7143 return element_info[element].crumbled[action];
7145 direction = MV_DIR_TO_BIT(direction);
7147 return element_info[element].direction_crumbled[action][direction];
7150 static int el_act_dir2crm(int element, int action, int direction)
7152 element = GFX_ELEMENT(element);
7153 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
7155 /* direction_graphic[][] == graphic[] for undefined direction graphics */
7156 return element_info[element].direction_crumbled[action][direction];
7160 int el_act2img(int element, int action)
7162 element = GFX_ELEMENT(element);
7164 return element_info[element].graphic[action];
7167 int el_act2crm(int element, int action)
7169 element = GFX_ELEMENT(element);
7171 return element_info[element].crumbled[action];
7174 int el_dir2img(int element, int direction)
7176 element = GFX_ELEMENT(element);
7178 return el_act_dir2img(element, ACTION_DEFAULT, direction);
7181 int el2baseimg(int element)
7183 return element_info[element].graphic[ACTION_DEFAULT];
7186 int el2img(int element)
7188 element = GFX_ELEMENT(element);
7190 return element_info[element].graphic[ACTION_DEFAULT];
7193 int el2edimg(int element)
7195 element = GFX_ELEMENT(element);
7197 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
7200 int el2preimg(int element)
7202 element = GFX_ELEMENT(element);
7204 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
7207 int el2panelimg(int element)
7209 element = GFX_ELEMENT(element);
7211 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PANEL];
7214 int font2baseimg(int font_nr)
7216 return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
7219 int getBeltNrFromBeltElement(int element)
7221 return (element < EL_CONVEYOR_BELT_2_LEFT ? 0 :
7222 element < EL_CONVEYOR_BELT_3_LEFT ? 1 :
7223 element < EL_CONVEYOR_BELT_4_LEFT ? 2 : 3);
7226 int getBeltNrFromBeltActiveElement(int element)
7228 return (element < EL_CONVEYOR_BELT_2_LEFT_ACTIVE ? 0 :
7229 element < EL_CONVEYOR_BELT_3_LEFT_ACTIVE ? 1 :
7230 element < EL_CONVEYOR_BELT_4_LEFT_ACTIVE ? 2 : 3);
7233 int getBeltNrFromBeltSwitchElement(int element)
7235 return (element < EL_CONVEYOR_BELT_2_SWITCH_LEFT ? 0 :
7236 element < EL_CONVEYOR_BELT_3_SWITCH_LEFT ? 1 :
7237 element < EL_CONVEYOR_BELT_4_SWITCH_LEFT ? 2 : 3);
7240 int getBeltDirNrFromBeltElement(int element)
7242 static int belt_base_element[4] =
7244 EL_CONVEYOR_BELT_1_LEFT,
7245 EL_CONVEYOR_BELT_2_LEFT,
7246 EL_CONVEYOR_BELT_3_LEFT,
7247 EL_CONVEYOR_BELT_4_LEFT
7250 int belt_nr = getBeltNrFromBeltElement(element);
7251 int belt_dir_nr = element - belt_base_element[belt_nr];
7253 return (belt_dir_nr % 3);
7256 int getBeltDirNrFromBeltSwitchElement(int element)
7258 static int belt_base_element[4] =
7260 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
7261 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
7262 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
7263 EL_CONVEYOR_BELT_4_SWITCH_LEFT
7266 int belt_nr = getBeltNrFromBeltSwitchElement(element);
7267 int belt_dir_nr = element - belt_base_element[belt_nr];
7269 return (belt_dir_nr % 3);
7272 int getBeltDirFromBeltElement(int element)
7274 static int belt_move_dir[3] =
7281 int belt_dir_nr = getBeltDirNrFromBeltElement(element);
7283 return belt_move_dir[belt_dir_nr];
7286 int getBeltDirFromBeltSwitchElement(int element)
7288 static int belt_move_dir[3] =
7295 int belt_dir_nr = getBeltDirNrFromBeltSwitchElement(element);
7297 return belt_move_dir[belt_dir_nr];
7300 int getBeltElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
7302 static int belt_base_element[4] =
7304 EL_CONVEYOR_BELT_1_LEFT,
7305 EL_CONVEYOR_BELT_2_LEFT,
7306 EL_CONVEYOR_BELT_3_LEFT,
7307 EL_CONVEYOR_BELT_4_LEFT
7310 return belt_base_element[belt_nr] + belt_dir_nr;
7313 int getBeltElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
7315 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
7317 return getBeltElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
7320 int getBeltSwitchElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
7322 static int belt_base_element[4] =
7324 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
7325 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
7326 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
7327 EL_CONVEYOR_BELT_4_SWITCH_LEFT
7330 return belt_base_element[belt_nr] + belt_dir_nr;
7333 int getBeltSwitchElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
7335 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
7337 return getBeltSwitchElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
7340 int getNumActivePlayers_EM()
7342 int num_players = 0;
7348 for (i = 0; i < MAX_PLAYERS; i++)
7349 if (tape.player_participates[i])
7355 int getGameFrameDelay_EM(int native_em_game_frame_delay)
7357 int game_frame_delay_value;
7359 game_frame_delay_value =
7360 (tape.playing && tape.fast_forward ? FfwdFrameDelay :
7361 GameFrameDelay == GAME_FRAME_DELAY ? native_em_game_frame_delay :
7364 if (tape.playing && tape.warp_forward && !tape.pausing)
7365 game_frame_delay_value = 0;
7367 return game_frame_delay_value;
7370 unsigned int InitRND(int seed)
7372 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
7373 return InitEngineRandom_EM(seed);
7374 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
7375 return InitEngineRandom_SP(seed);
7377 return InitEngineRandom_RND(seed);
7381 static struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
7382 static struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
7385 inline static int get_effective_element_EM(int tile, int frame_em)
7387 int element = object_mapping[tile].element_rnd;
7388 int action = object_mapping[tile].action;
7389 boolean is_backside = object_mapping[tile].is_backside;
7390 boolean action_removing = (action == ACTION_DIGGING ||
7391 action == ACTION_SNAPPING ||
7392 action == ACTION_COLLECTING);
7398 case Yacid_splash_eB:
7399 case Yacid_splash_wB:
7400 return (frame_em > 5 ? EL_EMPTY : element);
7404 case Ydiamond_stone:
7405 // if (!game.use_native_emc_graphics_engine)
7413 else /* frame_em == 7 */
7417 case Yacid_splash_eB:
7418 case Yacid_splash_wB:
7421 case Yemerald_stone:
7424 case Ydiamond_stone:
7428 case Xdrip_stretchB:
7447 case Xsand_stonein_1:
7448 case Xsand_stonein_2:
7449 case Xsand_stonein_3:
7450 case Xsand_stonein_4:
7454 return (is_backside || action_removing ? EL_EMPTY : element);
7459 inline static boolean check_linear_animation_EM(int tile)
7463 case Xsand_stonesand_1:
7464 case Xsand_stonesand_quickout_1:
7465 case Xsand_sandstone_1:
7466 case Xsand_stonein_1:
7467 case Xsand_stoneout_1:
7487 case Yacid_splash_eB:
7488 case Yacid_splash_wB:
7489 case Yemerald_stone:
7497 inline static void set_crumbled_graphics_EM(struct GraphicInfo_EM *g_em,
7498 boolean has_crumbled_graphics,
7499 int crumbled, int sync_frame)
7501 /* if element can be crumbled, but certain action graphics are just empty
7502 space (like instantly snapping sand to empty space in 1 frame), do not
7503 treat these empty space graphics as crumbled graphics in EMC engine */
7504 if (crumbled == IMG_EMPTY_SPACE)
7505 has_crumbled_graphics = FALSE;
7507 if (has_crumbled_graphics)
7509 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
7510 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
7511 g_crumbled->anim_delay,
7512 g_crumbled->anim_mode,
7513 g_crumbled->anim_start_frame,
7516 getGraphicSource(crumbled, frame_crumbled, &g_em->crumbled_bitmap,
7517 &g_em->crumbled_src_x, &g_em->crumbled_src_y);
7519 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
7521 g_em->has_crumbled_graphics = TRUE;
7525 g_em->crumbled_bitmap = NULL;
7526 g_em->crumbled_src_x = 0;
7527 g_em->crumbled_src_y = 0;
7528 g_em->crumbled_border_size = 0;
7530 g_em->has_crumbled_graphics = FALSE;
7534 void ResetGfxAnimation_EM(int x, int y, int tile)
7539 void SetGfxAnimation_EM(struct GraphicInfo_EM *g_em,
7540 int tile, int frame_em, int x, int y)
7542 int action = object_mapping[tile].action;
7544 int direction = object_mapping[tile].direction;
7545 int effective_element = get_effective_element_EM(tile, frame_em);
7546 int graphic = (direction == MV_NONE ?
7547 el_act2img(effective_element, action) :
7548 el_act_dir2img(effective_element, action, direction));
7549 struct GraphicInfo *g = &graphic_info[graphic];
7552 boolean action_removing = (action == ACTION_DIGGING ||
7553 action == ACTION_SNAPPING ||
7554 action == ACTION_COLLECTING);
7555 boolean action_moving = (action == ACTION_FALLING ||
7556 action == ACTION_MOVING ||
7557 action == ACTION_PUSHING ||
7558 action == ACTION_EATING ||
7559 action == ACTION_FILLING ||
7560 action == ACTION_EMPTYING);
7561 boolean action_falling = (action == ACTION_FALLING ||
7562 action == ACTION_FILLING ||
7563 action == ACTION_EMPTYING);
7565 /* special case: graphic uses "2nd movement tile" and has defined
7566 7 frames for movement animation (or less) => use default graphic
7567 for last (8th) frame which ends the movement animation */
7568 if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
7570 action = ACTION_DEFAULT; /* (keep action_* unchanged for now) */
7571 graphic = (direction == MV_NONE ?
7572 el_act2img(effective_element, action) :
7573 el_act_dir2img(effective_element, action, direction));
7575 g = &graphic_info[graphic];
7579 if (tile == Xsand_stonesand_1 ||
7580 tile == Xsand_stonesand_2 ||
7581 tile == Xsand_stonesand_3 ||
7582 tile == Xsand_stonesand_4)
7583 printf("::: 1: quicksand frame %d [%d]\n", GfxFrame[x][y], tile);
7587 if ((action_removing || check_linear_animation_EM(tile)) && frame_em == 0)
7591 // printf("::: resetting... [%d]\n", tile);
7594 if (action_removing || check_linear_animation_EM(tile))
7596 GfxFrame[x][y] = frame_em;
7598 // printf("::: resetting... [%d]\n", tile);
7601 else if (action_moving)
7603 boolean is_backside = object_mapping[tile].is_backside;
7607 int direction = object_mapping[tile].direction;
7608 int move_dir = (action_falling ? MV_DOWN : direction);
7613 /* !!! TEST !!! NEW !!! DOES NOT WORK RIGHT YET !!! */
7614 if (g->double_movement && frame_em == 0)
7618 // printf("::: resetting... [%d]\n", tile);
7622 if (move_dir == MV_LEFT)
7623 GfxFrame[x - 1][y] = GfxFrame[x][y];
7624 else if (move_dir == MV_RIGHT)
7625 GfxFrame[x + 1][y] = GfxFrame[x][y];
7626 else if (move_dir == MV_UP)
7627 GfxFrame[x][y - 1] = GfxFrame[x][y];
7628 else if (move_dir == MV_DOWN)
7629 GfxFrame[x][y + 1] = GfxFrame[x][y];
7636 /* special case: animation for Xsand_stonesand_quickout_1/2 twice as fast */
7637 if (tile == Xsand_stonesand_quickout_1 ||
7638 tile == Xsand_stonesand_quickout_2)
7643 if (tile == Xsand_stonesand_1 ||
7644 tile == Xsand_stonesand_2 ||
7645 tile == Xsand_stonesand_3 ||
7646 tile == Xsand_stonesand_4)
7647 printf("::: 2: quicksand frame %d [%d]\n", GfxFrame[x][y], tile);
7651 if (graphic_info[graphic].anim_global_sync)
7652 sync_frame = FrameCounter;
7653 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
7654 sync_frame = GfxFrame[x][y];
7656 sync_frame = 0; /* playfield border (pseudo steel) */
7658 SetRandomAnimationValue(x, y);
7660 int frame = getAnimationFrame(g->anim_frames,
7663 g->anim_start_frame,
7666 g_em->unique_identifier =
7667 (graphic << 16) | ((frame % 8) << 12) | (g_em->width << 6) | g_em->height;
7671 void getGraphicSourceObjectExt_EM(struct GraphicInfo_EM *g_em,
7672 int tile, int frame_em, int x, int y)
7674 int action = object_mapping[tile].action;
7675 int direction = object_mapping[tile].direction;
7676 boolean is_backside = object_mapping[tile].is_backside;
7677 int effective_element = get_effective_element_EM(tile, frame_em);
7679 int effective_action = action;
7681 int effective_action = (frame_em < 7 ? action : ACTION_DEFAULT);
7683 int graphic = (direction == MV_NONE ?
7684 el_act2img(effective_element, effective_action) :
7685 el_act_dir2img(effective_element, effective_action,
7687 int crumbled = (direction == MV_NONE ?
7688 el_act2crm(effective_element, effective_action) :
7689 el_act_dir2crm(effective_element, effective_action,
7691 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
7692 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
7693 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
7694 struct GraphicInfo *g = &graphic_info[graphic];
7696 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
7700 /* special case: graphic uses "2nd movement tile" and has defined
7701 7 frames for movement animation (or less) => use default graphic
7702 for last (8th) frame which ends the movement animation */
7703 if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
7705 effective_action = ACTION_DEFAULT;
7706 graphic = (direction == MV_NONE ?
7707 el_act2img(effective_element, effective_action) :
7708 el_act_dir2img(effective_element, effective_action,
7710 crumbled = (direction == MV_NONE ?
7711 el_act2crm(effective_element, effective_action) :
7712 el_act_dir2crm(effective_element, effective_action,
7715 g = &graphic_info[graphic];
7725 if (frame_em == 0) /* reset animation frame for certain elements */
7727 if (check_linear_animation_EM(tile))
7732 if (graphic_info[graphic].anim_global_sync)
7733 sync_frame = FrameCounter;
7734 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
7735 sync_frame = GfxFrame[x][y];
7737 sync_frame = 0; /* playfield border (pseudo steel) */
7739 SetRandomAnimationValue(x, y);
7744 int xxx_sync_frame = (i == Xdrip_stretch ? 7 :
7745 i == Xdrip_stretchB ? 7 :
7746 i == Ydrip_s2 ? j + 8 :
7747 i == Ydrip_s2B ? j + 8 :
7756 i == Xfake_acid_1 ? 0 :
7757 i == Xfake_acid_2 ? 10 :
7758 i == Xfake_acid_3 ? 20 :
7759 i == Xfake_acid_4 ? 30 :
7760 i == Xfake_acid_5 ? 40 :
7761 i == Xfake_acid_6 ? 50 :
7762 i == Xfake_acid_7 ? 60 :
7763 i == Xfake_acid_8 ? 70 :
7765 i == Xball_2B ? j + 8 :
7766 i == Yball_eat ? j + 1 :
7767 i == Ykey_1_eat ? j + 1 :
7768 i == Ykey_2_eat ? j + 1 :
7769 i == Ykey_3_eat ? j + 1 :
7770 i == Ykey_4_eat ? j + 1 :
7771 i == Ykey_5_eat ? j + 1 :
7772 i == Ykey_6_eat ? j + 1 :
7773 i == Ykey_7_eat ? j + 1 :
7774 i == Ykey_8_eat ? j + 1 :
7775 i == Ylenses_eat ? j + 1 :
7776 i == Ymagnify_eat ? j + 1 :
7777 i == Ygrass_eat ? j + 1 :
7778 i == Ydirt_eat ? j + 1 :
7779 i == Xamoeba_1 ? 0 :
7780 i == Xamoeba_2 ? 1 :
7781 i == Xamoeba_3 ? 2 :
7782 i == Xamoeba_4 ? 3 :
7783 i == Xamoeba_5 ? 0 :
7784 i == Xamoeba_6 ? 1 :
7785 i == Xamoeba_7 ? 2 :
7786 i == Xamoeba_8 ? 3 :
7787 i == Xexit_2 ? j + 8 :
7788 i == Xexit_3 ? j + 16 :
7789 i == Xdynamite_1 ? 0 :
7790 i == Xdynamite_2 ? 8 :
7791 i == Xdynamite_3 ? 16 :
7792 i == Xdynamite_4 ? 24 :
7793 i == Xsand_stonein_1 ? j + 1 :
7794 i == Xsand_stonein_2 ? j + 9 :
7795 i == Xsand_stonein_3 ? j + 17 :
7796 i == Xsand_stonein_4 ? j + 25 :
7797 i == Xsand_stoneout_1 && j == 0 ? 0 :
7798 i == Xsand_stoneout_1 && j == 1 ? 0 :
7799 i == Xsand_stoneout_1 && j == 2 ? 1 :
7800 i == Xsand_stoneout_1 && j == 3 ? 2 :
7801 i == Xsand_stoneout_1 && j == 4 ? 2 :
7802 i == Xsand_stoneout_1 && j == 5 ? 3 :
7803 i == Xsand_stoneout_1 && j == 6 ? 4 :
7804 i == Xsand_stoneout_1 && j == 7 ? 4 :
7805 i == Xsand_stoneout_2 && j == 0 ? 5 :
7806 i == Xsand_stoneout_2 && j == 1 ? 6 :
7807 i == Xsand_stoneout_2 && j == 2 ? 7 :
7808 i == Xsand_stoneout_2 && j == 3 ? 8 :
7809 i == Xsand_stoneout_2 && j == 4 ? 9 :
7810 i == Xsand_stoneout_2 && j == 5 ? 11 :
7811 i == Xsand_stoneout_2 && j == 6 ? 13 :
7812 i == Xsand_stoneout_2 && j == 7 ? 15 :
7813 i == Xboom_bug && j == 1 ? 2 :
7814 i == Xboom_bug && j == 2 ? 2 :
7815 i == Xboom_bug && j == 3 ? 4 :
7816 i == Xboom_bug && j == 4 ? 4 :
7817 i == Xboom_bug && j == 5 ? 2 :
7818 i == Xboom_bug && j == 6 ? 2 :
7819 i == Xboom_bug && j == 7 ? 0 :
7820 i == Xboom_bomb && j == 1 ? 2 :
7821 i == Xboom_bomb && j == 2 ? 2 :
7822 i == Xboom_bomb && j == 3 ? 4 :
7823 i == Xboom_bomb && j == 4 ? 4 :
7824 i == Xboom_bomb && j == 5 ? 2 :
7825 i == Xboom_bomb && j == 6 ? 2 :
7826 i == Xboom_bomb && j == 7 ? 0 :
7827 i == Xboom_android && j == 7 ? 6 :
7828 i == Xboom_1 && j == 1 ? 2 :
7829 i == Xboom_1 && j == 2 ? 2 :
7830 i == Xboom_1 && j == 3 ? 4 :
7831 i == Xboom_1 && j == 4 ? 4 :
7832 i == Xboom_1 && j == 5 ? 6 :
7833 i == Xboom_1 && j == 6 ? 6 :
7834 i == Xboom_1 && j == 7 ? 8 :
7835 i == Xboom_2 && j == 0 ? 8 :
7836 i == Xboom_2 && j == 1 ? 8 :
7837 i == Xboom_2 && j == 2 ? 10 :
7838 i == Xboom_2 && j == 3 ? 10 :
7839 i == Xboom_2 && j == 4 ? 10 :
7840 i == Xboom_2 && j == 5 ? 12 :
7841 i == Xboom_2 && j == 6 ? 12 :
7842 i == Xboom_2 && j == 7 ? 12 :
7844 special_animation && j == 4 ? 3 :
7845 effective_action != action ? 0 :
7851 int xxx_effective_action;
7852 int xxx_has_action_graphics;
7855 int element = object_mapping[i].element_rnd;
7856 int action = object_mapping[i].action;
7857 int direction = object_mapping[i].direction;
7858 boolean is_backside = object_mapping[i].is_backside;
7860 boolean action_removing = (action == ACTION_DIGGING ||
7861 action == ACTION_SNAPPING ||
7862 action == ACTION_COLLECTING);
7864 boolean action_exploding = ((action == ACTION_EXPLODING ||
7865 action == ACTION_SMASHED_BY_ROCK ||
7866 action == ACTION_SMASHED_BY_SPRING) &&
7867 element != EL_DIAMOND);
7868 boolean action_active = (action == ACTION_ACTIVE);
7869 boolean action_other = (action == ACTION_OTHER);
7873 int effective_element = get_effective_element_EM(i, j);
7875 int effective_element = (j > 5 && i == Yacid_splash_eB ? EL_EMPTY :
7876 j > 5 && i == Yacid_splash_wB ? EL_EMPTY :
7878 i == Xdrip_stretch ? element :
7879 i == Xdrip_stretchB ? element :
7880 i == Ydrip_s1 ? element :
7881 i == Ydrip_s1B ? element :
7882 i == Xball_1B ? element :
7883 i == Xball_2 ? element :
7884 i == Xball_2B ? element :
7885 i == Yball_eat ? element :
7886 i == Ykey_1_eat ? element :
7887 i == Ykey_2_eat ? element :
7888 i == Ykey_3_eat ? element :
7889 i == Ykey_4_eat ? element :
7890 i == Ykey_5_eat ? element :
7891 i == Ykey_6_eat ? element :
7892 i == Ykey_7_eat ? element :
7893 i == Ykey_8_eat ? element :
7894 i == Ylenses_eat ? element :
7895 i == Ymagnify_eat ? element :
7896 i == Ygrass_eat ? element :
7897 i == Ydirt_eat ? element :
7898 i == Yemerald_stone ? EL_EMERALD :
7899 i == Ydiamond_stone ? EL_ROCK :
7900 i == Xsand_stonein_1 ? element :
7901 i == Xsand_stonein_2 ? element :
7902 i == Xsand_stonein_3 ? element :
7903 i == Xsand_stonein_4 ? element :
7904 is_backside ? EL_EMPTY :
7905 action_removing ? EL_EMPTY :
7908 int effective_action = (j < 7 ? action :
7909 i == Xdrip_stretch ? action :
7910 i == Xdrip_stretchB ? action :
7911 i == Ydrip_s1 ? action :
7912 i == Ydrip_s1B ? action :
7913 i == Xball_1B ? action :
7914 i == Xball_2 ? action :
7915 i == Xball_2B ? action :
7916 i == Yball_eat ? action :
7917 i == Ykey_1_eat ? action :
7918 i == Ykey_2_eat ? action :
7919 i == Ykey_3_eat ? action :
7920 i == Ykey_4_eat ? action :
7921 i == Ykey_5_eat ? action :
7922 i == Ykey_6_eat ? action :
7923 i == Ykey_7_eat ? action :
7924 i == Ykey_8_eat ? action :
7925 i == Ylenses_eat ? action :
7926 i == Ymagnify_eat ? action :
7927 i == Ygrass_eat ? action :
7928 i == Ydirt_eat ? action :
7929 i == Xsand_stonein_1 ? action :
7930 i == Xsand_stonein_2 ? action :
7931 i == Xsand_stonein_3 ? action :
7932 i == Xsand_stonein_4 ? action :
7933 i == Xsand_stoneout_1 ? action :
7934 i == Xsand_stoneout_2 ? action :
7935 i == Xboom_android ? ACTION_EXPLODING :
7936 action_exploding ? ACTION_EXPLODING :
7937 action_active ? action :
7938 action_other ? action :
7940 int graphic = (el_act_dir2img(effective_element, effective_action,
7942 int crumbled = (el_act_dir2crm(effective_element, effective_action,
7944 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
7945 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
7946 boolean has_action_graphics = (graphic != base_graphic);
7947 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
7948 struct GraphicInfo *g = &graphic_info[graphic];
7950 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
7952 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
7955 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
7956 boolean special_animation = (action != ACTION_DEFAULT &&
7957 g->anim_frames == 3 &&
7958 g->anim_delay == 2 &&
7959 g->anim_mode & ANIM_LINEAR);
7960 xxx_sync_frame = (i == Xdrip_stretch ? 7 :
7961 i == Xdrip_stretchB ? 7 :
7962 i == Ydrip_s2 ? j + 8 :
7963 i == Ydrip_s2B ? j + 8 :
7972 i == Xfake_acid_1 ? 0 :
7973 i == Xfake_acid_2 ? 10 :
7974 i == Xfake_acid_3 ? 20 :
7975 i == Xfake_acid_4 ? 30 :
7976 i == Xfake_acid_5 ? 40 :
7977 i == Xfake_acid_6 ? 50 :
7978 i == Xfake_acid_7 ? 60 :
7979 i == Xfake_acid_8 ? 70 :
7981 i == Xball_2B ? j + 8 :
7982 i == Yball_eat ? j + 1 :
7983 i == Ykey_1_eat ? j + 1 :
7984 i == Ykey_2_eat ? j + 1 :
7985 i == Ykey_3_eat ? j + 1 :
7986 i == Ykey_4_eat ? j + 1 :
7987 i == Ykey_5_eat ? j + 1 :
7988 i == Ykey_6_eat ? j + 1 :
7989 i == Ykey_7_eat ? j + 1 :
7990 i == Ykey_8_eat ? j + 1 :
7991 i == Ylenses_eat ? j + 1 :
7992 i == Ymagnify_eat ? j + 1 :
7993 i == Ygrass_eat ? j + 1 :
7994 i == Ydirt_eat ? j + 1 :
7995 i == Xamoeba_1 ? 0 :
7996 i == Xamoeba_2 ? 1 :
7997 i == Xamoeba_3 ? 2 :
7998 i == Xamoeba_4 ? 3 :
7999 i == Xamoeba_5 ? 0 :
8000 i == Xamoeba_6 ? 1 :
8001 i == Xamoeba_7 ? 2 :
8002 i == Xamoeba_8 ? 3 :
8003 i == Xexit_2 ? j + 8 :
8004 i == Xexit_3 ? j + 16 :
8005 i == Xdynamite_1 ? 0 :
8006 i == Xdynamite_2 ? 8 :
8007 i == Xdynamite_3 ? 16 :
8008 i == Xdynamite_4 ? 24 :
8009 i == Xsand_stonein_1 ? j + 1 :
8010 i == Xsand_stonein_2 ? j + 9 :
8011 i == Xsand_stonein_3 ? j + 17 :
8012 i == Xsand_stonein_4 ? j + 25 :
8013 i == Xsand_stoneout_1 && j == 0 ? 0 :
8014 i == Xsand_stoneout_1 && j == 1 ? 0 :
8015 i == Xsand_stoneout_1 && j == 2 ? 1 :
8016 i == Xsand_stoneout_1 && j == 3 ? 2 :
8017 i == Xsand_stoneout_1 && j == 4 ? 2 :
8018 i == Xsand_stoneout_1 && j == 5 ? 3 :
8019 i == Xsand_stoneout_1 && j == 6 ? 4 :
8020 i == Xsand_stoneout_1 && j == 7 ? 4 :
8021 i == Xsand_stoneout_2 && j == 0 ? 5 :
8022 i == Xsand_stoneout_2 && j == 1 ? 6 :
8023 i == Xsand_stoneout_2 && j == 2 ? 7 :
8024 i == Xsand_stoneout_2 && j == 3 ? 8 :
8025 i == Xsand_stoneout_2 && j == 4 ? 9 :
8026 i == Xsand_stoneout_2 && j == 5 ? 11 :
8027 i == Xsand_stoneout_2 && j == 6 ? 13 :
8028 i == Xsand_stoneout_2 && j == 7 ? 15 :
8029 i == Xboom_bug && j == 1 ? 2 :
8030 i == Xboom_bug && j == 2 ? 2 :
8031 i == Xboom_bug && j == 3 ? 4 :
8032 i == Xboom_bug && j == 4 ? 4 :
8033 i == Xboom_bug && j == 5 ? 2 :
8034 i == Xboom_bug && j == 6 ? 2 :
8035 i == Xboom_bug && j == 7 ? 0 :
8036 i == Xboom_bomb && j == 1 ? 2 :
8037 i == Xboom_bomb && j == 2 ? 2 :
8038 i == Xboom_bomb && j == 3 ? 4 :
8039 i == Xboom_bomb && j == 4 ? 4 :
8040 i == Xboom_bomb && j == 5 ? 2 :
8041 i == Xboom_bomb && j == 6 ? 2 :
8042 i == Xboom_bomb && j == 7 ? 0 :
8043 i == Xboom_android && j == 7 ? 6 :
8044 i == Xboom_1 && j == 1 ? 2 :
8045 i == Xboom_1 && j == 2 ? 2 :
8046 i == Xboom_1 && j == 3 ? 4 :
8047 i == Xboom_1 && j == 4 ? 4 :
8048 i == Xboom_1 && j == 5 ? 6 :
8049 i == Xboom_1 && j == 6 ? 6 :
8050 i == Xboom_1 && j == 7 ? 8 :
8051 i == Xboom_2 && j == 0 ? 8 :
8052 i == Xboom_2 && j == 1 ? 8 :
8053 i == Xboom_2 && j == 2 ? 10 :
8054 i == Xboom_2 && j == 3 ? 10 :
8055 i == Xboom_2 && j == 4 ? 10 :
8056 i == Xboom_2 && j == 5 ? 12 :
8057 i == Xboom_2 && j == 6 ? 12 :
8058 i == Xboom_2 && j == 7 ? 12 :
8059 special_animation && j == 4 ? 3 :
8060 effective_action != action ? 0 :
8063 xxx_effective_action = effective_action;
8064 xxx_has_action_graphics = has_action_graphics;
8069 int frame = getAnimationFrame(g->anim_frames,
8072 g->anim_start_frame,
8086 int old_src_x = g_em->src_x;
8087 int old_src_y = g_em->src_y;
8091 getGraphicSourceExt(graphic, frame, &g_em->bitmap, &g_em->src_x, &g_em->src_y,
8092 g->double_movement && is_backside);
8094 getGraphicSourceExt(graphic, frame, &g_em->bitmap,
8095 &g_em->src_x, &g_em->src_y, FALSE);
8100 if (tile == Ydiamond_stone)
8101 printf("::: stone smashing diamond... %d: %d, %d, %d, %d, %d -> %d [%d, %d, %d, %d, %d, %d] [%d]\n",
8106 g->anim_start_frame,
8109 g_em->src_x, g_em->src_y,
8110 g_em->src_offset_x, g_em->src_offset_y,
8111 g_em->dst_offset_x, g_em->dst_offset_y,
8123 if (graphic == IMG_BUG_MOVING_RIGHT)
8124 printf("::: %d, %d, %d: %d, %d [%d, %d -> %d, %d]\n", graphic, x, y,
8125 g->double_movement, is_backside,
8126 old_src_x, old_src_y, g_em->src_x, g_em->src_y);
8134 g_em->src_offset_x = 0;
8135 g_em->src_offset_y = 0;
8136 g_em->dst_offset_x = 0;
8137 g_em->dst_offset_y = 0;
8138 g_em->width = TILEX;
8139 g_em->height = TILEY;
8141 g_em->preserve_background = FALSE;
8144 /* (updating the "crumbled" graphic definitions is probably not really needed,
8145 as animations for crumbled graphics can't be longer than one EMC cycle) */
8147 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
8152 g_em->crumbled_bitmap = NULL;
8153 g_em->crumbled_src_x = 0;
8154 g_em->crumbled_src_y = 0;
8156 g_em->has_crumbled_graphics = FALSE;
8158 if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
8160 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
8161 g_crumbled->anim_delay,
8162 g_crumbled->anim_mode,
8163 g_crumbled->anim_start_frame,
8166 getGraphicSource(crumbled, frame_crumbled, &g_em->crumbled_bitmap,
8167 &g_em->crumbled_src_x, &g_em->crumbled_src_y);
8169 g_em->has_crumbled_graphics = TRUE;
8175 int effective_action = xxx_effective_action;
8176 int has_action_graphics = xxx_has_action_graphics;
8178 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
8179 effective_action == ACTION_MOVING ||
8180 effective_action == ACTION_PUSHING ||
8181 effective_action == ACTION_EATING)) ||
8182 (!has_action_graphics && (effective_action == ACTION_FILLING ||
8183 effective_action == ACTION_EMPTYING)))
8186 (effective_action == ACTION_FALLING ||
8187 effective_action == ACTION_FILLING ||
8188 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
8189 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
8190 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
8191 int num_steps = (i == Ydrip_s1 ? 16 :
8192 i == Ydrip_s1B ? 16 :
8193 i == Ydrip_s2 ? 16 :
8194 i == Ydrip_s2B ? 16 :
8195 i == Xsand_stonein_1 ? 32 :
8196 i == Xsand_stonein_2 ? 32 :
8197 i == Xsand_stonein_3 ? 32 :
8198 i == Xsand_stonein_4 ? 32 :
8199 i == Xsand_stoneout_1 ? 16 :
8200 i == Xsand_stoneout_2 ? 16 : 8);
8201 int cx = ABS(dx) * (TILEX / num_steps);
8202 int cy = ABS(dy) * (TILEY / num_steps);
8203 int step_frame = (i == Ydrip_s2 ? j + 8 :
8204 i == Ydrip_s2B ? j + 8 :
8205 i == Xsand_stonein_2 ? j + 8 :
8206 i == Xsand_stonein_3 ? j + 16 :
8207 i == Xsand_stonein_4 ? j + 24 :
8208 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
8209 int step = (is_backside ? step_frame : num_steps - step_frame);
8211 if (is_backside) /* tile where movement starts */
8213 if (dx < 0 || dy < 0)
8215 g_em->src_offset_x = cx * step;
8216 g_em->src_offset_y = cy * step;
8220 g_em->dst_offset_x = cx * step;
8221 g_em->dst_offset_y = cy * step;
8224 else /* tile where movement ends */
8226 if (dx < 0 || dy < 0)
8228 g_em->dst_offset_x = cx * step;
8229 g_em->dst_offset_y = cy * step;
8233 g_em->src_offset_x = cx * step;
8234 g_em->src_offset_y = cy * step;
8238 g_em->width = TILEX - cx * step;
8239 g_em->height = TILEY - cy * step;
8242 /* create unique graphic identifier to decide if tile must be redrawn */
8243 /* bit 31 - 16 (16 bit): EM style graphic
8244 bit 15 - 12 ( 4 bit): EM style frame
8245 bit 11 - 6 ( 6 bit): graphic width
8246 bit 5 - 0 ( 6 bit): graphic height */
8247 g_em->unique_identifier =
8248 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
8254 void getGraphicSourcePlayerExt_EM(struct GraphicInfo_EM *g_em,
8255 int player_nr, int anim, int frame_em)
8257 int element = player_mapping[player_nr][anim].element_rnd;
8258 int action = player_mapping[player_nr][anim].action;
8259 int direction = player_mapping[player_nr][anim].direction;
8260 int graphic = (direction == MV_NONE ?
8261 el_act2img(element, action) :
8262 el_act_dir2img(element, action, direction));
8263 struct GraphicInfo *g = &graphic_info[graphic];
8266 InitPlayerGfxAnimation(&stored_player[player_nr], action, direction);
8268 stored_player[player_nr].StepFrame = frame_em;
8270 sync_frame = stored_player[player_nr].Frame;
8272 int frame = getAnimationFrame(g->anim_frames,
8275 g->anim_start_frame,
8278 getGraphicSourceExt(graphic, frame, &g_em->bitmap,
8279 &g_em->src_x, &g_em->src_y, FALSE);
8282 printf("::: %d: %d, %d [%d]\n",
8284 stored_player[player_nr].Frame,
8285 stored_player[player_nr].StepFrame,
8290 void InitGraphicInfo_EM(void)
8293 struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
8294 struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
8299 int num_em_gfx_errors = 0;
8301 if (graphic_info_em_object[0][0].bitmap == NULL)
8303 /* EM graphics not yet initialized in em_open_all() */
8308 printf("::: [4 errors can be ignored (1 x 'bomb', 3 x 'em_dynamite']\n");
8311 /* always start with reliable default values */
8312 for (i = 0; i < TILE_MAX; i++)
8314 object_mapping[i].element_rnd = EL_UNKNOWN;
8315 object_mapping[i].is_backside = FALSE;
8316 object_mapping[i].action = ACTION_DEFAULT;
8317 object_mapping[i].direction = MV_NONE;
8320 /* always start with reliable default values */
8321 for (p = 0; p < MAX_PLAYERS; p++)
8323 for (i = 0; i < SPR_MAX; i++)
8325 player_mapping[p][i].element_rnd = EL_UNKNOWN;
8326 player_mapping[p][i].action = ACTION_DEFAULT;
8327 player_mapping[p][i].direction = MV_NONE;
8331 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
8333 int e = em_object_mapping_list[i].element_em;
8335 object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd;
8336 object_mapping[e].is_backside = em_object_mapping_list[i].is_backside;
8338 if (em_object_mapping_list[i].action != -1)
8339 object_mapping[e].action = em_object_mapping_list[i].action;
8341 if (em_object_mapping_list[i].direction != -1)
8342 object_mapping[e].direction =
8343 MV_DIR_FROM_BIT(em_object_mapping_list[i].direction);
8346 for (i = 0; em_player_mapping_list[i].action_em != -1; i++)
8348 int a = em_player_mapping_list[i].action_em;
8349 int p = em_player_mapping_list[i].player_nr;
8351 player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd;
8353 if (em_player_mapping_list[i].action != -1)
8354 player_mapping[p][a].action = em_player_mapping_list[i].action;
8356 if (em_player_mapping_list[i].direction != -1)
8357 player_mapping[p][a].direction =
8358 MV_DIR_FROM_BIT(em_player_mapping_list[i].direction);
8361 for (i = 0; i < TILE_MAX; i++)
8363 int element = object_mapping[i].element_rnd;
8364 int action = object_mapping[i].action;
8365 int direction = object_mapping[i].direction;
8366 boolean is_backside = object_mapping[i].is_backside;
8368 boolean action_removing = (action == ACTION_DIGGING ||
8369 action == ACTION_SNAPPING ||
8370 action == ACTION_COLLECTING);
8372 boolean action_exploding = ((action == ACTION_EXPLODING ||
8373 action == ACTION_SMASHED_BY_ROCK ||
8374 action == ACTION_SMASHED_BY_SPRING) &&
8375 element != EL_DIAMOND);
8376 boolean action_active = (action == ACTION_ACTIVE);
8377 boolean action_other = (action == ACTION_OTHER);
8379 for (j = 0; j < 8; j++)
8382 int effective_element = get_effective_element_EM(i, j);
8384 int effective_element = (j > 5 && i == Yacid_splash_eB ? EL_EMPTY :
8385 j > 5 && i == Yacid_splash_wB ? EL_EMPTY :
8387 i == Xdrip_stretch ? element :
8388 i == Xdrip_stretchB ? element :
8389 i == Ydrip_s1 ? element :
8390 i == Ydrip_s1B ? element :
8391 i == Xball_1B ? element :
8392 i == Xball_2 ? element :
8393 i == Xball_2B ? element :
8394 i == Yball_eat ? element :
8395 i == Ykey_1_eat ? element :
8396 i == Ykey_2_eat ? element :
8397 i == Ykey_3_eat ? element :
8398 i == Ykey_4_eat ? element :
8399 i == Ykey_5_eat ? element :
8400 i == Ykey_6_eat ? element :
8401 i == Ykey_7_eat ? element :
8402 i == Ykey_8_eat ? element :
8403 i == Ylenses_eat ? element :
8404 i == Ymagnify_eat ? element :
8405 i == Ygrass_eat ? element :
8406 i == Ydirt_eat ? element :
8407 i == Yemerald_stone ? EL_EMERALD :
8408 i == Ydiamond_stone ? EL_ROCK :
8409 i == Xsand_stonein_1 ? element :
8410 i == Xsand_stonein_2 ? element :
8411 i == Xsand_stonein_3 ? element :
8412 i == Xsand_stonein_4 ? element :
8413 is_backside ? EL_EMPTY :
8414 action_removing ? EL_EMPTY :
8417 int effective_action = (j < 7 ? action :
8418 i == Xdrip_stretch ? action :
8419 i == Xdrip_stretchB ? action :
8420 i == Ydrip_s1 ? action :
8421 i == Ydrip_s1B ? action :
8422 i == Xball_1B ? action :
8423 i == Xball_2 ? action :
8424 i == Xball_2B ? action :
8425 i == Yball_eat ? action :
8426 i == Ykey_1_eat ? action :
8427 i == Ykey_2_eat ? action :
8428 i == Ykey_3_eat ? action :
8429 i == Ykey_4_eat ? action :
8430 i == Ykey_5_eat ? action :
8431 i == Ykey_6_eat ? action :
8432 i == Ykey_7_eat ? action :
8433 i == Ykey_8_eat ? action :
8434 i == Ylenses_eat ? action :
8435 i == Ymagnify_eat ? action :
8436 i == Ygrass_eat ? action :
8437 i == Ydirt_eat ? action :
8438 i == Xsand_stonein_1 ? action :
8439 i == Xsand_stonein_2 ? action :
8440 i == Xsand_stonein_3 ? action :
8441 i == Xsand_stonein_4 ? action :
8442 i == Xsand_stoneout_1 ? action :
8443 i == Xsand_stoneout_2 ? action :
8444 i == Xboom_android ? ACTION_EXPLODING :
8445 action_exploding ? ACTION_EXPLODING :
8446 action_active ? action :
8447 action_other ? action :
8449 int graphic = (el_act_dir2img(effective_element, effective_action,
8451 int crumbled = (el_act_dir2crm(effective_element, effective_action,
8453 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
8454 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
8455 boolean has_action_graphics = (graphic != base_graphic);
8456 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
8457 struct GraphicInfo *g = &graphic_info[graphic];
8459 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
8461 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
8464 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
8465 boolean special_animation = (action != ACTION_DEFAULT &&
8466 g->anim_frames == 3 &&
8467 g->anim_delay == 2 &&
8468 g->anim_mode & ANIM_LINEAR);
8469 int sync_frame = (i == Xdrip_stretch ? 7 :
8470 i == Xdrip_stretchB ? 7 :
8471 i == Ydrip_s2 ? j + 8 :
8472 i == Ydrip_s2B ? j + 8 :
8481 i == Xfake_acid_1 ? 0 :
8482 i == Xfake_acid_2 ? 10 :
8483 i == Xfake_acid_3 ? 20 :
8484 i == Xfake_acid_4 ? 30 :
8485 i == Xfake_acid_5 ? 40 :
8486 i == Xfake_acid_6 ? 50 :
8487 i == Xfake_acid_7 ? 60 :
8488 i == Xfake_acid_8 ? 70 :
8490 i == Xball_2B ? j + 8 :
8491 i == Yball_eat ? j + 1 :
8492 i == Ykey_1_eat ? j + 1 :
8493 i == Ykey_2_eat ? j + 1 :
8494 i == Ykey_3_eat ? j + 1 :
8495 i == Ykey_4_eat ? j + 1 :
8496 i == Ykey_5_eat ? j + 1 :
8497 i == Ykey_6_eat ? j + 1 :
8498 i == Ykey_7_eat ? j + 1 :
8499 i == Ykey_8_eat ? j + 1 :
8500 i == Ylenses_eat ? j + 1 :
8501 i == Ymagnify_eat ? j + 1 :
8502 i == Ygrass_eat ? j + 1 :
8503 i == Ydirt_eat ? j + 1 :
8504 i == Xamoeba_1 ? 0 :
8505 i == Xamoeba_2 ? 1 :
8506 i == Xamoeba_3 ? 2 :
8507 i == Xamoeba_4 ? 3 :
8508 i == Xamoeba_5 ? 0 :
8509 i == Xamoeba_6 ? 1 :
8510 i == Xamoeba_7 ? 2 :
8511 i == Xamoeba_8 ? 3 :
8512 i == Xexit_2 ? j + 8 :
8513 i == Xexit_3 ? j + 16 :
8514 i == Xdynamite_1 ? 0 :
8515 i == Xdynamite_2 ? 8 :
8516 i == Xdynamite_3 ? 16 :
8517 i == Xdynamite_4 ? 24 :
8518 i == Xsand_stonein_1 ? j + 1 :
8519 i == Xsand_stonein_2 ? j + 9 :
8520 i == Xsand_stonein_3 ? j + 17 :
8521 i == Xsand_stonein_4 ? j + 25 :
8522 i == Xsand_stoneout_1 && j == 0 ? 0 :
8523 i == Xsand_stoneout_1 && j == 1 ? 0 :
8524 i == Xsand_stoneout_1 && j == 2 ? 1 :
8525 i == Xsand_stoneout_1 && j == 3 ? 2 :
8526 i == Xsand_stoneout_1 && j == 4 ? 2 :
8527 i == Xsand_stoneout_1 && j == 5 ? 3 :
8528 i == Xsand_stoneout_1 && j == 6 ? 4 :
8529 i == Xsand_stoneout_1 && j == 7 ? 4 :
8530 i == Xsand_stoneout_2 && j == 0 ? 5 :
8531 i == Xsand_stoneout_2 && j == 1 ? 6 :
8532 i == Xsand_stoneout_2 && j == 2 ? 7 :
8533 i == Xsand_stoneout_2 && j == 3 ? 8 :
8534 i == Xsand_stoneout_2 && j == 4 ? 9 :
8535 i == Xsand_stoneout_2 && j == 5 ? 11 :
8536 i == Xsand_stoneout_2 && j == 6 ? 13 :
8537 i == Xsand_stoneout_2 && j == 7 ? 15 :
8538 i == Xboom_bug && j == 1 ? 2 :
8539 i == Xboom_bug && j == 2 ? 2 :
8540 i == Xboom_bug && j == 3 ? 4 :
8541 i == Xboom_bug && j == 4 ? 4 :
8542 i == Xboom_bug && j == 5 ? 2 :
8543 i == Xboom_bug && j == 6 ? 2 :
8544 i == Xboom_bug && j == 7 ? 0 :
8545 i == Xboom_bomb && j == 1 ? 2 :
8546 i == Xboom_bomb && j == 2 ? 2 :
8547 i == Xboom_bomb && j == 3 ? 4 :
8548 i == Xboom_bomb && j == 4 ? 4 :
8549 i == Xboom_bomb && j == 5 ? 2 :
8550 i == Xboom_bomb && j == 6 ? 2 :
8551 i == Xboom_bomb && j == 7 ? 0 :
8552 i == Xboom_android && j == 7 ? 6 :
8553 i == Xboom_1 && j == 1 ? 2 :
8554 i == Xboom_1 && j == 2 ? 2 :
8555 i == Xboom_1 && j == 3 ? 4 :
8556 i == Xboom_1 && j == 4 ? 4 :
8557 i == Xboom_1 && j == 5 ? 6 :
8558 i == Xboom_1 && j == 6 ? 6 :
8559 i == Xboom_1 && j == 7 ? 8 :
8560 i == Xboom_2 && j == 0 ? 8 :
8561 i == Xboom_2 && j == 1 ? 8 :
8562 i == Xboom_2 && j == 2 ? 10 :
8563 i == Xboom_2 && j == 3 ? 10 :
8564 i == Xboom_2 && j == 4 ? 10 :
8565 i == Xboom_2 && j == 5 ? 12 :
8566 i == Xboom_2 && j == 6 ? 12 :
8567 i == Xboom_2 && j == 7 ? 12 :
8568 special_animation && j == 4 ? 3 :
8569 effective_action != action ? 0 :
8573 Bitmap *debug_bitmap = g_em->bitmap;
8574 int debug_src_x = g_em->src_x;
8575 int debug_src_y = g_em->src_y;
8578 int frame = getAnimationFrame(g->anim_frames,
8581 g->anim_start_frame,
8584 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y,
8585 g->double_movement && is_backside);
8587 g_em->bitmap = src_bitmap;
8588 g_em->src_x = src_x;
8589 g_em->src_y = src_y;
8590 g_em->src_offset_x = 0;
8591 g_em->src_offset_y = 0;
8592 g_em->dst_offset_x = 0;
8593 g_em->dst_offset_y = 0;
8594 g_em->width = TILEX;
8595 g_em->height = TILEY;
8597 g_em->preserve_background = FALSE;
8600 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
8605 g_em->crumbled_bitmap = NULL;
8606 g_em->crumbled_src_x = 0;
8607 g_em->crumbled_src_y = 0;
8608 g_em->crumbled_border_size = 0;
8610 g_em->has_crumbled_graphics = FALSE;
8613 if (has_crumbled_graphics && crumbled == IMG_EMPTY_SPACE)
8614 printf("::: empty crumbled: %d [%s], %d, %d\n",
8615 effective_element, element_info[effective_element].token_name,
8616 effective_action, direction);
8619 /* if element can be crumbled, but certain action graphics are just empty
8620 space (like instantly snapping sand to empty space in 1 frame), do not
8621 treat these empty space graphics as crumbled graphics in EMC engine */
8622 if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
8624 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
8625 g_crumbled->anim_delay,
8626 g_crumbled->anim_mode,
8627 g_crumbled->anim_start_frame,
8630 getGraphicSource(crumbled, frame_crumbled, &src_bitmap, &src_x, &src_y);
8632 g_em->has_crumbled_graphics = TRUE;
8633 g_em->crumbled_bitmap = src_bitmap;
8634 g_em->crumbled_src_x = src_x;
8635 g_em->crumbled_src_y = src_y;
8636 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
8640 if (g_em == &graphic_info_em_object[207][0])
8641 printf("... %d, %d [%d, %d, %d, %d] [%d, %d, %d, %d, %d, %d => %d]\n",
8642 graphic_info_em_object[207][0].crumbled_src_x,
8643 graphic_info_em_object[207][0].crumbled_src_y,
8645 crumbled, frame, src_x, src_y,
8650 g->anim_start_frame,
8652 gfx.anim_random_frame,
8657 printf("::: EMC tile %d is crumbled\n", i);
8663 if (element == EL_ROCK &&
8664 effective_action == ACTION_FILLING)
8665 printf("::: has_action_graphics == %d\n", has_action_graphics);
8668 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
8669 effective_action == ACTION_MOVING ||
8670 effective_action == ACTION_PUSHING ||
8671 effective_action == ACTION_EATING)) ||
8672 (!has_action_graphics && (effective_action == ACTION_FILLING ||
8673 effective_action == ACTION_EMPTYING)))
8676 (effective_action == ACTION_FALLING ||
8677 effective_action == ACTION_FILLING ||
8678 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
8679 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
8680 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
8681 int num_steps = (i == Ydrip_s1 ? 16 :
8682 i == Ydrip_s1B ? 16 :
8683 i == Ydrip_s2 ? 16 :
8684 i == Ydrip_s2B ? 16 :
8685 i == Xsand_stonein_1 ? 32 :
8686 i == Xsand_stonein_2 ? 32 :
8687 i == Xsand_stonein_3 ? 32 :
8688 i == Xsand_stonein_4 ? 32 :
8689 i == Xsand_stoneout_1 ? 16 :
8690 i == Xsand_stoneout_2 ? 16 : 8);
8691 int cx = ABS(dx) * (TILEX / num_steps);
8692 int cy = ABS(dy) * (TILEY / num_steps);
8693 int step_frame = (i == Ydrip_s2 ? j + 8 :
8694 i == Ydrip_s2B ? j + 8 :
8695 i == Xsand_stonein_2 ? j + 8 :
8696 i == Xsand_stonein_3 ? j + 16 :
8697 i == Xsand_stonein_4 ? j + 24 :
8698 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
8699 int step = (is_backside ? step_frame : num_steps - step_frame);
8701 if (is_backside) /* tile where movement starts */
8703 if (dx < 0 || dy < 0)
8705 g_em->src_offset_x = cx * step;
8706 g_em->src_offset_y = cy * step;
8710 g_em->dst_offset_x = cx * step;
8711 g_em->dst_offset_y = cy * step;
8714 else /* tile where movement ends */
8716 if (dx < 0 || dy < 0)
8718 g_em->dst_offset_x = cx * step;
8719 g_em->dst_offset_y = cy * step;
8723 g_em->src_offset_x = cx * step;
8724 g_em->src_offset_y = cy * step;
8728 g_em->width = TILEX - cx * step;
8729 g_em->height = TILEY - cy * step;
8732 /* create unique graphic identifier to decide if tile must be redrawn */
8733 /* bit 31 - 16 (16 bit): EM style graphic
8734 bit 15 - 12 ( 4 bit): EM style frame
8735 bit 11 - 6 ( 6 bit): graphic width
8736 bit 5 - 0 ( 6 bit): graphic height */
8737 g_em->unique_identifier =
8738 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
8742 /* skip check for EMC elements not contained in original EMC artwork */
8743 if (element == EL_EMC_FAKE_ACID)
8746 if (g_em->bitmap != debug_bitmap ||
8747 g_em->src_x != debug_src_x ||
8748 g_em->src_y != debug_src_y ||
8749 g_em->src_offset_x != 0 ||
8750 g_em->src_offset_y != 0 ||
8751 g_em->dst_offset_x != 0 ||
8752 g_em->dst_offset_y != 0 ||
8753 g_em->width != TILEX ||
8754 g_em->height != TILEY)
8756 static int last_i = -1;
8764 printf("::: EMC GFX ERROR for element %d -> %d ('%s', '%s', %d)",
8765 i, element, element_info[element].token_name,
8766 element_action_info[effective_action].suffix, direction);
8768 if (element != effective_element)
8769 printf(" [%d ('%s')]",
8771 element_info[effective_element].token_name);
8775 if (g_em->bitmap != debug_bitmap)
8776 printf(" %d (%d): different bitmap! (0x%08x != 0x%08x)\n",
8777 j, is_backside, (int)(g_em->bitmap), (int)(debug_bitmap));
8779 if (g_em->src_x != debug_src_x ||
8780 g_em->src_y != debug_src_y)
8781 printf(" frame %d (%c): %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
8782 j, (is_backside ? 'B' : 'F'),
8783 g_em->src_x, g_em->src_y,
8784 g_em->src_x / 32, g_em->src_y / 32,
8785 debug_src_x, debug_src_y,
8786 debug_src_x / 32, debug_src_y / 32);
8788 if (g_em->src_offset_x != 0 ||
8789 g_em->src_offset_y != 0 ||
8790 g_em->dst_offset_x != 0 ||
8791 g_em->dst_offset_y != 0)
8792 printf(" %d (%d): offsets %d,%d and %d,%d should be all 0\n",
8794 g_em->src_offset_x, g_em->src_offset_y,
8795 g_em->dst_offset_x, g_em->dst_offset_y);
8797 if (g_em->width != TILEX ||
8798 g_em->height != TILEY)
8799 printf(" %d (%d): size %d,%d should be %d,%d\n",
8801 g_em->width, g_em->height, TILEX, TILEY);
8803 num_em_gfx_errors++;
8810 for (i = 0; i < TILE_MAX; i++)
8812 for (j = 0; j < 8; j++)
8814 int element = object_mapping[i].element_rnd;
8815 int action = object_mapping[i].action;
8816 int direction = object_mapping[i].direction;
8817 boolean is_backside = object_mapping[i].is_backside;
8818 int graphic_action = el_act_dir2img(element, action, direction);
8819 int graphic_default = el_act_dir2img(element, ACTION_DEFAULT, direction);
8821 if ((action == ACTION_SMASHED_BY_ROCK ||
8822 action == ACTION_SMASHED_BY_SPRING ||
8823 action == ACTION_EATING) &&
8824 graphic_action == graphic_default)
8826 int e = (action == ACTION_SMASHED_BY_ROCK ? Ystone_s :
8827 action == ACTION_SMASHED_BY_SPRING ? Yspring_s :
8828 direction == MV_LEFT ? (is_backside? Yspring_wB: Yspring_w) :
8829 direction == MV_RIGHT ? (is_backside? Yspring_eB: Yspring_e) :
8832 /* no separate animation for "smashed by rock" -- use rock instead */
8833 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
8834 struct GraphicInfo_EM *g_xx = &graphic_info_em_object[e][7 - j];
8836 g_em->bitmap = g_xx->bitmap;
8837 g_em->src_x = g_xx->src_x;
8838 g_em->src_y = g_xx->src_y;
8839 g_em->src_offset_x = g_xx->src_offset_x;
8840 g_em->src_offset_y = g_xx->src_offset_y;
8841 g_em->dst_offset_x = g_xx->dst_offset_x;
8842 g_em->dst_offset_y = g_xx->dst_offset_y;
8843 g_em->width = g_xx->width;
8844 g_em->height = g_xx->height;
8845 g_em->unique_identifier = g_xx->unique_identifier;
8848 g_em->preserve_background = TRUE;
8853 for (p = 0; p < MAX_PLAYERS; p++)
8855 for (i = 0; i < SPR_MAX; i++)
8857 int element = player_mapping[p][i].element_rnd;
8858 int action = player_mapping[p][i].action;
8859 int direction = player_mapping[p][i].direction;
8861 for (j = 0; j < 8; j++)
8863 int effective_element = element;
8864 int effective_action = action;
8865 int graphic = (direction == MV_NONE ?
8866 el_act2img(effective_element, effective_action) :
8867 el_act_dir2img(effective_element, effective_action,
8869 struct GraphicInfo *g = &graphic_info[graphic];
8870 struct GraphicInfo_EM *g_em = &graphic_info_em_player[p][i][7 - j];
8876 Bitmap *debug_bitmap = g_em->bitmap;
8877 int debug_src_x = g_em->src_x;
8878 int debug_src_y = g_em->src_y;
8881 int frame = getAnimationFrame(g->anim_frames,
8884 g->anim_start_frame,
8887 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
8889 g_em->bitmap = src_bitmap;
8890 g_em->src_x = src_x;
8891 g_em->src_y = src_y;
8892 g_em->src_offset_x = 0;
8893 g_em->src_offset_y = 0;
8894 g_em->dst_offset_x = 0;
8895 g_em->dst_offset_y = 0;
8896 g_em->width = TILEX;
8897 g_em->height = TILEY;
8901 /* skip check for EMC elements not contained in original EMC artwork */
8902 if (element == EL_PLAYER_3 ||
8903 element == EL_PLAYER_4)
8906 if (g_em->bitmap != debug_bitmap ||
8907 g_em->src_x != debug_src_x ||
8908 g_em->src_y != debug_src_y)
8910 static int last_i = -1;
8918 printf("::: EMC GFX ERROR for p/a %d/%d -> %d ('%s', '%s', %d)",
8919 p, i, element, element_info[element].token_name,
8920 element_action_info[effective_action].suffix, direction);
8922 if (element != effective_element)
8923 printf(" [%d ('%s')]",
8925 element_info[effective_element].token_name);
8929 if (g_em->bitmap != debug_bitmap)
8930 printf(" %d: different bitmap! (0x%08x != 0x%08x)\n",
8931 j, (int)(g_em->bitmap), (int)(debug_bitmap));
8933 if (g_em->src_x != debug_src_x ||
8934 g_em->src_y != debug_src_y)
8935 printf(" frame %d: %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
8937 g_em->src_x, g_em->src_y,
8938 g_em->src_x / 32, g_em->src_y / 32,
8939 debug_src_x, debug_src_y,
8940 debug_src_x / 32, debug_src_y / 32);
8942 num_em_gfx_errors++;
8952 printf("::: [%d errors found]\n", num_em_gfx_errors);
8958 void CheckSingleStepMode_EM(byte action[MAX_PLAYERS], int frame,
8959 boolean any_player_moving,
8960 boolean player_is_dropping)
8962 if (tape.single_step && tape.recording && !tape.pausing)
8965 boolean active_players = FALSE;
8968 for (i = 0; i < MAX_PLAYERS; i++)
8969 if (action[i] != JOY_NO_ACTION)
8970 active_players = TRUE;
8974 if (frame == 0 && !player_is_dropping)
8975 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
8979 void CheckSingleStepMode_SP(boolean murphy_is_waiting,
8980 boolean murphy_is_dropping)
8983 printf("::: waiting: %d, dropping: %d\n",
8984 murphy_is_waiting, murphy_is_dropping);
8987 if (tape.single_step && tape.recording && !tape.pausing)
8989 // if (murphy_is_waiting || murphy_is_dropping)
8990 if (murphy_is_waiting)
8993 printf("::: murphy is waiting -> pause mode\n");
8996 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
9001 void getGraphicSource_SP(struct GraphicInfo_SP *g_sp,
9002 int graphic, int sync_frame, int x, int y)
9004 int frame = getGraphicAnimationFrame(graphic, sync_frame);
9006 getGraphicSource(graphic, frame, &g_sp->bitmap, &g_sp->src_x, &g_sp->src_y);
9009 boolean isNextAnimationFrame_SP(int graphic, int sync_frame)
9011 return (IS_NEXT_FRAME(sync_frame, graphic));
9014 int getGraphicInfo_Delay(int graphic)
9016 return graphic_info[graphic].anim_delay;
9019 void PlayMenuSoundExt(int sound)
9021 if (sound == SND_UNDEFINED)
9024 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
9025 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
9028 if (IS_LOOP_SOUND(sound))
9029 PlaySoundLoop(sound);
9034 void PlayMenuSound()
9036 PlayMenuSoundExt(menu.sound[game_status]);
9039 void PlayMenuSoundStereo(int sound, int stereo_position)
9041 if (sound == SND_UNDEFINED)
9044 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
9045 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
9048 if (IS_LOOP_SOUND(sound))
9049 PlaySoundExt(sound, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_LOOP);
9051 PlaySoundStereo(sound, stereo_position);
9054 void PlayMenuSoundIfLoopExt(int sound)
9056 if (sound == SND_UNDEFINED)
9059 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
9060 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
9063 if (IS_LOOP_SOUND(sound))
9064 PlaySoundLoop(sound);
9067 void PlayMenuSoundIfLoop()
9069 PlayMenuSoundIfLoopExt(menu.sound[game_status]);
9072 void PlayMenuMusicExt(int music)
9074 if (music == MUS_UNDEFINED)
9077 if (!setup.sound_music)
9083 void PlayMenuMusic()
9085 PlayMenuMusicExt(menu.music[game_status]);
9088 void PlaySoundActivating()
9091 PlaySound(SND_MENU_ITEM_ACTIVATING);
9095 void PlaySoundSelecting()
9098 PlaySound(SND_MENU_ITEM_SELECTING);
9102 void ToggleFullscreenOrChangeWindowScalingIfNeeded()
9104 boolean change_fullscreen = (setup.fullscreen !=
9105 video.fullscreen_enabled);
9106 boolean change_fullscreen_mode = (video.fullscreen_enabled &&
9107 !strEqual(setup.fullscreen_mode,
9108 video.fullscreen_mode_current));
9109 boolean change_window_scaling_percent = (!video.fullscreen_enabled &&
9110 setup.window_scaling_percent !=
9111 video.window_scaling_percent);
9113 if (change_window_scaling_percent && video.fullscreen_enabled)
9116 if (!change_window_scaling_percent && !video.fullscreen_available)
9119 #if defined(TARGET_SDL2)
9120 if (change_window_scaling_percent)
9122 SDLSetWindowScaling(setup.window_scaling_percent);
9126 else if (change_fullscreen)
9128 SDLSetWindowFullscreen(setup.fullscreen);
9130 /* set setup value according to successfully changed fullscreen mode */
9131 setup.fullscreen = video.fullscreen_enabled;
9137 if (change_fullscreen ||
9138 change_fullscreen_mode ||
9139 change_window_scaling_percent)
9141 Bitmap *tmp_backbuffer = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
9143 /* save backbuffer content which gets lost when toggling fullscreen mode */
9144 BlitBitmap(backbuffer, tmp_backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
9146 if (change_fullscreen_mode)
9148 /* keep fullscreen, but change fullscreen mode (screen resolution) */
9149 video.fullscreen_enabled = FALSE; /* force new fullscreen mode */
9152 if (change_window_scaling_percent)
9154 /* keep window mode, but change window scaling */
9155 video.fullscreen_enabled = TRUE; /* force new window scaling */
9158 /* toggle fullscreen */
9159 ChangeVideoModeIfNeeded(setup.fullscreen);
9161 /* set setup value according to successfully changed fullscreen mode */
9162 setup.fullscreen = video.fullscreen_enabled;
9164 /* restore backbuffer content from temporary backbuffer backup bitmap */
9165 BlitBitmap(tmp_backbuffer, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
9167 FreeBitmap(tmp_backbuffer);
9170 /* update visible window/screen */
9171 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
9173 redraw_mask = REDRAW_ALL;
9178 void ChangeViewportPropertiesIfNeeded()
9180 int *door_1_x = &DX;
9181 int *door_1_y = &DY;
9182 int *door_2_x = (game_status == GAME_MODE_EDITOR ? &EX : &VX);
9183 int *door_2_y = (game_status == GAME_MODE_EDITOR ? &EY : &VY);
9184 int gfx_game_mode = (game_status == GAME_MODE_PLAYING ||
9185 game_status == GAME_MODE_EDITOR ? game_status :
9187 struct RectWithBorder *vp_playfield = &viewport.playfield[gfx_game_mode];
9188 struct RectWithBorder *vp_door_1 = &viewport.door_1[gfx_game_mode];
9189 struct RectWithBorder *vp_door_2 = &viewport.door_2[gfx_game_mode];
9190 int border_size = vp_playfield->border_size;
9191 int new_sx = vp_playfield->x + border_size;
9192 int new_sy = vp_playfield->y + border_size;
9193 int new_sxsize = vp_playfield->width - 2 * border_size;
9194 int new_sysize = vp_playfield->height - 2 * border_size;
9195 int new_real_sx = vp_playfield->x;
9196 int new_real_sy = vp_playfield->y;
9197 int new_full_sxsize = vp_playfield->width;
9198 int new_full_sysize = vp_playfield->height;
9200 int new_tilesize_var = TILESIZE / (setup.small_game_graphics ? 2 : 1);
9201 int tilesize = (gfx_game_mode == GAME_MODE_PLAYING ? new_tilesize_var :
9202 gfx_game_mode == GAME_MODE_EDITOR ? MINI_TILESIZE : TILESIZE);
9203 int new_scr_fieldx = new_sxsize / tilesize;
9204 int new_scr_fieldy = new_sysize / tilesize;
9205 int new_scr_fieldx_buffers = new_sxsize / new_tilesize_var;
9206 int new_scr_fieldy_buffers = new_sysize / new_tilesize_var;
9208 int new_scr_fieldx = (vp_playfield->width - 2 * border_size) / TILESIZE;
9209 int new_scr_fieldy = (vp_playfield->height - 2 * border_size) / TILESIZE;
9211 boolean init_gfx_buffers = FALSE;
9212 boolean init_video_buffer = FALSE;
9213 boolean init_gadgets_and_toons = FALSE;
9216 /* !!! TEST ONLY !!! */
9217 // InitGfxBuffers();
9221 if (viewport.window.width != WIN_XSIZE ||
9222 viewport.window.height != WIN_YSIZE)
9224 WIN_XSIZE = viewport.window.width;
9225 WIN_YSIZE = viewport.window.height;
9228 init_video_buffer = TRUE;
9229 init_gfx_buffers = TRUE;
9231 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
9235 SetDrawDeactivationMask(REDRAW_NONE);
9236 SetDrawBackgroundMask(REDRAW_FIELD);
9238 // RedrawBackground();
9242 // printf("::: video: init_video_buffer, init_gfx_buffers\n");
9245 if (new_scr_fieldx != SCR_FIELDX ||
9246 new_scr_fieldy != SCR_FIELDY)
9248 /* this always toggles between MAIN and GAME when using small tile size */
9250 SCR_FIELDX = new_scr_fieldx;
9251 SCR_FIELDY = new_scr_fieldy;
9253 // printf("::: new_scr_fieldx != SCR_FIELDX ...\n");
9257 if (new_tilesize_var != TILESIZE_VAR &&
9258 gfx_game_mode == GAME_MODE_PLAYING)
9260 /* doing this outside GAME_MODE_PLAYING would give wrong playfield size */
9262 TILESIZE_VAR = new_tilesize_var;
9264 init_gfx_buffers = TRUE;
9266 // printf("::: tilesize: init_gfx_buffers\n");
9272 new_sxsize != SXSIZE ||
9273 new_sysize != SYSIZE ||
9274 new_real_sx != REAL_SX ||
9275 new_real_sy != REAL_SY ||
9276 new_full_sxsize != FULL_SXSIZE ||
9277 new_full_sysize != FULL_SYSIZE ||
9278 new_tilesize_var != TILESIZE_VAR ||
9279 vp_door_1->x != *door_1_x ||
9280 vp_door_1->y != *door_1_y ||
9281 vp_door_2->x != *door_2_x ||
9282 vp_door_2->y != *door_2_y)
9286 SXSIZE = new_sxsize;
9287 SYSIZE = new_sysize;
9288 REAL_SX = new_real_sx;
9289 REAL_SY = new_real_sy;
9290 FULL_SXSIZE = new_full_sxsize;
9291 FULL_SYSIZE = new_full_sysize;
9292 TILESIZE_VAR = new_tilesize_var;
9295 printf("::: %d, %d, %d [%d]\n",
9296 SCR_FIELDX, SCR_FIELDY, TILESIZE_VAR,
9297 setup.small_game_graphics);
9300 *door_1_x = vp_door_1->x;
9301 *door_1_y = vp_door_1->y;
9302 *door_2_x = vp_door_2->x;
9303 *door_2_y = vp_door_2->y;
9306 init_gfx_buffers = TRUE;
9308 // printf("::: viewports: init_gfx_buffers\n");
9313 if (gfx_game_mode == GAME_MODE_MAIN)
9316 init_gadgets_and_toons = TRUE;
9318 // printf("::: viewports: init_gadgets_and_toons\n");
9326 if (init_gfx_buffers)
9328 // printf("::: init_gfx_buffers\n");
9330 SCR_FIELDX = new_scr_fieldx_buffers;
9331 SCR_FIELDY = new_scr_fieldy_buffers;
9335 SCR_FIELDX = new_scr_fieldx;
9336 SCR_FIELDY = new_scr_fieldy;
9339 if (init_video_buffer)
9341 // printf("::: init_video_buffer\n");
9343 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
9345 SetDrawDeactivationMask(REDRAW_NONE);
9346 SetDrawBackgroundMask(REDRAW_FIELD);
9349 if (init_gadgets_and_toons)
9351 // printf("::: init_gadgets_and_toons\n");
9358 printf("::: %d, %d / %d, %d [%d]\n", VX, VY, EX, EY, game_status);