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);
2544 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
2546 SetDrawtoField(DRAW_BACKBUFFER);
2548 for (yy = 0; yy < ysize; yy++) for (xx = 0; xx < xsize; xx++)
2549 DrawEnvelopeBackground(envelope_nr, sx,sy, xx,yy, xsize, ysize, font_nr);
2552 DrawTextBuffer(SX + sx + font_width, SY + sy + font_height,
2553 level.envelope[envelope_nr].text, font_nr, max_xsize,
2554 xsize - 2, ysize - 2, 0, mask_mode,
2555 level.envelope[envelope_nr].autowrap,
2556 level.envelope[envelope_nr].centered, FALSE);
2558 DrawTextToTextArea(SX + sx + font_width, SY + sy + font_height,
2559 level.envelope[envelope_nr].text, font_nr, max_xsize,
2560 xsize - 2, ysize - 2, mask_mode);
2563 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
2566 WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
2570 void AnimateEnvelopeDoor(char *text, int anim_mode, int action)
2573 int envelope_nr = 0;
2575 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2576 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
2577 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
2578 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2579 boolean no_delay = (tape.warp_forward);
2580 unsigned int anim_delay = 0;
2581 int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
2582 int anim_delay_value = (no_delay ? 0 : frame_delay_value);
2584 int max_word_len = maxWordLengthInString(text);
2585 int font_nr = (max_word_len > 7 ? FONT_TEXT_1 : FONT_TEXT_2);
2587 int font_nr = FONT_ENVELOPE_1 + envelope_nr;
2589 int font_width = getFontWidth(font_nr);
2590 int font_height = getFontHeight(font_nr);
2594 int max_xsize = DXSIZE / font_width;
2595 int max_ysize = DYSIZE / font_height;
2597 int max_xsize = 7; /* tools.c: MAX_REQUEST_LINE_FONT1_LEN == 7 */
2598 int max_ysize = 13; /* tools.c: MAX_REQUEST_LINES == 13 */
2602 int max_xsize = level.envelope[envelope_nr].xsize;
2603 int max_ysize = level.envelope[envelope_nr].ysize;
2605 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
2606 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
2607 int xend = max_xsize;
2608 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
2609 int xstep = (xstart < xend ? 1 : 0);
2610 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
2615 char *text_copy = getStringCopy(text);
2618 font_nr = FONT_TEXT_2;
2620 if (maxWordLengthInString(text) > 7) /* MAX_REQUEST_LINE_FONT1_LEN == 7 */
2622 max_xsize = 10; /* tools.c: MAX_REQUEST_LINE_FONT2_LEN == 10 */
2623 font_nr = FONT_TEXT_1;
2626 int max_word_len = 0;
2628 char *text_copy = getStringCopy(text);
2630 font_nr = FONT_TEXT_2;
2632 for (text_ptr = text; *text_ptr; text_ptr++)
2634 max_word_len = (*text_ptr != ' ' ? max_word_len + 1 : 0);
2636 if (max_word_len > 7) /* tools.c: MAX_REQUEST_LINE_FONT1_LEN == 7 */
2638 max_xsize = 10; /* tools.c: MAX_REQUEST_LINE_FONT2_LEN == 10 */
2639 font_nr = FONT_TEXT_1;
2648 for (text_ptr = text_copy; *text_ptr; text_ptr++)
2649 if (*text_ptr == ' ')
2654 dDX = SX + (SXSIZE - DXSIZE) / 2 - DX;
2655 dDY = SY + (SYSIZE - DYSIZE) / 2 - DY;
2657 dDX = SX + SXSIZE / 2 - max_xsize * font_width / 2 - DX;
2658 dDY = SY + SYSIZE / 2 - max_ysize * font_height / 2 - DY;
2661 for (x = xstart, y = ystart; x <= xend && y <= yend; x += xstep, y += ystep)
2663 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
2664 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
2665 int sx = (SXSIZE - xsize * font_width) / 2;
2666 int sy = (SYSIZE - ysize * font_height) / 2;
2670 BlitBitmap(bitmap_db_store, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2672 SetDrawtoField(DRAW_BUFFERED);
2674 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
2676 SetDrawtoField(DRAW_BACKBUFFER);
2679 for (yy = 0; yy < ysize; yy++) for (xx = 0; xx < xsize; xx++)
2680 DrawEnvelopeBackground(envelope_nr, sx,sy, xx,yy, xsize, ysize, font_nr);
2685 DrawTextBuffer(SX + sx + font_width, SY + sy + font_height + 8,
2686 text_copy, font_nr, max_xsize,
2687 xsize - 2, ysize - 2, 2, mask_mode,
2688 FALSE, TRUE, FALSE);
2690 DrawTextBuffer(SX + sx + font_width, SY + sy + font_height,
2691 level.envelope[envelope_nr].text, font_nr, max_xsize,
2692 xsize - 2, ysize - 2, 0, mask_mode,
2693 level.envelope[envelope_nr].autowrap,
2694 level.envelope[envelope_nr].centered, FALSE);
2698 DrawTextToTextArea(SX + sx + font_width, SY + sy + font_height,
2699 level.envelope[envelope_nr].text, font_nr, max_xsize,
2700 xsize - 2, ysize - 2, mask_mode);
2703 /* copy request gadgets to door backbuffer */
2705 if ((ysize - 2) > 13)
2706 BlitBitmap(bitmap_db_door, drawto,
2707 DOOR_GFX_PAGEX1 + (DXSIZE - (xsize - 2) * font_width) / 2,
2708 DOOR_GFX_PAGEY1 + 13 * font_height,
2709 (xsize - 2) * font_width,
2710 (ysize - 2 - 13) * font_height,
2711 SX + sx + font_width,
2712 SY + sy + font_height * (1 + 13));
2714 if ((ysize - 2) > 13)
2715 BlitBitmap(bitmap_db_door, drawto,
2716 DOOR_GFX_PAGEX1 + (DXSIZE - (xsize - 2) * font_width) / 2,
2717 DOOR_GFX_PAGEY1 + 13 * font_height,
2718 (xsize - 2) * font_width,
2719 (ysize - 2 - 13) * font_height,
2720 SX + sx + font_width,
2721 SY + sy + font_height * (1 + 13));
2725 redraw_mask = REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
2726 // redraw_mask |= REDRAW_ALL | REDRAW_FROM_BACKBUFFER;
2728 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
2738 WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
2746 void ShowEnvelope(int envelope_nr)
2748 int element = EL_ENVELOPE_1 + envelope_nr;
2749 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2750 int sound_opening = element_info[element].sound[ACTION_OPENING];
2751 int sound_closing = element_info[element].sound[ACTION_CLOSING];
2752 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2753 boolean no_delay = (tape.warp_forward);
2754 int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
2755 int wait_delay_value = (no_delay ? 0 : normal_delay_value);
2756 int anim_mode = graphic_info[graphic].anim_mode;
2757 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
2758 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
2760 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
2762 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
2764 if (anim_mode == ANIM_DEFAULT)
2765 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_OPENING);
2767 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_OPENING);
2770 Delay(wait_delay_value);
2772 WaitForEventToContinue();
2774 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
2776 if (anim_mode != ANIM_NONE)
2777 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_CLOSING);
2779 if (anim_mode == ANIM_DEFAULT)
2780 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_CLOSING);
2782 game.envelope_active = FALSE;
2784 SetDrawtoField(DRAW_BUFFERED);
2786 redraw_mask |= REDRAW_FIELD;
2790 void ShowEnvelopeDoor(char *text, int action)
2793 int last_game_status = game_status; /* save current game status */
2794 // int last_draw_background_mask = gfx.draw_background_mask;
2795 int envelope_nr = 0;
2797 int element = EL_ENVELOPE_1 + envelope_nr;
2798 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2799 int sound_opening = element_info[element].sound[ACTION_OPENING];
2800 int sound_closing = element_info[element].sound[ACTION_CLOSING];
2802 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2803 boolean no_delay = (tape.warp_forward);
2804 int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
2805 int wait_delay_value = (no_delay ? 0 : normal_delay_value);
2807 int anim_mode = graphic_info[graphic].anim_mode;
2808 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
2809 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
2812 if (game_status == GAME_MODE_PLAYING)
2814 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
2815 BlitScreenToBitmap_EM(backbuffer);
2816 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
2817 BlitScreenToBitmap_SP(backbuffer);
2820 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
2824 SetDrawtoField(DRAW_BACKBUFFER);
2826 // SetDrawBackgroundMask(REDRAW_NONE);
2828 if (action == ACTION_OPENING)
2830 BlitBitmap(backbuffer, bitmap_db_store, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2832 if (game_status != GAME_MODE_MAIN)
2836 /* force DOOR font inside door area */
2837 game_status = GAME_MODE_PSEUDO_DOOR;
2840 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
2842 if (action == ACTION_OPENING)
2844 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
2846 if (anim_mode == ANIM_DEFAULT)
2847 AnimateEnvelopeDoor(text, ANIM_DEFAULT, ACTION_OPENING);
2849 AnimateEnvelopeDoor(text, main_anim_mode, ACTION_OPENING);
2853 Delay(wait_delay_value);
2855 WaitForEventToContinue();
2860 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
2862 if (anim_mode != ANIM_NONE)
2863 AnimateEnvelopeDoor(text, main_anim_mode, ACTION_CLOSING);
2865 if (anim_mode == ANIM_DEFAULT)
2866 AnimateEnvelopeDoor(text, ANIM_DEFAULT, ACTION_CLOSING);
2869 game.envelope_active = FALSE;
2872 // game_status = last_game_status; /* restore current game status */
2874 if (action == ACTION_CLOSING)
2876 if (game_status != GAME_MODE_MAIN)
2879 BlitBitmap(bitmap_db_store, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2882 SetDrawtoField(DRAW_BUFFERED);
2885 // SetDrawBackgroundMask(last_draw_background_mask);
2888 redraw_mask = REDRAW_FIELD;
2889 // redraw_mask |= REDRAW_ALL;
2891 redraw_mask |= REDRAW_FIELD;
2895 if (game_status == GAME_MODE_MAIN)
2900 /* (important: after "BackToFront()", but before "SetDrawtoField()") */
2901 game_status = last_game_status; /* restore current game status */
2903 if (game_status == GAME_MODE_PLAYING &&
2904 level.game_engine_type == GAME_ENGINE_TYPE_RND)
2905 SetDrawtoField(DRAW_BUFFERED);
2911 void DrawPreviewElement(int dst_x, int dst_y, int element, int tilesize)
2915 int graphic = el2preimg(element);
2917 getSizedGraphicSource(graphic, 0, tilesize, &src_bitmap, &src_x, &src_y);
2918 BlitBitmap(src_bitmap, drawto, src_x, src_y, tilesize, tilesize, dst_x,dst_y);
2926 SetMainBackgroundImage(IMG_BACKGROUND_PLAYING);
2927 SetDrawBackgroundMask(REDRAW_FIELD);
2929 SetDrawBackgroundMask(REDRAW_NONE);
2934 for (x = BX1; x <= BX2; x++)
2935 for (y = BY1; y <= BY2; y++)
2936 DrawScreenField(x, y);
2938 redraw_mask |= REDRAW_FIELD;
2941 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
2945 for (x = 0; x < size_x; x++)
2946 for (y = 0; y < size_y; y++)
2947 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
2949 redraw_mask |= REDRAW_FIELD;
2952 static void DrawPreviewLevelExt(int from_x, int from_y)
2954 boolean show_level_border = (BorderElement != EL_EMPTY);
2955 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
2956 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
2957 int tile_size = preview.tile_size;
2958 int preview_width = preview.xsize * tile_size;
2959 int preview_height = preview.ysize * tile_size;
2960 int real_preview_xsize = MIN(level_xsize, preview.xsize);
2961 int real_preview_ysize = MIN(level_ysize, preview.ysize);
2962 int dst_x = SX + ALIGNED_XPOS(preview.x, preview_width, preview.align);
2963 int dst_y = SY + ALIGNED_YPOS(preview.y, preview_height, preview.valign);
2966 DrawBackground(dst_x, dst_y, preview_width, preview_height);
2968 dst_x += (preview_width - real_preview_xsize * tile_size) / 2;
2969 dst_y += (preview_height - real_preview_ysize * tile_size) / 2;
2971 for (x = 0; x < real_preview_xsize; x++)
2973 for (y = 0; y < real_preview_ysize; y++)
2975 int lx = from_x + x + (show_level_border ? -1 : 0);
2976 int ly = from_y + y + (show_level_border ? -1 : 0);
2977 int element = (IN_LEV_FIELD(lx, ly) ? level.field[lx][ly] :
2978 getBorderElement(lx, ly));
2980 DrawPreviewElement(dst_x + x * tile_size, dst_y + y * tile_size,
2981 element, tile_size);
2985 redraw_mask |= REDRAW_MICROLEVEL;
2988 #define MICROLABEL_EMPTY 0
2989 #define MICROLABEL_LEVEL_NAME 1
2990 #define MICROLABEL_LEVEL_AUTHOR_HEAD 2
2991 #define MICROLABEL_LEVEL_AUTHOR 3
2992 #define MICROLABEL_IMPORTED_FROM_HEAD 4
2993 #define MICROLABEL_IMPORTED_FROM 5
2994 #define MICROLABEL_IMPORTED_BY_HEAD 6
2995 #define MICROLABEL_IMPORTED_BY 7
2997 static int getMaxTextLength(struct TextPosInfo *pos, int font_nr)
2999 int max_text_width = SXSIZE;
3000 int font_width = getFontWidth(font_nr);
3002 if (pos->align == ALIGN_CENTER)
3003 max_text_width = (pos->x < SXSIZE / 2 ? pos->x * 2 : (SXSIZE - pos->x) * 2);
3004 else if (pos->align == ALIGN_RIGHT)
3005 max_text_width = pos->x;
3007 max_text_width = SXSIZE - pos->x;
3009 return max_text_width / font_width;
3012 static void DrawPreviewLevelLabelExt(int mode)
3014 struct TextPosInfo *pos = &menu.main.text.level_info_2;
3015 char label_text[MAX_OUTPUT_LINESIZE + 1];
3016 int max_len_label_text;
3018 int font_nr = pos->font;
3021 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
3022 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
3023 mode == MICROLABEL_IMPORTED_BY_HEAD)
3024 font_nr = pos->font_alt;
3026 int font_nr = FONT_TEXT_2;
3029 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
3030 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
3031 mode == MICROLABEL_IMPORTED_BY_HEAD)
3032 font_nr = FONT_TEXT_3;
3036 max_len_label_text = getMaxTextLength(pos, font_nr);
3038 max_len_label_text = SXSIZE / getFontWidth(font_nr);
3042 if (pos->size != -1)
3043 max_len_label_text = pos->size;
3046 for (i = 0; i < max_len_label_text; i++)
3047 label_text[i] = ' ';
3048 label_text[max_len_label_text] = '\0';
3050 if (strlen(label_text) > 0)
3053 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
3055 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
3056 int lypos = MICROLABEL2_YPOS;
3058 DrawText(lxpos, lypos, label_text, font_nr);
3063 (mode == MICROLABEL_LEVEL_NAME ? level.name :
3064 mode == MICROLABEL_LEVEL_AUTHOR_HEAD ? "created by" :
3065 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
3066 mode == MICROLABEL_IMPORTED_FROM_HEAD ? "imported from" :
3067 mode == MICROLABEL_IMPORTED_FROM ? leveldir_current->imported_from :
3068 mode == MICROLABEL_IMPORTED_BY_HEAD ? "imported by" :
3069 mode == MICROLABEL_IMPORTED_BY ? leveldir_current->imported_by :""),
3070 max_len_label_text);
3071 label_text[max_len_label_text] = '\0';
3073 if (strlen(label_text) > 0)
3076 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
3078 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
3079 int lypos = MICROLABEL2_YPOS;
3081 DrawText(lxpos, lypos, label_text, font_nr);
3085 redraw_mask |= REDRAW_MICROLEVEL;
3088 void DrawPreviewLevel(boolean restart)
3090 static unsigned int scroll_delay = 0;
3091 static unsigned int label_delay = 0;
3092 static int from_x, from_y, scroll_direction;
3093 static int label_state, label_counter;
3094 unsigned int scroll_delay_value = preview.step_delay;
3095 boolean show_level_border = (BorderElement != EL_EMPTY);
3096 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
3097 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
3098 int last_game_status = game_status; /* save current game status */
3101 /* force PREVIEW font on preview level */
3102 game_status = GAME_MODE_PSEUDO_PREVIEW;
3110 if (preview.anim_mode == ANIM_CENTERED)
3112 if (level_xsize > preview.xsize)
3113 from_x = (level_xsize - preview.xsize) / 2;
3114 if (level_ysize > preview.ysize)
3115 from_y = (level_ysize - preview.ysize) / 2;
3118 from_x += preview.xoffset;
3119 from_y += preview.yoffset;
3121 scroll_direction = MV_RIGHT;
3125 DrawPreviewLevelExt(from_x, from_y);
3126 DrawPreviewLevelLabelExt(label_state);
3128 /* initialize delay counters */
3129 DelayReached(&scroll_delay, 0);
3130 DelayReached(&label_delay, 0);
3132 if (leveldir_current->name)
3134 struct TextPosInfo *pos = &menu.main.text.level_info_1;
3135 char label_text[MAX_OUTPUT_LINESIZE + 1];
3137 int font_nr = pos->font;
3139 int font_nr = FONT_TEXT_1;
3142 int max_len_label_text = getMaxTextLength(pos, font_nr);
3144 int max_len_label_text = SXSIZE / getFontWidth(font_nr);
3152 if (pos->size != -1)
3153 max_len_label_text = pos->size;
3156 strncpy(label_text, leveldir_current->name, max_len_label_text);
3157 label_text[max_len_label_text] = '\0';
3160 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
3162 lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
3163 lypos = SY + MICROLABEL1_YPOS;
3165 DrawText(lxpos, lypos, label_text, font_nr);
3169 game_status = last_game_status; /* restore current game status */
3174 /* scroll preview level, if needed */
3175 if (preview.anim_mode != ANIM_NONE &&
3176 (level_xsize > preview.xsize || level_ysize > preview.ysize) &&
3177 DelayReached(&scroll_delay, scroll_delay_value))
3179 switch (scroll_direction)
3184 from_x -= preview.step_offset;
3185 from_x = (from_x < 0 ? 0 : from_x);
3188 scroll_direction = MV_UP;
3192 if (from_x < level_xsize - preview.xsize)
3194 from_x += preview.step_offset;
3195 from_x = (from_x > level_xsize - preview.xsize ?
3196 level_xsize - preview.xsize : from_x);
3199 scroll_direction = MV_DOWN;
3205 from_y -= preview.step_offset;
3206 from_y = (from_y < 0 ? 0 : from_y);
3209 scroll_direction = MV_RIGHT;
3213 if (from_y < level_ysize - preview.ysize)
3215 from_y += preview.step_offset;
3216 from_y = (from_y > level_ysize - preview.ysize ?
3217 level_ysize - preview.ysize : from_y);
3220 scroll_direction = MV_LEFT;
3227 DrawPreviewLevelExt(from_x, from_y);
3230 /* !!! THIS ALL SUCKS -- SHOULD BE CLEANLY REWRITTEN !!! */
3231 /* redraw micro level label, if needed */
3232 if (!strEqual(level.name, NAMELESS_LEVEL_NAME) &&
3233 !strEqual(level.author, ANONYMOUS_NAME) &&
3234 !strEqual(level.author, leveldir_current->name) &&
3235 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
3237 int max_label_counter = 23;
3239 if (leveldir_current->imported_from != NULL &&
3240 strlen(leveldir_current->imported_from) > 0)
3241 max_label_counter += 14;
3242 if (leveldir_current->imported_by != NULL &&
3243 strlen(leveldir_current->imported_by) > 0)
3244 max_label_counter += 14;
3246 label_counter = (label_counter + 1) % max_label_counter;
3247 label_state = (label_counter >= 0 && label_counter <= 7 ?
3248 MICROLABEL_LEVEL_NAME :
3249 label_counter >= 9 && label_counter <= 12 ?
3250 MICROLABEL_LEVEL_AUTHOR_HEAD :
3251 label_counter >= 14 && label_counter <= 21 ?
3252 MICROLABEL_LEVEL_AUTHOR :
3253 label_counter >= 23 && label_counter <= 26 ?
3254 MICROLABEL_IMPORTED_FROM_HEAD :
3255 label_counter >= 28 && label_counter <= 35 ?
3256 MICROLABEL_IMPORTED_FROM :
3257 label_counter >= 37 && label_counter <= 40 ?
3258 MICROLABEL_IMPORTED_BY_HEAD :
3259 label_counter >= 42 && label_counter <= 49 ?
3260 MICROLABEL_IMPORTED_BY : MICROLABEL_EMPTY);
3262 if (leveldir_current->imported_from == NULL &&
3263 (label_state == MICROLABEL_IMPORTED_FROM_HEAD ||
3264 label_state == MICROLABEL_IMPORTED_FROM))
3265 label_state = (label_state == MICROLABEL_IMPORTED_FROM_HEAD ?
3266 MICROLABEL_IMPORTED_BY_HEAD : MICROLABEL_IMPORTED_BY);
3268 DrawPreviewLevelLabelExt(label_state);
3271 game_status = last_game_status; /* restore current game status */
3274 inline void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
3275 int graphic, int sync_frame, int mask_mode)
3277 int frame = getGraphicAnimationFrame(graphic, sync_frame);
3279 if (mask_mode == USE_MASKING)
3280 DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
3282 DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
3285 inline void DrawFixedGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
3286 int graphic, int sync_frame,
3289 int frame = getGraphicAnimationFrame(graphic, sync_frame);
3291 if (mask_mode == USE_MASKING)
3292 DrawFixedGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
3294 DrawFixedGraphicExt(dst_bitmap, x, y, graphic, frame);
3297 inline void DrawGraphicAnimation(int x, int y, int graphic)
3299 int lx = LEVELX(x), ly = LEVELY(y);
3301 if (!IN_SCR_FIELD(x, y))
3305 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR,
3306 graphic, GfxFrame[lx][ly], NO_MASKING);
3308 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
3309 graphic, GfxFrame[lx][ly], NO_MASKING);
3311 MarkTileDirty(x, y);
3314 inline void DrawFixedGraphicAnimation(int x, int y, int graphic)
3316 int lx = LEVELX(x), ly = LEVELY(y);
3318 if (!IN_SCR_FIELD(x, y))
3321 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
3322 graphic, GfxFrame[lx][ly], NO_MASKING);
3323 MarkTileDirty(x, y);
3326 void DrawLevelGraphicAnimation(int x, int y, int graphic)
3328 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
3331 void DrawLevelElementAnimation(int x, int y, int element)
3333 int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
3335 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
3338 inline void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
3340 int sx = SCREENX(x), sy = SCREENY(y);
3342 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
3345 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
3348 DrawGraphicAnimation(sx, sy, graphic);
3351 if (GFX_CRUMBLED(TILE_GFX_ELEMENT(x, y)))
3352 DrawLevelFieldCrumbled(x, y);
3354 if (GFX_CRUMBLED(Feld[x][y]))
3355 DrawLevelFieldCrumbled(x, y);
3359 void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
3361 int sx = SCREENX(x), sy = SCREENY(y);
3364 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
3367 graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
3369 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
3372 DrawGraphicAnimation(sx, sy, graphic);
3374 if (GFX_CRUMBLED(element))
3375 DrawLevelFieldCrumbled(x, y);
3378 static int getPlayerGraphic(struct PlayerInfo *player, int move_dir)
3380 if (player->use_murphy)
3382 /* this works only because currently only one player can be "murphy" ... */
3383 static int last_horizontal_dir = MV_LEFT;
3384 int graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir);
3386 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3387 last_horizontal_dir = move_dir;
3389 if (graphic == IMG_SP_MURPHY) /* undefined => use special graphic */
3391 int direction = (player->is_snapping ? move_dir : last_horizontal_dir);
3393 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
3399 return el_act_dir2img(player->artwork_element, player->GfxAction,move_dir);
3402 static boolean equalGraphics(int graphic1, int graphic2)
3404 struct GraphicInfo *g1 = &graphic_info[graphic1];
3405 struct GraphicInfo *g2 = &graphic_info[graphic2];
3407 return (g1->bitmap == g2->bitmap &&
3408 g1->src_x == g2->src_x &&
3409 g1->src_y == g2->src_y &&
3410 g1->anim_frames == g2->anim_frames &&
3411 g1->anim_delay == g2->anim_delay &&
3412 g1->anim_mode == g2->anim_mode);
3415 void DrawAllPlayers()
3419 for (i = 0; i < MAX_PLAYERS; i++)
3420 if (stored_player[i].active)
3421 DrawPlayer(&stored_player[i]);
3424 void DrawPlayerField(int x, int y)
3426 if (!IS_PLAYER(x, y))
3429 DrawPlayer(PLAYERINFO(x, y));
3432 #define DRAW_PLAYER_OVER_PUSHED_ELEMENT 1
3434 void DrawPlayer(struct PlayerInfo *player)
3436 int jx = player->jx;
3437 int jy = player->jy;
3438 int move_dir = player->MovDir;
3439 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? +1 : 0);
3440 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? +1 : 0);
3441 int last_jx = (player->is_moving ? jx - dx : jx);
3442 int last_jy = (player->is_moving ? jy - dy : jy);
3443 int next_jx = jx + dx;
3444 int next_jy = jy + dy;
3445 boolean player_is_moving = (player->MovPos ? TRUE : FALSE);
3446 boolean player_is_opaque = FALSE;
3447 int sx = SCREENX(jx), sy = SCREENY(jy);
3448 int sxx = 0, syy = 0;
3449 int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
3451 int action = ACTION_DEFAULT;
3452 int last_player_graphic = getPlayerGraphic(player, move_dir);
3453 int last_player_frame = player->Frame;
3456 /* GfxElement[][] is set to the element the player is digging or collecting;
3457 remove also for off-screen player if the player is not moving anymore */
3458 if (IN_LEV_FIELD(jx, jy) && !player_is_moving)
3459 GfxElement[jx][jy] = EL_UNDEFINED;
3461 if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
3465 if (!IN_LEV_FIELD(jx, jy))
3467 printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
3468 printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
3469 printf("DrawPlayerField(): This should never happen!\n");
3474 if (element == EL_EXPLOSION)
3477 action = (player->is_pushing ? ACTION_PUSHING :
3478 player->is_digging ? ACTION_DIGGING :
3479 player->is_collecting ? ACTION_COLLECTING :
3480 player->is_moving ? ACTION_MOVING :
3481 player->is_snapping ? ACTION_SNAPPING :
3482 player->is_dropping ? ACTION_DROPPING :
3483 player->is_waiting ? player->action_waiting : ACTION_DEFAULT);
3485 if (player->is_waiting)
3486 move_dir = player->dir_waiting;
3488 InitPlayerGfxAnimation(player, action, move_dir);
3490 /* ----------------------------------------------------------------------- */
3491 /* draw things in the field the player is leaving, if needed */
3492 /* ----------------------------------------------------------------------- */
3494 if (player->is_moving)
3496 if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
3498 DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
3500 if (last_element == EL_DYNAMITE_ACTIVE ||
3501 last_element == EL_EM_DYNAMITE_ACTIVE ||
3502 last_element == EL_SP_DISK_RED_ACTIVE)
3503 DrawDynamite(last_jx, last_jy);
3505 DrawLevelFieldThruMask(last_jx, last_jy);
3507 else if (last_element == EL_DYNAMITE_ACTIVE ||
3508 last_element == EL_EM_DYNAMITE_ACTIVE ||
3509 last_element == EL_SP_DISK_RED_ACTIVE)
3510 DrawDynamite(last_jx, last_jy);
3512 /* !!! this is not enough to prevent flickering of players which are
3513 moving next to each others without a free tile between them -- this
3514 can only be solved by drawing all players layer by layer (first the
3515 background, then the foreground etc.) !!! => TODO */
3516 else if (!IS_PLAYER(last_jx, last_jy))
3517 DrawLevelField(last_jx, last_jy);
3520 DrawLevelField(last_jx, last_jy);
3523 if (player->is_pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
3524 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
3527 if (!IN_SCR_FIELD(sx, sy))
3530 /* ----------------------------------------------------------------------- */
3531 /* draw things behind the player, if needed */
3532 /* ----------------------------------------------------------------------- */
3535 DrawLevelElement(jx, jy, Back[jx][jy]);
3536 else if (IS_ACTIVE_BOMB(element))
3537 DrawLevelElement(jx, jy, EL_EMPTY);
3540 if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
3542 int old_element = GfxElement[jx][jy];
3543 int old_graphic = el_act_dir2img(old_element, action, move_dir);
3544 int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
3546 if (GFX_CRUMBLED(old_element))
3547 DrawLevelFieldCrumbledDigging(jx, jy, move_dir, player->StepFrame);
3549 DrawGraphic(sx, sy, old_graphic, frame);
3551 if (graphic_info[old_graphic].anim_mode & ANIM_OPAQUE_PLAYER)
3552 player_is_opaque = TRUE;
3556 GfxElement[jx][jy] = EL_UNDEFINED;
3558 /* make sure that pushed elements are drawn with correct frame rate */
3560 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
3562 if (player->is_pushing && player->is_moving && !IS_ANIM_MODE_CE(graphic))
3563 GfxFrame[jx][jy] = player->StepFrame;
3565 if (player->is_pushing && player->is_moving)
3566 GfxFrame[jx][jy] = player->StepFrame;
3569 DrawLevelField(jx, jy);
3573 #if !DRAW_PLAYER_OVER_PUSHED_ELEMENT
3574 /* ----------------------------------------------------------------------- */
3575 /* draw player himself */
3576 /* ----------------------------------------------------------------------- */
3578 graphic = getPlayerGraphic(player, move_dir);
3580 /* in the case of changed player action or direction, prevent the current
3581 animation frame from being restarted for identical animations */
3582 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
3583 player->Frame = last_player_frame;
3585 frame = getGraphicAnimationFrame(graphic, player->Frame);
3589 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3590 sxx = player->GfxPos;
3592 syy = player->GfxPos;
3595 if (!setup.soft_scrolling && ScreenMovPos)
3598 if (player_is_opaque)
3599 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
3601 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3603 if (SHIELD_ON(player))
3605 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
3606 IMG_SHIELD_NORMAL_ACTIVE);
3607 int frame = getGraphicAnimationFrame(graphic, -1);
3609 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3613 #if DRAW_PLAYER_OVER_PUSHED_ELEMENT
3616 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3617 sxx = player->GfxPos;
3619 syy = player->GfxPos;
3623 /* ----------------------------------------------------------------------- */
3624 /* draw things the player is pushing, if needed */
3625 /* ----------------------------------------------------------------------- */
3628 printf("::: %d, %d [%d, %d] [%d]\n",
3629 player->is_pushing, player_is_moving, player->GfxAction,
3630 player->is_moving, player_is_moving);
3634 if (player->is_pushing && player->is_moving)
3636 int px = SCREENX(jx), py = SCREENY(jy);
3637 int pxx = (TILEX - ABS(sxx)) * dx;
3638 int pyy = (TILEY - ABS(syy)) * dy;
3639 int gfx_frame = GfxFrame[jx][jy];
3645 if (!IS_MOVING(jx, jy)) /* push movement already finished */
3647 element = Feld[next_jx][next_jy];
3648 gfx_frame = GfxFrame[next_jx][next_jy];
3651 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
3654 sync_frame = (IS_ANIM_MODE_CE(graphic) ? gfx_frame : player->StepFrame);
3655 frame = getGraphicAnimationFrame(graphic, sync_frame);
3657 frame = getGraphicAnimationFrame(graphic, player->StepFrame);
3660 /* draw background element under pushed element (like the Sokoban field) */
3662 if (game.use_masked_pushing && IS_MOVING(jx, jy))
3664 /* this allows transparent pushing animation over non-black background */
3667 DrawLevelElement(jx, jy, Back[jx][jy]);
3669 DrawLevelElement(jx, jy, EL_EMPTY);
3671 if (Back[next_jx][next_jy])
3672 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
3674 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
3676 else if (Back[next_jx][next_jy])
3677 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
3679 if (Back[next_jx][next_jy])
3680 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
3684 printf("::: %d, %d, %d, %d [%d] [%d, %d, %d] [%d] [%d, %d] [%d, %d]\n",
3685 jx, px, player->GfxPos, player->StepFrame,
3690 GfxFrame[jx][jy], GfxFrame[next_jx][next_jy]);
3694 /* do not draw (EM style) pushing animation when pushing is finished */
3695 /* (two-tile animations usually do not contain start and end frame) */
3696 if (graphic_info[graphic].double_movement && !IS_MOVING(jx, jy))
3697 DrawLevelElement(next_jx, next_jy, Feld[next_jx][next_jy]);
3699 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
3701 /* masked drawing is needed for EMC style (double) movement graphics */
3702 /* !!! (ONLY WHEN DRAWING PUSHED ELEMENT OVER THE PLAYER) !!! */
3703 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
3708 #if DRAW_PLAYER_OVER_PUSHED_ELEMENT
3709 /* ----------------------------------------------------------------------- */
3710 /* draw player himself */
3711 /* ----------------------------------------------------------------------- */
3713 graphic = getPlayerGraphic(player, move_dir);
3715 /* in the case of changed player action or direction, prevent the current
3716 animation frame from being restarted for identical animations */
3717 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
3718 player->Frame = last_player_frame;
3720 frame = getGraphicAnimationFrame(graphic, player->Frame);
3724 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3725 sxx = player->GfxPos;
3727 syy = player->GfxPos;
3730 if (!setup.soft_scrolling && ScreenMovPos)
3733 if (player_is_opaque)
3734 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
3736 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3738 if (SHIELD_ON(player))
3740 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
3741 IMG_SHIELD_NORMAL_ACTIVE);
3742 int frame = getGraphicAnimationFrame(graphic, -1);
3744 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3748 /* ----------------------------------------------------------------------- */
3749 /* draw things in front of player (active dynamite or dynabombs) */
3750 /* ----------------------------------------------------------------------- */
3752 if (IS_ACTIVE_BOMB(element))
3754 graphic = el2img(element);
3755 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
3757 if (game.emulation == EMU_SUPAPLEX)
3758 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
3760 DrawGraphicThruMask(sx, sy, graphic, frame);
3763 if (player_is_moving && last_element == EL_EXPLOSION)
3765 int element = (GfxElement[last_jx][last_jy] != EL_UNDEFINED ?
3766 GfxElement[last_jx][last_jy] : EL_EMPTY);
3767 int graphic = el_act2img(element, ACTION_EXPLODING);
3768 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
3769 int phase = ExplodePhase[last_jx][last_jy] - 1;
3770 int frame = getGraphicAnimationFrame(graphic, phase - delay);
3773 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
3776 /* ----------------------------------------------------------------------- */
3777 /* draw elements the player is just walking/passing through/under */
3778 /* ----------------------------------------------------------------------- */
3780 if (player_is_moving)
3782 /* handle the field the player is leaving ... */
3783 if (IS_ACCESSIBLE_INSIDE(last_element))
3784 DrawLevelField(last_jx, last_jy);
3785 else if (IS_ACCESSIBLE_UNDER(last_element))
3786 DrawLevelFieldThruMask(last_jx, last_jy);
3789 /* do not redraw accessible elements if the player is just pushing them */
3790 if (!player_is_moving || !player->is_pushing)
3792 /* ... and the field the player is entering */
3793 if (IS_ACCESSIBLE_INSIDE(element))
3794 DrawLevelField(jx, jy);
3795 else if (IS_ACCESSIBLE_UNDER(element))
3796 DrawLevelFieldThruMask(jx, jy);
3799 MarkTileDirty(sx, sy);
3802 /* ------------------------------------------------------------------------- */
3804 void WaitForEventToContinue()
3806 boolean still_wait = TRUE;
3808 /* simulate releasing mouse button over last gadget, if still pressed */
3810 HandleGadgets(-1, -1, 0);
3812 button_status = MB_RELEASED;
3828 case EVENT_BUTTONPRESS:
3829 case EVENT_KEYPRESS:
3833 case EVENT_KEYRELEASE:
3834 ClearPlayerAction();
3838 HandleOtherEvents(&event);
3842 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
3849 /* don't eat all CPU time */
3854 #define MAX_REQUEST_LINES 13
3855 #define MAX_REQUEST_LINE_FONT1_LEN 7
3856 #define MAX_REQUEST_LINE_FONT2_LEN 10
3858 boolean Request(char *text, unsigned int req_state)
3860 int mx, my, ty, result = -1;
3861 unsigned int old_door_state;
3862 int last_game_status = game_status; /* save current game status */
3863 int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
3864 int font_nr = FONT_TEXT_2;
3866 int max_word_len = 0;
3872 global.use_envelope_request = 0;
3876 if (maxWordLengthInString(text) > MAX_REQUEST_LINE_FONT1_LEN)
3878 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
3879 font_nr = FONT_TEXT_1;
3882 for (text_ptr = text; *text_ptr; text_ptr++)
3884 max_word_len = (*text_ptr != ' ' ? max_word_len + 1 : 0);
3886 if (max_word_len > MAX_REQUEST_LINE_FONT1_LEN)
3888 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
3890 font_nr = FONT_TEXT_1;
3892 font_nr = FONT_LEVEL_NUMBER;
3900 if (game_status == GAME_MODE_PLAYING)
3902 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
3903 BlitScreenToBitmap_EM(backbuffer);
3904 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
3905 BlitScreenToBitmap_SP(backbuffer);
3908 /* disable deactivated drawing when quick-loading level tape recording */
3909 if (tape.playing && tape.deactivate_display)
3910 TapeDeactivateDisplayOff(TRUE);
3912 SetMouseCursor(CURSOR_DEFAULT);
3914 #if defined(NETWORK_AVALIABLE)
3915 /* pause network game while waiting for request to answer */
3916 if (options.network &&
3917 game_status == GAME_MODE_PLAYING &&
3918 req_state & REQUEST_WAIT_FOR_INPUT)
3919 SendToServer_PausePlaying();
3922 old_door_state = GetDoorState();
3924 /* simulate releasing mouse button over last gadget, if still pressed */
3926 HandleGadgets(-1, -1, 0);
3930 /* draw released gadget before proceeding */
3934 if (old_door_state & DOOR_OPEN_1 && !global.use_envelope_request)
3936 if (old_door_state & DOOR_OPEN_1)
3940 if (!global.use_envelope_request)
3941 CloseDoor(DOOR_CLOSE_1);
3943 CloseDoor(DOOR_CLOSE_1);
3946 /* save old door content */
3947 BlitBitmap(bitmap_db_door, bitmap_db_door,
3948 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
3949 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
3953 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
3956 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3958 /* clear door drawing field */
3959 DrawBackground(DX, DY, DXSIZE, DYSIZE);
3961 /* force DOOR font inside door area */
3962 game_status = GAME_MODE_PSEUDO_DOOR;
3964 /* write text for request */
3965 for (text_ptr = text, ty = 0; ty < MAX_REQUEST_LINES; ty++)
3967 char text_line[max_request_line_len + 1];
3973 for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
3975 tc = *(text_ptr + tx);
3976 if (!tc || tc == ' ')
3987 strncpy(text_line, text_ptr, tl);
3990 DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
3991 DY + 8 + ty * (getFontHeight(font_nr) + 2),
3992 text_line, font_nr);
3994 text_ptr += tl + (tc == ' ' ? 1 : 0);
3997 game_status = last_game_status; /* restore current game status */
4000 if (global.use_envelope_request)
4004 CreateToolButtons();
4008 if (req_state & REQ_ASK)
4010 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
4011 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
4013 else if (req_state & REQ_CONFIRM)
4015 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
4017 else if (req_state & REQ_PLAYER)
4019 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
4020 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
4021 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
4022 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
4025 /* copy request gadgets to door backbuffer */
4026 BlitBitmap(drawto, bitmap_db_door,
4027 DX, DY, DXSIZE, DYSIZE,
4028 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
4031 if (global.use_envelope_request)
4033 ShowEnvelopeDoor(text, ACTION_OPENING);
4035 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4037 if ((req_state & REQ_ASK && (i == TOOL_CTRL_ID_YES ||
4038 i == TOOL_CTRL_ID_NO)) ||
4039 (req_state & REQ_CONFIRM && i == TOOL_CTRL_ID_CONFIRM) ||
4040 (req_state & REQ_PLAYER && (i == TOOL_CTRL_ID_PLAYER_1 &&
4041 i == TOOL_CTRL_ID_PLAYER_2 &&
4042 i == TOOL_CTRL_ID_PLAYER_3 &&
4043 i == TOOL_CTRL_ID_PLAYER_4)))
4045 int x = tool_gadget[i]->x + dDX;
4046 int y = tool_gadget[i]->y + dDY;
4048 ModifyGadget(tool_gadget[i], GDI_X, x, GDI_Y, y, GDI_END);
4055 if (!global.use_envelope_request)
4056 OpenDoor(DOOR_OPEN_1);
4058 OpenDoor(DOOR_OPEN_1);
4061 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
4063 if (game_status == GAME_MODE_PLAYING)
4065 SetPanelBackground();
4066 SetDrawBackgroundMask(REDRAW_DOOR_1);
4070 SetDrawBackgroundMask(REDRAW_FIELD);
4077 if (game_status != GAME_MODE_MAIN && !global.use_envelope_request)
4080 if (game_status != GAME_MODE_MAIN)
4084 button_status = MB_RELEASED;
4086 request_gadget_id = -1;
4088 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
4100 case EVENT_BUTTONPRESS:
4101 case EVENT_BUTTONRELEASE:
4102 case EVENT_MOTIONNOTIFY:
4104 if (event.type == EVENT_MOTIONNOTIFY)
4106 if (!PointerInWindow(window))
4107 continue; /* window and pointer are on different screens */
4112 motion_status = TRUE;
4113 mx = ((MotionEvent *) &event)->x;
4114 my = ((MotionEvent *) &event)->y;
4118 motion_status = FALSE;
4119 mx = ((ButtonEvent *) &event)->x;
4120 my = ((ButtonEvent *) &event)->y;
4121 if (event.type == EVENT_BUTTONPRESS)
4122 button_status = ((ButtonEvent *) &event)->button;
4124 button_status = MB_RELEASED;
4127 /* this sets 'request_gadget_id' */
4128 HandleGadgets(mx, my, button_status);
4130 switch (request_gadget_id)
4132 case TOOL_CTRL_ID_YES:
4135 case TOOL_CTRL_ID_NO:
4138 case TOOL_CTRL_ID_CONFIRM:
4139 result = TRUE | FALSE;
4142 case TOOL_CTRL_ID_PLAYER_1:
4145 case TOOL_CTRL_ID_PLAYER_2:
4148 case TOOL_CTRL_ID_PLAYER_3:
4151 case TOOL_CTRL_ID_PLAYER_4:
4162 case EVENT_KEYPRESS:
4163 switch (GetEventKey((KeyEvent *)&event, TRUE))
4166 if (req_state & REQ_CONFIRM)
4175 #if defined(TARGET_SDL2)
4185 if (req_state & REQ_PLAYER)
4189 case EVENT_KEYRELEASE:
4190 ClearPlayerAction();
4194 HandleOtherEvents(&event);
4198 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
4200 int joy = AnyJoystick();
4202 if (joy & JOY_BUTTON_1)
4204 else if (joy & JOY_BUTTON_2)
4210 if (game_status == GAME_MODE_PLAYING && local_player->LevelSolved_GameEnd)
4212 HandleGameActions();
4218 if (!PendingEvent()) /* delay only if no pending events */
4223 game_status = GAME_MODE_PSEUDO_DOOR;
4229 game_status = last_game_status; /* restore current game status */
4237 if (!PendingEvent()) /* delay only if no pending events */
4240 /* don't eat all CPU time */
4247 if (game_status != GAME_MODE_MAIN)
4253 if (global.use_envelope_request)
4254 ShowEnvelopeDoor(text, ACTION_CLOSING);
4258 if (!(req_state & REQ_STAY_OPEN) && !global.use_envelope_request)
4260 if (!(req_state & REQ_STAY_OPEN))
4263 CloseDoor(DOOR_CLOSE_1);
4265 if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
4266 (req_state & REQ_REOPEN))
4267 OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
4272 if (game_status == GAME_MODE_PLAYING)
4274 SetPanelBackground();
4275 SetDrawBackgroundMask(REDRAW_DOOR_1);
4279 SetDrawBackgroundMask(REDRAW_FIELD);
4282 #if defined(NETWORK_AVALIABLE)
4283 /* continue network game after request */
4284 if (options.network &&
4285 game_status == GAME_MODE_PLAYING &&
4286 req_state & REQUEST_WAIT_FOR_INPUT)
4287 SendToServer_ContinuePlaying();
4290 /* restore deactivated drawing when quick-loading level tape recording */
4291 if (tape.playing && tape.deactivate_display)
4292 TapeDeactivateDisplayOn();
4297 unsigned int OpenDoor(unsigned int door_state)
4299 if (door_state & DOOR_COPY_BACK)
4301 if (door_state & DOOR_OPEN_1)
4302 BlitBitmap(bitmap_db_door, bitmap_db_door,
4303 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
4304 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
4306 if (door_state & DOOR_OPEN_2)
4307 BlitBitmap(bitmap_db_door, bitmap_db_door,
4308 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY2, VXSIZE, VYSIZE,
4309 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
4311 door_state &= ~DOOR_COPY_BACK;
4314 return MoveDoor(door_state);
4317 unsigned int CloseDoor(unsigned int door_state)
4319 unsigned int old_door_state = GetDoorState();
4321 if (!(door_state & DOOR_NO_COPY_BACK))
4323 if (old_door_state & DOOR_OPEN_1)
4324 BlitBitmap(backbuffer, bitmap_db_door,
4325 DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
4327 if (old_door_state & DOOR_OPEN_2)
4328 BlitBitmap(backbuffer, bitmap_db_door,
4329 VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
4331 door_state &= ~DOOR_NO_COPY_BACK;
4334 return MoveDoor(door_state);
4337 unsigned int GetDoorState()
4339 return MoveDoor(DOOR_GET_STATE);
4342 unsigned int SetDoorState(unsigned int door_state)
4344 return MoveDoor(door_state | DOOR_SET_STATE);
4347 unsigned int MoveDoor(unsigned int door_state)
4349 static int door1 = DOOR_OPEN_1;
4350 static int door2 = DOOR_CLOSE_2;
4351 unsigned int door_delay = 0;
4352 unsigned int door_delay_value;
4355 if (door_1.width < 0 || door_1.width > DXSIZE)
4356 door_1.width = DXSIZE;
4357 if (door_1.height < 0 || door_1.height > DYSIZE)
4358 door_1.height = DYSIZE;
4359 if (door_2.width < 0 || door_2.width > VXSIZE)
4360 door_2.width = VXSIZE;
4361 if (door_2.height < 0 || door_2.height > VYSIZE)
4362 door_2.height = VYSIZE;
4364 if (door_state == DOOR_GET_STATE)
4365 return (door1 | door2);
4367 if (door_state & DOOR_SET_STATE)
4369 if (door_state & DOOR_ACTION_1)
4370 door1 = door_state & DOOR_ACTION_1;
4371 if (door_state & DOOR_ACTION_2)
4372 door2 = door_state & DOOR_ACTION_2;
4374 return (door1 | door2);
4377 if (!(door_state & DOOR_FORCE_REDRAW))
4379 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
4380 door_state &= ~DOOR_OPEN_1;
4381 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
4382 door_state &= ~DOOR_CLOSE_1;
4383 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
4384 door_state &= ~DOOR_OPEN_2;
4385 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
4386 door_state &= ~DOOR_CLOSE_2;
4389 door_delay_value = (door_state & DOOR_ACTION_1 ? door_1.step_delay :
4392 if (setup.quick_doors)
4394 stepsize = 20; /* must be chosen to always draw last frame */
4395 door_delay_value = 0;
4398 if (global.autoplay_leveldir)
4400 door_state |= DOOR_NO_DELAY;
4401 door_state &= ~DOOR_CLOSE_ALL;
4405 if (game_status == GAME_MODE_EDITOR)
4406 door_state |= DOOR_NO_DELAY;
4409 if (door_state & DOOR_ACTION)
4411 boolean handle_door_1 = (door_state & DOOR_ACTION_1);
4412 boolean handle_door_2 = (door_state & DOOR_ACTION_2);
4413 boolean door_1_done = (!handle_door_1);
4414 boolean door_2_done = (!handle_door_2);
4415 boolean door_1_vertical = (door_1.anim_mode & ANIM_VERTICAL);
4416 boolean door_2_vertical = (door_2.anim_mode & ANIM_VERTICAL);
4417 int door_size_1 = (door_1_vertical ? door_1.height : door_1.width);
4418 int door_size_2 = (door_2_vertical ? door_2.height : door_2.width);
4419 int max_door_size_1 = (door_1_vertical ? DYSIZE : DXSIZE);
4420 int max_door_size_2 = (door_2_vertical ? VYSIZE : VXSIZE);
4421 int door_size = (handle_door_1 ? door_size_1 : door_size_2);
4422 int max_door_size = (handle_door_1 ? max_door_size_1 : max_door_size_2);
4423 int door_skip = max_door_size - door_size;
4424 int end = door_size;
4425 int start = ((door_state & DOOR_NO_DELAY) ? end : 0);
4428 if (!(door_state & DOOR_NO_DELAY) && !setup.quick_doors)
4430 /* opening door sound has priority over simultaneously closing door */
4431 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
4432 PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
4433 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
4434 PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
4437 for (k = start; k <= end && !(door_1_done && door_2_done); k += stepsize)
4440 Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
4441 GC gc = bitmap->stored_clip_gc;
4443 if (door_state & DOOR_ACTION_1)
4445 int a = MIN(x * door_1.step_offset, end);
4446 int p = (door_state & DOOR_OPEN_1 ? end - a : a);
4447 int i = p + door_skip;
4449 if (door_1.anim_mode & ANIM_STATIC_PANEL)
4451 BlitBitmap(bitmap_db_door, drawto,
4452 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1,
4453 DXSIZE, DYSIZE, DX, DY);
4457 BlitBitmap(bitmap_db_door, drawto,
4458 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + p / 2,
4459 DXSIZE, DYSIZE - p / 2, DX, DY);
4461 ClearRectangle(drawto, DX, DY + DYSIZE - p / 2, DXSIZE, p / 2);
4464 if (door_1.anim_mode & ANIM_HORIZONTAL && x <= DXSIZE)
4466 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
4467 int dst1_x = DX + DXSIZE - i, dst1_y = DY;
4468 int src2_x = DXSIZE - i, src2_y = DOOR_GFX_PAGEY1;
4469 int dst2_x = DX, dst2_y = DY;
4470 int width = i, height = DYSIZE;
4472 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
4473 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
4476 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
4477 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
4480 else if (door_1.anim_mode & ANIM_VERTICAL && x <= DYSIZE)
4482 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
4483 int dst1_x = DX, dst1_y = DY + DYSIZE - i;
4484 int src2_x = 0, src2_y = DOOR_GFX_PAGEY1 + DYSIZE - i;
4485 int dst2_x = DX, dst2_y = DY;
4486 int width = DXSIZE, height = i;
4488 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
4489 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
4492 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
4493 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
4496 else if (x <= DXSIZE) /* ANIM_DEFAULT */
4498 int j = (door_1.anim_mode == ANIM_DEFAULT ? (DXSIZE - i) / 3 : 0);
4500 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
4501 BlitBitmapMasked(bitmap, drawto,
4502 DXSIZE, DOOR_GFX_PAGEY1, i, 77,
4503 DX + DXSIZE - i, DY + j);
4504 BlitBitmapMasked(bitmap, drawto,
4505 DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
4506 DX + DXSIZE - i, DY + 140 + j);
4507 SetClipOrigin(bitmap, gc, DX - DXSIZE + i,
4508 DY - (DOOR_GFX_PAGEY1 + j));
4509 BlitBitmapMasked(bitmap, drawto,
4510 DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
4512 BlitBitmapMasked(bitmap, drawto,
4513 DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
4516 BlitBitmapMasked(bitmap, drawto,
4517 DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
4519 BlitBitmapMasked(bitmap, drawto,
4520 DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
4522 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
4523 BlitBitmapMasked(bitmap, drawto,
4524 DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
4525 DX + DXSIZE - i, DY + 77 + j);
4526 BlitBitmapMasked(bitmap, drawto,
4527 DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
4528 DX + DXSIZE - i, DY + 203 + j);
4531 redraw_mask |= REDRAW_DOOR_1;
4532 door_1_done = (a == end);
4535 if (door_state & DOOR_ACTION_2)
4537 int a = MIN(x * door_2.step_offset, door_size);
4538 int p = (door_state & DOOR_OPEN_2 ? door_size - a : a);
4539 int i = p + door_skip;
4541 if (door_2.anim_mode & ANIM_STATIC_PANEL)
4543 BlitBitmap(bitmap_db_door, drawto,
4544 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2,
4545 VXSIZE, VYSIZE, VX, VY);
4547 else if (x <= VYSIZE)
4549 BlitBitmap(bitmap_db_door, drawto,
4550 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + p / 2,
4551 VXSIZE, VYSIZE - p / 2, VX, VY);
4553 ClearRectangle(drawto, VX, VY + VYSIZE - p / 2, VXSIZE, p / 2);
4556 if (door_2.anim_mode & ANIM_HORIZONTAL && x <= VXSIZE)
4558 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
4559 int dst1_x = VX + VXSIZE - i, dst1_y = VY;
4560 int src2_x = VXSIZE - i, src2_y = DOOR_GFX_PAGEY2;
4561 int dst2_x = VX, dst2_y = VY;
4562 int width = i, height = VYSIZE;
4564 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
4565 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
4568 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
4569 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
4572 else if (door_2.anim_mode & ANIM_VERTICAL && x <= VYSIZE)
4574 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
4575 int dst1_x = VX, dst1_y = VY + VYSIZE - i;
4576 int src2_x = 0, src2_y = DOOR_GFX_PAGEY2 + VYSIZE - i;
4577 int dst2_x = VX, dst2_y = VY;
4578 int width = VXSIZE, height = i;
4580 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
4581 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
4584 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
4585 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
4588 else if (x <= VXSIZE) /* ANIM_DEFAULT */
4590 int j = (door_2.anim_mode == ANIM_DEFAULT ? (VXSIZE - i) / 3 : 0);
4592 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
4593 BlitBitmapMasked(bitmap, drawto,
4594 VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
4595 VX + VXSIZE - i, VY + j);
4596 SetClipOrigin(bitmap, gc,
4597 VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
4598 BlitBitmapMasked(bitmap, drawto,
4599 VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
4602 BlitBitmapMasked(bitmap, drawto,
4603 VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
4604 i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
4605 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
4606 BlitBitmapMasked(bitmap, drawto,
4607 VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
4609 VX + VXSIZE - i, VY + VYSIZE / 2 + j);
4612 redraw_mask |= REDRAW_DOOR_2;
4613 door_2_done = (a == VXSIZE);
4616 if (!(door_state & DOOR_NO_DELAY))
4620 if (game_status == GAME_MODE_MAIN)
4623 WaitUntilDelayReached(&door_delay, door_delay_value);
4628 if (door_state & DOOR_ACTION_1)
4629 door1 = door_state & DOOR_ACTION_1;
4630 if (door_state & DOOR_ACTION_2)
4631 door2 = door_state & DOOR_ACTION_2;
4633 return (door1 | door2);
4636 void DrawSpecialEditorDoor()
4638 /* draw bigger toolbox window */
4639 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
4640 DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
4642 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
4643 EX - 6, VY - 4, EXSIZE + 12, EYSIZE - VYSIZE + 4,
4646 redraw_mask |= REDRAW_ALL;
4649 void UndrawSpecialEditorDoor()
4651 /* draw normal tape recorder window */
4652 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
4653 EX - 6, EY - 12, EXSIZE + 12, EYSIZE - VYSIZE + 12,
4656 redraw_mask |= REDRAW_ALL;
4660 /* ---------- new tool button stuff ---------------------------------------- */
4662 /* graphic position values for tool buttons */
4663 #define TOOL_BUTTON_YES_XPOS 2
4664 #define TOOL_BUTTON_YES_YPOS 250
4665 #define TOOL_BUTTON_YES_GFX_YPOS 0
4666 #define TOOL_BUTTON_YES_XSIZE 46
4667 #define TOOL_BUTTON_YES_YSIZE 28
4668 #define TOOL_BUTTON_NO_XPOS 52
4669 #define TOOL_BUTTON_NO_YPOS TOOL_BUTTON_YES_YPOS
4670 #define TOOL_BUTTON_NO_GFX_YPOS TOOL_BUTTON_YES_GFX_YPOS
4671 #define TOOL_BUTTON_NO_XSIZE TOOL_BUTTON_YES_XSIZE
4672 #define TOOL_BUTTON_NO_YSIZE TOOL_BUTTON_YES_YSIZE
4673 #define TOOL_BUTTON_CONFIRM_XPOS TOOL_BUTTON_YES_XPOS
4674 #define TOOL_BUTTON_CONFIRM_YPOS TOOL_BUTTON_YES_YPOS
4675 #define TOOL_BUTTON_CONFIRM_GFX_YPOS 30
4676 #define TOOL_BUTTON_CONFIRM_XSIZE 96
4677 #define TOOL_BUTTON_CONFIRM_YSIZE TOOL_BUTTON_YES_YSIZE
4678 #define TOOL_BUTTON_PLAYER_XSIZE 30
4679 #define TOOL_BUTTON_PLAYER_YSIZE 30
4680 #define TOOL_BUTTON_PLAYER_GFX_XPOS 5
4681 #define TOOL_BUTTON_PLAYER_GFX_YPOS 185
4682 #define TOOL_BUTTON_PLAYER_XPOS (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
4683 #define TOOL_BUTTON_PLAYER_YPOS (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
4684 #define TOOL_BUTTON_PLAYER1_XPOS (TOOL_BUTTON_PLAYER_XPOS \
4685 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
4686 #define TOOL_BUTTON_PLAYER2_XPOS (TOOL_BUTTON_PLAYER_XPOS \
4687 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
4688 #define TOOL_BUTTON_PLAYER3_XPOS (TOOL_BUTTON_PLAYER_XPOS \
4689 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
4690 #define TOOL_BUTTON_PLAYER4_XPOS (TOOL_BUTTON_PLAYER_XPOS \
4691 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
4692 #define TOOL_BUTTON_PLAYER1_YPOS (TOOL_BUTTON_PLAYER_YPOS \
4693 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
4694 #define TOOL_BUTTON_PLAYER2_YPOS (TOOL_BUTTON_PLAYER_YPOS \
4695 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
4696 #define TOOL_BUTTON_PLAYER3_YPOS (TOOL_BUTTON_PLAYER_YPOS \
4697 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
4698 #define TOOL_BUTTON_PLAYER4_YPOS (TOOL_BUTTON_PLAYER_YPOS \
4699 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
4708 } toolbutton_info[NUM_TOOL_BUTTONS] =
4711 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_GFX_YPOS,
4712 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_YPOS,
4713 TOOL_BUTTON_YES_XSIZE, TOOL_BUTTON_YES_YSIZE,
4718 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_GFX_YPOS,
4719 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_YPOS,
4720 TOOL_BUTTON_NO_XSIZE, TOOL_BUTTON_NO_YSIZE,
4725 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_GFX_YPOS,
4726 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_YPOS,
4727 TOOL_BUTTON_CONFIRM_XSIZE, TOOL_BUTTON_CONFIRM_YSIZE,
4728 TOOL_CTRL_ID_CONFIRM,
4732 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
4733 TOOL_BUTTON_PLAYER1_XPOS, TOOL_BUTTON_PLAYER1_YPOS,
4734 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
4735 TOOL_CTRL_ID_PLAYER_1,
4739 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
4740 TOOL_BUTTON_PLAYER2_XPOS, TOOL_BUTTON_PLAYER2_YPOS,
4741 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
4742 TOOL_CTRL_ID_PLAYER_2,
4746 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
4747 TOOL_BUTTON_PLAYER3_XPOS, TOOL_BUTTON_PLAYER3_YPOS,
4748 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
4749 TOOL_CTRL_ID_PLAYER_3,
4753 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
4754 TOOL_BUTTON_PLAYER4_XPOS, TOOL_BUTTON_PLAYER4_YPOS,
4755 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
4756 TOOL_CTRL_ID_PLAYER_4,
4761 void CreateToolButtons()
4765 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4767 Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
4768 Bitmap *deco_bitmap = None;
4769 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
4770 struct GadgetInfo *gi;
4771 unsigned int event_mask;
4772 int gd_xoffset, gd_yoffset;
4773 int gd_x1, gd_x2, gd_y;
4776 event_mask = GD_EVENT_RELEASED;
4778 gd_xoffset = toolbutton_info[i].xpos;
4779 gd_yoffset = toolbutton_info[i].ypos;
4780 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
4781 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
4782 gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
4784 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
4786 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
4788 getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr),
4789 &deco_bitmap, &deco_x, &deco_y);
4790 deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
4791 deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
4794 gi = CreateGadget(GDI_CUSTOM_ID, id,
4795 GDI_INFO_TEXT, toolbutton_info[i].infotext,
4796 GDI_X, DX + toolbutton_info[i].x,
4797 GDI_Y, DY + toolbutton_info[i].y,
4798 GDI_WIDTH, toolbutton_info[i].width,
4799 GDI_HEIGHT, toolbutton_info[i].height,
4800 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
4801 GDI_STATE, GD_BUTTON_UNPRESSED,
4802 GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
4803 GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
4804 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
4805 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
4806 GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
4807 GDI_DECORATION_SHIFTING, 1, 1,
4808 GDI_DIRECT_DRAW, FALSE,
4809 GDI_EVENT_MASK, event_mask,
4810 GDI_CALLBACK_ACTION, HandleToolButtons,
4814 Error(ERR_EXIT, "cannot create gadget");
4816 tool_gadget[id] = gi;
4820 void FreeToolButtons()
4824 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4825 FreeGadget(tool_gadget[i]);
4828 static void UnmapToolButtons()
4832 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4833 UnmapGadget(tool_gadget[i]);
4836 static void HandleToolButtons(struct GadgetInfo *gi)
4838 request_gadget_id = gi->custom_id;
4841 static struct Mapping_EM_to_RND_object
4844 boolean is_rnd_to_em_mapping; /* unique mapping EM <-> RND */
4845 boolean is_backside; /* backside of moving element */
4851 em_object_mapping_list[] =
4854 Xblank, TRUE, FALSE,
4858 Yacid_splash_eB, FALSE, FALSE,
4859 EL_ACID_SPLASH_RIGHT, -1, -1
4862 Yacid_splash_wB, FALSE, FALSE,
4863 EL_ACID_SPLASH_LEFT, -1, -1
4866 #ifdef EM_ENGINE_BAD_ROLL
4868 Xstone_force_e, FALSE, FALSE,
4869 EL_ROCK, -1, MV_BIT_RIGHT
4872 Xstone_force_w, FALSE, FALSE,
4873 EL_ROCK, -1, MV_BIT_LEFT
4876 Xnut_force_e, FALSE, FALSE,
4877 EL_NUT, -1, MV_BIT_RIGHT
4880 Xnut_force_w, FALSE, FALSE,
4881 EL_NUT, -1, MV_BIT_LEFT
4884 Xspring_force_e, FALSE, FALSE,
4885 EL_SPRING, -1, MV_BIT_RIGHT
4888 Xspring_force_w, FALSE, FALSE,
4889 EL_SPRING, -1, MV_BIT_LEFT
4892 Xemerald_force_e, FALSE, FALSE,
4893 EL_EMERALD, -1, MV_BIT_RIGHT
4896 Xemerald_force_w, FALSE, FALSE,
4897 EL_EMERALD, -1, MV_BIT_LEFT
4900 Xdiamond_force_e, FALSE, FALSE,
4901 EL_DIAMOND, -1, MV_BIT_RIGHT
4904 Xdiamond_force_w, FALSE, FALSE,
4905 EL_DIAMOND, -1, MV_BIT_LEFT
4908 Xbomb_force_e, FALSE, FALSE,
4909 EL_BOMB, -1, MV_BIT_RIGHT
4912 Xbomb_force_w, FALSE, FALSE,
4913 EL_BOMB, -1, MV_BIT_LEFT
4915 #endif /* EM_ENGINE_BAD_ROLL */
4918 Xstone, TRUE, FALSE,
4922 Xstone_pause, FALSE, FALSE,
4926 Xstone_fall, FALSE, FALSE,
4930 Ystone_s, FALSE, FALSE,
4931 EL_ROCK, ACTION_FALLING, -1
4934 Ystone_sB, FALSE, TRUE,
4935 EL_ROCK, ACTION_FALLING, -1
4938 Ystone_e, FALSE, FALSE,
4939 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
4942 Ystone_eB, FALSE, TRUE,
4943 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
4946 Ystone_w, FALSE, FALSE,
4947 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
4950 Ystone_wB, FALSE, TRUE,
4951 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
4958 Xnut_pause, FALSE, FALSE,
4962 Xnut_fall, FALSE, FALSE,
4966 Ynut_s, FALSE, FALSE,
4967 EL_NUT, ACTION_FALLING, -1
4970 Ynut_sB, FALSE, TRUE,
4971 EL_NUT, ACTION_FALLING, -1
4974 Ynut_e, FALSE, FALSE,
4975 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
4978 Ynut_eB, FALSE, TRUE,
4979 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
4982 Ynut_w, FALSE, FALSE,
4983 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
4986 Ynut_wB, FALSE, TRUE,
4987 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
4990 Xbug_n, TRUE, FALSE,
4994 Xbug_e, TRUE, FALSE,
4995 EL_BUG_RIGHT, -1, -1
4998 Xbug_s, TRUE, FALSE,
5002 Xbug_w, TRUE, FALSE,
5006 Xbug_gon, FALSE, FALSE,
5010 Xbug_goe, FALSE, FALSE,
5011 EL_BUG_RIGHT, -1, -1
5014 Xbug_gos, FALSE, FALSE,
5018 Xbug_gow, FALSE, FALSE,
5022 Ybug_n, FALSE, FALSE,
5023 EL_BUG, ACTION_MOVING, MV_BIT_UP
5026 Ybug_nB, FALSE, TRUE,
5027 EL_BUG, ACTION_MOVING, MV_BIT_UP
5030 Ybug_e, FALSE, FALSE,
5031 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
5034 Ybug_eB, FALSE, TRUE,
5035 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
5038 Ybug_s, FALSE, FALSE,
5039 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
5042 Ybug_sB, FALSE, TRUE,
5043 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
5046 Ybug_w, FALSE, FALSE,
5047 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
5050 Ybug_wB, FALSE, TRUE,
5051 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
5054 Ybug_w_n, FALSE, FALSE,
5055 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
5058 Ybug_n_e, FALSE, FALSE,
5059 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
5062 Ybug_e_s, FALSE, FALSE,
5063 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
5066 Ybug_s_w, FALSE, FALSE,
5067 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
5070 Ybug_e_n, FALSE, FALSE,
5071 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
5074 Ybug_s_e, FALSE, FALSE,
5075 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
5078 Ybug_w_s, FALSE, FALSE,
5079 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
5082 Ybug_n_w, FALSE, FALSE,
5083 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
5086 Ybug_stone, FALSE, FALSE,
5087 EL_BUG, ACTION_SMASHED_BY_ROCK, -1
5090 Ybug_spring, FALSE, FALSE,
5091 EL_BUG, ACTION_SMASHED_BY_SPRING, -1
5094 Xtank_n, TRUE, FALSE,
5095 EL_SPACESHIP_UP, -1, -1
5098 Xtank_e, TRUE, FALSE,
5099 EL_SPACESHIP_RIGHT, -1, -1
5102 Xtank_s, TRUE, FALSE,
5103 EL_SPACESHIP_DOWN, -1, -1
5106 Xtank_w, TRUE, FALSE,
5107 EL_SPACESHIP_LEFT, -1, -1
5110 Xtank_gon, FALSE, FALSE,
5111 EL_SPACESHIP_UP, -1, -1
5114 Xtank_goe, FALSE, FALSE,
5115 EL_SPACESHIP_RIGHT, -1, -1
5118 Xtank_gos, FALSE, FALSE,
5119 EL_SPACESHIP_DOWN, -1, -1
5122 Xtank_gow, FALSE, FALSE,
5123 EL_SPACESHIP_LEFT, -1, -1
5126 Ytank_n, FALSE, FALSE,
5127 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
5130 Ytank_nB, FALSE, TRUE,
5131 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
5134 Ytank_e, FALSE, FALSE,
5135 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
5138 Ytank_eB, FALSE, TRUE,
5139 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
5142 Ytank_s, FALSE, FALSE,
5143 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
5146 Ytank_sB, FALSE, TRUE,
5147 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
5150 Ytank_w, FALSE, FALSE,
5151 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
5154 Ytank_wB, FALSE, TRUE,
5155 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
5158 Ytank_w_n, FALSE, FALSE,
5159 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
5162 Ytank_n_e, FALSE, FALSE,
5163 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
5166 Ytank_e_s, FALSE, FALSE,
5167 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
5170 Ytank_s_w, FALSE, FALSE,
5171 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
5174 Ytank_e_n, FALSE, FALSE,
5175 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
5178 Ytank_s_e, FALSE, FALSE,
5179 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
5182 Ytank_w_s, FALSE, FALSE,
5183 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
5186 Ytank_n_w, FALSE, FALSE,
5187 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
5190 Ytank_stone, FALSE, FALSE,
5191 EL_SPACESHIP, ACTION_SMASHED_BY_ROCK, -1
5194 Ytank_spring, FALSE, FALSE,
5195 EL_SPACESHIP, ACTION_SMASHED_BY_SPRING, -1
5198 Xandroid, TRUE, FALSE,
5199 EL_EMC_ANDROID, ACTION_ACTIVE, -1
5202 Xandroid_1_n, FALSE, FALSE,
5203 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
5206 Xandroid_2_n, FALSE, FALSE,
5207 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
5210 Xandroid_1_e, FALSE, FALSE,
5211 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
5214 Xandroid_2_e, FALSE, FALSE,
5215 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
5218 Xandroid_1_w, FALSE, FALSE,
5219 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
5222 Xandroid_2_w, FALSE, FALSE,
5223 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
5226 Xandroid_1_s, FALSE, FALSE,
5227 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
5230 Xandroid_2_s, FALSE, FALSE,
5231 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
5234 Yandroid_n, FALSE, FALSE,
5235 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
5238 Yandroid_nB, FALSE, TRUE,
5239 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
5242 Yandroid_ne, FALSE, FALSE,
5243 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPRIGHT
5246 Yandroid_neB, FALSE, TRUE,
5247 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPRIGHT
5250 Yandroid_e, FALSE, FALSE,
5251 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
5254 Yandroid_eB, FALSE, TRUE,
5255 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
5258 Yandroid_se, FALSE, FALSE,
5259 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNRIGHT
5262 Yandroid_seB, FALSE, TRUE,
5263 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNRIGHT
5266 Yandroid_s, FALSE, FALSE,
5267 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
5270 Yandroid_sB, FALSE, TRUE,
5271 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
5274 Yandroid_sw, FALSE, FALSE,
5275 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNLEFT
5278 Yandroid_swB, FALSE, TRUE,
5279 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNLEFT
5282 Yandroid_w, FALSE, FALSE,
5283 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
5286 Yandroid_wB, FALSE, TRUE,
5287 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
5290 Yandroid_nw, FALSE, FALSE,
5291 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPLEFT
5294 Yandroid_nwB, FALSE, TRUE,
5295 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPLEFT
5298 Xspring, TRUE, FALSE,
5302 Xspring_pause, FALSE, FALSE,
5306 Xspring_e, FALSE, FALSE,
5310 Xspring_w, FALSE, FALSE,
5314 Xspring_fall, FALSE, FALSE,
5318 Yspring_s, FALSE, FALSE,
5319 EL_SPRING, ACTION_FALLING, -1
5322 Yspring_sB, FALSE, TRUE,
5323 EL_SPRING, ACTION_FALLING, -1
5326 Yspring_e, FALSE, FALSE,
5327 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
5330 Yspring_eB, FALSE, TRUE,
5331 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
5334 Yspring_w, FALSE, FALSE,
5335 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
5338 Yspring_wB, FALSE, TRUE,
5339 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
5342 Yspring_kill_e, FALSE, FALSE,
5343 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
5346 Yspring_kill_eB, FALSE, TRUE,
5347 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
5350 Yspring_kill_w, FALSE, FALSE,
5351 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
5354 Yspring_kill_wB, FALSE, TRUE,
5355 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
5358 Xeater_n, TRUE, FALSE,
5359 EL_YAMYAM_UP, -1, -1
5362 Xeater_e, TRUE, FALSE,
5363 EL_YAMYAM_RIGHT, -1, -1
5366 Xeater_w, TRUE, FALSE,
5367 EL_YAMYAM_LEFT, -1, -1
5370 Xeater_s, TRUE, FALSE,
5371 EL_YAMYAM_DOWN, -1, -1
5374 Yeater_n, FALSE, FALSE,
5375 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
5378 Yeater_nB, FALSE, TRUE,
5379 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
5382 Yeater_e, FALSE, FALSE,
5383 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
5386 Yeater_eB, FALSE, TRUE,
5387 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
5390 Yeater_s, FALSE, FALSE,
5391 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
5394 Yeater_sB, FALSE, TRUE,
5395 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
5398 Yeater_w, FALSE, FALSE,
5399 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
5402 Yeater_wB, FALSE, TRUE,
5403 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
5406 Yeater_stone, FALSE, FALSE,
5407 EL_YAMYAM, ACTION_SMASHED_BY_ROCK, -1
5410 Yeater_spring, FALSE, FALSE,
5411 EL_YAMYAM, ACTION_SMASHED_BY_SPRING, -1
5414 Xalien, TRUE, FALSE,
5418 Xalien_pause, FALSE, FALSE,
5422 Yalien_n, FALSE, FALSE,
5423 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
5426 Yalien_nB, FALSE, TRUE,
5427 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
5430 Yalien_e, FALSE, FALSE,
5431 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
5434 Yalien_eB, FALSE, TRUE,
5435 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
5438 Yalien_s, FALSE, FALSE,
5439 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
5442 Yalien_sB, FALSE, TRUE,
5443 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
5446 Yalien_w, FALSE, FALSE,
5447 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
5450 Yalien_wB, FALSE, TRUE,
5451 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
5454 Yalien_stone, FALSE, FALSE,
5455 EL_ROBOT, ACTION_SMASHED_BY_ROCK, -1
5458 Yalien_spring, FALSE, FALSE,
5459 EL_ROBOT, ACTION_SMASHED_BY_SPRING, -1
5462 Xemerald, TRUE, FALSE,
5466 Xemerald_pause, FALSE, FALSE,
5470 Xemerald_fall, FALSE, FALSE,
5474 Xemerald_shine, FALSE, FALSE,
5475 EL_EMERALD, ACTION_TWINKLING, -1
5478 Yemerald_s, FALSE, FALSE,
5479 EL_EMERALD, ACTION_FALLING, -1
5482 Yemerald_sB, FALSE, TRUE,
5483 EL_EMERALD, ACTION_FALLING, -1
5486 Yemerald_e, FALSE, FALSE,
5487 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
5490 Yemerald_eB, FALSE, TRUE,
5491 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
5494 Yemerald_w, FALSE, FALSE,
5495 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
5498 Yemerald_wB, FALSE, TRUE,
5499 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
5502 Yemerald_eat, FALSE, FALSE,
5503 EL_EMERALD, ACTION_COLLECTING, -1
5506 Yemerald_stone, FALSE, FALSE,
5507 EL_NUT, ACTION_BREAKING, -1
5510 Xdiamond, TRUE, FALSE,
5514 Xdiamond_pause, FALSE, FALSE,
5518 Xdiamond_fall, FALSE, FALSE,
5522 Xdiamond_shine, FALSE, FALSE,
5523 EL_DIAMOND, ACTION_TWINKLING, -1
5526 Ydiamond_s, FALSE, FALSE,
5527 EL_DIAMOND, ACTION_FALLING, -1
5530 Ydiamond_sB, FALSE, TRUE,
5531 EL_DIAMOND, ACTION_FALLING, -1
5534 Ydiamond_e, FALSE, FALSE,
5535 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
5538 Ydiamond_eB, FALSE, TRUE,
5539 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
5542 Ydiamond_w, FALSE, FALSE,
5543 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
5546 Ydiamond_wB, FALSE, TRUE,
5547 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
5550 Ydiamond_eat, FALSE, FALSE,
5551 EL_DIAMOND, ACTION_COLLECTING, -1
5554 Ydiamond_stone, FALSE, FALSE,
5555 EL_DIAMOND, ACTION_SMASHED_BY_ROCK, -1
5558 Xdrip_fall, TRUE, FALSE,
5559 EL_AMOEBA_DROP, -1, -1
5562 Xdrip_stretch, FALSE, FALSE,
5563 EL_AMOEBA_DROP, ACTION_FALLING, -1
5566 Xdrip_stretchB, FALSE, TRUE,
5567 EL_AMOEBA_DROP, ACTION_FALLING, -1
5570 Xdrip_eat, FALSE, FALSE,
5571 EL_AMOEBA_DROP, ACTION_GROWING, -1
5574 Ydrip_s1, FALSE, FALSE,
5575 EL_AMOEBA_DROP, ACTION_FALLING, -1
5578 Ydrip_s1B, FALSE, TRUE,
5579 EL_AMOEBA_DROP, ACTION_FALLING, -1
5582 Ydrip_s2, FALSE, FALSE,
5583 EL_AMOEBA_DROP, ACTION_FALLING, -1
5586 Ydrip_s2B, FALSE, TRUE,
5587 EL_AMOEBA_DROP, ACTION_FALLING, -1
5594 Xbomb_pause, FALSE, FALSE,
5598 Xbomb_fall, FALSE, FALSE,
5602 Ybomb_s, FALSE, FALSE,
5603 EL_BOMB, ACTION_FALLING, -1
5606 Ybomb_sB, FALSE, TRUE,
5607 EL_BOMB, ACTION_FALLING, -1
5610 Ybomb_e, FALSE, FALSE,
5611 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
5614 Ybomb_eB, FALSE, TRUE,
5615 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
5618 Ybomb_w, FALSE, FALSE,
5619 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
5622 Ybomb_wB, FALSE, TRUE,
5623 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
5626 Ybomb_eat, FALSE, FALSE,
5627 EL_BOMB, ACTION_ACTIVATING, -1
5630 Xballoon, TRUE, FALSE,
5634 Yballoon_n, FALSE, FALSE,
5635 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
5638 Yballoon_nB, FALSE, TRUE,
5639 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
5642 Yballoon_e, FALSE, FALSE,
5643 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
5646 Yballoon_eB, FALSE, TRUE,
5647 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
5650 Yballoon_s, FALSE, FALSE,
5651 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
5654 Yballoon_sB, FALSE, TRUE,
5655 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
5658 Yballoon_w, FALSE, FALSE,
5659 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
5662 Yballoon_wB, FALSE, TRUE,
5663 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
5666 Xgrass, TRUE, FALSE,
5667 EL_EMC_GRASS, -1, -1
5670 Ygrass_nB, FALSE, FALSE,
5671 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_UP
5674 Ygrass_eB, FALSE, FALSE,
5675 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_RIGHT
5678 Ygrass_sB, FALSE, FALSE,
5679 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_DOWN
5682 Ygrass_wB, FALSE, FALSE,
5683 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_LEFT
5690 Ydirt_nB, FALSE, FALSE,
5691 EL_SAND, ACTION_DIGGING, MV_BIT_UP
5694 Ydirt_eB, FALSE, FALSE,
5695 EL_SAND, ACTION_DIGGING, MV_BIT_RIGHT
5698 Ydirt_sB, FALSE, FALSE,
5699 EL_SAND, ACTION_DIGGING, MV_BIT_DOWN
5702 Ydirt_wB, FALSE, FALSE,
5703 EL_SAND, ACTION_DIGGING, MV_BIT_LEFT
5706 Xacid_ne, TRUE, FALSE,
5707 EL_ACID_POOL_TOPRIGHT, -1, -1
5710 Xacid_se, TRUE, FALSE,
5711 EL_ACID_POOL_BOTTOMRIGHT, -1, -1
5714 Xacid_s, TRUE, FALSE,
5715 EL_ACID_POOL_BOTTOM, -1, -1
5718 Xacid_sw, TRUE, FALSE,
5719 EL_ACID_POOL_BOTTOMLEFT, -1, -1
5722 Xacid_nw, TRUE, FALSE,
5723 EL_ACID_POOL_TOPLEFT, -1, -1
5726 Xacid_1, TRUE, FALSE,
5730 Xacid_2, FALSE, FALSE,
5734 Xacid_3, FALSE, FALSE,
5738 Xacid_4, FALSE, FALSE,
5742 Xacid_5, FALSE, FALSE,
5746 Xacid_6, FALSE, FALSE,
5750 Xacid_7, FALSE, FALSE,
5754 Xacid_8, FALSE, FALSE,
5758 Xball_1, TRUE, FALSE,
5759 EL_EMC_MAGIC_BALL, -1, -1
5762 Xball_1B, FALSE, FALSE,
5763 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
5766 Xball_2, FALSE, FALSE,
5767 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
5770 Xball_2B, FALSE, FALSE,
5771 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
5774 Yball_eat, FALSE, FALSE,
5775 EL_EMC_MAGIC_BALL, ACTION_DROPPING, -1
5778 Ykey_1_eat, FALSE, FALSE,
5779 EL_EM_KEY_1, ACTION_COLLECTING, -1
5782 Ykey_2_eat, FALSE, FALSE,
5783 EL_EM_KEY_2, ACTION_COLLECTING, -1
5786 Ykey_3_eat, FALSE, FALSE,
5787 EL_EM_KEY_3, ACTION_COLLECTING, -1
5790 Ykey_4_eat, FALSE, FALSE,
5791 EL_EM_KEY_4, ACTION_COLLECTING, -1
5794 Ykey_5_eat, FALSE, FALSE,
5795 EL_EMC_KEY_5, ACTION_COLLECTING, -1
5798 Ykey_6_eat, FALSE, FALSE,
5799 EL_EMC_KEY_6, ACTION_COLLECTING, -1
5802 Ykey_7_eat, FALSE, FALSE,
5803 EL_EMC_KEY_7, ACTION_COLLECTING, -1
5806 Ykey_8_eat, FALSE, FALSE,
5807 EL_EMC_KEY_8, ACTION_COLLECTING, -1
5810 Ylenses_eat, FALSE, FALSE,
5811 EL_EMC_LENSES, ACTION_COLLECTING, -1
5814 Ymagnify_eat, FALSE, FALSE,
5815 EL_EMC_MAGNIFIER, ACTION_COLLECTING, -1
5818 Ygrass_eat, FALSE, FALSE,
5819 EL_EMC_GRASS, ACTION_SNAPPING, -1
5822 Ydirt_eat, FALSE, FALSE,
5823 EL_SAND, ACTION_SNAPPING, -1
5826 Xgrow_ns, TRUE, FALSE,
5827 EL_EXPANDABLE_WALL_VERTICAL, -1, -1
5830 Ygrow_ns_eat, FALSE, FALSE,
5831 EL_EXPANDABLE_WALL_VERTICAL, ACTION_GROWING, -1
5834 Xgrow_ew, TRUE, FALSE,
5835 EL_EXPANDABLE_WALL_HORIZONTAL, -1, -1
5838 Ygrow_ew_eat, FALSE, FALSE,
5839 EL_EXPANDABLE_WALL_HORIZONTAL, ACTION_GROWING, -1
5842 Xwonderwall, TRUE, FALSE,
5843 EL_MAGIC_WALL, -1, -1
5846 XwonderwallB, FALSE, FALSE,
5847 EL_MAGIC_WALL, ACTION_ACTIVE, -1
5850 Xamoeba_1, TRUE, FALSE,
5851 EL_AMOEBA_DRY, ACTION_OTHER, -1
5854 Xamoeba_2, FALSE, FALSE,
5855 EL_AMOEBA_DRY, ACTION_OTHER, -1
5858 Xamoeba_3, FALSE, FALSE,
5859 EL_AMOEBA_DRY, ACTION_OTHER, -1
5862 Xamoeba_4, FALSE, FALSE,
5863 EL_AMOEBA_DRY, ACTION_OTHER, -1
5866 Xamoeba_5, TRUE, FALSE,
5867 EL_AMOEBA_WET, ACTION_OTHER, -1
5870 Xamoeba_6, FALSE, FALSE,
5871 EL_AMOEBA_WET, ACTION_OTHER, -1
5874 Xamoeba_7, FALSE, FALSE,
5875 EL_AMOEBA_WET, ACTION_OTHER, -1
5878 Xamoeba_8, FALSE, FALSE,
5879 EL_AMOEBA_WET, ACTION_OTHER, -1
5882 Xdoor_1, TRUE, FALSE,
5883 EL_EM_GATE_1, -1, -1
5886 Xdoor_2, TRUE, FALSE,
5887 EL_EM_GATE_2, -1, -1
5890 Xdoor_3, TRUE, FALSE,
5891 EL_EM_GATE_3, -1, -1
5894 Xdoor_4, TRUE, FALSE,
5895 EL_EM_GATE_4, -1, -1
5898 Xdoor_5, TRUE, FALSE,
5899 EL_EMC_GATE_5, -1, -1
5902 Xdoor_6, TRUE, FALSE,
5903 EL_EMC_GATE_6, -1, -1
5906 Xdoor_7, TRUE, FALSE,
5907 EL_EMC_GATE_7, -1, -1
5910 Xdoor_8, TRUE, FALSE,
5911 EL_EMC_GATE_8, -1, -1
5914 Xkey_1, TRUE, FALSE,
5918 Xkey_2, TRUE, FALSE,
5922 Xkey_3, TRUE, FALSE,
5926 Xkey_4, TRUE, FALSE,
5930 Xkey_5, TRUE, FALSE,
5931 EL_EMC_KEY_5, -1, -1
5934 Xkey_6, TRUE, FALSE,
5935 EL_EMC_KEY_6, -1, -1
5938 Xkey_7, TRUE, FALSE,
5939 EL_EMC_KEY_7, -1, -1
5942 Xkey_8, TRUE, FALSE,
5943 EL_EMC_KEY_8, -1, -1
5946 Xwind_n, TRUE, FALSE,
5947 EL_BALLOON_SWITCH_UP, -1, -1
5950 Xwind_e, TRUE, FALSE,
5951 EL_BALLOON_SWITCH_RIGHT, -1, -1
5954 Xwind_s, TRUE, FALSE,
5955 EL_BALLOON_SWITCH_DOWN, -1, -1
5958 Xwind_w, TRUE, FALSE,
5959 EL_BALLOON_SWITCH_LEFT, -1, -1
5962 Xwind_nesw, TRUE, FALSE,
5963 EL_BALLOON_SWITCH_ANY, -1, -1
5966 Xwind_stop, TRUE, FALSE,
5967 EL_BALLOON_SWITCH_NONE, -1, -1
5971 EL_EM_EXIT_CLOSED, -1, -1
5974 Xexit_1, TRUE, FALSE,
5975 EL_EM_EXIT_OPEN, -1, -1
5978 Xexit_2, FALSE, FALSE,
5979 EL_EM_EXIT_OPEN, -1, -1
5982 Xexit_3, FALSE, FALSE,
5983 EL_EM_EXIT_OPEN, -1, -1
5986 Xdynamite, TRUE, FALSE,
5987 EL_EM_DYNAMITE, -1, -1
5990 Ydynamite_eat, FALSE, FALSE,
5991 EL_EM_DYNAMITE, ACTION_COLLECTING, -1
5994 Xdynamite_1, TRUE, FALSE,
5995 EL_EM_DYNAMITE_ACTIVE, -1, -1
5998 Xdynamite_2, FALSE, FALSE,
5999 EL_EM_DYNAMITE_ACTIVE, -1, -1
6002 Xdynamite_3, FALSE, FALSE,
6003 EL_EM_DYNAMITE_ACTIVE, -1, -1
6006 Xdynamite_4, FALSE, FALSE,
6007 EL_EM_DYNAMITE_ACTIVE, -1, -1
6010 Xbumper, TRUE, FALSE,
6011 EL_EMC_SPRING_BUMPER, -1, -1
6014 XbumperB, FALSE, FALSE,
6015 EL_EMC_SPRING_BUMPER, ACTION_ACTIVE, -1
6018 Xwheel, TRUE, FALSE,
6019 EL_ROBOT_WHEEL, -1, -1
6022 XwheelB, FALSE, FALSE,
6023 EL_ROBOT_WHEEL, ACTION_ACTIVE, -1
6026 Xswitch, TRUE, FALSE,
6027 EL_EMC_MAGIC_BALL_SWITCH, -1, -1
6030 XswitchB, FALSE, FALSE,
6031 EL_EMC_MAGIC_BALL_SWITCH, ACTION_ACTIVE, -1
6035 EL_QUICKSAND_EMPTY, -1, -1
6038 Xsand_stone, TRUE, FALSE,
6039 EL_QUICKSAND_FULL, -1, -1
6042 Xsand_stonein_1, FALSE, TRUE,
6043 EL_ROCK, ACTION_FILLING, -1
6046 Xsand_stonein_2, FALSE, TRUE,
6047 EL_ROCK, ACTION_FILLING, -1
6050 Xsand_stonein_3, FALSE, TRUE,
6051 EL_ROCK, ACTION_FILLING, -1
6054 Xsand_stonein_4, FALSE, TRUE,
6055 EL_ROCK, ACTION_FILLING, -1
6059 Xsand_stonesand_1, FALSE, FALSE,
6060 EL_QUICKSAND_EMPTYING, -1, -1
6063 Xsand_stonesand_2, FALSE, FALSE,
6064 EL_QUICKSAND_EMPTYING, -1, -1
6067 Xsand_stonesand_3, FALSE, FALSE,
6068 EL_QUICKSAND_EMPTYING, -1, -1
6071 Xsand_stonesand_4, FALSE, FALSE,
6072 EL_QUICKSAND_EMPTYING, -1, -1
6075 Xsand_stonesand_quickout_1, FALSE, FALSE,
6076 EL_QUICKSAND_EMPTYING, -1, -1
6079 Xsand_stonesand_quickout_2, FALSE, FALSE,
6080 EL_QUICKSAND_EMPTYING, -1, -1
6084 Xsand_stonesand_1, FALSE, FALSE,
6085 EL_QUICKSAND_FULL, -1, -1
6088 Xsand_stonesand_2, FALSE, FALSE,
6089 EL_QUICKSAND_FULL, -1, -1
6092 Xsand_stonesand_3, FALSE, FALSE,
6093 EL_QUICKSAND_FULL, -1, -1
6096 Xsand_stonesand_4, FALSE, FALSE,
6097 EL_QUICKSAND_FULL, -1, -1
6101 Xsand_stoneout_1, FALSE, FALSE,
6102 EL_ROCK, ACTION_EMPTYING, -1
6105 Xsand_stoneout_2, FALSE, FALSE,
6106 EL_ROCK, ACTION_EMPTYING, -1
6110 Xsand_sandstone_1, FALSE, FALSE,
6111 EL_QUICKSAND_FILLING, -1, -1
6114 Xsand_sandstone_2, FALSE, FALSE,
6115 EL_QUICKSAND_FILLING, -1, -1
6118 Xsand_sandstone_3, FALSE, FALSE,
6119 EL_QUICKSAND_FILLING, -1, -1
6122 Xsand_sandstone_4, FALSE, FALSE,
6123 EL_QUICKSAND_FILLING, -1, -1
6127 Xsand_sandstone_1, FALSE, FALSE,
6128 EL_QUICKSAND_FULL, -1, -1
6131 Xsand_sandstone_2, FALSE, FALSE,
6132 EL_QUICKSAND_FULL, -1, -1
6135 Xsand_sandstone_3, FALSE, FALSE,
6136 EL_QUICKSAND_FULL, -1, -1
6139 Xsand_sandstone_4, FALSE, FALSE,
6140 EL_QUICKSAND_FULL, -1, -1
6144 Xplant, TRUE, FALSE,
6145 EL_EMC_PLANT, -1, -1
6148 Yplant, FALSE, FALSE,
6149 EL_EMC_PLANT, -1, -1
6152 Xlenses, TRUE, FALSE,
6153 EL_EMC_LENSES, -1, -1
6156 Xmagnify, TRUE, FALSE,
6157 EL_EMC_MAGNIFIER, -1, -1
6160 Xdripper, TRUE, FALSE,
6161 EL_EMC_DRIPPER, -1, -1
6164 XdripperB, FALSE, FALSE,
6165 EL_EMC_DRIPPER, ACTION_ACTIVE, -1
6168 Xfake_blank, TRUE, FALSE,
6169 EL_INVISIBLE_WALL, -1, -1
6172 Xfake_blankB, FALSE, FALSE,
6173 EL_INVISIBLE_WALL, ACTION_ACTIVE, -1
6176 Xfake_grass, TRUE, FALSE,
6177 EL_EMC_FAKE_GRASS, -1, -1
6180 Xfake_grassB, FALSE, FALSE,
6181 EL_EMC_FAKE_GRASS, ACTION_ACTIVE, -1
6184 Xfake_door_1, TRUE, FALSE,
6185 EL_EM_GATE_1_GRAY, -1, -1
6188 Xfake_door_2, TRUE, FALSE,
6189 EL_EM_GATE_2_GRAY, -1, -1
6192 Xfake_door_3, TRUE, FALSE,
6193 EL_EM_GATE_3_GRAY, -1, -1
6196 Xfake_door_4, TRUE, FALSE,
6197 EL_EM_GATE_4_GRAY, -1, -1
6200 Xfake_door_5, TRUE, FALSE,
6201 EL_EMC_GATE_5_GRAY, -1, -1
6204 Xfake_door_6, TRUE, FALSE,
6205 EL_EMC_GATE_6_GRAY, -1, -1
6208 Xfake_door_7, TRUE, FALSE,
6209 EL_EMC_GATE_7_GRAY, -1, -1
6212 Xfake_door_8, TRUE, FALSE,
6213 EL_EMC_GATE_8_GRAY, -1, -1
6216 Xfake_acid_1, TRUE, FALSE,
6217 EL_EMC_FAKE_ACID, -1, -1
6220 Xfake_acid_2, FALSE, FALSE,
6221 EL_EMC_FAKE_ACID, -1, -1
6224 Xfake_acid_3, FALSE, FALSE,
6225 EL_EMC_FAKE_ACID, -1, -1
6228 Xfake_acid_4, FALSE, FALSE,
6229 EL_EMC_FAKE_ACID, -1, -1
6232 Xfake_acid_5, FALSE, FALSE,
6233 EL_EMC_FAKE_ACID, -1, -1
6236 Xfake_acid_6, FALSE, FALSE,
6237 EL_EMC_FAKE_ACID, -1, -1
6240 Xfake_acid_7, FALSE, FALSE,
6241 EL_EMC_FAKE_ACID, -1, -1
6244 Xfake_acid_8, FALSE, FALSE,
6245 EL_EMC_FAKE_ACID, -1, -1
6248 Xsteel_1, TRUE, FALSE,
6249 EL_STEELWALL, -1, -1
6252 Xsteel_2, TRUE, FALSE,
6253 EL_EMC_STEELWALL_2, -1, -1
6256 Xsteel_3, TRUE, FALSE,
6257 EL_EMC_STEELWALL_3, -1, -1
6260 Xsteel_4, TRUE, FALSE,
6261 EL_EMC_STEELWALL_4, -1, -1
6264 Xwall_1, TRUE, FALSE,
6268 Xwall_2, TRUE, FALSE,
6269 EL_EMC_WALL_14, -1, -1
6272 Xwall_3, TRUE, FALSE,
6273 EL_EMC_WALL_15, -1, -1
6276 Xwall_4, TRUE, FALSE,
6277 EL_EMC_WALL_16, -1, -1
6280 Xround_wall_1, TRUE, FALSE,
6281 EL_WALL_SLIPPERY, -1, -1
6284 Xround_wall_2, TRUE, FALSE,
6285 EL_EMC_WALL_SLIPPERY_2, -1, -1
6288 Xround_wall_3, TRUE, FALSE,
6289 EL_EMC_WALL_SLIPPERY_3, -1, -1
6292 Xround_wall_4, TRUE, FALSE,
6293 EL_EMC_WALL_SLIPPERY_4, -1, -1
6296 Xdecor_1, TRUE, FALSE,
6297 EL_EMC_WALL_8, -1, -1
6300 Xdecor_2, TRUE, FALSE,
6301 EL_EMC_WALL_6, -1, -1
6304 Xdecor_3, TRUE, FALSE,
6305 EL_EMC_WALL_4, -1, -1
6308 Xdecor_4, TRUE, FALSE,
6309 EL_EMC_WALL_7, -1, -1
6312 Xdecor_5, TRUE, FALSE,
6313 EL_EMC_WALL_5, -1, -1
6316 Xdecor_6, TRUE, FALSE,
6317 EL_EMC_WALL_9, -1, -1
6320 Xdecor_7, TRUE, FALSE,
6321 EL_EMC_WALL_10, -1, -1
6324 Xdecor_8, TRUE, FALSE,
6325 EL_EMC_WALL_1, -1, -1
6328 Xdecor_9, TRUE, FALSE,
6329 EL_EMC_WALL_2, -1, -1
6332 Xdecor_10, TRUE, FALSE,
6333 EL_EMC_WALL_3, -1, -1
6336 Xdecor_11, TRUE, FALSE,
6337 EL_EMC_WALL_11, -1, -1
6340 Xdecor_12, TRUE, FALSE,
6341 EL_EMC_WALL_12, -1, -1
6344 Xalpha_0, TRUE, FALSE,
6345 EL_CHAR('0'), -1, -1
6348 Xalpha_1, TRUE, FALSE,
6349 EL_CHAR('1'), -1, -1
6352 Xalpha_2, TRUE, FALSE,
6353 EL_CHAR('2'), -1, -1
6356 Xalpha_3, TRUE, FALSE,
6357 EL_CHAR('3'), -1, -1
6360 Xalpha_4, TRUE, FALSE,
6361 EL_CHAR('4'), -1, -1
6364 Xalpha_5, TRUE, FALSE,
6365 EL_CHAR('5'), -1, -1
6368 Xalpha_6, TRUE, FALSE,
6369 EL_CHAR('6'), -1, -1
6372 Xalpha_7, TRUE, FALSE,
6373 EL_CHAR('7'), -1, -1
6376 Xalpha_8, TRUE, FALSE,
6377 EL_CHAR('8'), -1, -1
6380 Xalpha_9, TRUE, FALSE,
6381 EL_CHAR('9'), -1, -1
6384 Xalpha_excla, TRUE, FALSE,
6385 EL_CHAR('!'), -1, -1
6388 Xalpha_quote, TRUE, FALSE,
6389 EL_CHAR('"'), -1, -1
6392 Xalpha_comma, TRUE, FALSE,
6393 EL_CHAR(','), -1, -1
6396 Xalpha_minus, TRUE, FALSE,
6397 EL_CHAR('-'), -1, -1
6400 Xalpha_perio, TRUE, FALSE,
6401 EL_CHAR('.'), -1, -1
6404 Xalpha_colon, TRUE, FALSE,
6405 EL_CHAR(':'), -1, -1
6408 Xalpha_quest, TRUE, FALSE,
6409 EL_CHAR('?'), -1, -1
6412 Xalpha_a, TRUE, FALSE,
6413 EL_CHAR('A'), -1, -1
6416 Xalpha_b, TRUE, FALSE,
6417 EL_CHAR('B'), -1, -1
6420 Xalpha_c, TRUE, FALSE,
6421 EL_CHAR('C'), -1, -1
6424 Xalpha_d, TRUE, FALSE,
6425 EL_CHAR('D'), -1, -1
6428 Xalpha_e, TRUE, FALSE,
6429 EL_CHAR('E'), -1, -1
6432 Xalpha_f, TRUE, FALSE,
6433 EL_CHAR('F'), -1, -1
6436 Xalpha_g, TRUE, FALSE,
6437 EL_CHAR('G'), -1, -1
6440 Xalpha_h, TRUE, FALSE,
6441 EL_CHAR('H'), -1, -1
6444 Xalpha_i, TRUE, FALSE,
6445 EL_CHAR('I'), -1, -1
6448 Xalpha_j, TRUE, FALSE,
6449 EL_CHAR('J'), -1, -1
6452 Xalpha_k, TRUE, FALSE,
6453 EL_CHAR('K'), -1, -1
6456 Xalpha_l, TRUE, FALSE,
6457 EL_CHAR('L'), -1, -1
6460 Xalpha_m, TRUE, FALSE,
6461 EL_CHAR('M'), -1, -1
6464 Xalpha_n, TRUE, FALSE,
6465 EL_CHAR('N'), -1, -1
6468 Xalpha_o, TRUE, FALSE,
6469 EL_CHAR('O'), -1, -1
6472 Xalpha_p, TRUE, FALSE,
6473 EL_CHAR('P'), -1, -1
6476 Xalpha_q, TRUE, FALSE,
6477 EL_CHAR('Q'), -1, -1
6480 Xalpha_r, TRUE, FALSE,
6481 EL_CHAR('R'), -1, -1
6484 Xalpha_s, TRUE, FALSE,
6485 EL_CHAR('S'), -1, -1
6488 Xalpha_t, TRUE, FALSE,
6489 EL_CHAR('T'), -1, -1
6492 Xalpha_u, TRUE, FALSE,
6493 EL_CHAR('U'), -1, -1
6496 Xalpha_v, TRUE, FALSE,
6497 EL_CHAR('V'), -1, -1
6500 Xalpha_w, TRUE, FALSE,
6501 EL_CHAR('W'), -1, -1
6504 Xalpha_x, TRUE, FALSE,
6505 EL_CHAR('X'), -1, -1
6508 Xalpha_y, TRUE, FALSE,
6509 EL_CHAR('Y'), -1, -1
6512 Xalpha_z, TRUE, FALSE,
6513 EL_CHAR('Z'), -1, -1
6516 Xalpha_arrow_e, TRUE, FALSE,
6517 EL_CHAR('>'), -1, -1
6520 Xalpha_arrow_w, TRUE, FALSE,
6521 EL_CHAR('<'), -1, -1
6524 Xalpha_copyr, TRUE, FALSE,
6525 EL_CHAR('©'), -1, -1
6529 Xboom_bug, FALSE, FALSE,
6530 EL_BUG, ACTION_EXPLODING, -1
6533 Xboom_bomb, FALSE, FALSE,
6534 EL_BOMB, ACTION_EXPLODING, -1
6537 Xboom_android, FALSE, FALSE,
6538 EL_EMC_ANDROID, ACTION_OTHER, -1
6541 Xboom_1, FALSE, FALSE,
6542 EL_DEFAULT, ACTION_EXPLODING, -1
6545 Xboom_2, FALSE, FALSE,
6546 EL_DEFAULT, ACTION_EXPLODING, -1
6549 Znormal, FALSE, FALSE,
6553 Zdynamite, FALSE, FALSE,
6557 Zplayer, FALSE, FALSE,
6561 ZBORDER, FALSE, FALSE,
6571 static struct Mapping_EM_to_RND_player
6580 em_player_mapping_list[] =
6584 EL_PLAYER_1, ACTION_MOVING, MV_BIT_UP,
6588 EL_PLAYER_1, ACTION_MOVING, MV_BIT_RIGHT,
6592 EL_PLAYER_1, ACTION_MOVING, MV_BIT_DOWN,
6596 EL_PLAYER_1, ACTION_MOVING, MV_BIT_LEFT,
6600 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_UP,
6604 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_RIGHT,
6608 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_DOWN,
6612 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_LEFT,
6616 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_UP,
6620 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_RIGHT,
6624 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_DOWN,
6628 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_LEFT,
6632 EL_PLAYER_2, ACTION_MOVING, MV_BIT_UP,
6636 EL_PLAYER_2, ACTION_MOVING, MV_BIT_RIGHT,
6640 EL_PLAYER_2, ACTION_MOVING, MV_BIT_DOWN,
6644 EL_PLAYER_2, ACTION_MOVING, MV_BIT_LEFT,
6648 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_UP,
6652 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_RIGHT,
6656 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_DOWN,
6660 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_LEFT,
6664 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_UP,
6668 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_RIGHT,
6672 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_DOWN,
6676 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_LEFT,
6680 EL_PLAYER_1, ACTION_DEFAULT, -1,
6684 EL_PLAYER_2, ACTION_DEFAULT, -1,
6688 EL_PLAYER_3, ACTION_MOVING, MV_BIT_UP,
6692 EL_PLAYER_3, ACTION_MOVING, MV_BIT_RIGHT,
6696 EL_PLAYER_3, ACTION_MOVING, MV_BIT_DOWN,
6700 EL_PLAYER_3, ACTION_MOVING, MV_BIT_LEFT,
6704 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_UP,
6708 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_RIGHT,
6712 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_DOWN,
6716 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_LEFT,
6720 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_UP,
6724 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_RIGHT,
6728 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_DOWN,
6732 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_LEFT,
6736 EL_PLAYER_4, ACTION_MOVING, MV_BIT_UP,
6740 EL_PLAYER_4, ACTION_MOVING, MV_BIT_RIGHT,
6744 EL_PLAYER_4, ACTION_MOVING, MV_BIT_DOWN,
6748 EL_PLAYER_4, ACTION_MOVING, MV_BIT_LEFT,
6752 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_UP,
6756 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_RIGHT,
6760 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_DOWN,
6764 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_LEFT,
6768 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_UP,
6772 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_RIGHT,
6776 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_DOWN,
6780 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_LEFT,
6784 EL_PLAYER_3, ACTION_DEFAULT, -1,
6788 EL_PLAYER_4, ACTION_DEFAULT, -1,
6797 int map_element_RND_to_EM(int element_rnd)
6799 static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
6800 static boolean mapping_initialized = FALSE;
6802 if (!mapping_initialized)
6806 /* return "Xalpha_quest" for all undefined elements in mapping array */
6807 for (i = 0; i < NUM_FILE_ELEMENTS; i++)
6808 mapping_RND_to_EM[i] = Xalpha_quest;
6810 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
6811 if (em_object_mapping_list[i].is_rnd_to_em_mapping)
6812 mapping_RND_to_EM[em_object_mapping_list[i].element_rnd] =
6813 em_object_mapping_list[i].element_em;
6815 mapping_initialized = TRUE;
6818 if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
6819 return mapping_RND_to_EM[element_rnd];
6821 Error(ERR_WARN, "invalid RND level element %d", element_rnd);
6826 int map_element_EM_to_RND(int element_em)
6828 static unsigned short mapping_EM_to_RND[TILE_MAX];
6829 static boolean mapping_initialized = FALSE;
6831 if (!mapping_initialized)
6835 /* return "EL_UNKNOWN" for all undefined elements in mapping array */
6836 for (i = 0; i < TILE_MAX; i++)
6837 mapping_EM_to_RND[i] = EL_UNKNOWN;
6839 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
6840 mapping_EM_to_RND[em_object_mapping_list[i].element_em] =
6841 em_object_mapping_list[i].element_rnd;
6843 mapping_initialized = TRUE;
6846 if (element_em >= 0 && element_em < TILE_MAX)
6847 return mapping_EM_to_RND[element_em];
6849 Error(ERR_WARN, "invalid EM level element %d", element_em);
6854 void map_android_clone_elements_RND_to_EM(struct LevelInfo *level)
6856 struct LevelInfo_EM *level_em = level->native_em_level;
6857 struct LEVEL *lev = level_em->lev;
6860 for (i = 0; i < TILE_MAX; i++)
6861 lev->android_array[i] = Xblank;
6863 for (i = 0; i < level->num_android_clone_elements; i++)
6865 int element_rnd = level->android_clone_element[i];
6866 int element_em = map_element_RND_to_EM(element_rnd);
6868 for (j = 0; em_object_mapping_list[j].element_em != -1; j++)
6869 if (em_object_mapping_list[j].element_rnd == element_rnd)
6870 lev->android_array[em_object_mapping_list[j].element_em] = element_em;
6874 void map_android_clone_elements_EM_to_RND(struct LevelInfo *level)
6876 struct LevelInfo_EM *level_em = level->native_em_level;
6877 struct LEVEL *lev = level_em->lev;
6880 level->num_android_clone_elements = 0;
6882 for (i = 0; i < TILE_MAX; i++)
6884 int element_em = lev->android_array[i];
6886 boolean element_found = FALSE;
6888 if (element_em == Xblank)
6891 element_rnd = map_element_EM_to_RND(element_em);
6893 for (j = 0; j < level->num_android_clone_elements; j++)
6894 if (level->android_clone_element[j] == element_rnd)
6895 element_found = TRUE;
6899 level->android_clone_element[level->num_android_clone_elements++] =
6902 if (level->num_android_clone_elements == MAX_ANDROID_ELEMENTS)
6907 if (level->num_android_clone_elements == 0)
6909 level->num_android_clone_elements = 1;
6910 level->android_clone_element[0] = EL_EMPTY;
6914 int map_direction_RND_to_EM(int direction)
6916 return (direction == MV_UP ? 0 :
6917 direction == MV_RIGHT ? 1 :
6918 direction == MV_DOWN ? 2 :
6919 direction == MV_LEFT ? 3 :
6923 int map_direction_EM_to_RND(int direction)
6925 return (direction == 0 ? MV_UP :
6926 direction == 1 ? MV_RIGHT :
6927 direction == 2 ? MV_DOWN :
6928 direction == 3 ? MV_LEFT :
6932 int map_element_RND_to_SP(int element_rnd)
6934 int element_sp = 0x20; /* map unknown elements to yellow "hardware" */
6936 if (element_rnd >= EL_SP_START &&
6937 element_rnd <= EL_SP_END)
6938 element_sp = element_rnd - EL_SP_START;
6939 else if (element_rnd == EL_EMPTY_SPACE)
6941 else if (element_rnd == EL_INVISIBLE_WALL)
6947 int map_element_SP_to_RND(int element_sp)
6949 int element_rnd = EL_UNKNOWN;
6951 if (element_sp >= 0x00 &&
6953 element_rnd = EL_SP_START + element_sp;
6954 else if (element_sp == 0x28)
6955 element_rnd = EL_INVISIBLE_WALL;
6960 int map_action_SP_to_RND(int action_sp)
6964 case actActive: return ACTION_ACTIVE;
6965 case actImpact: return ACTION_IMPACT;
6966 case actExploding: return ACTION_EXPLODING;
6967 case actDigging: return ACTION_DIGGING;
6968 case actSnapping: return ACTION_SNAPPING;
6969 case actCollecting: return ACTION_COLLECTING;
6970 case actPassing: return ACTION_PASSING;
6971 case actPushing: return ACTION_PUSHING;
6972 case actDropping: return ACTION_DROPPING;
6974 default: return ACTION_DEFAULT;
6978 int get_next_element(int element)
6982 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
6983 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
6984 case EL_QUICKSAND_FAST_FILLING: return EL_QUICKSAND_FAST_FULL;
6985 case EL_QUICKSAND_FAST_EMPTYING: return EL_QUICKSAND_FAST_EMPTY;
6986 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
6987 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
6988 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
6989 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
6990 case EL_DC_MAGIC_WALL_FILLING: return EL_DC_MAGIC_WALL_FULL;
6991 case EL_DC_MAGIC_WALL_EMPTYING: return EL_DC_MAGIC_WALL_ACTIVE;
6992 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
6994 default: return element;
6999 int el_act_dir2img(int element, int action, int direction)
7001 element = GFX_ELEMENT(element);
7003 if (direction == MV_NONE)
7004 return element_info[element].graphic[action];
7006 direction = MV_DIR_TO_BIT(direction);
7008 return element_info[element].direction_graphic[action][direction];
7011 int el_act_dir2img(int element, int action, int direction)
7013 element = GFX_ELEMENT(element);
7014 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
7016 /* direction_graphic[][] == graphic[] for undefined direction graphics */
7017 return element_info[element].direction_graphic[action][direction];
7022 static int el_act_dir2crm(int element, int action, int direction)
7024 element = GFX_ELEMENT(element);
7026 if (direction == MV_NONE)
7027 return element_info[element].crumbled[action];
7029 direction = MV_DIR_TO_BIT(direction);
7031 return element_info[element].direction_crumbled[action][direction];
7034 static int el_act_dir2crm(int element, int action, int direction)
7036 element = GFX_ELEMENT(element);
7037 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
7039 /* direction_graphic[][] == graphic[] for undefined direction graphics */
7040 return element_info[element].direction_crumbled[action][direction];
7044 int el_act2img(int element, int action)
7046 element = GFX_ELEMENT(element);
7048 return element_info[element].graphic[action];
7051 int el_act2crm(int element, int action)
7053 element = GFX_ELEMENT(element);
7055 return element_info[element].crumbled[action];
7058 int el_dir2img(int element, int direction)
7060 element = GFX_ELEMENT(element);
7062 return el_act_dir2img(element, ACTION_DEFAULT, direction);
7065 int el2baseimg(int element)
7067 return element_info[element].graphic[ACTION_DEFAULT];
7070 int el2img(int element)
7072 element = GFX_ELEMENT(element);
7074 return element_info[element].graphic[ACTION_DEFAULT];
7077 int el2edimg(int element)
7079 element = GFX_ELEMENT(element);
7081 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
7084 int el2preimg(int element)
7086 element = GFX_ELEMENT(element);
7088 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
7091 int el2panelimg(int element)
7093 element = GFX_ELEMENT(element);
7095 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PANEL];
7098 int font2baseimg(int font_nr)
7100 return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
7103 int getBeltNrFromBeltElement(int element)
7105 return (element < EL_CONVEYOR_BELT_2_LEFT ? 0 :
7106 element < EL_CONVEYOR_BELT_3_LEFT ? 1 :
7107 element < EL_CONVEYOR_BELT_4_LEFT ? 2 : 3);
7110 int getBeltNrFromBeltActiveElement(int element)
7112 return (element < EL_CONVEYOR_BELT_2_LEFT_ACTIVE ? 0 :
7113 element < EL_CONVEYOR_BELT_3_LEFT_ACTIVE ? 1 :
7114 element < EL_CONVEYOR_BELT_4_LEFT_ACTIVE ? 2 : 3);
7117 int getBeltNrFromBeltSwitchElement(int element)
7119 return (element < EL_CONVEYOR_BELT_2_SWITCH_LEFT ? 0 :
7120 element < EL_CONVEYOR_BELT_3_SWITCH_LEFT ? 1 :
7121 element < EL_CONVEYOR_BELT_4_SWITCH_LEFT ? 2 : 3);
7124 int getBeltDirNrFromBeltElement(int element)
7126 static int belt_base_element[4] =
7128 EL_CONVEYOR_BELT_1_LEFT,
7129 EL_CONVEYOR_BELT_2_LEFT,
7130 EL_CONVEYOR_BELT_3_LEFT,
7131 EL_CONVEYOR_BELT_4_LEFT
7134 int belt_nr = getBeltNrFromBeltElement(element);
7135 int belt_dir_nr = element - belt_base_element[belt_nr];
7137 return (belt_dir_nr % 3);
7140 int getBeltDirNrFromBeltSwitchElement(int element)
7142 static int belt_base_element[4] =
7144 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
7145 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
7146 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
7147 EL_CONVEYOR_BELT_4_SWITCH_LEFT
7150 int belt_nr = getBeltNrFromBeltSwitchElement(element);
7151 int belt_dir_nr = element - belt_base_element[belt_nr];
7153 return (belt_dir_nr % 3);
7156 int getBeltDirFromBeltElement(int element)
7158 static int belt_move_dir[3] =
7165 int belt_dir_nr = getBeltDirNrFromBeltElement(element);
7167 return belt_move_dir[belt_dir_nr];
7170 int getBeltDirFromBeltSwitchElement(int element)
7172 static int belt_move_dir[3] =
7179 int belt_dir_nr = getBeltDirNrFromBeltSwitchElement(element);
7181 return belt_move_dir[belt_dir_nr];
7184 int getBeltElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
7186 static int belt_base_element[4] =
7188 EL_CONVEYOR_BELT_1_LEFT,
7189 EL_CONVEYOR_BELT_2_LEFT,
7190 EL_CONVEYOR_BELT_3_LEFT,
7191 EL_CONVEYOR_BELT_4_LEFT
7194 return belt_base_element[belt_nr] + belt_dir_nr;
7197 int getBeltElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
7199 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
7201 return getBeltElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
7204 int getBeltSwitchElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
7206 static int belt_base_element[4] =
7208 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
7209 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
7210 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
7211 EL_CONVEYOR_BELT_4_SWITCH_LEFT
7214 return belt_base_element[belt_nr] + belt_dir_nr;
7217 int getBeltSwitchElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
7219 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
7221 return getBeltSwitchElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
7224 int getNumActivePlayers_EM()
7226 int num_players = 0;
7232 for (i = 0; i < MAX_PLAYERS; i++)
7233 if (tape.player_participates[i])
7239 int getGameFrameDelay_EM(int native_em_game_frame_delay)
7241 int game_frame_delay_value;
7243 game_frame_delay_value =
7244 (tape.playing && tape.fast_forward ? FfwdFrameDelay :
7245 GameFrameDelay == GAME_FRAME_DELAY ? native_em_game_frame_delay :
7248 if (tape.playing && tape.warp_forward && !tape.pausing)
7249 game_frame_delay_value = 0;
7251 return game_frame_delay_value;
7254 unsigned int InitRND(int seed)
7256 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
7257 return InitEngineRandom_EM(seed);
7258 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
7259 return InitEngineRandom_SP(seed);
7261 return InitEngineRandom_RND(seed);
7265 static struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
7266 static struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
7269 inline static int get_effective_element_EM(int tile, int frame_em)
7271 int element = object_mapping[tile].element_rnd;
7272 int action = object_mapping[tile].action;
7273 boolean is_backside = object_mapping[tile].is_backside;
7274 boolean action_removing = (action == ACTION_DIGGING ||
7275 action == ACTION_SNAPPING ||
7276 action == ACTION_COLLECTING);
7282 case Yacid_splash_eB:
7283 case Yacid_splash_wB:
7284 return (frame_em > 5 ? EL_EMPTY : element);
7288 case Ydiamond_stone:
7289 // if (!game.use_native_emc_graphics_engine)
7297 else /* frame_em == 7 */
7301 case Yacid_splash_eB:
7302 case Yacid_splash_wB:
7305 case Yemerald_stone:
7308 case Ydiamond_stone:
7312 case Xdrip_stretchB:
7331 case Xsand_stonein_1:
7332 case Xsand_stonein_2:
7333 case Xsand_stonein_3:
7334 case Xsand_stonein_4:
7338 return (is_backside || action_removing ? EL_EMPTY : element);
7343 inline static boolean check_linear_animation_EM(int tile)
7347 case Xsand_stonesand_1:
7348 case Xsand_stonesand_quickout_1:
7349 case Xsand_sandstone_1:
7350 case Xsand_stonein_1:
7351 case Xsand_stoneout_1:
7371 case Yacid_splash_eB:
7372 case Yacid_splash_wB:
7373 case Yemerald_stone:
7381 inline static void set_crumbled_graphics_EM(struct GraphicInfo_EM *g_em,
7382 boolean has_crumbled_graphics,
7383 int crumbled, int sync_frame)
7385 /* if element can be crumbled, but certain action graphics are just empty
7386 space (like instantly snapping sand to empty space in 1 frame), do not
7387 treat these empty space graphics as crumbled graphics in EMC engine */
7388 if (crumbled == IMG_EMPTY_SPACE)
7389 has_crumbled_graphics = FALSE;
7391 if (has_crumbled_graphics)
7393 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
7394 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
7395 g_crumbled->anim_delay,
7396 g_crumbled->anim_mode,
7397 g_crumbled->anim_start_frame,
7400 getGraphicSource(crumbled, frame_crumbled, &g_em->crumbled_bitmap,
7401 &g_em->crumbled_src_x, &g_em->crumbled_src_y);
7403 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
7405 g_em->has_crumbled_graphics = TRUE;
7409 g_em->crumbled_bitmap = NULL;
7410 g_em->crumbled_src_x = 0;
7411 g_em->crumbled_src_y = 0;
7412 g_em->crumbled_border_size = 0;
7414 g_em->has_crumbled_graphics = FALSE;
7418 void ResetGfxAnimation_EM(int x, int y, int tile)
7423 void SetGfxAnimation_EM(struct GraphicInfo_EM *g_em,
7424 int tile, int frame_em, int x, int y)
7426 int action = object_mapping[tile].action;
7428 int direction = object_mapping[tile].direction;
7429 int effective_element = get_effective_element_EM(tile, frame_em);
7430 int graphic = (direction == MV_NONE ?
7431 el_act2img(effective_element, action) :
7432 el_act_dir2img(effective_element, action, direction));
7433 struct GraphicInfo *g = &graphic_info[graphic];
7436 boolean action_removing = (action == ACTION_DIGGING ||
7437 action == ACTION_SNAPPING ||
7438 action == ACTION_COLLECTING);
7439 boolean action_moving = (action == ACTION_FALLING ||
7440 action == ACTION_MOVING ||
7441 action == ACTION_PUSHING ||
7442 action == ACTION_EATING ||
7443 action == ACTION_FILLING ||
7444 action == ACTION_EMPTYING);
7445 boolean action_falling = (action == ACTION_FALLING ||
7446 action == ACTION_FILLING ||
7447 action == ACTION_EMPTYING);
7449 /* special case: graphic uses "2nd movement tile" and has defined
7450 7 frames for movement animation (or less) => use default graphic
7451 for last (8th) frame which ends the movement animation */
7452 if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
7454 action = ACTION_DEFAULT; /* (keep action_* unchanged for now) */
7455 graphic = (direction == MV_NONE ?
7456 el_act2img(effective_element, action) :
7457 el_act_dir2img(effective_element, action, direction));
7459 g = &graphic_info[graphic];
7463 if (tile == Xsand_stonesand_1 ||
7464 tile == Xsand_stonesand_2 ||
7465 tile == Xsand_stonesand_3 ||
7466 tile == Xsand_stonesand_4)
7467 printf("::: 1: quicksand frame %d [%d]\n", GfxFrame[x][y], tile);
7471 if ((action_removing || check_linear_animation_EM(tile)) && frame_em == 0)
7475 // printf("::: resetting... [%d]\n", tile);
7478 if (action_removing || check_linear_animation_EM(tile))
7480 GfxFrame[x][y] = frame_em;
7482 // printf("::: resetting... [%d]\n", tile);
7485 else if (action_moving)
7487 boolean is_backside = object_mapping[tile].is_backside;
7491 int direction = object_mapping[tile].direction;
7492 int move_dir = (action_falling ? MV_DOWN : direction);
7497 /* !!! TEST !!! NEW !!! DOES NOT WORK RIGHT YET !!! */
7498 if (g->double_movement && frame_em == 0)
7502 // printf("::: resetting... [%d]\n", tile);
7506 if (move_dir == MV_LEFT)
7507 GfxFrame[x - 1][y] = GfxFrame[x][y];
7508 else if (move_dir == MV_RIGHT)
7509 GfxFrame[x + 1][y] = GfxFrame[x][y];
7510 else if (move_dir == MV_UP)
7511 GfxFrame[x][y - 1] = GfxFrame[x][y];
7512 else if (move_dir == MV_DOWN)
7513 GfxFrame[x][y + 1] = GfxFrame[x][y];
7520 /* special case: animation for Xsand_stonesand_quickout_1/2 twice as fast */
7521 if (tile == Xsand_stonesand_quickout_1 ||
7522 tile == Xsand_stonesand_quickout_2)
7527 if (tile == Xsand_stonesand_1 ||
7528 tile == Xsand_stonesand_2 ||
7529 tile == Xsand_stonesand_3 ||
7530 tile == Xsand_stonesand_4)
7531 printf("::: 2: quicksand frame %d [%d]\n", GfxFrame[x][y], tile);
7535 if (graphic_info[graphic].anim_global_sync)
7536 sync_frame = FrameCounter;
7537 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
7538 sync_frame = GfxFrame[x][y];
7540 sync_frame = 0; /* playfield border (pseudo steel) */
7542 SetRandomAnimationValue(x, y);
7544 int frame = getAnimationFrame(g->anim_frames,
7547 g->anim_start_frame,
7550 g_em->unique_identifier =
7551 (graphic << 16) | ((frame % 8) << 12) | (g_em->width << 6) | g_em->height;
7555 void getGraphicSourceObjectExt_EM(struct GraphicInfo_EM *g_em,
7556 int tile, int frame_em, int x, int y)
7558 int action = object_mapping[tile].action;
7559 int direction = object_mapping[tile].direction;
7560 boolean is_backside = object_mapping[tile].is_backside;
7561 int effective_element = get_effective_element_EM(tile, frame_em);
7563 int effective_action = action;
7565 int effective_action = (frame_em < 7 ? action : ACTION_DEFAULT);
7567 int graphic = (direction == MV_NONE ?
7568 el_act2img(effective_element, effective_action) :
7569 el_act_dir2img(effective_element, effective_action,
7571 int crumbled = (direction == MV_NONE ?
7572 el_act2crm(effective_element, effective_action) :
7573 el_act_dir2crm(effective_element, effective_action,
7575 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
7576 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
7577 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
7578 struct GraphicInfo *g = &graphic_info[graphic];
7580 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
7584 /* special case: graphic uses "2nd movement tile" and has defined
7585 7 frames for movement animation (or less) => use default graphic
7586 for last (8th) frame which ends the movement animation */
7587 if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
7589 effective_action = ACTION_DEFAULT;
7590 graphic = (direction == MV_NONE ?
7591 el_act2img(effective_element, effective_action) :
7592 el_act_dir2img(effective_element, effective_action,
7594 crumbled = (direction == MV_NONE ?
7595 el_act2crm(effective_element, effective_action) :
7596 el_act_dir2crm(effective_element, effective_action,
7599 g = &graphic_info[graphic];
7609 if (frame_em == 0) /* reset animation frame for certain elements */
7611 if (check_linear_animation_EM(tile))
7616 if (graphic_info[graphic].anim_global_sync)
7617 sync_frame = FrameCounter;
7618 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
7619 sync_frame = GfxFrame[x][y];
7621 sync_frame = 0; /* playfield border (pseudo steel) */
7623 SetRandomAnimationValue(x, y);
7628 int xxx_sync_frame = (i == Xdrip_stretch ? 7 :
7629 i == Xdrip_stretchB ? 7 :
7630 i == Ydrip_s2 ? j + 8 :
7631 i == Ydrip_s2B ? j + 8 :
7640 i == Xfake_acid_1 ? 0 :
7641 i == Xfake_acid_2 ? 10 :
7642 i == Xfake_acid_3 ? 20 :
7643 i == Xfake_acid_4 ? 30 :
7644 i == Xfake_acid_5 ? 40 :
7645 i == Xfake_acid_6 ? 50 :
7646 i == Xfake_acid_7 ? 60 :
7647 i == Xfake_acid_8 ? 70 :
7649 i == Xball_2B ? j + 8 :
7650 i == Yball_eat ? j + 1 :
7651 i == Ykey_1_eat ? j + 1 :
7652 i == Ykey_2_eat ? j + 1 :
7653 i == Ykey_3_eat ? j + 1 :
7654 i == Ykey_4_eat ? j + 1 :
7655 i == Ykey_5_eat ? j + 1 :
7656 i == Ykey_6_eat ? j + 1 :
7657 i == Ykey_7_eat ? j + 1 :
7658 i == Ykey_8_eat ? j + 1 :
7659 i == Ylenses_eat ? j + 1 :
7660 i == Ymagnify_eat ? j + 1 :
7661 i == Ygrass_eat ? j + 1 :
7662 i == Ydirt_eat ? j + 1 :
7663 i == Xamoeba_1 ? 0 :
7664 i == Xamoeba_2 ? 1 :
7665 i == Xamoeba_3 ? 2 :
7666 i == Xamoeba_4 ? 3 :
7667 i == Xamoeba_5 ? 0 :
7668 i == Xamoeba_6 ? 1 :
7669 i == Xamoeba_7 ? 2 :
7670 i == Xamoeba_8 ? 3 :
7671 i == Xexit_2 ? j + 8 :
7672 i == Xexit_3 ? j + 16 :
7673 i == Xdynamite_1 ? 0 :
7674 i == Xdynamite_2 ? 8 :
7675 i == Xdynamite_3 ? 16 :
7676 i == Xdynamite_4 ? 24 :
7677 i == Xsand_stonein_1 ? j + 1 :
7678 i == Xsand_stonein_2 ? j + 9 :
7679 i == Xsand_stonein_3 ? j + 17 :
7680 i == Xsand_stonein_4 ? j + 25 :
7681 i == Xsand_stoneout_1 && j == 0 ? 0 :
7682 i == Xsand_stoneout_1 && j == 1 ? 0 :
7683 i == Xsand_stoneout_1 && j == 2 ? 1 :
7684 i == Xsand_stoneout_1 && j == 3 ? 2 :
7685 i == Xsand_stoneout_1 && j == 4 ? 2 :
7686 i == Xsand_stoneout_1 && j == 5 ? 3 :
7687 i == Xsand_stoneout_1 && j == 6 ? 4 :
7688 i == Xsand_stoneout_1 && j == 7 ? 4 :
7689 i == Xsand_stoneout_2 && j == 0 ? 5 :
7690 i == Xsand_stoneout_2 && j == 1 ? 6 :
7691 i == Xsand_stoneout_2 && j == 2 ? 7 :
7692 i == Xsand_stoneout_2 && j == 3 ? 8 :
7693 i == Xsand_stoneout_2 && j == 4 ? 9 :
7694 i == Xsand_stoneout_2 && j == 5 ? 11 :
7695 i == Xsand_stoneout_2 && j == 6 ? 13 :
7696 i == Xsand_stoneout_2 && j == 7 ? 15 :
7697 i == Xboom_bug && j == 1 ? 2 :
7698 i == Xboom_bug && j == 2 ? 2 :
7699 i == Xboom_bug && j == 3 ? 4 :
7700 i == Xboom_bug && j == 4 ? 4 :
7701 i == Xboom_bug && j == 5 ? 2 :
7702 i == Xboom_bug && j == 6 ? 2 :
7703 i == Xboom_bug && j == 7 ? 0 :
7704 i == Xboom_bomb && j == 1 ? 2 :
7705 i == Xboom_bomb && j == 2 ? 2 :
7706 i == Xboom_bomb && j == 3 ? 4 :
7707 i == Xboom_bomb && j == 4 ? 4 :
7708 i == Xboom_bomb && j == 5 ? 2 :
7709 i == Xboom_bomb && j == 6 ? 2 :
7710 i == Xboom_bomb && j == 7 ? 0 :
7711 i == Xboom_android && j == 7 ? 6 :
7712 i == Xboom_1 && j == 1 ? 2 :
7713 i == Xboom_1 && j == 2 ? 2 :
7714 i == Xboom_1 && j == 3 ? 4 :
7715 i == Xboom_1 && j == 4 ? 4 :
7716 i == Xboom_1 && j == 5 ? 6 :
7717 i == Xboom_1 && j == 6 ? 6 :
7718 i == Xboom_1 && j == 7 ? 8 :
7719 i == Xboom_2 && j == 0 ? 8 :
7720 i == Xboom_2 && j == 1 ? 8 :
7721 i == Xboom_2 && j == 2 ? 10 :
7722 i == Xboom_2 && j == 3 ? 10 :
7723 i == Xboom_2 && j == 4 ? 10 :
7724 i == Xboom_2 && j == 5 ? 12 :
7725 i == Xboom_2 && j == 6 ? 12 :
7726 i == Xboom_2 && j == 7 ? 12 :
7728 special_animation && j == 4 ? 3 :
7729 effective_action != action ? 0 :
7735 int xxx_effective_action;
7736 int xxx_has_action_graphics;
7739 int element = object_mapping[i].element_rnd;
7740 int action = object_mapping[i].action;
7741 int direction = object_mapping[i].direction;
7742 boolean is_backside = object_mapping[i].is_backside;
7744 boolean action_removing = (action == ACTION_DIGGING ||
7745 action == ACTION_SNAPPING ||
7746 action == ACTION_COLLECTING);
7748 boolean action_exploding = ((action == ACTION_EXPLODING ||
7749 action == ACTION_SMASHED_BY_ROCK ||
7750 action == ACTION_SMASHED_BY_SPRING) &&
7751 element != EL_DIAMOND);
7752 boolean action_active = (action == ACTION_ACTIVE);
7753 boolean action_other = (action == ACTION_OTHER);
7757 int effective_element = get_effective_element_EM(i, j);
7759 int effective_element = (j > 5 && i == Yacid_splash_eB ? EL_EMPTY :
7760 j > 5 && i == Yacid_splash_wB ? EL_EMPTY :
7762 i == Xdrip_stretch ? element :
7763 i == Xdrip_stretchB ? element :
7764 i == Ydrip_s1 ? element :
7765 i == Ydrip_s1B ? element :
7766 i == Xball_1B ? element :
7767 i == Xball_2 ? element :
7768 i == Xball_2B ? element :
7769 i == Yball_eat ? element :
7770 i == Ykey_1_eat ? element :
7771 i == Ykey_2_eat ? element :
7772 i == Ykey_3_eat ? element :
7773 i == Ykey_4_eat ? element :
7774 i == Ykey_5_eat ? element :
7775 i == Ykey_6_eat ? element :
7776 i == Ykey_7_eat ? element :
7777 i == Ykey_8_eat ? element :
7778 i == Ylenses_eat ? element :
7779 i == Ymagnify_eat ? element :
7780 i == Ygrass_eat ? element :
7781 i == Ydirt_eat ? element :
7782 i == Yemerald_stone ? EL_EMERALD :
7783 i == Ydiamond_stone ? EL_ROCK :
7784 i == Xsand_stonein_1 ? element :
7785 i == Xsand_stonein_2 ? element :
7786 i == Xsand_stonein_3 ? element :
7787 i == Xsand_stonein_4 ? element :
7788 is_backside ? EL_EMPTY :
7789 action_removing ? EL_EMPTY :
7792 int effective_action = (j < 7 ? action :
7793 i == Xdrip_stretch ? action :
7794 i == Xdrip_stretchB ? action :
7795 i == Ydrip_s1 ? action :
7796 i == Ydrip_s1B ? action :
7797 i == Xball_1B ? action :
7798 i == Xball_2 ? action :
7799 i == Xball_2B ? action :
7800 i == Yball_eat ? action :
7801 i == Ykey_1_eat ? action :
7802 i == Ykey_2_eat ? action :
7803 i == Ykey_3_eat ? action :
7804 i == Ykey_4_eat ? action :
7805 i == Ykey_5_eat ? action :
7806 i == Ykey_6_eat ? action :
7807 i == Ykey_7_eat ? action :
7808 i == Ykey_8_eat ? action :
7809 i == Ylenses_eat ? action :
7810 i == Ymagnify_eat ? action :
7811 i == Ygrass_eat ? action :
7812 i == Ydirt_eat ? action :
7813 i == Xsand_stonein_1 ? action :
7814 i == Xsand_stonein_2 ? action :
7815 i == Xsand_stonein_3 ? action :
7816 i == Xsand_stonein_4 ? action :
7817 i == Xsand_stoneout_1 ? action :
7818 i == Xsand_stoneout_2 ? action :
7819 i == Xboom_android ? ACTION_EXPLODING :
7820 action_exploding ? ACTION_EXPLODING :
7821 action_active ? action :
7822 action_other ? action :
7824 int graphic = (el_act_dir2img(effective_element, effective_action,
7826 int crumbled = (el_act_dir2crm(effective_element, effective_action,
7828 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
7829 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
7830 boolean has_action_graphics = (graphic != base_graphic);
7831 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
7832 struct GraphicInfo *g = &graphic_info[graphic];
7834 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
7836 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
7839 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
7840 boolean special_animation = (action != ACTION_DEFAULT &&
7841 g->anim_frames == 3 &&
7842 g->anim_delay == 2 &&
7843 g->anim_mode & ANIM_LINEAR);
7844 xxx_sync_frame = (i == Xdrip_stretch ? 7 :
7845 i == Xdrip_stretchB ? 7 :
7846 i == Ydrip_s2 ? j + 8 :
7847 i == Ydrip_s2B ? j + 8 :
7856 i == Xfake_acid_1 ? 0 :
7857 i == Xfake_acid_2 ? 10 :
7858 i == Xfake_acid_3 ? 20 :
7859 i == Xfake_acid_4 ? 30 :
7860 i == Xfake_acid_5 ? 40 :
7861 i == Xfake_acid_6 ? 50 :
7862 i == Xfake_acid_7 ? 60 :
7863 i == Xfake_acid_8 ? 70 :
7865 i == Xball_2B ? j + 8 :
7866 i == Yball_eat ? j + 1 :
7867 i == Ykey_1_eat ? j + 1 :
7868 i == Ykey_2_eat ? j + 1 :
7869 i == Ykey_3_eat ? j + 1 :
7870 i == Ykey_4_eat ? j + 1 :
7871 i == Ykey_5_eat ? j + 1 :
7872 i == Ykey_6_eat ? j + 1 :
7873 i == Ykey_7_eat ? j + 1 :
7874 i == Ykey_8_eat ? j + 1 :
7875 i == Ylenses_eat ? j + 1 :
7876 i == Ymagnify_eat ? j + 1 :
7877 i == Ygrass_eat ? j + 1 :
7878 i == Ydirt_eat ? j + 1 :
7879 i == Xamoeba_1 ? 0 :
7880 i == Xamoeba_2 ? 1 :
7881 i == Xamoeba_3 ? 2 :
7882 i == Xamoeba_4 ? 3 :
7883 i == Xamoeba_5 ? 0 :
7884 i == Xamoeba_6 ? 1 :
7885 i == Xamoeba_7 ? 2 :
7886 i == Xamoeba_8 ? 3 :
7887 i == Xexit_2 ? j + 8 :
7888 i == Xexit_3 ? j + 16 :
7889 i == Xdynamite_1 ? 0 :
7890 i == Xdynamite_2 ? 8 :
7891 i == Xdynamite_3 ? 16 :
7892 i == Xdynamite_4 ? 24 :
7893 i == Xsand_stonein_1 ? j + 1 :
7894 i == Xsand_stonein_2 ? j + 9 :
7895 i == Xsand_stonein_3 ? j + 17 :
7896 i == Xsand_stonein_4 ? j + 25 :
7897 i == Xsand_stoneout_1 && j == 0 ? 0 :
7898 i == Xsand_stoneout_1 && j == 1 ? 0 :
7899 i == Xsand_stoneout_1 && j == 2 ? 1 :
7900 i == Xsand_stoneout_1 && j == 3 ? 2 :
7901 i == Xsand_stoneout_1 && j == 4 ? 2 :
7902 i == Xsand_stoneout_1 && j == 5 ? 3 :
7903 i == Xsand_stoneout_1 && j == 6 ? 4 :
7904 i == Xsand_stoneout_1 && j == 7 ? 4 :
7905 i == Xsand_stoneout_2 && j == 0 ? 5 :
7906 i == Xsand_stoneout_2 && j == 1 ? 6 :
7907 i == Xsand_stoneout_2 && j == 2 ? 7 :
7908 i == Xsand_stoneout_2 && j == 3 ? 8 :
7909 i == Xsand_stoneout_2 && j == 4 ? 9 :
7910 i == Xsand_stoneout_2 && j == 5 ? 11 :
7911 i == Xsand_stoneout_2 && j == 6 ? 13 :
7912 i == Xsand_stoneout_2 && j == 7 ? 15 :
7913 i == Xboom_bug && j == 1 ? 2 :
7914 i == Xboom_bug && j == 2 ? 2 :
7915 i == Xboom_bug && j == 3 ? 4 :
7916 i == Xboom_bug && j == 4 ? 4 :
7917 i == Xboom_bug && j == 5 ? 2 :
7918 i == Xboom_bug && j == 6 ? 2 :
7919 i == Xboom_bug && j == 7 ? 0 :
7920 i == Xboom_bomb && j == 1 ? 2 :
7921 i == Xboom_bomb && j == 2 ? 2 :
7922 i == Xboom_bomb && j == 3 ? 4 :
7923 i == Xboom_bomb && j == 4 ? 4 :
7924 i == Xboom_bomb && j == 5 ? 2 :
7925 i == Xboom_bomb && j == 6 ? 2 :
7926 i == Xboom_bomb && j == 7 ? 0 :
7927 i == Xboom_android && j == 7 ? 6 :
7928 i == Xboom_1 && j == 1 ? 2 :
7929 i == Xboom_1 && j == 2 ? 2 :
7930 i == Xboom_1 && j == 3 ? 4 :
7931 i == Xboom_1 && j == 4 ? 4 :
7932 i == Xboom_1 && j == 5 ? 6 :
7933 i == Xboom_1 && j == 6 ? 6 :
7934 i == Xboom_1 && j == 7 ? 8 :
7935 i == Xboom_2 && j == 0 ? 8 :
7936 i == Xboom_2 && j == 1 ? 8 :
7937 i == Xboom_2 && j == 2 ? 10 :
7938 i == Xboom_2 && j == 3 ? 10 :
7939 i == Xboom_2 && j == 4 ? 10 :
7940 i == Xboom_2 && j == 5 ? 12 :
7941 i == Xboom_2 && j == 6 ? 12 :
7942 i == Xboom_2 && j == 7 ? 12 :
7943 special_animation && j == 4 ? 3 :
7944 effective_action != action ? 0 :
7947 xxx_effective_action = effective_action;
7948 xxx_has_action_graphics = has_action_graphics;
7953 int frame = getAnimationFrame(g->anim_frames,
7956 g->anim_start_frame,
7970 int old_src_x = g_em->src_x;
7971 int old_src_y = g_em->src_y;
7975 getGraphicSourceExt(graphic, frame, &g_em->bitmap, &g_em->src_x, &g_em->src_y,
7976 g->double_movement && is_backside);
7978 getGraphicSourceExt(graphic, frame, &g_em->bitmap,
7979 &g_em->src_x, &g_em->src_y, FALSE);
7984 if (tile == Ydiamond_stone)
7985 printf("::: stone smashing diamond... %d: %d, %d, %d, %d, %d -> %d [%d, %d, %d, %d, %d, %d] [%d]\n",
7990 g->anim_start_frame,
7993 g_em->src_x, g_em->src_y,
7994 g_em->src_offset_x, g_em->src_offset_y,
7995 g_em->dst_offset_x, g_em->dst_offset_y,
8007 if (graphic == IMG_BUG_MOVING_RIGHT)
8008 printf("::: %d, %d, %d: %d, %d [%d, %d -> %d, %d]\n", graphic, x, y,
8009 g->double_movement, is_backside,
8010 old_src_x, old_src_y, g_em->src_x, g_em->src_y);
8018 g_em->src_offset_x = 0;
8019 g_em->src_offset_y = 0;
8020 g_em->dst_offset_x = 0;
8021 g_em->dst_offset_y = 0;
8022 g_em->width = TILEX;
8023 g_em->height = TILEY;
8025 g_em->preserve_background = FALSE;
8028 /* (updating the "crumbled" graphic definitions is probably not really needed,
8029 as animations for crumbled graphics can't be longer than one EMC cycle) */
8031 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
8036 g_em->crumbled_bitmap = NULL;
8037 g_em->crumbled_src_x = 0;
8038 g_em->crumbled_src_y = 0;
8040 g_em->has_crumbled_graphics = FALSE;
8042 if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
8044 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
8045 g_crumbled->anim_delay,
8046 g_crumbled->anim_mode,
8047 g_crumbled->anim_start_frame,
8050 getGraphicSource(crumbled, frame_crumbled, &g_em->crumbled_bitmap,
8051 &g_em->crumbled_src_x, &g_em->crumbled_src_y);
8053 g_em->has_crumbled_graphics = TRUE;
8059 int effective_action = xxx_effective_action;
8060 int has_action_graphics = xxx_has_action_graphics;
8062 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
8063 effective_action == ACTION_MOVING ||
8064 effective_action == ACTION_PUSHING ||
8065 effective_action == ACTION_EATING)) ||
8066 (!has_action_graphics && (effective_action == ACTION_FILLING ||
8067 effective_action == ACTION_EMPTYING)))
8070 (effective_action == ACTION_FALLING ||
8071 effective_action == ACTION_FILLING ||
8072 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
8073 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
8074 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
8075 int num_steps = (i == Ydrip_s1 ? 16 :
8076 i == Ydrip_s1B ? 16 :
8077 i == Ydrip_s2 ? 16 :
8078 i == Ydrip_s2B ? 16 :
8079 i == Xsand_stonein_1 ? 32 :
8080 i == Xsand_stonein_2 ? 32 :
8081 i == Xsand_stonein_3 ? 32 :
8082 i == Xsand_stonein_4 ? 32 :
8083 i == Xsand_stoneout_1 ? 16 :
8084 i == Xsand_stoneout_2 ? 16 : 8);
8085 int cx = ABS(dx) * (TILEX / num_steps);
8086 int cy = ABS(dy) * (TILEY / num_steps);
8087 int step_frame = (i == Ydrip_s2 ? j + 8 :
8088 i == Ydrip_s2B ? j + 8 :
8089 i == Xsand_stonein_2 ? j + 8 :
8090 i == Xsand_stonein_3 ? j + 16 :
8091 i == Xsand_stonein_4 ? j + 24 :
8092 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
8093 int step = (is_backside ? step_frame : num_steps - step_frame);
8095 if (is_backside) /* tile where movement starts */
8097 if (dx < 0 || dy < 0)
8099 g_em->src_offset_x = cx * step;
8100 g_em->src_offset_y = cy * step;
8104 g_em->dst_offset_x = cx * step;
8105 g_em->dst_offset_y = cy * step;
8108 else /* tile where movement ends */
8110 if (dx < 0 || dy < 0)
8112 g_em->dst_offset_x = cx * step;
8113 g_em->dst_offset_y = cy * step;
8117 g_em->src_offset_x = cx * step;
8118 g_em->src_offset_y = cy * step;
8122 g_em->width = TILEX - cx * step;
8123 g_em->height = TILEY - cy * step;
8126 /* create unique graphic identifier to decide if tile must be redrawn */
8127 /* bit 31 - 16 (16 bit): EM style graphic
8128 bit 15 - 12 ( 4 bit): EM style frame
8129 bit 11 - 6 ( 6 bit): graphic width
8130 bit 5 - 0 ( 6 bit): graphic height */
8131 g_em->unique_identifier =
8132 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
8138 void getGraphicSourcePlayerExt_EM(struct GraphicInfo_EM *g_em,
8139 int player_nr, int anim, int frame_em)
8141 int element = player_mapping[player_nr][anim].element_rnd;
8142 int action = player_mapping[player_nr][anim].action;
8143 int direction = player_mapping[player_nr][anim].direction;
8144 int graphic = (direction == MV_NONE ?
8145 el_act2img(element, action) :
8146 el_act_dir2img(element, action, direction));
8147 struct GraphicInfo *g = &graphic_info[graphic];
8150 InitPlayerGfxAnimation(&stored_player[player_nr], action, direction);
8152 stored_player[player_nr].StepFrame = frame_em;
8154 sync_frame = stored_player[player_nr].Frame;
8156 int frame = getAnimationFrame(g->anim_frames,
8159 g->anim_start_frame,
8162 getGraphicSourceExt(graphic, frame, &g_em->bitmap,
8163 &g_em->src_x, &g_em->src_y, FALSE);
8166 printf("::: %d: %d, %d [%d]\n",
8168 stored_player[player_nr].Frame,
8169 stored_player[player_nr].StepFrame,
8174 void InitGraphicInfo_EM(void)
8177 struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
8178 struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
8183 int num_em_gfx_errors = 0;
8185 if (graphic_info_em_object[0][0].bitmap == NULL)
8187 /* EM graphics not yet initialized in em_open_all() */
8192 printf("::: [4 errors can be ignored (1 x 'bomb', 3 x 'em_dynamite']\n");
8195 /* always start with reliable default values */
8196 for (i = 0; i < TILE_MAX; i++)
8198 object_mapping[i].element_rnd = EL_UNKNOWN;
8199 object_mapping[i].is_backside = FALSE;
8200 object_mapping[i].action = ACTION_DEFAULT;
8201 object_mapping[i].direction = MV_NONE;
8204 /* always start with reliable default values */
8205 for (p = 0; p < MAX_PLAYERS; p++)
8207 for (i = 0; i < SPR_MAX; i++)
8209 player_mapping[p][i].element_rnd = EL_UNKNOWN;
8210 player_mapping[p][i].action = ACTION_DEFAULT;
8211 player_mapping[p][i].direction = MV_NONE;
8215 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
8217 int e = em_object_mapping_list[i].element_em;
8219 object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd;
8220 object_mapping[e].is_backside = em_object_mapping_list[i].is_backside;
8222 if (em_object_mapping_list[i].action != -1)
8223 object_mapping[e].action = em_object_mapping_list[i].action;
8225 if (em_object_mapping_list[i].direction != -1)
8226 object_mapping[e].direction =
8227 MV_DIR_FROM_BIT(em_object_mapping_list[i].direction);
8230 for (i = 0; em_player_mapping_list[i].action_em != -1; i++)
8232 int a = em_player_mapping_list[i].action_em;
8233 int p = em_player_mapping_list[i].player_nr;
8235 player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd;
8237 if (em_player_mapping_list[i].action != -1)
8238 player_mapping[p][a].action = em_player_mapping_list[i].action;
8240 if (em_player_mapping_list[i].direction != -1)
8241 player_mapping[p][a].direction =
8242 MV_DIR_FROM_BIT(em_player_mapping_list[i].direction);
8245 for (i = 0; i < TILE_MAX; i++)
8247 int element = object_mapping[i].element_rnd;
8248 int action = object_mapping[i].action;
8249 int direction = object_mapping[i].direction;
8250 boolean is_backside = object_mapping[i].is_backside;
8252 boolean action_removing = (action == ACTION_DIGGING ||
8253 action == ACTION_SNAPPING ||
8254 action == ACTION_COLLECTING);
8256 boolean action_exploding = ((action == ACTION_EXPLODING ||
8257 action == ACTION_SMASHED_BY_ROCK ||
8258 action == ACTION_SMASHED_BY_SPRING) &&
8259 element != EL_DIAMOND);
8260 boolean action_active = (action == ACTION_ACTIVE);
8261 boolean action_other = (action == ACTION_OTHER);
8263 for (j = 0; j < 8; j++)
8266 int effective_element = get_effective_element_EM(i, j);
8268 int effective_element = (j > 5 && i == Yacid_splash_eB ? EL_EMPTY :
8269 j > 5 && i == Yacid_splash_wB ? EL_EMPTY :
8271 i == Xdrip_stretch ? element :
8272 i == Xdrip_stretchB ? element :
8273 i == Ydrip_s1 ? element :
8274 i == Ydrip_s1B ? element :
8275 i == Xball_1B ? element :
8276 i == Xball_2 ? element :
8277 i == Xball_2B ? element :
8278 i == Yball_eat ? element :
8279 i == Ykey_1_eat ? element :
8280 i == Ykey_2_eat ? element :
8281 i == Ykey_3_eat ? element :
8282 i == Ykey_4_eat ? element :
8283 i == Ykey_5_eat ? element :
8284 i == Ykey_6_eat ? element :
8285 i == Ykey_7_eat ? element :
8286 i == Ykey_8_eat ? element :
8287 i == Ylenses_eat ? element :
8288 i == Ymagnify_eat ? element :
8289 i == Ygrass_eat ? element :
8290 i == Ydirt_eat ? element :
8291 i == Yemerald_stone ? EL_EMERALD :
8292 i == Ydiamond_stone ? EL_ROCK :
8293 i == Xsand_stonein_1 ? element :
8294 i == Xsand_stonein_2 ? element :
8295 i == Xsand_stonein_3 ? element :
8296 i == Xsand_stonein_4 ? element :
8297 is_backside ? EL_EMPTY :
8298 action_removing ? EL_EMPTY :
8301 int effective_action = (j < 7 ? action :
8302 i == Xdrip_stretch ? action :
8303 i == Xdrip_stretchB ? action :
8304 i == Ydrip_s1 ? action :
8305 i == Ydrip_s1B ? action :
8306 i == Xball_1B ? action :
8307 i == Xball_2 ? action :
8308 i == Xball_2B ? action :
8309 i == Yball_eat ? action :
8310 i == Ykey_1_eat ? action :
8311 i == Ykey_2_eat ? action :
8312 i == Ykey_3_eat ? action :
8313 i == Ykey_4_eat ? action :
8314 i == Ykey_5_eat ? action :
8315 i == Ykey_6_eat ? action :
8316 i == Ykey_7_eat ? action :
8317 i == Ykey_8_eat ? action :
8318 i == Ylenses_eat ? action :
8319 i == Ymagnify_eat ? action :
8320 i == Ygrass_eat ? action :
8321 i == Ydirt_eat ? action :
8322 i == Xsand_stonein_1 ? action :
8323 i == Xsand_stonein_2 ? action :
8324 i == Xsand_stonein_3 ? action :
8325 i == Xsand_stonein_4 ? action :
8326 i == Xsand_stoneout_1 ? action :
8327 i == Xsand_stoneout_2 ? action :
8328 i == Xboom_android ? ACTION_EXPLODING :
8329 action_exploding ? ACTION_EXPLODING :
8330 action_active ? action :
8331 action_other ? action :
8333 int graphic = (el_act_dir2img(effective_element, effective_action,
8335 int crumbled = (el_act_dir2crm(effective_element, effective_action,
8337 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
8338 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
8339 boolean has_action_graphics = (graphic != base_graphic);
8340 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
8341 struct GraphicInfo *g = &graphic_info[graphic];
8343 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
8345 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
8348 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
8349 boolean special_animation = (action != ACTION_DEFAULT &&
8350 g->anim_frames == 3 &&
8351 g->anim_delay == 2 &&
8352 g->anim_mode & ANIM_LINEAR);
8353 int sync_frame = (i == Xdrip_stretch ? 7 :
8354 i == Xdrip_stretchB ? 7 :
8355 i == Ydrip_s2 ? j + 8 :
8356 i == Ydrip_s2B ? j + 8 :
8365 i == Xfake_acid_1 ? 0 :
8366 i == Xfake_acid_2 ? 10 :
8367 i == Xfake_acid_3 ? 20 :
8368 i == Xfake_acid_4 ? 30 :
8369 i == Xfake_acid_5 ? 40 :
8370 i == Xfake_acid_6 ? 50 :
8371 i == Xfake_acid_7 ? 60 :
8372 i == Xfake_acid_8 ? 70 :
8374 i == Xball_2B ? j + 8 :
8375 i == Yball_eat ? j + 1 :
8376 i == Ykey_1_eat ? j + 1 :
8377 i == Ykey_2_eat ? j + 1 :
8378 i == Ykey_3_eat ? j + 1 :
8379 i == Ykey_4_eat ? j + 1 :
8380 i == Ykey_5_eat ? j + 1 :
8381 i == Ykey_6_eat ? j + 1 :
8382 i == Ykey_7_eat ? j + 1 :
8383 i == Ykey_8_eat ? j + 1 :
8384 i == Ylenses_eat ? j + 1 :
8385 i == Ymagnify_eat ? j + 1 :
8386 i == Ygrass_eat ? j + 1 :
8387 i == Ydirt_eat ? j + 1 :
8388 i == Xamoeba_1 ? 0 :
8389 i == Xamoeba_2 ? 1 :
8390 i == Xamoeba_3 ? 2 :
8391 i == Xamoeba_4 ? 3 :
8392 i == Xamoeba_5 ? 0 :
8393 i == Xamoeba_6 ? 1 :
8394 i == Xamoeba_7 ? 2 :
8395 i == Xamoeba_8 ? 3 :
8396 i == Xexit_2 ? j + 8 :
8397 i == Xexit_3 ? j + 16 :
8398 i == Xdynamite_1 ? 0 :
8399 i == Xdynamite_2 ? 8 :
8400 i == Xdynamite_3 ? 16 :
8401 i == Xdynamite_4 ? 24 :
8402 i == Xsand_stonein_1 ? j + 1 :
8403 i == Xsand_stonein_2 ? j + 9 :
8404 i == Xsand_stonein_3 ? j + 17 :
8405 i == Xsand_stonein_4 ? j + 25 :
8406 i == Xsand_stoneout_1 && j == 0 ? 0 :
8407 i == Xsand_stoneout_1 && j == 1 ? 0 :
8408 i == Xsand_stoneout_1 && j == 2 ? 1 :
8409 i == Xsand_stoneout_1 && j == 3 ? 2 :
8410 i == Xsand_stoneout_1 && j == 4 ? 2 :
8411 i == Xsand_stoneout_1 && j == 5 ? 3 :
8412 i == Xsand_stoneout_1 && j == 6 ? 4 :
8413 i == Xsand_stoneout_1 && j == 7 ? 4 :
8414 i == Xsand_stoneout_2 && j == 0 ? 5 :
8415 i == Xsand_stoneout_2 && j == 1 ? 6 :
8416 i == Xsand_stoneout_2 && j == 2 ? 7 :
8417 i == Xsand_stoneout_2 && j == 3 ? 8 :
8418 i == Xsand_stoneout_2 && j == 4 ? 9 :
8419 i == Xsand_stoneout_2 && j == 5 ? 11 :
8420 i == Xsand_stoneout_2 && j == 6 ? 13 :
8421 i == Xsand_stoneout_2 && j == 7 ? 15 :
8422 i == Xboom_bug && j == 1 ? 2 :
8423 i == Xboom_bug && j == 2 ? 2 :
8424 i == Xboom_bug && j == 3 ? 4 :
8425 i == Xboom_bug && j == 4 ? 4 :
8426 i == Xboom_bug && j == 5 ? 2 :
8427 i == Xboom_bug && j == 6 ? 2 :
8428 i == Xboom_bug && j == 7 ? 0 :
8429 i == Xboom_bomb && j == 1 ? 2 :
8430 i == Xboom_bomb && j == 2 ? 2 :
8431 i == Xboom_bomb && j == 3 ? 4 :
8432 i == Xboom_bomb && j == 4 ? 4 :
8433 i == Xboom_bomb && j == 5 ? 2 :
8434 i == Xboom_bomb && j == 6 ? 2 :
8435 i == Xboom_bomb && j == 7 ? 0 :
8436 i == Xboom_android && j == 7 ? 6 :
8437 i == Xboom_1 && j == 1 ? 2 :
8438 i == Xboom_1 && j == 2 ? 2 :
8439 i == Xboom_1 && j == 3 ? 4 :
8440 i == Xboom_1 && j == 4 ? 4 :
8441 i == Xboom_1 && j == 5 ? 6 :
8442 i == Xboom_1 && j == 6 ? 6 :
8443 i == Xboom_1 && j == 7 ? 8 :
8444 i == Xboom_2 && j == 0 ? 8 :
8445 i == Xboom_2 && j == 1 ? 8 :
8446 i == Xboom_2 && j == 2 ? 10 :
8447 i == Xboom_2 && j == 3 ? 10 :
8448 i == Xboom_2 && j == 4 ? 10 :
8449 i == Xboom_2 && j == 5 ? 12 :
8450 i == Xboom_2 && j == 6 ? 12 :
8451 i == Xboom_2 && j == 7 ? 12 :
8452 special_animation && j == 4 ? 3 :
8453 effective_action != action ? 0 :
8457 Bitmap *debug_bitmap = g_em->bitmap;
8458 int debug_src_x = g_em->src_x;
8459 int debug_src_y = g_em->src_y;
8462 int frame = getAnimationFrame(g->anim_frames,
8465 g->anim_start_frame,
8468 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y,
8469 g->double_movement && is_backside);
8471 g_em->bitmap = src_bitmap;
8472 g_em->src_x = src_x;
8473 g_em->src_y = src_y;
8474 g_em->src_offset_x = 0;
8475 g_em->src_offset_y = 0;
8476 g_em->dst_offset_x = 0;
8477 g_em->dst_offset_y = 0;
8478 g_em->width = TILEX;
8479 g_em->height = TILEY;
8481 g_em->preserve_background = FALSE;
8484 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
8489 g_em->crumbled_bitmap = NULL;
8490 g_em->crumbled_src_x = 0;
8491 g_em->crumbled_src_y = 0;
8492 g_em->crumbled_border_size = 0;
8494 g_em->has_crumbled_graphics = FALSE;
8497 if (has_crumbled_graphics && crumbled == IMG_EMPTY_SPACE)
8498 printf("::: empty crumbled: %d [%s], %d, %d\n",
8499 effective_element, element_info[effective_element].token_name,
8500 effective_action, direction);
8503 /* if element can be crumbled, but certain action graphics are just empty
8504 space (like instantly snapping sand to empty space in 1 frame), do not
8505 treat these empty space graphics as crumbled graphics in EMC engine */
8506 if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
8508 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
8509 g_crumbled->anim_delay,
8510 g_crumbled->anim_mode,
8511 g_crumbled->anim_start_frame,
8514 getGraphicSource(crumbled, frame_crumbled, &src_bitmap, &src_x, &src_y);
8516 g_em->has_crumbled_graphics = TRUE;
8517 g_em->crumbled_bitmap = src_bitmap;
8518 g_em->crumbled_src_x = src_x;
8519 g_em->crumbled_src_y = src_y;
8520 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
8524 if (g_em == &graphic_info_em_object[207][0])
8525 printf("... %d, %d [%d, %d, %d, %d] [%d, %d, %d, %d, %d, %d => %d]\n",
8526 graphic_info_em_object[207][0].crumbled_src_x,
8527 graphic_info_em_object[207][0].crumbled_src_y,
8529 crumbled, frame, src_x, src_y,
8534 g->anim_start_frame,
8536 gfx.anim_random_frame,
8541 printf("::: EMC tile %d is crumbled\n", i);
8547 if (element == EL_ROCK &&
8548 effective_action == ACTION_FILLING)
8549 printf("::: has_action_graphics == %d\n", has_action_graphics);
8552 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
8553 effective_action == ACTION_MOVING ||
8554 effective_action == ACTION_PUSHING ||
8555 effective_action == ACTION_EATING)) ||
8556 (!has_action_graphics && (effective_action == ACTION_FILLING ||
8557 effective_action == ACTION_EMPTYING)))
8560 (effective_action == ACTION_FALLING ||
8561 effective_action == ACTION_FILLING ||
8562 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
8563 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
8564 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
8565 int num_steps = (i == Ydrip_s1 ? 16 :
8566 i == Ydrip_s1B ? 16 :
8567 i == Ydrip_s2 ? 16 :
8568 i == Ydrip_s2B ? 16 :
8569 i == Xsand_stonein_1 ? 32 :
8570 i == Xsand_stonein_2 ? 32 :
8571 i == Xsand_stonein_3 ? 32 :
8572 i == Xsand_stonein_4 ? 32 :
8573 i == Xsand_stoneout_1 ? 16 :
8574 i == Xsand_stoneout_2 ? 16 : 8);
8575 int cx = ABS(dx) * (TILEX / num_steps);
8576 int cy = ABS(dy) * (TILEY / num_steps);
8577 int step_frame = (i == Ydrip_s2 ? j + 8 :
8578 i == Ydrip_s2B ? j + 8 :
8579 i == Xsand_stonein_2 ? j + 8 :
8580 i == Xsand_stonein_3 ? j + 16 :
8581 i == Xsand_stonein_4 ? j + 24 :
8582 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
8583 int step = (is_backside ? step_frame : num_steps - step_frame);
8585 if (is_backside) /* tile where movement starts */
8587 if (dx < 0 || dy < 0)
8589 g_em->src_offset_x = cx * step;
8590 g_em->src_offset_y = cy * step;
8594 g_em->dst_offset_x = cx * step;
8595 g_em->dst_offset_y = cy * step;
8598 else /* tile where movement ends */
8600 if (dx < 0 || dy < 0)
8602 g_em->dst_offset_x = cx * step;
8603 g_em->dst_offset_y = cy * step;
8607 g_em->src_offset_x = cx * step;
8608 g_em->src_offset_y = cy * step;
8612 g_em->width = TILEX - cx * step;
8613 g_em->height = TILEY - cy * step;
8616 /* create unique graphic identifier to decide if tile must be redrawn */
8617 /* bit 31 - 16 (16 bit): EM style graphic
8618 bit 15 - 12 ( 4 bit): EM style frame
8619 bit 11 - 6 ( 6 bit): graphic width
8620 bit 5 - 0 ( 6 bit): graphic height */
8621 g_em->unique_identifier =
8622 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
8626 /* skip check for EMC elements not contained in original EMC artwork */
8627 if (element == EL_EMC_FAKE_ACID)
8630 if (g_em->bitmap != debug_bitmap ||
8631 g_em->src_x != debug_src_x ||
8632 g_em->src_y != debug_src_y ||
8633 g_em->src_offset_x != 0 ||
8634 g_em->src_offset_y != 0 ||
8635 g_em->dst_offset_x != 0 ||
8636 g_em->dst_offset_y != 0 ||
8637 g_em->width != TILEX ||
8638 g_em->height != TILEY)
8640 static int last_i = -1;
8648 printf("::: EMC GFX ERROR for element %d -> %d ('%s', '%s', %d)",
8649 i, element, element_info[element].token_name,
8650 element_action_info[effective_action].suffix, direction);
8652 if (element != effective_element)
8653 printf(" [%d ('%s')]",
8655 element_info[effective_element].token_name);
8659 if (g_em->bitmap != debug_bitmap)
8660 printf(" %d (%d): different bitmap! (0x%08x != 0x%08x)\n",
8661 j, is_backside, (int)(g_em->bitmap), (int)(debug_bitmap));
8663 if (g_em->src_x != debug_src_x ||
8664 g_em->src_y != debug_src_y)
8665 printf(" frame %d (%c): %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
8666 j, (is_backside ? 'B' : 'F'),
8667 g_em->src_x, g_em->src_y,
8668 g_em->src_x / 32, g_em->src_y / 32,
8669 debug_src_x, debug_src_y,
8670 debug_src_x / 32, debug_src_y / 32);
8672 if (g_em->src_offset_x != 0 ||
8673 g_em->src_offset_y != 0 ||
8674 g_em->dst_offset_x != 0 ||
8675 g_em->dst_offset_y != 0)
8676 printf(" %d (%d): offsets %d,%d and %d,%d should be all 0\n",
8678 g_em->src_offset_x, g_em->src_offset_y,
8679 g_em->dst_offset_x, g_em->dst_offset_y);
8681 if (g_em->width != TILEX ||
8682 g_em->height != TILEY)
8683 printf(" %d (%d): size %d,%d should be %d,%d\n",
8685 g_em->width, g_em->height, TILEX, TILEY);
8687 num_em_gfx_errors++;
8694 for (i = 0; i < TILE_MAX; i++)
8696 for (j = 0; j < 8; j++)
8698 int element = object_mapping[i].element_rnd;
8699 int action = object_mapping[i].action;
8700 int direction = object_mapping[i].direction;
8701 boolean is_backside = object_mapping[i].is_backside;
8702 int graphic_action = el_act_dir2img(element, action, direction);
8703 int graphic_default = el_act_dir2img(element, ACTION_DEFAULT, direction);
8705 if ((action == ACTION_SMASHED_BY_ROCK ||
8706 action == ACTION_SMASHED_BY_SPRING ||
8707 action == ACTION_EATING) &&
8708 graphic_action == graphic_default)
8710 int e = (action == ACTION_SMASHED_BY_ROCK ? Ystone_s :
8711 action == ACTION_SMASHED_BY_SPRING ? Yspring_s :
8712 direction == MV_LEFT ? (is_backside? Yspring_wB: Yspring_w) :
8713 direction == MV_RIGHT ? (is_backside? Yspring_eB: Yspring_e) :
8716 /* no separate animation for "smashed by rock" -- use rock instead */
8717 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
8718 struct GraphicInfo_EM *g_xx = &graphic_info_em_object[e][7 - j];
8720 g_em->bitmap = g_xx->bitmap;
8721 g_em->src_x = g_xx->src_x;
8722 g_em->src_y = g_xx->src_y;
8723 g_em->src_offset_x = g_xx->src_offset_x;
8724 g_em->src_offset_y = g_xx->src_offset_y;
8725 g_em->dst_offset_x = g_xx->dst_offset_x;
8726 g_em->dst_offset_y = g_xx->dst_offset_y;
8727 g_em->width = g_xx->width;
8728 g_em->height = g_xx->height;
8729 g_em->unique_identifier = g_xx->unique_identifier;
8732 g_em->preserve_background = TRUE;
8737 for (p = 0; p < MAX_PLAYERS; p++)
8739 for (i = 0; i < SPR_MAX; i++)
8741 int element = player_mapping[p][i].element_rnd;
8742 int action = player_mapping[p][i].action;
8743 int direction = player_mapping[p][i].direction;
8745 for (j = 0; j < 8; j++)
8747 int effective_element = element;
8748 int effective_action = action;
8749 int graphic = (direction == MV_NONE ?
8750 el_act2img(effective_element, effective_action) :
8751 el_act_dir2img(effective_element, effective_action,
8753 struct GraphicInfo *g = &graphic_info[graphic];
8754 struct GraphicInfo_EM *g_em = &graphic_info_em_player[p][i][7 - j];
8760 Bitmap *debug_bitmap = g_em->bitmap;
8761 int debug_src_x = g_em->src_x;
8762 int debug_src_y = g_em->src_y;
8765 int frame = getAnimationFrame(g->anim_frames,
8768 g->anim_start_frame,
8771 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
8773 g_em->bitmap = src_bitmap;
8774 g_em->src_x = src_x;
8775 g_em->src_y = src_y;
8776 g_em->src_offset_x = 0;
8777 g_em->src_offset_y = 0;
8778 g_em->dst_offset_x = 0;
8779 g_em->dst_offset_y = 0;
8780 g_em->width = TILEX;
8781 g_em->height = TILEY;
8785 /* skip check for EMC elements not contained in original EMC artwork */
8786 if (element == EL_PLAYER_3 ||
8787 element == EL_PLAYER_4)
8790 if (g_em->bitmap != debug_bitmap ||
8791 g_em->src_x != debug_src_x ||
8792 g_em->src_y != debug_src_y)
8794 static int last_i = -1;
8802 printf("::: EMC GFX ERROR for p/a %d/%d -> %d ('%s', '%s', %d)",
8803 p, i, element, element_info[element].token_name,
8804 element_action_info[effective_action].suffix, direction);
8806 if (element != effective_element)
8807 printf(" [%d ('%s')]",
8809 element_info[effective_element].token_name);
8813 if (g_em->bitmap != debug_bitmap)
8814 printf(" %d: different bitmap! (0x%08x != 0x%08x)\n",
8815 j, (int)(g_em->bitmap), (int)(debug_bitmap));
8817 if (g_em->src_x != debug_src_x ||
8818 g_em->src_y != debug_src_y)
8819 printf(" frame %d: %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
8821 g_em->src_x, g_em->src_y,
8822 g_em->src_x / 32, g_em->src_y / 32,
8823 debug_src_x, debug_src_y,
8824 debug_src_x / 32, debug_src_y / 32);
8826 num_em_gfx_errors++;
8836 printf("::: [%d errors found]\n", num_em_gfx_errors);
8842 void CheckSingleStepMode_EM(byte action[MAX_PLAYERS], int frame,
8843 boolean any_player_moving,
8844 boolean player_is_dropping)
8846 if (tape.single_step && tape.recording && !tape.pausing)
8849 boolean active_players = FALSE;
8852 for (i = 0; i < MAX_PLAYERS; i++)
8853 if (action[i] != JOY_NO_ACTION)
8854 active_players = TRUE;
8858 if (frame == 0 && !player_is_dropping)
8859 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
8863 void CheckSingleStepMode_SP(boolean murphy_is_waiting,
8864 boolean murphy_is_dropping)
8867 printf("::: waiting: %d, dropping: %d\n",
8868 murphy_is_waiting, murphy_is_dropping);
8871 if (tape.single_step && tape.recording && !tape.pausing)
8873 // if (murphy_is_waiting || murphy_is_dropping)
8874 if (murphy_is_waiting)
8877 printf("::: murphy is waiting -> pause mode\n");
8880 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
8885 void getGraphicSource_SP(struct GraphicInfo_SP *g_sp,
8886 int graphic, int sync_frame, int x, int y)
8888 int frame = getGraphicAnimationFrame(graphic, sync_frame);
8890 getGraphicSource(graphic, frame, &g_sp->bitmap, &g_sp->src_x, &g_sp->src_y);
8893 boolean isNextAnimationFrame_SP(int graphic, int sync_frame)
8895 return (IS_NEXT_FRAME(sync_frame, graphic));
8898 int getGraphicInfo_Delay(int graphic)
8900 return graphic_info[graphic].anim_delay;
8903 void PlayMenuSoundExt(int sound)
8905 if (sound == SND_UNDEFINED)
8908 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
8909 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
8912 if (IS_LOOP_SOUND(sound))
8913 PlaySoundLoop(sound);
8918 void PlayMenuSound()
8920 PlayMenuSoundExt(menu.sound[game_status]);
8923 void PlayMenuSoundStereo(int sound, int stereo_position)
8925 if (sound == SND_UNDEFINED)
8928 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
8929 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
8932 if (IS_LOOP_SOUND(sound))
8933 PlaySoundExt(sound, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_LOOP);
8935 PlaySoundStereo(sound, stereo_position);
8938 void PlayMenuSoundIfLoopExt(int sound)
8940 if (sound == SND_UNDEFINED)
8943 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
8944 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
8947 if (IS_LOOP_SOUND(sound))
8948 PlaySoundLoop(sound);
8951 void PlayMenuSoundIfLoop()
8953 PlayMenuSoundIfLoopExt(menu.sound[game_status]);
8956 void PlayMenuMusicExt(int music)
8958 if (music == MUS_UNDEFINED)
8961 if (!setup.sound_music)
8967 void PlayMenuMusic()
8969 PlayMenuMusicExt(menu.music[game_status]);
8972 void PlaySoundActivating()
8975 PlaySound(SND_MENU_ITEM_ACTIVATING);
8979 void PlaySoundSelecting()
8982 PlaySound(SND_MENU_ITEM_SELECTING);
8986 void ToggleFullscreenIfNeeded()
8988 boolean change_fullscreen = (setup.fullscreen !=
8989 video.fullscreen_enabled);
8990 boolean change_fullscreen_mode = (video.fullscreen_enabled &&
8991 !strEqual(setup.fullscreen_mode,
8992 video.fullscreen_mode_current));
8993 boolean change_window_scaling_percent = (!video.fullscreen_enabled &&
8994 setup.window_scaling_percent !=
8995 video.window_scaling_percent);
8997 if (change_window_scaling_percent && video.fullscreen_enabled)
9000 if (!change_window_scaling_percent && !video.fullscreen_available)
9003 if (change_fullscreen ||
9004 change_fullscreen_mode ||
9005 change_window_scaling_percent)
9007 Bitmap *tmp_backbuffer = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
9009 /* save backbuffer content which gets lost when toggling fullscreen mode */
9010 BlitBitmap(backbuffer, tmp_backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
9012 if (change_fullscreen_mode)
9014 /* keep fullscreen, but change fullscreen mode (screen resolution) */
9015 video.fullscreen_enabled = FALSE; /* force new fullscreen mode */
9018 if (change_window_scaling_percent)
9020 /* keep window mode, but change window scaling */
9021 video.fullscreen_enabled = TRUE; /* force new window scaling */
9024 /* toggle fullscreen */
9025 ChangeVideoModeIfNeeded(setup.fullscreen);
9027 /* set setup value according to successfully enabled fullscreen mode */
9028 setup.fullscreen = video.fullscreen_enabled;
9030 /* restore backbuffer content from temporary backbuffer backup bitmap */
9031 BlitBitmap(tmp_backbuffer, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
9033 FreeBitmap(tmp_backbuffer);
9036 /* update visible window/screen */
9037 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
9039 redraw_mask = REDRAW_ALL;
9044 void ChangeViewportPropertiesIfNeeded()
9046 int *door_1_x = &DX;
9047 int *door_1_y = &DY;
9048 int *door_2_x = (game_status == GAME_MODE_EDITOR ? &EX : &VX);
9049 int *door_2_y = (game_status == GAME_MODE_EDITOR ? &EY : &VY);
9050 int gfx_game_mode = (game_status == GAME_MODE_PLAYING ||
9051 game_status == GAME_MODE_EDITOR ? game_status :
9053 struct RectWithBorder *vp_playfield = &viewport.playfield[gfx_game_mode];
9054 struct RectWithBorder *vp_door_1 = &viewport.door_1[gfx_game_mode];
9055 struct RectWithBorder *vp_door_2 = &viewport.door_2[gfx_game_mode];
9056 int border_size = vp_playfield->border_size;
9057 int new_sx = vp_playfield->x + border_size;
9058 int new_sy = vp_playfield->y + border_size;
9059 int new_sxsize = vp_playfield->width - 2 * border_size;
9060 int new_sysize = vp_playfield->height - 2 * border_size;
9061 int new_real_sx = vp_playfield->x;
9062 int new_real_sy = vp_playfield->y;
9063 int new_full_sxsize = vp_playfield->width;
9064 int new_full_sysize = vp_playfield->height;
9066 int new_tilesize_var = TILESIZE / (setup.small_game_graphics ? 2 : 1);
9067 int tilesize = (gfx_game_mode == GAME_MODE_PLAYING ? new_tilesize_var :
9068 gfx_game_mode == GAME_MODE_EDITOR ? MINI_TILESIZE : TILESIZE);
9069 int new_scr_fieldx = new_sxsize / tilesize;
9070 int new_scr_fieldy = new_sysize / tilesize;
9071 int new_scr_fieldx_buffers = new_sxsize / new_tilesize_var;
9072 int new_scr_fieldy_buffers = new_sysize / new_tilesize_var;
9074 int new_scr_fieldx = (vp_playfield->width - 2 * border_size) / TILESIZE;
9075 int new_scr_fieldy = (vp_playfield->height - 2 * border_size) / TILESIZE;
9077 boolean init_gfx_buffers = FALSE;
9078 boolean init_video_buffer = FALSE;
9079 boolean init_gadgets_and_toons = FALSE;
9082 /* !!! TEST ONLY !!! */
9083 // InitGfxBuffers();
9087 if (viewport.window.width != WIN_XSIZE ||
9088 viewport.window.height != WIN_YSIZE)
9090 WIN_XSIZE = viewport.window.width;
9091 WIN_YSIZE = viewport.window.height;
9094 init_video_buffer = TRUE;
9095 init_gfx_buffers = TRUE;
9097 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
9101 SetDrawDeactivationMask(REDRAW_NONE);
9102 SetDrawBackgroundMask(REDRAW_FIELD);
9104 // RedrawBackground();
9108 // printf("::: video: init_video_buffer, init_gfx_buffers\n");
9111 if (new_scr_fieldx != SCR_FIELDX ||
9112 new_scr_fieldy != SCR_FIELDY)
9114 /* this always toggles between MAIN and GAME when using small tile size */
9116 SCR_FIELDX = new_scr_fieldx;
9117 SCR_FIELDY = new_scr_fieldy;
9119 // printf("::: new_scr_fieldx != SCR_FIELDX ...\n");
9123 if (new_tilesize_var != TILESIZE_VAR &&
9124 gfx_game_mode == GAME_MODE_PLAYING)
9126 /* doing this outside GAME_MODE_PLAYING would give wrong playfield size */
9128 TILESIZE_VAR = new_tilesize_var;
9130 init_gfx_buffers = TRUE;
9132 // printf("::: tilesize: init_gfx_buffers\n");
9138 new_sxsize != SXSIZE ||
9139 new_sysize != SYSIZE ||
9140 new_real_sx != REAL_SX ||
9141 new_real_sy != REAL_SY ||
9142 new_full_sxsize != FULL_SXSIZE ||
9143 new_full_sysize != FULL_SYSIZE ||
9144 new_tilesize_var != TILESIZE_VAR ||
9145 vp_door_1->x != *door_1_x ||
9146 vp_door_1->y != *door_1_y ||
9147 vp_door_2->x != *door_2_x ||
9148 vp_door_2->y != *door_2_y)
9152 SXSIZE = new_sxsize;
9153 SYSIZE = new_sysize;
9154 REAL_SX = new_real_sx;
9155 REAL_SY = new_real_sy;
9156 FULL_SXSIZE = new_full_sxsize;
9157 FULL_SYSIZE = new_full_sysize;
9158 TILESIZE_VAR = new_tilesize_var;
9161 printf("::: %d, %d, %d [%d]\n",
9162 SCR_FIELDX, SCR_FIELDY, TILESIZE_VAR,
9163 setup.small_game_graphics);
9166 *door_1_x = vp_door_1->x;
9167 *door_1_y = vp_door_1->y;
9168 *door_2_x = vp_door_2->x;
9169 *door_2_y = vp_door_2->y;
9172 init_gfx_buffers = TRUE;
9174 // printf("::: viewports: init_gfx_buffers\n");
9179 if (gfx_game_mode == GAME_MODE_MAIN)
9182 init_gadgets_and_toons = TRUE;
9184 // printf("::: viewports: init_gadgets_and_toons\n");
9192 if (init_gfx_buffers)
9194 // printf("::: init_gfx_buffers\n");
9196 SCR_FIELDX = new_scr_fieldx_buffers;
9197 SCR_FIELDY = new_scr_fieldy_buffers;
9201 SCR_FIELDX = new_scr_fieldx;
9202 SCR_FIELDY = new_scr_fieldy;
9205 if (init_video_buffer)
9207 // printf("::: init_video_buffer\n");
9209 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
9211 SetDrawDeactivationMask(REDRAW_NONE);
9212 SetDrawBackgroundMask(REDRAW_FIELD);
9215 if (init_gadgets_and_toons)
9217 // printf("::: init_gadgets_and_toons\n");
9224 printf("::: %d, %d / %d, %d [%d]\n", VX, VY, EX, EY, game_status);