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 DrawPreviewLevelExt(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 void DrawPreviewLevel(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 DrawPreviewLevelExt(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 DrawPreviewLevelExt(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 inline void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
3283 int graphic, int sync_frame, int mask_mode)
3285 int frame = getGraphicAnimationFrame(graphic, sync_frame);
3287 if (mask_mode == USE_MASKING)
3288 DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
3290 DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
3293 inline void DrawFixedGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
3294 int graphic, int sync_frame,
3297 int frame = getGraphicAnimationFrame(graphic, sync_frame);
3299 if (mask_mode == USE_MASKING)
3300 DrawFixedGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
3302 DrawFixedGraphicExt(dst_bitmap, x, y, graphic, frame);
3305 inline void DrawGraphicAnimation(int x, int y, int graphic)
3307 int lx = LEVELX(x), ly = LEVELY(y);
3309 if (!IN_SCR_FIELD(x, y))
3313 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR,
3314 graphic, GfxFrame[lx][ly], NO_MASKING);
3316 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
3317 graphic, GfxFrame[lx][ly], NO_MASKING);
3319 MarkTileDirty(x, y);
3322 inline void DrawFixedGraphicAnimation(int x, int y, int graphic)
3324 int lx = LEVELX(x), ly = LEVELY(y);
3326 if (!IN_SCR_FIELD(x, y))
3329 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
3330 graphic, GfxFrame[lx][ly], NO_MASKING);
3331 MarkTileDirty(x, y);
3334 void DrawLevelGraphicAnimation(int x, int y, int graphic)
3336 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
3339 void DrawLevelElementAnimation(int x, int y, int element)
3341 int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
3343 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
3346 inline void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
3348 int sx = SCREENX(x), sy = SCREENY(y);
3350 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
3353 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
3356 DrawGraphicAnimation(sx, sy, graphic);
3359 if (GFX_CRUMBLED(TILE_GFX_ELEMENT(x, y)))
3360 DrawLevelFieldCrumbled(x, y);
3362 if (GFX_CRUMBLED(Feld[x][y]))
3363 DrawLevelFieldCrumbled(x, y);
3367 void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
3369 int sx = SCREENX(x), sy = SCREENY(y);
3372 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
3375 graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
3377 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
3380 DrawGraphicAnimation(sx, sy, graphic);
3382 if (GFX_CRUMBLED(element))
3383 DrawLevelFieldCrumbled(x, y);
3386 static int getPlayerGraphic(struct PlayerInfo *player, int move_dir)
3388 if (player->use_murphy)
3390 /* this works only because currently only one player can be "murphy" ... */
3391 static int last_horizontal_dir = MV_LEFT;
3392 int graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir);
3394 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3395 last_horizontal_dir = move_dir;
3397 if (graphic == IMG_SP_MURPHY) /* undefined => use special graphic */
3399 int direction = (player->is_snapping ? move_dir : last_horizontal_dir);
3401 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
3407 return el_act_dir2img(player->artwork_element, player->GfxAction,move_dir);
3410 static boolean equalGraphics(int graphic1, int graphic2)
3412 struct GraphicInfo *g1 = &graphic_info[graphic1];
3413 struct GraphicInfo *g2 = &graphic_info[graphic2];
3415 return (g1->bitmap == g2->bitmap &&
3416 g1->src_x == g2->src_x &&
3417 g1->src_y == g2->src_y &&
3418 g1->anim_frames == g2->anim_frames &&
3419 g1->anim_delay == g2->anim_delay &&
3420 g1->anim_mode == g2->anim_mode);
3423 void DrawAllPlayers()
3427 for (i = 0; i < MAX_PLAYERS; i++)
3428 if (stored_player[i].active)
3429 DrawPlayer(&stored_player[i]);
3432 void DrawPlayerField(int x, int y)
3434 if (!IS_PLAYER(x, y))
3437 DrawPlayer(PLAYERINFO(x, y));
3440 #define DRAW_PLAYER_OVER_PUSHED_ELEMENT 1
3442 void DrawPlayer(struct PlayerInfo *player)
3444 int jx = player->jx;
3445 int jy = player->jy;
3446 int move_dir = player->MovDir;
3447 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? +1 : 0);
3448 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? +1 : 0);
3449 int last_jx = (player->is_moving ? jx - dx : jx);
3450 int last_jy = (player->is_moving ? jy - dy : jy);
3451 int next_jx = jx + dx;
3452 int next_jy = jy + dy;
3453 boolean player_is_moving = (player->MovPos ? TRUE : FALSE);
3454 boolean player_is_opaque = FALSE;
3455 int sx = SCREENX(jx), sy = SCREENY(jy);
3456 int sxx = 0, syy = 0;
3457 int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
3459 int action = ACTION_DEFAULT;
3460 int last_player_graphic = getPlayerGraphic(player, move_dir);
3461 int last_player_frame = player->Frame;
3464 /* GfxElement[][] is set to the element the player is digging or collecting;
3465 remove also for off-screen player if the player is not moving anymore */
3466 if (IN_LEV_FIELD(jx, jy) && !player_is_moving)
3467 GfxElement[jx][jy] = EL_UNDEFINED;
3469 if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
3473 if (!IN_LEV_FIELD(jx, jy))
3475 printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
3476 printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
3477 printf("DrawPlayerField(): This should never happen!\n");
3482 if (element == EL_EXPLOSION)
3485 action = (player->is_pushing ? ACTION_PUSHING :
3486 player->is_digging ? ACTION_DIGGING :
3487 player->is_collecting ? ACTION_COLLECTING :
3488 player->is_moving ? ACTION_MOVING :
3489 player->is_snapping ? ACTION_SNAPPING :
3490 player->is_dropping ? ACTION_DROPPING :
3491 player->is_waiting ? player->action_waiting : ACTION_DEFAULT);
3493 if (player->is_waiting)
3494 move_dir = player->dir_waiting;
3496 InitPlayerGfxAnimation(player, action, move_dir);
3498 /* ----------------------------------------------------------------------- */
3499 /* draw things in the field the player is leaving, if needed */
3500 /* ----------------------------------------------------------------------- */
3502 if (player->is_moving)
3504 if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
3506 DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
3508 if (last_element == EL_DYNAMITE_ACTIVE ||
3509 last_element == EL_EM_DYNAMITE_ACTIVE ||
3510 last_element == EL_SP_DISK_RED_ACTIVE)
3511 DrawDynamite(last_jx, last_jy);
3513 DrawLevelFieldThruMask(last_jx, last_jy);
3515 else if (last_element == EL_DYNAMITE_ACTIVE ||
3516 last_element == EL_EM_DYNAMITE_ACTIVE ||
3517 last_element == EL_SP_DISK_RED_ACTIVE)
3518 DrawDynamite(last_jx, last_jy);
3520 /* !!! this is not enough to prevent flickering of players which are
3521 moving next to each others without a free tile between them -- this
3522 can only be solved by drawing all players layer by layer (first the
3523 background, then the foreground etc.) !!! => TODO */
3524 else if (!IS_PLAYER(last_jx, last_jy))
3525 DrawLevelField(last_jx, last_jy);
3528 DrawLevelField(last_jx, last_jy);
3531 if (player->is_pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
3532 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
3535 if (!IN_SCR_FIELD(sx, sy))
3538 /* ----------------------------------------------------------------------- */
3539 /* draw things behind the player, if needed */
3540 /* ----------------------------------------------------------------------- */
3543 DrawLevelElement(jx, jy, Back[jx][jy]);
3544 else if (IS_ACTIVE_BOMB(element))
3545 DrawLevelElement(jx, jy, EL_EMPTY);
3548 if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
3550 int old_element = GfxElement[jx][jy];
3551 int old_graphic = el_act_dir2img(old_element, action, move_dir);
3552 int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
3554 if (GFX_CRUMBLED(old_element))
3555 DrawLevelFieldCrumbledDigging(jx, jy, move_dir, player->StepFrame);
3557 DrawGraphic(sx, sy, old_graphic, frame);
3559 if (graphic_info[old_graphic].anim_mode & ANIM_OPAQUE_PLAYER)
3560 player_is_opaque = TRUE;
3564 GfxElement[jx][jy] = EL_UNDEFINED;
3566 /* make sure that pushed elements are drawn with correct frame rate */
3568 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
3570 if (player->is_pushing && player->is_moving && !IS_ANIM_MODE_CE(graphic))
3571 GfxFrame[jx][jy] = player->StepFrame;
3573 if (player->is_pushing && player->is_moving)
3574 GfxFrame[jx][jy] = player->StepFrame;
3577 DrawLevelField(jx, jy);
3581 #if !DRAW_PLAYER_OVER_PUSHED_ELEMENT
3582 /* ----------------------------------------------------------------------- */
3583 /* draw player himself */
3584 /* ----------------------------------------------------------------------- */
3586 graphic = getPlayerGraphic(player, move_dir);
3588 /* in the case of changed player action or direction, prevent the current
3589 animation frame from being restarted for identical animations */
3590 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
3591 player->Frame = last_player_frame;
3593 frame = getGraphicAnimationFrame(graphic, player->Frame);
3597 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3598 sxx = player->GfxPos;
3600 syy = player->GfxPos;
3603 if (!setup.soft_scrolling && ScreenMovPos)
3606 if (player_is_opaque)
3607 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
3609 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3611 if (SHIELD_ON(player))
3613 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
3614 IMG_SHIELD_NORMAL_ACTIVE);
3615 int frame = getGraphicAnimationFrame(graphic, -1);
3617 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3621 #if DRAW_PLAYER_OVER_PUSHED_ELEMENT
3624 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3625 sxx = player->GfxPos;
3627 syy = player->GfxPos;
3631 /* ----------------------------------------------------------------------- */
3632 /* draw things the player is pushing, if needed */
3633 /* ----------------------------------------------------------------------- */
3636 printf("::: %d, %d [%d, %d] [%d]\n",
3637 player->is_pushing, player_is_moving, player->GfxAction,
3638 player->is_moving, player_is_moving);
3642 if (player->is_pushing && player->is_moving)
3644 int px = SCREENX(jx), py = SCREENY(jy);
3645 int pxx = (TILEX - ABS(sxx)) * dx;
3646 int pyy = (TILEY - ABS(syy)) * dy;
3647 int gfx_frame = GfxFrame[jx][jy];
3653 if (!IS_MOVING(jx, jy)) /* push movement already finished */
3655 element = Feld[next_jx][next_jy];
3656 gfx_frame = GfxFrame[next_jx][next_jy];
3659 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
3662 sync_frame = (IS_ANIM_MODE_CE(graphic) ? gfx_frame : player->StepFrame);
3663 frame = getGraphicAnimationFrame(graphic, sync_frame);
3665 frame = getGraphicAnimationFrame(graphic, player->StepFrame);
3668 /* draw background element under pushed element (like the Sokoban field) */
3670 if (game.use_masked_pushing && IS_MOVING(jx, jy))
3672 /* this allows transparent pushing animation over non-black background */
3675 DrawLevelElement(jx, jy, Back[jx][jy]);
3677 DrawLevelElement(jx, jy, EL_EMPTY);
3679 if (Back[next_jx][next_jy])
3680 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
3682 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
3684 else if (Back[next_jx][next_jy])
3685 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
3687 if (Back[next_jx][next_jy])
3688 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
3692 printf("::: %d, %d, %d, %d [%d] [%d, %d, %d] [%d] [%d, %d] [%d, %d]\n",
3693 jx, px, player->GfxPos, player->StepFrame,
3698 GfxFrame[jx][jy], GfxFrame[next_jx][next_jy]);
3702 /* do not draw (EM style) pushing animation when pushing is finished */
3703 /* (two-tile animations usually do not contain start and end frame) */
3704 if (graphic_info[graphic].double_movement && !IS_MOVING(jx, jy))
3705 DrawLevelElement(next_jx, next_jy, Feld[next_jx][next_jy]);
3707 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
3709 /* masked drawing is needed for EMC style (double) movement graphics */
3710 /* !!! (ONLY WHEN DRAWING PUSHED ELEMENT OVER THE PLAYER) !!! */
3711 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
3716 #if DRAW_PLAYER_OVER_PUSHED_ELEMENT
3717 /* ----------------------------------------------------------------------- */
3718 /* draw player himself */
3719 /* ----------------------------------------------------------------------- */
3721 graphic = getPlayerGraphic(player, move_dir);
3723 /* in the case of changed player action or direction, prevent the current
3724 animation frame from being restarted for identical animations */
3725 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
3726 player->Frame = last_player_frame;
3728 frame = getGraphicAnimationFrame(graphic, player->Frame);
3732 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3733 sxx = player->GfxPos;
3735 syy = player->GfxPos;
3738 if (!setup.soft_scrolling && ScreenMovPos)
3741 if (player_is_opaque)
3742 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
3744 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3746 if (SHIELD_ON(player))
3748 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
3749 IMG_SHIELD_NORMAL_ACTIVE);
3750 int frame = getGraphicAnimationFrame(graphic, -1);
3752 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3756 /* ----------------------------------------------------------------------- */
3757 /* draw things in front of player (active dynamite or dynabombs) */
3758 /* ----------------------------------------------------------------------- */
3760 if (IS_ACTIVE_BOMB(element))
3762 graphic = el2img(element);
3763 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
3765 if (game.emulation == EMU_SUPAPLEX)
3766 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
3768 DrawGraphicThruMask(sx, sy, graphic, frame);
3771 if (player_is_moving && last_element == EL_EXPLOSION)
3773 int element = (GfxElement[last_jx][last_jy] != EL_UNDEFINED ?
3774 GfxElement[last_jx][last_jy] : EL_EMPTY);
3775 int graphic = el_act2img(element, ACTION_EXPLODING);
3776 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
3777 int phase = ExplodePhase[last_jx][last_jy] - 1;
3778 int frame = getGraphicAnimationFrame(graphic, phase - delay);
3781 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
3784 /* ----------------------------------------------------------------------- */
3785 /* draw elements the player is just walking/passing through/under */
3786 /* ----------------------------------------------------------------------- */
3788 if (player_is_moving)
3790 /* handle the field the player is leaving ... */
3791 if (IS_ACCESSIBLE_INSIDE(last_element))
3792 DrawLevelField(last_jx, last_jy);
3793 else if (IS_ACCESSIBLE_UNDER(last_element))
3794 DrawLevelFieldThruMask(last_jx, last_jy);
3797 /* do not redraw accessible elements if the player is just pushing them */
3798 if (!player_is_moving || !player->is_pushing)
3800 /* ... and the field the player is entering */
3801 if (IS_ACCESSIBLE_INSIDE(element))
3802 DrawLevelField(jx, jy);
3803 else if (IS_ACCESSIBLE_UNDER(element))
3804 DrawLevelFieldThruMask(jx, jy);
3807 MarkTileDirty(sx, sy);
3810 /* ------------------------------------------------------------------------- */
3812 void WaitForEventToContinue()
3814 boolean still_wait = TRUE;
3816 /* simulate releasing mouse button over last gadget, if still pressed */
3818 HandleGadgets(-1, -1, 0);
3820 button_status = MB_RELEASED;
3836 case EVENT_BUTTONPRESS:
3837 case EVENT_KEYPRESS:
3841 case EVENT_KEYRELEASE:
3842 ClearPlayerAction();
3846 HandleOtherEvents(&event);
3850 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
3857 /* don't eat all CPU time */
3862 #define MAX_REQUEST_LINES 13
3863 #define MAX_REQUEST_LINE_FONT1_LEN 7
3864 #define MAX_REQUEST_LINE_FONT2_LEN 10
3866 boolean Request(char *text, unsigned int req_state)
3868 int mx, my, ty, result = -1;
3869 unsigned int old_door_state;
3870 int last_game_status = game_status; /* save current game status */
3871 int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
3872 int font_nr = FONT_TEXT_2;
3874 int max_word_len = 0;
3880 global.use_envelope_request = 0;
3884 if (maxWordLengthInString(text) > MAX_REQUEST_LINE_FONT1_LEN)
3886 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
3887 font_nr = FONT_TEXT_1;
3890 for (text_ptr = text; *text_ptr; text_ptr++)
3892 max_word_len = (*text_ptr != ' ' ? max_word_len + 1 : 0);
3894 if (max_word_len > MAX_REQUEST_LINE_FONT1_LEN)
3896 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
3898 font_nr = FONT_TEXT_1;
3900 font_nr = FONT_LEVEL_NUMBER;
3908 if (game_status == GAME_MODE_PLAYING)
3910 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
3911 BlitScreenToBitmap_EM(backbuffer);
3912 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
3913 BlitScreenToBitmap_SP(backbuffer);
3916 /* disable deactivated drawing when quick-loading level tape recording */
3917 if (tape.playing && tape.deactivate_display)
3918 TapeDeactivateDisplayOff(TRUE);
3920 SetMouseCursor(CURSOR_DEFAULT);
3922 #if defined(NETWORK_AVALIABLE)
3923 /* pause network game while waiting for request to answer */
3924 if (options.network &&
3925 game_status == GAME_MODE_PLAYING &&
3926 req_state & REQUEST_WAIT_FOR_INPUT)
3927 SendToServer_PausePlaying();
3930 old_door_state = GetDoorState();
3932 /* simulate releasing mouse button over last gadget, if still pressed */
3934 HandleGadgets(-1, -1, 0);
3938 /* draw released gadget before proceeding */
3942 if (old_door_state & DOOR_OPEN_1 && !global.use_envelope_request)
3944 if (old_door_state & DOOR_OPEN_1)
3948 if (!global.use_envelope_request)
3949 CloseDoor(DOOR_CLOSE_1);
3951 CloseDoor(DOOR_CLOSE_1);
3954 /* save old door content */
3955 BlitBitmap(bitmap_db_door, bitmap_db_door,
3956 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
3957 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
3961 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
3964 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3966 /* clear door drawing field */
3967 DrawBackground(DX, DY, DXSIZE, DYSIZE);
3969 /* force DOOR font inside door area */
3970 game_status = GAME_MODE_PSEUDO_DOOR;
3972 /* write text for request */
3973 for (text_ptr = text, ty = 0; ty < MAX_REQUEST_LINES; ty++)
3975 char text_line[max_request_line_len + 1];
3981 for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
3983 tc = *(text_ptr + tx);
3984 if (!tc || tc == ' ')
3995 strncpy(text_line, text_ptr, tl);
3998 DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
3999 DY + 8 + ty * (getFontHeight(font_nr) + 2),
4000 text_line, font_nr);
4002 text_ptr += tl + (tc == ' ' ? 1 : 0);
4005 game_status = last_game_status; /* restore current game status */
4008 if (global.use_envelope_request)
4012 CreateToolButtons();
4016 if (req_state & REQ_ASK)
4018 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
4019 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
4021 else if (req_state & REQ_CONFIRM)
4023 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
4025 else if (req_state & REQ_PLAYER)
4027 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
4028 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
4029 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
4030 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
4033 /* copy request gadgets to door backbuffer */
4034 BlitBitmap(drawto, bitmap_db_door,
4035 DX, DY, DXSIZE, DYSIZE,
4036 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
4039 if (global.use_envelope_request)
4041 ShowEnvelopeDoor(text, ACTION_OPENING);
4043 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4045 if ((req_state & REQ_ASK && (i == TOOL_CTRL_ID_YES ||
4046 i == TOOL_CTRL_ID_NO)) ||
4047 (req_state & REQ_CONFIRM && i == TOOL_CTRL_ID_CONFIRM) ||
4048 (req_state & REQ_PLAYER && (i == TOOL_CTRL_ID_PLAYER_1 &&
4049 i == TOOL_CTRL_ID_PLAYER_2 &&
4050 i == TOOL_CTRL_ID_PLAYER_3 &&
4051 i == TOOL_CTRL_ID_PLAYER_4)))
4053 int x = tool_gadget[i]->x + dDX;
4054 int y = tool_gadget[i]->y + dDY;
4056 ModifyGadget(tool_gadget[i], GDI_X, x, GDI_Y, y, GDI_END);
4063 if (!global.use_envelope_request)
4064 OpenDoor(DOOR_OPEN_1);
4066 OpenDoor(DOOR_OPEN_1);
4069 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
4071 if (game_status == GAME_MODE_PLAYING)
4073 SetPanelBackground();
4074 SetDrawBackgroundMask(REDRAW_DOOR_1);
4078 SetDrawBackgroundMask(REDRAW_FIELD);
4085 if (game_status != GAME_MODE_MAIN && !global.use_envelope_request)
4088 if (game_status != GAME_MODE_MAIN)
4092 button_status = MB_RELEASED;
4094 request_gadget_id = -1;
4096 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
4108 case EVENT_BUTTONPRESS:
4109 case EVENT_BUTTONRELEASE:
4110 case EVENT_MOTIONNOTIFY:
4112 if (event.type == EVENT_MOTIONNOTIFY)
4114 if (!PointerInWindow(window))
4115 continue; /* window and pointer are on different screens */
4120 motion_status = TRUE;
4121 mx = ((MotionEvent *) &event)->x;
4122 my = ((MotionEvent *) &event)->y;
4126 motion_status = FALSE;
4127 mx = ((ButtonEvent *) &event)->x;
4128 my = ((ButtonEvent *) &event)->y;
4129 if (event.type == EVENT_BUTTONPRESS)
4130 button_status = ((ButtonEvent *) &event)->button;
4132 button_status = MB_RELEASED;
4135 /* this sets 'request_gadget_id' */
4136 HandleGadgets(mx, my, button_status);
4138 switch (request_gadget_id)
4140 case TOOL_CTRL_ID_YES:
4143 case TOOL_CTRL_ID_NO:
4146 case TOOL_CTRL_ID_CONFIRM:
4147 result = TRUE | FALSE;
4150 case TOOL_CTRL_ID_PLAYER_1:
4153 case TOOL_CTRL_ID_PLAYER_2:
4156 case TOOL_CTRL_ID_PLAYER_3:
4159 case TOOL_CTRL_ID_PLAYER_4:
4170 case EVENT_KEYPRESS:
4171 switch (GetEventKey((KeyEvent *)&event, TRUE))
4174 if (req_state & REQ_CONFIRM)
4183 #if defined(TARGET_SDL2)
4193 if (req_state & REQ_PLAYER)
4197 case EVENT_KEYRELEASE:
4198 ClearPlayerAction();
4202 HandleOtherEvents(&event);
4206 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
4208 int joy = AnyJoystick();
4210 if (joy & JOY_BUTTON_1)
4212 else if (joy & JOY_BUTTON_2)
4218 if (game_status == GAME_MODE_PLAYING && local_player->LevelSolved_GameEnd)
4220 HandleGameActions();
4226 if (!PendingEvent()) /* delay only if no pending events */
4231 game_status = GAME_MODE_PSEUDO_DOOR;
4237 game_status = last_game_status; /* restore current game status */
4245 if (!PendingEvent()) /* delay only if no pending events */
4248 /* don't eat all CPU time */
4255 if (game_status != GAME_MODE_MAIN)
4261 if (global.use_envelope_request)
4262 ShowEnvelopeDoor(text, ACTION_CLOSING);
4266 if (!(req_state & REQ_STAY_OPEN) && !global.use_envelope_request)
4268 if (!(req_state & REQ_STAY_OPEN))
4271 CloseDoor(DOOR_CLOSE_1);
4273 if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
4274 (req_state & REQ_REOPEN))
4275 OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
4280 if (game_status == GAME_MODE_PLAYING)
4282 SetPanelBackground();
4283 SetDrawBackgroundMask(REDRAW_DOOR_1);
4287 SetDrawBackgroundMask(REDRAW_FIELD);
4290 #if defined(NETWORK_AVALIABLE)
4291 /* continue network game after request */
4292 if (options.network &&
4293 game_status == GAME_MODE_PLAYING &&
4294 req_state & REQUEST_WAIT_FOR_INPUT)
4295 SendToServer_ContinuePlaying();
4298 /* restore deactivated drawing when quick-loading level tape recording */
4299 if (tape.playing && tape.deactivate_display)
4300 TapeDeactivateDisplayOn();
4305 unsigned int OpenDoor(unsigned int door_state)
4307 if (door_state & DOOR_COPY_BACK)
4309 if (door_state & DOOR_OPEN_1)
4310 BlitBitmap(bitmap_db_door, bitmap_db_door,
4311 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
4312 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
4314 if (door_state & DOOR_OPEN_2)
4315 BlitBitmap(bitmap_db_door, bitmap_db_door,
4316 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY2, VXSIZE, VYSIZE,
4317 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
4319 door_state &= ~DOOR_COPY_BACK;
4322 return MoveDoor(door_state);
4325 unsigned int CloseDoor(unsigned int door_state)
4327 unsigned int old_door_state = GetDoorState();
4329 if (!(door_state & DOOR_NO_COPY_BACK))
4331 if (old_door_state & DOOR_OPEN_1)
4332 BlitBitmap(backbuffer, bitmap_db_door,
4333 DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
4335 if (old_door_state & DOOR_OPEN_2)
4336 BlitBitmap(backbuffer, bitmap_db_door,
4337 VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
4339 door_state &= ~DOOR_NO_COPY_BACK;
4342 return MoveDoor(door_state);
4345 unsigned int GetDoorState()
4347 return MoveDoor(DOOR_GET_STATE);
4350 unsigned int SetDoorState(unsigned int door_state)
4352 return MoveDoor(door_state | DOOR_SET_STATE);
4355 unsigned int MoveDoor(unsigned int door_state)
4357 static int door1 = DOOR_OPEN_1;
4358 static int door2 = DOOR_CLOSE_2;
4359 unsigned int door_delay = 0;
4360 unsigned int door_delay_value;
4363 if (door_1.width < 0 || door_1.width > DXSIZE)
4364 door_1.width = DXSIZE;
4365 if (door_1.height < 0 || door_1.height > DYSIZE)
4366 door_1.height = DYSIZE;
4367 if (door_2.width < 0 || door_2.width > VXSIZE)
4368 door_2.width = VXSIZE;
4369 if (door_2.height < 0 || door_2.height > VYSIZE)
4370 door_2.height = VYSIZE;
4372 if (door_state == DOOR_GET_STATE)
4373 return (door1 | door2);
4375 if (door_state & DOOR_SET_STATE)
4377 if (door_state & DOOR_ACTION_1)
4378 door1 = door_state & DOOR_ACTION_1;
4379 if (door_state & DOOR_ACTION_2)
4380 door2 = door_state & DOOR_ACTION_2;
4382 return (door1 | door2);
4385 if (!(door_state & DOOR_FORCE_REDRAW))
4387 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
4388 door_state &= ~DOOR_OPEN_1;
4389 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
4390 door_state &= ~DOOR_CLOSE_1;
4391 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
4392 door_state &= ~DOOR_OPEN_2;
4393 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
4394 door_state &= ~DOOR_CLOSE_2;
4397 door_delay_value = (door_state & DOOR_ACTION_1 ? door_1.step_delay :
4400 if (setup.quick_doors)
4402 stepsize = 20; /* must be chosen to always draw last frame */
4403 door_delay_value = 0;
4406 if (global.autoplay_leveldir)
4408 door_state |= DOOR_NO_DELAY;
4409 door_state &= ~DOOR_CLOSE_ALL;
4413 if (game_status == GAME_MODE_EDITOR)
4414 door_state |= DOOR_NO_DELAY;
4417 if (door_state & DOOR_ACTION)
4419 boolean handle_door_1 = (door_state & DOOR_ACTION_1);
4420 boolean handle_door_2 = (door_state & DOOR_ACTION_2);
4421 boolean door_1_done = (!handle_door_1);
4422 boolean door_2_done = (!handle_door_2);
4423 boolean door_1_vertical = (door_1.anim_mode & ANIM_VERTICAL);
4424 boolean door_2_vertical = (door_2.anim_mode & ANIM_VERTICAL);
4425 int door_size_1 = (door_1_vertical ? door_1.height : door_1.width);
4426 int door_size_2 = (door_2_vertical ? door_2.height : door_2.width);
4427 int max_door_size_1 = (door_1_vertical ? DYSIZE : DXSIZE);
4428 int max_door_size_2 = (door_2_vertical ? VYSIZE : VXSIZE);
4429 int door_size = (handle_door_1 ? door_size_1 : door_size_2);
4430 int max_door_size = (handle_door_1 ? max_door_size_1 : max_door_size_2);
4431 int door_skip = max_door_size - door_size;
4432 int end = door_size;
4433 int start = ((door_state & DOOR_NO_DELAY) ? end : 0);
4436 if (!(door_state & DOOR_NO_DELAY) && !setup.quick_doors)
4438 /* opening door sound has priority over simultaneously closing door */
4439 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
4440 PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
4441 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
4442 PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
4445 for (k = start; k <= end && !(door_1_done && door_2_done); k += stepsize)
4448 Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
4449 GC gc = bitmap->stored_clip_gc;
4451 if (door_state & DOOR_ACTION_1)
4453 int a = MIN(x * door_1.step_offset, end);
4454 int p = (door_state & DOOR_OPEN_1 ? end - a : a);
4455 int i = p + door_skip;
4457 if (door_1.anim_mode & ANIM_STATIC_PANEL)
4459 BlitBitmap(bitmap_db_door, drawto,
4460 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1,
4461 DXSIZE, DYSIZE, DX, DY);
4465 BlitBitmap(bitmap_db_door, drawto,
4466 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + p / 2,
4467 DXSIZE, DYSIZE - p / 2, DX, DY);
4469 ClearRectangle(drawto, DX, DY + DYSIZE - p / 2, DXSIZE, p / 2);
4472 if (door_1.anim_mode & ANIM_HORIZONTAL && x <= DXSIZE)
4474 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
4475 int dst1_x = DX + DXSIZE - i, dst1_y = DY;
4476 int src2_x = DXSIZE - i, src2_y = DOOR_GFX_PAGEY1;
4477 int dst2_x = DX, dst2_y = DY;
4478 int width = i, height = DYSIZE;
4480 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
4481 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
4484 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
4485 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
4488 else if (door_1.anim_mode & ANIM_VERTICAL && x <= DYSIZE)
4490 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
4491 int dst1_x = DX, dst1_y = DY + DYSIZE - i;
4492 int src2_x = 0, src2_y = DOOR_GFX_PAGEY1 + DYSIZE - i;
4493 int dst2_x = DX, dst2_y = DY;
4494 int width = DXSIZE, height = i;
4496 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
4497 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
4500 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
4501 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
4504 else if (x <= DXSIZE) /* ANIM_DEFAULT */
4506 int j = (door_1.anim_mode == ANIM_DEFAULT ? (DXSIZE - i) / 3 : 0);
4508 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
4509 BlitBitmapMasked(bitmap, drawto,
4510 DXSIZE, DOOR_GFX_PAGEY1, i, 77,
4511 DX + DXSIZE - i, DY + j);
4512 BlitBitmapMasked(bitmap, drawto,
4513 DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
4514 DX + DXSIZE - i, DY + 140 + j);
4515 SetClipOrigin(bitmap, gc, DX - DXSIZE + i,
4516 DY - (DOOR_GFX_PAGEY1 + j));
4517 BlitBitmapMasked(bitmap, drawto,
4518 DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
4520 BlitBitmapMasked(bitmap, drawto,
4521 DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
4524 BlitBitmapMasked(bitmap, drawto,
4525 DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
4527 BlitBitmapMasked(bitmap, drawto,
4528 DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
4530 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
4531 BlitBitmapMasked(bitmap, drawto,
4532 DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
4533 DX + DXSIZE - i, DY + 77 + j);
4534 BlitBitmapMasked(bitmap, drawto,
4535 DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
4536 DX + DXSIZE - i, DY + 203 + j);
4539 redraw_mask |= REDRAW_DOOR_1;
4540 door_1_done = (a == end);
4543 if (door_state & DOOR_ACTION_2)
4545 int a = MIN(x * door_2.step_offset, door_size);
4546 int p = (door_state & DOOR_OPEN_2 ? door_size - a : a);
4547 int i = p + door_skip;
4549 if (door_2.anim_mode & ANIM_STATIC_PANEL)
4551 BlitBitmap(bitmap_db_door, drawto,
4552 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2,
4553 VXSIZE, VYSIZE, VX, VY);
4555 else if (x <= VYSIZE)
4557 BlitBitmap(bitmap_db_door, drawto,
4558 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + p / 2,
4559 VXSIZE, VYSIZE - p / 2, VX, VY);
4561 ClearRectangle(drawto, VX, VY + VYSIZE - p / 2, VXSIZE, p / 2);
4564 if (door_2.anim_mode & ANIM_HORIZONTAL && x <= VXSIZE)
4566 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
4567 int dst1_x = VX + VXSIZE - i, dst1_y = VY;
4568 int src2_x = VXSIZE - i, src2_y = DOOR_GFX_PAGEY2;
4569 int dst2_x = VX, dst2_y = VY;
4570 int width = i, height = VYSIZE;
4572 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
4573 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
4576 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
4577 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
4580 else if (door_2.anim_mode & ANIM_VERTICAL && x <= VYSIZE)
4582 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
4583 int dst1_x = VX, dst1_y = VY + VYSIZE - i;
4584 int src2_x = 0, src2_y = DOOR_GFX_PAGEY2 + VYSIZE - i;
4585 int dst2_x = VX, dst2_y = VY;
4586 int width = VXSIZE, height = i;
4588 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
4589 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
4592 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
4593 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
4596 else if (x <= VXSIZE) /* ANIM_DEFAULT */
4598 int j = (door_2.anim_mode == ANIM_DEFAULT ? (VXSIZE - i) / 3 : 0);
4600 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
4601 BlitBitmapMasked(bitmap, drawto,
4602 VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
4603 VX + VXSIZE - i, VY + j);
4604 SetClipOrigin(bitmap, gc,
4605 VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
4606 BlitBitmapMasked(bitmap, drawto,
4607 VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
4610 BlitBitmapMasked(bitmap, drawto,
4611 VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
4612 i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
4613 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
4614 BlitBitmapMasked(bitmap, drawto,
4615 VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
4617 VX + VXSIZE - i, VY + VYSIZE / 2 + j);
4620 redraw_mask |= REDRAW_DOOR_2;
4621 door_2_done = (a == VXSIZE);
4624 if (!(door_state & DOOR_NO_DELAY))
4628 if (game_status == GAME_MODE_MAIN)
4631 WaitUntilDelayReached(&door_delay, door_delay_value);
4636 if (door_state & DOOR_ACTION_1)
4637 door1 = door_state & DOOR_ACTION_1;
4638 if (door_state & DOOR_ACTION_2)
4639 door2 = door_state & DOOR_ACTION_2;
4641 return (door1 | door2);
4644 void DrawSpecialEditorDoor()
4646 /* draw bigger toolbox window */
4647 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
4648 DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
4650 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
4651 EX - 6, VY - 4, EXSIZE + 12, EYSIZE - VYSIZE + 4,
4654 redraw_mask |= REDRAW_ALL;
4657 void UndrawSpecialEditorDoor()
4659 /* draw normal tape recorder window */
4660 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
4661 EX - 6, EY - 12, EXSIZE + 12, EYSIZE - VYSIZE + 12,
4664 redraw_mask |= REDRAW_ALL;
4668 /* ---------- new tool button stuff ---------------------------------------- */
4675 struct TextPosInfo *pos;
4678 } toolbutton_info[NUM_TOOL_BUTTONS] =
4681 IMG_REQUEST_BUTTON_GFX_YES, &request.button.yes,
4682 TOOL_CTRL_ID_YES, "yes"
4685 IMG_REQUEST_BUTTON_GFX_NO, &request.button.no,
4686 TOOL_CTRL_ID_NO, "no"
4689 IMG_REQUEST_BUTTON_GFX_CONFIRM, &request.button.confirm,
4690 TOOL_CTRL_ID_CONFIRM, "confirm"
4693 IMG_REQUEST_BUTTON_GFX_PLAYER_1, &request.button.player_1,
4694 TOOL_CTRL_ID_PLAYER_1, "player 1"
4697 IMG_REQUEST_BUTTON_GFX_PLAYER_2, &request.button.player_2,
4698 TOOL_CTRL_ID_PLAYER_2, "player 2"
4701 IMG_REQUEST_BUTTON_GFX_PLAYER_3, &request.button.player_3,
4702 TOOL_CTRL_ID_PLAYER_3, "player 3"
4705 IMG_REQUEST_BUTTON_GFX_PLAYER_4, &request.button.player_4,
4706 TOOL_CTRL_ID_PLAYER_4, "player 4"
4710 void CreateToolButtons()
4714 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4716 struct GraphicInfo *gfx = &graphic_info[toolbutton_info[i].graphic];
4717 struct TextPosInfo *pos = toolbutton_info[i].pos;
4718 struct GadgetInfo *gi;
4719 Bitmap *deco_bitmap = None;
4720 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
4721 unsigned int event_mask = GD_EVENT_RELEASED;
4722 int gd_x = gfx->src_x;
4723 int gd_y = gfx->src_y;
4724 int gd_xp = gfx->src_x + gfx->pressed_xoffset;
4725 int gd_yp = gfx->src_y + gfx->pressed_yoffset;
4728 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
4730 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
4732 getSizedGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr), 0,
4733 pos->size, &deco_bitmap, &deco_x, &deco_y);
4734 deco_xpos = (gfx->width - pos->size) / 2;
4735 deco_ypos = (gfx->height - pos->size) / 2;
4738 gi = CreateGadget(GDI_CUSTOM_ID, id,
4739 GDI_INFO_TEXT, toolbutton_info[i].infotext,
4742 GDI_WIDTH, gfx->width,
4743 GDI_HEIGHT, gfx->height,
4744 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
4745 GDI_STATE, GD_BUTTON_UNPRESSED,
4746 GDI_DESIGN_UNPRESSED, gfx->bitmap, gd_x, gd_y,
4747 GDI_DESIGN_PRESSED, gfx->bitmap, gd_xp, gd_yp,
4748 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
4749 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
4750 GDI_DECORATION_SIZE, pos->size, pos->size,
4751 GDI_DECORATION_SHIFTING, 1, 1,
4752 GDI_DIRECT_DRAW, FALSE,
4753 GDI_EVENT_MASK, event_mask,
4754 GDI_CALLBACK_ACTION, HandleToolButtons,
4758 Error(ERR_EXIT, "cannot create gadget");
4760 tool_gadget[id] = gi;
4766 /* graphic position values for tool buttons */
4767 #define TOOL_BUTTON_YES_XPOS 2
4768 #define TOOL_BUTTON_YES_YPOS 250
4769 #define TOOL_BUTTON_YES_GFX_YPOS 0
4770 #define TOOL_BUTTON_YES_XSIZE 46
4771 #define TOOL_BUTTON_YES_YSIZE 28
4772 #define TOOL_BUTTON_NO_XPOS 52
4773 #define TOOL_BUTTON_NO_YPOS TOOL_BUTTON_YES_YPOS
4774 #define TOOL_BUTTON_NO_GFX_YPOS TOOL_BUTTON_YES_GFX_YPOS
4775 #define TOOL_BUTTON_NO_XSIZE TOOL_BUTTON_YES_XSIZE
4776 #define TOOL_BUTTON_NO_YSIZE TOOL_BUTTON_YES_YSIZE
4777 #define TOOL_BUTTON_CONFIRM_XPOS TOOL_BUTTON_YES_XPOS
4778 #define TOOL_BUTTON_CONFIRM_YPOS TOOL_BUTTON_YES_YPOS
4779 #define TOOL_BUTTON_CONFIRM_GFX_YPOS 30
4780 #define TOOL_BUTTON_CONFIRM_XSIZE 96
4781 #define TOOL_BUTTON_CONFIRM_YSIZE TOOL_BUTTON_YES_YSIZE
4782 #define TOOL_BUTTON_PLAYER_XSIZE 30
4783 #define TOOL_BUTTON_PLAYER_YSIZE 30
4784 #define TOOL_BUTTON_PLAYER_GFX_XPOS 5
4785 #define TOOL_BUTTON_PLAYER_GFX_YPOS 185
4786 #define TOOL_BUTTON_PLAYER_XPOS (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
4787 #define TOOL_BUTTON_PLAYER_YPOS (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
4788 #define TOOL_BUTTON_PLAYER1_XPOS (TOOL_BUTTON_PLAYER_XPOS \
4789 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
4790 #define TOOL_BUTTON_PLAYER2_XPOS (TOOL_BUTTON_PLAYER_XPOS \
4791 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
4792 #define TOOL_BUTTON_PLAYER3_XPOS (TOOL_BUTTON_PLAYER_XPOS \
4793 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
4794 #define TOOL_BUTTON_PLAYER4_XPOS (TOOL_BUTTON_PLAYER_XPOS \
4795 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
4796 #define TOOL_BUTTON_PLAYER1_YPOS (TOOL_BUTTON_PLAYER_YPOS \
4797 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
4798 #define TOOL_BUTTON_PLAYER2_YPOS (TOOL_BUTTON_PLAYER_YPOS \
4799 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
4800 #define TOOL_BUTTON_PLAYER3_YPOS (TOOL_BUTTON_PLAYER_YPOS \
4801 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
4802 #define TOOL_BUTTON_PLAYER4_YPOS (TOOL_BUTTON_PLAYER_YPOS \
4803 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
4812 } toolbutton_info[NUM_TOOL_BUTTONS] =
4815 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_GFX_YPOS,
4816 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_YPOS,
4817 TOOL_BUTTON_YES_XSIZE, TOOL_BUTTON_YES_YSIZE,
4822 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_GFX_YPOS,
4823 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_YPOS,
4824 TOOL_BUTTON_NO_XSIZE, TOOL_BUTTON_NO_YSIZE,
4829 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_GFX_YPOS,
4830 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_YPOS,
4831 TOOL_BUTTON_CONFIRM_XSIZE, TOOL_BUTTON_CONFIRM_YSIZE,
4832 TOOL_CTRL_ID_CONFIRM,
4836 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
4837 TOOL_BUTTON_PLAYER1_XPOS, TOOL_BUTTON_PLAYER1_YPOS,
4838 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
4839 TOOL_CTRL_ID_PLAYER_1,
4843 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
4844 TOOL_BUTTON_PLAYER2_XPOS, TOOL_BUTTON_PLAYER2_YPOS,
4845 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
4846 TOOL_CTRL_ID_PLAYER_2,
4850 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
4851 TOOL_BUTTON_PLAYER3_XPOS, TOOL_BUTTON_PLAYER3_YPOS,
4852 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
4853 TOOL_CTRL_ID_PLAYER_3,
4857 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
4858 TOOL_BUTTON_PLAYER4_XPOS, TOOL_BUTTON_PLAYER4_YPOS,
4859 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
4860 TOOL_CTRL_ID_PLAYER_4,
4865 void CreateToolButtons()
4869 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4871 Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
4872 Bitmap *deco_bitmap = None;
4873 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
4874 struct GadgetInfo *gi;
4875 unsigned int event_mask;
4876 int gd_xoffset, gd_yoffset;
4877 int gd_x1, gd_x2, gd_y;
4880 event_mask = GD_EVENT_RELEASED;
4882 gd_xoffset = toolbutton_info[i].xpos;
4883 gd_yoffset = toolbutton_info[i].ypos;
4884 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
4885 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
4886 gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
4888 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
4890 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
4892 getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr),
4893 &deco_bitmap, &deco_x, &deco_y);
4894 deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
4895 deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
4898 gi = CreateGadget(GDI_CUSTOM_ID, id,
4899 GDI_INFO_TEXT, toolbutton_info[i].infotext,
4900 GDI_X, DX + toolbutton_info[i].x,
4901 GDI_Y, DY + toolbutton_info[i].y,
4902 GDI_WIDTH, toolbutton_info[i].width,
4903 GDI_HEIGHT, toolbutton_info[i].height,
4904 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
4905 GDI_STATE, GD_BUTTON_UNPRESSED,
4906 GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
4907 GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
4908 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
4909 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
4910 GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
4911 GDI_DECORATION_SHIFTING, 1, 1,
4912 GDI_DIRECT_DRAW, FALSE,
4913 GDI_EVENT_MASK, event_mask,
4914 GDI_CALLBACK_ACTION, HandleToolButtons,
4918 Error(ERR_EXIT, "cannot create gadget");
4920 tool_gadget[id] = gi;
4926 void FreeToolButtons()
4930 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4931 FreeGadget(tool_gadget[i]);
4934 static void UnmapToolButtons()
4938 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4939 UnmapGadget(tool_gadget[i]);
4942 static void HandleToolButtons(struct GadgetInfo *gi)
4944 request_gadget_id = gi->custom_id;
4947 static struct Mapping_EM_to_RND_object
4950 boolean is_rnd_to_em_mapping; /* unique mapping EM <-> RND */
4951 boolean is_backside; /* backside of moving element */
4957 em_object_mapping_list[] =
4960 Xblank, TRUE, FALSE,
4964 Yacid_splash_eB, FALSE, FALSE,
4965 EL_ACID_SPLASH_RIGHT, -1, -1
4968 Yacid_splash_wB, FALSE, FALSE,
4969 EL_ACID_SPLASH_LEFT, -1, -1
4972 #ifdef EM_ENGINE_BAD_ROLL
4974 Xstone_force_e, FALSE, FALSE,
4975 EL_ROCK, -1, MV_BIT_RIGHT
4978 Xstone_force_w, FALSE, FALSE,
4979 EL_ROCK, -1, MV_BIT_LEFT
4982 Xnut_force_e, FALSE, FALSE,
4983 EL_NUT, -1, MV_BIT_RIGHT
4986 Xnut_force_w, FALSE, FALSE,
4987 EL_NUT, -1, MV_BIT_LEFT
4990 Xspring_force_e, FALSE, FALSE,
4991 EL_SPRING, -1, MV_BIT_RIGHT
4994 Xspring_force_w, FALSE, FALSE,
4995 EL_SPRING, -1, MV_BIT_LEFT
4998 Xemerald_force_e, FALSE, FALSE,
4999 EL_EMERALD, -1, MV_BIT_RIGHT
5002 Xemerald_force_w, FALSE, FALSE,
5003 EL_EMERALD, -1, MV_BIT_LEFT
5006 Xdiamond_force_e, FALSE, FALSE,
5007 EL_DIAMOND, -1, MV_BIT_RIGHT
5010 Xdiamond_force_w, FALSE, FALSE,
5011 EL_DIAMOND, -1, MV_BIT_LEFT
5014 Xbomb_force_e, FALSE, FALSE,
5015 EL_BOMB, -1, MV_BIT_RIGHT
5018 Xbomb_force_w, FALSE, FALSE,
5019 EL_BOMB, -1, MV_BIT_LEFT
5021 #endif /* EM_ENGINE_BAD_ROLL */
5024 Xstone, TRUE, FALSE,
5028 Xstone_pause, FALSE, FALSE,
5032 Xstone_fall, FALSE, FALSE,
5036 Ystone_s, FALSE, FALSE,
5037 EL_ROCK, ACTION_FALLING, -1
5040 Ystone_sB, FALSE, TRUE,
5041 EL_ROCK, ACTION_FALLING, -1
5044 Ystone_e, FALSE, FALSE,
5045 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
5048 Ystone_eB, FALSE, TRUE,
5049 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
5052 Ystone_w, FALSE, FALSE,
5053 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
5056 Ystone_wB, FALSE, TRUE,
5057 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
5064 Xnut_pause, FALSE, FALSE,
5068 Xnut_fall, FALSE, FALSE,
5072 Ynut_s, FALSE, FALSE,
5073 EL_NUT, ACTION_FALLING, -1
5076 Ynut_sB, FALSE, TRUE,
5077 EL_NUT, ACTION_FALLING, -1
5080 Ynut_e, FALSE, FALSE,
5081 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
5084 Ynut_eB, FALSE, TRUE,
5085 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
5088 Ynut_w, FALSE, FALSE,
5089 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
5092 Ynut_wB, FALSE, TRUE,
5093 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
5096 Xbug_n, TRUE, FALSE,
5100 Xbug_e, TRUE, FALSE,
5101 EL_BUG_RIGHT, -1, -1
5104 Xbug_s, TRUE, FALSE,
5108 Xbug_w, TRUE, FALSE,
5112 Xbug_gon, FALSE, FALSE,
5116 Xbug_goe, FALSE, FALSE,
5117 EL_BUG_RIGHT, -1, -1
5120 Xbug_gos, FALSE, FALSE,
5124 Xbug_gow, FALSE, FALSE,
5128 Ybug_n, FALSE, FALSE,
5129 EL_BUG, ACTION_MOVING, MV_BIT_UP
5132 Ybug_nB, FALSE, TRUE,
5133 EL_BUG, ACTION_MOVING, MV_BIT_UP
5136 Ybug_e, FALSE, FALSE,
5137 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
5140 Ybug_eB, FALSE, TRUE,
5141 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
5144 Ybug_s, FALSE, FALSE,
5145 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
5148 Ybug_sB, FALSE, TRUE,
5149 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
5152 Ybug_w, FALSE, FALSE,
5153 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
5156 Ybug_wB, FALSE, TRUE,
5157 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
5160 Ybug_w_n, FALSE, FALSE,
5161 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
5164 Ybug_n_e, FALSE, FALSE,
5165 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
5168 Ybug_e_s, FALSE, FALSE,
5169 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
5172 Ybug_s_w, FALSE, FALSE,
5173 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
5176 Ybug_e_n, FALSE, FALSE,
5177 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
5180 Ybug_s_e, FALSE, FALSE,
5181 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
5184 Ybug_w_s, FALSE, FALSE,
5185 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
5188 Ybug_n_w, FALSE, FALSE,
5189 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
5192 Ybug_stone, FALSE, FALSE,
5193 EL_BUG, ACTION_SMASHED_BY_ROCK, -1
5196 Ybug_spring, FALSE, FALSE,
5197 EL_BUG, ACTION_SMASHED_BY_SPRING, -1
5200 Xtank_n, TRUE, FALSE,
5201 EL_SPACESHIP_UP, -1, -1
5204 Xtank_e, TRUE, FALSE,
5205 EL_SPACESHIP_RIGHT, -1, -1
5208 Xtank_s, TRUE, FALSE,
5209 EL_SPACESHIP_DOWN, -1, -1
5212 Xtank_w, TRUE, FALSE,
5213 EL_SPACESHIP_LEFT, -1, -1
5216 Xtank_gon, FALSE, FALSE,
5217 EL_SPACESHIP_UP, -1, -1
5220 Xtank_goe, FALSE, FALSE,
5221 EL_SPACESHIP_RIGHT, -1, -1
5224 Xtank_gos, FALSE, FALSE,
5225 EL_SPACESHIP_DOWN, -1, -1
5228 Xtank_gow, FALSE, FALSE,
5229 EL_SPACESHIP_LEFT, -1, -1
5232 Ytank_n, FALSE, FALSE,
5233 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
5236 Ytank_nB, FALSE, TRUE,
5237 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
5240 Ytank_e, FALSE, FALSE,
5241 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
5244 Ytank_eB, FALSE, TRUE,
5245 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
5248 Ytank_s, FALSE, FALSE,
5249 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
5252 Ytank_sB, FALSE, TRUE,
5253 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
5256 Ytank_w, FALSE, FALSE,
5257 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
5260 Ytank_wB, FALSE, TRUE,
5261 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
5264 Ytank_w_n, FALSE, FALSE,
5265 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
5268 Ytank_n_e, FALSE, FALSE,
5269 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
5272 Ytank_e_s, FALSE, FALSE,
5273 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
5276 Ytank_s_w, FALSE, FALSE,
5277 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
5280 Ytank_e_n, FALSE, FALSE,
5281 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
5284 Ytank_s_e, FALSE, FALSE,
5285 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
5288 Ytank_w_s, FALSE, FALSE,
5289 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
5292 Ytank_n_w, FALSE, FALSE,
5293 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
5296 Ytank_stone, FALSE, FALSE,
5297 EL_SPACESHIP, ACTION_SMASHED_BY_ROCK, -1
5300 Ytank_spring, FALSE, FALSE,
5301 EL_SPACESHIP, ACTION_SMASHED_BY_SPRING, -1
5304 Xandroid, TRUE, FALSE,
5305 EL_EMC_ANDROID, ACTION_ACTIVE, -1
5308 Xandroid_1_n, FALSE, FALSE,
5309 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
5312 Xandroid_2_n, FALSE, FALSE,
5313 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
5316 Xandroid_1_e, FALSE, FALSE,
5317 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
5320 Xandroid_2_e, FALSE, FALSE,
5321 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
5324 Xandroid_1_w, FALSE, FALSE,
5325 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
5328 Xandroid_2_w, FALSE, FALSE,
5329 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
5332 Xandroid_1_s, FALSE, FALSE,
5333 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
5336 Xandroid_2_s, FALSE, FALSE,
5337 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
5340 Yandroid_n, FALSE, FALSE,
5341 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
5344 Yandroid_nB, FALSE, TRUE,
5345 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
5348 Yandroid_ne, FALSE, FALSE,
5349 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPRIGHT
5352 Yandroid_neB, FALSE, TRUE,
5353 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPRIGHT
5356 Yandroid_e, FALSE, FALSE,
5357 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
5360 Yandroid_eB, FALSE, TRUE,
5361 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
5364 Yandroid_se, FALSE, FALSE,
5365 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNRIGHT
5368 Yandroid_seB, FALSE, TRUE,
5369 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNRIGHT
5372 Yandroid_s, FALSE, FALSE,
5373 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
5376 Yandroid_sB, FALSE, TRUE,
5377 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
5380 Yandroid_sw, FALSE, FALSE,
5381 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNLEFT
5384 Yandroid_swB, FALSE, TRUE,
5385 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNLEFT
5388 Yandroid_w, FALSE, FALSE,
5389 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
5392 Yandroid_wB, FALSE, TRUE,
5393 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
5396 Yandroid_nw, FALSE, FALSE,
5397 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPLEFT
5400 Yandroid_nwB, FALSE, TRUE,
5401 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPLEFT
5404 Xspring, TRUE, FALSE,
5408 Xspring_pause, FALSE, FALSE,
5412 Xspring_e, FALSE, FALSE,
5416 Xspring_w, FALSE, FALSE,
5420 Xspring_fall, FALSE, FALSE,
5424 Yspring_s, FALSE, FALSE,
5425 EL_SPRING, ACTION_FALLING, -1
5428 Yspring_sB, FALSE, TRUE,
5429 EL_SPRING, ACTION_FALLING, -1
5432 Yspring_e, FALSE, FALSE,
5433 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
5436 Yspring_eB, FALSE, TRUE,
5437 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
5440 Yspring_w, FALSE, FALSE,
5441 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
5444 Yspring_wB, FALSE, TRUE,
5445 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
5448 Yspring_kill_e, FALSE, FALSE,
5449 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
5452 Yspring_kill_eB, FALSE, TRUE,
5453 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
5456 Yspring_kill_w, FALSE, FALSE,
5457 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
5460 Yspring_kill_wB, FALSE, TRUE,
5461 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
5464 Xeater_n, TRUE, FALSE,
5465 EL_YAMYAM_UP, -1, -1
5468 Xeater_e, TRUE, FALSE,
5469 EL_YAMYAM_RIGHT, -1, -1
5472 Xeater_w, TRUE, FALSE,
5473 EL_YAMYAM_LEFT, -1, -1
5476 Xeater_s, TRUE, FALSE,
5477 EL_YAMYAM_DOWN, -1, -1
5480 Yeater_n, FALSE, FALSE,
5481 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
5484 Yeater_nB, FALSE, TRUE,
5485 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
5488 Yeater_e, FALSE, FALSE,
5489 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
5492 Yeater_eB, FALSE, TRUE,
5493 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
5496 Yeater_s, FALSE, FALSE,
5497 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
5500 Yeater_sB, FALSE, TRUE,
5501 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
5504 Yeater_w, FALSE, FALSE,
5505 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
5508 Yeater_wB, FALSE, TRUE,
5509 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
5512 Yeater_stone, FALSE, FALSE,
5513 EL_YAMYAM, ACTION_SMASHED_BY_ROCK, -1
5516 Yeater_spring, FALSE, FALSE,
5517 EL_YAMYAM, ACTION_SMASHED_BY_SPRING, -1
5520 Xalien, TRUE, FALSE,
5524 Xalien_pause, FALSE, FALSE,
5528 Yalien_n, FALSE, FALSE,
5529 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
5532 Yalien_nB, FALSE, TRUE,
5533 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
5536 Yalien_e, FALSE, FALSE,
5537 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
5540 Yalien_eB, FALSE, TRUE,
5541 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
5544 Yalien_s, FALSE, FALSE,
5545 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
5548 Yalien_sB, FALSE, TRUE,
5549 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
5552 Yalien_w, FALSE, FALSE,
5553 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
5556 Yalien_wB, FALSE, TRUE,
5557 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
5560 Yalien_stone, FALSE, FALSE,
5561 EL_ROBOT, ACTION_SMASHED_BY_ROCK, -1
5564 Yalien_spring, FALSE, FALSE,
5565 EL_ROBOT, ACTION_SMASHED_BY_SPRING, -1
5568 Xemerald, TRUE, FALSE,
5572 Xemerald_pause, FALSE, FALSE,
5576 Xemerald_fall, FALSE, FALSE,
5580 Xemerald_shine, FALSE, FALSE,
5581 EL_EMERALD, ACTION_TWINKLING, -1
5584 Yemerald_s, FALSE, FALSE,
5585 EL_EMERALD, ACTION_FALLING, -1
5588 Yemerald_sB, FALSE, TRUE,
5589 EL_EMERALD, ACTION_FALLING, -1
5592 Yemerald_e, FALSE, FALSE,
5593 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
5596 Yemerald_eB, FALSE, TRUE,
5597 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
5600 Yemerald_w, FALSE, FALSE,
5601 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
5604 Yemerald_wB, FALSE, TRUE,
5605 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
5608 Yemerald_eat, FALSE, FALSE,
5609 EL_EMERALD, ACTION_COLLECTING, -1
5612 Yemerald_stone, FALSE, FALSE,
5613 EL_NUT, ACTION_BREAKING, -1
5616 Xdiamond, TRUE, FALSE,
5620 Xdiamond_pause, FALSE, FALSE,
5624 Xdiamond_fall, FALSE, FALSE,
5628 Xdiamond_shine, FALSE, FALSE,
5629 EL_DIAMOND, ACTION_TWINKLING, -1
5632 Ydiamond_s, FALSE, FALSE,
5633 EL_DIAMOND, ACTION_FALLING, -1
5636 Ydiamond_sB, FALSE, TRUE,
5637 EL_DIAMOND, ACTION_FALLING, -1
5640 Ydiamond_e, FALSE, FALSE,
5641 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
5644 Ydiamond_eB, FALSE, TRUE,
5645 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
5648 Ydiamond_w, FALSE, FALSE,
5649 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
5652 Ydiamond_wB, FALSE, TRUE,
5653 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
5656 Ydiamond_eat, FALSE, FALSE,
5657 EL_DIAMOND, ACTION_COLLECTING, -1
5660 Ydiamond_stone, FALSE, FALSE,
5661 EL_DIAMOND, ACTION_SMASHED_BY_ROCK, -1
5664 Xdrip_fall, TRUE, FALSE,
5665 EL_AMOEBA_DROP, -1, -1
5668 Xdrip_stretch, FALSE, FALSE,
5669 EL_AMOEBA_DROP, ACTION_FALLING, -1
5672 Xdrip_stretchB, FALSE, TRUE,
5673 EL_AMOEBA_DROP, ACTION_FALLING, -1
5676 Xdrip_eat, FALSE, FALSE,
5677 EL_AMOEBA_DROP, ACTION_GROWING, -1
5680 Ydrip_s1, FALSE, FALSE,
5681 EL_AMOEBA_DROP, ACTION_FALLING, -1
5684 Ydrip_s1B, FALSE, TRUE,
5685 EL_AMOEBA_DROP, ACTION_FALLING, -1
5688 Ydrip_s2, FALSE, FALSE,
5689 EL_AMOEBA_DROP, ACTION_FALLING, -1
5692 Ydrip_s2B, FALSE, TRUE,
5693 EL_AMOEBA_DROP, ACTION_FALLING, -1
5700 Xbomb_pause, FALSE, FALSE,
5704 Xbomb_fall, FALSE, FALSE,
5708 Ybomb_s, FALSE, FALSE,
5709 EL_BOMB, ACTION_FALLING, -1
5712 Ybomb_sB, FALSE, TRUE,
5713 EL_BOMB, ACTION_FALLING, -1
5716 Ybomb_e, FALSE, FALSE,
5717 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
5720 Ybomb_eB, FALSE, TRUE,
5721 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
5724 Ybomb_w, FALSE, FALSE,
5725 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
5728 Ybomb_wB, FALSE, TRUE,
5729 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
5732 Ybomb_eat, FALSE, FALSE,
5733 EL_BOMB, ACTION_ACTIVATING, -1
5736 Xballoon, TRUE, FALSE,
5740 Yballoon_n, FALSE, FALSE,
5741 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
5744 Yballoon_nB, FALSE, TRUE,
5745 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
5748 Yballoon_e, FALSE, FALSE,
5749 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
5752 Yballoon_eB, FALSE, TRUE,
5753 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
5756 Yballoon_s, FALSE, FALSE,
5757 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
5760 Yballoon_sB, FALSE, TRUE,
5761 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
5764 Yballoon_w, FALSE, FALSE,
5765 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
5768 Yballoon_wB, FALSE, TRUE,
5769 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
5772 Xgrass, TRUE, FALSE,
5773 EL_EMC_GRASS, -1, -1
5776 Ygrass_nB, FALSE, FALSE,
5777 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_UP
5780 Ygrass_eB, FALSE, FALSE,
5781 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_RIGHT
5784 Ygrass_sB, FALSE, FALSE,
5785 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_DOWN
5788 Ygrass_wB, FALSE, FALSE,
5789 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_LEFT
5796 Ydirt_nB, FALSE, FALSE,
5797 EL_SAND, ACTION_DIGGING, MV_BIT_UP
5800 Ydirt_eB, FALSE, FALSE,
5801 EL_SAND, ACTION_DIGGING, MV_BIT_RIGHT
5804 Ydirt_sB, FALSE, FALSE,
5805 EL_SAND, ACTION_DIGGING, MV_BIT_DOWN
5808 Ydirt_wB, FALSE, FALSE,
5809 EL_SAND, ACTION_DIGGING, MV_BIT_LEFT
5812 Xacid_ne, TRUE, FALSE,
5813 EL_ACID_POOL_TOPRIGHT, -1, -1
5816 Xacid_se, TRUE, FALSE,
5817 EL_ACID_POOL_BOTTOMRIGHT, -1, -1
5820 Xacid_s, TRUE, FALSE,
5821 EL_ACID_POOL_BOTTOM, -1, -1
5824 Xacid_sw, TRUE, FALSE,
5825 EL_ACID_POOL_BOTTOMLEFT, -1, -1
5828 Xacid_nw, TRUE, FALSE,
5829 EL_ACID_POOL_TOPLEFT, -1, -1
5832 Xacid_1, TRUE, FALSE,
5836 Xacid_2, FALSE, FALSE,
5840 Xacid_3, FALSE, FALSE,
5844 Xacid_4, FALSE, FALSE,
5848 Xacid_5, FALSE, FALSE,
5852 Xacid_6, FALSE, FALSE,
5856 Xacid_7, FALSE, FALSE,
5860 Xacid_8, FALSE, FALSE,
5864 Xball_1, TRUE, FALSE,
5865 EL_EMC_MAGIC_BALL, -1, -1
5868 Xball_1B, FALSE, FALSE,
5869 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
5872 Xball_2, FALSE, FALSE,
5873 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
5876 Xball_2B, FALSE, FALSE,
5877 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
5880 Yball_eat, FALSE, FALSE,
5881 EL_EMC_MAGIC_BALL, ACTION_DROPPING, -1
5884 Ykey_1_eat, FALSE, FALSE,
5885 EL_EM_KEY_1, ACTION_COLLECTING, -1
5888 Ykey_2_eat, FALSE, FALSE,
5889 EL_EM_KEY_2, ACTION_COLLECTING, -1
5892 Ykey_3_eat, FALSE, FALSE,
5893 EL_EM_KEY_3, ACTION_COLLECTING, -1
5896 Ykey_4_eat, FALSE, FALSE,
5897 EL_EM_KEY_4, ACTION_COLLECTING, -1
5900 Ykey_5_eat, FALSE, FALSE,
5901 EL_EMC_KEY_5, ACTION_COLLECTING, -1
5904 Ykey_6_eat, FALSE, FALSE,
5905 EL_EMC_KEY_6, ACTION_COLLECTING, -1
5908 Ykey_7_eat, FALSE, FALSE,
5909 EL_EMC_KEY_7, ACTION_COLLECTING, -1
5912 Ykey_8_eat, FALSE, FALSE,
5913 EL_EMC_KEY_8, ACTION_COLLECTING, -1
5916 Ylenses_eat, FALSE, FALSE,
5917 EL_EMC_LENSES, ACTION_COLLECTING, -1
5920 Ymagnify_eat, FALSE, FALSE,
5921 EL_EMC_MAGNIFIER, ACTION_COLLECTING, -1
5924 Ygrass_eat, FALSE, FALSE,
5925 EL_EMC_GRASS, ACTION_SNAPPING, -1
5928 Ydirt_eat, FALSE, FALSE,
5929 EL_SAND, ACTION_SNAPPING, -1
5932 Xgrow_ns, TRUE, FALSE,
5933 EL_EXPANDABLE_WALL_VERTICAL, -1, -1
5936 Ygrow_ns_eat, FALSE, FALSE,
5937 EL_EXPANDABLE_WALL_VERTICAL, ACTION_GROWING, -1
5940 Xgrow_ew, TRUE, FALSE,
5941 EL_EXPANDABLE_WALL_HORIZONTAL, -1, -1
5944 Ygrow_ew_eat, FALSE, FALSE,
5945 EL_EXPANDABLE_WALL_HORIZONTAL, ACTION_GROWING, -1
5948 Xwonderwall, TRUE, FALSE,
5949 EL_MAGIC_WALL, -1, -1
5952 XwonderwallB, FALSE, FALSE,
5953 EL_MAGIC_WALL, ACTION_ACTIVE, -1
5956 Xamoeba_1, TRUE, FALSE,
5957 EL_AMOEBA_DRY, ACTION_OTHER, -1
5960 Xamoeba_2, FALSE, FALSE,
5961 EL_AMOEBA_DRY, ACTION_OTHER, -1
5964 Xamoeba_3, FALSE, FALSE,
5965 EL_AMOEBA_DRY, ACTION_OTHER, -1
5968 Xamoeba_4, FALSE, FALSE,
5969 EL_AMOEBA_DRY, ACTION_OTHER, -1
5972 Xamoeba_5, TRUE, FALSE,
5973 EL_AMOEBA_WET, ACTION_OTHER, -1
5976 Xamoeba_6, FALSE, FALSE,
5977 EL_AMOEBA_WET, ACTION_OTHER, -1
5980 Xamoeba_7, FALSE, FALSE,
5981 EL_AMOEBA_WET, ACTION_OTHER, -1
5984 Xamoeba_8, FALSE, FALSE,
5985 EL_AMOEBA_WET, ACTION_OTHER, -1
5988 Xdoor_1, TRUE, FALSE,
5989 EL_EM_GATE_1, -1, -1
5992 Xdoor_2, TRUE, FALSE,
5993 EL_EM_GATE_2, -1, -1
5996 Xdoor_3, TRUE, FALSE,
5997 EL_EM_GATE_3, -1, -1
6000 Xdoor_4, TRUE, FALSE,
6001 EL_EM_GATE_4, -1, -1
6004 Xdoor_5, TRUE, FALSE,
6005 EL_EMC_GATE_5, -1, -1
6008 Xdoor_6, TRUE, FALSE,
6009 EL_EMC_GATE_6, -1, -1
6012 Xdoor_7, TRUE, FALSE,
6013 EL_EMC_GATE_7, -1, -1
6016 Xdoor_8, TRUE, FALSE,
6017 EL_EMC_GATE_8, -1, -1
6020 Xkey_1, TRUE, FALSE,
6024 Xkey_2, TRUE, FALSE,
6028 Xkey_3, TRUE, FALSE,
6032 Xkey_4, TRUE, FALSE,
6036 Xkey_5, TRUE, FALSE,
6037 EL_EMC_KEY_5, -1, -1
6040 Xkey_6, TRUE, FALSE,
6041 EL_EMC_KEY_6, -1, -1
6044 Xkey_7, TRUE, FALSE,
6045 EL_EMC_KEY_7, -1, -1
6048 Xkey_8, TRUE, FALSE,
6049 EL_EMC_KEY_8, -1, -1
6052 Xwind_n, TRUE, FALSE,
6053 EL_BALLOON_SWITCH_UP, -1, -1
6056 Xwind_e, TRUE, FALSE,
6057 EL_BALLOON_SWITCH_RIGHT, -1, -1
6060 Xwind_s, TRUE, FALSE,
6061 EL_BALLOON_SWITCH_DOWN, -1, -1
6064 Xwind_w, TRUE, FALSE,
6065 EL_BALLOON_SWITCH_LEFT, -1, -1
6068 Xwind_nesw, TRUE, FALSE,
6069 EL_BALLOON_SWITCH_ANY, -1, -1
6072 Xwind_stop, TRUE, FALSE,
6073 EL_BALLOON_SWITCH_NONE, -1, -1
6077 EL_EM_EXIT_CLOSED, -1, -1
6080 Xexit_1, TRUE, FALSE,
6081 EL_EM_EXIT_OPEN, -1, -1
6084 Xexit_2, FALSE, FALSE,
6085 EL_EM_EXIT_OPEN, -1, -1
6088 Xexit_3, FALSE, FALSE,
6089 EL_EM_EXIT_OPEN, -1, -1
6092 Xdynamite, TRUE, FALSE,
6093 EL_EM_DYNAMITE, -1, -1
6096 Ydynamite_eat, FALSE, FALSE,
6097 EL_EM_DYNAMITE, ACTION_COLLECTING, -1
6100 Xdynamite_1, TRUE, FALSE,
6101 EL_EM_DYNAMITE_ACTIVE, -1, -1
6104 Xdynamite_2, FALSE, FALSE,
6105 EL_EM_DYNAMITE_ACTIVE, -1, -1
6108 Xdynamite_3, FALSE, FALSE,
6109 EL_EM_DYNAMITE_ACTIVE, -1, -1
6112 Xdynamite_4, FALSE, FALSE,
6113 EL_EM_DYNAMITE_ACTIVE, -1, -1
6116 Xbumper, TRUE, FALSE,
6117 EL_EMC_SPRING_BUMPER, -1, -1
6120 XbumperB, FALSE, FALSE,
6121 EL_EMC_SPRING_BUMPER, ACTION_ACTIVE, -1
6124 Xwheel, TRUE, FALSE,
6125 EL_ROBOT_WHEEL, -1, -1
6128 XwheelB, FALSE, FALSE,
6129 EL_ROBOT_WHEEL, ACTION_ACTIVE, -1
6132 Xswitch, TRUE, FALSE,
6133 EL_EMC_MAGIC_BALL_SWITCH, -1, -1
6136 XswitchB, FALSE, FALSE,
6137 EL_EMC_MAGIC_BALL_SWITCH, ACTION_ACTIVE, -1
6141 EL_QUICKSAND_EMPTY, -1, -1
6144 Xsand_stone, TRUE, FALSE,
6145 EL_QUICKSAND_FULL, -1, -1
6148 Xsand_stonein_1, FALSE, TRUE,
6149 EL_ROCK, ACTION_FILLING, -1
6152 Xsand_stonein_2, FALSE, TRUE,
6153 EL_ROCK, ACTION_FILLING, -1
6156 Xsand_stonein_3, FALSE, TRUE,
6157 EL_ROCK, ACTION_FILLING, -1
6160 Xsand_stonein_4, FALSE, TRUE,
6161 EL_ROCK, ACTION_FILLING, -1
6165 Xsand_stonesand_1, FALSE, FALSE,
6166 EL_QUICKSAND_EMPTYING, -1, -1
6169 Xsand_stonesand_2, FALSE, FALSE,
6170 EL_QUICKSAND_EMPTYING, -1, -1
6173 Xsand_stonesand_3, FALSE, FALSE,
6174 EL_QUICKSAND_EMPTYING, -1, -1
6177 Xsand_stonesand_4, FALSE, FALSE,
6178 EL_QUICKSAND_EMPTYING, -1, -1
6181 Xsand_stonesand_quickout_1, FALSE, FALSE,
6182 EL_QUICKSAND_EMPTYING, -1, -1
6185 Xsand_stonesand_quickout_2, FALSE, FALSE,
6186 EL_QUICKSAND_EMPTYING, -1, -1
6190 Xsand_stonesand_1, FALSE, FALSE,
6191 EL_QUICKSAND_FULL, -1, -1
6194 Xsand_stonesand_2, FALSE, FALSE,
6195 EL_QUICKSAND_FULL, -1, -1
6198 Xsand_stonesand_3, FALSE, FALSE,
6199 EL_QUICKSAND_FULL, -1, -1
6202 Xsand_stonesand_4, FALSE, FALSE,
6203 EL_QUICKSAND_FULL, -1, -1
6207 Xsand_stoneout_1, FALSE, FALSE,
6208 EL_ROCK, ACTION_EMPTYING, -1
6211 Xsand_stoneout_2, FALSE, FALSE,
6212 EL_ROCK, ACTION_EMPTYING, -1
6216 Xsand_sandstone_1, FALSE, FALSE,
6217 EL_QUICKSAND_FILLING, -1, -1
6220 Xsand_sandstone_2, FALSE, FALSE,
6221 EL_QUICKSAND_FILLING, -1, -1
6224 Xsand_sandstone_3, FALSE, FALSE,
6225 EL_QUICKSAND_FILLING, -1, -1
6228 Xsand_sandstone_4, FALSE, FALSE,
6229 EL_QUICKSAND_FILLING, -1, -1
6233 Xsand_sandstone_1, FALSE, FALSE,
6234 EL_QUICKSAND_FULL, -1, -1
6237 Xsand_sandstone_2, FALSE, FALSE,
6238 EL_QUICKSAND_FULL, -1, -1
6241 Xsand_sandstone_3, FALSE, FALSE,
6242 EL_QUICKSAND_FULL, -1, -1
6245 Xsand_sandstone_4, FALSE, FALSE,
6246 EL_QUICKSAND_FULL, -1, -1
6250 Xplant, TRUE, FALSE,
6251 EL_EMC_PLANT, -1, -1
6254 Yplant, FALSE, FALSE,
6255 EL_EMC_PLANT, -1, -1
6258 Xlenses, TRUE, FALSE,
6259 EL_EMC_LENSES, -1, -1
6262 Xmagnify, TRUE, FALSE,
6263 EL_EMC_MAGNIFIER, -1, -1
6266 Xdripper, TRUE, FALSE,
6267 EL_EMC_DRIPPER, -1, -1
6270 XdripperB, FALSE, FALSE,
6271 EL_EMC_DRIPPER, ACTION_ACTIVE, -1
6274 Xfake_blank, TRUE, FALSE,
6275 EL_INVISIBLE_WALL, -1, -1
6278 Xfake_blankB, FALSE, FALSE,
6279 EL_INVISIBLE_WALL, ACTION_ACTIVE, -1
6282 Xfake_grass, TRUE, FALSE,
6283 EL_EMC_FAKE_GRASS, -1, -1
6286 Xfake_grassB, FALSE, FALSE,
6287 EL_EMC_FAKE_GRASS, ACTION_ACTIVE, -1
6290 Xfake_door_1, TRUE, FALSE,
6291 EL_EM_GATE_1_GRAY, -1, -1
6294 Xfake_door_2, TRUE, FALSE,
6295 EL_EM_GATE_2_GRAY, -1, -1
6298 Xfake_door_3, TRUE, FALSE,
6299 EL_EM_GATE_3_GRAY, -1, -1
6302 Xfake_door_4, TRUE, FALSE,
6303 EL_EM_GATE_4_GRAY, -1, -1
6306 Xfake_door_5, TRUE, FALSE,
6307 EL_EMC_GATE_5_GRAY, -1, -1
6310 Xfake_door_6, TRUE, FALSE,
6311 EL_EMC_GATE_6_GRAY, -1, -1
6314 Xfake_door_7, TRUE, FALSE,
6315 EL_EMC_GATE_7_GRAY, -1, -1
6318 Xfake_door_8, TRUE, FALSE,
6319 EL_EMC_GATE_8_GRAY, -1, -1
6322 Xfake_acid_1, TRUE, FALSE,
6323 EL_EMC_FAKE_ACID, -1, -1
6326 Xfake_acid_2, FALSE, FALSE,
6327 EL_EMC_FAKE_ACID, -1, -1
6330 Xfake_acid_3, FALSE, FALSE,
6331 EL_EMC_FAKE_ACID, -1, -1
6334 Xfake_acid_4, FALSE, FALSE,
6335 EL_EMC_FAKE_ACID, -1, -1
6338 Xfake_acid_5, FALSE, FALSE,
6339 EL_EMC_FAKE_ACID, -1, -1
6342 Xfake_acid_6, FALSE, FALSE,
6343 EL_EMC_FAKE_ACID, -1, -1
6346 Xfake_acid_7, FALSE, FALSE,
6347 EL_EMC_FAKE_ACID, -1, -1
6350 Xfake_acid_8, FALSE, FALSE,
6351 EL_EMC_FAKE_ACID, -1, -1
6354 Xsteel_1, TRUE, FALSE,
6355 EL_STEELWALL, -1, -1
6358 Xsteel_2, TRUE, FALSE,
6359 EL_EMC_STEELWALL_2, -1, -1
6362 Xsteel_3, TRUE, FALSE,
6363 EL_EMC_STEELWALL_3, -1, -1
6366 Xsteel_4, TRUE, FALSE,
6367 EL_EMC_STEELWALL_4, -1, -1
6370 Xwall_1, TRUE, FALSE,
6374 Xwall_2, TRUE, FALSE,
6375 EL_EMC_WALL_14, -1, -1
6378 Xwall_3, TRUE, FALSE,
6379 EL_EMC_WALL_15, -1, -1
6382 Xwall_4, TRUE, FALSE,
6383 EL_EMC_WALL_16, -1, -1
6386 Xround_wall_1, TRUE, FALSE,
6387 EL_WALL_SLIPPERY, -1, -1
6390 Xround_wall_2, TRUE, FALSE,
6391 EL_EMC_WALL_SLIPPERY_2, -1, -1
6394 Xround_wall_3, TRUE, FALSE,
6395 EL_EMC_WALL_SLIPPERY_3, -1, -1
6398 Xround_wall_4, TRUE, FALSE,
6399 EL_EMC_WALL_SLIPPERY_4, -1, -1
6402 Xdecor_1, TRUE, FALSE,
6403 EL_EMC_WALL_8, -1, -1
6406 Xdecor_2, TRUE, FALSE,
6407 EL_EMC_WALL_6, -1, -1
6410 Xdecor_3, TRUE, FALSE,
6411 EL_EMC_WALL_4, -1, -1
6414 Xdecor_4, TRUE, FALSE,
6415 EL_EMC_WALL_7, -1, -1
6418 Xdecor_5, TRUE, FALSE,
6419 EL_EMC_WALL_5, -1, -1
6422 Xdecor_6, TRUE, FALSE,
6423 EL_EMC_WALL_9, -1, -1
6426 Xdecor_7, TRUE, FALSE,
6427 EL_EMC_WALL_10, -1, -1
6430 Xdecor_8, TRUE, FALSE,
6431 EL_EMC_WALL_1, -1, -1
6434 Xdecor_9, TRUE, FALSE,
6435 EL_EMC_WALL_2, -1, -1
6438 Xdecor_10, TRUE, FALSE,
6439 EL_EMC_WALL_3, -1, -1
6442 Xdecor_11, TRUE, FALSE,
6443 EL_EMC_WALL_11, -1, -1
6446 Xdecor_12, TRUE, FALSE,
6447 EL_EMC_WALL_12, -1, -1
6450 Xalpha_0, TRUE, FALSE,
6451 EL_CHAR('0'), -1, -1
6454 Xalpha_1, TRUE, FALSE,
6455 EL_CHAR('1'), -1, -1
6458 Xalpha_2, TRUE, FALSE,
6459 EL_CHAR('2'), -1, -1
6462 Xalpha_3, TRUE, FALSE,
6463 EL_CHAR('3'), -1, -1
6466 Xalpha_4, TRUE, FALSE,
6467 EL_CHAR('4'), -1, -1
6470 Xalpha_5, TRUE, FALSE,
6471 EL_CHAR('5'), -1, -1
6474 Xalpha_6, TRUE, FALSE,
6475 EL_CHAR('6'), -1, -1
6478 Xalpha_7, TRUE, FALSE,
6479 EL_CHAR('7'), -1, -1
6482 Xalpha_8, TRUE, FALSE,
6483 EL_CHAR('8'), -1, -1
6486 Xalpha_9, TRUE, FALSE,
6487 EL_CHAR('9'), -1, -1
6490 Xalpha_excla, TRUE, FALSE,
6491 EL_CHAR('!'), -1, -1
6494 Xalpha_quote, TRUE, FALSE,
6495 EL_CHAR('"'), -1, -1
6498 Xalpha_comma, TRUE, FALSE,
6499 EL_CHAR(','), -1, -1
6502 Xalpha_minus, TRUE, FALSE,
6503 EL_CHAR('-'), -1, -1
6506 Xalpha_perio, TRUE, FALSE,
6507 EL_CHAR('.'), -1, -1
6510 Xalpha_colon, TRUE, FALSE,
6511 EL_CHAR(':'), -1, -1
6514 Xalpha_quest, TRUE, FALSE,
6515 EL_CHAR('?'), -1, -1
6518 Xalpha_a, TRUE, FALSE,
6519 EL_CHAR('A'), -1, -1
6522 Xalpha_b, TRUE, FALSE,
6523 EL_CHAR('B'), -1, -1
6526 Xalpha_c, TRUE, FALSE,
6527 EL_CHAR('C'), -1, -1
6530 Xalpha_d, TRUE, FALSE,
6531 EL_CHAR('D'), -1, -1
6534 Xalpha_e, TRUE, FALSE,
6535 EL_CHAR('E'), -1, -1
6538 Xalpha_f, TRUE, FALSE,
6539 EL_CHAR('F'), -1, -1
6542 Xalpha_g, TRUE, FALSE,
6543 EL_CHAR('G'), -1, -1
6546 Xalpha_h, TRUE, FALSE,
6547 EL_CHAR('H'), -1, -1
6550 Xalpha_i, TRUE, FALSE,
6551 EL_CHAR('I'), -1, -1
6554 Xalpha_j, TRUE, FALSE,
6555 EL_CHAR('J'), -1, -1
6558 Xalpha_k, TRUE, FALSE,
6559 EL_CHAR('K'), -1, -1
6562 Xalpha_l, TRUE, FALSE,
6563 EL_CHAR('L'), -1, -1
6566 Xalpha_m, TRUE, FALSE,
6567 EL_CHAR('M'), -1, -1
6570 Xalpha_n, TRUE, FALSE,
6571 EL_CHAR('N'), -1, -1
6574 Xalpha_o, TRUE, FALSE,
6575 EL_CHAR('O'), -1, -1
6578 Xalpha_p, TRUE, FALSE,
6579 EL_CHAR('P'), -1, -1
6582 Xalpha_q, TRUE, FALSE,
6583 EL_CHAR('Q'), -1, -1
6586 Xalpha_r, TRUE, FALSE,
6587 EL_CHAR('R'), -1, -1
6590 Xalpha_s, TRUE, FALSE,
6591 EL_CHAR('S'), -1, -1
6594 Xalpha_t, TRUE, FALSE,
6595 EL_CHAR('T'), -1, -1
6598 Xalpha_u, TRUE, FALSE,
6599 EL_CHAR('U'), -1, -1
6602 Xalpha_v, TRUE, FALSE,
6603 EL_CHAR('V'), -1, -1
6606 Xalpha_w, TRUE, FALSE,
6607 EL_CHAR('W'), -1, -1
6610 Xalpha_x, TRUE, FALSE,
6611 EL_CHAR('X'), -1, -1
6614 Xalpha_y, TRUE, FALSE,
6615 EL_CHAR('Y'), -1, -1
6618 Xalpha_z, TRUE, FALSE,
6619 EL_CHAR('Z'), -1, -1
6622 Xalpha_arrow_e, TRUE, FALSE,
6623 EL_CHAR('>'), -1, -1
6626 Xalpha_arrow_w, TRUE, FALSE,
6627 EL_CHAR('<'), -1, -1
6630 Xalpha_copyr, TRUE, FALSE,
6631 EL_CHAR('©'), -1, -1
6635 Xboom_bug, FALSE, FALSE,
6636 EL_BUG, ACTION_EXPLODING, -1
6639 Xboom_bomb, FALSE, FALSE,
6640 EL_BOMB, ACTION_EXPLODING, -1
6643 Xboom_android, FALSE, FALSE,
6644 EL_EMC_ANDROID, ACTION_OTHER, -1
6647 Xboom_1, FALSE, FALSE,
6648 EL_DEFAULT, ACTION_EXPLODING, -1
6651 Xboom_2, FALSE, FALSE,
6652 EL_DEFAULT, ACTION_EXPLODING, -1
6655 Znormal, FALSE, FALSE,
6659 Zdynamite, FALSE, FALSE,
6663 Zplayer, FALSE, FALSE,
6667 ZBORDER, FALSE, FALSE,
6677 static struct Mapping_EM_to_RND_player
6686 em_player_mapping_list[] =
6690 EL_PLAYER_1, ACTION_MOVING, MV_BIT_UP,
6694 EL_PLAYER_1, ACTION_MOVING, MV_BIT_RIGHT,
6698 EL_PLAYER_1, ACTION_MOVING, MV_BIT_DOWN,
6702 EL_PLAYER_1, ACTION_MOVING, MV_BIT_LEFT,
6706 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_UP,
6710 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_RIGHT,
6714 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_DOWN,
6718 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_LEFT,
6722 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_UP,
6726 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_RIGHT,
6730 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_DOWN,
6734 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_LEFT,
6738 EL_PLAYER_2, ACTION_MOVING, MV_BIT_UP,
6742 EL_PLAYER_2, ACTION_MOVING, MV_BIT_RIGHT,
6746 EL_PLAYER_2, ACTION_MOVING, MV_BIT_DOWN,
6750 EL_PLAYER_2, ACTION_MOVING, MV_BIT_LEFT,
6754 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_UP,
6758 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_RIGHT,
6762 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_DOWN,
6766 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_LEFT,
6770 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_UP,
6774 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_RIGHT,
6778 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_DOWN,
6782 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_LEFT,
6786 EL_PLAYER_1, ACTION_DEFAULT, -1,
6790 EL_PLAYER_2, ACTION_DEFAULT, -1,
6794 EL_PLAYER_3, ACTION_MOVING, MV_BIT_UP,
6798 EL_PLAYER_3, ACTION_MOVING, MV_BIT_RIGHT,
6802 EL_PLAYER_3, ACTION_MOVING, MV_BIT_DOWN,
6806 EL_PLAYER_3, ACTION_MOVING, MV_BIT_LEFT,
6810 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_UP,
6814 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_RIGHT,
6818 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_DOWN,
6822 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_LEFT,
6826 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_UP,
6830 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_RIGHT,
6834 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_DOWN,
6838 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_LEFT,
6842 EL_PLAYER_4, ACTION_MOVING, MV_BIT_UP,
6846 EL_PLAYER_4, ACTION_MOVING, MV_BIT_RIGHT,
6850 EL_PLAYER_4, ACTION_MOVING, MV_BIT_DOWN,
6854 EL_PLAYER_4, ACTION_MOVING, MV_BIT_LEFT,
6858 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_UP,
6862 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_RIGHT,
6866 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_DOWN,
6870 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_LEFT,
6874 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_UP,
6878 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_RIGHT,
6882 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_DOWN,
6886 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_LEFT,
6890 EL_PLAYER_3, ACTION_DEFAULT, -1,
6894 EL_PLAYER_4, ACTION_DEFAULT, -1,
6903 int map_element_RND_to_EM(int element_rnd)
6905 static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
6906 static boolean mapping_initialized = FALSE;
6908 if (!mapping_initialized)
6912 /* return "Xalpha_quest" for all undefined elements in mapping array */
6913 for (i = 0; i < NUM_FILE_ELEMENTS; i++)
6914 mapping_RND_to_EM[i] = Xalpha_quest;
6916 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
6917 if (em_object_mapping_list[i].is_rnd_to_em_mapping)
6918 mapping_RND_to_EM[em_object_mapping_list[i].element_rnd] =
6919 em_object_mapping_list[i].element_em;
6921 mapping_initialized = TRUE;
6924 if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
6925 return mapping_RND_to_EM[element_rnd];
6927 Error(ERR_WARN, "invalid RND level element %d", element_rnd);
6932 int map_element_EM_to_RND(int element_em)
6934 static unsigned short mapping_EM_to_RND[TILE_MAX];
6935 static boolean mapping_initialized = FALSE;
6937 if (!mapping_initialized)
6941 /* return "EL_UNKNOWN" for all undefined elements in mapping array */
6942 for (i = 0; i < TILE_MAX; i++)
6943 mapping_EM_to_RND[i] = EL_UNKNOWN;
6945 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
6946 mapping_EM_to_RND[em_object_mapping_list[i].element_em] =
6947 em_object_mapping_list[i].element_rnd;
6949 mapping_initialized = TRUE;
6952 if (element_em >= 0 && element_em < TILE_MAX)
6953 return mapping_EM_to_RND[element_em];
6955 Error(ERR_WARN, "invalid EM level element %d", element_em);
6960 void map_android_clone_elements_RND_to_EM(struct LevelInfo *level)
6962 struct LevelInfo_EM *level_em = level->native_em_level;
6963 struct LEVEL *lev = level_em->lev;
6966 for (i = 0; i < TILE_MAX; i++)
6967 lev->android_array[i] = Xblank;
6969 for (i = 0; i < level->num_android_clone_elements; i++)
6971 int element_rnd = level->android_clone_element[i];
6972 int element_em = map_element_RND_to_EM(element_rnd);
6974 for (j = 0; em_object_mapping_list[j].element_em != -1; j++)
6975 if (em_object_mapping_list[j].element_rnd == element_rnd)
6976 lev->android_array[em_object_mapping_list[j].element_em] = element_em;
6980 void map_android_clone_elements_EM_to_RND(struct LevelInfo *level)
6982 struct LevelInfo_EM *level_em = level->native_em_level;
6983 struct LEVEL *lev = level_em->lev;
6986 level->num_android_clone_elements = 0;
6988 for (i = 0; i < TILE_MAX; i++)
6990 int element_em = lev->android_array[i];
6992 boolean element_found = FALSE;
6994 if (element_em == Xblank)
6997 element_rnd = map_element_EM_to_RND(element_em);
6999 for (j = 0; j < level->num_android_clone_elements; j++)
7000 if (level->android_clone_element[j] == element_rnd)
7001 element_found = TRUE;
7005 level->android_clone_element[level->num_android_clone_elements++] =
7008 if (level->num_android_clone_elements == MAX_ANDROID_ELEMENTS)
7013 if (level->num_android_clone_elements == 0)
7015 level->num_android_clone_elements = 1;
7016 level->android_clone_element[0] = EL_EMPTY;
7020 int map_direction_RND_to_EM(int direction)
7022 return (direction == MV_UP ? 0 :
7023 direction == MV_RIGHT ? 1 :
7024 direction == MV_DOWN ? 2 :
7025 direction == MV_LEFT ? 3 :
7029 int map_direction_EM_to_RND(int direction)
7031 return (direction == 0 ? MV_UP :
7032 direction == 1 ? MV_RIGHT :
7033 direction == 2 ? MV_DOWN :
7034 direction == 3 ? MV_LEFT :
7038 int map_element_RND_to_SP(int element_rnd)
7040 int element_sp = 0x20; /* map unknown elements to yellow "hardware" */
7042 if (element_rnd >= EL_SP_START &&
7043 element_rnd <= EL_SP_END)
7044 element_sp = element_rnd - EL_SP_START;
7045 else if (element_rnd == EL_EMPTY_SPACE)
7047 else if (element_rnd == EL_INVISIBLE_WALL)
7053 int map_element_SP_to_RND(int element_sp)
7055 int element_rnd = EL_UNKNOWN;
7057 if (element_sp >= 0x00 &&
7059 element_rnd = EL_SP_START + element_sp;
7060 else if (element_sp == 0x28)
7061 element_rnd = EL_INVISIBLE_WALL;
7066 int map_action_SP_to_RND(int action_sp)
7070 case actActive: return ACTION_ACTIVE;
7071 case actImpact: return ACTION_IMPACT;
7072 case actExploding: return ACTION_EXPLODING;
7073 case actDigging: return ACTION_DIGGING;
7074 case actSnapping: return ACTION_SNAPPING;
7075 case actCollecting: return ACTION_COLLECTING;
7076 case actPassing: return ACTION_PASSING;
7077 case actPushing: return ACTION_PUSHING;
7078 case actDropping: return ACTION_DROPPING;
7080 default: return ACTION_DEFAULT;
7084 int get_next_element(int element)
7088 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
7089 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
7090 case EL_QUICKSAND_FAST_FILLING: return EL_QUICKSAND_FAST_FULL;
7091 case EL_QUICKSAND_FAST_EMPTYING: return EL_QUICKSAND_FAST_EMPTY;
7092 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
7093 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
7094 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
7095 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
7096 case EL_DC_MAGIC_WALL_FILLING: return EL_DC_MAGIC_WALL_FULL;
7097 case EL_DC_MAGIC_WALL_EMPTYING: return EL_DC_MAGIC_WALL_ACTIVE;
7098 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
7100 default: return element;
7105 int el_act_dir2img(int element, int action, int direction)
7107 element = GFX_ELEMENT(element);
7109 if (direction == MV_NONE)
7110 return element_info[element].graphic[action];
7112 direction = MV_DIR_TO_BIT(direction);
7114 return element_info[element].direction_graphic[action][direction];
7117 int el_act_dir2img(int element, int action, int direction)
7119 element = GFX_ELEMENT(element);
7120 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
7122 /* direction_graphic[][] == graphic[] for undefined direction graphics */
7123 return element_info[element].direction_graphic[action][direction];
7128 static int el_act_dir2crm(int element, int action, int direction)
7130 element = GFX_ELEMENT(element);
7132 if (direction == MV_NONE)
7133 return element_info[element].crumbled[action];
7135 direction = MV_DIR_TO_BIT(direction);
7137 return element_info[element].direction_crumbled[action][direction];
7140 static int el_act_dir2crm(int element, int action, int direction)
7142 element = GFX_ELEMENT(element);
7143 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
7145 /* direction_graphic[][] == graphic[] for undefined direction graphics */
7146 return element_info[element].direction_crumbled[action][direction];
7150 int el_act2img(int element, int action)
7152 element = GFX_ELEMENT(element);
7154 return element_info[element].graphic[action];
7157 int el_act2crm(int element, int action)
7159 element = GFX_ELEMENT(element);
7161 return element_info[element].crumbled[action];
7164 int el_dir2img(int element, int direction)
7166 element = GFX_ELEMENT(element);
7168 return el_act_dir2img(element, ACTION_DEFAULT, direction);
7171 int el2baseimg(int element)
7173 return element_info[element].graphic[ACTION_DEFAULT];
7176 int el2img(int element)
7178 element = GFX_ELEMENT(element);
7180 return element_info[element].graphic[ACTION_DEFAULT];
7183 int el2edimg(int element)
7185 element = GFX_ELEMENT(element);
7187 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
7190 int el2preimg(int element)
7192 element = GFX_ELEMENT(element);
7194 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
7197 int el2panelimg(int element)
7199 element = GFX_ELEMENT(element);
7201 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PANEL];
7204 int font2baseimg(int font_nr)
7206 return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
7209 int getBeltNrFromBeltElement(int element)
7211 return (element < EL_CONVEYOR_BELT_2_LEFT ? 0 :
7212 element < EL_CONVEYOR_BELT_3_LEFT ? 1 :
7213 element < EL_CONVEYOR_BELT_4_LEFT ? 2 : 3);
7216 int getBeltNrFromBeltActiveElement(int element)
7218 return (element < EL_CONVEYOR_BELT_2_LEFT_ACTIVE ? 0 :
7219 element < EL_CONVEYOR_BELT_3_LEFT_ACTIVE ? 1 :
7220 element < EL_CONVEYOR_BELT_4_LEFT_ACTIVE ? 2 : 3);
7223 int getBeltNrFromBeltSwitchElement(int element)
7225 return (element < EL_CONVEYOR_BELT_2_SWITCH_LEFT ? 0 :
7226 element < EL_CONVEYOR_BELT_3_SWITCH_LEFT ? 1 :
7227 element < EL_CONVEYOR_BELT_4_SWITCH_LEFT ? 2 : 3);
7230 int getBeltDirNrFromBeltElement(int element)
7232 static int belt_base_element[4] =
7234 EL_CONVEYOR_BELT_1_LEFT,
7235 EL_CONVEYOR_BELT_2_LEFT,
7236 EL_CONVEYOR_BELT_3_LEFT,
7237 EL_CONVEYOR_BELT_4_LEFT
7240 int belt_nr = getBeltNrFromBeltElement(element);
7241 int belt_dir_nr = element - belt_base_element[belt_nr];
7243 return (belt_dir_nr % 3);
7246 int getBeltDirNrFromBeltSwitchElement(int element)
7248 static int belt_base_element[4] =
7250 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
7251 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
7252 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
7253 EL_CONVEYOR_BELT_4_SWITCH_LEFT
7256 int belt_nr = getBeltNrFromBeltSwitchElement(element);
7257 int belt_dir_nr = element - belt_base_element[belt_nr];
7259 return (belt_dir_nr % 3);
7262 int getBeltDirFromBeltElement(int element)
7264 static int belt_move_dir[3] =
7271 int belt_dir_nr = getBeltDirNrFromBeltElement(element);
7273 return belt_move_dir[belt_dir_nr];
7276 int getBeltDirFromBeltSwitchElement(int element)
7278 static int belt_move_dir[3] =
7285 int belt_dir_nr = getBeltDirNrFromBeltSwitchElement(element);
7287 return belt_move_dir[belt_dir_nr];
7290 int getBeltElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
7292 static int belt_base_element[4] =
7294 EL_CONVEYOR_BELT_1_LEFT,
7295 EL_CONVEYOR_BELT_2_LEFT,
7296 EL_CONVEYOR_BELT_3_LEFT,
7297 EL_CONVEYOR_BELT_4_LEFT
7300 return belt_base_element[belt_nr] + belt_dir_nr;
7303 int getBeltElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
7305 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
7307 return getBeltElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
7310 int getBeltSwitchElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
7312 static int belt_base_element[4] =
7314 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
7315 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
7316 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
7317 EL_CONVEYOR_BELT_4_SWITCH_LEFT
7320 return belt_base_element[belt_nr] + belt_dir_nr;
7323 int getBeltSwitchElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
7325 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
7327 return getBeltSwitchElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
7330 int getNumActivePlayers_EM()
7332 int num_players = 0;
7338 for (i = 0; i < MAX_PLAYERS; i++)
7339 if (tape.player_participates[i])
7345 int getGameFrameDelay_EM(int native_em_game_frame_delay)
7347 int game_frame_delay_value;
7349 game_frame_delay_value =
7350 (tape.playing && tape.fast_forward ? FfwdFrameDelay :
7351 GameFrameDelay == GAME_FRAME_DELAY ? native_em_game_frame_delay :
7354 if (tape.playing && tape.warp_forward && !tape.pausing)
7355 game_frame_delay_value = 0;
7357 return game_frame_delay_value;
7360 unsigned int InitRND(int seed)
7362 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
7363 return InitEngineRandom_EM(seed);
7364 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
7365 return InitEngineRandom_SP(seed);
7367 return InitEngineRandom_RND(seed);
7371 static struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
7372 static struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
7375 inline static int get_effective_element_EM(int tile, int frame_em)
7377 int element = object_mapping[tile].element_rnd;
7378 int action = object_mapping[tile].action;
7379 boolean is_backside = object_mapping[tile].is_backside;
7380 boolean action_removing = (action == ACTION_DIGGING ||
7381 action == ACTION_SNAPPING ||
7382 action == ACTION_COLLECTING);
7388 case Yacid_splash_eB:
7389 case Yacid_splash_wB:
7390 return (frame_em > 5 ? EL_EMPTY : element);
7394 case Ydiamond_stone:
7395 // if (!game.use_native_emc_graphics_engine)
7403 else /* frame_em == 7 */
7407 case Yacid_splash_eB:
7408 case Yacid_splash_wB:
7411 case Yemerald_stone:
7414 case Ydiamond_stone:
7418 case Xdrip_stretchB:
7437 case Xsand_stonein_1:
7438 case Xsand_stonein_2:
7439 case Xsand_stonein_3:
7440 case Xsand_stonein_4:
7444 return (is_backside || action_removing ? EL_EMPTY : element);
7449 inline static boolean check_linear_animation_EM(int tile)
7453 case Xsand_stonesand_1:
7454 case Xsand_stonesand_quickout_1:
7455 case Xsand_sandstone_1:
7456 case Xsand_stonein_1:
7457 case Xsand_stoneout_1:
7477 case Yacid_splash_eB:
7478 case Yacid_splash_wB:
7479 case Yemerald_stone:
7487 inline static void set_crumbled_graphics_EM(struct GraphicInfo_EM *g_em,
7488 boolean has_crumbled_graphics,
7489 int crumbled, int sync_frame)
7491 /* if element can be crumbled, but certain action graphics are just empty
7492 space (like instantly snapping sand to empty space in 1 frame), do not
7493 treat these empty space graphics as crumbled graphics in EMC engine */
7494 if (crumbled == IMG_EMPTY_SPACE)
7495 has_crumbled_graphics = FALSE;
7497 if (has_crumbled_graphics)
7499 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
7500 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
7501 g_crumbled->anim_delay,
7502 g_crumbled->anim_mode,
7503 g_crumbled->anim_start_frame,
7506 getGraphicSource(crumbled, frame_crumbled, &g_em->crumbled_bitmap,
7507 &g_em->crumbled_src_x, &g_em->crumbled_src_y);
7509 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
7511 g_em->has_crumbled_graphics = TRUE;
7515 g_em->crumbled_bitmap = NULL;
7516 g_em->crumbled_src_x = 0;
7517 g_em->crumbled_src_y = 0;
7518 g_em->crumbled_border_size = 0;
7520 g_em->has_crumbled_graphics = FALSE;
7524 void ResetGfxAnimation_EM(int x, int y, int tile)
7529 void SetGfxAnimation_EM(struct GraphicInfo_EM *g_em,
7530 int tile, int frame_em, int x, int y)
7532 int action = object_mapping[tile].action;
7534 int direction = object_mapping[tile].direction;
7535 int effective_element = get_effective_element_EM(tile, frame_em);
7536 int graphic = (direction == MV_NONE ?
7537 el_act2img(effective_element, action) :
7538 el_act_dir2img(effective_element, action, direction));
7539 struct GraphicInfo *g = &graphic_info[graphic];
7542 boolean action_removing = (action == ACTION_DIGGING ||
7543 action == ACTION_SNAPPING ||
7544 action == ACTION_COLLECTING);
7545 boolean action_moving = (action == ACTION_FALLING ||
7546 action == ACTION_MOVING ||
7547 action == ACTION_PUSHING ||
7548 action == ACTION_EATING ||
7549 action == ACTION_FILLING ||
7550 action == ACTION_EMPTYING);
7551 boolean action_falling = (action == ACTION_FALLING ||
7552 action == ACTION_FILLING ||
7553 action == ACTION_EMPTYING);
7555 /* special case: graphic uses "2nd movement tile" and has defined
7556 7 frames for movement animation (or less) => use default graphic
7557 for last (8th) frame which ends the movement animation */
7558 if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
7560 action = ACTION_DEFAULT; /* (keep action_* unchanged for now) */
7561 graphic = (direction == MV_NONE ?
7562 el_act2img(effective_element, action) :
7563 el_act_dir2img(effective_element, action, direction));
7565 g = &graphic_info[graphic];
7569 if (tile == Xsand_stonesand_1 ||
7570 tile == Xsand_stonesand_2 ||
7571 tile == Xsand_stonesand_3 ||
7572 tile == Xsand_stonesand_4)
7573 printf("::: 1: quicksand frame %d [%d]\n", GfxFrame[x][y], tile);
7577 if ((action_removing || check_linear_animation_EM(tile)) && frame_em == 0)
7581 // printf("::: resetting... [%d]\n", tile);
7584 if (action_removing || check_linear_animation_EM(tile))
7586 GfxFrame[x][y] = frame_em;
7588 // printf("::: resetting... [%d]\n", tile);
7591 else if (action_moving)
7593 boolean is_backside = object_mapping[tile].is_backside;
7597 int direction = object_mapping[tile].direction;
7598 int move_dir = (action_falling ? MV_DOWN : direction);
7603 /* !!! TEST !!! NEW !!! DOES NOT WORK RIGHT YET !!! */
7604 if (g->double_movement && frame_em == 0)
7608 // printf("::: resetting... [%d]\n", tile);
7612 if (move_dir == MV_LEFT)
7613 GfxFrame[x - 1][y] = GfxFrame[x][y];
7614 else if (move_dir == MV_RIGHT)
7615 GfxFrame[x + 1][y] = GfxFrame[x][y];
7616 else if (move_dir == MV_UP)
7617 GfxFrame[x][y - 1] = GfxFrame[x][y];
7618 else if (move_dir == MV_DOWN)
7619 GfxFrame[x][y + 1] = GfxFrame[x][y];
7626 /* special case: animation for Xsand_stonesand_quickout_1/2 twice as fast */
7627 if (tile == Xsand_stonesand_quickout_1 ||
7628 tile == Xsand_stonesand_quickout_2)
7633 if (tile == Xsand_stonesand_1 ||
7634 tile == Xsand_stonesand_2 ||
7635 tile == Xsand_stonesand_3 ||
7636 tile == Xsand_stonesand_4)
7637 printf("::: 2: quicksand frame %d [%d]\n", GfxFrame[x][y], tile);
7641 if (graphic_info[graphic].anim_global_sync)
7642 sync_frame = FrameCounter;
7643 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
7644 sync_frame = GfxFrame[x][y];
7646 sync_frame = 0; /* playfield border (pseudo steel) */
7648 SetRandomAnimationValue(x, y);
7650 int frame = getAnimationFrame(g->anim_frames,
7653 g->anim_start_frame,
7656 g_em->unique_identifier =
7657 (graphic << 16) | ((frame % 8) << 12) | (g_em->width << 6) | g_em->height;
7661 void getGraphicSourceObjectExt_EM(struct GraphicInfo_EM *g_em,
7662 int tile, int frame_em, int x, int y)
7664 int action = object_mapping[tile].action;
7665 int direction = object_mapping[tile].direction;
7666 boolean is_backside = object_mapping[tile].is_backside;
7667 int effective_element = get_effective_element_EM(tile, frame_em);
7669 int effective_action = action;
7671 int effective_action = (frame_em < 7 ? action : ACTION_DEFAULT);
7673 int graphic = (direction == MV_NONE ?
7674 el_act2img(effective_element, effective_action) :
7675 el_act_dir2img(effective_element, effective_action,
7677 int crumbled = (direction == MV_NONE ?
7678 el_act2crm(effective_element, effective_action) :
7679 el_act_dir2crm(effective_element, effective_action,
7681 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
7682 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
7683 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
7684 struct GraphicInfo *g = &graphic_info[graphic];
7686 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
7690 /* special case: graphic uses "2nd movement tile" and has defined
7691 7 frames for movement animation (or less) => use default graphic
7692 for last (8th) frame which ends the movement animation */
7693 if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
7695 effective_action = ACTION_DEFAULT;
7696 graphic = (direction == MV_NONE ?
7697 el_act2img(effective_element, effective_action) :
7698 el_act_dir2img(effective_element, effective_action,
7700 crumbled = (direction == MV_NONE ?
7701 el_act2crm(effective_element, effective_action) :
7702 el_act_dir2crm(effective_element, effective_action,
7705 g = &graphic_info[graphic];
7715 if (frame_em == 0) /* reset animation frame for certain elements */
7717 if (check_linear_animation_EM(tile))
7722 if (graphic_info[graphic].anim_global_sync)
7723 sync_frame = FrameCounter;
7724 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
7725 sync_frame = GfxFrame[x][y];
7727 sync_frame = 0; /* playfield border (pseudo steel) */
7729 SetRandomAnimationValue(x, y);
7734 int xxx_sync_frame = (i == Xdrip_stretch ? 7 :
7735 i == Xdrip_stretchB ? 7 :
7736 i == Ydrip_s2 ? j + 8 :
7737 i == Ydrip_s2B ? j + 8 :
7746 i == Xfake_acid_1 ? 0 :
7747 i == Xfake_acid_2 ? 10 :
7748 i == Xfake_acid_3 ? 20 :
7749 i == Xfake_acid_4 ? 30 :
7750 i == Xfake_acid_5 ? 40 :
7751 i == Xfake_acid_6 ? 50 :
7752 i == Xfake_acid_7 ? 60 :
7753 i == Xfake_acid_8 ? 70 :
7755 i == Xball_2B ? j + 8 :
7756 i == Yball_eat ? j + 1 :
7757 i == Ykey_1_eat ? j + 1 :
7758 i == Ykey_2_eat ? j + 1 :
7759 i == Ykey_3_eat ? j + 1 :
7760 i == Ykey_4_eat ? j + 1 :
7761 i == Ykey_5_eat ? j + 1 :
7762 i == Ykey_6_eat ? j + 1 :
7763 i == Ykey_7_eat ? j + 1 :
7764 i == Ykey_8_eat ? j + 1 :
7765 i == Ylenses_eat ? j + 1 :
7766 i == Ymagnify_eat ? j + 1 :
7767 i == Ygrass_eat ? j + 1 :
7768 i == Ydirt_eat ? j + 1 :
7769 i == Xamoeba_1 ? 0 :
7770 i == Xamoeba_2 ? 1 :
7771 i == Xamoeba_3 ? 2 :
7772 i == Xamoeba_4 ? 3 :
7773 i == Xamoeba_5 ? 0 :
7774 i == Xamoeba_6 ? 1 :
7775 i == Xamoeba_7 ? 2 :
7776 i == Xamoeba_8 ? 3 :
7777 i == Xexit_2 ? j + 8 :
7778 i == Xexit_3 ? j + 16 :
7779 i == Xdynamite_1 ? 0 :
7780 i == Xdynamite_2 ? 8 :
7781 i == Xdynamite_3 ? 16 :
7782 i == Xdynamite_4 ? 24 :
7783 i == Xsand_stonein_1 ? j + 1 :
7784 i == Xsand_stonein_2 ? j + 9 :
7785 i == Xsand_stonein_3 ? j + 17 :
7786 i == Xsand_stonein_4 ? j + 25 :
7787 i == Xsand_stoneout_1 && j == 0 ? 0 :
7788 i == Xsand_stoneout_1 && j == 1 ? 0 :
7789 i == Xsand_stoneout_1 && j == 2 ? 1 :
7790 i == Xsand_stoneout_1 && j == 3 ? 2 :
7791 i == Xsand_stoneout_1 && j == 4 ? 2 :
7792 i == Xsand_stoneout_1 && j == 5 ? 3 :
7793 i == Xsand_stoneout_1 && j == 6 ? 4 :
7794 i == Xsand_stoneout_1 && j == 7 ? 4 :
7795 i == Xsand_stoneout_2 && j == 0 ? 5 :
7796 i == Xsand_stoneout_2 && j == 1 ? 6 :
7797 i == Xsand_stoneout_2 && j == 2 ? 7 :
7798 i == Xsand_stoneout_2 && j == 3 ? 8 :
7799 i == Xsand_stoneout_2 && j == 4 ? 9 :
7800 i == Xsand_stoneout_2 && j == 5 ? 11 :
7801 i == Xsand_stoneout_2 && j == 6 ? 13 :
7802 i == Xsand_stoneout_2 && j == 7 ? 15 :
7803 i == Xboom_bug && j == 1 ? 2 :
7804 i == Xboom_bug && j == 2 ? 2 :
7805 i == Xboom_bug && j == 3 ? 4 :
7806 i == Xboom_bug && j == 4 ? 4 :
7807 i == Xboom_bug && j == 5 ? 2 :
7808 i == Xboom_bug && j == 6 ? 2 :
7809 i == Xboom_bug && j == 7 ? 0 :
7810 i == Xboom_bomb && j == 1 ? 2 :
7811 i == Xboom_bomb && j == 2 ? 2 :
7812 i == Xboom_bomb && j == 3 ? 4 :
7813 i == Xboom_bomb && j == 4 ? 4 :
7814 i == Xboom_bomb && j == 5 ? 2 :
7815 i == Xboom_bomb && j == 6 ? 2 :
7816 i == Xboom_bomb && j == 7 ? 0 :
7817 i == Xboom_android && j == 7 ? 6 :
7818 i == Xboom_1 && j == 1 ? 2 :
7819 i == Xboom_1 && j == 2 ? 2 :
7820 i == Xboom_1 && j == 3 ? 4 :
7821 i == Xboom_1 && j == 4 ? 4 :
7822 i == Xboom_1 && j == 5 ? 6 :
7823 i == Xboom_1 && j == 6 ? 6 :
7824 i == Xboom_1 && j == 7 ? 8 :
7825 i == Xboom_2 && j == 0 ? 8 :
7826 i == Xboom_2 && j == 1 ? 8 :
7827 i == Xboom_2 && j == 2 ? 10 :
7828 i == Xboom_2 && j == 3 ? 10 :
7829 i == Xboom_2 && j == 4 ? 10 :
7830 i == Xboom_2 && j == 5 ? 12 :
7831 i == Xboom_2 && j == 6 ? 12 :
7832 i == Xboom_2 && j == 7 ? 12 :
7834 special_animation && j == 4 ? 3 :
7835 effective_action != action ? 0 :
7841 int xxx_effective_action;
7842 int xxx_has_action_graphics;
7845 int element = object_mapping[i].element_rnd;
7846 int action = object_mapping[i].action;
7847 int direction = object_mapping[i].direction;
7848 boolean is_backside = object_mapping[i].is_backside;
7850 boolean action_removing = (action == ACTION_DIGGING ||
7851 action == ACTION_SNAPPING ||
7852 action == ACTION_COLLECTING);
7854 boolean action_exploding = ((action == ACTION_EXPLODING ||
7855 action == ACTION_SMASHED_BY_ROCK ||
7856 action == ACTION_SMASHED_BY_SPRING) &&
7857 element != EL_DIAMOND);
7858 boolean action_active = (action == ACTION_ACTIVE);
7859 boolean action_other = (action == ACTION_OTHER);
7863 int effective_element = get_effective_element_EM(i, j);
7865 int effective_element = (j > 5 && i == Yacid_splash_eB ? EL_EMPTY :
7866 j > 5 && i == Yacid_splash_wB ? EL_EMPTY :
7868 i == Xdrip_stretch ? element :
7869 i == Xdrip_stretchB ? element :
7870 i == Ydrip_s1 ? element :
7871 i == Ydrip_s1B ? element :
7872 i == Xball_1B ? element :
7873 i == Xball_2 ? element :
7874 i == Xball_2B ? element :
7875 i == Yball_eat ? element :
7876 i == Ykey_1_eat ? element :
7877 i == Ykey_2_eat ? element :
7878 i == Ykey_3_eat ? element :
7879 i == Ykey_4_eat ? element :
7880 i == Ykey_5_eat ? element :
7881 i == Ykey_6_eat ? element :
7882 i == Ykey_7_eat ? element :
7883 i == Ykey_8_eat ? element :
7884 i == Ylenses_eat ? element :
7885 i == Ymagnify_eat ? element :
7886 i == Ygrass_eat ? element :
7887 i == Ydirt_eat ? element :
7888 i == Yemerald_stone ? EL_EMERALD :
7889 i == Ydiamond_stone ? EL_ROCK :
7890 i == Xsand_stonein_1 ? element :
7891 i == Xsand_stonein_2 ? element :
7892 i == Xsand_stonein_3 ? element :
7893 i == Xsand_stonein_4 ? element :
7894 is_backside ? EL_EMPTY :
7895 action_removing ? EL_EMPTY :
7898 int effective_action = (j < 7 ? action :
7899 i == Xdrip_stretch ? action :
7900 i == Xdrip_stretchB ? action :
7901 i == Ydrip_s1 ? action :
7902 i == Ydrip_s1B ? action :
7903 i == Xball_1B ? action :
7904 i == Xball_2 ? action :
7905 i == Xball_2B ? action :
7906 i == Yball_eat ? action :
7907 i == Ykey_1_eat ? action :
7908 i == Ykey_2_eat ? action :
7909 i == Ykey_3_eat ? action :
7910 i == Ykey_4_eat ? action :
7911 i == Ykey_5_eat ? action :
7912 i == Ykey_6_eat ? action :
7913 i == Ykey_7_eat ? action :
7914 i == Ykey_8_eat ? action :
7915 i == Ylenses_eat ? action :
7916 i == Ymagnify_eat ? action :
7917 i == Ygrass_eat ? action :
7918 i == Ydirt_eat ? action :
7919 i == Xsand_stonein_1 ? action :
7920 i == Xsand_stonein_2 ? action :
7921 i == Xsand_stonein_3 ? action :
7922 i == Xsand_stonein_4 ? action :
7923 i == Xsand_stoneout_1 ? action :
7924 i == Xsand_stoneout_2 ? action :
7925 i == Xboom_android ? ACTION_EXPLODING :
7926 action_exploding ? ACTION_EXPLODING :
7927 action_active ? action :
7928 action_other ? action :
7930 int graphic = (el_act_dir2img(effective_element, effective_action,
7932 int crumbled = (el_act_dir2crm(effective_element, effective_action,
7934 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
7935 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
7936 boolean has_action_graphics = (graphic != base_graphic);
7937 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
7938 struct GraphicInfo *g = &graphic_info[graphic];
7940 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
7942 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
7945 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
7946 boolean special_animation = (action != ACTION_DEFAULT &&
7947 g->anim_frames == 3 &&
7948 g->anim_delay == 2 &&
7949 g->anim_mode & ANIM_LINEAR);
7950 xxx_sync_frame = (i == Xdrip_stretch ? 7 :
7951 i == Xdrip_stretchB ? 7 :
7952 i == Ydrip_s2 ? j + 8 :
7953 i == Ydrip_s2B ? j + 8 :
7962 i == Xfake_acid_1 ? 0 :
7963 i == Xfake_acid_2 ? 10 :
7964 i == Xfake_acid_3 ? 20 :
7965 i == Xfake_acid_4 ? 30 :
7966 i == Xfake_acid_5 ? 40 :
7967 i == Xfake_acid_6 ? 50 :
7968 i == Xfake_acid_7 ? 60 :
7969 i == Xfake_acid_8 ? 70 :
7971 i == Xball_2B ? j + 8 :
7972 i == Yball_eat ? j + 1 :
7973 i == Ykey_1_eat ? j + 1 :
7974 i == Ykey_2_eat ? j + 1 :
7975 i == Ykey_3_eat ? j + 1 :
7976 i == Ykey_4_eat ? j + 1 :
7977 i == Ykey_5_eat ? j + 1 :
7978 i == Ykey_6_eat ? j + 1 :
7979 i == Ykey_7_eat ? j + 1 :
7980 i == Ykey_8_eat ? j + 1 :
7981 i == Ylenses_eat ? j + 1 :
7982 i == Ymagnify_eat ? j + 1 :
7983 i == Ygrass_eat ? j + 1 :
7984 i == Ydirt_eat ? j + 1 :
7985 i == Xamoeba_1 ? 0 :
7986 i == Xamoeba_2 ? 1 :
7987 i == Xamoeba_3 ? 2 :
7988 i == Xamoeba_4 ? 3 :
7989 i == Xamoeba_5 ? 0 :
7990 i == Xamoeba_6 ? 1 :
7991 i == Xamoeba_7 ? 2 :
7992 i == Xamoeba_8 ? 3 :
7993 i == Xexit_2 ? j + 8 :
7994 i == Xexit_3 ? j + 16 :
7995 i == Xdynamite_1 ? 0 :
7996 i == Xdynamite_2 ? 8 :
7997 i == Xdynamite_3 ? 16 :
7998 i == Xdynamite_4 ? 24 :
7999 i == Xsand_stonein_1 ? j + 1 :
8000 i == Xsand_stonein_2 ? j + 9 :
8001 i == Xsand_stonein_3 ? j + 17 :
8002 i == Xsand_stonein_4 ? j + 25 :
8003 i == Xsand_stoneout_1 && j == 0 ? 0 :
8004 i == Xsand_stoneout_1 && j == 1 ? 0 :
8005 i == Xsand_stoneout_1 && j == 2 ? 1 :
8006 i == Xsand_stoneout_1 && j == 3 ? 2 :
8007 i == Xsand_stoneout_1 && j == 4 ? 2 :
8008 i == Xsand_stoneout_1 && j == 5 ? 3 :
8009 i == Xsand_stoneout_1 && j == 6 ? 4 :
8010 i == Xsand_stoneout_1 && j == 7 ? 4 :
8011 i == Xsand_stoneout_2 && j == 0 ? 5 :
8012 i == Xsand_stoneout_2 && j == 1 ? 6 :
8013 i == Xsand_stoneout_2 && j == 2 ? 7 :
8014 i == Xsand_stoneout_2 && j == 3 ? 8 :
8015 i == Xsand_stoneout_2 && j == 4 ? 9 :
8016 i == Xsand_stoneout_2 && j == 5 ? 11 :
8017 i == Xsand_stoneout_2 && j == 6 ? 13 :
8018 i == Xsand_stoneout_2 && j == 7 ? 15 :
8019 i == Xboom_bug && j == 1 ? 2 :
8020 i == Xboom_bug && j == 2 ? 2 :
8021 i == Xboom_bug && j == 3 ? 4 :
8022 i == Xboom_bug && j == 4 ? 4 :
8023 i == Xboom_bug && j == 5 ? 2 :
8024 i == Xboom_bug && j == 6 ? 2 :
8025 i == Xboom_bug && j == 7 ? 0 :
8026 i == Xboom_bomb && j == 1 ? 2 :
8027 i == Xboom_bomb && j == 2 ? 2 :
8028 i == Xboom_bomb && j == 3 ? 4 :
8029 i == Xboom_bomb && j == 4 ? 4 :
8030 i == Xboom_bomb && j == 5 ? 2 :
8031 i == Xboom_bomb && j == 6 ? 2 :
8032 i == Xboom_bomb && j == 7 ? 0 :
8033 i == Xboom_android && j == 7 ? 6 :
8034 i == Xboom_1 && j == 1 ? 2 :
8035 i == Xboom_1 && j == 2 ? 2 :
8036 i == Xboom_1 && j == 3 ? 4 :
8037 i == Xboom_1 && j == 4 ? 4 :
8038 i == Xboom_1 && j == 5 ? 6 :
8039 i == Xboom_1 && j == 6 ? 6 :
8040 i == Xboom_1 && j == 7 ? 8 :
8041 i == Xboom_2 && j == 0 ? 8 :
8042 i == Xboom_2 && j == 1 ? 8 :
8043 i == Xboom_2 && j == 2 ? 10 :
8044 i == Xboom_2 && j == 3 ? 10 :
8045 i == Xboom_2 && j == 4 ? 10 :
8046 i == Xboom_2 && j == 5 ? 12 :
8047 i == Xboom_2 && j == 6 ? 12 :
8048 i == Xboom_2 && j == 7 ? 12 :
8049 special_animation && j == 4 ? 3 :
8050 effective_action != action ? 0 :
8053 xxx_effective_action = effective_action;
8054 xxx_has_action_graphics = has_action_graphics;
8059 int frame = getAnimationFrame(g->anim_frames,
8062 g->anim_start_frame,
8076 int old_src_x = g_em->src_x;
8077 int old_src_y = g_em->src_y;
8081 getGraphicSourceExt(graphic, frame, &g_em->bitmap, &g_em->src_x, &g_em->src_y,
8082 g->double_movement && is_backside);
8084 getGraphicSourceExt(graphic, frame, &g_em->bitmap,
8085 &g_em->src_x, &g_em->src_y, FALSE);
8090 if (tile == Ydiamond_stone)
8091 printf("::: stone smashing diamond... %d: %d, %d, %d, %d, %d -> %d [%d, %d, %d, %d, %d, %d] [%d]\n",
8096 g->anim_start_frame,
8099 g_em->src_x, g_em->src_y,
8100 g_em->src_offset_x, g_em->src_offset_y,
8101 g_em->dst_offset_x, g_em->dst_offset_y,
8113 if (graphic == IMG_BUG_MOVING_RIGHT)
8114 printf("::: %d, %d, %d: %d, %d [%d, %d -> %d, %d]\n", graphic, x, y,
8115 g->double_movement, is_backside,
8116 old_src_x, old_src_y, g_em->src_x, g_em->src_y);
8124 g_em->src_offset_x = 0;
8125 g_em->src_offset_y = 0;
8126 g_em->dst_offset_x = 0;
8127 g_em->dst_offset_y = 0;
8128 g_em->width = TILEX;
8129 g_em->height = TILEY;
8131 g_em->preserve_background = FALSE;
8134 /* (updating the "crumbled" graphic definitions is probably not really needed,
8135 as animations for crumbled graphics can't be longer than one EMC cycle) */
8137 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
8142 g_em->crumbled_bitmap = NULL;
8143 g_em->crumbled_src_x = 0;
8144 g_em->crumbled_src_y = 0;
8146 g_em->has_crumbled_graphics = FALSE;
8148 if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
8150 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
8151 g_crumbled->anim_delay,
8152 g_crumbled->anim_mode,
8153 g_crumbled->anim_start_frame,
8156 getGraphicSource(crumbled, frame_crumbled, &g_em->crumbled_bitmap,
8157 &g_em->crumbled_src_x, &g_em->crumbled_src_y);
8159 g_em->has_crumbled_graphics = TRUE;
8165 int effective_action = xxx_effective_action;
8166 int has_action_graphics = xxx_has_action_graphics;
8168 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
8169 effective_action == ACTION_MOVING ||
8170 effective_action == ACTION_PUSHING ||
8171 effective_action == ACTION_EATING)) ||
8172 (!has_action_graphics && (effective_action == ACTION_FILLING ||
8173 effective_action == ACTION_EMPTYING)))
8176 (effective_action == ACTION_FALLING ||
8177 effective_action == ACTION_FILLING ||
8178 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
8179 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
8180 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
8181 int num_steps = (i == Ydrip_s1 ? 16 :
8182 i == Ydrip_s1B ? 16 :
8183 i == Ydrip_s2 ? 16 :
8184 i == Ydrip_s2B ? 16 :
8185 i == Xsand_stonein_1 ? 32 :
8186 i == Xsand_stonein_2 ? 32 :
8187 i == Xsand_stonein_3 ? 32 :
8188 i == Xsand_stonein_4 ? 32 :
8189 i == Xsand_stoneout_1 ? 16 :
8190 i == Xsand_stoneout_2 ? 16 : 8);
8191 int cx = ABS(dx) * (TILEX / num_steps);
8192 int cy = ABS(dy) * (TILEY / num_steps);
8193 int step_frame = (i == Ydrip_s2 ? j + 8 :
8194 i == Ydrip_s2B ? j + 8 :
8195 i == Xsand_stonein_2 ? j + 8 :
8196 i == Xsand_stonein_3 ? j + 16 :
8197 i == Xsand_stonein_4 ? j + 24 :
8198 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
8199 int step = (is_backside ? step_frame : num_steps - step_frame);
8201 if (is_backside) /* tile where movement starts */
8203 if (dx < 0 || dy < 0)
8205 g_em->src_offset_x = cx * step;
8206 g_em->src_offset_y = cy * step;
8210 g_em->dst_offset_x = cx * step;
8211 g_em->dst_offset_y = cy * step;
8214 else /* tile where movement ends */
8216 if (dx < 0 || dy < 0)
8218 g_em->dst_offset_x = cx * step;
8219 g_em->dst_offset_y = cy * step;
8223 g_em->src_offset_x = cx * step;
8224 g_em->src_offset_y = cy * step;
8228 g_em->width = TILEX - cx * step;
8229 g_em->height = TILEY - cy * step;
8232 /* create unique graphic identifier to decide if tile must be redrawn */
8233 /* bit 31 - 16 (16 bit): EM style graphic
8234 bit 15 - 12 ( 4 bit): EM style frame
8235 bit 11 - 6 ( 6 bit): graphic width
8236 bit 5 - 0 ( 6 bit): graphic height */
8237 g_em->unique_identifier =
8238 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
8244 void getGraphicSourcePlayerExt_EM(struct GraphicInfo_EM *g_em,
8245 int player_nr, int anim, int frame_em)
8247 int element = player_mapping[player_nr][anim].element_rnd;
8248 int action = player_mapping[player_nr][anim].action;
8249 int direction = player_mapping[player_nr][anim].direction;
8250 int graphic = (direction == MV_NONE ?
8251 el_act2img(element, action) :
8252 el_act_dir2img(element, action, direction));
8253 struct GraphicInfo *g = &graphic_info[graphic];
8256 InitPlayerGfxAnimation(&stored_player[player_nr], action, direction);
8258 stored_player[player_nr].StepFrame = frame_em;
8260 sync_frame = stored_player[player_nr].Frame;
8262 int frame = getAnimationFrame(g->anim_frames,
8265 g->anim_start_frame,
8268 getGraphicSourceExt(graphic, frame, &g_em->bitmap,
8269 &g_em->src_x, &g_em->src_y, FALSE);
8272 printf("::: %d: %d, %d [%d]\n",
8274 stored_player[player_nr].Frame,
8275 stored_player[player_nr].StepFrame,
8280 void InitGraphicInfo_EM(void)
8283 struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
8284 struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
8289 int num_em_gfx_errors = 0;
8291 if (graphic_info_em_object[0][0].bitmap == NULL)
8293 /* EM graphics not yet initialized in em_open_all() */
8298 printf("::: [4 errors can be ignored (1 x 'bomb', 3 x 'em_dynamite']\n");
8301 /* always start with reliable default values */
8302 for (i = 0; i < TILE_MAX; i++)
8304 object_mapping[i].element_rnd = EL_UNKNOWN;
8305 object_mapping[i].is_backside = FALSE;
8306 object_mapping[i].action = ACTION_DEFAULT;
8307 object_mapping[i].direction = MV_NONE;
8310 /* always start with reliable default values */
8311 for (p = 0; p < MAX_PLAYERS; p++)
8313 for (i = 0; i < SPR_MAX; i++)
8315 player_mapping[p][i].element_rnd = EL_UNKNOWN;
8316 player_mapping[p][i].action = ACTION_DEFAULT;
8317 player_mapping[p][i].direction = MV_NONE;
8321 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
8323 int e = em_object_mapping_list[i].element_em;
8325 object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd;
8326 object_mapping[e].is_backside = em_object_mapping_list[i].is_backside;
8328 if (em_object_mapping_list[i].action != -1)
8329 object_mapping[e].action = em_object_mapping_list[i].action;
8331 if (em_object_mapping_list[i].direction != -1)
8332 object_mapping[e].direction =
8333 MV_DIR_FROM_BIT(em_object_mapping_list[i].direction);
8336 for (i = 0; em_player_mapping_list[i].action_em != -1; i++)
8338 int a = em_player_mapping_list[i].action_em;
8339 int p = em_player_mapping_list[i].player_nr;
8341 player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd;
8343 if (em_player_mapping_list[i].action != -1)
8344 player_mapping[p][a].action = em_player_mapping_list[i].action;
8346 if (em_player_mapping_list[i].direction != -1)
8347 player_mapping[p][a].direction =
8348 MV_DIR_FROM_BIT(em_player_mapping_list[i].direction);
8351 for (i = 0; i < TILE_MAX; i++)
8353 int element = object_mapping[i].element_rnd;
8354 int action = object_mapping[i].action;
8355 int direction = object_mapping[i].direction;
8356 boolean is_backside = object_mapping[i].is_backside;
8358 boolean action_removing = (action == ACTION_DIGGING ||
8359 action == ACTION_SNAPPING ||
8360 action == ACTION_COLLECTING);
8362 boolean action_exploding = ((action == ACTION_EXPLODING ||
8363 action == ACTION_SMASHED_BY_ROCK ||
8364 action == ACTION_SMASHED_BY_SPRING) &&
8365 element != EL_DIAMOND);
8366 boolean action_active = (action == ACTION_ACTIVE);
8367 boolean action_other = (action == ACTION_OTHER);
8369 for (j = 0; j < 8; j++)
8372 int effective_element = get_effective_element_EM(i, j);
8374 int effective_element = (j > 5 && i == Yacid_splash_eB ? EL_EMPTY :
8375 j > 5 && i == Yacid_splash_wB ? EL_EMPTY :
8377 i == Xdrip_stretch ? element :
8378 i == Xdrip_stretchB ? element :
8379 i == Ydrip_s1 ? element :
8380 i == Ydrip_s1B ? element :
8381 i == Xball_1B ? element :
8382 i == Xball_2 ? element :
8383 i == Xball_2B ? element :
8384 i == Yball_eat ? element :
8385 i == Ykey_1_eat ? element :
8386 i == Ykey_2_eat ? element :
8387 i == Ykey_3_eat ? element :
8388 i == Ykey_4_eat ? element :
8389 i == Ykey_5_eat ? element :
8390 i == Ykey_6_eat ? element :
8391 i == Ykey_7_eat ? element :
8392 i == Ykey_8_eat ? element :
8393 i == Ylenses_eat ? element :
8394 i == Ymagnify_eat ? element :
8395 i == Ygrass_eat ? element :
8396 i == Ydirt_eat ? element :
8397 i == Yemerald_stone ? EL_EMERALD :
8398 i == Ydiamond_stone ? EL_ROCK :
8399 i == Xsand_stonein_1 ? element :
8400 i == Xsand_stonein_2 ? element :
8401 i == Xsand_stonein_3 ? element :
8402 i == Xsand_stonein_4 ? element :
8403 is_backside ? EL_EMPTY :
8404 action_removing ? EL_EMPTY :
8407 int effective_action = (j < 7 ? action :
8408 i == Xdrip_stretch ? action :
8409 i == Xdrip_stretchB ? action :
8410 i == Ydrip_s1 ? action :
8411 i == Ydrip_s1B ? action :
8412 i == Xball_1B ? action :
8413 i == Xball_2 ? action :
8414 i == Xball_2B ? action :
8415 i == Yball_eat ? action :
8416 i == Ykey_1_eat ? action :
8417 i == Ykey_2_eat ? action :
8418 i == Ykey_3_eat ? action :
8419 i == Ykey_4_eat ? action :
8420 i == Ykey_5_eat ? action :
8421 i == Ykey_6_eat ? action :
8422 i == Ykey_7_eat ? action :
8423 i == Ykey_8_eat ? action :
8424 i == Ylenses_eat ? action :
8425 i == Ymagnify_eat ? action :
8426 i == Ygrass_eat ? action :
8427 i == Ydirt_eat ? action :
8428 i == Xsand_stonein_1 ? action :
8429 i == Xsand_stonein_2 ? action :
8430 i == Xsand_stonein_3 ? action :
8431 i == Xsand_stonein_4 ? action :
8432 i == Xsand_stoneout_1 ? action :
8433 i == Xsand_stoneout_2 ? action :
8434 i == Xboom_android ? ACTION_EXPLODING :
8435 action_exploding ? ACTION_EXPLODING :
8436 action_active ? action :
8437 action_other ? action :
8439 int graphic = (el_act_dir2img(effective_element, effective_action,
8441 int crumbled = (el_act_dir2crm(effective_element, effective_action,
8443 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
8444 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
8445 boolean has_action_graphics = (graphic != base_graphic);
8446 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
8447 struct GraphicInfo *g = &graphic_info[graphic];
8449 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
8451 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
8454 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
8455 boolean special_animation = (action != ACTION_DEFAULT &&
8456 g->anim_frames == 3 &&
8457 g->anim_delay == 2 &&
8458 g->anim_mode & ANIM_LINEAR);
8459 int sync_frame = (i == Xdrip_stretch ? 7 :
8460 i == Xdrip_stretchB ? 7 :
8461 i == Ydrip_s2 ? j + 8 :
8462 i == Ydrip_s2B ? j + 8 :
8471 i == Xfake_acid_1 ? 0 :
8472 i == Xfake_acid_2 ? 10 :
8473 i == Xfake_acid_3 ? 20 :
8474 i == Xfake_acid_4 ? 30 :
8475 i == Xfake_acid_5 ? 40 :
8476 i == Xfake_acid_6 ? 50 :
8477 i == Xfake_acid_7 ? 60 :
8478 i == Xfake_acid_8 ? 70 :
8480 i == Xball_2B ? j + 8 :
8481 i == Yball_eat ? j + 1 :
8482 i == Ykey_1_eat ? j + 1 :
8483 i == Ykey_2_eat ? j + 1 :
8484 i == Ykey_3_eat ? j + 1 :
8485 i == Ykey_4_eat ? j + 1 :
8486 i == Ykey_5_eat ? j + 1 :
8487 i == Ykey_6_eat ? j + 1 :
8488 i == Ykey_7_eat ? j + 1 :
8489 i == Ykey_8_eat ? j + 1 :
8490 i == Ylenses_eat ? j + 1 :
8491 i == Ymagnify_eat ? j + 1 :
8492 i == Ygrass_eat ? j + 1 :
8493 i == Ydirt_eat ? j + 1 :
8494 i == Xamoeba_1 ? 0 :
8495 i == Xamoeba_2 ? 1 :
8496 i == Xamoeba_3 ? 2 :
8497 i == Xamoeba_4 ? 3 :
8498 i == Xamoeba_5 ? 0 :
8499 i == Xamoeba_6 ? 1 :
8500 i == Xamoeba_7 ? 2 :
8501 i == Xamoeba_8 ? 3 :
8502 i == Xexit_2 ? j + 8 :
8503 i == Xexit_3 ? j + 16 :
8504 i == Xdynamite_1 ? 0 :
8505 i == Xdynamite_2 ? 8 :
8506 i == Xdynamite_3 ? 16 :
8507 i == Xdynamite_4 ? 24 :
8508 i == Xsand_stonein_1 ? j + 1 :
8509 i == Xsand_stonein_2 ? j + 9 :
8510 i == Xsand_stonein_3 ? j + 17 :
8511 i == Xsand_stonein_4 ? j + 25 :
8512 i == Xsand_stoneout_1 && j == 0 ? 0 :
8513 i == Xsand_stoneout_1 && j == 1 ? 0 :
8514 i == Xsand_stoneout_1 && j == 2 ? 1 :
8515 i == Xsand_stoneout_1 && j == 3 ? 2 :
8516 i == Xsand_stoneout_1 && j == 4 ? 2 :
8517 i == Xsand_stoneout_1 && j == 5 ? 3 :
8518 i == Xsand_stoneout_1 && j == 6 ? 4 :
8519 i == Xsand_stoneout_1 && j == 7 ? 4 :
8520 i == Xsand_stoneout_2 && j == 0 ? 5 :
8521 i == Xsand_stoneout_2 && j == 1 ? 6 :
8522 i == Xsand_stoneout_2 && j == 2 ? 7 :
8523 i == Xsand_stoneout_2 && j == 3 ? 8 :
8524 i == Xsand_stoneout_2 && j == 4 ? 9 :
8525 i == Xsand_stoneout_2 && j == 5 ? 11 :
8526 i == Xsand_stoneout_2 && j == 6 ? 13 :
8527 i == Xsand_stoneout_2 && j == 7 ? 15 :
8528 i == Xboom_bug && j == 1 ? 2 :
8529 i == Xboom_bug && j == 2 ? 2 :
8530 i == Xboom_bug && j == 3 ? 4 :
8531 i == Xboom_bug && j == 4 ? 4 :
8532 i == Xboom_bug && j == 5 ? 2 :
8533 i == Xboom_bug && j == 6 ? 2 :
8534 i == Xboom_bug && j == 7 ? 0 :
8535 i == Xboom_bomb && j == 1 ? 2 :
8536 i == Xboom_bomb && j == 2 ? 2 :
8537 i == Xboom_bomb && j == 3 ? 4 :
8538 i == Xboom_bomb && j == 4 ? 4 :
8539 i == Xboom_bomb && j == 5 ? 2 :
8540 i == Xboom_bomb && j == 6 ? 2 :
8541 i == Xboom_bomb && j == 7 ? 0 :
8542 i == Xboom_android && j == 7 ? 6 :
8543 i == Xboom_1 && j == 1 ? 2 :
8544 i == Xboom_1 && j == 2 ? 2 :
8545 i == Xboom_1 && j == 3 ? 4 :
8546 i == Xboom_1 && j == 4 ? 4 :
8547 i == Xboom_1 && j == 5 ? 6 :
8548 i == Xboom_1 && j == 6 ? 6 :
8549 i == Xboom_1 && j == 7 ? 8 :
8550 i == Xboom_2 && j == 0 ? 8 :
8551 i == Xboom_2 && j == 1 ? 8 :
8552 i == Xboom_2 && j == 2 ? 10 :
8553 i == Xboom_2 && j == 3 ? 10 :
8554 i == Xboom_2 && j == 4 ? 10 :
8555 i == Xboom_2 && j == 5 ? 12 :
8556 i == Xboom_2 && j == 6 ? 12 :
8557 i == Xboom_2 && j == 7 ? 12 :
8558 special_animation && j == 4 ? 3 :
8559 effective_action != action ? 0 :
8563 Bitmap *debug_bitmap = g_em->bitmap;
8564 int debug_src_x = g_em->src_x;
8565 int debug_src_y = g_em->src_y;
8568 int frame = getAnimationFrame(g->anim_frames,
8571 g->anim_start_frame,
8574 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y,
8575 g->double_movement && is_backside);
8577 g_em->bitmap = src_bitmap;
8578 g_em->src_x = src_x;
8579 g_em->src_y = src_y;
8580 g_em->src_offset_x = 0;
8581 g_em->src_offset_y = 0;
8582 g_em->dst_offset_x = 0;
8583 g_em->dst_offset_y = 0;
8584 g_em->width = TILEX;
8585 g_em->height = TILEY;
8587 g_em->preserve_background = FALSE;
8590 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
8595 g_em->crumbled_bitmap = NULL;
8596 g_em->crumbled_src_x = 0;
8597 g_em->crumbled_src_y = 0;
8598 g_em->crumbled_border_size = 0;
8600 g_em->has_crumbled_graphics = FALSE;
8603 if (has_crumbled_graphics && crumbled == IMG_EMPTY_SPACE)
8604 printf("::: empty crumbled: %d [%s], %d, %d\n",
8605 effective_element, element_info[effective_element].token_name,
8606 effective_action, direction);
8609 /* if element can be crumbled, but certain action graphics are just empty
8610 space (like instantly snapping sand to empty space in 1 frame), do not
8611 treat these empty space graphics as crumbled graphics in EMC engine */
8612 if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
8614 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
8615 g_crumbled->anim_delay,
8616 g_crumbled->anim_mode,
8617 g_crumbled->anim_start_frame,
8620 getGraphicSource(crumbled, frame_crumbled, &src_bitmap, &src_x, &src_y);
8622 g_em->has_crumbled_graphics = TRUE;
8623 g_em->crumbled_bitmap = src_bitmap;
8624 g_em->crumbled_src_x = src_x;
8625 g_em->crumbled_src_y = src_y;
8626 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
8630 if (g_em == &graphic_info_em_object[207][0])
8631 printf("... %d, %d [%d, %d, %d, %d] [%d, %d, %d, %d, %d, %d => %d]\n",
8632 graphic_info_em_object[207][0].crumbled_src_x,
8633 graphic_info_em_object[207][0].crumbled_src_y,
8635 crumbled, frame, src_x, src_y,
8640 g->anim_start_frame,
8642 gfx.anim_random_frame,
8647 printf("::: EMC tile %d is crumbled\n", i);
8653 if (element == EL_ROCK &&
8654 effective_action == ACTION_FILLING)
8655 printf("::: has_action_graphics == %d\n", has_action_graphics);
8658 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
8659 effective_action == ACTION_MOVING ||
8660 effective_action == ACTION_PUSHING ||
8661 effective_action == ACTION_EATING)) ||
8662 (!has_action_graphics && (effective_action == ACTION_FILLING ||
8663 effective_action == ACTION_EMPTYING)))
8666 (effective_action == ACTION_FALLING ||
8667 effective_action == ACTION_FILLING ||
8668 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
8669 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
8670 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
8671 int num_steps = (i == Ydrip_s1 ? 16 :
8672 i == Ydrip_s1B ? 16 :
8673 i == Ydrip_s2 ? 16 :
8674 i == Ydrip_s2B ? 16 :
8675 i == Xsand_stonein_1 ? 32 :
8676 i == Xsand_stonein_2 ? 32 :
8677 i == Xsand_stonein_3 ? 32 :
8678 i == Xsand_stonein_4 ? 32 :
8679 i == Xsand_stoneout_1 ? 16 :
8680 i == Xsand_stoneout_2 ? 16 : 8);
8681 int cx = ABS(dx) * (TILEX / num_steps);
8682 int cy = ABS(dy) * (TILEY / num_steps);
8683 int step_frame = (i == Ydrip_s2 ? j + 8 :
8684 i == Ydrip_s2B ? j + 8 :
8685 i == Xsand_stonein_2 ? j + 8 :
8686 i == Xsand_stonein_3 ? j + 16 :
8687 i == Xsand_stonein_4 ? j + 24 :
8688 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
8689 int step = (is_backside ? step_frame : num_steps - step_frame);
8691 if (is_backside) /* tile where movement starts */
8693 if (dx < 0 || dy < 0)
8695 g_em->src_offset_x = cx * step;
8696 g_em->src_offset_y = cy * step;
8700 g_em->dst_offset_x = cx * step;
8701 g_em->dst_offset_y = cy * step;
8704 else /* tile where movement ends */
8706 if (dx < 0 || dy < 0)
8708 g_em->dst_offset_x = cx * step;
8709 g_em->dst_offset_y = cy * step;
8713 g_em->src_offset_x = cx * step;
8714 g_em->src_offset_y = cy * step;
8718 g_em->width = TILEX - cx * step;
8719 g_em->height = TILEY - cy * step;
8722 /* create unique graphic identifier to decide if tile must be redrawn */
8723 /* bit 31 - 16 (16 bit): EM style graphic
8724 bit 15 - 12 ( 4 bit): EM style frame
8725 bit 11 - 6 ( 6 bit): graphic width
8726 bit 5 - 0 ( 6 bit): graphic height */
8727 g_em->unique_identifier =
8728 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
8732 /* skip check for EMC elements not contained in original EMC artwork */
8733 if (element == EL_EMC_FAKE_ACID)
8736 if (g_em->bitmap != debug_bitmap ||
8737 g_em->src_x != debug_src_x ||
8738 g_em->src_y != debug_src_y ||
8739 g_em->src_offset_x != 0 ||
8740 g_em->src_offset_y != 0 ||
8741 g_em->dst_offset_x != 0 ||
8742 g_em->dst_offset_y != 0 ||
8743 g_em->width != TILEX ||
8744 g_em->height != TILEY)
8746 static int last_i = -1;
8754 printf("::: EMC GFX ERROR for element %d -> %d ('%s', '%s', %d)",
8755 i, element, element_info[element].token_name,
8756 element_action_info[effective_action].suffix, direction);
8758 if (element != effective_element)
8759 printf(" [%d ('%s')]",
8761 element_info[effective_element].token_name);
8765 if (g_em->bitmap != debug_bitmap)
8766 printf(" %d (%d): different bitmap! (0x%08x != 0x%08x)\n",
8767 j, is_backside, (int)(g_em->bitmap), (int)(debug_bitmap));
8769 if (g_em->src_x != debug_src_x ||
8770 g_em->src_y != debug_src_y)
8771 printf(" frame %d (%c): %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
8772 j, (is_backside ? 'B' : 'F'),
8773 g_em->src_x, g_em->src_y,
8774 g_em->src_x / 32, g_em->src_y / 32,
8775 debug_src_x, debug_src_y,
8776 debug_src_x / 32, debug_src_y / 32);
8778 if (g_em->src_offset_x != 0 ||
8779 g_em->src_offset_y != 0 ||
8780 g_em->dst_offset_x != 0 ||
8781 g_em->dst_offset_y != 0)
8782 printf(" %d (%d): offsets %d,%d and %d,%d should be all 0\n",
8784 g_em->src_offset_x, g_em->src_offset_y,
8785 g_em->dst_offset_x, g_em->dst_offset_y);
8787 if (g_em->width != TILEX ||
8788 g_em->height != TILEY)
8789 printf(" %d (%d): size %d,%d should be %d,%d\n",
8791 g_em->width, g_em->height, TILEX, TILEY);
8793 num_em_gfx_errors++;
8800 for (i = 0; i < TILE_MAX; i++)
8802 for (j = 0; j < 8; j++)
8804 int element = object_mapping[i].element_rnd;
8805 int action = object_mapping[i].action;
8806 int direction = object_mapping[i].direction;
8807 boolean is_backside = object_mapping[i].is_backside;
8808 int graphic_action = el_act_dir2img(element, action, direction);
8809 int graphic_default = el_act_dir2img(element, ACTION_DEFAULT, direction);
8811 if ((action == ACTION_SMASHED_BY_ROCK ||
8812 action == ACTION_SMASHED_BY_SPRING ||
8813 action == ACTION_EATING) &&
8814 graphic_action == graphic_default)
8816 int e = (action == ACTION_SMASHED_BY_ROCK ? Ystone_s :
8817 action == ACTION_SMASHED_BY_SPRING ? Yspring_s :
8818 direction == MV_LEFT ? (is_backside? Yspring_wB: Yspring_w) :
8819 direction == MV_RIGHT ? (is_backside? Yspring_eB: Yspring_e) :
8822 /* no separate animation for "smashed by rock" -- use rock instead */
8823 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
8824 struct GraphicInfo_EM *g_xx = &graphic_info_em_object[e][7 - j];
8826 g_em->bitmap = g_xx->bitmap;
8827 g_em->src_x = g_xx->src_x;
8828 g_em->src_y = g_xx->src_y;
8829 g_em->src_offset_x = g_xx->src_offset_x;
8830 g_em->src_offset_y = g_xx->src_offset_y;
8831 g_em->dst_offset_x = g_xx->dst_offset_x;
8832 g_em->dst_offset_y = g_xx->dst_offset_y;
8833 g_em->width = g_xx->width;
8834 g_em->height = g_xx->height;
8835 g_em->unique_identifier = g_xx->unique_identifier;
8838 g_em->preserve_background = TRUE;
8843 for (p = 0; p < MAX_PLAYERS; p++)
8845 for (i = 0; i < SPR_MAX; i++)
8847 int element = player_mapping[p][i].element_rnd;
8848 int action = player_mapping[p][i].action;
8849 int direction = player_mapping[p][i].direction;
8851 for (j = 0; j < 8; j++)
8853 int effective_element = element;
8854 int effective_action = action;
8855 int graphic = (direction == MV_NONE ?
8856 el_act2img(effective_element, effective_action) :
8857 el_act_dir2img(effective_element, effective_action,
8859 struct GraphicInfo *g = &graphic_info[graphic];
8860 struct GraphicInfo_EM *g_em = &graphic_info_em_player[p][i][7 - j];
8866 Bitmap *debug_bitmap = g_em->bitmap;
8867 int debug_src_x = g_em->src_x;
8868 int debug_src_y = g_em->src_y;
8871 int frame = getAnimationFrame(g->anim_frames,
8874 g->anim_start_frame,
8877 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
8879 g_em->bitmap = src_bitmap;
8880 g_em->src_x = src_x;
8881 g_em->src_y = src_y;
8882 g_em->src_offset_x = 0;
8883 g_em->src_offset_y = 0;
8884 g_em->dst_offset_x = 0;
8885 g_em->dst_offset_y = 0;
8886 g_em->width = TILEX;
8887 g_em->height = TILEY;
8891 /* skip check for EMC elements not contained in original EMC artwork */
8892 if (element == EL_PLAYER_3 ||
8893 element == EL_PLAYER_4)
8896 if (g_em->bitmap != debug_bitmap ||
8897 g_em->src_x != debug_src_x ||
8898 g_em->src_y != debug_src_y)
8900 static int last_i = -1;
8908 printf("::: EMC GFX ERROR for p/a %d/%d -> %d ('%s', '%s', %d)",
8909 p, i, element, element_info[element].token_name,
8910 element_action_info[effective_action].suffix, direction);
8912 if (element != effective_element)
8913 printf(" [%d ('%s')]",
8915 element_info[effective_element].token_name);
8919 if (g_em->bitmap != debug_bitmap)
8920 printf(" %d: different bitmap! (0x%08x != 0x%08x)\n",
8921 j, (int)(g_em->bitmap), (int)(debug_bitmap));
8923 if (g_em->src_x != debug_src_x ||
8924 g_em->src_y != debug_src_y)
8925 printf(" frame %d: %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
8927 g_em->src_x, g_em->src_y,
8928 g_em->src_x / 32, g_em->src_y / 32,
8929 debug_src_x, debug_src_y,
8930 debug_src_x / 32, debug_src_y / 32);
8932 num_em_gfx_errors++;
8942 printf("::: [%d errors found]\n", num_em_gfx_errors);
8948 void CheckSingleStepMode_EM(byte action[MAX_PLAYERS], int frame,
8949 boolean any_player_moving,
8950 boolean player_is_dropping)
8952 if (tape.single_step && tape.recording && !tape.pausing)
8955 boolean active_players = FALSE;
8958 for (i = 0; i < MAX_PLAYERS; i++)
8959 if (action[i] != JOY_NO_ACTION)
8960 active_players = TRUE;
8964 if (frame == 0 && !player_is_dropping)
8965 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
8969 void CheckSingleStepMode_SP(boolean murphy_is_waiting,
8970 boolean murphy_is_dropping)
8973 printf("::: waiting: %d, dropping: %d\n",
8974 murphy_is_waiting, murphy_is_dropping);
8977 if (tape.single_step && tape.recording && !tape.pausing)
8979 // if (murphy_is_waiting || murphy_is_dropping)
8980 if (murphy_is_waiting)
8983 printf("::: murphy is waiting -> pause mode\n");
8986 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
8991 void getGraphicSource_SP(struct GraphicInfo_SP *g_sp,
8992 int graphic, int sync_frame, int x, int y)
8994 int frame = getGraphicAnimationFrame(graphic, sync_frame);
8996 getGraphicSource(graphic, frame, &g_sp->bitmap, &g_sp->src_x, &g_sp->src_y);
8999 boolean isNextAnimationFrame_SP(int graphic, int sync_frame)
9001 return (IS_NEXT_FRAME(sync_frame, graphic));
9004 int getGraphicInfo_Delay(int graphic)
9006 return graphic_info[graphic].anim_delay;
9009 void PlayMenuSoundExt(int sound)
9011 if (sound == SND_UNDEFINED)
9014 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
9015 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
9018 if (IS_LOOP_SOUND(sound))
9019 PlaySoundLoop(sound);
9024 void PlayMenuSound()
9026 PlayMenuSoundExt(menu.sound[game_status]);
9029 void PlayMenuSoundStereo(int sound, int stereo_position)
9031 if (sound == SND_UNDEFINED)
9034 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
9035 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
9038 if (IS_LOOP_SOUND(sound))
9039 PlaySoundExt(sound, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_LOOP);
9041 PlaySoundStereo(sound, stereo_position);
9044 void PlayMenuSoundIfLoopExt(int sound)
9046 if (sound == SND_UNDEFINED)
9049 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
9050 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
9053 if (IS_LOOP_SOUND(sound))
9054 PlaySoundLoop(sound);
9057 void PlayMenuSoundIfLoop()
9059 PlayMenuSoundIfLoopExt(menu.sound[game_status]);
9062 void PlayMenuMusicExt(int music)
9064 if (music == MUS_UNDEFINED)
9067 if (!setup.sound_music)
9073 void PlayMenuMusic()
9075 PlayMenuMusicExt(menu.music[game_status]);
9078 void PlaySoundActivating()
9081 PlaySound(SND_MENU_ITEM_ACTIVATING);
9085 void PlaySoundSelecting()
9088 PlaySound(SND_MENU_ITEM_SELECTING);
9092 void ToggleFullscreenIfNeeded()
9094 boolean change_fullscreen = (setup.fullscreen !=
9095 video.fullscreen_enabled);
9096 boolean change_fullscreen_mode = (video.fullscreen_enabled &&
9097 !strEqual(setup.fullscreen_mode,
9098 video.fullscreen_mode_current));
9099 boolean change_window_scaling_percent = (!video.fullscreen_enabled &&
9100 setup.window_scaling_percent !=
9101 video.window_scaling_percent);
9103 if (change_window_scaling_percent && video.fullscreen_enabled)
9106 if (!change_window_scaling_percent && !video.fullscreen_available)
9109 #if defined(TARGET_SDL2)
9110 if (change_window_scaling_percent)
9112 SDLSetWindowScaling(setup.window_scaling_percent);
9116 else if (change_fullscreen)
9118 SDLSetWindowFullscreen(setup.fullscreen);
9120 /* set setup value according to successfully changed fullscreen mode */
9121 setup.fullscreen = video.fullscreen_enabled;
9127 if (change_fullscreen ||
9128 change_fullscreen_mode ||
9129 change_window_scaling_percent)
9131 Bitmap *tmp_backbuffer = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
9133 /* save backbuffer content which gets lost when toggling fullscreen mode */
9134 BlitBitmap(backbuffer, tmp_backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
9136 if (change_fullscreen_mode)
9138 /* keep fullscreen, but change fullscreen mode (screen resolution) */
9139 video.fullscreen_enabled = FALSE; /* force new fullscreen mode */
9142 if (change_window_scaling_percent)
9144 /* keep window mode, but change window scaling */
9145 video.fullscreen_enabled = TRUE; /* force new window scaling */
9148 /* toggle fullscreen */
9149 ChangeVideoModeIfNeeded(setup.fullscreen);
9151 /* set setup value according to successfully changed fullscreen mode */
9152 setup.fullscreen = video.fullscreen_enabled;
9154 /* restore backbuffer content from temporary backbuffer backup bitmap */
9155 BlitBitmap(tmp_backbuffer, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
9157 FreeBitmap(tmp_backbuffer);
9160 /* update visible window/screen */
9161 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
9163 redraw_mask = REDRAW_ALL;
9168 void ChangeViewportPropertiesIfNeeded()
9170 int *door_1_x = &DX;
9171 int *door_1_y = &DY;
9172 int *door_2_x = (game_status == GAME_MODE_EDITOR ? &EX : &VX);
9173 int *door_2_y = (game_status == GAME_MODE_EDITOR ? &EY : &VY);
9174 int gfx_game_mode = (game_status == GAME_MODE_PLAYING ||
9175 game_status == GAME_MODE_EDITOR ? game_status :
9177 struct RectWithBorder *vp_playfield = &viewport.playfield[gfx_game_mode];
9178 struct RectWithBorder *vp_door_1 = &viewport.door_1[gfx_game_mode];
9179 struct RectWithBorder *vp_door_2 = &viewport.door_2[gfx_game_mode];
9180 int border_size = vp_playfield->border_size;
9181 int new_sx = vp_playfield->x + border_size;
9182 int new_sy = vp_playfield->y + border_size;
9183 int new_sxsize = vp_playfield->width - 2 * border_size;
9184 int new_sysize = vp_playfield->height - 2 * border_size;
9185 int new_real_sx = vp_playfield->x;
9186 int new_real_sy = vp_playfield->y;
9187 int new_full_sxsize = vp_playfield->width;
9188 int new_full_sysize = vp_playfield->height;
9190 int new_tilesize_var = TILESIZE / (setup.small_game_graphics ? 2 : 1);
9191 int tilesize = (gfx_game_mode == GAME_MODE_PLAYING ? new_tilesize_var :
9192 gfx_game_mode == GAME_MODE_EDITOR ? MINI_TILESIZE : TILESIZE);
9193 int new_scr_fieldx = new_sxsize / tilesize;
9194 int new_scr_fieldy = new_sysize / tilesize;
9195 int new_scr_fieldx_buffers = new_sxsize / new_tilesize_var;
9196 int new_scr_fieldy_buffers = new_sysize / new_tilesize_var;
9198 int new_scr_fieldx = (vp_playfield->width - 2 * border_size) / TILESIZE;
9199 int new_scr_fieldy = (vp_playfield->height - 2 * border_size) / TILESIZE;
9201 boolean init_gfx_buffers = FALSE;
9202 boolean init_video_buffer = FALSE;
9203 boolean init_gadgets_and_toons = FALSE;
9206 /* !!! TEST ONLY !!! */
9207 // InitGfxBuffers();
9211 if (viewport.window.width != WIN_XSIZE ||
9212 viewport.window.height != WIN_YSIZE)
9214 WIN_XSIZE = viewport.window.width;
9215 WIN_YSIZE = viewport.window.height;
9218 init_video_buffer = TRUE;
9219 init_gfx_buffers = TRUE;
9221 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
9225 SetDrawDeactivationMask(REDRAW_NONE);
9226 SetDrawBackgroundMask(REDRAW_FIELD);
9228 // RedrawBackground();
9232 // printf("::: video: init_video_buffer, init_gfx_buffers\n");
9235 if (new_scr_fieldx != SCR_FIELDX ||
9236 new_scr_fieldy != SCR_FIELDY)
9238 /* this always toggles between MAIN and GAME when using small tile size */
9240 SCR_FIELDX = new_scr_fieldx;
9241 SCR_FIELDY = new_scr_fieldy;
9243 // printf("::: new_scr_fieldx != SCR_FIELDX ...\n");
9247 if (new_tilesize_var != TILESIZE_VAR &&
9248 gfx_game_mode == GAME_MODE_PLAYING)
9250 /* doing this outside GAME_MODE_PLAYING would give wrong playfield size */
9252 TILESIZE_VAR = new_tilesize_var;
9254 init_gfx_buffers = TRUE;
9256 // printf("::: tilesize: init_gfx_buffers\n");
9262 new_sxsize != SXSIZE ||
9263 new_sysize != SYSIZE ||
9264 new_real_sx != REAL_SX ||
9265 new_real_sy != REAL_SY ||
9266 new_full_sxsize != FULL_SXSIZE ||
9267 new_full_sysize != FULL_SYSIZE ||
9268 new_tilesize_var != TILESIZE_VAR ||
9269 vp_door_1->x != *door_1_x ||
9270 vp_door_1->y != *door_1_y ||
9271 vp_door_2->x != *door_2_x ||
9272 vp_door_2->y != *door_2_y)
9276 SXSIZE = new_sxsize;
9277 SYSIZE = new_sysize;
9278 REAL_SX = new_real_sx;
9279 REAL_SY = new_real_sy;
9280 FULL_SXSIZE = new_full_sxsize;
9281 FULL_SYSIZE = new_full_sysize;
9282 TILESIZE_VAR = new_tilesize_var;
9285 printf("::: %d, %d, %d [%d]\n",
9286 SCR_FIELDX, SCR_FIELDY, TILESIZE_VAR,
9287 setup.small_game_graphics);
9290 *door_1_x = vp_door_1->x;
9291 *door_1_y = vp_door_1->y;
9292 *door_2_x = vp_door_2->x;
9293 *door_2_y = vp_door_2->y;
9296 init_gfx_buffers = TRUE;
9298 // printf("::: viewports: init_gfx_buffers\n");
9303 if (gfx_game_mode == GAME_MODE_MAIN)
9306 init_gadgets_and_toons = TRUE;
9308 // printf("::: viewports: init_gadgets_and_toons\n");
9316 if (init_gfx_buffers)
9318 // printf("::: init_gfx_buffers\n");
9320 SCR_FIELDX = new_scr_fieldx_buffers;
9321 SCR_FIELDY = new_scr_fieldy_buffers;
9325 SCR_FIELDX = new_scr_fieldx;
9326 SCR_FIELDY = new_scr_fieldy;
9329 if (init_video_buffer)
9331 // printf("::: init_video_buffer\n");
9333 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
9335 SetDrawDeactivationMask(REDRAW_NONE);
9336 SetDrawBackgroundMask(REDRAW_FIELD);
9339 if (init_gadgets_and_toons)
9341 // printf("::: init_gadgets_and_toons\n");
9348 printf("::: %d, %d / %d, %d [%d]\n", VX, VY, EX, EY, game_status);