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 if (redraw_mask & REDRAW_TILES)
403 redraw_mask |= REDRAW_FIELD;
407 /* !!! TEST ONLY !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */
408 /* (force full redraw) */
409 if (game_status == GAME_MODE_PLAYING)
410 redraw_mask |= REDRAW_FIELD;
413 if (redraw_mask & REDRAW_FIELD)
414 redraw_mask &= ~REDRAW_TILES;
416 if (redraw_mask == REDRAW_NONE)
421 if (redraw_mask & REDRAW_ALL)
422 printf("[REDRAW_ALL]");
423 if (redraw_mask & REDRAW_FIELD)
424 printf("[REDRAW_FIELD]");
425 if (redraw_mask & REDRAW_TILES)
426 printf("[REDRAW_TILES]");
427 if (redraw_mask & REDRAW_DOOR_1)
428 printf("[REDRAW_DOOR_1]");
429 if (redraw_mask & REDRAW_DOOR_2)
430 printf("[REDRAW_DOOR_2]");
431 if (redraw_mask & REDRAW_FROM_BACKBUFFER)
432 printf("[REDRAW_FROM_BACKBUFFER]");
433 printf(" [%d]\n", FrameCounter);
436 if (redraw_mask & REDRAW_TILES &&
437 game_status == GAME_MODE_PLAYING &&
438 border.draw_masked[GAME_MODE_PLAYING])
439 redraw_mask |= REDRAW_FIELD;
441 if (global.fps_slowdown && game_status == GAME_MODE_PLAYING)
443 static boolean last_frame_skipped = FALSE;
444 boolean skip_even_when_not_scrolling = TRUE;
445 boolean just_scrolling = (ScreenMovDir != 0);
446 boolean verbose = FALSE;
448 if (global.fps_slowdown_factor > 1 &&
449 (FrameCounter % global.fps_slowdown_factor) &&
450 (just_scrolling || skip_even_when_not_scrolling))
452 redraw_mask &= ~REDRAW_MAIN;
454 last_frame_skipped = TRUE;
457 printf("FRAME SKIPPED\n");
461 if (last_frame_skipped)
462 redraw_mask |= REDRAW_FIELD;
464 last_frame_skipped = FALSE;
467 printf("frame not skipped\n");
471 /* synchronize X11 graphics at this point; if we would synchronize the
472 display immediately after the buffer switching (after the XFlush),
473 this could mean that we have to wait for the graphics to complete,
474 although we could go on doing calculations for the next frame */
478 /* never draw masked border to backbuffer when using playfield buffer */
479 if (game_status != GAME_MODE_PLAYING ||
480 redraw_mask & REDRAW_FROM_BACKBUFFER ||
481 buffer == backbuffer)
482 DrawMaskedBorder(redraw_mask);
484 DrawMaskedBorder(redraw_mask & REDRAW_DOORS);
486 if (redraw_mask & REDRAW_ALL)
488 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
490 redraw_mask = REDRAW_NONE;
493 if (redraw_mask & REDRAW_FIELD)
496 printf("::: REDRAW_FIELD\n");
499 if (game_status != GAME_MODE_PLAYING ||
500 redraw_mask & REDRAW_FROM_BACKBUFFER)
502 BlitBitmap(backbuffer, window,
503 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE, REAL_SX, REAL_SY);
508 BlitScreenToBitmap(window);
510 int fx = FX, fy = FY;
513 int dx = (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
514 int dy = (ScreenMovDir & (MV_UP | MV_DOWN) ? ScreenGfxPos : 0);
515 int dx_var = dx * TILESIZE_VAR / TILESIZE;
516 int dy_var = dy * TILESIZE_VAR / TILESIZE;
519 // fx += dx * TILESIZE_VAR / TILESIZE;
520 // fy += dy * TILESIZE_VAR / TILESIZE;
522 fx += (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
523 fy += (ScreenMovDir & (MV_UP | MV_DOWN) ? ScreenGfxPos : 0);
526 /* !!! THIS WORKS !!! */
528 printf("::: %d, %d\n", scroll_x, scroll_y);
530 ffx = (scroll_x - SBX_Left) * TILEX_VAR + dx_var;
531 ffy = (scroll_y - SBY_Upper) * TILEY_VAR + dy_var;
533 if (EVEN(SCR_FIELDX))
535 if (ffx < SBX_Right * TILEX_VAR + TILEX_VAR / 2 + TILEX_VAR)
536 fx += dx_var - MIN(ffx, TILEX_VAR / 2) + TILEX_VAR;
538 fx += (dx > 0 ? TILEX_VAR : 0);
545 if (EVEN(SCR_FIELDY))
547 if (ffy < SBY_Lower * TILEY_VAR + TILEY_VAR / 2 + TILEY_VAR)
548 fy += dy_var - MIN(ffy, TILEY_VAR / 2) + TILEY_VAR;
550 fy += (dy > 0 ? TILEY_VAR : 0);
557 if (border.draw_masked[GAME_MODE_PLAYING])
559 if (buffer != backbuffer)
561 /* copy playfield buffer to backbuffer to add masked border */
562 BlitBitmap(buffer, backbuffer, fx, fy, SXSIZE, SYSIZE, SX, SY);
563 DrawMaskedBorder(REDRAW_FIELD);
566 BlitBitmap(backbuffer, window,
567 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
572 BlitBitmap(buffer, window, fx, fy, SXSIZE, SYSIZE, SX, SY);
578 printf("redrawing all (ScreenGfxPos == %d) because %s\n",
580 (setup.soft_scrolling ?
581 "setup.soft_scrolling" :
582 ABS(ScreenGfxPos) + ScrollStepSize == TILEX ?
583 "ABS(ScreenGfxPos) + ScrollStepSize == TILEX" :
584 ABS(ScreenGfxPos) == ScrollStepSize ?
585 "ABS(ScreenGfxPos) == ScrollStepSize" :
586 "redraw_tiles > REDRAWTILES_THRESHOLD"));
591 redraw_mask &= ~REDRAW_MAIN;
594 if (redraw_mask & REDRAW_DOORS)
596 if (redraw_mask & REDRAW_DOOR_1)
597 BlitBitmap(backbuffer, window, DX, DY, DXSIZE, DYSIZE, DX, DY);
599 if (redraw_mask & REDRAW_DOOR_2)
600 BlitBitmap(backbuffer, window, VX, VY, VXSIZE, VYSIZE, VX, VY);
602 if (redraw_mask & REDRAW_DOOR_3)
603 BlitBitmap(backbuffer, window, EX, EY, EXSIZE, EYSIZE, EX, EY);
605 redraw_mask &= ~REDRAW_DOORS;
608 if (redraw_mask & REDRAW_MICROLEVEL)
610 BlitBitmap(backbuffer, window, SX, SY + 10 * TILEY, SXSIZE, 7 * TILEY,
611 SX, SY + 10 * TILEY);
613 redraw_mask &= ~REDRAW_MICROLEVEL;
616 if (redraw_mask & REDRAW_TILES)
619 printf("::: REDRAW_TILES\n");
625 InitGfxClipRegion(TRUE, SX, SY, SXSIZE, SYSIZE);
628 int sx = SX; // - (EVEN(SCR_FIELDX) ? TILEX_VAR / 2 : 0);
629 int sy = SY; // + (EVEN(SCR_FIELDY) ? TILEY_VAR / 2 : 0);
632 int dx_var = dx * TILESIZE_VAR / TILESIZE;
633 int dy_var = dy * TILESIZE_VAR / TILESIZE;
635 int fx = FX, fy = FY;
637 int scr_fieldx = SCR_FIELDX + (EVEN(SCR_FIELDX) ? 2 : 0);
638 int scr_fieldy = SCR_FIELDY + (EVEN(SCR_FIELDY) ? 2 : 0);
640 ffx = (scroll_x - SBX_Left) * TILEX_VAR + dx_var;
641 ffy = (scroll_y - SBY_Upper) * TILEY_VAR + dy_var;
643 if (EVEN(SCR_FIELDX))
645 if (ffx < SBX_Right * TILEX_VAR + TILEX_VAR / 2 + TILEX_VAR)
647 fx += dx_var - MIN(ffx, TILEX_VAR / 2) + TILEX_VAR;
656 fx += (dx_var > 0 ? TILEX_VAR : 0);
660 if (EVEN(SCR_FIELDY))
662 if (ffy < SBY_Lower * TILEY_VAR + TILEY_VAR / 2 + TILEY_VAR)
664 fy += dy_var - MIN(ffy, TILEY_VAR / 2) + TILEY_VAR;
673 fy += (dy_var > 0 ? TILEY_VAR : 0);
678 printf("::: %d, %d, %d, %d\n", sx, sy, SCR_FIELDX, SCR_FIELDY);
681 for (x = 0; x < scr_fieldx; x++)
682 for (y = 0 ; y < scr_fieldy; y++)
683 if (redraw[redraw_x1 + x][redraw_y1 + y])
684 BlitBitmap(buffer, window,
685 FX + x * TILEX_VAR, FY + y * TILEY_VAR,
686 TILEX_VAR, TILEY_VAR,
687 sx + x * TILEX_VAR, sy + y * TILEY_VAR);
690 InitGfxClipRegion(FALSE, -1, -1, -1, -1);
692 for (x = 0; x < SCR_FIELDX; x++)
693 for (y = 0 ; y < SCR_FIELDY; y++)
694 if (redraw[redraw_x1 + x][redraw_y1 + y])
695 BlitBitmap(buffer, window,
696 FX + x * TILEX_VAR, FY + y * TILEY_VAR,
697 TILEX_VAR, TILEY_VAR,
698 SX + x * TILEX_VAR, SY + y * TILEY_VAR);
702 for (x = 0; x < SCR_FIELDX; x++)
703 for (y = 0 ; y < SCR_FIELDY; y++)
704 if (redraw[redraw_x1 + x][redraw_y1 + y])
705 BlitBitmap(buffer, window,
706 FX + x * TILEX, FY + y * TILEY, TILEX, TILEY,
707 SX + x * TILEX, SY + y * TILEY);
711 if (redraw_mask & REDRAW_FPS) /* display frames per second */
716 sprintf(info1, " (only every %d. frame)", global.fps_slowdown_factor);
717 if (!global.fps_slowdown)
720 sprintf(text, "%04.1f fps%s", global.frames_per_second, info1);
722 DrawTextExt(window, SX + SXSIZE + SX, 0, text, FONT_TEXT_2, BLIT_OPAQUE);
724 DrawTextExt(window, SX, SY, text, FONT_TEXT_2, BLIT_OPAQUE);
730 for (x = 0; x < MAX_BUF_XSIZE; x++)
731 for (y = 0; y < MAX_BUF_YSIZE; y++)
734 redraw_mask = REDRAW_NONE;
737 static void FadeCrossSaveBackbuffer()
739 BlitBitmap(backbuffer, bitmap_db_cross, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
742 static void FadeExt(int fade_mask, int fade_mode, int fade_type)
744 static int fade_type_skip = FADE_TYPE_NONE;
745 void (*draw_border_function)(void) = NULL;
746 Bitmap *bitmap = (fade_mode & FADE_TYPE_TRANSFORM ? bitmap_db_cross : NULL);
747 int x, y, width, height;
748 int fade_delay, post_delay;
750 if (fade_type == FADE_TYPE_FADE_OUT)
752 if (fade_type_skip != FADE_TYPE_NONE)
755 printf("::: skipping %d ... [%d] (X)\n", fade_mode, fade_type_skip);
758 /* skip all fade operations until specified fade operation */
759 if (fade_type & fade_type_skip)
760 fade_type_skip = FADE_TYPE_NONE;
765 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
767 FadeCrossSaveBackbuffer();
773 redraw_mask |= fade_mask;
775 if (fade_type == FADE_TYPE_SKIP)
778 printf("::: will skip %d ... [%d]\n", fade_mode, fade_type_skip);
781 fade_type_skip = fade_mode;
787 printf("::: !!! FADING %d ... [%d] [%d]\n", fade_mode, fade_type,
792 fade_delay = fading.fade_delay;
793 post_delay = (fade_mode == FADE_MODE_FADE_OUT ? fading.post_delay : 0);
796 if (fade_type_skip != FADE_TYPE_NONE)
799 printf("::: skipping %d ... [%d]\n", fade_mode, fade_type_skip);
802 /* skip all fade operations until specified fade operation */
803 if (fade_type & fade_type_skip)
804 fade_type_skip = FADE_TYPE_NONE;
814 if (global.autoplay_leveldir)
816 // fading.fade_mode = FADE_MODE_NONE;
823 if (fading.fade_mode == FADE_MODE_NONE)
831 /* !!! what about fade_mask == REDRAW_FIELD | REDRAW_ALL ??? !!! */
834 printf("::: NOW FADING %d ... [%d]\n", fade_mode, fade_type);
838 if (fade_mask == REDRAW_NONE)
839 fade_mask = REDRAW_FIELD;
842 // if (fade_mask & REDRAW_FIELD)
843 if (fade_mask == REDRAW_FIELD)
848 height = FULL_SYSIZE;
851 fade_delay = fading.fade_delay;
852 post_delay = (fade_mode == FADE_MODE_FADE_OUT ? fading.post_delay : 0);
855 if (border.draw_masked_when_fading)
856 draw_border_function = DrawMaskedBorder_FIELD; /* update when fading */
858 DrawMaskedBorder_FIELD(); /* draw once */
860 else /* REDRAW_ALL */
868 fade_delay = fading.fade_delay;
869 post_delay = (fade_mode == FADE_MODE_FADE_OUT ? fading.post_delay : 0);
874 if (!setup.fade_screens ||
876 fading.fade_mode == FADE_MODE_NONE)
878 if (!setup.fade_screens || fade_delay == 0)
881 if (fade_mode == FADE_MODE_FADE_OUT)
885 if (fade_mode == FADE_MODE_FADE_OUT &&
886 fading.fade_mode != FADE_MODE_NONE)
887 ClearRectangle(backbuffer, x, y, width, height);
891 BlitBitmap(backbuffer, window, x, y, width, height, x, y);
892 redraw_mask = REDRAW_NONE;
900 FadeRectangle(bitmap, x, y, width, height, fade_mode, fade_delay, post_delay,
901 draw_border_function);
903 redraw_mask &= ~fade_mask;
906 void FadeIn(int fade_mask)
908 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
909 FadeExt(fade_mask, fading.fade_mode, FADE_TYPE_FADE_IN);
911 FadeExt(fade_mask, FADE_MODE_FADE_IN, FADE_TYPE_FADE_IN);
914 void FadeOut(int fade_mask)
916 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
917 FadeExt(fade_mask, fading.fade_mode, FADE_TYPE_FADE_OUT);
919 FadeExt(fade_mask, FADE_MODE_FADE_OUT, FADE_TYPE_FADE_OUT);
921 global.border_status = game_status;
924 static void FadeSetLeaveNext(struct TitleFadingInfo fading_leave, boolean set)
926 static struct TitleFadingInfo fading_leave_stored;
929 fading_leave_stored = fading_leave;
931 fading = fading_leave_stored;
934 void FadeSetEnterMenu()
936 fading = menu.enter_menu;
939 printf("::: storing enter_menu\n");
942 FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
945 void FadeSetLeaveMenu()
947 fading = menu.leave_menu;
950 printf("::: storing leave_menu\n");
953 FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
956 void FadeSetEnterScreen()
958 fading = menu.enter_screen[game_status];
961 printf("::: storing leave_screen[%d]\n", game_status);
964 FadeSetLeaveNext(menu.leave_screen[game_status], TRUE); /* store */
967 void FadeSetNextScreen()
969 fading = menu.next_screen;
972 printf("::: storing next_screen\n");
975 // (do not overwrite fade mode set by FadeSetEnterScreen)
976 // FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
979 void FadeSetLeaveScreen()
982 printf("::: recalling last stored value\n");
985 FadeSetLeaveNext(menu.leave_screen[game_status], FALSE); /* recall */
988 void FadeSetFromType(int type)
990 if (type & TYPE_ENTER_SCREEN)
991 FadeSetEnterScreen();
992 else if (type & TYPE_ENTER)
994 else if (type & TYPE_LEAVE)
998 void FadeSetDisabled()
1000 static struct TitleFadingInfo fading_none = { FADE_MODE_NONE, -1, -1, -1 };
1002 fading = fading_none;
1005 void FadeSkipNextFadeIn()
1007 FadeExt(0, FADE_MODE_SKIP_FADE_IN, FADE_TYPE_SKIP);
1010 void FadeSkipNextFadeOut()
1012 FadeExt(0, FADE_MODE_SKIP_FADE_OUT, FADE_TYPE_SKIP);
1015 void SetWindowBackgroundImageIfDefined(int graphic)
1017 if (graphic_info[graphic].bitmap)
1018 SetWindowBackgroundBitmap(graphic_info[graphic].bitmap);
1021 void SetMainBackgroundImageIfDefined(int graphic)
1023 if (graphic_info[graphic].bitmap)
1024 SetMainBackgroundBitmap(graphic_info[graphic].bitmap);
1027 void SetDoorBackgroundImageIfDefined(int graphic)
1029 if (graphic_info[graphic].bitmap)
1030 SetDoorBackgroundBitmap(graphic_info[graphic].bitmap);
1033 void SetWindowBackgroundImage(int graphic)
1035 SetWindowBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
1036 graphic_info[graphic].bitmap ?
1037 graphic_info[graphic].bitmap :
1038 graphic_info[IMG_BACKGROUND].bitmap);
1041 void SetMainBackgroundImage(int graphic)
1043 SetMainBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
1044 graphic_info[graphic].bitmap ?
1045 graphic_info[graphic].bitmap :
1046 graphic_info[IMG_BACKGROUND].bitmap);
1049 void SetDoorBackgroundImage(int graphic)
1051 SetDoorBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
1052 graphic_info[graphic].bitmap ?
1053 graphic_info[graphic].bitmap :
1054 graphic_info[IMG_BACKGROUND].bitmap);
1057 void SetPanelBackground()
1060 struct GraphicInfo *gfx = &graphic_info[IMG_BACKGROUND_PANEL];
1063 BlitBitmapTiled(gfx->bitmap, bitmap_db_panel, gfx->src_x, gfx->src_y,
1064 gfx->width, gfx->height, 0, 0, DXSIZE, DYSIZE);
1066 /* (ClearRectangle() only needed if panel bitmap is smaller than panel) */
1067 ClearRectangle(bitmap_db_panel, DX, DY, DXSIZE, DYSIZE);
1068 BlitBitmap(gfx->bitmap, bitmap_db_panel, gfx->src_x, gfx->src_y,
1069 MIN(gfx->width, DXSIZE), MIN(gfx->height, DYSIZE), 0, 0);
1072 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, bitmap_db_panel,
1073 DOOR_GFX_PAGEX5, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE, 0, 0);
1076 SetDoorBackgroundBitmap(bitmap_db_panel);
1079 void DrawBackground(int x, int y, int width, int height)
1081 /* !!! "drawto" might still point to playfield buffer here (see below) !!! */
1082 /* (when entering hall of fame after playing) */
1084 ClearRectangleOnBackground(drawto, x, y, width, height);
1086 ClearRectangleOnBackground(backbuffer, x, y, width, height);
1090 /* (this only works for the current arrangement of playfield and panels) */
1092 redraw_mask |= REDRAW_FIELD;
1093 else if (y < gfx.vy)
1094 redraw_mask |= REDRAW_DOOR_1;
1096 redraw_mask |= REDRAW_DOOR_2;
1098 /* (this is just wrong (when drawing to one of the two door panel areas)) */
1099 redraw_mask |= REDRAW_FIELD;
1103 void DrawBackgroundForFont(int x, int y, int width, int height, int font_nr)
1105 struct FontBitmapInfo *font = getFontBitmapInfo(font_nr);
1107 if (font->bitmap == NULL)
1110 DrawBackground(x, y, width, height);
1113 void DrawBackgroundForGraphic(int x, int y, int width, int height, int graphic)
1115 struct GraphicInfo *g = &graphic_info[graphic];
1117 if (g->bitmap == NULL)
1120 DrawBackground(x, y, width, height);
1125 /* !!! "drawto" might still point to playfield buffer here (see above) !!! */
1126 /* (when entering hall of fame after playing) */
1127 DrawBackground(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
1129 /* !!! maybe this should be done before clearing the background !!! */
1130 if (setup.soft_scrolling && game_status == GAME_MODE_PLAYING)
1132 ClearRectangle(fieldbuffer, 0, 0, FXSIZE, FYSIZE);
1133 SetDrawtoField(DRAW_BUFFERED);
1136 SetDrawtoField(DRAW_BACKBUFFER);
1139 void MarkTileDirty(int x, int y)
1141 int xx = redraw_x1 + x;
1142 int yy = redraw_y1 + y;
1144 if (!redraw[xx][yy])
1147 redraw[xx][yy] = TRUE;
1148 redraw_mask |= REDRAW_TILES;
1151 void SetBorderElement()
1155 BorderElement = EL_EMPTY;
1157 for (y = 0; y < lev_fieldy && BorderElement == EL_EMPTY; y++)
1159 for (x = 0; x < lev_fieldx; x++)
1161 if (!IS_INDESTRUCTIBLE(Feld[x][y]))
1162 BorderElement = EL_STEELWALL;
1164 if (y != 0 && y != lev_fieldy - 1 && x != lev_fieldx - 1)
1170 void FloodFillLevel(int from_x, int from_y, int fill_element,
1171 short field[MAX_LEV_FIELDX][MAX_LEV_FIELDY],
1172 int max_fieldx, int max_fieldy)
1176 static int check[4][2] = { { -1, 0 }, { 0, -1 }, { 1, 0 }, { 0, 1 } };
1177 static int safety = 0;
1179 /* check if starting field still has the desired content */
1180 if (field[from_x][from_y] == fill_element)
1185 if (safety > max_fieldx * max_fieldy)
1186 Error(ERR_EXIT, "Something went wrong in 'FloodFill()'. Please debug.");
1188 old_element = field[from_x][from_y];
1189 field[from_x][from_y] = fill_element;
1191 for (i = 0; i < 4; i++)
1193 x = from_x + check[i][0];
1194 y = from_y + check[i][1];
1196 if (IN_FIELD(x, y, max_fieldx, max_fieldy) && field[x][y] == old_element)
1197 FloodFillLevel(x, y, fill_element, field, max_fieldx, max_fieldy);
1203 void SetRandomAnimationValue(int x, int y)
1205 gfx.anim_random_frame = GfxRandom[x][y];
1208 inline int getGraphicAnimationFrame(int graphic, int sync_frame)
1210 /* animation synchronized with global frame counter, not move position */
1211 if (graphic_info[graphic].anim_global_sync || sync_frame < 0)
1212 sync_frame = FrameCounter;
1214 return getAnimationFrame(graphic_info[graphic].anim_frames,
1215 graphic_info[graphic].anim_delay,
1216 graphic_info[graphic].anim_mode,
1217 graphic_info[graphic].anim_start_frame,
1221 void getSizedGraphicSourceExt(int graphic, int frame, int tilesize_raw,
1222 Bitmap **bitmap, int *x, int *y,
1223 boolean get_backside)
1227 int width_mult, width_div;
1228 int height_mult, height_div;
1232 { 15, 16, 2, 3 }, /* 1 x 1 */
1233 { 7, 8, 2, 3 }, /* 2 x 2 */
1234 { 3, 4, 2, 3 }, /* 4 x 4 */
1235 { 1, 2, 2, 3 }, /* 8 x 8 */
1236 { 0, 1, 2, 3 }, /* 16 x 16 */
1237 { 0, 1, 0, 1 }, /* 32 x 32 */
1239 struct GraphicInfo *g = &graphic_info[graphic];
1240 Bitmap *src_bitmap = g->bitmap;
1241 int tilesize = MIN(MAX(1, tilesize_raw), TILESIZE);
1242 int offset_calc_pos = log_2(tilesize);
1243 int width_mult = offset_calc[offset_calc_pos].width_mult;
1244 int width_div = offset_calc[offset_calc_pos].width_div;
1245 int height_mult = offset_calc[offset_calc_pos].height_mult;
1246 int height_div = offset_calc[offset_calc_pos].height_div;
1247 int startx = src_bitmap->width * width_mult / width_div;
1248 int starty = src_bitmap->height * height_mult / height_div;
1250 int src_x = (g->src_x + (get_backside ? g->offset2_x : 0)) *
1251 tilesize / TILESIZE;
1252 int src_y = (g->src_y + (get_backside ? g->offset2_y : 0)) *
1253 tilesize / TILESIZE;
1255 int src_x = g->src_x * tilesize / TILESIZE;
1256 int src_y = g->src_y * tilesize / TILESIZE;
1258 int width = g->width * tilesize / TILESIZE;
1259 int height = g->height * tilesize / TILESIZE;
1260 int offset_x = g->offset_x * tilesize / TILESIZE;
1261 int offset_y = g->offset_y * tilesize / TILESIZE;
1263 if (g->offset_y == 0) /* frames are ordered horizontally */
1265 int max_width = g->anim_frames_per_line * width;
1266 int pos = (src_y / height) * max_width + src_x + frame * offset_x;
1268 src_x = pos % max_width;
1269 src_y = src_y % height + pos / max_width * height;
1271 else if (g->offset_x == 0) /* frames are ordered vertically */
1273 int max_height = g->anim_frames_per_line * height;
1274 int pos = (src_x / width) * max_height + src_y + frame * offset_y;
1276 src_x = src_x % width + pos / max_height * width;
1277 src_y = pos % max_height;
1279 else /* frames are ordered diagonally */
1281 src_x = src_x + frame * offset_x;
1282 src_y = src_y + frame * offset_y;
1285 *bitmap = src_bitmap;
1286 *x = startx + src_x;
1287 *y = starty + src_y;
1290 void getFixedGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
1291 int *x, int *y, boolean get_backside)
1293 getSizedGraphicSourceExt(graphic, frame, TILESIZE, bitmap, x, y,
1297 void getSizedGraphicSource(int graphic, int frame, int tilesize_raw,
1298 Bitmap **bitmap, int *x, int *y)
1300 getSizedGraphicSourceExt(graphic, frame, tilesize_raw, bitmap, x, y, FALSE);
1303 void getFixedGraphicSource(int graphic, int frame,
1304 Bitmap **bitmap, int *x, int *y)
1306 getSizedGraphicSourceExt(graphic, frame, TILESIZE, bitmap, x, y, FALSE);
1309 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
1312 getSizedGraphicSource(graphic, 0, MINI_TILESIZE, bitmap, x, y);
1314 struct GraphicInfo *g = &graphic_info[graphic];
1315 int mini_startx = 0;
1316 int mini_starty = g->bitmap->height * 2 / 3;
1318 *bitmap = g->bitmap;
1319 *x = mini_startx + g->src_x / 2;
1320 *y = mini_starty + g->src_y / 2;
1324 inline void getGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
1325 int *x, int *y, boolean get_backside)
1327 struct GraphicInfo *g = &graphic_info[graphic];
1328 int src_x = g->src_x + (get_backside ? g->offset2_x : 0);
1329 int src_y = g->src_y + (get_backside ? g->offset2_y : 0);
1332 if (TILESIZE_VAR != TILESIZE)
1333 return getSizedGraphicSourceExt(graphic, frame, TILESIZE_VAR, bitmap, x, y,
1337 *bitmap = g->bitmap;
1339 if (g->offset_y == 0) /* frames are ordered horizontally */
1341 int max_width = g->anim_frames_per_line * g->width;
1342 int pos = (src_y / g->height) * max_width + src_x + frame * g->offset_x;
1344 *x = pos % max_width;
1345 *y = src_y % g->height + pos / max_width * g->height;
1347 else if (g->offset_x == 0) /* frames are ordered vertically */
1349 int max_height = g->anim_frames_per_line * g->height;
1350 int pos = (src_x / g->width) * max_height + src_y + frame * g->offset_y;
1352 *x = src_x % g->width + pos / max_height * g->width;
1353 *y = pos % max_height;
1355 else /* frames are ordered diagonally */
1357 *x = src_x + frame * g->offset_x;
1358 *y = src_y + frame * g->offset_y;
1362 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
1364 getGraphicSourceExt(graphic, frame, bitmap, x, y, FALSE);
1367 void DrawGraphic(int x, int y, int graphic, int frame)
1370 if (!IN_SCR_FIELD(x, y))
1372 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
1373 printf("DrawGraphic(): This should never happen!\n");
1379 DrawGraphicExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR, graphic,
1382 DrawGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic, frame);
1384 MarkTileDirty(x, y);
1387 void DrawFixedGraphic(int x, int y, int graphic, int frame)
1390 if (!IN_SCR_FIELD(x, y))
1392 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
1393 printf("DrawGraphic(): This should never happen!\n");
1398 DrawFixedGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic,
1400 MarkTileDirty(x, y);
1403 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
1409 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1411 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX_VAR, TILEY_VAR, x, y);
1413 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
1417 void DrawFixedGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
1423 getFixedGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1424 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
1427 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
1430 if (!IN_SCR_FIELD(x, y))
1432 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
1433 printf("DrawGraphicThruMask(): This should never happen!\n");
1439 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR,
1442 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic,
1445 MarkTileDirty(x, y);
1448 void DrawFixedGraphicThruMask(int x, int y, int graphic, int frame)
1451 if (!IN_SCR_FIELD(x, y))
1453 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
1454 printf("DrawGraphicThruMask(): This should never happen!\n");
1459 DrawFixedGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
1461 MarkTileDirty(x, y);
1464 void DrawGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y, int graphic,
1470 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1472 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1473 dst_x - src_x, dst_y - src_y);
1475 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX_VAR, TILEY_VAR,
1478 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dst_x, dst_y);
1482 void DrawFixedGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y,
1483 int graphic, int frame)
1488 getFixedGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1490 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1491 dst_x - src_x, dst_y - src_y);
1492 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dst_x, dst_y);
1495 void DrawSizedGraphic(int x, int y, int graphic, int frame, int tilesize)
1497 DrawSizedGraphicExt(drawto, SX + x * tilesize, SY + y * tilesize, graphic,
1499 MarkTileDirty(x / tilesize, y / tilesize);
1502 void DrawSizedGraphicExt(DrawBuffer *d, int x, int y, int graphic, int frame,
1508 getSizedGraphicSource(graphic, frame, tilesize, &src_bitmap, &src_x, &src_y);
1509 BlitBitmap(src_bitmap, d, src_x, src_y, tilesize, tilesize, x, y);
1512 void DrawMiniGraphic(int x, int y, int graphic)
1514 DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
1515 MarkTileDirty(x / 2, y / 2);
1518 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
1523 getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1524 BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
1527 inline static void DrawGraphicShiftedNormal(int x, int y, int dx, int dy,
1528 int graphic, int frame,
1529 int cut_mode, int mask_mode)
1534 int width = TILEX, height = TILEY;
1537 if (dx || dy) /* shifted graphic */
1539 if (x < BX1) /* object enters playfield from the left */
1546 else if (x > BX2) /* object enters playfield from the right */
1552 else if (x==BX1 && dx < 0) /* object leaves playfield to the left */
1558 else if (x==BX2 && dx > 0) /* object leaves playfield to the right */
1560 else if (dx) /* general horizontal movement */
1561 MarkTileDirty(x + SIGN(dx), y);
1563 if (y < BY1) /* object enters playfield from the top */
1565 if (cut_mode==CUT_BELOW) /* object completely above top border */
1573 else if (y > BY2) /* object enters playfield from the bottom */
1579 else if (y==BY1 && dy < 0) /* object leaves playfield to the top */
1585 else if (dy > 0 && cut_mode == CUT_ABOVE)
1587 if (y == BY2) /* object completely above bottom border */
1593 MarkTileDirty(x, y + 1);
1594 } /* object leaves playfield to the bottom */
1595 else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
1597 else if (dy) /* general vertical movement */
1598 MarkTileDirty(x, y + SIGN(dy));
1602 if (!IN_SCR_FIELD(x, y))
1604 printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
1605 printf("DrawGraphicShifted(): This should never happen!\n");
1611 width = width * TILESIZE_VAR / TILESIZE;
1612 height = height * TILESIZE_VAR / TILESIZE;
1613 cx = cx * TILESIZE_VAR / TILESIZE;
1614 cy = cy * TILESIZE_VAR / TILESIZE;
1615 dx = dx * TILESIZE_VAR / TILESIZE;
1616 dy = dy * TILESIZE_VAR / TILESIZE;
1619 if (width > 0 && height > 0)
1621 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1627 dst_x = FX + x * TILEX_VAR + dx;
1628 dst_y = FY + y * TILEY_VAR + dy;
1630 dst_x = FX + x * TILEX + dx;
1631 dst_y = FY + y * TILEY + dy;
1634 if (mask_mode == USE_MASKING)
1636 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1637 dst_x - src_x, dst_y - src_y);
1638 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1642 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1645 MarkTileDirty(x, y);
1649 inline static void DrawGraphicShiftedDouble(int x, int y, int dx, int dy,
1650 int graphic, int frame,
1651 int cut_mode, int mask_mode)
1657 int width = TILEX_VAR, height = TILEY_VAR;
1659 int width = TILEX, height = TILEY;
1663 int x2 = x + SIGN(dx);
1664 int y2 = y + SIGN(dy);
1666 /* !!! DOES NOT WORK FOR SLOW MOVEMENT !!! */
1667 int sync_frame = GfxFrame[LEVELX(x)][LEVELY(y)];
1669 /* movement with two-tile animations must be sync'ed with movement position,
1670 not with current GfxFrame (which can be higher when using slow movement) */
1671 int anim_pos = (dx ? ABS(dx) : ABS(dy));
1672 int anim_frames = graphic_info[graphic].anim_frames;
1674 /* (we also need anim_delay here for movement animations with less frames) */
1675 int anim_delay = graphic_info[graphic].anim_delay;
1676 int sync_frame = anim_pos * anim_frames * anim_delay / TILESIZE;
1678 int sync_frame = anim_pos * anim_frames / TILESIZE;
1681 boolean draw_start_tile = (cut_mode != CUT_ABOVE); /* only for falling! */
1682 boolean draw_end_tile = (cut_mode != CUT_BELOW); /* only for falling! */
1684 /* re-calculate animation frame for two-tile movement animation */
1685 frame = getGraphicAnimationFrame(graphic, sync_frame);
1689 printf("::: %d, %d, %d => %d [%d]\n",
1690 anim_pos, anim_frames, anim_delay, sync_frame, graphic);
1692 printf("::: %d, %d => %d\n",
1693 anim_pos, anim_frames, sync_frame);
1698 printf("::: %d [%d, %d] [%d] [%d]\n", frame, sync_frame, dy,
1699 GfxFrame[LEVELX(x)][LEVELY(y)], mask_mode);
1702 /* check if movement start graphic inside screen area and should be drawn */
1703 if (draw_start_tile && IN_SCR_FIELD(x1, y1))
1705 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, TRUE);
1708 dst_x = FX + x1 * TILEX_VAR;
1709 dst_y = FY + y1 * TILEY_VAR;
1711 dst_x = FX + x1 * TILEX;
1712 dst_y = FY + y1 * TILEY;
1715 if (mask_mode == USE_MASKING)
1717 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1718 dst_x - src_x, dst_y - src_y);
1719 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1723 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1726 MarkTileDirty(x1, y1);
1729 /* check if movement end graphic inside screen area and should be drawn */
1730 if (draw_end_tile && IN_SCR_FIELD(x2, y2))
1732 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
1735 dst_x = FX + x2 * TILEX_VAR;
1736 dst_y = FY + y2 * TILEY_VAR;
1738 dst_x = FX + x2 * TILEX;
1739 dst_y = FY + y2 * TILEY;
1742 if (mask_mode == USE_MASKING)
1744 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1745 dst_x - src_x, dst_y - src_y);
1746 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1750 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1753 MarkTileDirty(x2, y2);
1757 static void DrawGraphicShifted(int x, int y, int dx, int dy,
1758 int graphic, int frame,
1759 int cut_mode, int mask_mode)
1763 DrawGraphic(x, y, graphic, frame);
1768 if (graphic_info[graphic].double_movement) /* EM style movement images */
1769 DrawGraphicShiftedDouble(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1771 DrawGraphicShiftedNormal(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1774 void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
1775 int frame, int cut_mode)
1777 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, USE_MASKING);
1780 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
1781 int cut_mode, int mask_mode)
1783 int lx = LEVELX(x), ly = LEVELY(y);
1787 if (IN_LEV_FIELD(lx, ly))
1789 SetRandomAnimationValue(lx, ly);
1791 graphic = el_act_dir2img(element, GfxAction[lx][ly], GfxDir[lx][ly]);
1792 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1794 /* do not use double (EM style) movement graphic when not moving */
1795 if (graphic_info[graphic].double_movement && !dx && !dy)
1797 graphic = el_act_dir2img(element, ACTION_DEFAULT, GfxDir[lx][ly]);
1798 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1801 else /* border element */
1803 graphic = el2img(element);
1804 frame = getGraphicAnimationFrame(graphic, -1);
1807 if (element == EL_EXPANDABLE_WALL)
1809 boolean left_stopped = FALSE, right_stopped = FALSE;
1811 if (!IN_LEV_FIELD(lx - 1, ly) || IS_WALL(Feld[lx - 1][ly]))
1812 left_stopped = TRUE;
1813 if (!IN_LEV_FIELD(lx + 1, ly) || IS_WALL(Feld[lx + 1][ly]))
1814 right_stopped = TRUE;
1816 if (left_stopped && right_stopped)
1818 else if (left_stopped)
1820 graphic = IMG_EXPANDABLE_WALL_GROWING_RIGHT;
1821 frame = graphic_info[graphic].anim_frames - 1;
1823 else if (right_stopped)
1825 graphic = IMG_EXPANDABLE_WALL_GROWING_LEFT;
1826 frame = graphic_info[graphic].anim_frames - 1;
1831 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
1832 else if (mask_mode == USE_MASKING)
1833 DrawGraphicThruMask(x, y, graphic, frame);
1835 DrawGraphic(x, y, graphic, frame);
1838 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
1839 int cut_mode, int mask_mode)
1841 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1842 DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
1843 cut_mode, mask_mode);
1846 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
1849 DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1852 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
1855 DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1858 void DrawLevelElementThruMask(int x, int y, int element)
1860 DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1863 void DrawLevelFieldThruMask(int x, int y)
1865 DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
1868 /* !!! implementation of quicksand is totally broken !!! */
1869 #define IS_CRUMBLED_TILE(x, y, e) \
1870 (GFX_CRUMBLED(e) && (!IN_LEV_FIELD(x, y) || \
1871 !IS_MOVING(x, y) || \
1872 (e) == EL_QUICKSAND_EMPTYING || \
1873 (e) == EL_QUICKSAND_FAST_EMPTYING))
1875 static void DrawLevelFieldCrumbledInnerCorners(int x, int y, int dx, int dy,
1880 int width, height, cx, cy;
1881 int sx = SCREENX(x), sy = SCREENY(y);
1882 int crumbled_border_size = graphic_info[graphic].border_size;
1885 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1887 for (i = 1; i < 4; i++)
1889 int dxx = (i & 1 ? dx : 0);
1890 int dyy = (i & 2 ? dy : 0);
1893 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1896 /* check if neighbour field is of same crumble type */
1897 boolean same = (IS_CRUMBLED_TILE(xx, yy, element) &&
1898 graphic_info[graphic].class ==
1899 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class);
1901 /* return if check prevents inner corner */
1902 if (same == (dxx == dx && dyy == dy))
1906 /* if we reach this point, we have an inner corner */
1908 getGraphicSource(graphic, 1, &src_bitmap, &src_x, &src_y);
1911 width = crumbled_border_size * TILESIZE_VAR / TILESIZE;
1912 height = crumbled_border_size * TILESIZE_VAR / TILESIZE;
1913 cx = (dx > 0 ? TILEX - crumbled_border_size : 0) * TILESIZE_VAR / TILESIZE;
1914 cy = (dy > 0 ? TILEY - crumbled_border_size : 0) * TILESIZE_VAR / TILESIZE;
1916 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1917 width, height, FX + sx * TILEX_VAR + cx, FY + sy * TILEY_VAR + cy);
1919 width = crumbled_border_size;
1920 height = crumbled_border_size;
1921 cx = (dx > 0 ? TILEX - crumbled_border_size : 0);
1922 cy = (dy > 0 ? TILEY - crumbled_border_size : 0);
1924 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1925 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
1929 static void DrawLevelFieldCrumbledBorders(int x, int y, int graphic, int frame,
1934 int width, height, bx, by, cx, cy;
1935 int sx = SCREENX(x), sy = SCREENY(y);
1936 int crumbled_border_size = graphic_info[graphic].border_size;
1939 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1941 /* draw simple, sloppy, non-corner-accurate crumbled border */
1944 width = (dir == 1 || dir == 2 ? crumbled_border_size : TILEX);
1945 height = (dir == 0 || dir == 3 ? crumbled_border_size : TILEY);
1946 cx = (dir == 2 ? TILEX - crumbled_border_size : 0);
1947 cy = (dir == 3 ? TILEY - crumbled_border_size : 0);
1949 if (dir == 1 || dir == 2) /* left or right crumbled border */
1951 width = crumbled_border_size;
1953 cx = (dir == 2 ? TILEX - crumbled_border_size : 0);
1956 else /* top or bottom crumbled border */
1959 height = crumbled_border_size;
1961 cy = (dir == 3 ? TILEY - crumbled_border_size : 0);
1966 BlitBitmap(src_bitmap, drawto_field,
1967 src_x + cx * TILESIZE_VAR / TILESIZE,
1968 src_y + cy * TILESIZE_VAR / TILESIZE,
1969 width * TILESIZE_VAR / TILESIZE,
1970 height * TILESIZE_VAR / TILESIZE,
1971 FX + sx * TILEX_VAR + cx * TILESIZE_VAR / TILESIZE,
1972 FY + sy * TILEY_VAR + cy * TILESIZE_VAR / TILESIZE);
1974 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1975 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
1978 /* (remaining middle border part must be at least as big as corner part) */
1979 if (!(graphic_info[graphic].style & STYLE_ACCURATE_BORDERS) ||
1980 crumbled_border_size >= TILESIZE / 3)
1983 /* correct corners of crumbled border, if needed */
1986 for (i = -1; i <= 1; i+=2)
1988 int xx = x + (dir == 0 || dir == 3 ? i : 0);
1989 int yy = y + (dir == 1 || dir == 2 ? i : 0);
1990 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1993 /* check if neighbour field is of same crumble type */
1994 if (IS_CRUMBLED_TILE(xx, yy, element) &&
1995 graphic_info[graphic].class ==
1996 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
1998 /* no crumbled corner, but continued crumbled border */
2000 int c1 = (dir == 2 || dir == 3 ? TILESIZE - crumbled_border_size : 0);
2001 int c2 = (i == 1 ? TILESIZE - crumbled_border_size : 0);
2002 int b1 = (i == 1 ? crumbled_border_size :
2003 TILESIZE - 2 * crumbled_border_size);
2005 width = crumbled_border_size;
2006 height = crumbled_border_size;
2008 if (dir == 1 || dir == 2)
2024 BlitBitmap(src_bitmap, drawto_field,
2025 src_x + bx * TILESIZE_VAR / TILESIZE,
2026 src_y + by * TILESIZE_VAR / TILESIZE,
2027 width * TILESIZE_VAR / TILESIZE,
2028 height * TILESIZE_VAR / TILESIZE,
2029 FX + sx * TILEX_VAR + cx * TILESIZE_VAR / TILESIZE,
2030 FY + sy * TILEY_VAR + cy * TILESIZE_VAR / TILESIZE);
2032 BlitBitmap(src_bitmap, drawto_field, src_x + bx, src_y + by,
2033 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
2038 if (dir == 1 || dir == 2) /* left or right crumbled border */
2040 for (i = -1; i <= 1; i+=2)
2044 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
2047 /* check if neighbour field is of same crumble type */
2048 if (IS_CRUMBLED_TILE(xx, yy, element) &&
2049 graphic_info[graphic].class ==
2050 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
2052 /* no crumbled corner, but continued crumbled border */
2054 width = crumbled_border_size;
2055 height = crumbled_border_size;
2056 cx = (dir == 2 ? TILEX - crumbled_border_size : 0);
2057 cy = (i == 1 ? TILEY - crumbled_border_size : 0);
2059 by = (i == 1 ? crumbled_border_size :
2060 TILEY - 2 * crumbled_border_size);
2062 BlitBitmap(src_bitmap, drawto_field, src_x + bx, src_y + by,
2063 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
2067 else /* top or bottom crumbled border */
2069 for (i = -1; i <= 1; i+=2)
2073 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
2076 /* check if neighbour field is of same crumble type */
2077 if (IS_CRUMBLED_TILE(xx, yy, element) &&
2078 graphic_info[graphic].class ==
2079 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
2081 /* no crumbled corner, but continued crumbled border */
2083 width = crumbled_border_size;
2084 height = crumbled_border_size;
2085 cx = (i == 1 ? TILEX - crumbled_border_size : 0);
2086 cy = (dir == 3 ? TILEY - crumbled_border_size : 0);
2087 bx = (i == 1 ? crumbled_border_size :
2088 TILEX - 2 * crumbled_border_size);
2091 BlitBitmap(src_bitmap, drawto_field, src_x + bx, src_y + by,
2092 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
2099 static void DrawLevelFieldCrumbledExt(int x, int y, int graphic, int frame)
2101 int sx = SCREENX(x), sy = SCREENY(y);
2104 static int xy[4][2] =
2112 if (!IN_LEV_FIELD(x, y))
2115 element = TILE_GFX_ELEMENT(x, y);
2117 /* crumble field itself */
2118 if (IS_CRUMBLED_TILE(x, y, element))
2120 if (!IN_SCR_FIELD(sx, sy))
2123 for (i = 0; i < 4; i++)
2125 int xx = x + xy[i][0];
2126 int yy = y + xy[i][1];
2128 element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
2131 /* check if neighbour field is of same crumble type */
2133 if (IS_CRUMBLED_TILE(xx, yy, element) &&
2134 graphic_info[graphic].class ==
2135 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
2138 if (IS_CRUMBLED_TILE(xx, yy, element))
2142 DrawLevelFieldCrumbledBorders(x, y, graphic, frame, i);
2145 if ((graphic_info[graphic].style & STYLE_INNER_CORNERS) &&
2146 graphic_info[graphic].anim_frames == 2)
2148 for (i = 0; i < 4; i++)
2150 int dx = (i & 1 ? +1 : -1);
2151 int dy = (i & 2 ? +1 : -1);
2153 DrawLevelFieldCrumbledInnerCorners(x, y, dx, dy, graphic);
2157 MarkTileDirty(sx, sy);
2159 else /* center field not crumbled -- crumble neighbour fields */
2161 for (i = 0; i < 4; i++)
2163 int xx = x + xy[i][0];
2164 int yy = y + xy[i][1];
2165 int sxx = sx + xy[i][0];
2166 int syy = sy + xy[i][1];
2168 if (!IN_LEV_FIELD(xx, yy) ||
2169 !IN_SCR_FIELD(sxx, syy))
2172 if (Feld[xx][yy] == EL_ELEMENT_SNAPPING)
2175 element = TILE_GFX_ELEMENT(xx, yy);
2177 if (!IS_CRUMBLED_TILE(xx, yy, element))
2180 graphic = el_act2crm(element, ACTION_DEFAULT);
2182 DrawLevelFieldCrumbledBorders(xx, yy, graphic, 0, 3 - i);
2184 MarkTileDirty(sxx, syy);
2189 void DrawLevelFieldCrumbled(int x, int y)
2193 if (!IN_LEV_FIELD(x, y))
2197 /* !!! CHECK THIS !!! */
2200 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
2201 GFX_CRUMBLED(GfxElement[x][y]))
2204 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
2205 GfxElement[x][y] != EL_UNDEFINED &&
2206 GFX_CRUMBLED(GfxElement[x][y]))
2208 DrawLevelFieldCrumbledDigging(x, y, GfxDir[x][y], GfxFrame[x][y]);
2215 graphic = el_act2crm(TILE_GFX_ELEMENT(x, y), ACTION_DEFAULT);
2217 graphic = el_act2crm(Feld[x][y], ACTION_DEFAULT);
2220 DrawLevelFieldCrumbledExt(x, y, graphic, 0);
2223 void DrawLevelFieldCrumbledDigging(int x, int y, int direction,
2226 int graphic1 = el_act_dir2img(GfxElement[x][y], ACTION_DIGGING, direction);
2227 int graphic2 = el_act_dir2crm(GfxElement[x][y], ACTION_DIGGING, direction);
2228 int frame1 = getGraphicAnimationFrame(graphic1, step_frame);
2229 int frame2 = getGraphicAnimationFrame(graphic2, step_frame);
2230 int sx = SCREENX(x), sy = SCREENY(y);
2232 DrawGraphic(sx, sy, graphic1, frame1);
2233 DrawLevelFieldCrumbledExt(x, y, graphic2, frame2);
2236 void DrawLevelFieldCrumbledNeighbours(int x, int y)
2238 int sx = SCREENX(x), sy = SCREENY(y);
2239 static int xy[4][2] =
2248 for (i = 0; i < 4; i++)
2250 int xx = x + xy[i][0];
2251 int yy = y + xy[i][1];
2252 int sxx = sx + xy[i][0];
2253 int syy = sy + xy[i][1];
2255 if (!IN_LEV_FIELD(xx, yy) ||
2256 !IN_SCR_FIELD(sxx, syy) ||
2257 !GFX_CRUMBLED(Feld[xx][yy]) ||
2261 DrawLevelField(xx, yy);
2265 static int getBorderElement(int x, int y)
2269 { EL_STEELWALL_TOPLEFT, EL_INVISIBLE_STEELWALL_TOPLEFT },
2270 { EL_STEELWALL_TOPRIGHT, EL_INVISIBLE_STEELWALL_TOPRIGHT },
2271 { EL_STEELWALL_BOTTOMLEFT, EL_INVISIBLE_STEELWALL_BOTTOMLEFT },
2272 { EL_STEELWALL_BOTTOMRIGHT, EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
2273 { EL_STEELWALL_VERTICAL, EL_INVISIBLE_STEELWALL_VERTICAL },
2274 { EL_STEELWALL_HORIZONTAL, EL_INVISIBLE_STEELWALL_HORIZONTAL },
2275 { EL_STEELWALL, EL_INVISIBLE_STEELWALL }
2277 int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
2278 int steel_position = (x == -1 && y == -1 ? 0 :
2279 x == lev_fieldx && y == -1 ? 1 :
2280 x == -1 && y == lev_fieldy ? 2 :
2281 x == lev_fieldx && y == lev_fieldy ? 3 :
2282 x == -1 || x == lev_fieldx ? 4 :
2283 y == -1 || y == lev_fieldy ? 5 : 6);
2285 return border[steel_position][steel_type];
2288 void DrawScreenElement(int x, int y, int element)
2290 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
2291 DrawLevelFieldCrumbled(LEVELX(x), LEVELY(y));
2294 void DrawLevelElement(int x, int y, int element)
2296 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
2297 DrawScreenElement(SCREENX(x), SCREENY(y), element);
2300 void DrawScreenField(int x, int y)
2302 int lx = LEVELX(x), ly = LEVELY(y);
2303 int element, content;
2305 if (!IN_LEV_FIELD(lx, ly))
2307 if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
2310 element = getBorderElement(lx, ly);
2312 DrawScreenElement(x, y, element);
2317 element = Feld[lx][ly];
2318 content = Store[lx][ly];
2320 if (IS_MOVING(lx, ly))
2322 int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
2323 boolean cut_mode = NO_CUTTING;
2325 if (element == EL_QUICKSAND_EMPTYING ||
2326 element == EL_QUICKSAND_FAST_EMPTYING ||
2327 element == EL_MAGIC_WALL_EMPTYING ||
2328 element == EL_BD_MAGIC_WALL_EMPTYING ||
2329 element == EL_DC_MAGIC_WALL_EMPTYING ||
2330 element == EL_AMOEBA_DROPPING)
2331 cut_mode = CUT_ABOVE;
2332 else if (element == EL_QUICKSAND_FILLING ||
2333 element == EL_QUICKSAND_FAST_FILLING ||
2334 element == EL_MAGIC_WALL_FILLING ||
2335 element == EL_BD_MAGIC_WALL_FILLING ||
2336 element == EL_DC_MAGIC_WALL_FILLING)
2337 cut_mode = CUT_BELOW;
2340 if (lx == 9 && ly == 1)
2341 printf("::: %s [%d] [%d, %d] [%d]\n",
2342 EL_NAME(TILE_GFX_ELEMENT(lx, ly)),
2343 el_act2crm(TILE_GFX_ELEMENT(lx, ly), ACTION_DEFAULT),
2344 element_info[EL_QUICKSAND_EMPTYING].graphic[ACTION_DEFAULT],
2345 element_info[EL_QUICKSAND_EMPTYING].crumbled[ACTION_DEFAULT],
2346 GFX_CRUMBLED(TILE_GFX_ELEMENT(lx, ly)));
2349 if (cut_mode == CUT_ABOVE)
2351 DrawScreenElement(x, y, element);
2353 DrawScreenElementShifted(x, y, 0, 0, element, NO_CUTTING);
2356 DrawScreenElement(x, y, EL_EMPTY);
2359 DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
2360 else if (cut_mode == NO_CUTTING)
2361 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
2364 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
2367 if (cut_mode == CUT_BELOW &&
2368 IN_LEV_FIELD(lx, ly + 1) && IN_SCR_FIELD(x, y + 1))
2369 DrawLevelElement(lx, ly + 1, element);
2373 if (content == EL_ACID)
2375 int dir = MovDir[lx][ly];
2376 int newlx = lx + (dir == MV_LEFT ? -1 : dir == MV_RIGHT ? +1 : 0);
2377 int newly = ly + (dir == MV_UP ? -1 : dir == MV_DOWN ? +1 : 0);
2379 DrawLevelElementThruMask(newlx, newly, EL_ACID);
2382 else if (IS_BLOCKED(lx, ly))
2387 boolean cut_mode = NO_CUTTING;
2388 int element_old, content_old;
2390 Blocked2Moving(lx, ly, &oldx, &oldy);
2393 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
2394 MovDir[oldx][oldy] == MV_RIGHT);
2396 element_old = Feld[oldx][oldy];
2397 content_old = Store[oldx][oldy];
2399 if (element_old == EL_QUICKSAND_EMPTYING ||
2400 element_old == EL_QUICKSAND_FAST_EMPTYING ||
2401 element_old == EL_MAGIC_WALL_EMPTYING ||
2402 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
2403 element_old == EL_DC_MAGIC_WALL_EMPTYING ||
2404 element_old == EL_AMOEBA_DROPPING)
2405 cut_mode = CUT_ABOVE;
2407 DrawScreenElement(x, y, EL_EMPTY);
2410 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
2412 else if (cut_mode == NO_CUTTING)
2413 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
2416 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
2419 else if (IS_DRAWABLE(element))
2420 DrawScreenElement(x, y, element);
2422 DrawScreenElement(x, y, EL_EMPTY);
2425 void DrawLevelField(int x, int y)
2427 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
2428 DrawScreenField(SCREENX(x), SCREENY(y));
2429 else if (IS_MOVING(x, y))
2433 Moving2Blocked(x, y, &newx, &newy);
2434 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
2435 DrawScreenField(SCREENX(newx), SCREENY(newy));
2437 else if (IS_BLOCKED(x, y))
2441 Blocked2Moving(x, y, &oldx, &oldy);
2442 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
2443 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
2447 void DrawMiniElement(int x, int y, int element)
2451 graphic = el2edimg(element);
2452 DrawMiniGraphic(x, y, graphic);
2455 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
2457 int x = sx + scroll_x, y = sy + scroll_y;
2459 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
2460 DrawMiniElement(sx, sy, EL_EMPTY);
2461 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
2462 DrawMiniElement(sx, sy, Feld[x][y]);
2464 DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
2467 void DrawEnvelopeBackground(int envelope_nr, int startx, int starty,
2468 int x, int y, int xsize, int ysize, int font_nr)
2470 int font_width = getFontWidth(font_nr);
2471 int font_height = getFontHeight(font_nr);
2472 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2475 int dst_x = SX + startx + x * font_width;
2476 int dst_y = SY + starty + y * font_height;
2477 int width = graphic_info[graphic].width;
2478 int height = graphic_info[graphic].height;
2479 int inner_width = MAX(width - 2 * font_width, font_width);
2480 int inner_height = MAX(height - 2 * font_height, font_height);
2481 int inner_sx = (width >= 3 * font_width ? font_width : 0);
2482 int inner_sy = (height >= 3 * font_height ? font_height : 0);
2483 boolean draw_masked = graphic_info[graphic].draw_masked;
2485 getFixedGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
2487 if (src_bitmap == NULL || width < font_width || height < font_height)
2489 ClearRectangle(drawto, dst_x, dst_y, font_width, font_height);
2493 src_x += (x == 0 ? 0 : x == xsize - 1 ? width - font_width :
2494 inner_sx + (x - 1) * font_width % inner_width);
2495 src_y += (y == 0 ? 0 : y == ysize - 1 ? height - font_height :
2496 inner_sy + (y - 1) * font_height % inner_height);
2500 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
2501 dst_x - src_x, dst_y - src_y);
2502 BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, font_width, font_height,
2506 BlitBitmap(src_bitmap, drawto, src_x, src_y, font_width, font_height,
2510 void AnimateEnvelope(int envelope_nr, int anim_mode, int action)
2512 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2513 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
2514 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
2515 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2516 boolean no_delay = (tape.warp_forward);
2517 unsigned int anim_delay = 0;
2518 int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
2519 int anim_delay_value = (no_delay ? 0 : frame_delay_value);
2520 int font_nr = FONT_ENVELOPE_1 + envelope_nr;
2521 int font_width = getFontWidth(font_nr);
2522 int font_height = getFontHeight(font_nr);
2523 int max_xsize = level.envelope[envelope_nr].xsize;
2524 int max_ysize = level.envelope[envelope_nr].ysize;
2525 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
2526 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
2527 int xend = max_xsize;
2528 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
2529 int xstep = (xstart < xend ? 1 : 0);
2530 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
2533 for (x = xstart, y = ystart; x <= xend && y <= yend; x += xstep, y += ystep)
2535 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
2536 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
2537 int sx = (SXSIZE - xsize * font_width) / 2;
2538 int sy = (SYSIZE - ysize * font_height) / 2;
2541 SetDrawtoField(DRAW_BUFFERED);
2543 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
2545 SetDrawtoField(DRAW_BACKBUFFER);
2547 for (yy = 0; yy < ysize; yy++) for (xx = 0; xx < xsize; xx++)
2548 DrawEnvelopeBackground(envelope_nr, sx,sy, xx,yy, xsize, ysize, font_nr);
2551 DrawTextBuffer(SX + sx + font_width, SY + sy + font_height,
2552 level.envelope[envelope_nr].text, font_nr, max_xsize,
2553 xsize - 2, ysize - 2, 0, mask_mode,
2554 level.envelope[envelope_nr].autowrap,
2555 level.envelope[envelope_nr].centered, FALSE);
2557 DrawTextToTextArea(SX + sx + font_width, SY + sy + font_height,
2558 level.envelope[envelope_nr].text, font_nr, max_xsize,
2559 xsize - 2, ysize - 2, mask_mode);
2562 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
2565 WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
2569 void AnimateEnvelopeDoor(char *text, int anim_mode, int action)
2572 int envelope_nr = 0;
2574 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2575 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
2576 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
2577 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2578 boolean no_delay = (tape.warp_forward);
2579 unsigned int anim_delay = 0;
2580 int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
2581 int anim_delay_value = (no_delay ? 0 : frame_delay_value);
2583 int max_word_len = maxWordLengthInString(text);
2584 int font_nr = (max_word_len > 7 ? FONT_TEXT_1 : FONT_TEXT_2);
2586 int font_nr = FONT_ENVELOPE_1 + envelope_nr;
2588 int font_width = getFontWidth(font_nr);
2589 int font_height = getFontHeight(font_nr);
2593 int max_xsize = DXSIZE / font_width;
2594 int max_ysize = DYSIZE / font_height;
2596 int max_xsize = 7; /* tools.c: MAX_REQUEST_LINE_FONT1_LEN == 7 */
2597 int max_ysize = 13; /* tools.c: MAX_REQUEST_LINES == 13 */
2601 int max_xsize = level.envelope[envelope_nr].xsize;
2602 int max_ysize = level.envelope[envelope_nr].ysize;
2604 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
2605 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
2606 int xend = max_xsize;
2607 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
2608 int xstep = (xstart < xend ? 1 : 0);
2609 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
2614 char *text_copy = getStringCopy(text);
2617 font_nr = FONT_TEXT_2;
2619 if (maxWordLengthInString(text) > 7) /* MAX_REQUEST_LINE_FONT1_LEN == 7 */
2621 max_xsize = 10; /* tools.c: MAX_REQUEST_LINE_FONT2_LEN == 10 */
2622 font_nr = FONT_TEXT_1;
2625 int max_word_len = 0;
2627 char *text_copy = getStringCopy(text);
2629 font_nr = FONT_TEXT_2;
2631 for (text_ptr = text; *text_ptr; text_ptr++)
2633 max_word_len = (*text_ptr != ' ' ? max_word_len + 1 : 0);
2635 if (max_word_len > 7) /* tools.c: MAX_REQUEST_LINE_FONT1_LEN == 7 */
2637 max_xsize = 10; /* tools.c: MAX_REQUEST_LINE_FONT2_LEN == 10 */
2638 font_nr = FONT_TEXT_1;
2647 for (text_ptr = text_copy; *text_ptr; text_ptr++)
2648 if (*text_ptr == ' ')
2653 dDX = SX + (SXSIZE - DXSIZE) / 2 - DX;
2654 dDY = SY + (SYSIZE - DYSIZE) / 2 - DY;
2656 dDX = SX + SXSIZE / 2 - max_xsize * font_width / 2 - DX;
2657 dDY = SY + SYSIZE / 2 - max_ysize * font_height / 2 - DY;
2660 for (x = xstart, y = ystart; x <= xend && y <= yend; x += xstep, y += ystep)
2662 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
2663 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
2664 int sx = (SXSIZE - xsize * font_width) / 2;
2665 int sy = (SYSIZE - ysize * font_height) / 2;
2669 BlitBitmap(bitmap_db_store, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2671 SetDrawtoField(DRAW_BUFFERED);
2673 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
2675 SetDrawtoField(DRAW_BACKBUFFER);
2678 for (yy = 0; yy < ysize; yy++) for (xx = 0; xx < xsize; xx++)
2679 DrawEnvelopeBackground(envelope_nr, sx,sy, xx,yy, xsize, ysize, font_nr);
2684 DrawTextBuffer(SX + sx + font_width, SY + sy + font_height + 8,
2685 text_copy, font_nr, max_xsize,
2686 xsize - 2, ysize - 2, 2, mask_mode,
2687 FALSE, TRUE, FALSE);
2689 DrawTextBuffer(SX + sx + font_width, SY + sy + font_height,
2690 level.envelope[envelope_nr].text, font_nr, max_xsize,
2691 xsize - 2, ysize - 2, 0, mask_mode,
2692 level.envelope[envelope_nr].autowrap,
2693 level.envelope[envelope_nr].centered, FALSE);
2697 DrawTextToTextArea(SX + sx + font_width, SY + sy + font_height,
2698 level.envelope[envelope_nr].text, font_nr, max_xsize,
2699 xsize - 2, ysize - 2, mask_mode);
2702 /* copy request gadgets to door backbuffer */
2704 if ((ysize - 2) > 13)
2705 BlitBitmap(bitmap_db_door, drawto,
2706 DOOR_GFX_PAGEX1 + (DXSIZE - (xsize - 2) * font_width) / 2,
2707 DOOR_GFX_PAGEY1 + 13 * font_height,
2708 (xsize - 2) * font_width,
2709 (ysize - 2 - 13) * font_height,
2710 SX + sx + font_width,
2711 SY + sy + font_height * (1 + 13));
2713 if ((ysize - 2) > 13)
2714 BlitBitmap(bitmap_db_door, drawto,
2715 DOOR_GFX_PAGEX1 + (DXSIZE - (xsize - 2) * font_width) / 2,
2716 DOOR_GFX_PAGEY1 + 13 * font_height,
2717 (xsize - 2) * font_width,
2718 (ysize - 2 - 13) * font_height,
2719 SX + sx + font_width,
2720 SY + sy + font_height * (1 + 13));
2724 redraw_mask = REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
2725 // redraw_mask |= REDRAW_ALL | REDRAW_FROM_BACKBUFFER;
2727 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
2737 WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
2745 void ShowEnvelope(int envelope_nr)
2747 int element = EL_ENVELOPE_1 + envelope_nr;
2748 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2749 int sound_opening = element_info[element].sound[ACTION_OPENING];
2750 int sound_closing = element_info[element].sound[ACTION_CLOSING];
2751 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2752 boolean no_delay = (tape.warp_forward);
2753 int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
2754 int wait_delay_value = (no_delay ? 0 : normal_delay_value);
2755 int anim_mode = graphic_info[graphic].anim_mode;
2756 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
2757 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
2759 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
2761 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
2763 if (anim_mode == ANIM_DEFAULT)
2764 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_OPENING);
2766 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_OPENING);
2769 Delay(wait_delay_value);
2771 WaitForEventToContinue();
2773 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
2775 if (anim_mode != ANIM_NONE)
2776 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_CLOSING);
2778 if (anim_mode == ANIM_DEFAULT)
2779 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_CLOSING);
2781 game.envelope_active = FALSE;
2783 SetDrawtoField(DRAW_BUFFERED);
2785 redraw_mask |= REDRAW_FIELD;
2789 void ShowEnvelopeDoor(char *text, int action)
2792 int last_game_status = game_status; /* save current game status */
2793 // int last_draw_background_mask = gfx.draw_background_mask;
2794 int envelope_nr = 0;
2796 int element = EL_ENVELOPE_1 + envelope_nr;
2797 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2798 int sound_opening = element_info[element].sound[ACTION_OPENING];
2799 int sound_closing = element_info[element].sound[ACTION_CLOSING];
2801 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2802 boolean no_delay = (tape.warp_forward);
2803 int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
2804 int wait_delay_value = (no_delay ? 0 : normal_delay_value);
2806 int anim_mode = graphic_info[graphic].anim_mode;
2807 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
2808 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
2811 if (game_status == GAME_MODE_PLAYING)
2813 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
2814 BlitScreenToBitmap_EM(backbuffer);
2815 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
2816 BlitScreenToBitmap_SP(backbuffer);
2819 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
2823 SetDrawtoField(DRAW_BACKBUFFER);
2825 // SetDrawBackgroundMask(REDRAW_NONE);
2827 if (action == ACTION_OPENING)
2829 BlitBitmap(backbuffer, bitmap_db_store, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2831 if (game_status != GAME_MODE_MAIN)
2835 /* force DOOR font inside door area */
2836 game_status = GAME_MODE_PSEUDO_DOOR;
2839 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
2841 if (action == ACTION_OPENING)
2843 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
2845 if (anim_mode == ANIM_DEFAULT)
2846 AnimateEnvelopeDoor(text, ANIM_DEFAULT, ACTION_OPENING);
2848 AnimateEnvelopeDoor(text, main_anim_mode, ACTION_OPENING);
2852 Delay(wait_delay_value);
2854 WaitForEventToContinue();
2859 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
2861 if (anim_mode != ANIM_NONE)
2862 AnimateEnvelopeDoor(text, main_anim_mode, ACTION_CLOSING);
2864 if (anim_mode == ANIM_DEFAULT)
2865 AnimateEnvelopeDoor(text, ANIM_DEFAULT, ACTION_CLOSING);
2868 game.envelope_active = FALSE;
2871 // game_status = last_game_status; /* restore current game status */
2873 if (action == ACTION_CLOSING)
2875 if (game_status != GAME_MODE_MAIN)
2878 BlitBitmap(bitmap_db_store, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2881 SetDrawtoField(DRAW_BUFFERED);
2884 // SetDrawBackgroundMask(last_draw_background_mask);
2887 redraw_mask = REDRAW_FIELD;
2888 // redraw_mask |= REDRAW_ALL;
2890 redraw_mask |= REDRAW_FIELD;
2894 if (game_status == GAME_MODE_MAIN)
2899 /* (important: after "BackToFront()", but before "SetDrawtoField()") */
2900 game_status = last_game_status; /* restore current game status */
2902 if (game_status == GAME_MODE_PLAYING &&
2903 level.game_engine_type == GAME_ENGINE_TYPE_RND)
2904 SetDrawtoField(DRAW_BUFFERED);
2910 void DrawPreviewElement(int dst_x, int dst_y, int element, int tilesize)
2914 int graphic = el2preimg(element);
2916 getSizedGraphicSource(graphic, 0, tilesize, &src_bitmap, &src_x, &src_y);
2917 BlitBitmap(src_bitmap, drawto, src_x, src_y, tilesize, tilesize, dst_x,dst_y);
2925 SetMainBackgroundImage(IMG_BACKGROUND_PLAYING);
2926 SetDrawBackgroundMask(REDRAW_FIELD);
2928 SetDrawBackgroundMask(REDRAW_NONE);
2933 for (x = BX1; x <= BX2; x++)
2934 for (y = BY1; y <= BY2; y++)
2935 DrawScreenField(x, y);
2937 redraw_mask |= REDRAW_FIELD;
2940 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
2944 for (x = 0; x < size_x; x++)
2945 for (y = 0; y < size_y; y++)
2946 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
2948 redraw_mask |= REDRAW_FIELD;
2951 static void DrawPreviewLevelExt(int from_x, int from_y)
2953 boolean show_level_border = (BorderElement != EL_EMPTY);
2954 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
2955 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
2956 int tile_size = preview.tile_size;
2957 int preview_width = preview.xsize * tile_size;
2958 int preview_height = preview.ysize * tile_size;
2959 int real_preview_xsize = MIN(level_xsize, preview.xsize);
2960 int real_preview_ysize = MIN(level_ysize, preview.ysize);
2961 int dst_x = SX + ALIGNED_XPOS(preview.x, preview_width, preview.align);
2962 int dst_y = SY + ALIGNED_YPOS(preview.y, preview_height, preview.valign);
2965 DrawBackground(dst_x, dst_y, preview_width, preview_height);
2967 dst_x += (preview_width - real_preview_xsize * tile_size) / 2;
2968 dst_y += (preview_height - real_preview_ysize * tile_size) / 2;
2970 for (x = 0; x < real_preview_xsize; x++)
2972 for (y = 0; y < real_preview_ysize; y++)
2974 int lx = from_x + x + (show_level_border ? -1 : 0);
2975 int ly = from_y + y + (show_level_border ? -1 : 0);
2976 int element = (IN_LEV_FIELD(lx, ly) ? level.field[lx][ly] :
2977 getBorderElement(lx, ly));
2979 DrawPreviewElement(dst_x + x * tile_size, dst_y + y * tile_size,
2980 element, tile_size);
2984 redraw_mask |= REDRAW_MICROLEVEL;
2987 #define MICROLABEL_EMPTY 0
2988 #define MICROLABEL_LEVEL_NAME 1
2989 #define MICROLABEL_LEVEL_AUTHOR_HEAD 2
2990 #define MICROLABEL_LEVEL_AUTHOR 3
2991 #define MICROLABEL_IMPORTED_FROM_HEAD 4
2992 #define MICROLABEL_IMPORTED_FROM 5
2993 #define MICROLABEL_IMPORTED_BY_HEAD 6
2994 #define MICROLABEL_IMPORTED_BY 7
2996 static int getMaxTextLength(struct TextPosInfo *pos, int font_nr)
2998 int max_text_width = SXSIZE;
2999 int font_width = getFontWidth(font_nr);
3001 if (pos->align == ALIGN_CENTER)
3002 max_text_width = (pos->x < SXSIZE / 2 ? pos->x * 2 : (SXSIZE - pos->x) * 2);
3003 else if (pos->align == ALIGN_RIGHT)
3004 max_text_width = pos->x;
3006 max_text_width = SXSIZE - pos->x;
3008 return max_text_width / font_width;
3011 static void DrawPreviewLevelLabelExt(int mode)
3013 struct TextPosInfo *pos = &menu.main.text.level_info_2;
3014 char label_text[MAX_OUTPUT_LINESIZE + 1];
3015 int max_len_label_text;
3017 int font_nr = pos->font;
3020 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
3021 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
3022 mode == MICROLABEL_IMPORTED_BY_HEAD)
3023 font_nr = pos->font_alt;
3025 int font_nr = FONT_TEXT_2;
3028 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
3029 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
3030 mode == MICROLABEL_IMPORTED_BY_HEAD)
3031 font_nr = FONT_TEXT_3;
3035 max_len_label_text = getMaxTextLength(pos, font_nr);
3037 max_len_label_text = SXSIZE / getFontWidth(font_nr);
3041 if (pos->size != -1)
3042 max_len_label_text = pos->size;
3045 for (i = 0; i < max_len_label_text; i++)
3046 label_text[i] = ' ';
3047 label_text[max_len_label_text] = '\0';
3049 if (strlen(label_text) > 0)
3052 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
3054 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
3055 int lypos = MICROLABEL2_YPOS;
3057 DrawText(lxpos, lypos, label_text, font_nr);
3062 (mode == MICROLABEL_LEVEL_NAME ? level.name :
3063 mode == MICROLABEL_LEVEL_AUTHOR_HEAD ? "created by" :
3064 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
3065 mode == MICROLABEL_IMPORTED_FROM_HEAD ? "imported from" :
3066 mode == MICROLABEL_IMPORTED_FROM ? leveldir_current->imported_from :
3067 mode == MICROLABEL_IMPORTED_BY_HEAD ? "imported by" :
3068 mode == MICROLABEL_IMPORTED_BY ? leveldir_current->imported_by :""),
3069 max_len_label_text);
3070 label_text[max_len_label_text] = '\0';
3072 if (strlen(label_text) > 0)
3075 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
3077 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
3078 int lypos = MICROLABEL2_YPOS;
3080 DrawText(lxpos, lypos, label_text, font_nr);
3084 redraw_mask |= REDRAW_MICROLEVEL;
3087 void DrawPreviewLevel(boolean restart)
3089 static unsigned int scroll_delay = 0;
3090 static unsigned int label_delay = 0;
3091 static int from_x, from_y, scroll_direction;
3092 static int label_state, label_counter;
3093 unsigned int scroll_delay_value = preview.step_delay;
3094 boolean show_level_border = (BorderElement != EL_EMPTY);
3095 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
3096 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
3097 int last_game_status = game_status; /* save current game status */
3100 /* force PREVIEW font on preview level */
3101 game_status = GAME_MODE_PSEUDO_PREVIEW;
3109 if (preview.anim_mode == ANIM_CENTERED)
3111 if (level_xsize > preview.xsize)
3112 from_x = (level_xsize - preview.xsize) / 2;
3113 if (level_ysize > preview.ysize)
3114 from_y = (level_ysize - preview.ysize) / 2;
3117 from_x += preview.xoffset;
3118 from_y += preview.yoffset;
3120 scroll_direction = MV_RIGHT;
3124 DrawPreviewLevelExt(from_x, from_y);
3125 DrawPreviewLevelLabelExt(label_state);
3127 /* initialize delay counters */
3128 DelayReached(&scroll_delay, 0);
3129 DelayReached(&label_delay, 0);
3131 if (leveldir_current->name)
3133 struct TextPosInfo *pos = &menu.main.text.level_info_1;
3134 char label_text[MAX_OUTPUT_LINESIZE + 1];
3136 int font_nr = pos->font;
3138 int font_nr = FONT_TEXT_1;
3141 int max_len_label_text = getMaxTextLength(pos, font_nr);
3143 int max_len_label_text = SXSIZE / getFontWidth(font_nr);
3151 if (pos->size != -1)
3152 max_len_label_text = pos->size;
3155 strncpy(label_text, leveldir_current->name, max_len_label_text);
3156 label_text[max_len_label_text] = '\0';
3159 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
3161 lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
3162 lypos = SY + MICROLABEL1_YPOS;
3164 DrawText(lxpos, lypos, label_text, font_nr);
3168 game_status = last_game_status; /* restore current game status */
3173 /* scroll preview level, if needed */
3174 if (preview.anim_mode != ANIM_NONE &&
3175 (level_xsize > preview.xsize || level_ysize > preview.ysize) &&
3176 DelayReached(&scroll_delay, scroll_delay_value))
3178 switch (scroll_direction)
3183 from_x -= preview.step_offset;
3184 from_x = (from_x < 0 ? 0 : from_x);
3187 scroll_direction = MV_UP;
3191 if (from_x < level_xsize - preview.xsize)
3193 from_x += preview.step_offset;
3194 from_x = (from_x > level_xsize - preview.xsize ?
3195 level_xsize - preview.xsize : from_x);
3198 scroll_direction = MV_DOWN;
3204 from_y -= preview.step_offset;
3205 from_y = (from_y < 0 ? 0 : from_y);
3208 scroll_direction = MV_RIGHT;
3212 if (from_y < level_ysize - preview.ysize)
3214 from_y += preview.step_offset;
3215 from_y = (from_y > level_ysize - preview.ysize ?
3216 level_ysize - preview.ysize : from_y);
3219 scroll_direction = MV_LEFT;
3226 DrawPreviewLevelExt(from_x, from_y);
3229 /* !!! THIS ALL SUCKS -- SHOULD BE CLEANLY REWRITTEN !!! */
3230 /* redraw micro level label, if needed */
3231 if (!strEqual(level.name, NAMELESS_LEVEL_NAME) &&
3232 !strEqual(level.author, ANONYMOUS_NAME) &&
3233 !strEqual(level.author, leveldir_current->name) &&
3234 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
3236 int max_label_counter = 23;
3238 if (leveldir_current->imported_from != NULL &&
3239 strlen(leveldir_current->imported_from) > 0)
3240 max_label_counter += 14;
3241 if (leveldir_current->imported_by != NULL &&
3242 strlen(leveldir_current->imported_by) > 0)
3243 max_label_counter += 14;
3245 label_counter = (label_counter + 1) % max_label_counter;
3246 label_state = (label_counter >= 0 && label_counter <= 7 ?
3247 MICROLABEL_LEVEL_NAME :
3248 label_counter >= 9 && label_counter <= 12 ?
3249 MICROLABEL_LEVEL_AUTHOR_HEAD :
3250 label_counter >= 14 && label_counter <= 21 ?
3251 MICROLABEL_LEVEL_AUTHOR :
3252 label_counter >= 23 && label_counter <= 26 ?
3253 MICROLABEL_IMPORTED_FROM_HEAD :
3254 label_counter >= 28 && label_counter <= 35 ?
3255 MICROLABEL_IMPORTED_FROM :
3256 label_counter >= 37 && label_counter <= 40 ?
3257 MICROLABEL_IMPORTED_BY_HEAD :
3258 label_counter >= 42 && label_counter <= 49 ?
3259 MICROLABEL_IMPORTED_BY : MICROLABEL_EMPTY);
3261 if (leveldir_current->imported_from == NULL &&
3262 (label_state == MICROLABEL_IMPORTED_FROM_HEAD ||
3263 label_state == MICROLABEL_IMPORTED_FROM))
3264 label_state = (label_state == MICROLABEL_IMPORTED_FROM_HEAD ?
3265 MICROLABEL_IMPORTED_BY_HEAD : MICROLABEL_IMPORTED_BY);
3267 DrawPreviewLevelLabelExt(label_state);
3270 game_status = last_game_status; /* restore current game status */
3273 inline void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
3274 int graphic, int sync_frame, int mask_mode)
3276 int frame = getGraphicAnimationFrame(graphic, sync_frame);
3278 if (mask_mode == USE_MASKING)
3279 DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
3281 DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
3284 inline void DrawFixedGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
3285 int graphic, int sync_frame,
3288 int frame = getGraphicAnimationFrame(graphic, sync_frame);
3290 if (mask_mode == USE_MASKING)
3291 DrawFixedGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
3293 DrawFixedGraphicExt(dst_bitmap, x, y, graphic, frame);
3296 inline void DrawGraphicAnimation(int x, int y, int graphic)
3298 int lx = LEVELX(x), ly = LEVELY(y);
3300 if (!IN_SCR_FIELD(x, y))
3304 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR,
3305 graphic, GfxFrame[lx][ly], NO_MASKING);
3307 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
3308 graphic, GfxFrame[lx][ly], NO_MASKING);
3310 MarkTileDirty(x, y);
3313 inline void DrawFixedGraphicAnimation(int x, int y, int graphic)
3315 int lx = LEVELX(x), ly = LEVELY(y);
3317 if (!IN_SCR_FIELD(x, y))
3320 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
3321 graphic, GfxFrame[lx][ly], NO_MASKING);
3322 MarkTileDirty(x, y);
3325 void DrawLevelGraphicAnimation(int x, int y, int graphic)
3327 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
3330 void DrawLevelElementAnimation(int x, int y, int element)
3332 int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
3334 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
3337 inline void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
3339 int sx = SCREENX(x), sy = SCREENY(y);
3341 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
3344 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
3347 DrawGraphicAnimation(sx, sy, graphic);
3350 if (GFX_CRUMBLED(TILE_GFX_ELEMENT(x, y)))
3351 DrawLevelFieldCrumbled(x, y);
3353 if (GFX_CRUMBLED(Feld[x][y]))
3354 DrawLevelFieldCrumbled(x, y);
3358 void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
3360 int sx = SCREENX(x), sy = SCREENY(y);
3363 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
3366 graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
3368 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
3371 DrawGraphicAnimation(sx, sy, graphic);
3373 if (GFX_CRUMBLED(element))
3374 DrawLevelFieldCrumbled(x, y);
3377 static int getPlayerGraphic(struct PlayerInfo *player, int move_dir)
3379 if (player->use_murphy)
3381 /* this works only because currently only one player can be "murphy" ... */
3382 static int last_horizontal_dir = MV_LEFT;
3383 int graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir);
3385 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3386 last_horizontal_dir = move_dir;
3388 if (graphic == IMG_SP_MURPHY) /* undefined => use special graphic */
3390 int direction = (player->is_snapping ? move_dir : last_horizontal_dir);
3392 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
3398 return el_act_dir2img(player->artwork_element, player->GfxAction,move_dir);
3401 static boolean equalGraphics(int graphic1, int graphic2)
3403 struct GraphicInfo *g1 = &graphic_info[graphic1];
3404 struct GraphicInfo *g2 = &graphic_info[graphic2];
3406 return (g1->bitmap == g2->bitmap &&
3407 g1->src_x == g2->src_x &&
3408 g1->src_y == g2->src_y &&
3409 g1->anim_frames == g2->anim_frames &&
3410 g1->anim_delay == g2->anim_delay &&
3411 g1->anim_mode == g2->anim_mode);
3414 void DrawAllPlayers()
3418 for (i = 0; i < MAX_PLAYERS; i++)
3419 if (stored_player[i].active)
3420 DrawPlayer(&stored_player[i]);
3423 void DrawPlayerField(int x, int y)
3425 if (!IS_PLAYER(x, y))
3428 DrawPlayer(PLAYERINFO(x, y));
3431 #define DRAW_PLAYER_OVER_PUSHED_ELEMENT 1
3433 void DrawPlayer(struct PlayerInfo *player)
3435 int jx = player->jx;
3436 int jy = player->jy;
3437 int move_dir = player->MovDir;
3438 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? +1 : 0);
3439 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? +1 : 0);
3440 int last_jx = (player->is_moving ? jx - dx : jx);
3441 int last_jy = (player->is_moving ? jy - dy : jy);
3442 int next_jx = jx + dx;
3443 int next_jy = jy + dy;
3444 boolean player_is_moving = (player->MovPos ? TRUE : FALSE);
3445 boolean player_is_opaque = FALSE;
3446 int sx = SCREENX(jx), sy = SCREENY(jy);
3447 int sxx = 0, syy = 0;
3448 int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
3450 int action = ACTION_DEFAULT;
3451 int last_player_graphic = getPlayerGraphic(player, move_dir);
3452 int last_player_frame = player->Frame;
3455 /* GfxElement[][] is set to the element the player is digging or collecting;
3456 remove also for off-screen player if the player is not moving anymore */
3457 if (IN_LEV_FIELD(jx, jy) && !player_is_moving)
3458 GfxElement[jx][jy] = EL_UNDEFINED;
3460 if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
3464 if (!IN_LEV_FIELD(jx, jy))
3466 printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
3467 printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
3468 printf("DrawPlayerField(): This should never happen!\n");
3473 if (element == EL_EXPLOSION)
3476 action = (player->is_pushing ? ACTION_PUSHING :
3477 player->is_digging ? ACTION_DIGGING :
3478 player->is_collecting ? ACTION_COLLECTING :
3479 player->is_moving ? ACTION_MOVING :
3480 player->is_snapping ? ACTION_SNAPPING :
3481 player->is_dropping ? ACTION_DROPPING :
3482 player->is_waiting ? player->action_waiting : ACTION_DEFAULT);
3484 if (player->is_waiting)
3485 move_dir = player->dir_waiting;
3487 InitPlayerGfxAnimation(player, action, move_dir);
3489 /* ----------------------------------------------------------------------- */
3490 /* draw things in the field the player is leaving, if needed */
3491 /* ----------------------------------------------------------------------- */
3493 if (player->is_moving)
3495 if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
3497 DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
3499 if (last_element == EL_DYNAMITE_ACTIVE ||
3500 last_element == EL_EM_DYNAMITE_ACTIVE ||
3501 last_element == EL_SP_DISK_RED_ACTIVE)
3502 DrawDynamite(last_jx, last_jy);
3504 DrawLevelFieldThruMask(last_jx, last_jy);
3506 else if (last_element == EL_DYNAMITE_ACTIVE ||
3507 last_element == EL_EM_DYNAMITE_ACTIVE ||
3508 last_element == EL_SP_DISK_RED_ACTIVE)
3509 DrawDynamite(last_jx, last_jy);
3511 /* !!! this is not enough to prevent flickering of players which are
3512 moving next to each others without a free tile between them -- this
3513 can only be solved by drawing all players layer by layer (first the
3514 background, then the foreground etc.) !!! => TODO */
3515 else if (!IS_PLAYER(last_jx, last_jy))
3516 DrawLevelField(last_jx, last_jy);
3519 DrawLevelField(last_jx, last_jy);
3522 if (player->is_pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
3523 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
3526 if (!IN_SCR_FIELD(sx, sy))
3529 /* ----------------------------------------------------------------------- */
3530 /* draw things behind the player, if needed */
3531 /* ----------------------------------------------------------------------- */
3534 DrawLevelElement(jx, jy, Back[jx][jy]);
3535 else if (IS_ACTIVE_BOMB(element))
3536 DrawLevelElement(jx, jy, EL_EMPTY);
3539 if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
3541 int old_element = GfxElement[jx][jy];
3542 int old_graphic = el_act_dir2img(old_element, action, move_dir);
3543 int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
3545 if (GFX_CRUMBLED(old_element))
3546 DrawLevelFieldCrumbledDigging(jx, jy, move_dir, player->StepFrame);
3548 DrawGraphic(sx, sy, old_graphic, frame);
3550 if (graphic_info[old_graphic].anim_mode & ANIM_OPAQUE_PLAYER)
3551 player_is_opaque = TRUE;
3555 GfxElement[jx][jy] = EL_UNDEFINED;
3557 /* make sure that pushed elements are drawn with correct frame rate */
3559 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
3561 if (player->is_pushing && player->is_moving && !IS_ANIM_MODE_CE(graphic))
3562 GfxFrame[jx][jy] = player->StepFrame;
3564 if (player->is_pushing && player->is_moving)
3565 GfxFrame[jx][jy] = player->StepFrame;
3568 DrawLevelField(jx, jy);
3572 #if !DRAW_PLAYER_OVER_PUSHED_ELEMENT
3573 /* ----------------------------------------------------------------------- */
3574 /* draw player himself */
3575 /* ----------------------------------------------------------------------- */
3577 graphic = getPlayerGraphic(player, move_dir);
3579 /* in the case of changed player action or direction, prevent the current
3580 animation frame from being restarted for identical animations */
3581 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
3582 player->Frame = last_player_frame;
3584 frame = getGraphicAnimationFrame(graphic, player->Frame);
3588 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3589 sxx = player->GfxPos;
3591 syy = player->GfxPos;
3594 if (!setup.soft_scrolling && ScreenMovPos)
3597 if (player_is_opaque)
3598 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
3600 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3602 if (SHIELD_ON(player))
3604 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
3605 IMG_SHIELD_NORMAL_ACTIVE);
3606 int frame = getGraphicAnimationFrame(graphic, -1);
3608 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3612 #if DRAW_PLAYER_OVER_PUSHED_ELEMENT
3615 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3616 sxx = player->GfxPos;
3618 syy = player->GfxPos;
3622 /* ----------------------------------------------------------------------- */
3623 /* draw things the player is pushing, if needed */
3624 /* ----------------------------------------------------------------------- */
3627 printf("::: %d, %d [%d, %d] [%d]\n",
3628 player->is_pushing, player_is_moving, player->GfxAction,
3629 player->is_moving, player_is_moving);
3633 if (player->is_pushing && player->is_moving)
3635 int px = SCREENX(jx), py = SCREENY(jy);
3636 int pxx = (TILEX - ABS(sxx)) * dx;
3637 int pyy = (TILEY - ABS(syy)) * dy;
3638 int gfx_frame = GfxFrame[jx][jy];
3644 if (!IS_MOVING(jx, jy)) /* push movement already finished */
3646 element = Feld[next_jx][next_jy];
3647 gfx_frame = GfxFrame[next_jx][next_jy];
3650 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
3653 sync_frame = (IS_ANIM_MODE_CE(graphic) ? gfx_frame : player->StepFrame);
3654 frame = getGraphicAnimationFrame(graphic, sync_frame);
3656 frame = getGraphicAnimationFrame(graphic, player->StepFrame);
3659 /* draw background element under pushed element (like the Sokoban field) */
3661 if (game.use_masked_pushing && IS_MOVING(jx, jy))
3663 /* this allows transparent pushing animation over non-black background */
3666 DrawLevelElement(jx, jy, Back[jx][jy]);
3668 DrawLevelElement(jx, jy, EL_EMPTY);
3670 if (Back[next_jx][next_jy])
3671 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
3673 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
3675 else if (Back[next_jx][next_jy])
3676 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
3678 if (Back[next_jx][next_jy])
3679 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
3683 printf("::: %d, %d, %d, %d [%d] [%d, %d, %d] [%d] [%d, %d] [%d, %d]\n",
3684 jx, px, player->GfxPos, player->StepFrame,
3689 GfxFrame[jx][jy], GfxFrame[next_jx][next_jy]);
3693 /* do not draw (EM style) pushing animation when pushing is finished */
3694 /* (two-tile animations usually do not contain start and end frame) */
3695 if (graphic_info[graphic].double_movement && !IS_MOVING(jx, jy))
3696 DrawLevelElement(next_jx, next_jy, Feld[next_jx][next_jy]);
3698 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
3700 /* masked drawing is needed for EMC style (double) movement graphics */
3701 /* !!! (ONLY WHEN DRAWING PUSHED ELEMENT OVER THE PLAYER) !!! */
3702 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
3707 #if DRAW_PLAYER_OVER_PUSHED_ELEMENT
3708 /* ----------------------------------------------------------------------- */
3709 /* draw player himself */
3710 /* ----------------------------------------------------------------------- */
3712 graphic = getPlayerGraphic(player, move_dir);
3714 /* in the case of changed player action or direction, prevent the current
3715 animation frame from being restarted for identical animations */
3716 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
3717 player->Frame = last_player_frame;
3719 frame = getGraphicAnimationFrame(graphic, player->Frame);
3723 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3724 sxx = player->GfxPos;
3726 syy = player->GfxPos;
3729 if (!setup.soft_scrolling && ScreenMovPos)
3732 if (player_is_opaque)
3733 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
3735 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3737 if (SHIELD_ON(player))
3739 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
3740 IMG_SHIELD_NORMAL_ACTIVE);
3741 int frame = getGraphicAnimationFrame(graphic, -1);
3743 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3747 /* ----------------------------------------------------------------------- */
3748 /* draw things in front of player (active dynamite or dynabombs) */
3749 /* ----------------------------------------------------------------------- */
3751 if (IS_ACTIVE_BOMB(element))
3753 graphic = el2img(element);
3754 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
3756 if (game.emulation == EMU_SUPAPLEX)
3757 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
3759 DrawGraphicThruMask(sx, sy, graphic, frame);
3762 if (player_is_moving && last_element == EL_EXPLOSION)
3764 int element = (GfxElement[last_jx][last_jy] != EL_UNDEFINED ?
3765 GfxElement[last_jx][last_jy] : EL_EMPTY);
3766 int graphic = el_act2img(element, ACTION_EXPLODING);
3767 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
3768 int phase = ExplodePhase[last_jx][last_jy] - 1;
3769 int frame = getGraphicAnimationFrame(graphic, phase - delay);
3772 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
3775 /* ----------------------------------------------------------------------- */
3776 /* draw elements the player is just walking/passing through/under */
3777 /* ----------------------------------------------------------------------- */
3779 if (player_is_moving)
3781 /* handle the field the player is leaving ... */
3782 if (IS_ACCESSIBLE_INSIDE(last_element))
3783 DrawLevelField(last_jx, last_jy);
3784 else if (IS_ACCESSIBLE_UNDER(last_element))
3785 DrawLevelFieldThruMask(last_jx, last_jy);
3788 /* do not redraw accessible elements if the player is just pushing them */
3789 if (!player_is_moving || !player->is_pushing)
3791 /* ... and the field the player is entering */
3792 if (IS_ACCESSIBLE_INSIDE(element))
3793 DrawLevelField(jx, jy);
3794 else if (IS_ACCESSIBLE_UNDER(element))
3795 DrawLevelFieldThruMask(jx, jy);
3798 MarkTileDirty(sx, sy);
3801 /* ------------------------------------------------------------------------- */
3803 void WaitForEventToContinue()
3805 boolean still_wait = TRUE;
3807 /* simulate releasing mouse button over last gadget, if still pressed */
3809 HandleGadgets(-1, -1, 0);
3811 button_status = MB_RELEASED;
3827 case EVENT_BUTTONPRESS:
3828 case EVENT_KEYPRESS:
3832 case EVENT_KEYRELEASE:
3833 ClearPlayerAction();
3837 HandleOtherEvents(&event);
3841 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
3848 /* don't eat all CPU time */
3853 #define MAX_REQUEST_LINES 13
3854 #define MAX_REQUEST_LINE_FONT1_LEN 7
3855 #define MAX_REQUEST_LINE_FONT2_LEN 10
3857 boolean Request(char *text, unsigned int req_state)
3859 int mx, my, ty, result = -1;
3860 unsigned int old_door_state;
3861 int last_game_status = game_status; /* save current game status */
3862 int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
3863 int font_nr = FONT_TEXT_2;
3865 int max_word_len = 0;
3871 global.use_envelope_request = 0;
3875 if (maxWordLengthInString(text) > MAX_REQUEST_LINE_FONT1_LEN)
3877 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
3878 font_nr = FONT_TEXT_1;
3881 for (text_ptr = text; *text_ptr; text_ptr++)
3883 max_word_len = (*text_ptr != ' ' ? max_word_len + 1 : 0);
3885 if (max_word_len > MAX_REQUEST_LINE_FONT1_LEN)
3887 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
3889 font_nr = FONT_TEXT_1;
3891 font_nr = FONT_LEVEL_NUMBER;
3899 if (game_status == GAME_MODE_PLAYING)
3901 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
3902 BlitScreenToBitmap_EM(backbuffer);
3903 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
3904 BlitScreenToBitmap_SP(backbuffer);
3907 /* disable deactivated drawing when quick-loading level tape recording */
3908 if (tape.playing && tape.deactivate_display)
3909 TapeDeactivateDisplayOff(TRUE);
3911 SetMouseCursor(CURSOR_DEFAULT);
3913 #if defined(NETWORK_AVALIABLE)
3914 /* pause network game while waiting for request to answer */
3915 if (options.network &&
3916 game_status == GAME_MODE_PLAYING &&
3917 req_state & REQUEST_WAIT_FOR_INPUT)
3918 SendToServer_PausePlaying();
3921 old_door_state = GetDoorState();
3923 /* simulate releasing mouse button over last gadget, if still pressed */
3925 HandleGadgets(-1, -1, 0);
3929 /* draw released gadget before proceeding */
3933 if (old_door_state & DOOR_OPEN_1 && !global.use_envelope_request)
3935 if (old_door_state & DOOR_OPEN_1)
3939 if (!global.use_envelope_request)
3940 CloseDoor(DOOR_CLOSE_1);
3942 CloseDoor(DOOR_CLOSE_1);
3945 /* save old door content */
3946 BlitBitmap(bitmap_db_door, bitmap_db_door,
3947 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
3948 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
3952 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
3955 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3957 /* clear door drawing field */
3958 DrawBackground(DX, DY, DXSIZE, DYSIZE);
3960 /* force DOOR font inside door area */
3961 game_status = GAME_MODE_PSEUDO_DOOR;
3963 /* write text for request */
3964 for (text_ptr = text, ty = 0; ty < MAX_REQUEST_LINES; ty++)
3966 char text_line[max_request_line_len + 1];
3972 for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
3974 tc = *(text_ptr + tx);
3975 if (!tc || tc == ' ')
3986 strncpy(text_line, text_ptr, tl);
3989 DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
3990 DY + 8 + ty * (getFontHeight(font_nr) + 2),
3991 text_line, font_nr);
3993 text_ptr += tl + (tc == ' ' ? 1 : 0);
3996 game_status = last_game_status; /* restore current game status */
3999 if (global.use_envelope_request)
4003 CreateToolButtons();
4007 if (req_state & REQ_ASK)
4009 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
4010 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
4012 else if (req_state & REQ_CONFIRM)
4014 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
4016 else if (req_state & REQ_PLAYER)
4018 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
4019 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
4020 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
4021 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
4024 /* copy request gadgets to door backbuffer */
4025 BlitBitmap(drawto, bitmap_db_door,
4026 DX, DY, DXSIZE, DYSIZE,
4027 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
4030 if (global.use_envelope_request)
4032 ShowEnvelopeDoor(text, ACTION_OPENING);
4034 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4036 if ((req_state & REQ_ASK && (i == TOOL_CTRL_ID_YES ||
4037 i == TOOL_CTRL_ID_NO)) ||
4038 (req_state & REQ_CONFIRM && i == TOOL_CTRL_ID_CONFIRM) ||
4039 (req_state & REQ_PLAYER && (i == TOOL_CTRL_ID_PLAYER_1 &&
4040 i == TOOL_CTRL_ID_PLAYER_2 &&
4041 i == TOOL_CTRL_ID_PLAYER_3 &&
4042 i == TOOL_CTRL_ID_PLAYER_4)))
4044 int x = tool_gadget[i]->x + dDX;
4045 int y = tool_gadget[i]->y + dDY;
4047 ModifyGadget(tool_gadget[i], GDI_X, x, GDI_Y, y, GDI_END);
4054 if (!global.use_envelope_request)
4055 OpenDoor(DOOR_OPEN_1);
4057 OpenDoor(DOOR_OPEN_1);
4060 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
4062 if (game_status == GAME_MODE_PLAYING)
4064 SetPanelBackground();
4065 SetDrawBackgroundMask(REDRAW_DOOR_1);
4069 SetDrawBackgroundMask(REDRAW_FIELD);
4076 if (game_status != GAME_MODE_MAIN && !global.use_envelope_request)
4079 if (game_status != GAME_MODE_MAIN)
4083 button_status = MB_RELEASED;
4085 request_gadget_id = -1;
4087 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
4099 case EVENT_BUTTONPRESS:
4100 case EVENT_BUTTONRELEASE:
4101 case EVENT_MOTIONNOTIFY:
4103 if (event.type == EVENT_MOTIONNOTIFY)
4105 if (!PointerInWindow(window))
4106 continue; /* window and pointer are on different screens */
4111 motion_status = TRUE;
4112 mx = ((MotionEvent *) &event)->x;
4113 my = ((MotionEvent *) &event)->y;
4117 motion_status = FALSE;
4118 mx = ((ButtonEvent *) &event)->x;
4119 my = ((ButtonEvent *) &event)->y;
4120 if (event.type == EVENT_BUTTONPRESS)
4121 button_status = ((ButtonEvent *) &event)->button;
4123 button_status = MB_RELEASED;
4126 /* this sets 'request_gadget_id' */
4127 HandleGadgets(mx, my, button_status);
4129 switch (request_gadget_id)
4131 case TOOL_CTRL_ID_YES:
4134 case TOOL_CTRL_ID_NO:
4137 case TOOL_CTRL_ID_CONFIRM:
4138 result = TRUE | FALSE;
4141 case TOOL_CTRL_ID_PLAYER_1:
4144 case TOOL_CTRL_ID_PLAYER_2:
4147 case TOOL_CTRL_ID_PLAYER_3:
4150 case TOOL_CTRL_ID_PLAYER_4:
4161 case EVENT_KEYPRESS:
4162 switch (GetEventKey((KeyEvent *)&event, TRUE))
4165 if (req_state & REQ_CONFIRM)
4181 if (req_state & REQ_PLAYER)
4185 case EVENT_KEYRELEASE:
4186 ClearPlayerAction();
4190 HandleOtherEvents(&event);
4194 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
4196 int joy = AnyJoystick();
4198 if (joy & JOY_BUTTON_1)
4200 else if (joy & JOY_BUTTON_2)
4206 if (game_status == GAME_MODE_PLAYING && local_player->LevelSolved_GameEnd)
4208 HandleGameActions();
4214 if (!PendingEvent()) /* delay only if no pending events */
4219 game_status = GAME_MODE_PSEUDO_DOOR;
4225 game_status = last_game_status; /* restore current game status */
4233 if (!PendingEvent()) /* delay only if no pending events */
4236 /* don't eat all CPU time */
4243 if (game_status != GAME_MODE_MAIN)
4249 if (global.use_envelope_request)
4250 ShowEnvelopeDoor(text, ACTION_CLOSING);
4254 if (!(req_state & REQ_STAY_OPEN) && !global.use_envelope_request)
4256 if (!(req_state & REQ_STAY_OPEN))
4259 CloseDoor(DOOR_CLOSE_1);
4261 if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
4262 (req_state & REQ_REOPEN))
4263 OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
4268 if (game_status == GAME_MODE_PLAYING)
4270 SetPanelBackground();
4271 SetDrawBackgroundMask(REDRAW_DOOR_1);
4275 SetDrawBackgroundMask(REDRAW_FIELD);
4278 #if defined(NETWORK_AVALIABLE)
4279 /* continue network game after request */
4280 if (options.network &&
4281 game_status == GAME_MODE_PLAYING &&
4282 req_state & REQUEST_WAIT_FOR_INPUT)
4283 SendToServer_ContinuePlaying();
4286 /* restore deactivated drawing when quick-loading level tape recording */
4287 if (tape.playing && tape.deactivate_display)
4288 TapeDeactivateDisplayOn();
4293 unsigned int OpenDoor(unsigned int door_state)
4295 if (door_state & DOOR_COPY_BACK)
4297 if (door_state & DOOR_OPEN_1)
4298 BlitBitmap(bitmap_db_door, bitmap_db_door,
4299 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
4300 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
4302 if (door_state & DOOR_OPEN_2)
4303 BlitBitmap(bitmap_db_door, bitmap_db_door,
4304 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY2, VXSIZE, VYSIZE,
4305 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
4307 door_state &= ~DOOR_COPY_BACK;
4310 return MoveDoor(door_state);
4313 unsigned int CloseDoor(unsigned int door_state)
4315 unsigned int old_door_state = GetDoorState();
4317 if (!(door_state & DOOR_NO_COPY_BACK))
4319 if (old_door_state & DOOR_OPEN_1)
4320 BlitBitmap(backbuffer, bitmap_db_door,
4321 DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
4323 if (old_door_state & DOOR_OPEN_2)
4324 BlitBitmap(backbuffer, bitmap_db_door,
4325 VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
4327 door_state &= ~DOOR_NO_COPY_BACK;
4330 return MoveDoor(door_state);
4333 unsigned int GetDoorState()
4335 return MoveDoor(DOOR_GET_STATE);
4338 unsigned int SetDoorState(unsigned int door_state)
4340 return MoveDoor(door_state | DOOR_SET_STATE);
4343 unsigned int MoveDoor(unsigned int door_state)
4345 static int door1 = DOOR_OPEN_1;
4346 static int door2 = DOOR_CLOSE_2;
4347 unsigned int door_delay = 0;
4348 unsigned int door_delay_value;
4351 if (door_1.width < 0 || door_1.width > DXSIZE)
4352 door_1.width = DXSIZE;
4353 if (door_1.height < 0 || door_1.height > DYSIZE)
4354 door_1.height = DYSIZE;
4355 if (door_2.width < 0 || door_2.width > VXSIZE)
4356 door_2.width = VXSIZE;
4357 if (door_2.height < 0 || door_2.height > VYSIZE)
4358 door_2.height = VYSIZE;
4360 if (door_state == DOOR_GET_STATE)
4361 return (door1 | door2);
4363 if (door_state & DOOR_SET_STATE)
4365 if (door_state & DOOR_ACTION_1)
4366 door1 = door_state & DOOR_ACTION_1;
4367 if (door_state & DOOR_ACTION_2)
4368 door2 = door_state & DOOR_ACTION_2;
4370 return (door1 | door2);
4373 if (!(door_state & DOOR_FORCE_REDRAW))
4375 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
4376 door_state &= ~DOOR_OPEN_1;
4377 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
4378 door_state &= ~DOOR_CLOSE_1;
4379 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
4380 door_state &= ~DOOR_OPEN_2;
4381 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
4382 door_state &= ~DOOR_CLOSE_2;
4385 door_delay_value = (door_state & DOOR_ACTION_1 ? door_1.step_delay :
4388 if (setup.quick_doors)
4390 stepsize = 20; /* must be chosen to always draw last frame */
4391 door_delay_value = 0;
4394 if (global.autoplay_leveldir)
4396 door_state |= DOOR_NO_DELAY;
4397 door_state &= ~DOOR_CLOSE_ALL;
4401 if (game_status == GAME_MODE_EDITOR)
4402 door_state |= DOOR_NO_DELAY;
4405 if (door_state & DOOR_ACTION)
4407 boolean handle_door_1 = (door_state & DOOR_ACTION_1);
4408 boolean handle_door_2 = (door_state & DOOR_ACTION_2);
4409 boolean door_1_done = (!handle_door_1);
4410 boolean door_2_done = (!handle_door_2);
4411 boolean door_1_vertical = (door_1.anim_mode & ANIM_VERTICAL);
4412 boolean door_2_vertical = (door_2.anim_mode & ANIM_VERTICAL);
4413 int door_size_1 = (door_1_vertical ? door_1.height : door_1.width);
4414 int door_size_2 = (door_2_vertical ? door_2.height : door_2.width);
4415 int max_door_size_1 = (door_1_vertical ? DYSIZE : DXSIZE);
4416 int max_door_size_2 = (door_2_vertical ? VYSIZE : VXSIZE);
4417 int door_size = (handle_door_1 ? door_size_1 : door_size_2);
4418 int max_door_size = (handle_door_1 ? max_door_size_1 : max_door_size_2);
4419 int door_skip = max_door_size - door_size;
4420 int end = door_size;
4421 int start = ((door_state & DOOR_NO_DELAY) ? end : 0);
4424 if (!(door_state & DOOR_NO_DELAY) && !setup.quick_doors)
4426 /* opening door sound has priority over simultaneously closing door */
4427 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
4428 PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
4429 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
4430 PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
4433 for (k = start; k <= end && !(door_1_done && door_2_done); k += stepsize)
4436 Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
4437 GC gc = bitmap->stored_clip_gc;
4439 if (door_state & DOOR_ACTION_1)
4441 int a = MIN(x * door_1.step_offset, end);
4442 int p = (door_state & DOOR_OPEN_1 ? end - a : a);
4443 int i = p + door_skip;
4445 if (door_1.anim_mode & ANIM_STATIC_PANEL)
4447 BlitBitmap(bitmap_db_door, drawto,
4448 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1,
4449 DXSIZE, DYSIZE, DX, DY);
4453 BlitBitmap(bitmap_db_door, drawto,
4454 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + p / 2,
4455 DXSIZE, DYSIZE - p / 2, DX, DY);
4457 ClearRectangle(drawto, DX, DY + DYSIZE - p / 2, DXSIZE, p / 2);
4460 if (door_1.anim_mode & ANIM_HORIZONTAL && x <= DXSIZE)
4462 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
4463 int dst1_x = DX + DXSIZE - i, dst1_y = DY;
4464 int src2_x = DXSIZE - i, src2_y = DOOR_GFX_PAGEY1;
4465 int dst2_x = DX, dst2_y = DY;
4466 int width = i, height = DYSIZE;
4468 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
4469 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
4472 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
4473 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
4476 else if (door_1.anim_mode & ANIM_VERTICAL && x <= DYSIZE)
4478 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
4479 int dst1_x = DX, dst1_y = DY + DYSIZE - i;
4480 int src2_x = 0, src2_y = DOOR_GFX_PAGEY1 + DYSIZE - i;
4481 int dst2_x = DX, dst2_y = DY;
4482 int width = DXSIZE, height = i;
4484 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
4485 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
4488 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
4489 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
4492 else if (x <= DXSIZE) /* ANIM_DEFAULT */
4494 int j = (door_1.anim_mode == ANIM_DEFAULT ? (DXSIZE - i) / 3 : 0);
4496 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
4497 BlitBitmapMasked(bitmap, drawto,
4498 DXSIZE, DOOR_GFX_PAGEY1, i, 77,
4499 DX + DXSIZE - i, DY + j);
4500 BlitBitmapMasked(bitmap, drawto,
4501 DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
4502 DX + DXSIZE - i, DY + 140 + j);
4503 SetClipOrigin(bitmap, gc, DX - DXSIZE + i,
4504 DY - (DOOR_GFX_PAGEY1 + j));
4505 BlitBitmapMasked(bitmap, drawto,
4506 DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
4508 BlitBitmapMasked(bitmap, drawto,
4509 DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
4512 BlitBitmapMasked(bitmap, drawto,
4513 DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
4515 BlitBitmapMasked(bitmap, drawto,
4516 DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
4518 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
4519 BlitBitmapMasked(bitmap, drawto,
4520 DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
4521 DX + DXSIZE - i, DY + 77 + j);
4522 BlitBitmapMasked(bitmap, drawto,
4523 DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
4524 DX + DXSIZE - i, DY + 203 + j);
4527 redraw_mask |= REDRAW_DOOR_1;
4528 door_1_done = (a == end);
4531 if (door_state & DOOR_ACTION_2)
4533 int a = MIN(x * door_2.step_offset, door_size);
4534 int p = (door_state & DOOR_OPEN_2 ? door_size - a : a);
4535 int i = p + door_skip;
4537 if (door_2.anim_mode & ANIM_STATIC_PANEL)
4539 BlitBitmap(bitmap_db_door, drawto,
4540 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2,
4541 VXSIZE, VYSIZE, VX, VY);
4543 else if (x <= VYSIZE)
4545 BlitBitmap(bitmap_db_door, drawto,
4546 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + p / 2,
4547 VXSIZE, VYSIZE - p / 2, VX, VY);
4549 ClearRectangle(drawto, VX, VY + VYSIZE - p / 2, VXSIZE, p / 2);
4552 if (door_2.anim_mode & ANIM_HORIZONTAL && x <= VXSIZE)
4554 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
4555 int dst1_x = VX + VXSIZE - i, dst1_y = VY;
4556 int src2_x = VXSIZE - i, src2_y = DOOR_GFX_PAGEY2;
4557 int dst2_x = VX, dst2_y = VY;
4558 int width = i, height = VYSIZE;
4560 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
4561 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
4564 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
4565 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
4568 else if (door_2.anim_mode & ANIM_VERTICAL && x <= VYSIZE)
4570 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
4571 int dst1_x = VX, dst1_y = VY + VYSIZE - i;
4572 int src2_x = 0, src2_y = DOOR_GFX_PAGEY2 + VYSIZE - i;
4573 int dst2_x = VX, dst2_y = VY;
4574 int width = VXSIZE, height = i;
4576 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
4577 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
4580 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
4581 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
4584 else if (x <= VXSIZE) /* ANIM_DEFAULT */
4586 int j = (door_2.anim_mode == ANIM_DEFAULT ? (VXSIZE - i) / 3 : 0);
4588 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
4589 BlitBitmapMasked(bitmap, drawto,
4590 VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
4591 VX + VXSIZE - i, VY + j);
4592 SetClipOrigin(bitmap, gc,
4593 VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
4594 BlitBitmapMasked(bitmap, drawto,
4595 VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
4598 BlitBitmapMasked(bitmap, drawto,
4599 VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
4600 i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
4601 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
4602 BlitBitmapMasked(bitmap, drawto,
4603 VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
4605 VX + VXSIZE - i, VY + VYSIZE / 2 + j);
4608 redraw_mask |= REDRAW_DOOR_2;
4609 door_2_done = (a == VXSIZE);
4612 if (!(door_state & DOOR_NO_DELAY))
4616 if (game_status == GAME_MODE_MAIN)
4619 WaitUntilDelayReached(&door_delay, door_delay_value);
4624 if (door_state & DOOR_ACTION_1)
4625 door1 = door_state & DOOR_ACTION_1;
4626 if (door_state & DOOR_ACTION_2)
4627 door2 = door_state & DOOR_ACTION_2;
4629 return (door1 | door2);
4632 void DrawSpecialEditorDoor()
4634 /* draw bigger toolbox window */
4635 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
4636 DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
4638 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
4639 EX - 6, VY - 4, EXSIZE + 12, EYSIZE - VYSIZE + 4,
4642 redraw_mask |= REDRAW_ALL;
4645 void UndrawSpecialEditorDoor()
4647 /* draw normal tape recorder window */
4648 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
4649 EX - 6, EY - 12, EXSIZE + 12, EYSIZE - VYSIZE + 12,
4652 redraw_mask |= REDRAW_ALL;
4656 /* ---------- new tool button stuff ---------------------------------------- */
4658 /* graphic position values for tool buttons */
4659 #define TOOL_BUTTON_YES_XPOS 2
4660 #define TOOL_BUTTON_YES_YPOS 250
4661 #define TOOL_BUTTON_YES_GFX_YPOS 0
4662 #define TOOL_BUTTON_YES_XSIZE 46
4663 #define TOOL_BUTTON_YES_YSIZE 28
4664 #define TOOL_BUTTON_NO_XPOS 52
4665 #define TOOL_BUTTON_NO_YPOS TOOL_BUTTON_YES_YPOS
4666 #define TOOL_BUTTON_NO_GFX_YPOS TOOL_BUTTON_YES_GFX_YPOS
4667 #define TOOL_BUTTON_NO_XSIZE TOOL_BUTTON_YES_XSIZE
4668 #define TOOL_BUTTON_NO_YSIZE TOOL_BUTTON_YES_YSIZE
4669 #define TOOL_BUTTON_CONFIRM_XPOS TOOL_BUTTON_YES_XPOS
4670 #define TOOL_BUTTON_CONFIRM_YPOS TOOL_BUTTON_YES_YPOS
4671 #define TOOL_BUTTON_CONFIRM_GFX_YPOS 30
4672 #define TOOL_BUTTON_CONFIRM_XSIZE 96
4673 #define TOOL_BUTTON_CONFIRM_YSIZE TOOL_BUTTON_YES_YSIZE
4674 #define TOOL_BUTTON_PLAYER_XSIZE 30
4675 #define TOOL_BUTTON_PLAYER_YSIZE 30
4676 #define TOOL_BUTTON_PLAYER_GFX_XPOS 5
4677 #define TOOL_BUTTON_PLAYER_GFX_YPOS 185
4678 #define TOOL_BUTTON_PLAYER_XPOS (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
4679 #define TOOL_BUTTON_PLAYER_YPOS (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
4680 #define TOOL_BUTTON_PLAYER1_XPOS (TOOL_BUTTON_PLAYER_XPOS \
4681 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
4682 #define TOOL_BUTTON_PLAYER2_XPOS (TOOL_BUTTON_PLAYER_XPOS \
4683 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
4684 #define TOOL_BUTTON_PLAYER3_XPOS (TOOL_BUTTON_PLAYER_XPOS \
4685 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
4686 #define TOOL_BUTTON_PLAYER4_XPOS (TOOL_BUTTON_PLAYER_XPOS \
4687 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
4688 #define TOOL_BUTTON_PLAYER1_YPOS (TOOL_BUTTON_PLAYER_YPOS \
4689 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
4690 #define TOOL_BUTTON_PLAYER2_YPOS (TOOL_BUTTON_PLAYER_YPOS \
4691 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
4692 #define TOOL_BUTTON_PLAYER3_YPOS (TOOL_BUTTON_PLAYER_YPOS \
4693 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
4694 #define TOOL_BUTTON_PLAYER4_YPOS (TOOL_BUTTON_PLAYER_YPOS \
4695 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
4704 } toolbutton_info[NUM_TOOL_BUTTONS] =
4707 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_GFX_YPOS,
4708 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_YPOS,
4709 TOOL_BUTTON_YES_XSIZE, TOOL_BUTTON_YES_YSIZE,
4714 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_GFX_YPOS,
4715 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_YPOS,
4716 TOOL_BUTTON_NO_XSIZE, TOOL_BUTTON_NO_YSIZE,
4721 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_GFX_YPOS,
4722 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_YPOS,
4723 TOOL_BUTTON_CONFIRM_XSIZE, TOOL_BUTTON_CONFIRM_YSIZE,
4724 TOOL_CTRL_ID_CONFIRM,
4728 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
4729 TOOL_BUTTON_PLAYER1_XPOS, TOOL_BUTTON_PLAYER1_YPOS,
4730 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
4731 TOOL_CTRL_ID_PLAYER_1,
4735 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
4736 TOOL_BUTTON_PLAYER2_XPOS, TOOL_BUTTON_PLAYER2_YPOS,
4737 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
4738 TOOL_CTRL_ID_PLAYER_2,
4742 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
4743 TOOL_BUTTON_PLAYER3_XPOS, TOOL_BUTTON_PLAYER3_YPOS,
4744 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
4745 TOOL_CTRL_ID_PLAYER_3,
4749 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
4750 TOOL_BUTTON_PLAYER4_XPOS, TOOL_BUTTON_PLAYER4_YPOS,
4751 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
4752 TOOL_CTRL_ID_PLAYER_4,
4757 void CreateToolButtons()
4761 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4763 Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
4764 Bitmap *deco_bitmap = None;
4765 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
4766 struct GadgetInfo *gi;
4767 unsigned int event_mask;
4768 int gd_xoffset, gd_yoffset;
4769 int gd_x1, gd_x2, gd_y;
4772 event_mask = GD_EVENT_RELEASED;
4774 gd_xoffset = toolbutton_info[i].xpos;
4775 gd_yoffset = toolbutton_info[i].ypos;
4776 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
4777 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
4778 gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
4780 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
4782 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
4784 getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr),
4785 &deco_bitmap, &deco_x, &deco_y);
4786 deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
4787 deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
4790 gi = CreateGadget(GDI_CUSTOM_ID, id,
4791 GDI_INFO_TEXT, toolbutton_info[i].infotext,
4792 GDI_X, DX + toolbutton_info[i].x,
4793 GDI_Y, DY + toolbutton_info[i].y,
4794 GDI_WIDTH, toolbutton_info[i].width,
4795 GDI_HEIGHT, toolbutton_info[i].height,
4796 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
4797 GDI_STATE, GD_BUTTON_UNPRESSED,
4798 GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
4799 GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
4800 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
4801 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
4802 GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
4803 GDI_DECORATION_SHIFTING, 1, 1,
4804 GDI_DIRECT_DRAW, FALSE,
4805 GDI_EVENT_MASK, event_mask,
4806 GDI_CALLBACK_ACTION, HandleToolButtons,
4810 Error(ERR_EXIT, "cannot create gadget");
4812 tool_gadget[id] = gi;
4816 void FreeToolButtons()
4820 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4821 FreeGadget(tool_gadget[i]);
4824 static void UnmapToolButtons()
4828 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4829 UnmapGadget(tool_gadget[i]);
4832 static void HandleToolButtons(struct GadgetInfo *gi)
4834 request_gadget_id = gi->custom_id;
4837 static struct Mapping_EM_to_RND_object
4840 boolean is_rnd_to_em_mapping; /* unique mapping EM <-> RND */
4841 boolean is_backside; /* backside of moving element */
4847 em_object_mapping_list[] =
4850 Xblank, TRUE, FALSE,
4854 Yacid_splash_eB, FALSE, FALSE,
4855 EL_ACID_SPLASH_RIGHT, -1, -1
4858 Yacid_splash_wB, FALSE, FALSE,
4859 EL_ACID_SPLASH_LEFT, -1, -1
4862 #ifdef EM_ENGINE_BAD_ROLL
4864 Xstone_force_e, FALSE, FALSE,
4865 EL_ROCK, -1, MV_BIT_RIGHT
4868 Xstone_force_w, FALSE, FALSE,
4869 EL_ROCK, -1, MV_BIT_LEFT
4872 Xnut_force_e, FALSE, FALSE,
4873 EL_NUT, -1, MV_BIT_RIGHT
4876 Xnut_force_w, FALSE, FALSE,
4877 EL_NUT, -1, MV_BIT_LEFT
4880 Xspring_force_e, FALSE, FALSE,
4881 EL_SPRING, -1, MV_BIT_RIGHT
4884 Xspring_force_w, FALSE, FALSE,
4885 EL_SPRING, -1, MV_BIT_LEFT
4888 Xemerald_force_e, FALSE, FALSE,
4889 EL_EMERALD, -1, MV_BIT_RIGHT
4892 Xemerald_force_w, FALSE, FALSE,
4893 EL_EMERALD, -1, MV_BIT_LEFT
4896 Xdiamond_force_e, FALSE, FALSE,
4897 EL_DIAMOND, -1, MV_BIT_RIGHT
4900 Xdiamond_force_w, FALSE, FALSE,
4901 EL_DIAMOND, -1, MV_BIT_LEFT
4904 Xbomb_force_e, FALSE, FALSE,
4905 EL_BOMB, -1, MV_BIT_RIGHT
4908 Xbomb_force_w, FALSE, FALSE,
4909 EL_BOMB, -1, MV_BIT_LEFT
4911 #endif /* EM_ENGINE_BAD_ROLL */
4914 Xstone, TRUE, FALSE,
4918 Xstone_pause, FALSE, FALSE,
4922 Xstone_fall, FALSE, FALSE,
4926 Ystone_s, FALSE, FALSE,
4927 EL_ROCK, ACTION_FALLING, -1
4930 Ystone_sB, FALSE, TRUE,
4931 EL_ROCK, ACTION_FALLING, -1
4934 Ystone_e, FALSE, FALSE,
4935 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
4938 Ystone_eB, FALSE, TRUE,
4939 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
4942 Ystone_w, FALSE, FALSE,
4943 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
4946 Ystone_wB, FALSE, TRUE,
4947 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
4954 Xnut_pause, FALSE, FALSE,
4958 Xnut_fall, FALSE, FALSE,
4962 Ynut_s, FALSE, FALSE,
4963 EL_NUT, ACTION_FALLING, -1
4966 Ynut_sB, FALSE, TRUE,
4967 EL_NUT, ACTION_FALLING, -1
4970 Ynut_e, FALSE, FALSE,
4971 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
4974 Ynut_eB, FALSE, TRUE,
4975 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
4978 Ynut_w, FALSE, FALSE,
4979 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
4982 Ynut_wB, FALSE, TRUE,
4983 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
4986 Xbug_n, TRUE, FALSE,
4990 Xbug_e, TRUE, FALSE,
4991 EL_BUG_RIGHT, -1, -1
4994 Xbug_s, TRUE, FALSE,
4998 Xbug_w, TRUE, FALSE,
5002 Xbug_gon, FALSE, FALSE,
5006 Xbug_goe, FALSE, FALSE,
5007 EL_BUG_RIGHT, -1, -1
5010 Xbug_gos, FALSE, FALSE,
5014 Xbug_gow, FALSE, FALSE,
5018 Ybug_n, FALSE, FALSE,
5019 EL_BUG, ACTION_MOVING, MV_BIT_UP
5022 Ybug_nB, FALSE, TRUE,
5023 EL_BUG, ACTION_MOVING, MV_BIT_UP
5026 Ybug_e, FALSE, FALSE,
5027 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
5030 Ybug_eB, FALSE, TRUE,
5031 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
5034 Ybug_s, FALSE, FALSE,
5035 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
5038 Ybug_sB, FALSE, TRUE,
5039 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
5042 Ybug_w, FALSE, FALSE,
5043 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
5046 Ybug_wB, FALSE, TRUE,
5047 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
5050 Ybug_w_n, FALSE, FALSE,
5051 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
5054 Ybug_n_e, FALSE, FALSE,
5055 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
5058 Ybug_e_s, FALSE, FALSE,
5059 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
5062 Ybug_s_w, FALSE, FALSE,
5063 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
5066 Ybug_e_n, FALSE, FALSE,
5067 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
5070 Ybug_s_e, FALSE, FALSE,
5071 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
5074 Ybug_w_s, FALSE, FALSE,
5075 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
5078 Ybug_n_w, FALSE, FALSE,
5079 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
5082 Ybug_stone, FALSE, FALSE,
5083 EL_BUG, ACTION_SMASHED_BY_ROCK, -1
5086 Ybug_spring, FALSE, FALSE,
5087 EL_BUG, ACTION_SMASHED_BY_SPRING, -1
5090 Xtank_n, TRUE, FALSE,
5091 EL_SPACESHIP_UP, -1, -1
5094 Xtank_e, TRUE, FALSE,
5095 EL_SPACESHIP_RIGHT, -1, -1
5098 Xtank_s, TRUE, FALSE,
5099 EL_SPACESHIP_DOWN, -1, -1
5102 Xtank_w, TRUE, FALSE,
5103 EL_SPACESHIP_LEFT, -1, -1
5106 Xtank_gon, FALSE, FALSE,
5107 EL_SPACESHIP_UP, -1, -1
5110 Xtank_goe, FALSE, FALSE,
5111 EL_SPACESHIP_RIGHT, -1, -1
5114 Xtank_gos, FALSE, FALSE,
5115 EL_SPACESHIP_DOWN, -1, -1
5118 Xtank_gow, FALSE, FALSE,
5119 EL_SPACESHIP_LEFT, -1, -1
5122 Ytank_n, FALSE, FALSE,
5123 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
5126 Ytank_nB, FALSE, TRUE,
5127 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
5130 Ytank_e, FALSE, FALSE,
5131 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
5134 Ytank_eB, FALSE, TRUE,
5135 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
5138 Ytank_s, FALSE, FALSE,
5139 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
5142 Ytank_sB, FALSE, TRUE,
5143 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
5146 Ytank_w, FALSE, FALSE,
5147 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
5150 Ytank_wB, FALSE, TRUE,
5151 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
5154 Ytank_w_n, FALSE, FALSE,
5155 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
5158 Ytank_n_e, FALSE, FALSE,
5159 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
5162 Ytank_e_s, FALSE, FALSE,
5163 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
5166 Ytank_s_w, FALSE, FALSE,
5167 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
5170 Ytank_e_n, FALSE, FALSE,
5171 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
5174 Ytank_s_e, FALSE, FALSE,
5175 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
5178 Ytank_w_s, FALSE, FALSE,
5179 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
5182 Ytank_n_w, FALSE, FALSE,
5183 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
5186 Ytank_stone, FALSE, FALSE,
5187 EL_SPACESHIP, ACTION_SMASHED_BY_ROCK, -1
5190 Ytank_spring, FALSE, FALSE,
5191 EL_SPACESHIP, ACTION_SMASHED_BY_SPRING, -1
5194 Xandroid, TRUE, FALSE,
5195 EL_EMC_ANDROID, ACTION_ACTIVE, -1
5198 Xandroid_1_n, FALSE, FALSE,
5199 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
5202 Xandroid_2_n, FALSE, FALSE,
5203 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
5206 Xandroid_1_e, FALSE, FALSE,
5207 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
5210 Xandroid_2_e, FALSE, FALSE,
5211 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
5214 Xandroid_1_w, FALSE, FALSE,
5215 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
5218 Xandroid_2_w, FALSE, FALSE,
5219 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
5222 Xandroid_1_s, FALSE, FALSE,
5223 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
5226 Xandroid_2_s, FALSE, FALSE,
5227 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
5230 Yandroid_n, FALSE, FALSE,
5231 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
5234 Yandroid_nB, FALSE, TRUE,
5235 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
5238 Yandroid_ne, FALSE, FALSE,
5239 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPRIGHT
5242 Yandroid_neB, FALSE, TRUE,
5243 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPRIGHT
5246 Yandroid_e, FALSE, FALSE,
5247 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
5250 Yandroid_eB, FALSE, TRUE,
5251 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
5254 Yandroid_se, FALSE, FALSE,
5255 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNRIGHT
5258 Yandroid_seB, FALSE, TRUE,
5259 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNRIGHT
5262 Yandroid_s, FALSE, FALSE,
5263 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
5266 Yandroid_sB, FALSE, TRUE,
5267 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
5270 Yandroid_sw, FALSE, FALSE,
5271 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNLEFT
5274 Yandroid_swB, FALSE, TRUE,
5275 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNLEFT
5278 Yandroid_w, FALSE, FALSE,
5279 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
5282 Yandroid_wB, FALSE, TRUE,
5283 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
5286 Yandroid_nw, FALSE, FALSE,
5287 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPLEFT
5290 Yandroid_nwB, FALSE, TRUE,
5291 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPLEFT
5294 Xspring, TRUE, FALSE,
5298 Xspring_pause, FALSE, FALSE,
5302 Xspring_e, FALSE, FALSE,
5306 Xspring_w, FALSE, FALSE,
5310 Xspring_fall, FALSE, FALSE,
5314 Yspring_s, FALSE, FALSE,
5315 EL_SPRING, ACTION_FALLING, -1
5318 Yspring_sB, FALSE, TRUE,
5319 EL_SPRING, ACTION_FALLING, -1
5322 Yspring_e, FALSE, FALSE,
5323 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
5326 Yspring_eB, FALSE, TRUE,
5327 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
5330 Yspring_w, FALSE, FALSE,
5331 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
5334 Yspring_wB, FALSE, TRUE,
5335 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
5338 Yspring_kill_e, FALSE, FALSE,
5339 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
5342 Yspring_kill_eB, FALSE, TRUE,
5343 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
5346 Yspring_kill_w, FALSE, FALSE,
5347 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
5350 Yspring_kill_wB, FALSE, TRUE,
5351 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
5354 Xeater_n, TRUE, FALSE,
5355 EL_YAMYAM_UP, -1, -1
5358 Xeater_e, TRUE, FALSE,
5359 EL_YAMYAM_RIGHT, -1, -1
5362 Xeater_w, TRUE, FALSE,
5363 EL_YAMYAM_LEFT, -1, -1
5366 Xeater_s, TRUE, FALSE,
5367 EL_YAMYAM_DOWN, -1, -1
5370 Yeater_n, FALSE, FALSE,
5371 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
5374 Yeater_nB, FALSE, TRUE,
5375 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
5378 Yeater_e, FALSE, FALSE,
5379 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
5382 Yeater_eB, FALSE, TRUE,
5383 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
5386 Yeater_s, FALSE, FALSE,
5387 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
5390 Yeater_sB, FALSE, TRUE,
5391 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
5394 Yeater_w, FALSE, FALSE,
5395 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
5398 Yeater_wB, FALSE, TRUE,
5399 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
5402 Yeater_stone, FALSE, FALSE,
5403 EL_YAMYAM, ACTION_SMASHED_BY_ROCK, -1
5406 Yeater_spring, FALSE, FALSE,
5407 EL_YAMYAM, ACTION_SMASHED_BY_SPRING, -1
5410 Xalien, TRUE, FALSE,
5414 Xalien_pause, FALSE, FALSE,
5418 Yalien_n, FALSE, FALSE,
5419 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
5422 Yalien_nB, FALSE, TRUE,
5423 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
5426 Yalien_e, FALSE, FALSE,
5427 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
5430 Yalien_eB, FALSE, TRUE,
5431 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
5434 Yalien_s, FALSE, FALSE,
5435 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
5438 Yalien_sB, FALSE, TRUE,
5439 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
5442 Yalien_w, FALSE, FALSE,
5443 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
5446 Yalien_wB, FALSE, TRUE,
5447 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
5450 Yalien_stone, FALSE, FALSE,
5451 EL_ROBOT, ACTION_SMASHED_BY_ROCK, -1
5454 Yalien_spring, FALSE, FALSE,
5455 EL_ROBOT, ACTION_SMASHED_BY_SPRING, -1
5458 Xemerald, TRUE, FALSE,
5462 Xemerald_pause, FALSE, FALSE,
5466 Xemerald_fall, FALSE, FALSE,
5470 Xemerald_shine, FALSE, FALSE,
5471 EL_EMERALD, ACTION_TWINKLING, -1
5474 Yemerald_s, FALSE, FALSE,
5475 EL_EMERALD, ACTION_FALLING, -1
5478 Yemerald_sB, FALSE, TRUE,
5479 EL_EMERALD, ACTION_FALLING, -1
5482 Yemerald_e, FALSE, FALSE,
5483 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
5486 Yemerald_eB, FALSE, TRUE,
5487 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
5490 Yemerald_w, FALSE, FALSE,
5491 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
5494 Yemerald_wB, FALSE, TRUE,
5495 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
5498 Yemerald_eat, FALSE, FALSE,
5499 EL_EMERALD, ACTION_COLLECTING, -1
5502 Yemerald_stone, FALSE, FALSE,
5503 EL_NUT, ACTION_BREAKING, -1
5506 Xdiamond, TRUE, FALSE,
5510 Xdiamond_pause, FALSE, FALSE,
5514 Xdiamond_fall, FALSE, FALSE,
5518 Xdiamond_shine, FALSE, FALSE,
5519 EL_DIAMOND, ACTION_TWINKLING, -1
5522 Ydiamond_s, FALSE, FALSE,
5523 EL_DIAMOND, ACTION_FALLING, -1
5526 Ydiamond_sB, FALSE, TRUE,
5527 EL_DIAMOND, ACTION_FALLING, -1
5530 Ydiamond_e, FALSE, FALSE,
5531 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
5534 Ydiamond_eB, FALSE, TRUE,
5535 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
5538 Ydiamond_w, FALSE, FALSE,
5539 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
5542 Ydiamond_wB, FALSE, TRUE,
5543 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
5546 Ydiamond_eat, FALSE, FALSE,
5547 EL_DIAMOND, ACTION_COLLECTING, -1
5550 Ydiamond_stone, FALSE, FALSE,
5551 EL_DIAMOND, ACTION_SMASHED_BY_ROCK, -1
5554 Xdrip_fall, TRUE, FALSE,
5555 EL_AMOEBA_DROP, -1, -1
5558 Xdrip_stretch, FALSE, FALSE,
5559 EL_AMOEBA_DROP, ACTION_FALLING, -1
5562 Xdrip_stretchB, FALSE, TRUE,
5563 EL_AMOEBA_DROP, ACTION_FALLING, -1
5566 Xdrip_eat, FALSE, FALSE,
5567 EL_AMOEBA_DROP, ACTION_GROWING, -1
5570 Ydrip_s1, FALSE, FALSE,
5571 EL_AMOEBA_DROP, ACTION_FALLING, -1
5574 Ydrip_s1B, FALSE, TRUE,
5575 EL_AMOEBA_DROP, ACTION_FALLING, -1
5578 Ydrip_s2, FALSE, FALSE,
5579 EL_AMOEBA_DROP, ACTION_FALLING, -1
5582 Ydrip_s2B, FALSE, TRUE,
5583 EL_AMOEBA_DROP, ACTION_FALLING, -1
5590 Xbomb_pause, FALSE, FALSE,
5594 Xbomb_fall, FALSE, FALSE,
5598 Ybomb_s, FALSE, FALSE,
5599 EL_BOMB, ACTION_FALLING, -1
5602 Ybomb_sB, FALSE, TRUE,
5603 EL_BOMB, ACTION_FALLING, -1
5606 Ybomb_e, FALSE, FALSE,
5607 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
5610 Ybomb_eB, FALSE, TRUE,
5611 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
5614 Ybomb_w, FALSE, FALSE,
5615 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
5618 Ybomb_wB, FALSE, TRUE,
5619 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
5622 Ybomb_eat, FALSE, FALSE,
5623 EL_BOMB, ACTION_ACTIVATING, -1
5626 Xballoon, TRUE, FALSE,
5630 Yballoon_n, FALSE, FALSE,
5631 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
5634 Yballoon_nB, FALSE, TRUE,
5635 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
5638 Yballoon_e, FALSE, FALSE,
5639 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
5642 Yballoon_eB, FALSE, TRUE,
5643 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
5646 Yballoon_s, FALSE, FALSE,
5647 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
5650 Yballoon_sB, FALSE, TRUE,
5651 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
5654 Yballoon_w, FALSE, FALSE,
5655 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
5658 Yballoon_wB, FALSE, TRUE,
5659 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
5662 Xgrass, TRUE, FALSE,
5663 EL_EMC_GRASS, -1, -1
5666 Ygrass_nB, FALSE, FALSE,
5667 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_UP
5670 Ygrass_eB, FALSE, FALSE,
5671 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_RIGHT
5674 Ygrass_sB, FALSE, FALSE,
5675 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_DOWN
5678 Ygrass_wB, FALSE, FALSE,
5679 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_LEFT
5686 Ydirt_nB, FALSE, FALSE,
5687 EL_SAND, ACTION_DIGGING, MV_BIT_UP
5690 Ydirt_eB, FALSE, FALSE,
5691 EL_SAND, ACTION_DIGGING, MV_BIT_RIGHT
5694 Ydirt_sB, FALSE, FALSE,
5695 EL_SAND, ACTION_DIGGING, MV_BIT_DOWN
5698 Ydirt_wB, FALSE, FALSE,
5699 EL_SAND, ACTION_DIGGING, MV_BIT_LEFT
5702 Xacid_ne, TRUE, FALSE,
5703 EL_ACID_POOL_TOPRIGHT, -1, -1
5706 Xacid_se, TRUE, FALSE,
5707 EL_ACID_POOL_BOTTOMRIGHT, -1, -1
5710 Xacid_s, TRUE, FALSE,
5711 EL_ACID_POOL_BOTTOM, -1, -1
5714 Xacid_sw, TRUE, FALSE,
5715 EL_ACID_POOL_BOTTOMLEFT, -1, -1
5718 Xacid_nw, TRUE, FALSE,
5719 EL_ACID_POOL_TOPLEFT, -1, -1
5722 Xacid_1, TRUE, FALSE,
5726 Xacid_2, FALSE, FALSE,
5730 Xacid_3, FALSE, FALSE,
5734 Xacid_4, FALSE, FALSE,
5738 Xacid_5, FALSE, FALSE,
5742 Xacid_6, FALSE, FALSE,
5746 Xacid_7, FALSE, FALSE,
5750 Xacid_8, FALSE, FALSE,
5754 Xball_1, TRUE, FALSE,
5755 EL_EMC_MAGIC_BALL, -1, -1
5758 Xball_1B, FALSE, FALSE,
5759 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
5762 Xball_2, FALSE, FALSE,
5763 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
5766 Xball_2B, FALSE, FALSE,
5767 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
5770 Yball_eat, FALSE, FALSE,
5771 EL_EMC_MAGIC_BALL, ACTION_DROPPING, -1
5774 Ykey_1_eat, FALSE, FALSE,
5775 EL_EM_KEY_1, ACTION_COLLECTING, -1
5778 Ykey_2_eat, FALSE, FALSE,
5779 EL_EM_KEY_2, ACTION_COLLECTING, -1
5782 Ykey_3_eat, FALSE, FALSE,
5783 EL_EM_KEY_3, ACTION_COLLECTING, -1
5786 Ykey_4_eat, FALSE, FALSE,
5787 EL_EM_KEY_4, ACTION_COLLECTING, -1
5790 Ykey_5_eat, FALSE, FALSE,
5791 EL_EMC_KEY_5, ACTION_COLLECTING, -1
5794 Ykey_6_eat, FALSE, FALSE,
5795 EL_EMC_KEY_6, ACTION_COLLECTING, -1
5798 Ykey_7_eat, FALSE, FALSE,
5799 EL_EMC_KEY_7, ACTION_COLLECTING, -1
5802 Ykey_8_eat, FALSE, FALSE,
5803 EL_EMC_KEY_8, ACTION_COLLECTING, -1
5806 Ylenses_eat, FALSE, FALSE,
5807 EL_EMC_LENSES, ACTION_COLLECTING, -1
5810 Ymagnify_eat, FALSE, FALSE,
5811 EL_EMC_MAGNIFIER, ACTION_COLLECTING, -1
5814 Ygrass_eat, FALSE, FALSE,
5815 EL_EMC_GRASS, ACTION_SNAPPING, -1
5818 Ydirt_eat, FALSE, FALSE,
5819 EL_SAND, ACTION_SNAPPING, -1
5822 Xgrow_ns, TRUE, FALSE,
5823 EL_EXPANDABLE_WALL_VERTICAL, -1, -1
5826 Ygrow_ns_eat, FALSE, FALSE,
5827 EL_EXPANDABLE_WALL_VERTICAL, ACTION_GROWING, -1
5830 Xgrow_ew, TRUE, FALSE,
5831 EL_EXPANDABLE_WALL_HORIZONTAL, -1, -1
5834 Ygrow_ew_eat, FALSE, FALSE,
5835 EL_EXPANDABLE_WALL_HORIZONTAL, ACTION_GROWING, -1
5838 Xwonderwall, TRUE, FALSE,
5839 EL_MAGIC_WALL, -1, -1
5842 XwonderwallB, FALSE, FALSE,
5843 EL_MAGIC_WALL, ACTION_ACTIVE, -1
5846 Xamoeba_1, TRUE, FALSE,
5847 EL_AMOEBA_DRY, ACTION_OTHER, -1
5850 Xamoeba_2, FALSE, FALSE,
5851 EL_AMOEBA_DRY, ACTION_OTHER, -1
5854 Xamoeba_3, FALSE, FALSE,
5855 EL_AMOEBA_DRY, ACTION_OTHER, -1
5858 Xamoeba_4, FALSE, FALSE,
5859 EL_AMOEBA_DRY, ACTION_OTHER, -1
5862 Xamoeba_5, TRUE, FALSE,
5863 EL_AMOEBA_WET, ACTION_OTHER, -1
5866 Xamoeba_6, FALSE, FALSE,
5867 EL_AMOEBA_WET, ACTION_OTHER, -1
5870 Xamoeba_7, FALSE, FALSE,
5871 EL_AMOEBA_WET, ACTION_OTHER, -1
5874 Xamoeba_8, FALSE, FALSE,
5875 EL_AMOEBA_WET, ACTION_OTHER, -1
5878 Xdoor_1, TRUE, FALSE,
5879 EL_EM_GATE_1, -1, -1
5882 Xdoor_2, TRUE, FALSE,
5883 EL_EM_GATE_2, -1, -1
5886 Xdoor_3, TRUE, FALSE,
5887 EL_EM_GATE_3, -1, -1
5890 Xdoor_4, TRUE, FALSE,
5891 EL_EM_GATE_4, -1, -1
5894 Xdoor_5, TRUE, FALSE,
5895 EL_EMC_GATE_5, -1, -1
5898 Xdoor_6, TRUE, FALSE,
5899 EL_EMC_GATE_6, -1, -1
5902 Xdoor_7, TRUE, FALSE,
5903 EL_EMC_GATE_7, -1, -1
5906 Xdoor_8, TRUE, FALSE,
5907 EL_EMC_GATE_8, -1, -1
5910 Xkey_1, TRUE, FALSE,
5914 Xkey_2, TRUE, FALSE,
5918 Xkey_3, TRUE, FALSE,
5922 Xkey_4, TRUE, FALSE,
5926 Xkey_5, TRUE, FALSE,
5927 EL_EMC_KEY_5, -1, -1
5930 Xkey_6, TRUE, FALSE,
5931 EL_EMC_KEY_6, -1, -1
5934 Xkey_7, TRUE, FALSE,
5935 EL_EMC_KEY_7, -1, -1
5938 Xkey_8, TRUE, FALSE,
5939 EL_EMC_KEY_8, -1, -1
5942 Xwind_n, TRUE, FALSE,
5943 EL_BALLOON_SWITCH_UP, -1, -1
5946 Xwind_e, TRUE, FALSE,
5947 EL_BALLOON_SWITCH_RIGHT, -1, -1
5950 Xwind_s, TRUE, FALSE,
5951 EL_BALLOON_SWITCH_DOWN, -1, -1
5954 Xwind_w, TRUE, FALSE,
5955 EL_BALLOON_SWITCH_LEFT, -1, -1
5958 Xwind_nesw, TRUE, FALSE,
5959 EL_BALLOON_SWITCH_ANY, -1, -1
5962 Xwind_stop, TRUE, FALSE,
5963 EL_BALLOON_SWITCH_NONE, -1, -1
5967 EL_EM_EXIT_CLOSED, -1, -1
5970 Xexit_1, TRUE, FALSE,
5971 EL_EM_EXIT_OPEN, -1, -1
5974 Xexit_2, FALSE, FALSE,
5975 EL_EM_EXIT_OPEN, -1, -1
5978 Xexit_3, FALSE, FALSE,
5979 EL_EM_EXIT_OPEN, -1, -1
5982 Xdynamite, TRUE, FALSE,
5983 EL_EM_DYNAMITE, -1, -1
5986 Ydynamite_eat, FALSE, FALSE,
5987 EL_EM_DYNAMITE, ACTION_COLLECTING, -1
5990 Xdynamite_1, TRUE, FALSE,
5991 EL_EM_DYNAMITE_ACTIVE, -1, -1
5994 Xdynamite_2, FALSE, FALSE,
5995 EL_EM_DYNAMITE_ACTIVE, -1, -1
5998 Xdynamite_3, FALSE, FALSE,
5999 EL_EM_DYNAMITE_ACTIVE, -1, -1
6002 Xdynamite_4, FALSE, FALSE,
6003 EL_EM_DYNAMITE_ACTIVE, -1, -1
6006 Xbumper, TRUE, FALSE,
6007 EL_EMC_SPRING_BUMPER, -1, -1
6010 XbumperB, FALSE, FALSE,
6011 EL_EMC_SPRING_BUMPER, ACTION_ACTIVE, -1
6014 Xwheel, TRUE, FALSE,
6015 EL_ROBOT_WHEEL, -1, -1
6018 XwheelB, FALSE, FALSE,
6019 EL_ROBOT_WHEEL, ACTION_ACTIVE, -1
6022 Xswitch, TRUE, FALSE,
6023 EL_EMC_MAGIC_BALL_SWITCH, -1, -1
6026 XswitchB, FALSE, FALSE,
6027 EL_EMC_MAGIC_BALL_SWITCH, ACTION_ACTIVE, -1
6031 EL_QUICKSAND_EMPTY, -1, -1
6034 Xsand_stone, TRUE, FALSE,
6035 EL_QUICKSAND_FULL, -1, -1
6038 Xsand_stonein_1, FALSE, TRUE,
6039 EL_ROCK, ACTION_FILLING, -1
6042 Xsand_stonein_2, FALSE, TRUE,
6043 EL_ROCK, ACTION_FILLING, -1
6046 Xsand_stonein_3, FALSE, TRUE,
6047 EL_ROCK, ACTION_FILLING, -1
6050 Xsand_stonein_4, FALSE, TRUE,
6051 EL_ROCK, ACTION_FILLING, -1
6055 Xsand_stonesand_1, FALSE, FALSE,
6056 EL_QUICKSAND_EMPTYING, -1, -1
6059 Xsand_stonesand_2, FALSE, FALSE,
6060 EL_QUICKSAND_EMPTYING, -1, -1
6063 Xsand_stonesand_3, FALSE, FALSE,
6064 EL_QUICKSAND_EMPTYING, -1, -1
6067 Xsand_stonesand_4, FALSE, FALSE,
6068 EL_QUICKSAND_EMPTYING, -1, -1
6071 Xsand_stonesand_quickout_1, FALSE, FALSE,
6072 EL_QUICKSAND_EMPTYING, -1, -1
6075 Xsand_stonesand_quickout_2, FALSE, FALSE,
6076 EL_QUICKSAND_EMPTYING, -1, -1
6080 Xsand_stonesand_1, FALSE, FALSE,
6081 EL_QUICKSAND_FULL, -1, -1
6084 Xsand_stonesand_2, FALSE, FALSE,
6085 EL_QUICKSAND_FULL, -1, -1
6088 Xsand_stonesand_3, FALSE, FALSE,
6089 EL_QUICKSAND_FULL, -1, -1
6092 Xsand_stonesand_4, FALSE, FALSE,
6093 EL_QUICKSAND_FULL, -1, -1
6097 Xsand_stoneout_1, FALSE, FALSE,
6098 EL_ROCK, ACTION_EMPTYING, -1
6101 Xsand_stoneout_2, FALSE, FALSE,
6102 EL_ROCK, ACTION_EMPTYING, -1
6106 Xsand_sandstone_1, FALSE, FALSE,
6107 EL_QUICKSAND_FILLING, -1, -1
6110 Xsand_sandstone_2, FALSE, FALSE,
6111 EL_QUICKSAND_FILLING, -1, -1
6114 Xsand_sandstone_3, FALSE, FALSE,
6115 EL_QUICKSAND_FILLING, -1, -1
6118 Xsand_sandstone_4, FALSE, FALSE,
6119 EL_QUICKSAND_FILLING, -1, -1
6123 Xsand_sandstone_1, FALSE, FALSE,
6124 EL_QUICKSAND_FULL, -1, -1
6127 Xsand_sandstone_2, FALSE, FALSE,
6128 EL_QUICKSAND_FULL, -1, -1
6131 Xsand_sandstone_3, FALSE, FALSE,
6132 EL_QUICKSAND_FULL, -1, -1
6135 Xsand_sandstone_4, FALSE, FALSE,
6136 EL_QUICKSAND_FULL, -1, -1
6140 Xplant, TRUE, FALSE,
6141 EL_EMC_PLANT, -1, -1
6144 Yplant, FALSE, FALSE,
6145 EL_EMC_PLANT, -1, -1
6148 Xlenses, TRUE, FALSE,
6149 EL_EMC_LENSES, -1, -1
6152 Xmagnify, TRUE, FALSE,
6153 EL_EMC_MAGNIFIER, -1, -1
6156 Xdripper, TRUE, FALSE,
6157 EL_EMC_DRIPPER, -1, -1
6160 XdripperB, FALSE, FALSE,
6161 EL_EMC_DRIPPER, ACTION_ACTIVE, -1
6164 Xfake_blank, TRUE, FALSE,
6165 EL_INVISIBLE_WALL, -1, -1
6168 Xfake_blankB, FALSE, FALSE,
6169 EL_INVISIBLE_WALL, ACTION_ACTIVE, -1
6172 Xfake_grass, TRUE, FALSE,
6173 EL_EMC_FAKE_GRASS, -1, -1
6176 Xfake_grassB, FALSE, FALSE,
6177 EL_EMC_FAKE_GRASS, ACTION_ACTIVE, -1
6180 Xfake_door_1, TRUE, FALSE,
6181 EL_EM_GATE_1_GRAY, -1, -1
6184 Xfake_door_2, TRUE, FALSE,
6185 EL_EM_GATE_2_GRAY, -1, -1
6188 Xfake_door_3, TRUE, FALSE,
6189 EL_EM_GATE_3_GRAY, -1, -1
6192 Xfake_door_4, TRUE, FALSE,
6193 EL_EM_GATE_4_GRAY, -1, -1
6196 Xfake_door_5, TRUE, FALSE,
6197 EL_EMC_GATE_5_GRAY, -1, -1
6200 Xfake_door_6, TRUE, FALSE,
6201 EL_EMC_GATE_6_GRAY, -1, -1
6204 Xfake_door_7, TRUE, FALSE,
6205 EL_EMC_GATE_7_GRAY, -1, -1
6208 Xfake_door_8, TRUE, FALSE,
6209 EL_EMC_GATE_8_GRAY, -1, -1
6212 Xfake_acid_1, TRUE, FALSE,
6213 EL_EMC_FAKE_ACID, -1, -1
6216 Xfake_acid_2, FALSE, FALSE,
6217 EL_EMC_FAKE_ACID, -1, -1
6220 Xfake_acid_3, FALSE, FALSE,
6221 EL_EMC_FAKE_ACID, -1, -1
6224 Xfake_acid_4, FALSE, FALSE,
6225 EL_EMC_FAKE_ACID, -1, -1
6228 Xfake_acid_5, FALSE, FALSE,
6229 EL_EMC_FAKE_ACID, -1, -1
6232 Xfake_acid_6, FALSE, FALSE,
6233 EL_EMC_FAKE_ACID, -1, -1
6236 Xfake_acid_7, FALSE, FALSE,
6237 EL_EMC_FAKE_ACID, -1, -1
6240 Xfake_acid_8, FALSE, FALSE,
6241 EL_EMC_FAKE_ACID, -1, -1
6244 Xsteel_1, TRUE, FALSE,
6245 EL_STEELWALL, -1, -1
6248 Xsteel_2, TRUE, FALSE,
6249 EL_EMC_STEELWALL_2, -1, -1
6252 Xsteel_3, TRUE, FALSE,
6253 EL_EMC_STEELWALL_3, -1, -1
6256 Xsteel_4, TRUE, FALSE,
6257 EL_EMC_STEELWALL_4, -1, -1
6260 Xwall_1, TRUE, FALSE,
6264 Xwall_2, TRUE, FALSE,
6265 EL_EMC_WALL_14, -1, -1
6268 Xwall_3, TRUE, FALSE,
6269 EL_EMC_WALL_15, -1, -1
6272 Xwall_4, TRUE, FALSE,
6273 EL_EMC_WALL_16, -1, -1
6276 Xround_wall_1, TRUE, FALSE,
6277 EL_WALL_SLIPPERY, -1, -1
6280 Xround_wall_2, TRUE, FALSE,
6281 EL_EMC_WALL_SLIPPERY_2, -1, -1
6284 Xround_wall_3, TRUE, FALSE,
6285 EL_EMC_WALL_SLIPPERY_3, -1, -1
6288 Xround_wall_4, TRUE, FALSE,
6289 EL_EMC_WALL_SLIPPERY_4, -1, -1
6292 Xdecor_1, TRUE, FALSE,
6293 EL_EMC_WALL_8, -1, -1
6296 Xdecor_2, TRUE, FALSE,
6297 EL_EMC_WALL_6, -1, -1
6300 Xdecor_3, TRUE, FALSE,
6301 EL_EMC_WALL_4, -1, -1
6304 Xdecor_4, TRUE, FALSE,
6305 EL_EMC_WALL_7, -1, -1
6308 Xdecor_5, TRUE, FALSE,
6309 EL_EMC_WALL_5, -1, -1
6312 Xdecor_6, TRUE, FALSE,
6313 EL_EMC_WALL_9, -1, -1
6316 Xdecor_7, TRUE, FALSE,
6317 EL_EMC_WALL_10, -1, -1
6320 Xdecor_8, TRUE, FALSE,
6321 EL_EMC_WALL_1, -1, -1
6324 Xdecor_9, TRUE, FALSE,
6325 EL_EMC_WALL_2, -1, -1
6328 Xdecor_10, TRUE, FALSE,
6329 EL_EMC_WALL_3, -1, -1
6332 Xdecor_11, TRUE, FALSE,
6333 EL_EMC_WALL_11, -1, -1
6336 Xdecor_12, TRUE, FALSE,
6337 EL_EMC_WALL_12, -1, -1
6340 Xalpha_0, TRUE, FALSE,
6341 EL_CHAR('0'), -1, -1
6344 Xalpha_1, TRUE, FALSE,
6345 EL_CHAR('1'), -1, -1
6348 Xalpha_2, TRUE, FALSE,
6349 EL_CHAR('2'), -1, -1
6352 Xalpha_3, TRUE, FALSE,
6353 EL_CHAR('3'), -1, -1
6356 Xalpha_4, TRUE, FALSE,
6357 EL_CHAR('4'), -1, -1
6360 Xalpha_5, TRUE, FALSE,
6361 EL_CHAR('5'), -1, -1
6364 Xalpha_6, TRUE, FALSE,
6365 EL_CHAR('6'), -1, -1
6368 Xalpha_7, TRUE, FALSE,
6369 EL_CHAR('7'), -1, -1
6372 Xalpha_8, TRUE, FALSE,
6373 EL_CHAR('8'), -1, -1
6376 Xalpha_9, TRUE, FALSE,
6377 EL_CHAR('9'), -1, -1
6380 Xalpha_excla, TRUE, FALSE,
6381 EL_CHAR('!'), -1, -1
6384 Xalpha_quote, TRUE, FALSE,
6385 EL_CHAR('"'), -1, -1
6388 Xalpha_comma, TRUE, FALSE,
6389 EL_CHAR(','), -1, -1
6392 Xalpha_minus, TRUE, FALSE,
6393 EL_CHAR('-'), -1, -1
6396 Xalpha_perio, TRUE, FALSE,
6397 EL_CHAR('.'), -1, -1
6400 Xalpha_colon, TRUE, FALSE,
6401 EL_CHAR(':'), -1, -1
6404 Xalpha_quest, TRUE, FALSE,
6405 EL_CHAR('?'), -1, -1
6408 Xalpha_a, TRUE, FALSE,
6409 EL_CHAR('A'), -1, -1
6412 Xalpha_b, TRUE, FALSE,
6413 EL_CHAR('B'), -1, -1
6416 Xalpha_c, TRUE, FALSE,
6417 EL_CHAR('C'), -1, -1
6420 Xalpha_d, TRUE, FALSE,
6421 EL_CHAR('D'), -1, -1
6424 Xalpha_e, TRUE, FALSE,
6425 EL_CHAR('E'), -1, -1
6428 Xalpha_f, TRUE, FALSE,
6429 EL_CHAR('F'), -1, -1
6432 Xalpha_g, TRUE, FALSE,
6433 EL_CHAR('G'), -1, -1
6436 Xalpha_h, TRUE, FALSE,
6437 EL_CHAR('H'), -1, -1
6440 Xalpha_i, TRUE, FALSE,
6441 EL_CHAR('I'), -1, -1
6444 Xalpha_j, TRUE, FALSE,
6445 EL_CHAR('J'), -1, -1
6448 Xalpha_k, TRUE, FALSE,
6449 EL_CHAR('K'), -1, -1
6452 Xalpha_l, TRUE, FALSE,
6453 EL_CHAR('L'), -1, -1
6456 Xalpha_m, TRUE, FALSE,
6457 EL_CHAR('M'), -1, -1
6460 Xalpha_n, TRUE, FALSE,
6461 EL_CHAR('N'), -1, -1
6464 Xalpha_o, TRUE, FALSE,
6465 EL_CHAR('O'), -1, -1
6468 Xalpha_p, TRUE, FALSE,
6469 EL_CHAR('P'), -1, -1
6472 Xalpha_q, TRUE, FALSE,
6473 EL_CHAR('Q'), -1, -1
6476 Xalpha_r, TRUE, FALSE,
6477 EL_CHAR('R'), -1, -1
6480 Xalpha_s, TRUE, FALSE,
6481 EL_CHAR('S'), -1, -1
6484 Xalpha_t, TRUE, FALSE,
6485 EL_CHAR('T'), -1, -1
6488 Xalpha_u, TRUE, FALSE,
6489 EL_CHAR('U'), -1, -1
6492 Xalpha_v, TRUE, FALSE,
6493 EL_CHAR('V'), -1, -1
6496 Xalpha_w, TRUE, FALSE,
6497 EL_CHAR('W'), -1, -1
6500 Xalpha_x, TRUE, FALSE,
6501 EL_CHAR('X'), -1, -1
6504 Xalpha_y, TRUE, FALSE,
6505 EL_CHAR('Y'), -1, -1
6508 Xalpha_z, TRUE, FALSE,
6509 EL_CHAR('Z'), -1, -1
6512 Xalpha_arrow_e, TRUE, FALSE,
6513 EL_CHAR('>'), -1, -1
6516 Xalpha_arrow_w, TRUE, FALSE,
6517 EL_CHAR('<'), -1, -1
6520 Xalpha_copyr, TRUE, FALSE,
6521 EL_CHAR('©'), -1, -1
6525 Xboom_bug, FALSE, FALSE,
6526 EL_BUG, ACTION_EXPLODING, -1
6529 Xboom_bomb, FALSE, FALSE,
6530 EL_BOMB, ACTION_EXPLODING, -1
6533 Xboom_android, FALSE, FALSE,
6534 EL_EMC_ANDROID, ACTION_OTHER, -1
6537 Xboom_1, FALSE, FALSE,
6538 EL_DEFAULT, ACTION_EXPLODING, -1
6541 Xboom_2, FALSE, FALSE,
6542 EL_DEFAULT, ACTION_EXPLODING, -1
6545 Znormal, FALSE, FALSE,
6549 Zdynamite, FALSE, FALSE,
6553 Zplayer, FALSE, FALSE,
6557 ZBORDER, FALSE, FALSE,
6567 static struct Mapping_EM_to_RND_player
6576 em_player_mapping_list[] =
6580 EL_PLAYER_1, ACTION_MOVING, MV_BIT_UP,
6584 EL_PLAYER_1, ACTION_MOVING, MV_BIT_RIGHT,
6588 EL_PLAYER_1, ACTION_MOVING, MV_BIT_DOWN,
6592 EL_PLAYER_1, ACTION_MOVING, MV_BIT_LEFT,
6596 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_UP,
6600 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_RIGHT,
6604 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_DOWN,
6608 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_LEFT,
6612 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_UP,
6616 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_RIGHT,
6620 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_DOWN,
6624 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_LEFT,
6628 EL_PLAYER_2, ACTION_MOVING, MV_BIT_UP,
6632 EL_PLAYER_2, ACTION_MOVING, MV_BIT_RIGHT,
6636 EL_PLAYER_2, ACTION_MOVING, MV_BIT_DOWN,
6640 EL_PLAYER_2, ACTION_MOVING, MV_BIT_LEFT,
6644 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_UP,
6648 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_RIGHT,
6652 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_DOWN,
6656 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_LEFT,
6660 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_UP,
6664 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_RIGHT,
6668 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_DOWN,
6672 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_LEFT,
6676 EL_PLAYER_1, ACTION_DEFAULT, -1,
6680 EL_PLAYER_2, ACTION_DEFAULT, -1,
6684 EL_PLAYER_3, ACTION_MOVING, MV_BIT_UP,
6688 EL_PLAYER_3, ACTION_MOVING, MV_BIT_RIGHT,
6692 EL_PLAYER_3, ACTION_MOVING, MV_BIT_DOWN,
6696 EL_PLAYER_3, ACTION_MOVING, MV_BIT_LEFT,
6700 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_UP,
6704 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_RIGHT,
6708 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_DOWN,
6712 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_LEFT,
6716 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_UP,
6720 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_RIGHT,
6724 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_DOWN,
6728 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_LEFT,
6732 EL_PLAYER_4, ACTION_MOVING, MV_BIT_UP,
6736 EL_PLAYER_4, ACTION_MOVING, MV_BIT_RIGHT,
6740 EL_PLAYER_4, ACTION_MOVING, MV_BIT_DOWN,
6744 EL_PLAYER_4, ACTION_MOVING, MV_BIT_LEFT,
6748 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_UP,
6752 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_RIGHT,
6756 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_DOWN,
6760 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_LEFT,
6764 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_UP,
6768 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_RIGHT,
6772 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_DOWN,
6776 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_LEFT,
6780 EL_PLAYER_3, ACTION_DEFAULT, -1,
6784 EL_PLAYER_4, ACTION_DEFAULT, -1,
6793 int map_element_RND_to_EM(int element_rnd)
6795 static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
6796 static boolean mapping_initialized = FALSE;
6798 if (!mapping_initialized)
6802 /* return "Xalpha_quest" for all undefined elements in mapping array */
6803 for (i = 0; i < NUM_FILE_ELEMENTS; i++)
6804 mapping_RND_to_EM[i] = Xalpha_quest;
6806 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
6807 if (em_object_mapping_list[i].is_rnd_to_em_mapping)
6808 mapping_RND_to_EM[em_object_mapping_list[i].element_rnd] =
6809 em_object_mapping_list[i].element_em;
6811 mapping_initialized = TRUE;
6814 if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
6815 return mapping_RND_to_EM[element_rnd];
6817 Error(ERR_WARN, "invalid RND level element %d", element_rnd);
6822 int map_element_EM_to_RND(int element_em)
6824 static unsigned short mapping_EM_to_RND[TILE_MAX];
6825 static boolean mapping_initialized = FALSE;
6827 if (!mapping_initialized)
6831 /* return "EL_UNKNOWN" for all undefined elements in mapping array */
6832 for (i = 0; i < TILE_MAX; i++)
6833 mapping_EM_to_RND[i] = EL_UNKNOWN;
6835 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
6836 mapping_EM_to_RND[em_object_mapping_list[i].element_em] =
6837 em_object_mapping_list[i].element_rnd;
6839 mapping_initialized = TRUE;
6842 if (element_em >= 0 && element_em < TILE_MAX)
6843 return mapping_EM_to_RND[element_em];
6845 Error(ERR_WARN, "invalid EM level element %d", element_em);
6850 void map_android_clone_elements_RND_to_EM(struct LevelInfo *level)
6852 struct LevelInfo_EM *level_em = level->native_em_level;
6853 struct LEVEL *lev = level_em->lev;
6856 for (i = 0; i < TILE_MAX; i++)
6857 lev->android_array[i] = Xblank;
6859 for (i = 0; i < level->num_android_clone_elements; i++)
6861 int element_rnd = level->android_clone_element[i];
6862 int element_em = map_element_RND_to_EM(element_rnd);
6864 for (j = 0; em_object_mapping_list[j].element_em != -1; j++)
6865 if (em_object_mapping_list[j].element_rnd == element_rnd)
6866 lev->android_array[em_object_mapping_list[j].element_em] = element_em;
6870 void map_android_clone_elements_EM_to_RND(struct LevelInfo *level)
6872 struct LevelInfo_EM *level_em = level->native_em_level;
6873 struct LEVEL *lev = level_em->lev;
6876 level->num_android_clone_elements = 0;
6878 for (i = 0; i < TILE_MAX; i++)
6880 int element_em = lev->android_array[i];
6882 boolean element_found = FALSE;
6884 if (element_em == Xblank)
6887 element_rnd = map_element_EM_to_RND(element_em);
6889 for (j = 0; j < level->num_android_clone_elements; j++)
6890 if (level->android_clone_element[j] == element_rnd)
6891 element_found = TRUE;
6895 level->android_clone_element[level->num_android_clone_elements++] =
6898 if (level->num_android_clone_elements == MAX_ANDROID_ELEMENTS)
6903 if (level->num_android_clone_elements == 0)
6905 level->num_android_clone_elements = 1;
6906 level->android_clone_element[0] = EL_EMPTY;
6910 int map_direction_RND_to_EM(int direction)
6912 return (direction == MV_UP ? 0 :
6913 direction == MV_RIGHT ? 1 :
6914 direction == MV_DOWN ? 2 :
6915 direction == MV_LEFT ? 3 :
6919 int map_direction_EM_to_RND(int direction)
6921 return (direction == 0 ? MV_UP :
6922 direction == 1 ? MV_RIGHT :
6923 direction == 2 ? MV_DOWN :
6924 direction == 3 ? MV_LEFT :
6928 int map_element_RND_to_SP(int element_rnd)
6930 int element_sp = 0x20; /* map unknown elements to yellow "hardware" */
6932 if (element_rnd >= EL_SP_START &&
6933 element_rnd <= EL_SP_END)
6934 element_sp = element_rnd - EL_SP_START;
6935 else if (element_rnd == EL_EMPTY_SPACE)
6937 else if (element_rnd == EL_INVISIBLE_WALL)
6943 int map_element_SP_to_RND(int element_sp)
6945 int element_rnd = EL_UNKNOWN;
6947 if (element_sp >= 0x00 &&
6949 element_rnd = EL_SP_START + element_sp;
6950 else if (element_sp == 0x28)
6951 element_rnd = EL_INVISIBLE_WALL;
6956 int map_action_SP_to_RND(int action_sp)
6960 case actActive: return ACTION_ACTIVE;
6961 case actImpact: return ACTION_IMPACT;
6962 case actExploding: return ACTION_EXPLODING;
6963 case actDigging: return ACTION_DIGGING;
6964 case actSnapping: return ACTION_SNAPPING;
6965 case actCollecting: return ACTION_COLLECTING;
6966 case actPassing: return ACTION_PASSING;
6967 case actPushing: return ACTION_PUSHING;
6968 case actDropping: return ACTION_DROPPING;
6970 default: return ACTION_DEFAULT;
6974 int get_next_element(int element)
6978 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
6979 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
6980 case EL_QUICKSAND_FAST_FILLING: return EL_QUICKSAND_FAST_FULL;
6981 case EL_QUICKSAND_FAST_EMPTYING: return EL_QUICKSAND_FAST_EMPTY;
6982 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
6983 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
6984 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
6985 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
6986 case EL_DC_MAGIC_WALL_FILLING: return EL_DC_MAGIC_WALL_FULL;
6987 case EL_DC_MAGIC_WALL_EMPTYING: return EL_DC_MAGIC_WALL_ACTIVE;
6988 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
6990 default: return element;
6995 int el_act_dir2img(int element, int action, int direction)
6997 element = GFX_ELEMENT(element);
6999 if (direction == MV_NONE)
7000 return element_info[element].graphic[action];
7002 direction = MV_DIR_TO_BIT(direction);
7004 return element_info[element].direction_graphic[action][direction];
7007 int el_act_dir2img(int element, int action, int direction)
7009 element = GFX_ELEMENT(element);
7010 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
7012 /* direction_graphic[][] == graphic[] for undefined direction graphics */
7013 return element_info[element].direction_graphic[action][direction];
7018 static int el_act_dir2crm(int element, int action, int direction)
7020 element = GFX_ELEMENT(element);
7022 if (direction == MV_NONE)
7023 return element_info[element].crumbled[action];
7025 direction = MV_DIR_TO_BIT(direction);
7027 return element_info[element].direction_crumbled[action][direction];
7030 static int el_act_dir2crm(int element, int action, int direction)
7032 element = GFX_ELEMENT(element);
7033 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
7035 /* direction_graphic[][] == graphic[] for undefined direction graphics */
7036 return element_info[element].direction_crumbled[action][direction];
7040 int el_act2img(int element, int action)
7042 element = GFX_ELEMENT(element);
7044 return element_info[element].graphic[action];
7047 int el_act2crm(int element, int action)
7049 element = GFX_ELEMENT(element);
7051 return element_info[element].crumbled[action];
7054 int el_dir2img(int element, int direction)
7056 element = GFX_ELEMENT(element);
7058 return el_act_dir2img(element, ACTION_DEFAULT, direction);
7061 int el2baseimg(int element)
7063 return element_info[element].graphic[ACTION_DEFAULT];
7066 int el2img(int element)
7068 element = GFX_ELEMENT(element);
7070 return element_info[element].graphic[ACTION_DEFAULT];
7073 int el2edimg(int element)
7075 element = GFX_ELEMENT(element);
7077 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
7080 int el2preimg(int element)
7082 element = GFX_ELEMENT(element);
7084 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
7087 int el2panelimg(int element)
7089 element = GFX_ELEMENT(element);
7091 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PANEL];
7094 int font2baseimg(int font_nr)
7096 return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
7099 int getBeltNrFromBeltElement(int element)
7101 return (element < EL_CONVEYOR_BELT_2_LEFT ? 0 :
7102 element < EL_CONVEYOR_BELT_3_LEFT ? 1 :
7103 element < EL_CONVEYOR_BELT_4_LEFT ? 2 : 3);
7106 int getBeltNrFromBeltActiveElement(int element)
7108 return (element < EL_CONVEYOR_BELT_2_LEFT_ACTIVE ? 0 :
7109 element < EL_CONVEYOR_BELT_3_LEFT_ACTIVE ? 1 :
7110 element < EL_CONVEYOR_BELT_4_LEFT_ACTIVE ? 2 : 3);
7113 int getBeltNrFromBeltSwitchElement(int element)
7115 return (element < EL_CONVEYOR_BELT_2_SWITCH_LEFT ? 0 :
7116 element < EL_CONVEYOR_BELT_3_SWITCH_LEFT ? 1 :
7117 element < EL_CONVEYOR_BELT_4_SWITCH_LEFT ? 2 : 3);
7120 int getBeltDirNrFromBeltElement(int element)
7122 static int belt_base_element[4] =
7124 EL_CONVEYOR_BELT_1_LEFT,
7125 EL_CONVEYOR_BELT_2_LEFT,
7126 EL_CONVEYOR_BELT_3_LEFT,
7127 EL_CONVEYOR_BELT_4_LEFT
7130 int belt_nr = getBeltNrFromBeltElement(element);
7131 int belt_dir_nr = element - belt_base_element[belt_nr];
7133 return (belt_dir_nr % 3);
7136 int getBeltDirNrFromBeltSwitchElement(int element)
7138 static int belt_base_element[4] =
7140 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
7141 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
7142 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
7143 EL_CONVEYOR_BELT_4_SWITCH_LEFT
7146 int belt_nr = getBeltNrFromBeltSwitchElement(element);
7147 int belt_dir_nr = element - belt_base_element[belt_nr];
7149 return (belt_dir_nr % 3);
7152 int getBeltDirFromBeltElement(int element)
7154 static int belt_move_dir[3] =
7161 int belt_dir_nr = getBeltDirNrFromBeltElement(element);
7163 return belt_move_dir[belt_dir_nr];
7166 int getBeltDirFromBeltSwitchElement(int element)
7168 static int belt_move_dir[3] =
7175 int belt_dir_nr = getBeltDirNrFromBeltSwitchElement(element);
7177 return belt_move_dir[belt_dir_nr];
7180 int getBeltElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
7182 static int belt_base_element[4] =
7184 EL_CONVEYOR_BELT_1_LEFT,
7185 EL_CONVEYOR_BELT_2_LEFT,
7186 EL_CONVEYOR_BELT_3_LEFT,
7187 EL_CONVEYOR_BELT_4_LEFT
7190 return belt_base_element[belt_nr] + belt_dir_nr;
7193 int getBeltElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
7195 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
7197 return getBeltElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
7200 int getBeltSwitchElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
7202 static int belt_base_element[4] =
7204 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
7205 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
7206 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
7207 EL_CONVEYOR_BELT_4_SWITCH_LEFT
7210 return belt_base_element[belt_nr] + belt_dir_nr;
7213 int getBeltSwitchElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
7215 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
7217 return getBeltSwitchElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
7220 int getNumActivePlayers_EM()
7222 int num_players = 0;
7228 for (i = 0; i < MAX_PLAYERS; i++)
7229 if (tape.player_participates[i])
7235 int getGameFrameDelay_EM(int native_em_game_frame_delay)
7237 int game_frame_delay_value;
7239 game_frame_delay_value =
7240 (tape.playing && tape.fast_forward ? FfwdFrameDelay :
7241 GameFrameDelay == GAME_FRAME_DELAY ? native_em_game_frame_delay :
7244 if (tape.playing && tape.warp_forward && !tape.pausing)
7245 game_frame_delay_value = 0;
7247 return game_frame_delay_value;
7250 unsigned int InitRND(int seed)
7252 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
7253 return InitEngineRandom_EM(seed);
7254 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
7255 return InitEngineRandom_SP(seed);
7257 return InitEngineRandom_RND(seed);
7261 static struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
7262 static struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
7265 inline static int get_effective_element_EM(int tile, int frame_em)
7267 int element = object_mapping[tile].element_rnd;
7268 int action = object_mapping[tile].action;
7269 boolean is_backside = object_mapping[tile].is_backside;
7270 boolean action_removing = (action == ACTION_DIGGING ||
7271 action == ACTION_SNAPPING ||
7272 action == ACTION_COLLECTING);
7278 case Yacid_splash_eB:
7279 case Yacid_splash_wB:
7280 return (frame_em > 5 ? EL_EMPTY : element);
7284 case Ydiamond_stone:
7285 // if (!game.use_native_emc_graphics_engine)
7293 else /* frame_em == 7 */
7297 case Yacid_splash_eB:
7298 case Yacid_splash_wB:
7301 case Yemerald_stone:
7304 case Ydiamond_stone:
7308 case Xdrip_stretchB:
7327 case Xsand_stonein_1:
7328 case Xsand_stonein_2:
7329 case Xsand_stonein_3:
7330 case Xsand_stonein_4:
7334 return (is_backside || action_removing ? EL_EMPTY : element);
7339 inline static boolean check_linear_animation_EM(int tile)
7343 case Xsand_stonesand_1:
7344 case Xsand_stonesand_quickout_1:
7345 case Xsand_sandstone_1:
7346 case Xsand_stonein_1:
7347 case Xsand_stoneout_1:
7367 case Yacid_splash_eB:
7368 case Yacid_splash_wB:
7369 case Yemerald_stone:
7377 inline static void set_crumbled_graphics_EM(struct GraphicInfo_EM *g_em,
7378 boolean has_crumbled_graphics,
7379 int crumbled, int sync_frame)
7381 /* if element can be crumbled, but certain action graphics are just empty
7382 space (like instantly snapping sand to empty space in 1 frame), do not
7383 treat these empty space graphics as crumbled graphics in EMC engine */
7384 if (crumbled == IMG_EMPTY_SPACE)
7385 has_crumbled_graphics = FALSE;
7387 if (has_crumbled_graphics)
7389 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
7390 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
7391 g_crumbled->anim_delay,
7392 g_crumbled->anim_mode,
7393 g_crumbled->anim_start_frame,
7396 getGraphicSource(crumbled, frame_crumbled, &g_em->crumbled_bitmap,
7397 &g_em->crumbled_src_x, &g_em->crumbled_src_y);
7399 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
7401 g_em->has_crumbled_graphics = TRUE;
7405 g_em->crumbled_bitmap = NULL;
7406 g_em->crumbled_src_x = 0;
7407 g_em->crumbled_src_y = 0;
7408 g_em->crumbled_border_size = 0;
7410 g_em->has_crumbled_graphics = FALSE;
7414 void ResetGfxAnimation_EM(int x, int y, int tile)
7419 void SetGfxAnimation_EM(struct GraphicInfo_EM *g_em,
7420 int tile, int frame_em, int x, int y)
7422 int action = object_mapping[tile].action;
7424 int direction = object_mapping[tile].direction;
7425 int effective_element = get_effective_element_EM(tile, frame_em);
7426 int graphic = (direction == MV_NONE ?
7427 el_act2img(effective_element, action) :
7428 el_act_dir2img(effective_element, action, direction));
7429 struct GraphicInfo *g = &graphic_info[graphic];
7432 boolean action_removing = (action == ACTION_DIGGING ||
7433 action == ACTION_SNAPPING ||
7434 action == ACTION_COLLECTING);
7435 boolean action_moving = (action == ACTION_FALLING ||
7436 action == ACTION_MOVING ||
7437 action == ACTION_PUSHING ||
7438 action == ACTION_EATING ||
7439 action == ACTION_FILLING ||
7440 action == ACTION_EMPTYING);
7441 boolean action_falling = (action == ACTION_FALLING ||
7442 action == ACTION_FILLING ||
7443 action == ACTION_EMPTYING);
7445 /* special case: graphic uses "2nd movement tile" and has defined
7446 7 frames for movement animation (or less) => use default graphic
7447 for last (8th) frame which ends the movement animation */
7448 if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
7450 action = ACTION_DEFAULT; /* (keep action_* unchanged for now) */
7451 graphic = (direction == MV_NONE ?
7452 el_act2img(effective_element, action) :
7453 el_act_dir2img(effective_element, action, direction));
7455 g = &graphic_info[graphic];
7459 if (tile == Xsand_stonesand_1 ||
7460 tile == Xsand_stonesand_2 ||
7461 tile == Xsand_stonesand_3 ||
7462 tile == Xsand_stonesand_4)
7463 printf("::: 1: quicksand frame %d [%d]\n", GfxFrame[x][y], tile);
7467 if ((action_removing || check_linear_animation_EM(tile)) && frame_em == 0)
7471 // printf("::: resetting... [%d]\n", tile);
7474 if (action_removing || check_linear_animation_EM(tile))
7476 GfxFrame[x][y] = frame_em;
7478 // printf("::: resetting... [%d]\n", tile);
7481 else if (action_moving)
7483 boolean is_backside = object_mapping[tile].is_backside;
7487 int direction = object_mapping[tile].direction;
7488 int move_dir = (action_falling ? MV_DOWN : direction);
7493 /* !!! TEST !!! NEW !!! DOES NOT WORK RIGHT YET !!! */
7494 if (g->double_movement && frame_em == 0)
7498 // printf("::: resetting... [%d]\n", tile);
7502 if (move_dir == MV_LEFT)
7503 GfxFrame[x - 1][y] = GfxFrame[x][y];
7504 else if (move_dir == MV_RIGHT)
7505 GfxFrame[x + 1][y] = GfxFrame[x][y];
7506 else if (move_dir == MV_UP)
7507 GfxFrame[x][y - 1] = GfxFrame[x][y];
7508 else if (move_dir == MV_DOWN)
7509 GfxFrame[x][y + 1] = GfxFrame[x][y];
7516 /* special case: animation for Xsand_stonesand_quickout_1/2 twice as fast */
7517 if (tile == Xsand_stonesand_quickout_1 ||
7518 tile == Xsand_stonesand_quickout_2)
7523 if (tile == Xsand_stonesand_1 ||
7524 tile == Xsand_stonesand_2 ||
7525 tile == Xsand_stonesand_3 ||
7526 tile == Xsand_stonesand_4)
7527 printf("::: 2: quicksand frame %d [%d]\n", GfxFrame[x][y], tile);
7531 if (graphic_info[graphic].anim_global_sync)
7532 sync_frame = FrameCounter;
7533 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
7534 sync_frame = GfxFrame[x][y];
7536 sync_frame = 0; /* playfield border (pseudo steel) */
7538 SetRandomAnimationValue(x, y);
7540 int frame = getAnimationFrame(g->anim_frames,
7543 g->anim_start_frame,
7546 g_em->unique_identifier =
7547 (graphic << 16) | ((frame % 8) << 12) | (g_em->width << 6) | g_em->height;
7551 void getGraphicSourceObjectExt_EM(struct GraphicInfo_EM *g_em,
7552 int tile, int frame_em, int x, int y)
7554 int action = object_mapping[tile].action;
7555 int direction = object_mapping[tile].direction;
7556 boolean is_backside = object_mapping[tile].is_backside;
7557 int effective_element = get_effective_element_EM(tile, frame_em);
7559 int effective_action = action;
7561 int effective_action = (frame_em < 7 ? action : ACTION_DEFAULT);
7563 int graphic = (direction == MV_NONE ?
7564 el_act2img(effective_element, effective_action) :
7565 el_act_dir2img(effective_element, effective_action,
7567 int crumbled = (direction == MV_NONE ?
7568 el_act2crm(effective_element, effective_action) :
7569 el_act_dir2crm(effective_element, effective_action,
7571 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
7572 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
7573 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
7574 struct GraphicInfo *g = &graphic_info[graphic];
7576 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
7580 /* special case: graphic uses "2nd movement tile" and has defined
7581 7 frames for movement animation (or less) => use default graphic
7582 for last (8th) frame which ends the movement animation */
7583 if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
7585 effective_action = ACTION_DEFAULT;
7586 graphic = (direction == MV_NONE ?
7587 el_act2img(effective_element, effective_action) :
7588 el_act_dir2img(effective_element, effective_action,
7590 crumbled = (direction == MV_NONE ?
7591 el_act2crm(effective_element, effective_action) :
7592 el_act_dir2crm(effective_element, effective_action,
7595 g = &graphic_info[graphic];
7605 if (frame_em == 0) /* reset animation frame for certain elements */
7607 if (check_linear_animation_EM(tile))
7612 if (graphic_info[graphic].anim_global_sync)
7613 sync_frame = FrameCounter;
7614 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
7615 sync_frame = GfxFrame[x][y];
7617 sync_frame = 0; /* playfield border (pseudo steel) */
7619 SetRandomAnimationValue(x, y);
7624 int xxx_sync_frame = (i == Xdrip_stretch ? 7 :
7625 i == Xdrip_stretchB ? 7 :
7626 i == Ydrip_s2 ? j + 8 :
7627 i == Ydrip_s2B ? j + 8 :
7636 i == Xfake_acid_1 ? 0 :
7637 i == Xfake_acid_2 ? 10 :
7638 i == Xfake_acid_3 ? 20 :
7639 i == Xfake_acid_4 ? 30 :
7640 i == Xfake_acid_5 ? 40 :
7641 i == Xfake_acid_6 ? 50 :
7642 i == Xfake_acid_7 ? 60 :
7643 i == Xfake_acid_8 ? 70 :
7645 i == Xball_2B ? j + 8 :
7646 i == Yball_eat ? j + 1 :
7647 i == Ykey_1_eat ? j + 1 :
7648 i == Ykey_2_eat ? j + 1 :
7649 i == Ykey_3_eat ? j + 1 :
7650 i == Ykey_4_eat ? j + 1 :
7651 i == Ykey_5_eat ? j + 1 :
7652 i == Ykey_6_eat ? j + 1 :
7653 i == Ykey_7_eat ? j + 1 :
7654 i == Ykey_8_eat ? j + 1 :
7655 i == Ylenses_eat ? j + 1 :
7656 i == Ymagnify_eat ? j + 1 :
7657 i == Ygrass_eat ? j + 1 :
7658 i == Ydirt_eat ? j + 1 :
7659 i == Xamoeba_1 ? 0 :
7660 i == Xamoeba_2 ? 1 :
7661 i == Xamoeba_3 ? 2 :
7662 i == Xamoeba_4 ? 3 :
7663 i == Xamoeba_5 ? 0 :
7664 i == Xamoeba_6 ? 1 :
7665 i == Xamoeba_7 ? 2 :
7666 i == Xamoeba_8 ? 3 :
7667 i == Xexit_2 ? j + 8 :
7668 i == Xexit_3 ? j + 16 :
7669 i == Xdynamite_1 ? 0 :
7670 i == Xdynamite_2 ? 8 :
7671 i == Xdynamite_3 ? 16 :
7672 i == Xdynamite_4 ? 24 :
7673 i == Xsand_stonein_1 ? j + 1 :
7674 i == Xsand_stonein_2 ? j + 9 :
7675 i == Xsand_stonein_3 ? j + 17 :
7676 i == Xsand_stonein_4 ? j + 25 :
7677 i == Xsand_stoneout_1 && j == 0 ? 0 :
7678 i == Xsand_stoneout_1 && j == 1 ? 0 :
7679 i == Xsand_stoneout_1 && j == 2 ? 1 :
7680 i == Xsand_stoneout_1 && j == 3 ? 2 :
7681 i == Xsand_stoneout_1 && j == 4 ? 2 :
7682 i == Xsand_stoneout_1 && j == 5 ? 3 :
7683 i == Xsand_stoneout_1 && j == 6 ? 4 :
7684 i == Xsand_stoneout_1 && j == 7 ? 4 :
7685 i == Xsand_stoneout_2 && j == 0 ? 5 :
7686 i == Xsand_stoneout_2 && j == 1 ? 6 :
7687 i == Xsand_stoneout_2 && j == 2 ? 7 :
7688 i == Xsand_stoneout_2 && j == 3 ? 8 :
7689 i == Xsand_stoneout_2 && j == 4 ? 9 :
7690 i == Xsand_stoneout_2 && j == 5 ? 11 :
7691 i == Xsand_stoneout_2 && j == 6 ? 13 :
7692 i == Xsand_stoneout_2 && j == 7 ? 15 :
7693 i == Xboom_bug && j == 1 ? 2 :
7694 i == Xboom_bug && j == 2 ? 2 :
7695 i == Xboom_bug && j == 3 ? 4 :
7696 i == Xboom_bug && j == 4 ? 4 :
7697 i == Xboom_bug && j == 5 ? 2 :
7698 i == Xboom_bug && j == 6 ? 2 :
7699 i == Xboom_bug && j == 7 ? 0 :
7700 i == Xboom_bomb && j == 1 ? 2 :
7701 i == Xboom_bomb && j == 2 ? 2 :
7702 i == Xboom_bomb && j == 3 ? 4 :
7703 i == Xboom_bomb && j == 4 ? 4 :
7704 i == Xboom_bomb && j == 5 ? 2 :
7705 i == Xboom_bomb && j == 6 ? 2 :
7706 i == Xboom_bomb && j == 7 ? 0 :
7707 i == Xboom_android && j == 7 ? 6 :
7708 i == Xboom_1 && j == 1 ? 2 :
7709 i == Xboom_1 && j == 2 ? 2 :
7710 i == Xboom_1 && j == 3 ? 4 :
7711 i == Xboom_1 && j == 4 ? 4 :
7712 i == Xboom_1 && j == 5 ? 6 :
7713 i == Xboom_1 && j == 6 ? 6 :
7714 i == Xboom_1 && j == 7 ? 8 :
7715 i == Xboom_2 && j == 0 ? 8 :
7716 i == Xboom_2 && j == 1 ? 8 :
7717 i == Xboom_2 && j == 2 ? 10 :
7718 i == Xboom_2 && j == 3 ? 10 :
7719 i == Xboom_2 && j == 4 ? 10 :
7720 i == Xboom_2 && j == 5 ? 12 :
7721 i == Xboom_2 && j == 6 ? 12 :
7722 i == Xboom_2 && j == 7 ? 12 :
7724 special_animation && j == 4 ? 3 :
7725 effective_action != action ? 0 :
7731 int xxx_effective_action;
7732 int xxx_has_action_graphics;
7735 int element = object_mapping[i].element_rnd;
7736 int action = object_mapping[i].action;
7737 int direction = object_mapping[i].direction;
7738 boolean is_backside = object_mapping[i].is_backside;
7740 boolean action_removing = (action == ACTION_DIGGING ||
7741 action == ACTION_SNAPPING ||
7742 action == ACTION_COLLECTING);
7744 boolean action_exploding = ((action == ACTION_EXPLODING ||
7745 action == ACTION_SMASHED_BY_ROCK ||
7746 action == ACTION_SMASHED_BY_SPRING) &&
7747 element != EL_DIAMOND);
7748 boolean action_active = (action == ACTION_ACTIVE);
7749 boolean action_other = (action == ACTION_OTHER);
7753 int effective_element = get_effective_element_EM(i, j);
7755 int effective_element = (j > 5 && i == Yacid_splash_eB ? EL_EMPTY :
7756 j > 5 && i == Yacid_splash_wB ? EL_EMPTY :
7758 i == Xdrip_stretch ? element :
7759 i == Xdrip_stretchB ? element :
7760 i == Ydrip_s1 ? element :
7761 i == Ydrip_s1B ? element :
7762 i == Xball_1B ? element :
7763 i == Xball_2 ? element :
7764 i == Xball_2B ? element :
7765 i == Yball_eat ? element :
7766 i == Ykey_1_eat ? element :
7767 i == Ykey_2_eat ? element :
7768 i == Ykey_3_eat ? element :
7769 i == Ykey_4_eat ? element :
7770 i == Ykey_5_eat ? element :
7771 i == Ykey_6_eat ? element :
7772 i == Ykey_7_eat ? element :
7773 i == Ykey_8_eat ? element :
7774 i == Ylenses_eat ? element :
7775 i == Ymagnify_eat ? element :
7776 i == Ygrass_eat ? element :
7777 i == Ydirt_eat ? element :
7778 i == Yemerald_stone ? EL_EMERALD :
7779 i == Ydiamond_stone ? EL_ROCK :
7780 i == Xsand_stonein_1 ? element :
7781 i == Xsand_stonein_2 ? element :
7782 i == Xsand_stonein_3 ? element :
7783 i == Xsand_stonein_4 ? element :
7784 is_backside ? EL_EMPTY :
7785 action_removing ? EL_EMPTY :
7788 int effective_action = (j < 7 ? action :
7789 i == Xdrip_stretch ? action :
7790 i == Xdrip_stretchB ? action :
7791 i == Ydrip_s1 ? action :
7792 i == Ydrip_s1B ? action :
7793 i == Xball_1B ? action :
7794 i == Xball_2 ? action :
7795 i == Xball_2B ? action :
7796 i == Yball_eat ? action :
7797 i == Ykey_1_eat ? action :
7798 i == Ykey_2_eat ? action :
7799 i == Ykey_3_eat ? action :
7800 i == Ykey_4_eat ? action :
7801 i == Ykey_5_eat ? action :
7802 i == Ykey_6_eat ? action :
7803 i == Ykey_7_eat ? action :
7804 i == Ykey_8_eat ? action :
7805 i == Ylenses_eat ? action :
7806 i == Ymagnify_eat ? action :
7807 i == Ygrass_eat ? action :
7808 i == Ydirt_eat ? action :
7809 i == Xsand_stonein_1 ? action :
7810 i == Xsand_stonein_2 ? action :
7811 i == Xsand_stonein_3 ? action :
7812 i == Xsand_stonein_4 ? action :
7813 i == Xsand_stoneout_1 ? action :
7814 i == Xsand_stoneout_2 ? action :
7815 i == Xboom_android ? ACTION_EXPLODING :
7816 action_exploding ? ACTION_EXPLODING :
7817 action_active ? action :
7818 action_other ? action :
7820 int graphic = (el_act_dir2img(effective_element, effective_action,
7822 int crumbled = (el_act_dir2crm(effective_element, effective_action,
7824 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
7825 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
7826 boolean has_action_graphics = (graphic != base_graphic);
7827 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
7828 struct GraphicInfo *g = &graphic_info[graphic];
7830 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
7832 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
7835 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
7836 boolean special_animation = (action != ACTION_DEFAULT &&
7837 g->anim_frames == 3 &&
7838 g->anim_delay == 2 &&
7839 g->anim_mode & ANIM_LINEAR);
7840 xxx_sync_frame = (i == Xdrip_stretch ? 7 :
7841 i == Xdrip_stretchB ? 7 :
7842 i == Ydrip_s2 ? j + 8 :
7843 i == Ydrip_s2B ? j + 8 :
7852 i == Xfake_acid_1 ? 0 :
7853 i == Xfake_acid_2 ? 10 :
7854 i == Xfake_acid_3 ? 20 :
7855 i == Xfake_acid_4 ? 30 :
7856 i == Xfake_acid_5 ? 40 :
7857 i == Xfake_acid_6 ? 50 :
7858 i == Xfake_acid_7 ? 60 :
7859 i == Xfake_acid_8 ? 70 :
7861 i == Xball_2B ? j + 8 :
7862 i == Yball_eat ? j + 1 :
7863 i == Ykey_1_eat ? j + 1 :
7864 i == Ykey_2_eat ? j + 1 :
7865 i == Ykey_3_eat ? j + 1 :
7866 i == Ykey_4_eat ? j + 1 :
7867 i == Ykey_5_eat ? j + 1 :
7868 i == Ykey_6_eat ? j + 1 :
7869 i == Ykey_7_eat ? j + 1 :
7870 i == Ykey_8_eat ? j + 1 :
7871 i == Ylenses_eat ? j + 1 :
7872 i == Ymagnify_eat ? j + 1 :
7873 i == Ygrass_eat ? j + 1 :
7874 i == Ydirt_eat ? j + 1 :
7875 i == Xamoeba_1 ? 0 :
7876 i == Xamoeba_2 ? 1 :
7877 i == Xamoeba_3 ? 2 :
7878 i == Xamoeba_4 ? 3 :
7879 i == Xamoeba_5 ? 0 :
7880 i == Xamoeba_6 ? 1 :
7881 i == Xamoeba_7 ? 2 :
7882 i == Xamoeba_8 ? 3 :
7883 i == Xexit_2 ? j + 8 :
7884 i == Xexit_3 ? j + 16 :
7885 i == Xdynamite_1 ? 0 :
7886 i == Xdynamite_2 ? 8 :
7887 i == Xdynamite_3 ? 16 :
7888 i == Xdynamite_4 ? 24 :
7889 i == Xsand_stonein_1 ? j + 1 :
7890 i == Xsand_stonein_2 ? j + 9 :
7891 i == Xsand_stonein_3 ? j + 17 :
7892 i == Xsand_stonein_4 ? j + 25 :
7893 i == Xsand_stoneout_1 && j == 0 ? 0 :
7894 i == Xsand_stoneout_1 && j == 1 ? 0 :
7895 i == Xsand_stoneout_1 && j == 2 ? 1 :
7896 i == Xsand_stoneout_1 && j == 3 ? 2 :
7897 i == Xsand_stoneout_1 && j == 4 ? 2 :
7898 i == Xsand_stoneout_1 && j == 5 ? 3 :
7899 i == Xsand_stoneout_1 && j == 6 ? 4 :
7900 i == Xsand_stoneout_1 && j == 7 ? 4 :
7901 i == Xsand_stoneout_2 && j == 0 ? 5 :
7902 i == Xsand_stoneout_2 && j == 1 ? 6 :
7903 i == Xsand_stoneout_2 && j == 2 ? 7 :
7904 i == Xsand_stoneout_2 && j == 3 ? 8 :
7905 i == Xsand_stoneout_2 && j == 4 ? 9 :
7906 i == Xsand_stoneout_2 && j == 5 ? 11 :
7907 i == Xsand_stoneout_2 && j == 6 ? 13 :
7908 i == Xsand_stoneout_2 && j == 7 ? 15 :
7909 i == Xboom_bug && j == 1 ? 2 :
7910 i == Xboom_bug && j == 2 ? 2 :
7911 i == Xboom_bug && j == 3 ? 4 :
7912 i == Xboom_bug && j == 4 ? 4 :
7913 i == Xboom_bug && j == 5 ? 2 :
7914 i == Xboom_bug && j == 6 ? 2 :
7915 i == Xboom_bug && j == 7 ? 0 :
7916 i == Xboom_bomb && j == 1 ? 2 :
7917 i == Xboom_bomb && j == 2 ? 2 :
7918 i == Xboom_bomb && j == 3 ? 4 :
7919 i == Xboom_bomb && j == 4 ? 4 :
7920 i == Xboom_bomb && j == 5 ? 2 :
7921 i == Xboom_bomb && j == 6 ? 2 :
7922 i == Xboom_bomb && j == 7 ? 0 :
7923 i == Xboom_android && j == 7 ? 6 :
7924 i == Xboom_1 && j == 1 ? 2 :
7925 i == Xboom_1 && j == 2 ? 2 :
7926 i == Xboom_1 && j == 3 ? 4 :
7927 i == Xboom_1 && j == 4 ? 4 :
7928 i == Xboom_1 && j == 5 ? 6 :
7929 i == Xboom_1 && j == 6 ? 6 :
7930 i == Xboom_1 && j == 7 ? 8 :
7931 i == Xboom_2 && j == 0 ? 8 :
7932 i == Xboom_2 && j == 1 ? 8 :
7933 i == Xboom_2 && j == 2 ? 10 :
7934 i == Xboom_2 && j == 3 ? 10 :
7935 i == Xboom_2 && j == 4 ? 10 :
7936 i == Xboom_2 && j == 5 ? 12 :
7937 i == Xboom_2 && j == 6 ? 12 :
7938 i == Xboom_2 && j == 7 ? 12 :
7939 special_animation && j == 4 ? 3 :
7940 effective_action != action ? 0 :
7943 xxx_effective_action = effective_action;
7944 xxx_has_action_graphics = has_action_graphics;
7949 int frame = getAnimationFrame(g->anim_frames,
7952 g->anim_start_frame,
7966 int old_src_x = g_em->src_x;
7967 int old_src_y = g_em->src_y;
7971 getGraphicSourceExt(graphic, frame, &g_em->bitmap, &g_em->src_x, &g_em->src_y,
7972 g->double_movement && is_backside);
7974 getGraphicSourceExt(graphic, frame, &g_em->bitmap,
7975 &g_em->src_x, &g_em->src_y, FALSE);
7980 if (tile == Ydiamond_stone)
7981 printf("::: stone smashing diamond... %d: %d, %d, %d, %d, %d -> %d [%d, %d, %d, %d, %d, %d] [%d]\n",
7986 g->anim_start_frame,
7989 g_em->src_x, g_em->src_y,
7990 g_em->src_offset_x, g_em->src_offset_y,
7991 g_em->dst_offset_x, g_em->dst_offset_y,
8003 if (graphic == IMG_BUG_MOVING_RIGHT)
8004 printf("::: %d, %d, %d: %d, %d [%d, %d -> %d, %d]\n", graphic, x, y,
8005 g->double_movement, is_backside,
8006 old_src_x, old_src_y, g_em->src_x, g_em->src_y);
8014 g_em->src_offset_x = 0;
8015 g_em->src_offset_y = 0;
8016 g_em->dst_offset_x = 0;
8017 g_em->dst_offset_y = 0;
8018 g_em->width = TILEX;
8019 g_em->height = TILEY;
8021 g_em->preserve_background = FALSE;
8024 /* (updating the "crumbled" graphic definitions is probably not really needed,
8025 as animations for crumbled graphics can't be longer than one EMC cycle) */
8027 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
8032 g_em->crumbled_bitmap = NULL;
8033 g_em->crumbled_src_x = 0;
8034 g_em->crumbled_src_y = 0;
8036 g_em->has_crumbled_graphics = FALSE;
8038 if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
8040 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
8041 g_crumbled->anim_delay,
8042 g_crumbled->anim_mode,
8043 g_crumbled->anim_start_frame,
8046 getGraphicSource(crumbled, frame_crumbled, &g_em->crumbled_bitmap,
8047 &g_em->crumbled_src_x, &g_em->crumbled_src_y);
8049 g_em->has_crumbled_graphics = TRUE;
8055 int effective_action = xxx_effective_action;
8056 int has_action_graphics = xxx_has_action_graphics;
8058 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
8059 effective_action == ACTION_MOVING ||
8060 effective_action == ACTION_PUSHING ||
8061 effective_action == ACTION_EATING)) ||
8062 (!has_action_graphics && (effective_action == ACTION_FILLING ||
8063 effective_action == ACTION_EMPTYING)))
8066 (effective_action == ACTION_FALLING ||
8067 effective_action == ACTION_FILLING ||
8068 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
8069 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
8070 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
8071 int num_steps = (i == Ydrip_s1 ? 16 :
8072 i == Ydrip_s1B ? 16 :
8073 i == Ydrip_s2 ? 16 :
8074 i == Ydrip_s2B ? 16 :
8075 i == Xsand_stonein_1 ? 32 :
8076 i == Xsand_stonein_2 ? 32 :
8077 i == Xsand_stonein_3 ? 32 :
8078 i == Xsand_stonein_4 ? 32 :
8079 i == Xsand_stoneout_1 ? 16 :
8080 i == Xsand_stoneout_2 ? 16 : 8);
8081 int cx = ABS(dx) * (TILEX / num_steps);
8082 int cy = ABS(dy) * (TILEY / num_steps);
8083 int step_frame = (i == Ydrip_s2 ? j + 8 :
8084 i == Ydrip_s2B ? j + 8 :
8085 i == Xsand_stonein_2 ? j + 8 :
8086 i == Xsand_stonein_3 ? j + 16 :
8087 i == Xsand_stonein_4 ? j + 24 :
8088 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
8089 int step = (is_backside ? step_frame : num_steps - step_frame);
8091 if (is_backside) /* tile where movement starts */
8093 if (dx < 0 || dy < 0)
8095 g_em->src_offset_x = cx * step;
8096 g_em->src_offset_y = cy * step;
8100 g_em->dst_offset_x = cx * step;
8101 g_em->dst_offset_y = cy * step;
8104 else /* tile where movement ends */
8106 if (dx < 0 || dy < 0)
8108 g_em->dst_offset_x = cx * step;
8109 g_em->dst_offset_y = cy * step;
8113 g_em->src_offset_x = cx * step;
8114 g_em->src_offset_y = cy * step;
8118 g_em->width = TILEX - cx * step;
8119 g_em->height = TILEY - cy * step;
8122 /* create unique graphic identifier to decide if tile must be redrawn */
8123 /* bit 31 - 16 (16 bit): EM style graphic
8124 bit 15 - 12 ( 4 bit): EM style frame
8125 bit 11 - 6 ( 6 bit): graphic width
8126 bit 5 - 0 ( 6 bit): graphic height */
8127 g_em->unique_identifier =
8128 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
8134 void getGraphicSourcePlayerExt_EM(struct GraphicInfo_EM *g_em,
8135 int player_nr, int anim, int frame_em)
8137 int element = player_mapping[player_nr][anim].element_rnd;
8138 int action = player_mapping[player_nr][anim].action;
8139 int direction = player_mapping[player_nr][anim].direction;
8140 int graphic = (direction == MV_NONE ?
8141 el_act2img(element, action) :
8142 el_act_dir2img(element, action, direction));
8143 struct GraphicInfo *g = &graphic_info[graphic];
8146 InitPlayerGfxAnimation(&stored_player[player_nr], action, direction);
8148 stored_player[player_nr].StepFrame = frame_em;
8150 sync_frame = stored_player[player_nr].Frame;
8152 int frame = getAnimationFrame(g->anim_frames,
8155 g->anim_start_frame,
8158 getGraphicSourceExt(graphic, frame, &g_em->bitmap,
8159 &g_em->src_x, &g_em->src_y, FALSE);
8162 printf("::: %d: %d, %d [%d]\n",
8164 stored_player[player_nr].Frame,
8165 stored_player[player_nr].StepFrame,
8170 void InitGraphicInfo_EM(void)
8173 struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
8174 struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
8179 int num_em_gfx_errors = 0;
8181 if (graphic_info_em_object[0][0].bitmap == NULL)
8183 /* EM graphics not yet initialized in em_open_all() */
8188 printf("::: [4 errors can be ignored (1 x 'bomb', 3 x 'em_dynamite']\n");
8191 /* always start with reliable default values */
8192 for (i = 0; i < TILE_MAX; i++)
8194 object_mapping[i].element_rnd = EL_UNKNOWN;
8195 object_mapping[i].is_backside = FALSE;
8196 object_mapping[i].action = ACTION_DEFAULT;
8197 object_mapping[i].direction = MV_NONE;
8200 /* always start with reliable default values */
8201 for (p = 0; p < MAX_PLAYERS; p++)
8203 for (i = 0; i < SPR_MAX; i++)
8205 player_mapping[p][i].element_rnd = EL_UNKNOWN;
8206 player_mapping[p][i].action = ACTION_DEFAULT;
8207 player_mapping[p][i].direction = MV_NONE;
8211 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
8213 int e = em_object_mapping_list[i].element_em;
8215 object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd;
8216 object_mapping[e].is_backside = em_object_mapping_list[i].is_backside;
8218 if (em_object_mapping_list[i].action != -1)
8219 object_mapping[e].action = em_object_mapping_list[i].action;
8221 if (em_object_mapping_list[i].direction != -1)
8222 object_mapping[e].direction =
8223 MV_DIR_FROM_BIT(em_object_mapping_list[i].direction);
8226 for (i = 0; em_player_mapping_list[i].action_em != -1; i++)
8228 int a = em_player_mapping_list[i].action_em;
8229 int p = em_player_mapping_list[i].player_nr;
8231 player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd;
8233 if (em_player_mapping_list[i].action != -1)
8234 player_mapping[p][a].action = em_player_mapping_list[i].action;
8236 if (em_player_mapping_list[i].direction != -1)
8237 player_mapping[p][a].direction =
8238 MV_DIR_FROM_BIT(em_player_mapping_list[i].direction);
8241 for (i = 0; i < TILE_MAX; i++)
8243 int element = object_mapping[i].element_rnd;
8244 int action = object_mapping[i].action;
8245 int direction = object_mapping[i].direction;
8246 boolean is_backside = object_mapping[i].is_backside;
8248 boolean action_removing = (action == ACTION_DIGGING ||
8249 action == ACTION_SNAPPING ||
8250 action == ACTION_COLLECTING);
8252 boolean action_exploding = ((action == ACTION_EXPLODING ||
8253 action == ACTION_SMASHED_BY_ROCK ||
8254 action == ACTION_SMASHED_BY_SPRING) &&
8255 element != EL_DIAMOND);
8256 boolean action_active = (action == ACTION_ACTIVE);
8257 boolean action_other = (action == ACTION_OTHER);
8259 for (j = 0; j < 8; j++)
8262 int effective_element = get_effective_element_EM(i, j);
8264 int effective_element = (j > 5 && i == Yacid_splash_eB ? EL_EMPTY :
8265 j > 5 && i == Yacid_splash_wB ? EL_EMPTY :
8267 i == Xdrip_stretch ? element :
8268 i == Xdrip_stretchB ? element :
8269 i == Ydrip_s1 ? element :
8270 i == Ydrip_s1B ? element :
8271 i == Xball_1B ? element :
8272 i == Xball_2 ? element :
8273 i == Xball_2B ? element :
8274 i == Yball_eat ? element :
8275 i == Ykey_1_eat ? element :
8276 i == Ykey_2_eat ? element :
8277 i == Ykey_3_eat ? element :
8278 i == Ykey_4_eat ? element :
8279 i == Ykey_5_eat ? element :
8280 i == Ykey_6_eat ? element :
8281 i == Ykey_7_eat ? element :
8282 i == Ykey_8_eat ? element :
8283 i == Ylenses_eat ? element :
8284 i == Ymagnify_eat ? element :
8285 i == Ygrass_eat ? element :
8286 i == Ydirt_eat ? element :
8287 i == Yemerald_stone ? EL_EMERALD :
8288 i == Ydiamond_stone ? EL_ROCK :
8289 i == Xsand_stonein_1 ? element :
8290 i == Xsand_stonein_2 ? element :
8291 i == Xsand_stonein_3 ? element :
8292 i == Xsand_stonein_4 ? element :
8293 is_backside ? EL_EMPTY :
8294 action_removing ? EL_EMPTY :
8297 int effective_action = (j < 7 ? action :
8298 i == Xdrip_stretch ? action :
8299 i == Xdrip_stretchB ? action :
8300 i == Ydrip_s1 ? action :
8301 i == Ydrip_s1B ? action :
8302 i == Xball_1B ? action :
8303 i == Xball_2 ? action :
8304 i == Xball_2B ? action :
8305 i == Yball_eat ? action :
8306 i == Ykey_1_eat ? action :
8307 i == Ykey_2_eat ? action :
8308 i == Ykey_3_eat ? action :
8309 i == Ykey_4_eat ? action :
8310 i == Ykey_5_eat ? action :
8311 i == Ykey_6_eat ? action :
8312 i == Ykey_7_eat ? action :
8313 i == Ykey_8_eat ? action :
8314 i == Ylenses_eat ? action :
8315 i == Ymagnify_eat ? action :
8316 i == Ygrass_eat ? action :
8317 i == Ydirt_eat ? action :
8318 i == Xsand_stonein_1 ? action :
8319 i == Xsand_stonein_2 ? action :
8320 i == Xsand_stonein_3 ? action :
8321 i == Xsand_stonein_4 ? action :
8322 i == Xsand_stoneout_1 ? action :
8323 i == Xsand_stoneout_2 ? action :
8324 i == Xboom_android ? ACTION_EXPLODING :
8325 action_exploding ? ACTION_EXPLODING :
8326 action_active ? action :
8327 action_other ? action :
8329 int graphic = (el_act_dir2img(effective_element, effective_action,
8331 int crumbled = (el_act_dir2crm(effective_element, effective_action,
8333 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
8334 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
8335 boolean has_action_graphics = (graphic != base_graphic);
8336 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
8337 struct GraphicInfo *g = &graphic_info[graphic];
8339 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
8341 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
8344 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
8345 boolean special_animation = (action != ACTION_DEFAULT &&
8346 g->anim_frames == 3 &&
8347 g->anim_delay == 2 &&
8348 g->anim_mode & ANIM_LINEAR);
8349 int sync_frame = (i == Xdrip_stretch ? 7 :
8350 i == Xdrip_stretchB ? 7 :
8351 i == Ydrip_s2 ? j + 8 :
8352 i == Ydrip_s2B ? j + 8 :
8361 i == Xfake_acid_1 ? 0 :
8362 i == Xfake_acid_2 ? 10 :
8363 i == Xfake_acid_3 ? 20 :
8364 i == Xfake_acid_4 ? 30 :
8365 i == Xfake_acid_5 ? 40 :
8366 i == Xfake_acid_6 ? 50 :
8367 i == Xfake_acid_7 ? 60 :
8368 i == Xfake_acid_8 ? 70 :
8370 i == Xball_2B ? j + 8 :
8371 i == Yball_eat ? j + 1 :
8372 i == Ykey_1_eat ? j + 1 :
8373 i == Ykey_2_eat ? j + 1 :
8374 i == Ykey_3_eat ? j + 1 :
8375 i == Ykey_4_eat ? j + 1 :
8376 i == Ykey_5_eat ? j + 1 :
8377 i == Ykey_6_eat ? j + 1 :
8378 i == Ykey_7_eat ? j + 1 :
8379 i == Ykey_8_eat ? j + 1 :
8380 i == Ylenses_eat ? j + 1 :
8381 i == Ymagnify_eat ? j + 1 :
8382 i == Ygrass_eat ? j + 1 :
8383 i == Ydirt_eat ? j + 1 :
8384 i == Xamoeba_1 ? 0 :
8385 i == Xamoeba_2 ? 1 :
8386 i == Xamoeba_3 ? 2 :
8387 i == Xamoeba_4 ? 3 :
8388 i == Xamoeba_5 ? 0 :
8389 i == Xamoeba_6 ? 1 :
8390 i == Xamoeba_7 ? 2 :
8391 i == Xamoeba_8 ? 3 :
8392 i == Xexit_2 ? j + 8 :
8393 i == Xexit_3 ? j + 16 :
8394 i == Xdynamite_1 ? 0 :
8395 i == Xdynamite_2 ? 8 :
8396 i == Xdynamite_3 ? 16 :
8397 i == Xdynamite_4 ? 24 :
8398 i == Xsand_stonein_1 ? j + 1 :
8399 i == Xsand_stonein_2 ? j + 9 :
8400 i == Xsand_stonein_3 ? j + 17 :
8401 i == Xsand_stonein_4 ? j + 25 :
8402 i == Xsand_stoneout_1 && j == 0 ? 0 :
8403 i == Xsand_stoneout_1 && j == 1 ? 0 :
8404 i == Xsand_stoneout_1 && j == 2 ? 1 :
8405 i == Xsand_stoneout_1 && j == 3 ? 2 :
8406 i == Xsand_stoneout_1 && j == 4 ? 2 :
8407 i == Xsand_stoneout_1 && j == 5 ? 3 :
8408 i == Xsand_stoneout_1 && j == 6 ? 4 :
8409 i == Xsand_stoneout_1 && j == 7 ? 4 :
8410 i == Xsand_stoneout_2 && j == 0 ? 5 :
8411 i == Xsand_stoneout_2 && j == 1 ? 6 :
8412 i == Xsand_stoneout_2 && j == 2 ? 7 :
8413 i == Xsand_stoneout_2 && j == 3 ? 8 :
8414 i == Xsand_stoneout_2 && j == 4 ? 9 :
8415 i == Xsand_stoneout_2 && j == 5 ? 11 :
8416 i == Xsand_stoneout_2 && j == 6 ? 13 :
8417 i == Xsand_stoneout_2 && j == 7 ? 15 :
8418 i == Xboom_bug && j == 1 ? 2 :
8419 i == Xboom_bug && j == 2 ? 2 :
8420 i == Xboom_bug && j == 3 ? 4 :
8421 i == Xboom_bug && j == 4 ? 4 :
8422 i == Xboom_bug && j == 5 ? 2 :
8423 i == Xboom_bug && j == 6 ? 2 :
8424 i == Xboom_bug && j == 7 ? 0 :
8425 i == Xboom_bomb && j == 1 ? 2 :
8426 i == Xboom_bomb && j == 2 ? 2 :
8427 i == Xboom_bomb && j == 3 ? 4 :
8428 i == Xboom_bomb && j == 4 ? 4 :
8429 i == Xboom_bomb && j == 5 ? 2 :
8430 i == Xboom_bomb && j == 6 ? 2 :
8431 i == Xboom_bomb && j == 7 ? 0 :
8432 i == Xboom_android && j == 7 ? 6 :
8433 i == Xboom_1 && j == 1 ? 2 :
8434 i == Xboom_1 && j == 2 ? 2 :
8435 i == Xboom_1 && j == 3 ? 4 :
8436 i == Xboom_1 && j == 4 ? 4 :
8437 i == Xboom_1 && j == 5 ? 6 :
8438 i == Xboom_1 && j == 6 ? 6 :
8439 i == Xboom_1 && j == 7 ? 8 :
8440 i == Xboom_2 && j == 0 ? 8 :
8441 i == Xboom_2 && j == 1 ? 8 :
8442 i == Xboom_2 && j == 2 ? 10 :
8443 i == Xboom_2 && j == 3 ? 10 :
8444 i == Xboom_2 && j == 4 ? 10 :
8445 i == Xboom_2 && j == 5 ? 12 :
8446 i == Xboom_2 && j == 6 ? 12 :
8447 i == Xboom_2 && j == 7 ? 12 :
8448 special_animation && j == 4 ? 3 :
8449 effective_action != action ? 0 :
8453 Bitmap *debug_bitmap = g_em->bitmap;
8454 int debug_src_x = g_em->src_x;
8455 int debug_src_y = g_em->src_y;
8458 int frame = getAnimationFrame(g->anim_frames,
8461 g->anim_start_frame,
8464 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y,
8465 g->double_movement && is_backside);
8467 g_em->bitmap = src_bitmap;
8468 g_em->src_x = src_x;
8469 g_em->src_y = src_y;
8470 g_em->src_offset_x = 0;
8471 g_em->src_offset_y = 0;
8472 g_em->dst_offset_x = 0;
8473 g_em->dst_offset_y = 0;
8474 g_em->width = TILEX;
8475 g_em->height = TILEY;
8477 g_em->preserve_background = FALSE;
8480 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
8485 g_em->crumbled_bitmap = NULL;
8486 g_em->crumbled_src_x = 0;
8487 g_em->crumbled_src_y = 0;
8488 g_em->crumbled_border_size = 0;
8490 g_em->has_crumbled_graphics = FALSE;
8493 if (has_crumbled_graphics && crumbled == IMG_EMPTY_SPACE)
8494 printf("::: empty crumbled: %d [%s], %d, %d\n",
8495 effective_element, element_info[effective_element].token_name,
8496 effective_action, direction);
8499 /* if element can be crumbled, but certain action graphics are just empty
8500 space (like instantly snapping sand to empty space in 1 frame), do not
8501 treat these empty space graphics as crumbled graphics in EMC engine */
8502 if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
8504 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
8505 g_crumbled->anim_delay,
8506 g_crumbled->anim_mode,
8507 g_crumbled->anim_start_frame,
8510 getGraphicSource(crumbled, frame_crumbled, &src_bitmap, &src_x, &src_y);
8512 g_em->has_crumbled_graphics = TRUE;
8513 g_em->crumbled_bitmap = src_bitmap;
8514 g_em->crumbled_src_x = src_x;
8515 g_em->crumbled_src_y = src_y;
8516 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
8520 if (g_em == &graphic_info_em_object[207][0])
8521 printf("... %d, %d [%d, %d, %d, %d] [%d, %d, %d, %d, %d, %d => %d]\n",
8522 graphic_info_em_object[207][0].crumbled_src_x,
8523 graphic_info_em_object[207][0].crumbled_src_y,
8525 crumbled, frame, src_x, src_y,
8530 g->anim_start_frame,
8532 gfx.anim_random_frame,
8537 printf("::: EMC tile %d is crumbled\n", i);
8543 if (element == EL_ROCK &&
8544 effective_action == ACTION_FILLING)
8545 printf("::: has_action_graphics == %d\n", has_action_graphics);
8548 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
8549 effective_action == ACTION_MOVING ||
8550 effective_action == ACTION_PUSHING ||
8551 effective_action == ACTION_EATING)) ||
8552 (!has_action_graphics && (effective_action == ACTION_FILLING ||
8553 effective_action == ACTION_EMPTYING)))
8556 (effective_action == ACTION_FALLING ||
8557 effective_action == ACTION_FILLING ||
8558 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
8559 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
8560 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
8561 int num_steps = (i == Ydrip_s1 ? 16 :
8562 i == Ydrip_s1B ? 16 :
8563 i == Ydrip_s2 ? 16 :
8564 i == Ydrip_s2B ? 16 :
8565 i == Xsand_stonein_1 ? 32 :
8566 i == Xsand_stonein_2 ? 32 :
8567 i == Xsand_stonein_3 ? 32 :
8568 i == Xsand_stonein_4 ? 32 :
8569 i == Xsand_stoneout_1 ? 16 :
8570 i == Xsand_stoneout_2 ? 16 : 8);
8571 int cx = ABS(dx) * (TILEX / num_steps);
8572 int cy = ABS(dy) * (TILEY / num_steps);
8573 int step_frame = (i == Ydrip_s2 ? j + 8 :
8574 i == Ydrip_s2B ? j + 8 :
8575 i == Xsand_stonein_2 ? j + 8 :
8576 i == Xsand_stonein_3 ? j + 16 :
8577 i == Xsand_stonein_4 ? j + 24 :
8578 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
8579 int step = (is_backside ? step_frame : num_steps - step_frame);
8581 if (is_backside) /* tile where movement starts */
8583 if (dx < 0 || dy < 0)
8585 g_em->src_offset_x = cx * step;
8586 g_em->src_offset_y = cy * step;
8590 g_em->dst_offset_x = cx * step;
8591 g_em->dst_offset_y = cy * step;
8594 else /* tile where movement ends */
8596 if (dx < 0 || dy < 0)
8598 g_em->dst_offset_x = cx * step;
8599 g_em->dst_offset_y = cy * step;
8603 g_em->src_offset_x = cx * step;
8604 g_em->src_offset_y = cy * step;
8608 g_em->width = TILEX - cx * step;
8609 g_em->height = TILEY - cy * step;
8612 /* create unique graphic identifier to decide if tile must be redrawn */
8613 /* bit 31 - 16 (16 bit): EM style graphic
8614 bit 15 - 12 ( 4 bit): EM style frame
8615 bit 11 - 6 ( 6 bit): graphic width
8616 bit 5 - 0 ( 6 bit): graphic height */
8617 g_em->unique_identifier =
8618 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
8622 /* skip check for EMC elements not contained in original EMC artwork */
8623 if (element == EL_EMC_FAKE_ACID)
8626 if (g_em->bitmap != debug_bitmap ||
8627 g_em->src_x != debug_src_x ||
8628 g_em->src_y != debug_src_y ||
8629 g_em->src_offset_x != 0 ||
8630 g_em->src_offset_y != 0 ||
8631 g_em->dst_offset_x != 0 ||
8632 g_em->dst_offset_y != 0 ||
8633 g_em->width != TILEX ||
8634 g_em->height != TILEY)
8636 static int last_i = -1;
8644 printf("::: EMC GFX ERROR for element %d -> %d ('%s', '%s', %d)",
8645 i, element, element_info[element].token_name,
8646 element_action_info[effective_action].suffix, direction);
8648 if (element != effective_element)
8649 printf(" [%d ('%s')]",
8651 element_info[effective_element].token_name);
8655 if (g_em->bitmap != debug_bitmap)
8656 printf(" %d (%d): different bitmap! (0x%08x != 0x%08x)\n",
8657 j, is_backside, (int)(g_em->bitmap), (int)(debug_bitmap));
8659 if (g_em->src_x != debug_src_x ||
8660 g_em->src_y != debug_src_y)
8661 printf(" frame %d (%c): %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
8662 j, (is_backside ? 'B' : 'F'),
8663 g_em->src_x, g_em->src_y,
8664 g_em->src_x / 32, g_em->src_y / 32,
8665 debug_src_x, debug_src_y,
8666 debug_src_x / 32, debug_src_y / 32);
8668 if (g_em->src_offset_x != 0 ||
8669 g_em->src_offset_y != 0 ||
8670 g_em->dst_offset_x != 0 ||
8671 g_em->dst_offset_y != 0)
8672 printf(" %d (%d): offsets %d,%d and %d,%d should be all 0\n",
8674 g_em->src_offset_x, g_em->src_offset_y,
8675 g_em->dst_offset_x, g_em->dst_offset_y);
8677 if (g_em->width != TILEX ||
8678 g_em->height != TILEY)
8679 printf(" %d (%d): size %d,%d should be %d,%d\n",
8681 g_em->width, g_em->height, TILEX, TILEY);
8683 num_em_gfx_errors++;
8690 for (i = 0; i < TILE_MAX; i++)
8692 for (j = 0; j < 8; j++)
8694 int element = object_mapping[i].element_rnd;
8695 int action = object_mapping[i].action;
8696 int direction = object_mapping[i].direction;
8697 boolean is_backside = object_mapping[i].is_backside;
8698 int graphic_action = el_act_dir2img(element, action, direction);
8699 int graphic_default = el_act_dir2img(element, ACTION_DEFAULT, direction);
8701 if ((action == ACTION_SMASHED_BY_ROCK ||
8702 action == ACTION_SMASHED_BY_SPRING ||
8703 action == ACTION_EATING) &&
8704 graphic_action == graphic_default)
8706 int e = (action == ACTION_SMASHED_BY_ROCK ? Ystone_s :
8707 action == ACTION_SMASHED_BY_SPRING ? Yspring_s :
8708 direction == MV_LEFT ? (is_backside? Yspring_wB: Yspring_w) :
8709 direction == MV_RIGHT ? (is_backside? Yspring_eB: Yspring_e) :
8712 /* no separate animation for "smashed by rock" -- use rock instead */
8713 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
8714 struct GraphicInfo_EM *g_xx = &graphic_info_em_object[e][7 - j];
8716 g_em->bitmap = g_xx->bitmap;
8717 g_em->src_x = g_xx->src_x;
8718 g_em->src_y = g_xx->src_y;
8719 g_em->src_offset_x = g_xx->src_offset_x;
8720 g_em->src_offset_y = g_xx->src_offset_y;
8721 g_em->dst_offset_x = g_xx->dst_offset_x;
8722 g_em->dst_offset_y = g_xx->dst_offset_y;
8723 g_em->width = g_xx->width;
8724 g_em->height = g_xx->height;
8725 g_em->unique_identifier = g_xx->unique_identifier;
8728 g_em->preserve_background = TRUE;
8733 for (p = 0; p < MAX_PLAYERS; p++)
8735 for (i = 0; i < SPR_MAX; i++)
8737 int element = player_mapping[p][i].element_rnd;
8738 int action = player_mapping[p][i].action;
8739 int direction = player_mapping[p][i].direction;
8741 for (j = 0; j < 8; j++)
8743 int effective_element = element;
8744 int effective_action = action;
8745 int graphic = (direction == MV_NONE ?
8746 el_act2img(effective_element, effective_action) :
8747 el_act_dir2img(effective_element, effective_action,
8749 struct GraphicInfo *g = &graphic_info[graphic];
8750 struct GraphicInfo_EM *g_em = &graphic_info_em_player[p][i][7 - j];
8756 Bitmap *debug_bitmap = g_em->bitmap;
8757 int debug_src_x = g_em->src_x;
8758 int debug_src_y = g_em->src_y;
8761 int frame = getAnimationFrame(g->anim_frames,
8764 g->anim_start_frame,
8767 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
8769 g_em->bitmap = src_bitmap;
8770 g_em->src_x = src_x;
8771 g_em->src_y = src_y;
8772 g_em->src_offset_x = 0;
8773 g_em->src_offset_y = 0;
8774 g_em->dst_offset_x = 0;
8775 g_em->dst_offset_y = 0;
8776 g_em->width = TILEX;
8777 g_em->height = TILEY;
8781 /* skip check for EMC elements not contained in original EMC artwork */
8782 if (element == EL_PLAYER_3 ||
8783 element == EL_PLAYER_4)
8786 if (g_em->bitmap != debug_bitmap ||
8787 g_em->src_x != debug_src_x ||
8788 g_em->src_y != debug_src_y)
8790 static int last_i = -1;
8798 printf("::: EMC GFX ERROR for p/a %d/%d -> %d ('%s', '%s', %d)",
8799 p, i, element, element_info[element].token_name,
8800 element_action_info[effective_action].suffix, direction);
8802 if (element != effective_element)
8803 printf(" [%d ('%s')]",
8805 element_info[effective_element].token_name);
8809 if (g_em->bitmap != debug_bitmap)
8810 printf(" %d: different bitmap! (0x%08x != 0x%08x)\n",
8811 j, (int)(g_em->bitmap), (int)(debug_bitmap));
8813 if (g_em->src_x != debug_src_x ||
8814 g_em->src_y != debug_src_y)
8815 printf(" frame %d: %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
8817 g_em->src_x, g_em->src_y,
8818 g_em->src_x / 32, g_em->src_y / 32,
8819 debug_src_x, debug_src_y,
8820 debug_src_x / 32, debug_src_y / 32);
8822 num_em_gfx_errors++;
8832 printf("::: [%d errors found]\n", num_em_gfx_errors);
8838 void CheckSingleStepMode_EM(byte action[MAX_PLAYERS], int frame,
8839 boolean any_player_moving,
8840 boolean player_is_dropping)
8844 if (tape.single_step && tape.recording && !tape.pausing)
8846 boolean active_players = FALSE;
8848 for (i = 0; i < MAX_PLAYERS; i++)
8849 if (action[i] != JOY_NO_ACTION)
8850 active_players = TRUE;
8853 if (frame == 0 && !player_is_dropping)
8854 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
8858 void CheckSingleStepMode_SP(boolean murphy_is_waiting,
8859 boolean murphy_is_dropping)
8862 printf("::: waiting: %d, dropping: %d\n",
8863 murphy_is_waiting, murphy_is_dropping);
8866 if (tape.single_step && tape.recording && !tape.pausing)
8868 // if (murphy_is_waiting || murphy_is_dropping)
8869 if (murphy_is_waiting)
8872 printf("::: murphy is waiting -> pause mode\n");
8875 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
8880 void getGraphicSource_SP(struct GraphicInfo_SP *g_sp,
8881 int graphic, int sync_frame, int x, int y)
8883 int frame = getGraphicAnimationFrame(graphic, sync_frame);
8885 getGraphicSource(graphic, frame, &g_sp->bitmap, &g_sp->src_x, &g_sp->src_y);
8888 boolean isNextAnimationFrame_SP(int graphic, int sync_frame)
8890 return (IS_NEXT_FRAME(sync_frame, graphic));
8893 int getGraphicInfo_Delay(int graphic)
8895 return graphic_info[graphic].anim_delay;
8898 void PlayMenuSoundExt(int sound)
8900 if (sound == SND_UNDEFINED)
8903 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
8904 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
8907 if (IS_LOOP_SOUND(sound))
8908 PlaySoundLoop(sound);
8913 void PlayMenuSound()
8915 PlayMenuSoundExt(menu.sound[game_status]);
8918 void PlayMenuSoundStereo(int sound, int stereo_position)
8920 if (sound == SND_UNDEFINED)
8923 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
8924 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
8927 if (IS_LOOP_SOUND(sound))
8928 PlaySoundExt(sound, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_LOOP);
8930 PlaySoundStereo(sound, stereo_position);
8933 void PlayMenuSoundIfLoopExt(int sound)
8935 if (sound == SND_UNDEFINED)
8938 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
8939 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
8942 if (IS_LOOP_SOUND(sound))
8943 PlaySoundLoop(sound);
8946 void PlayMenuSoundIfLoop()
8948 PlayMenuSoundIfLoopExt(menu.sound[game_status]);
8951 void PlayMenuMusicExt(int music)
8953 if (music == MUS_UNDEFINED)
8956 if (!setup.sound_music)
8962 void PlayMenuMusic()
8964 PlayMenuMusicExt(menu.music[game_status]);
8967 void PlaySoundActivating()
8970 PlaySound(SND_MENU_ITEM_ACTIVATING);
8974 void PlaySoundSelecting()
8977 PlaySound(SND_MENU_ITEM_SELECTING);
8981 void ToggleFullscreenIfNeeded()
8983 boolean change_fullscreen = (setup.fullscreen !=
8984 video.fullscreen_enabled);
8985 boolean change_fullscreen_mode = (video.fullscreen_enabled &&
8986 !strEqual(setup.fullscreen_mode,
8987 video.fullscreen_mode_current));
8989 if (!video.fullscreen_available)
8992 if (change_fullscreen || change_fullscreen_mode)
8994 Bitmap *tmp_backbuffer = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
8996 /* save backbuffer content which gets lost when toggling fullscreen mode */
8997 BlitBitmap(backbuffer, tmp_backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
8999 if (change_fullscreen_mode)
9001 /* keep fullscreen, but change fullscreen mode (screen resolution) */
9002 video.fullscreen_enabled = FALSE; /* force new fullscreen mode */
9005 /* toggle fullscreen */
9006 ChangeVideoModeIfNeeded(setup.fullscreen);
9008 setup.fullscreen = video.fullscreen_enabled;
9010 /* restore backbuffer content from temporary backbuffer backup bitmap */
9011 BlitBitmap(tmp_backbuffer, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
9013 FreeBitmap(tmp_backbuffer);
9016 /* update visible window/screen */
9017 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
9019 redraw_mask = REDRAW_ALL;
9024 void ChangeViewportPropertiesIfNeeded()
9026 int *door_1_x = &DX;
9027 int *door_1_y = &DY;
9028 int *door_2_x = (game_status == GAME_MODE_EDITOR ? &EX : &VX);
9029 int *door_2_y = (game_status == GAME_MODE_EDITOR ? &EY : &VY);
9030 int gfx_game_mode = (game_status == GAME_MODE_PLAYING ||
9031 game_status == GAME_MODE_EDITOR ? game_status :
9033 struct RectWithBorder *vp_playfield = &viewport.playfield[gfx_game_mode];
9034 struct RectWithBorder *vp_door_1 = &viewport.door_1[gfx_game_mode];
9035 struct RectWithBorder *vp_door_2 = &viewport.door_2[gfx_game_mode];
9036 int border_size = vp_playfield->border_size;
9037 int new_sx = vp_playfield->x + border_size;
9038 int new_sy = vp_playfield->y + border_size;
9039 int new_sxsize = vp_playfield->width - 2 * border_size;
9040 int new_sysize = vp_playfield->height - 2 * border_size;
9041 int new_real_sx = vp_playfield->x;
9042 int new_real_sy = vp_playfield->y;
9043 int new_full_sxsize = vp_playfield->width;
9044 int new_full_sysize = vp_playfield->height;
9046 int new_tilesize_var = TILESIZE / (setup.small_game_graphics ? 2 : 1);
9047 int tilesize = (gfx_game_mode == GAME_MODE_PLAYING ? new_tilesize_var :
9048 gfx_game_mode == GAME_MODE_EDITOR ? MINI_TILESIZE : TILESIZE);
9049 int new_scr_fieldx = new_sxsize / tilesize;
9050 int new_scr_fieldy = new_sysize / tilesize;
9051 int new_scr_fieldx_buffers = new_sxsize / new_tilesize_var;
9052 int new_scr_fieldy_buffers = new_sysize / new_tilesize_var;
9054 int new_scr_fieldx = (vp_playfield->width - 2 * border_size) / TILESIZE;
9055 int new_scr_fieldy = (vp_playfield->height - 2 * border_size) / TILESIZE;
9057 boolean init_gfx_buffers = FALSE;
9058 boolean init_video_buffer = FALSE;
9059 boolean init_gadgets_and_toons = FALSE;
9062 /* !!! TEST ONLY !!! */
9063 // InitGfxBuffers();
9067 if (viewport.window.width != WIN_XSIZE ||
9068 viewport.window.height != WIN_YSIZE)
9070 WIN_XSIZE = viewport.window.width;
9071 WIN_YSIZE = viewport.window.height;
9074 init_video_buffer = TRUE;
9075 init_gfx_buffers = TRUE;
9077 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
9081 SetDrawDeactivationMask(REDRAW_NONE);
9082 SetDrawBackgroundMask(REDRAW_FIELD);
9084 // RedrawBackground();
9088 // printf("::: video: init_video_buffer, init_gfx_buffers\n");
9091 if (new_scr_fieldx != SCR_FIELDX ||
9092 new_scr_fieldy != SCR_FIELDY)
9094 /* this always toggles between MAIN and GAME when using small tile size */
9096 SCR_FIELDX = new_scr_fieldx;
9097 SCR_FIELDY = new_scr_fieldy;
9099 // printf("::: new_scr_fieldx != SCR_FIELDX ...\n");
9103 if (new_tilesize_var != TILESIZE_VAR &&
9104 gfx_game_mode == GAME_MODE_PLAYING)
9106 /* doing this outside GAME_MODE_PLAYING would give wrong playfield size */
9108 TILESIZE_VAR = new_tilesize_var;
9110 init_gfx_buffers = TRUE;
9112 // printf("::: tilesize: init_gfx_buffers\n");
9118 new_sxsize != SXSIZE ||
9119 new_sysize != SYSIZE ||
9120 new_real_sx != REAL_SX ||
9121 new_real_sy != REAL_SY ||
9122 new_full_sxsize != FULL_SXSIZE ||
9123 new_full_sysize != FULL_SYSIZE ||
9124 new_tilesize_var != TILESIZE_VAR ||
9125 vp_door_1->x != *door_1_x ||
9126 vp_door_1->y != *door_1_y ||
9127 vp_door_2->x != *door_2_x ||
9128 vp_door_2->y != *door_2_y)
9132 SXSIZE = new_sxsize;
9133 SYSIZE = new_sysize;
9134 REAL_SX = new_real_sx;
9135 REAL_SY = new_real_sy;
9136 FULL_SXSIZE = new_full_sxsize;
9137 FULL_SYSIZE = new_full_sysize;
9138 TILESIZE_VAR = new_tilesize_var;
9141 printf("::: %d, %d, %d [%d]\n",
9142 SCR_FIELDX, SCR_FIELDY, TILESIZE_VAR,
9143 setup.small_game_graphics);
9146 *door_1_x = vp_door_1->x;
9147 *door_1_y = vp_door_1->y;
9148 *door_2_x = vp_door_2->x;
9149 *door_2_y = vp_door_2->y;
9152 init_gfx_buffers = TRUE;
9154 // printf("::: viewports: init_gfx_buffers\n");
9159 if (gfx_game_mode == GAME_MODE_MAIN)
9162 init_gadgets_and_toons = TRUE;
9164 // printf("::: viewports: init_gadgets_and_toons\n");
9172 if (init_gfx_buffers)
9174 // printf("::: init_gfx_buffers\n");
9176 SCR_FIELDX = new_scr_fieldx_buffers;
9177 SCR_FIELDY = new_scr_fieldy_buffers;
9181 SCR_FIELDX = new_scr_fieldx;
9182 SCR_FIELDY = new_scr_fieldy;
9185 if (init_video_buffer)
9187 // printf("::: init_video_buffer\n");
9189 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
9191 SetDrawDeactivationMask(REDRAW_NONE);
9192 SetDrawBackgroundMask(REDRAW_FIELD);
9195 if (init_gadgets_and_toons)
9197 // printf("::: init_gadgets_and_toons\n");
9204 printf("::: %d, %d / %d, %d [%d]\n", VX, VY, EX, EY, game_status);