1 // ============================================================================
2 // Rocks'n'Diamonds - McDuffin Strikes Back!
3 // ----------------------------------------------------------------------------
4 // (c) 1995-2014 by Artsoft Entertainment
7 // http://www.artsoft.org/
8 // ----------------------------------------------------------------------------
10 // ============================================================================
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 /* constants for number of doors and door parts */
42 #define NUM_PANELS NUM_DOORS
43 // #define NUM_PANELS 0
44 #define MAX_PARTS_PER_DOOR 8
45 #define MAX_DOOR_PARTS (NUM_DOORS * MAX_PARTS_PER_DOOR + NUM_PANELS)
46 #define DOOR_PART_IS_PANEL(i) ((i) >= NUM_DOORS * MAX_PARTS_PER_DOOR)
49 struct DoorPartOrderInfo
55 static struct DoorPartOrderInfo door_part_order[MAX_DOOR_PARTS];
57 struct DoorPartControlInfo
61 struct DoorPartPosInfo *pos;
64 static struct DoorPartControlInfo door_part_controls[] =
68 IMG_DOOR_1_GFX_PART_1,
73 IMG_DOOR_1_GFX_PART_2,
78 IMG_DOOR_1_GFX_PART_3,
83 IMG_DOOR_1_GFX_PART_4,
88 IMG_DOOR_1_GFX_PART_5,
93 IMG_DOOR_1_GFX_PART_6,
98 IMG_DOOR_1_GFX_PART_7,
103 IMG_DOOR_1_GFX_PART_8,
109 IMG_DOOR_2_GFX_PART_1,
114 IMG_DOOR_2_GFX_PART_2,
119 IMG_DOOR_2_GFX_PART_3,
124 IMG_DOOR_2_GFX_PART_4,
129 IMG_DOOR_2_GFX_PART_5,
134 IMG_DOOR_2_GFX_PART_6,
139 IMG_DOOR_2_GFX_PART_7,
144 IMG_DOOR_2_GFX_PART_8,
150 IMG_BACKGROUND_PANEL,
167 /* forward declaration for internal use */
168 static void UnmapToolButtons();
169 static void HandleToolButtons(struct GadgetInfo *);
170 static int el_act_dir2crm(int, int, int);
171 static int el_act2crm(int, int);
173 static struct GadgetInfo *tool_gadget[NUM_TOOL_BUTTONS];
174 static int request_gadget_id = -1;
176 static char *print_if_not_empty(int element)
178 static char *s = NULL;
179 char *token_name = element_info[element].token_name;
184 s = checked_malloc(strlen(token_name) + 10 + 1);
186 if (element != EL_EMPTY)
187 sprintf(s, "%d\t['%s']", element, token_name);
189 sprintf(s, "%d", element);
194 void DumpTile(int x, int y)
199 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
205 printf_line("-", 79);
206 printf("Field Info: SCREEN(%d, %d), LEVEL(%d, %d)\n", sx, sy, x, y);
207 printf_line("-", 79);
209 if (!IN_LEV_FIELD(x, y))
211 printf("(not in level field)\n");
217 printf(" Feld: %d\t['%s']\n", Feld[x][y],
218 element_info[Feld[x][y]].token_name);
219 printf(" Back: %s\n", print_if_not_empty(Back[x][y]));
220 printf(" Store: %s\n", print_if_not_empty(Store[x][y]));
221 printf(" Store2: %s\n", print_if_not_empty(Store2[x][y]));
222 printf(" StorePlayer: %s\n", print_if_not_empty(StorePlayer[x][y]));
223 printf(" MovPos: %d\n", MovPos[x][y]);
224 printf(" MovDir: %d\n", MovDir[x][y]);
225 printf(" MovDelay: %d\n", MovDelay[x][y]);
226 printf(" ChangeDelay: %d\n", ChangeDelay[x][y]);
227 printf(" CustomValue: %d\n", CustomValue[x][y]);
228 printf(" GfxElement: %d\n", GfxElement[x][y]);
229 printf(" GfxAction: %d\n", GfxAction[x][y]);
230 printf(" GfxFrame: %d\n", GfxFrame[x][y]);
234 void SetDrawtoField(int mode)
236 if (mode == DRAW_BUFFERED && setup.soft_scrolling)
244 BX2 = SCR_FIELDX + 1;
245 BY2 = SCR_FIELDY + 1;
264 BX2 = SCR_FIELDX + 1;
265 BY2 = SCR_FIELDY + 1;
280 drawto_field = fieldbuffer;
282 else /* DRAW_BACKBUFFER */
288 BX2 = SCR_FIELDX - 1;
289 BY2 = SCR_FIELDY - 1;
293 drawto_field = backbuffer;
299 static void RedrawPlayfield_RND()
301 if (game.envelope_active)
305 DrawLevel(REDRAW_ALL);
309 SetMainBackgroundImage(IMG_BACKGROUND_PLAYING);
310 // SetDrawBackgroundMask(REDRAW_FIELD); // !!! CHECK THIS !!!
311 SetDrawBackgroundMask(REDRAW_ALL); // !!! CHECK THIS !!!
313 for (x = BX1; x <= BX2; x++)
314 for (y = BY1; y <= BY2; y++)
315 DrawScreenField(x, y);
317 redraw_mask |= REDRAW_FIELD;
323 BlitScreenToBitmap(backbuffer);
325 /* blit playfield from scroll buffer to normal back buffer */
326 if (setup.soft_scrolling)
328 int fx = FX, fy = FY;
330 fx += (ScreenMovDir & (MV_LEFT|MV_RIGHT) ? ScreenGfxPos : 0);
331 fy += (ScreenMovDir & (MV_UP|MV_DOWN) ? ScreenGfxPos : 0);
333 BlitBitmap(fieldbuffer, backbuffer, fx,fy, SXSIZE,SYSIZE, SX,SY);
339 void RedrawPlayfield()
341 if (game_status != GAME_MODE_PLAYING)
344 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
345 RedrawPlayfield_EM(TRUE);
346 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
347 RedrawPlayfield_SP(TRUE);
348 else if (level.game_engine_type == GAME_ENGINE_TYPE_RND)
349 RedrawPlayfield_RND();
351 BlitScreenToBitmap(backbuffer);
353 BlitBitmap(drawto, window, gfx.sx, gfx.sy, gfx.sxsize, gfx.sysize,
359 void RedrawPlayfield(boolean force_redraw, int x, int y, int width, int height)
361 if (game_status == GAME_MODE_PLAYING &&
362 level.game_engine_type == GAME_ENGINE_TYPE_EM)
364 /* currently there is no partial redraw -- always redraw whole playfield */
365 RedrawPlayfield_EM(TRUE);
367 /* blit playfield from scroll buffer to normal back buffer for fading in */
368 BlitScreenToBitmap_EM(backbuffer);
370 else if (game_status == GAME_MODE_PLAYING &&
371 level.game_engine_type == GAME_ENGINE_TYPE_SP)
373 /* currently there is no partial redraw -- always redraw whole playfield */
374 RedrawPlayfield_SP(TRUE);
376 /* blit playfield from scroll buffer to normal back buffer for fading in */
377 BlitScreenToBitmap_SP(backbuffer);
379 else if (game_status == GAME_MODE_PLAYING &&
380 !game.envelope_active)
386 width = gfx.sxsize + 2 * TILEX;
387 height = gfx.sysize + 2 * TILEY;
393 int x1 = (x - SX) / TILEX, y1 = (y - SY) / TILEY;
394 int x2 = (x - SX + width) / TILEX, y2 = (y - SY + height) / TILEY;
396 for (xx = BX1; xx <= BX2; xx++)
397 for (yy = BY1; yy <= BY2; yy++)
398 if (xx >= x1 && xx <= x2 && yy >= y1 && yy <= y2)
399 DrawScreenField(xx, yy);
403 if (setup.soft_scrolling)
405 int fx = FX, fy = FY;
407 fx += (ScreenMovDir & (MV_LEFT|MV_RIGHT) ? ScreenGfxPos : 0);
408 fy += (ScreenMovDir & (MV_UP|MV_DOWN) ? ScreenGfxPos : 0);
410 BlitBitmap(fieldbuffer, backbuffer, fx,fy, SXSIZE,SYSIZE, SX,SY);
422 BlitBitmap(drawto, window, x, y, width, height, x, y);
427 void DrawMaskedBorder_Rect(int x, int y, int width, int height)
429 Bitmap *bitmap = graphic_info[IMG_GLOBAL_BORDER].bitmap;
431 SetClipOrigin(bitmap, bitmap->stored_clip_gc, 0, 0);
432 BlitBitmapMasked(bitmap, backbuffer, x, y, width, height, x, y);
435 void DrawMaskedBorder_FIELD()
437 if (global.border_status >= GAME_MODE_TITLE &&
438 global.border_status <= GAME_MODE_PLAYING &&
439 border.draw_masked[global.border_status])
440 DrawMaskedBorder_Rect(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
443 void DrawMaskedBorder_DOOR_1()
445 if (border.draw_masked[GFX_SPECIAL_ARG_DOOR] &&
446 (global.border_status != GAME_MODE_EDITOR ||
447 border.draw_masked[GFX_SPECIAL_ARG_EDITOR]))
448 DrawMaskedBorder_Rect(DX, DY, DXSIZE, DYSIZE);
451 void DrawMaskedBorder_DOOR_2()
453 if (border.draw_masked[GFX_SPECIAL_ARG_DOOR] &&
454 global.border_status != GAME_MODE_EDITOR)
455 DrawMaskedBorder_Rect(VX, VY, VXSIZE, VYSIZE);
458 void DrawMaskedBorder_DOOR_3()
460 /* currently not available */
463 void DrawMaskedBorder_ALL()
465 DrawMaskedBorder_FIELD();
466 DrawMaskedBorder_DOOR_1();
467 DrawMaskedBorder_DOOR_2();
468 DrawMaskedBorder_DOOR_3();
471 void DrawMaskedBorder(int redraw_mask)
473 /* never draw masked screen borders on borderless screens */
474 if (effectiveGameStatus() == GAME_MODE_LOADING ||
475 effectiveGameStatus() == GAME_MODE_TITLE)
478 /* never draw masked screen borders when displaying request outside door */
479 if (effectiveGameStatus() == GAME_MODE_PSEUDO_DOOR &&
480 global.use_envelope_request)
483 if (redraw_mask & REDRAW_ALL)
484 DrawMaskedBorder_ALL();
487 if (redraw_mask & REDRAW_FIELD)
488 DrawMaskedBorder_FIELD();
489 if (redraw_mask & REDRAW_DOOR_1)
490 DrawMaskedBorder_DOOR_1();
491 if (redraw_mask & REDRAW_DOOR_2)
492 DrawMaskedBorder_DOOR_2();
493 if (redraw_mask & REDRAW_DOOR_3)
494 DrawMaskedBorder_DOOR_3();
498 static void BlitScreenToBitmap_RND(Bitmap *target_bitmap)
500 DrawBuffer *buffer = (drawto_field == window ? backbuffer : drawto_field);
501 int fx = FX, fy = FY;
502 int full_lev_fieldx = lev_fieldx + (BorderElement != EL_EMPTY ? 2 : 0);
503 int full_lev_fieldy = lev_fieldy + (BorderElement != EL_EMPTY ? 2 : 0);
506 int dx = (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
507 int dy = (ScreenMovDir & (MV_UP | MV_DOWN) ? ScreenGfxPos : 0);
508 int dx_var = dx * TILESIZE_VAR / TILESIZE;
509 int dy_var = dy * TILESIZE_VAR / TILESIZE;
512 // fx += dx * TILESIZE_VAR / TILESIZE;
513 // fy += dy * TILESIZE_VAR / TILESIZE;
515 fx += (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
516 fy += (ScreenMovDir & (MV_UP | MV_DOWN) ? ScreenGfxPos : 0);
519 ffx = (scroll_x - SBX_Left) * TILEX_VAR + dx_var;
520 ffy = (scroll_y - SBY_Upper) * TILEY_VAR + dy_var;
522 if (EVEN(SCR_FIELDX))
524 if (ffx < SBX_Right * TILEX_VAR + TILEX_VAR / 2 + TILEX_VAR)
525 fx += dx_var - MIN(ffx, TILEX_VAR / 2) + TILEX_VAR;
527 fx += (dx_var > 0 ? TILEX_VAR : 0);
534 if (EVEN(SCR_FIELDY))
536 if (ffy < SBY_Lower * TILEY_VAR + TILEY_VAR / 2 + TILEY_VAR)
537 fy += dy_var - MIN(ffy, TILEY_VAR / 2) + TILEY_VAR;
539 fy += (dy_var > 0 ? TILEY_VAR : 0);
547 printf("::: (%d, %d) [(%d / %d, %d / %d)] => %d, %d\n",
550 SBY_Upper, SBY_Lower,
555 if (full_lev_fieldx <= SCR_FIELDX)
557 // printf(":1: PLAYFIELD FITS TO SCREEN [%d, %d, %d]\n", fx, ffx, dx_var);
559 if (EVEN(SCR_FIELDX))
560 fx = 2 * TILEX_VAR - (ODD(lev_fieldx) ? TILEX_VAR / 2 : 0);
562 fx = 2 * TILEX_VAR - (EVEN(lev_fieldx) ? TILEX_VAR / 2 : 0);
564 // printf(":2: PLAYFIELD FITS TO SCREEN [%d, %d, %d]\n", fx, ffx, dx_var);
567 if (full_lev_fieldy <= SCR_FIELDY)
569 if (EVEN(SCR_FIELDY))
570 fy = 2 * TILEY_VAR - (ODD(lev_fieldy) ? TILEY_VAR / 2 : 0);
572 fy = 2 * TILEY_VAR - (EVEN(lev_fieldy) ? TILEY_VAR / 2 : 0);
576 if (border.draw_masked[GAME_MODE_PLAYING])
578 if (buffer != backbuffer)
580 /* copy playfield buffer to backbuffer to add masked border */
581 BlitBitmap(buffer, backbuffer, fx, fy, SXSIZE, SYSIZE, SX, SY);
582 DrawMaskedBorder(REDRAW_FIELD);
585 BlitBitmap(backbuffer, target_bitmap,
586 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
591 BlitBitmap(buffer, target_bitmap, fx, fy, SXSIZE, SYSIZE, SX, SY);
595 void BlitScreenToBitmap(Bitmap *target_bitmap)
597 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
598 BlitScreenToBitmap_EM(target_bitmap);
599 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
600 BlitScreenToBitmap_SP(target_bitmap);
601 else if (level.game_engine_type == GAME_ENGINE_TYPE_RND)
602 BlitScreenToBitmap_RND(target_bitmap);
608 DrawBuffer *buffer = (drawto_field == window ? backbuffer : drawto_field);
611 printf("::: TILES TO REFRESH: %d\n", redraw_tiles);
612 for (x = 0; x < SCR_FIELDX; x++)
613 for (y = 0 ; y < SCR_FIELDY; y++)
614 if (redraw[redraw_x1 + x][redraw_y1 + y])
615 printf("::: - %d, %d [%s]\n",
616 LEVELX(x), LEVELY(y),
617 EL_NAME(Feld[LEVELX(x)][LEVELY(y)]));
620 if (redraw_mask & REDRAW_TILES && redraw_tiles > REDRAWTILES_THRESHOLD)
621 redraw_mask |= REDRAW_FIELD;
624 // never redraw single tiles, always redraw the whole field
625 // (redrawing single tiles up to a certain threshold was faster on old,
626 // now legacy graphics, but slows things down on modern graphics now)
627 // UPDATE: this is now globally defined by value of REDRAWTILES_THRESHOLD
628 if (redraw_mask & REDRAW_TILES)
629 redraw_mask |= REDRAW_FIELD;
633 /* !!! TEST ONLY !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */
634 /* (force full redraw) */
635 if (game_status == GAME_MODE_PLAYING)
636 redraw_mask |= REDRAW_FIELD;
639 if (redraw_mask & REDRAW_FIELD)
640 redraw_mask &= ~REDRAW_TILES;
642 if (redraw_mask == REDRAW_NONE)
647 if (redraw_mask & REDRAW_ALL)
648 printf("[REDRAW_ALL]");
649 if (redraw_mask & REDRAW_FIELD)
650 printf("[REDRAW_FIELD]");
651 if (redraw_mask & REDRAW_TILES)
652 printf("[REDRAW_TILES]");
653 if (redraw_mask & REDRAW_DOOR_1)
654 printf("[REDRAW_DOOR_1]");
655 if (redraw_mask & REDRAW_DOOR_2)
656 printf("[REDRAW_DOOR_2]");
657 if (redraw_mask & REDRAW_FROM_BACKBUFFER)
658 printf("[REDRAW_FROM_BACKBUFFER]");
659 printf(" [%d]\n", FrameCounter);
662 if (redraw_mask & REDRAW_TILES &&
663 game_status == GAME_MODE_PLAYING &&
664 border.draw_masked[GAME_MODE_PLAYING])
665 redraw_mask |= REDRAW_FIELD;
667 if (global.fps_slowdown && game_status == GAME_MODE_PLAYING)
669 static boolean last_frame_skipped = FALSE;
670 boolean skip_even_when_not_scrolling = TRUE;
671 boolean just_scrolling = (ScreenMovDir != 0);
672 boolean verbose = FALSE;
674 if (global.fps_slowdown_factor > 1 &&
675 (FrameCounter % global.fps_slowdown_factor) &&
676 (just_scrolling || skip_even_when_not_scrolling))
678 redraw_mask &= ~REDRAW_MAIN;
680 last_frame_skipped = TRUE;
683 printf("FRAME SKIPPED\n");
687 if (last_frame_skipped)
688 redraw_mask |= REDRAW_FIELD;
690 last_frame_skipped = FALSE;
693 printf("frame not skipped\n");
697 /* synchronize X11 graphics at this point; if we would synchronize the
698 display immediately after the buffer switching (after the XFlush),
699 this could mean that we have to wait for the graphics to complete,
700 although we could go on doing calculations for the next frame */
704 /* never draw masked border to backbuffer when using playfield buffer */
705 if (game_status != GAME_MODE_PLAYING ||
706 redraw_mask & REDRAW_FROM_BACKBUFFER ||
707 buffer == backbuffer)
708 DrawMaskedBorder(redraw_mask);
710 DrawMaskedBorder(redraw_mask & REDRAW_DOORS);
712 if (redraw_mask & REDRAW_ALL)
715 if (game_status != GAME_MODE_PLAYING ||
716 redraw_mask & REDRAW_FROM_BACKBUFFER)
719 printf("::: REDRAW_ALL [%d]\n", FrameCounter);
722 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
724 redraw_mask = REDRAW_NONE;
728 redraw_mask &= ~REDRAW_ALL;
732 printf("::: REDRAW_ALL [%d]\n", FrameCounter);
735 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
737 redraw_mask = REDRAW_NONE;
741 if (redraw_mask & REDRAW_FIELD)
744 printf("::: REDRAW_FIELD [%d]\n", FrameCounter);
747 if (game_status != GAME_MODE_PLAYING ||
748 redraw_mask & REDRAW_FROM_BACKBUFFER)
750 BlitBitmap(backbuffer, window,
751 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE, REAL_SX, REAL_SY);
756 BlitScreenToBitmap_RND(window);
758 int fx = FX, fy = FY;
761 int dx = (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
762 int dy = (ScreenMovDir & (MV_UP | MV_DOWN) ? ScreenGfxPos : 0);
763 int dx_var = dx * TILESIZE_VAR / TILESIZE;
764 int dy_var = dy * TILESIZE_VAR / TILESIZE;
767 // fx += dx * TILESIZE_VAR / TILESIZE;
768 // fy += dy * TILESIZE_VAR / TILESIZE;
770 fx += (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
771 fy += (ScreenMovDir & (MV_UP | MV_DOWN) ? ScreenGfxPos : 0);
774 /* !!! THIS WORKS !!! */
776 printf("::: %d, %d\n", scroll_x, scroll_y);
778 ffx = (scroll_x - SBX_Left) * TILEX_VAR + dx_var;
779 ffy = (scroll_y - SBY_Upper) * TILEY_VAR + dy_var;
781 if (EVEN(SCR_FIELDX))
783 if (ffx < SBX_Right * TILEX_VAR + TILEX_VAR / 2 + TILEX_VAR)
784 fx += dx_var - MIN(ffx, TILEX_VAR / 2) + TILEX_VAR;
786 fx += (dx > 0 ? TILEX_VAR : 0);
793 if (EVEN(SCR_FIELDY))
795 if (ffy < SBY_Lower * TILEY_VAR + TILEY_VAR / 2 + TILEY_VAR)
796 fy += dy_var - MIN(ffy, TILEY_VAR / 2) + TILEY_VAR;
798 fy += (dy > 0 ? TILEY_VAR : 0);
805 if (border.draw_masked[GAME_MODE_PLAYING])
807 if (buffer != backbuffer)
809 /* copy playfield buffer to backbuffer to add masked border */
810 BlitBitmap(buffer, backbuffer, fx, fy, SXSIZE, SYSIZE, SX, SY);
811 DrawMaskedBorder(REDRAW_FIELD);
814 BlitBitmap(backbuffer, window,
815 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
820 BlitBitmap(buffer, window, fx, fy, SXSIZE, SYSIZE, SX, SY);
826 printf("redrawing all (ScreenGfxPos == %d) because %s\n",
828 (setup.soft_scrolling ?
829 "setup.soft_scrolling" :
830 ABS(ScreenGfxPos) + ScrollStepSize == TILEX ?
831 "ABS(ScreenGfxPos) + ScrollStepSize == TILEX" :
832 ABS(ScreenGfxPos) == ScrollStepSize ?
833 "ABS(ScreenGfxPos) == ScrollStepSize" :
834 "redraw_tiles > REDRAWTILES_THRESHOLD"));
839 redraw_mask &= ~REDRAW_MAIN;
842 if (redraw_mask & REDRAW_DOORS)
844 if (redraw_mask & REDRAW_DOOR_1)
845 BlitBitmap(backbuffer, window, DX, DY, DXSIZE, DYSIZE, DX, DY);
847 if (redraw_mask & REDRAW_DOOR_2)
848 BlitBitmap(backbuffer, window, VX, VY, VXSIZE, VYSIZE, VX, VY);
850 if (redraw_mask & REDRAW_DOOR_3)
851 BlitBitmap(backbuffer, window, EX, EY, EXSIZE, EYSIZE, EX, EY);
853 redraw_mask &= ~REDRAW_DOORS;
856 if (redraw_mask & REDRAW_MICROLEVEL)
858 BlitBitmap(backbuffer, window, SX, SY + 10 * TILEY, SXSIZE, 7 * TILEY,
859 SX, SY + 10 * TILEY);
861 redraw_mask &= ~REDRAW_MICROLEVEL;
864 if (redraw_mask & REDRAW_TILES)
867 printf("::: REDRAW_TILES\n");
873 InitGfxClipRegion(TRUE, SX, SY, SXSIZE, SYSIZE);
876 int sx = SX; // - (EVEN(SCR_FIELDX) ? TILEX_VAR / 2 : 0);
877 int sy = SY; // + (EVEN(SCR_FIELDY) ? TILEY_VAR / 2 : 0);
880 int dx_var = dx * TILESIZE_VAR / TILESIZE;
881 int dy_var = dy * TILESIZE_VAR / TILESIZE;
883 int fx = FX, fy = FY;
885 int scr_fieldx = SCR_FIELDX + (EVEN(SCR_FIELDX) ? 2 : 0);
886 int scr_fieldy = SCR_FIELDY + (EVEN(SCR_FIELDY) ? 2 : 0);
888 ffx = (scroll_x - SBX_Left) * TILEX_VAR + dx_var;
889 ffy = (scroll_y - SBY_Upper) * TILEY_VAR + dy_var;
891 if (EVEN(SCR_FIELDX))
893 if (ffx < SBX_Right * TILEX_VAR + TILEX_VAR / 2 + TILEX_VAR)
895 fx += dx_var - MIN(ffx, TILEX_VAR / 2) + TILEX_VAR;
904 fx += (dx_var > 0 ? TILEX_VAR : 0);
908 if (EVEN(SCR_FIELDY))
910 if (ffy < SBY_Lower * TILEY_VAR + TILEY_VAR / 2 + TILEY_VAR)
912 fy += dy_var - MIN(ffy, TILEY_VAR / 2) + TILEY_VAR;
921 fy += (dy_var > 0 ? TILEY_VAR : 0);
926 printf("::: %d, %d, %d, %d\n", sx, sy, SCR_FIELDX, SCR_FIELDY);
929 for (x = 0; x < scr_fieldx; x++)
930 for (y = 0 ; y < scr_fieldy; y++)
931 if (redraw[redraw_x1 + x][redraw_y1 + y])
932 BlitBitmap(buffer, window,
933 FX + x * TILEX_VAR, FY + y * TILEY_VAR,
934 TILEX_VAR, TILEY_VAR,
935 sx + x * TILEX_VAR, sy + y * TILEY_VAR);
938 InitGfxClipRegion(FALSE, -1, -1, -1, -1);
940 for (x = 0; x < SCR_FIELDX; x++)
941 for (y = 0 ; y < SCR_FIELDY; y++)
942 if (redraw[redraw_x1 + x][redraw_y1 + y])
943 BlitBitmap(buffer, window,
944 FX + x * TILEX_VAR, FY + y * TILEY_VAR,
945 TILEX_VAR, TILEY_VAR,
946 SX + x * TILEX_VAR, SY + y * TILEY_VAR);
950 for (x = 0; x < SCR_FIELDX; x++)
951 for (y = 0 ; y < SCR_FIELDY; y++)
952 if (redraw[redraw_x1 + x][redraw_y1 + y])
953 BlitBitmap(buffer, window,
954 FX + x * TILEX, FY + y * TILEY, TILEX, TILEY,
955 SX + x * TILEX, SY + y * TILEY);
959 if (redraw_mask & REDRAW_FPS) /* display frames per second */
964 sprintf(info1, " (only every %d. frame)", global.fps_slowdown_factor);
965 if (!global.fps_slowdown)
968 sprintf(text, "%04.1f fps%s", global.frames_per_second, info1);
970 DrawTextExt(window, SX + SXSIZE + SX, 0, text, FONT_TEXT_2, BLIT_OPAQUE);
972 DrawTextExt(window, SX, SY, text, FONT_TEXT_2, BLIT_OPAQUE);
978 for (x = 0; x < MAX_BUF_XSIZE; x++)
979 for (y = 0; y < MAX_BUF_YSIZE; y++)
982 redraw_mask = REDRAW_NONE;
985 static void FadeCrossSaveBackbuffer()
987 BlitBitmap(backbuffer, bitmap_db_cross, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
990 static void FadeExt(int fade_mask, int fade_mode, int fade_type)
992 static int fade_type_skip = FADE_TYPE_NONE;
993 void (*draw_border_function)(void) = NULL;
994 Bitmap *bitmap = (fade_mode & FADE_TYPE_TRANSFORM ? bitmap_db_cross : NULL);
995 int x, y, width, height;
996 int fade_delay, post_delay;
998 if (fade_type == FADE_TYPE_FADE_OUT)
1000 if (fade_type_skip != FADE_TYPE_NONE)
1003 printf("::: skipping %d ... [%d] (X)\n", fade_mode, fade_type_skip);
1006 /* skip all fade operations until specified fade operation */
1007 if (fade_type & fade_type_skip)
1008 fade_type_skip = FADE_TYPE_NONE;
1013 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
1015 FadeCrossSaveBackbuffer();
1021 redraw_mask |= fade_mask;
1023 if (fade_type == FADE_TYPE_SKIP)
1026 printf("::: will skip %d ... [%d]\n", fade_mode, fade_type_skip);
1029 fade_type_skip = fade_mode;
1035 printf("::: !!! FADING %d ... [%d] [%d]\n", fade_mode, fade_type,
1040 fade_delay = fading.fade_delay;
1041 post_delay = (fade_mode == FADE_MODE_FADE_OUT ? fading.post_delay : 0);
1044 if (fade_type_skip != FADE_TYPE_NONE)
1047 printf("::: skipping %d ... [%d]\n", fade_mode, fade_type_skip);
1050 /* skip all fade operations until specified fade operation */
1051 if (fade_type & fade_type_skip)
1052 fade_type_skip = FADE_TYPE_NONE;
1062 if (global.autoplay_leveldir)
1064 // fading.fade_mode = FADE_MODE_NONE;
1071 if (fading.fade_mode == FADE_MODE_NONE)
1079 /* !!! what about fade_mask == REDRAW_FIELD | REDRAW_ALL ??? !!! */
1082 printf("::: NOW FADING %d ... [%d]\n", fade_mode, fade_type);
1086 if (fade_mask == REDRAW_NONE)
1087 fade_mask = REDRAW_FIELD;
1090 // if (fade_mask & REDRAW_FIELD)
1091 if (fade_mask == REDRAW_FIELD)
1095 width = FULL_SXSIZE;
1096 height = FULL_SYSIZE;
1099 fade_delay = fading.fade_delay;
1100 post_delay = (fade_mode == FADE_MODE_FADE_OUT ? fading.post_delay : 0);
1103 if (border.draw_masked_when_fading)
1104 draw_border_function = DrawMaskedBorder_FIELD; /* update when fading */
1106 DrawMaskedBorder_FIELD(); /* draw once */
1108 else /* REDRAW_ALL */
1116 fade_delay = fading.fade_delay;
1117 post_delay = (fade_mode == FADE_MODE_FADE_OUT ? fading.post_delay : 0);
1122 if (!setup.fade_screens ||
1124 fading.fade_mode == FADE_MODE_NONE)
1126 if (!setup.fade_screens || fade_delay == 0)
1129 if (fade_mode == FADE_MODE_FADE_OUT)
1133 if (fade_mode == FADE_MODE_FADE_OUT &&
1134 fading.fade_mode != FADE_MODE_NONE)
1135 ClearRectangle(backbuffer, x, y, width, height);
1141 BlitBitmap(backbuffer, window, x, y, width, height, x, y);
1143 redraw_mask &= ~fade_mask;
1145 /* always redraw area that was explicitly marked to fade */
1146 redraw_mask |= fade_mask;
1154 BlitBitmap(backbuffer, window, x, y, width, height, x, y);
1155 redraw_mask = REDRAW_NONE;
1156 // (^^^ WRONG; should be "redraw_mask &= ~fade_mask" if done this way)
1165 FadeRectangle(bitmap, x, y, width, height, fade_mode, fade_delay, post_delay,
1166 draw_border_function);
1168 redraw_mask &= ~fade_mask;
1171 void FadeIn(int fade_mask)
1173 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
1174 FadeExt(fade_mask, fading.fade_mode, FADE_TYPE_FADE_IN);
1176 FadeExt(fade_mask, FADE_MODE_FADE_IN, FADE_TYPE_FADE_IN);
1179 void FadeOut(int fade_mask)
1181 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
1182 FadeExt(fade_mask, fading.fade_mode, FADE_TYPE_FADE_OUT);
1184 FadeExt(fade_mask, FADE_MODE_FADE_OUT, FADE_TYPE_FADE_OUT);
1186 global.border_status = game_status;
1189 static void FadeSetLeaveNext(struct TitleFadingInfo fading_leave, boolean set)
1191 static struct TitleFadingInfo fading_leave_stored;
1194 fading_leave_stored = fading_leave;
1196 fading = fading_leave_stored;
1199 void FadeSetEnterMenu()
1201 fading = menu.enter_menu;
1204 printf("::: storing enter_menu\n");
1207 FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
1210 void FadeSetLeaveMenu()
1212 fading = menu.leave_menu;
1215 printf("::: storing leave_menu\n");
1218 FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
1221 void FadeSetEnterScreen()
1223 fading = menu.enter_screen[game_status];
1226 printf("::: storing leave_screen[%d]\n", game_status);
1229 FadeSetLeaveNext(menu.leave_screen[game_status], TRUE); /* store */
1232 void FadeSetNextScreen()
1234 fading = menu.next_screen;
1237 printf("::: storing next_screen\n");
1240 // (do not overwrite fade mode set by FadeSetEnterScreen)
1241 // FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
1244 void FadeSetLeaveScreen()
1247 printf("::: recalling last stored value\n");
1250 FadeSetLeaveNext(menu.leave_screen[game_status], FALSE); /* recall */
1253 void FadeSetFromType(int type)
1255 if (type & TYPE_ENTER_SCREEN)
1256 FadeSetEnterScreen();
1257 else if (type & TYPE_ENTER)
1259 else if (type & TYPE_LEAVE)
1263 void FadeSetDisabled()
1265 static struct TitleFadingInfo fading_none = { FADE_MODE_NONE, -1, -1, -1 };
1267 fading = fading_none;
1270 void FadeSkipNextFadeIn()
1272 FadeExt(0, FADE_MODE_SKIP_FADE_IN, FADE_TYPE_SKIP);
1275 void FadeSkipNextFadeOut()
1277 FadeExt(0, FADE_MODE_SKIP_FADE_OUT, FADE_TYPE_SKIP);
1280 void SetWindowBackgroundImageIfDefined(int graphic)
1282 if (graphic_info[graphic].bitmap)
1283 SetWindowBackgroundBitmap(graphic_info[graphic].bitmap);
1286 void SetMainBackgroundImageIfDefined(int graphic)
1288 if (graphic_info[graphic].bitmap)
1289 SetMainBackgroundBitmap(graphic_info[graphic].bitmap);
1292 void SetDoorBackgroundImageIfDefined(int graphic)
1294 if (graphic_info[graphic].bitmap)
1295 SetDoorBackgroundBitmap(graphic_info[graphic].bitmap);
1298 void SetWindowBackgroundImage(int graphic)
1300 SetWindowBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
1301 graphic_info[graphic].bitmap ?
1302 graphic_info[graphic].bitmap :
1303 graphic_info[IMG_BACKGROUND].bitmap);
1306 void SetMainBackgroundImage(int graphic)
1308 SetMainBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
1309 graphic_info[graphic].bitmap ?
1310 graphic_info[graphic].bitmap :
1311 graphic_info[IMG_BACKGROUND].bitmap);
1314 void SetDoorBackgroundImage(int graphic)
1316 SetDoorBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
1317 graphic_info[graphic].bitmap ?
1318 graphic_info[graphic].bitmap :
1319 graphic_info[IMG_BACKGROUND].bitmap);
1322 void SetPanelBackground()
1325 struct GraphicInfo *gfx = &graphic_info[IMG_BACKGROUND_PANEL];
1328 BlitBitmapTiled(gfx->bitmap, bitmap_db_panel, gfx->src_x, gfx->src_y,
1329 gfx->width, gfx->height, 0, 0, DXSIZE, DYSIZE);
1331 /* (ClearRectangle() only needed if panel bitmap is smaller than panel) */
1332 ClearRectangle(bitmap_db_panel, DX, DY, DXSIZE, DYSIZE);
1333 BlitBitmap(gfx->bitmap, bitmap_db_panel, gfx->src_x, gfx->src_y,
1334 MIN(gfx->width, DXSIZE), MIN(gfx->height, DYSIZE), 0, 0);
1337 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, bitmap_db_panel,
1338 DOOR_GFX_PAGEX5, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE, 0, 0);
1341 SetDoorBackgroundBitmap(bitmap_db_panel);
1344 void DrawBackground(int x, int y, int width, int height)
1346 /* !!! "drawto" might still point to playfield buffer here (see below) !!! */
1347 /* (when entering hall of fame after playing) */
1349 ClearRectangleOnBackground(drawto, x, y, width, height);
1351 ClearRectangleOnBackground(backbuffer, x, y, width, height);
1357 if (IN_GFX_FIELD_FULL(x, y))
1358 redraw_mask |= REDRAW_FIELD;
1359 else if (IN_GFX_DOOR_1(x, y))
1360 redraw_mask |= REDRAW_DOOR_1;
1361 else if (IN_GFX_DOOR_2(x, y))
1362 redraw_mask |= REDRAW_DOOR_2;
1363 else if (IN_GFX_DOOR_3(x, y))
1364 redraw_mask |= REDRAW_DOOR_3;
1366 /* (this only works for the current arrangement of playfield and panels) */
1368 redraw_mask |= REDRAW_FIELD;
1369 else if (y < gfx.vy)
1370 redraw_mask |= REDRAW_DOOR_1;
1372 redraw_mask |= REDRAW_DOOR_2;
1376 /* (this is just wrong (when drawing to one of the two door panel areas)) */
1377 redraw_mask |= REDRAW_FIELD;
1381 void DrawBackgroundForFont(int x, int y, int width, int height, int font_nr)
1383 struct FontBitmapInfo *font = getFontBitmapInfo(font_nr);
1385 if (font->bitmap == NULL)
1388 DrawBackground(x, y, width, height);
1391 void DrawBackgroundForGraphic(int x, int y, int width, int height, int graphic)
1393 struct GraphicInfo *g = &graphic_info[graphic];
1395 if (g->bitmap == NULL)
1398 DrawBackground(x, y, width, height);
1403 /* !!! "drawto" might still point to playfield buffer here (see above) !!! */
1404 /* (when entering hall of fame after playing) */
1405 DrawBackground(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
1407 /* !!! maybe this should be done before clearing the background !!! */
1408 if (setup.soft_scrolling && game_status == GAME_MODE_PLAYING)
1410 ClearRectangle(fieldbuffer, 0, 0, FXSIZE, FYSIZE);
1411 SetDrawtoField(DRAW_BUFFERED);
1414 SetDrawtoField(DRAW_BACKBUFFER);
1417 void MarkTileDirty(int x, int y)
1419 int xx = redraw_x1 + x;
1420 int yy = redraw_y1 + y;
1422 if (!redraw[xx][yy])
1425 redraw[xx][yy] = TRUE;
1426 redraw_mask |= REDRAW_TILES;
1429 void SetBorderElement()
1433 BorderElement = EL_EMPTY;
1435 for (y = 0; y < lev_fieldy && BorderElement == EL_EMPTY; y++)
1437 for (x = 0; x < lev_fieldx; x++)
1439 if (!IS_INDESTRUCTIBLE(Feld[x][y]))
1440 BorderElement = EL_STEELWALL;
1442 if (y != 0 && y != lev_fieldy - 1 && x != lev_fieldx - 1)
1448 void FloodFillLevel(int from_x, int from_y, int fill_element,
1449 short field[MAX_LEV_FIELDX][MAX_LEV_FIELDY],
1450 int max_fieldx, int max_fieldy)
1454 static int check[4][2] = { { -1, 0 }, { 0, -1 }, { 1, 0 }, { 0, 1 } };
1455 static int safety = 0;
1457 /* check if starting field still has the desired content */
1458 if (field[from_x][from_y] == fill_element)
1463 if (safety > max_fieldx * max_fieldy)
1464 Error(ERR_EXIT, "Something went wrong in 'FloodFill()'. Please debug.");
1466 old_element = field[from_x][from_y];
1467 field[from_x][from_y] = fill_element;
1469 for (i = 0; i < 4; i++)
1471 x = from_x + check[i][0];
1472 y = from_y + check[i][1];
1474 if (IN_FIELD(x, y, max_fieldx, max_fieldy) && field[x][y] == old_element)
1475 FloodFillLevel(x, y, fill_element, field, max_fieldx, max_fieldy);
1481 void SetRandomAnimationValue(int x, int y)
1483 gfx.anim_random_frame = GfxRandom[x][y];
1486 inline int getGraphicAnimationFrame(int graphic, int sync_frame)
1488 /* animation synchronized with global frame counter, not move position */
1489 if (graphic_info[graphic].anim_global_sync || sync_frame < 0)
1490 sync_frame = FrameCounter;
1492 return getAnimationFrame(graphic_info[graphic].anim_frames,
1493 graphic_info[graphic].anim_delay,
1494 graphic_info[graphic].anim_mode,
1495 graphic_info[graphic].anim_start_frame,
1499 void getSizedGraphicSourceExt(int graphic, int frame, int tilesize_raw,
1500 Bitmap **bitmap, int *x, int *y,
1501 boolean get_backside)
1505 int width_mult, width_div;
1506 int height_mult, height_div;
1510 { 15, 16, 2, 3 }, /* 1 x 1 */
1511 { 7, 8, 2, 3 }, /* 2 x 2 */
1512 { 3, 4, 2, 3 }, /* 4 x 4 */
1513 { 1, 2, 2, 3 }, /* 8 x 8 */
1514 { 0, 1, 2, 3 }, /* 16 x 16 */
1515 { 0, 1, 0, 1 }, /* 32 x 32 */
1517 struct GraphicInfo *g = &graphic_info[graphic];
1518 Bitmap *src_bitmap = g->bitmap;
1519 int tilesize = MIN(MAX(1, tilesize_raw), TILESIZE);
1520 int offset_calc_pos = log_2(tilesize);
1521 int bitmap_width = src_bitmap->width;
1522 int bitmap_height = src_bitmap->height;
1523 int width_mult = offset_calc[offset_calc_pos].width_mult;
1524 int width_div = offset_calc[offset_calc_pos].width_div;
1525 int height_mult = offset_calc[offset_calc_pos].height_mult;
1526 int height_div = offset_calc[offset_calc_pos].height_div;
1527 int startx = bitmap_width * width_mult / width_div;
1528 int starty = bitmap_height * height_mult / height_div;
1530 #if NEW_GAME_TILESIZE
1532 int src_x = (g->src_x + (get_backside ? g->offset2_x : 0)) *
1533 tilesize_raw / TILESIZE;
1534 int src_y = (g->src_y + (get_backside ? g->offset2_y : 0)) *
1535 tilesize_raw / TILESIZE;
1536 int width = g->width * tilesize_raw / TILESIZE;
1537 int height = g->height * tilesize_raw / TILESIZE;
1538 int offset_x = g->offset_x * tilesize_raw / TILESIZE;
1539 int offset_y = g->offset_y * tilesize_raw / TILESIZE;
1544 int src_x = (g->src_x + (get_backside ? g->offset2_x : 0)) *
1545 tilesize / TILESIZE;
1546 int src_y = (g->src_y + (get_backside ? g->offset2_y : 0)) *
1547 tilesize / TILESIZE;
1549 int src_x = g->src_x * tilesize / TILESIZE;
1550 int src_y = g->src_y * tilesize / TILESIZE;
1552 int width = g->width * tilesize / TILESIZE;
1553 int height = g->height * tilesize / TILESIZE;
1554 int offset_x = g->offset_x * tilesize / TILESIZE;
1555 int offset_y = g->offset_y * tilesize / TILESIZE;
1559 #if NEW_GAME_TILESIZE
1560 if (game.tile_size != TILESIZE)
1562 int bitmap_width_std =
1563 bitmap_width * TILESIZE / (TILESIZE + game.tile_size);
1564 int bitmap_height_std =
1565 bitmap_height * TILESIZE / game.tile_size * 3 / 2;
1567 if (tilesize_raw == game.tile_size)
1569 startx = bitmap_width_std;
1574 bitmap_width = bitmap_width_std;
1576 if (game.tile_size > TILESIZE * 3 / 2)
1577 bitmap_height = bitmap_height_std;
1579 startx = bitmap_width * width_mult / width_div;
1580 starty = bitmap_height * height_mult / height_div;
1585 if (g->offset_y == 0) /* frames are ordered horizontally */
1587 int max_width = g->anim_frames_per_line * width;
1588 int pos = (src_y / height) * max_width + src_x + frame * offset_x;
1590 src_x = pos % max_width;
1591 src_y = src_y % height + pos / max_width * height;
1593 else if (g->offset_x == 0) /* frames are ordered vertically */
1595 int max_height = g->anim_frames_per_line * height;
1596 int pos = (src_x / width) * max_height + src_y + frame * offset_y;
1598 src_x = src_x % width + pos / max_height * width;
1599 src_y = pos % max_height;
1601 else /* frames are ordered diagonally */
1603 src_x = src_x + frame * offset_x;
1604 src_y = src_y + frame * offset_y;
1607 *bitmap = src_bitmap;
1608 *x = startx + src_x;
1609 *y = starty + src_y;
1612 void getFixedGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
1613 int *x, int *y, boolean get_backside)
1615 getSizedGraphicSourceExt(graphic, frame, TILESIZE, bitmap, x, y,
1619 void getSizedGraphicSource(int graphic, int frame, int tilesize_raw,
1620 Bitmap **bitmap, int *x, int *y)
1622 getSizedGraphicSourceExt(graphic, frame, tilesize_raw, bitmap, x, y, FALSE);
1625 void getFixedGraphicSource(int graphic, int frame,
1626 Bitmap **bitmap, int *x, int *y)
1628 getSizedGraphicSourceExt(graphic, frame, TILESIZE, bitmap, x, y, FALSE);
1631 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
1634 getSizedGraphicSource(graphic, 0, MINI_TILESIZE, bitmap, x, y);
1636 struct GraphicInfo *g = &graphic_info[graphic];
1637 int mini_startx = 0;
1638 int mini_starty = g->bitmap->height * 2 / 3;
1640 *bitmap = g->bitmap;
1641 *x = mini_startx + g->src_x / 2;
1642 *y = mini_starty + g->src_y / 2;
1646 inline void getGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
1647 int *x, int *y, boolean get_backside)
1649 struct GraphicInfo *g = &graphic_info[graphic];
1650 int src_x = g->src_x + (get_backside ? g->offset2_x : 0);
1651 int src_y = g->src_y + (get_backside ? g->offset2_y : 0);
1654 if (TILESIZE_VAR != TILESIZE)
1655 return getSizedGraphicSourceExt(graphic, frame, TILESIZE_VAR, bitmap, x, y,
1659 *bitmap = g->bitmap;
1661 if (g->offset_y == 0) /* frames are ordered horizontally */
1663 int max_width = g->anim_frames_per_line * g->width;
1664 int pos = (src_y / g->height) * max_width + src_x + frame * g->offset_x;
1666 *x = pos % max_width;
1667 *y = src_y % g->height + pos / max_width * g->height;
1669 else if (g->offset_x == 0) /* frames are ordered vertically */
1671 int max_height = g->anim_frames_per_line * g->height;
1672 int pos = (src_x / g->width) * max_height + src_y + frame * g->offset_y;
1674 *x = src_x % g->width + pos / max_height * g->width;
1675 *y = pos % max_height;
1677 else /* frames are ordered diagonally */
1679 *x = src_x + frame * g->offset_x;
1680 *y = src_y + frame * g->offset_y;
1684 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
1686 getGraphicSourceExt(graphic, frame, bitmap, x, y, FALSE);
1689 void DrawGraphic(int x, int y, int graphic, int frame)
1692 if (!IN_SCR_FIELD(x, y))
1694 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
1695 printf("DrawGraphic(): This should never happen!\n");
1701 DrawGraphicExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR, graphic,
1704 DrawGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic, frame);
1706 MarkTileDirty(x, y);
1709 void DrawFixedGraphic(int x, int y, int graphic, int frame)
1712 if (!IN_SCR_FIELD(x, y))
1714 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
1715 printf("DrawGraphic(): This should never happen!\n");
1720 DrawFixedGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic,
1722 MarkTileDirty(x, y);
1725 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
1731 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1733 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX_VAR, TILEY_VAR, x, y);
1735 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
1739 void DrawFixedGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
1745 getFixedGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1746 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
1749 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
1752 if (!IN_SCR_FIELD(x, y))
1754 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
1755 printf("DrawGraphicThruMask(): This should never happen!\n");
1761 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR,
1764 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic,
1767 MarkTileDirty(x, y);
1770 void DrawFixedGraphicThruMask(int x, int y, int graphic, int frame)
1773 if (!IN_SCR_FIELD(x, y))
1775 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
1776 printf("DrawGraphicThruMask(): This should never happen!\n");
1781 DrawFixedGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
1783 MarkTileDirty(x, y);
1786 void DrawGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y, int graphic,
1792 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1794 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1795 dst_x - src_x, dst_y - src_y);
1797 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX_VAR, TILEY_VAR,
1800 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dst_x, dst_y);
1804 void DrawFixedGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y,
1805 int graphic, int frame)
1810 getFixedGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1812 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1813 dst_x - src_x, dst_y - src_y);
1814 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dst_x, dst_y);
1817 void DrawSizedGraphic(int x, int y, int graphic, int frame, int tilesize)
1819 DrawSizedGraphicExt(drawto, SX + x * tilesize, SY + y * tilesize, graphic,
1821 MarkTileDirty(x / tilesize, y / tilesize);
1824 void DrawSizedGraphicExt(DrawBuffer *d, int x, int y, int graphic, int frame,
1830 getSizedGraphicSource(graphic, frame, tilesize, &src_bitmap, &src_x, &src_y);
1831 BlitBitmap(src_bitmap, d, src_x, src_y, tilesize, tilesize, x, y);
1834 void DrawMiniGraphic(int x, int y, int graphic)
1836 DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
1837 MarkTileDirty(x / 2, y / 2);
1840 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
1845 getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1846 BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
1849 inline static void DrawGraphicShiftedNormal(int x, int y, int dx, int dy,
1850 int graphic, int frame,
1851 int cut_mode, int mask_mode)
1856 int width = TILEX, height = TILEY;
1859 if (dx || dy) /* shifted graphic */
1861 if (x < BX1) /* object enters playfield from the left */
1868 else if (x > BX2) /* object enters playfield from the right */
1874 else if (x==BX1 && dx < 0) /* object leaves playfield to the left */
1880 else if (x==BX2 && dx > 0) /* object leaves playfield to the right */
1882 else if (dx) /* general horizontal movement */
1883 MarkTileDirty(x + SIGN(dx), y);
1885 if (y < BY1) /* object enters playfield from the top */
1887 if (cut_mode==CUT_BELOW) /* object completely above top border */
1895 else if (y > BY2) /* object enters playfield from the bottom */
1901 else if (y==BY1 && dy < 0) /* object leaves playfield to the top */
1907 else if (dy > 0 && cut_mode == CUT_ABOVE)
1909 if (y == BY2) /* object completely above bottom border */
1915 MarkTileDirty(x, y + 1);
1916 } /* object leaves playfield to the bottom */
1917 else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
1919 else if (dy) /* general vertical movement */
1920 MarkTileDirty(x, y + SIGN(dy));
1924 if (!IN_SCR_FIELD(x, y))
1926 printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
1927 printf("DrawGraphicShifted(): This should never happen!\n");
1933 width = width * TILESIZE_VAR / TILESIZE;
1934 height = height * TILESIZE_VAR / TILESIZE;
1935 cx = cx * TILESIZE_VAR / TILESIZE;
1936 cy = cy * TILESIZE_VAR / TILESIZE;
1937 dx = dx * TILESIZE_VAR / TILESIZE;
1938 dy = dy * TILESIZE_VAR / TILESIZE;
1941 if (width > 0 && height > 0)
1943 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1949 dst_x = FX + x * TILEX_VAR + dx;
1950 dst_y = FY + y * TILEY_VAR + dy;
1952 dst_x = FX + x * TILEX + dx;
1953 dst_y = FY + y * TILEY + dy;
1956 if (mask_mode == USE_MASKING)
1958 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1959 dst_x - src_x, dst_y - src_y);
1960 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1964 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1967 MarkTileDirty(x, y);
1971 inline static void DrawGraphicShiftedDouble(int x, int y, int dx, int dy,
1972 int graphic, int frame,
1973 int cut_mode, int mask_mode)
1979 int width = TILEX_VAR, height = TILEY_VAR;
1981 int width = TILEX, height = TILEY;
1985 int x2 = x + SIGN(dx);
1986 int y2 = y + SIGN(dy);
1988 /* !!! DOES NOT WORK FOR SLOW MOVEMENT !!! */
1989 int sync_frame = GfxFrame[LEVELX(x)][LEVELY(y)];
1991 /* movement with two-tile animations must be sync'ed with movement position,
1992 not with current GfxFrame (which can be higher when using slow movement) */
1993 int anim_pos = (dx ? ABS(dx) : ABS(dy));
1994 int anim_frames = graphic_info[graphic].anim_frames;
1996 /* (we also need anim_delay here for movement animations with less frames) */
1997 int anim_delay = graphic_info[graphic].anim_delay;
1998 int sync_frame = anim_pos * anim_frames * anim_delay / TILESIZE;
2000 int sync_frame = anim_pos * anim_frames / TILESIZE;
2003 boolean draw_start_tile = (cut_mode != CUT_ABOVE); /* only for falling! */
2004 boolean draw_end_tile = (cut_mode != CUT_BELOW); /* only for falling! */
2006 /* re-calculate animation frame for two-tile movement animation */
2007 frame = getGraphicAnimationFrame(graphic, sync_frame);
2011 printf("::: %d, %d, %d => %d [%d]\n",
2012 anim_pos, anim_frames, anim_delay, sync_frame, graphic);
2014 printf("::: %d, %d => %d\n",
2015 anim_pos, anim_frames, sync_frame);
2020 printf("::: %d [%d, %d] [%d] [%d]\n", frame, sync_frame, dy,
2021 GfxFrame[LEVELX(x)][LEVELY(y)], mask_mode);
2024 /* check if movement start graphic inside screen area and should be drawn */
2025 if (draw_start_tile && IN_SCR_FIELD(x1, y1))
2027 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, TRUE);
2030 dst_x = FX + x1 * TILEX_VAR;
2031 dst_y = FY + y1 * TILEY_VAR;
2033 dst_x = FX + x1 * TILEX;
2034 dst_y = FY + y1 * TILEY;
2037 if (mask_mode == USE_MASKING)
2039 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
2040 dst_x - src_x, dst_y - src_y);
2041 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
2045 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
2048 MarkTileDirty(x1, y1);
2051 /* check if movement end graphic inside screen area and should be drawn */
2052 if (draw_end_tile && IN_SCR_FIELD(x2, y2))
2054 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
2057 dst_x = FX + x2 * TILEX_VAR;
2058 dst_y = FY + y2 * TILEY_VAR;
2060 dst_x = FX + x2 * TILEX;
2061 dst_y = FY + y2 * TILEY;
2064 if (mask_mode == USE_MASKING)
2066 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
2067 dst_x - src_x, dst_y - src_y);
2068 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
2072 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
2075 MarkTileDirty(x2, y2);
2079 static void DrawGraphicShifted(int x, int y, int dx, int dy,
2080 int graphic, int frame,
2081 int cut_mode, int mask_mode)
2085 DrawGraphic(x, y, graphic, frame);
2090 if (graphic_info[graphic].double_movement) /* EM style movement images */
2091 DrawGraphicShiftedDouble(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
2093 DrawGraphicShiftedNormal(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
2096 void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
2097 int frame, int cut_mode)
2099 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, USE_MASKING);
2102 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
2103 int cut_mode, int mask_mode)
2105 int lx = LEVELX(x), ly = LEVELY(y);
2109 if (IN_LEV_FIELD(lx, ly))
2111 SetRandomAnimationValue(lx, ly);
2113 graphic = el_act_dir2img(element, GfxAction[lx][ly], GfxDir[lx][ly]);
2114 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
2116 /* do not use double (EM style) movement graphic when not moving */
2117 if (graphic_info[graphic].double_movement && !dx && !dy)
2119 graphic = el_act_dir2img(element, ACTION_DEFAULT, GfxDir[lx][ly]);
2120 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
2123 else /* border element */
2125 graphic = el2img(element);
2126 frame = getGraphicAnimationFrame(graphic, -1);
2129 if (element == EL_EXPANDABLE_WALL)
2131 boolean left_stopped = FALSE, right_stopped = FALSE;
2133 if (!IN_LEV_FIELD(lx - 1, ly) || IS_WALL(Feld[lx - 1][ly]))
2134 left_stopped = TRUE;
2135 if (!IN_LEV_FIELD(lx + 1, ly) || IS_WALL(Feld[lx + 1][ly]))
2136 right_stopped = TRUE;
2138 if (left_stopped && right_stopped)
2140 else if (left_stopped)
2142 graphic = IMG_EXPANDABLE_WALL_GROWING_RIGHT;
2143 frame = graphic_info[graphic].anim_frames - 1;
2145 else if (right_stopped)
2147 graphic = IMG_EXPANDABLE_WALL_GROWING_LEFT;
2148 frame = graphic_info[graphic].anim_frames - 1;
2153 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
2154 else if (mask_mode == USE_MASKING)
2155 DrawGraphicThruMask(x, y, graphic, frame);
2157 DrawGraphic(x, y, graphic, frame);
2160 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
2161 int cut_mode, int mask_mode)
2163 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
2164 DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
2165 cut_mode, mask_mode);
2168 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
2171 DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
2174 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
2177 DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
2180 void DrawLevelElementThruMask(int x, int y, int element)
2182 DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
2185 void DrawLevelFieldThruMask(int x, int y)
2187 DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
2190 /* !!! implementation of quicksand is totally broken !!! */
2191 #define IS_CRUMBLED_TILE(x, y, e) \
2192 (GFX_CRUMBLED(e) && (!IN_LEV_FIELD(x, y) || \
2193 !IS_MOVING(x, y) || \
2194 (e) == EL_QUICKSAND_EMPTYING || \
2195 (e) == EL_QUICKSAND_FAST_EMPTYING))
2197 static void DrawLevelFieldCrumbledInnerCorners(int x, int y, int dx, int dy,
2202 int width, height, cx, cy;
2203 int sx = SCREENX(x), sy = SCREENY(y);
2204 int crumbled_border_size = graphic_info[graphic].border_size;
2207 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
2209 for (i = 1; i < 4; i++)
2211 int dxx = (i & 1 ? dx : 0);
2212 int dyy = (i & 2 ? dy : 0);
2215 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
2218 /* check if neighbour field is of same crumble type */
2219 boolean same = (IS_CRUMBLED_TILE(xx, yy, element) &&
2220 graphic_info[graphic].class ==
2221 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class);
2223 /* return if check prevents inner corner */
2224 if (same == (dxx == dx && dyy == dy))
2228 /* if we reach this point, we have an inner corner */
2230 getGraphicSource(graphic, 1, &src_bitmap, &src_x, &src_y);
2233 width = crumbled_border_size * TILESIZE_VAR / TILESIZE;
2234 height = crumbled_border_size * TILESIZE_VAR / TILESIZE;
2235 cx = (dx > 0 ? TILESIZE_VAR - width : 0);
2236 cy = (dy > 0 ? TILESIZE_VAR - height : 0);
2238 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
2239 width, height, FX + sx * TILEX_VAR + cx, FY + sy * TILEY_VAR + cy);
2241 width = crumbled_border_size;
2242 height = crumbled_border_size;
2243 cx = (dx > 0 ? TILEX - crumbled_border_size : 0);
2244 cy = (dy > 0 ? TILEY - crumbled_border_size : 0);
2246 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
2247 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
2251 static void DrawLevelFieldCrumbledBorders(int x, int y, int graphic, int frame,
2256 int width, height, bx, by, cx, cy;
2257 int sx = SCREENX(x), sy = SCREENY(y);
2258 int crumbled_border_size = graphic_info[graphic].border_size;
2259 int crumbled_border_size_var = crumbled_border_size * TILESIZE_VAR / TILESIZE;
2260 int crumbled_border_pos_var = TILESIZE_VAR - crumbled_border_size_var;
2263 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
2265 /* draw simple, sloppy, non-corner-accurate crumbled border */
2268 width = (dir == 1 || dir == 2 ? crumbled_border_size_var : TILESIZE_VAR);
2269 height = (dir == 0 || dir == 3 ? crumbled_border_size_var : TILESIZE_VAR);
2270 cx = (dir == 2 ? crumbled_border_pos_var : 0);
2271 cy = (dir == 3 ? crumbled_border_pos_var : 0);
2273 if (dir == 1 || dir == 2) /* left or right crumbled border */
2275 width = crumbled_border_size;
2277 cx = (dir == 2 ? TILEX - crumbled_border_size : 0);
2280 else /* top or bottom crumbled border */
2283 height = crumbled_border_size;
2285 cy = (dir == 3 ? TILEY - crumbled_border_size : 0);
2290 BlitBitmap(src_bitmap, drawto_field,
2295 FX + sx * TILEX_VAR + cx,
2296 FY + sy * TILEY_VAR + cy);
2298 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
2299 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
2302 /* (remaining middle border part must be at least as big as corner part) */
2303 if (!(graphic_info[graphic].style & STYLE_ACCURATE_BORDERS) ||
2304 crumbled_border_size >= TILESIZE / 3)
2307 /* correct corners of crumbled border, if needed */
2310 for (i = -1; i <= 1; i += 2)
2312 int xx = x + (dir == 0 || dir == 3 ? i : 0);
2313 int yy = y + (dir == 1 || dir == 2 ? i : 0);
2314 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
2317 /* check if neighbour field is of same crumble type */
2318 if (IS_CRUMBLED_TILE(xx, yy, element) &&
2319 graphic_info[graphic].class ==
2320 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
2322 /* no crumbled corner, but continued crumbled border */
2324 int c1 = (dir == 2 || dir == 3 ? crumbled_border_pos_var : 0);
2325 int c2 = (i == 1 ? crumbled_border_pos_var : 0);
2326 int b1 = (i == 1 ? crumbled_border_size_var :
2327 TILESIZE_VAR - 2 * crumbled_border_size_var);
2329 width = crumbled_border_size_var;
2330 height = crumbled_border_size_var;
2332 if (dir == 1 || dir == 2)
2348 BlitBitmap(src_bitmap, drawto_field,
2353 FX + sx * TILEX_VAR + cx,
2354 FY + sy * TILEY_VAR + cy);
2356 BlitBitmap(src_bitmap, drawto_field, src_x + bx, src_y + by,
2357 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
2362 if (dir == 1 || dir == 2) /* left or right crumbled border */
2364 for (i = -1; i <= 1; i+=2)
2368 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
2371 /* check if neighbour field is of same crumble type */
2372 if (IS_CRUMBLED_TILE(xx, yy, element) &&
2373 graphic_info[graphic].class ==
2374 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
2376 /* no crumbled corner, but continued crumbled border */
2378 width = crumbled_border_size;
2379 height = crumbled_border_size;
2380 cx = (dir == 2 ? TILEX - crumbled_border_size : 0);
2381 cy = (i == 1 ? TILEY - crumbled_border_size : 0);
2383 by = (i == 1 ? crumbled_border_size :
2384 TILEY - 2 * crumbled_border_size);
2386 BlitBitmap(src_bitmap, drawto_field, src_x + bx, src_y + by,
2387 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
2391 else /* top or bottom crumbled border */
2393 for (i = -1; i <= 1; i+=2)
2397 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
2400 /* check if neighbour field is of same crumble type */
2401 if (IS_CRUMBLED_TILE(xx, yy, element) &&
2402 graphic_info[graphic].class ==
2403 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
2405 /* no crumbled corner, but continued crumbled border */
2407 width = crumbled_border_size;
2408 height = crumbled_border_size;
2409 cx = (i == 1 ? TILEX - crumbled_border_size : 0);
2410 cy = (dir == 3 ? TILEY - crumbled_border_size : 0);
2411 bx = (i == 1 ? crumbled_border_size :
2412 TILEX - 2 * crumbled_border_size);
2415 BlitBitmap(src_bitmap, drawto_field, src_x + bx, src_y + by,
2416 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
2423 static void DrawLevelFieldCrumbledExt(int x, int y, int graphic, int frame)
2425 int sx = SCREENX(x), sy = SCREENY(y);
2428 static int xy[4][2] =
2436 if (!IN_LEV_FIELD(x, y))
2439 element = TILE_GFX_ELEMENT(x, y);
2441 /* crumble field itself */
2442 if (IS_CRUMBLED_TILE(x, y, element))
2444 if (!IN_SCR_FIELD(sx, sy))
2447 for (i = 0; i < 4; i++)
2449 int xx = x + xy[i][0];
2450 int yy = y + xy[i][1];
2452 element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
2455 /* check if neighbour field is of same crumble type */
2457 if (IS_CRUMBLED_TILE(xx, yy, element) &&
2458 graphic_info[graphic].class ==
2459 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
2462 if (IS_CRUMBLED_TILE(xx, yy, element))
2466 DrawLevelFieldCrumbledBorders(x, y, graphic, frame, i);
2469 if ((graphic_info[graphic].style & STYLE_INNER_CORNERS) &&
2470 graphic_info[graphic].anim_frames == 2)
2472 for (i = 0; i < 4; i++)
2474 int dx = (i & 1 ? +1 : -1);
2475 int dy = (i & 2 ? +1 : -1);
2477 DrawLevelFieldCrumbledInnerCorners(x, y, dx, dy, graphic);
2481 MarkTileDirty(sx, sy);
2483 else /* center field not crumbled -- crumble neighbour fields */
2485 for (i = 0; i < 4; i++)
2487 int xx = x + xy[i][0];
2488 int yy = y + xy[i][1];
2489 int sxx = sx + xy[i][0];
2490 int syy = sy + xy[i][1];
2492 if (!IN_LEV_FIELD(xx, yy) ||
2493 !IN_SCR_FIELD(sxx, syy))
2496 if (Feld[xx][yy] == EL_ELEMENT_SNAPPING)
2499 element = TILE_GFX_ELEMENT(xx, yy);
2501 if (!IS_CRUMBLED_TILE(xx, yy, element))
2504 graphic = el_act2crm(element, ACTION_DEFAULT);
2506 DrawLevelFieldCrumbledBorders(xx, yy, graphic, 0, 3 - i);
2508 MarkTileDirty(sxx, syy);
2513 void DrawLevelFieldCrumbled(int x, int y)
2517 if (!IN_LEV_FIELD(x, y))
2521 /* !!! CHECK THIS !!! */
2524 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
2525 GFX_CRUMBLED(GfxElement[x][y]))
2528 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
2529 GfxElement[x][y] != EL_UNDEFINED &&
2530 GFX_CRUMBLED(GfxElement[x][y]))
2532 DrawLevelFieldCrumbledDigging(x, y, GfxDir[x][y], GfxFrame[x][y]);
2539 graphic = el_act2crm(TILE_GFX_ELEMENT(x, y), ACTION_DEFAULT);
2541 graphic = el_act2crm(Feld[x][y], ACTION_DEFAULT);
2544 DrawLevelFieldCrumbledExt(x, y, graphic, 0);
2547 void DrawLevelFieldCrumbledDigging(int x, int y, int direction,
2550 int graphic1 = el_act_dir2img(GfxElement[x][y], ACTION_DIGGING, direction);
2551 int graphic2 = el_act_dir2crm(GfxElement[x][y], ACTION_DIGGING, direction);
2552 int frame1 = getGraphicAnimationFrame(graphic1, step_frame);
2553 int frame2 = getGraphicAnimationFrame(graphic2, step_frame);
2554 int sx = SCREENX(x), sy = SCREENY(y);
2556 DrawGraphic(sx, sy, graphic1, frame1);
2557 DrawLevelFieldCrumbledExt(x, y, graphic2, frame2);
2560 void DrawLevelFieldCrumbledNeighbours(int x, int y)
2562 int sx = SCREENX(x), sy = SCREENY(y);
2563 static int xy[4][2] =
2572 for (i = 0; i < 4; i++)
2574 int xx = x + xy[i][0];
2575 int yy = y + xy[i][1];
2576 int sxx = sx + xy[i][0];
2577 int syy = sy + xy[i][1];
2579 if (!IN_LEV_FIELD(xx, yy) ||
2580 !IN_SCR_FIELD(sxx, syy) ||
2581 !GFX_CRUMBLED(Feld[xx][yy]) ||
2585 DrawLevelField(xx, yy);
2589 static int getBorderElement(int x, int y)
2593 { EL_STEELWALL_TOPLEFT, EL_INVISIBLE_STEELWALL_TOPLEFT },
2594 { EL_STEELWALL_TOPRIGHT, EL_INVISIBLE_STEELWALL_TOPRIGHT },
2595 { EL_STEELWALL_BOTTOMLEFT, EL_INVISIBLE_STEELWALL_BOTTOMLEFT },
2596 { EL_STEELWALL_BOTTOMRIGHT, EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
2597 { EL_STEELWALL_VERTICAL, EL_INVISIBLE_STEELWALL_VERTICAL },
2598 { EL_STEELWALL_HORIZONTAL, EL_INVISIBLE_STEELWALL_HORIZONTAL },
2599 { EL_STEELWALL, EL_INVISIBLE_STEELWALL }
2601 int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
2602 int steel_position = (x == -1 && y == -1 ? 0 :
2603 x == lev_fieldx && y == -1 ? 1 :
2604 x == -1 && y == lev_fieldy ? 2 :
2605 x == lev_fieldx && y == lev_fieldy ? 3 :
2606 x == -1 || x == lev_fieldx ? 4 :
2607 y == -1 || y == lev_fieldy ? 5 : 6);
2609 return border[steel_position][steel_type];
2612 void DrawScreenElement(int x, int y, int element)
2614 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
2615 DrawLevelFieldCrumbled(LEVELX(x), LEVELY(y));
2618 void DrawLevelElement(int x, int y, int element)
2620 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
2621 DrawScreenElement(SCREENX(x), SCREENY(y), element);
2624 void DrawScreenField(int x, int y)
2626 int lx = LEVELX(x), ly = LEVELY(y);
2627 int element, content;
2629 if (!IN_LEV_FIELD(lx, ly))
2631 if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
2634 element = getBorderElement(lx, ly);
2636 DrawScreenElement(x, y, element);
2641 element = Feld[lx][ly];
2642 content = Store[lx][ly];
2644 if (IS_MOVING(lx, ly))
2646 int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
2647 boolean cut_mode = NO_CUTTING;
2649 if (element == EL_QUICKSAND_EMPTYING ||
2650 element == EL_QUICKSAND_FAST_EMPTYING ||
2651 element == EL_MAGIC_WALL_EMPTYING ||
2652 element == EL_BD_MAGIC_WALL_EMPTYING ||
2653 element == EL_DC_MAGIC_WALL_EMPTYING ||
2654 element == EL_AMOEBA_DROPPING)
2655 cut_mode = CUT_ABOVE;
2656 else if (element == EL_QUICKSAND_FILLING ||
2657 element == EL_QUICKSAND_FAST_FILLING ||
2658 element == EL_MAGIC_WALL_FILLING ||
2659 element == EL_BD_MAGIC_WALL_FILLING ||
2660 element == EL_DC_MAGIC_WALL_FILLING)
2661 cut_mode = CUT_BELOW;
2664 if (lx == 9 && ly == 1)
2665 printf("::: %s [%d] [%d, %d] [%d]\n",
2666 EL_NAME(TILE_GFX_ELEMENT(lx, ly)),
2667 el_act2crm(TILE_GFX_ELEMENT(lx, ly), ACTION_DEFAULT),
2668 element_info[EL_QUICKSAND_EMPTYING].graphic[ACTION_DEFAULT],
2669 element_info[EL_QUICKSAND_EMPTYING].crumbled[ACTION_DEFAULT],
2670 GFX_CRUMBLED(TILE_GFX_ELEMENT(lx, ly)));
2673 if (cut_mode == CUT_ABOVE)
2675 DrawScreenElement(x, y, element);
2677 DrawScreenElementShifted(x, y, 0, 0, element, NO_CUTTING);
2680 DrawScreenElement(x, y, EL_EMPTY);
2683 DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
2684 else if (cut_mode == NO_CUTTING)
2685 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
2688 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
2691 if (cut_mode == CUT_BELOW &&
2692 IN_LEV_FIELD(lx, ly + 1) && IN_SCR_FIELD(x, y + 1))
2693 DrawLevelElement(lx, ly + 1, element);
2697 if (content == EL_ACID)
2699 int dir = MovDir[lx][ly];
2700 int newlx = lx + (dir == MV_LEFT ? -1 : dir == MV_RIGHT ? +1 : 0);
2701 int newly = ly + (dir == MV_UP ? -1 : dir == MV_DOWN ? +1 : 0);
2703 DrawLevelElementThruMask(newlx, newly, EL_ACID);
2706 else if (IS_BLOCKED(lx, ly))
2711 boolean cut_mode = NO_CUTTING;
2712 int element_old, content_old;
2714 Blocked2Moving(lx, ly, &oldx, &oldy);
2717 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
2718 MovDir[oldx][oldy] == MV_RIGHT);
2720 element_old = Feld[oldx][oldy];
2721 content_old = Store[oldx][oldy];
2723 if (element_old == EL_QUICKSAND_EMPTYING ||
2724 element_old == EL_QUICKSAND_FAST_EMPTYING ||
2725 element_old == EL_MAGIC_WALL_EMPTYING ||
2726 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
2727 element_old == EL_DC_MAGIC_WALL_EMPTYING ||
2728 element_old == EL_AMOEBA_DROPPING)
2729 cut_mode = CUT_ABOVE;
2731 DrawScreenElement(x, y, EL_EMPTY);
2734 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
2736 else if (cut_mode == NO_CUTTING)
2737 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
2740 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
2743 else if (IS_DRAWABLE(element))
2744 DrawScreenElement(x, y, element);
2746 DrawScreenElement(x, y, EL_EMPTY);
2749 void DrawLevelField(int x, int y)
2751 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
2752 DrawScreenField(SCREENX(x), SCREENY(y));
2753 else if (IS_MOVING(x, y))
2757 Moving2Blocked(x, y, &newx, &newy);
2758 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
2759 DrawScreenField(SCREENX(newx), SCREENY(newy));
2761 else if (IS_BLOCKED(x, y))
2765 Blocked2Moving(x, y, &oldx, &oldy);
2766 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
2767 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
2771 void DrawMiniElement(int x, int y, int element)
2775 graphic = el2edimg(element);
2776 DrawMiniGraphic(x, y, graphic);
2779 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
2781 int x = sx + scroll_x, y = sy + scroll_y;
2783 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
2784 DrawMiniElement(sx, sy, EL_EMPTY);
2785 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
2786 DrawMiniElement(sx, sy, Feld[x][y]);
2788 DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
2791 void DrawEnvelopeBackgroundTiles(int graphic, int startx, int starty,
2792 int x, int y, int xsize, int ysize,
2793 int tile_width, int tile_height)
2797 int dst_x = startx + x * tile_width;
2798 int dst_y = starty + y * tile_height;
2799 int width = graphic_info[graphic].width;
2800 int height = graphic_info[graphic].height;
2801 int inner_width_raw = MAX(width - 2 * tile_width, tile_width);
2802 int inner_height_raw = MAX(height - 2 * tile_height, tile_height);
2803 int inner_width = inner_width_raw - (inner_width_raw % tile_width);
2804 int inner_height = inner_height_raw - (inner_height_raw % tile_height);
2805 int inner_sx = (width >= 3 * tile_width ? tile_width : 0);
2806 int inner_sy = (height >= 3 * tile_height ? tile_height : 0);
2807 boolean draw_masked = graphic_info[graphic].draw_masked;
2809 getFixedGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
2811 if (src_bitmap == NULL || width < tile_width || height < tile_height)
2813 ClearRectangle(drawto, dst_x, dst_y, tile_width, tile_height);
2817 src_x += (x == 0 ? 0 : x == xsize - 1 ? width - tile_width :
2818 inner_sx + (x - 1) * tile_width % inner_width);
2819 src_y += (y == 0 ? 0 : y == ysize - 1 ? height - tile_height :
2820 inner_sy + (y - 1) * tile_height % inner_height);
2824 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
2825 dst_x - src_x, dst_y - src_y);
2826 BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, tile_width, tile_height,
2830 BlitBitmap(src_bitmap, drawto, src_x, src_y, tile_width, tile_height,
2834 void DrawEnvelopeBackground(int graphic, int startx, int starty,
2835 int x, int y, int xsize, int ysize, int font_nr)
2837 int font_width = getFontWidth(font_nr);
2838 int font_height = getFontHeight(font_nr);
2840 DrawEnvelopeBackgroundTiles(graphic, startx, starty, x, y, xsize, ysize,
2841 font_width, font_height);
2844 void AnimateEnvelope(int envelope_nr, int anim_mode, int action)
2846 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2847 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
2848 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
2849 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2850 boolean no_delay = (tape.warp_forward);
2851 unsigned int anim_delay = 0;
2852 int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
2853 int anim_delay_value = (no_delay ? 0 : frame_delay_value);
2854 int font_nr = FONT_ENVELOPE_1 + envelope_nr;
2855 int font_width = getFontWidth(font_nr);
2856 int font_height = getFontHeight(font_nr);
2857 int max_xsize = level.envelope[envelope_nr].xsize;
2858 int max_ysize = level.envelope[envelope_nr].ysize;
2859 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
2860 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
2861 int xend = max_xsize;
2862 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
2863 int xstep = (xstart < xend ? 1 : 0);
2864 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
2867 for (x = xstart, y = ystart; x <= xend && y <= yend; x += xstep, y += ystep)
2869 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
2870 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
2871 int sx = SX + (SXSIZE - xsize * font_width) / 2;
2872 int sy = SY + (SYSIZE - ysize * font_height) / 2;
2875 SetDrawtoField(DRAW_BUFFERED);
2878 BlitScreenToBitmap(backbuffer);
2880 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
2883 SetDrawtoField(DRAW_BACKBUFFER);
2885 for (yy = 0; yy < ysize; yy++)
2886 for (xx = 0; xx < xsize; xx++)
2887 DrawEnvelopeBackground(graphic, sx, sy, xx, yy, xsize, ysize, font_nr);
2890 DrawTextBuffer(sx + font_width, sy + font_height,
2891 level.envelope[envelope_nr].text, font_nr, max_xsize,
2892 xsize - 2, ysize - 2, 0, mask_mode,
2893 level.envelope[envelope_nr].autowrap,
2894 level.envelope[envelope_nr].centered, FALSE);
2896 DrawTextToTextArea(sx + font_width, sy + font_height,
2897 level.envelope[envelope_nr].text, font_nr, max_xsize,
2898 xsize - 2, ysize - 2, mask_mode);
2901 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
2904 WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
2908 void ShowEnvelope(int envelope_nr)
2910 int element = EL_ENVELOPE_1 + envelope_nr;
2911 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2912 int sound_opening = element_info[element].sound[ACTION_OPENING];
2913 int sound_closing = element_info[element].sound[ACTION_CLOSING];
2914 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2915 boolean no_delay = (tape.warp_forward);
2916 int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
2917 int wait_delay_value = (no_delay ? 0 : normal_delay_value);
2918 int anim_mode = graphic_info[graphic].anim_mode;
2919 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
2920 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
2922 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
2924 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
2926 if (anim_mode == ANIM_DEFAULT)
2927 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_OPENING);
2929 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_OPENING);
2932 Delay(wait_delay_value);
2934 WaitForEventToContinue();
2936 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
2938 if (anim_mode != ANIM_NONE)
2939 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_CLOSING);
2941 if (anim_mode == ANIM_DEFAULT)
2942 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_CLOSING);
2944 game.envelope_active = FALSE;
2946 SetDrawtoField(DRAW_BUFFERED);
2948 redraw_mask |= REDRAW_FIELD;
2952 static void setRequestPosition(int *x, int *y, boolean add_border_size)
2954 int border_size = request.border_size;
2955 int sx_center = (request.x != -1 ? request.x : SX + SXSIZE / 2);
2956 int sy_center = (request.y != -1 ? request.y : SY + SYSIZE / 2);
2957 int sx = sx_center - request.width / 2;
2958 int sy = sy_center - request.height / 2;
2960 if (add_border_size)
2970 void DrawEnvelopeRequest(char *text)
2972 char *text_final = text;
2973 char *text_door_style = NULL;
2974 int graphic = IMG_BACKGROUND_REQUEST;
2975 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
2976 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
2977 int font_nr = FONT_REQUEST;
2978 int font_width = getFontWidth(font_nr);
2979 int font_height = getFontHeight(font_nr);
2980 int border_size = request.border_size;
2981 int line_spacing = request.line_spacing;
2982 int line_height = font_height + line_spacing;
2983 int text_width = request.width - 2 * border_size;
2984 int text_height = request.height - 2 * border_size;
2985 int line_length = text_width / font_width;
2986 int max_lines = text_height / line_height;
2987 int width = request.width;
2988 int height = request.height;
2989 int tile_size = request.step_offset;
2990 int x_steps = width / tile_size;
2991 int y_steps = height / tile_size;
2995 if (request.wrap_single_words)
2997 char *src_text_ptr, *dst_text_ptr;
2999 text_door_style = checked_malloc(2 * strlen(text) + 1);
3001 src_text_ptr = text;
3002 dst_text_ptr = text_door_style;
3004 while (*src_text_ptr)
3006 if (*src_text_ptr == ' ' ||
3007 *src_text_ptr == '?' ||
3008 *src_text_ptr == '!')
3009 *dst_text_ptr++ = '\n';
3011 if (*src_text_ptr != ' ')
3012 *dst_text_ptr++ = *src_text_ptr;
3017 *dst_text_ptr = '\0';
3019 text_final = text_door_style;
3022 setRequestPosition(&sx, &sy, FALSE);
3024 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
3026 for (y = 0; y < y_steps; y++)
3027 for (x = 0; x < x_steps; x++)
3028 DrawEnvelopeBackgroundTiles(graphic, sx, sy,
3029 x, y, x_steps, y_steps,
3030 tile_size, tile_size);
3032 DrawTextBuffer(sx + border_size, sy + border_size, text_final, font_nr,
3033 line_length, -1, max_lines, line_spacing, mask_mode,
3034 request.autowrap, request.centered, FALSE);
3036 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3037 RedrawGadget(tool_gadget[i]);
3039 // store readily prepared envelope request for later use when animating
3040 BlitBitmap(backbuffer, bitmap_db_cross, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
3044 BlitBitmap(bitmap_db_store, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
3045 BlitBitmap(bitmap_db_cross, backbuffer, sx, sy, width, height, sx, sy);
3047 redraw_mask = REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
3052 BlitBitmap(bitmap_db_store, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
3054 redraw_mask = REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
3060 if (text_door_style)
3061 free(text_door_style);
3066 void AnimateEnvelopeRequest(int anim_mode, int action)
3068 int graphic = IMG_BACKGROUND_REQUEST;
3069 boolean draw_masked = graphic_info[graphic].draw_masked;
3071 int delay_value_normal = request.step_delay;
3072 int delay_value_fast = delay_value_normal / 2;
3074 int delay_value_normal = GameFrameDelay;
3075 int delay_value_fast = FfwdFrameDelay;
3077 boolean ffwd_delay = (tape.playing && tape.fast_forward);
3078 boolean no_delay = (tape.warp_forward);
3079 int delay_value = (ffwd_delay ? delay_value_fast : delay_value_normal);
3080 int anim_delay_value = (no_delay ? 0 : delay_value + 500 * 0);
3081 unsigned int anim_delay = 0;
3083 int width = request.width;
3084 int height = request.height;
3085 int tile_size = request.step_offset;
3086 int max_xsize = width / tile_size;
3087 int max_ysize = height / tile_size;
3088 int max_xsize_inner = max_xsize - 2;
3089 int max_ysize_inner = max_ysize - 2;
3091 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize_inner : 0);
3092 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize_inner : 0);
3093 int xend = max_xsize_inner;
3094 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize_inner : 0);
3095 int xstep = (xstart < xend ? 1 : 0);
3096 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
3099 for (x = xstart, y = ystart; x <= xend && y <= yend; x += xstep, y += ystep)
3101 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
3102 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
3103 int sx_center = (request.x != -1 ? request.x : SX + SXSIZE / 2);
3104 int sy_center = (request.y != -1 ? request.y : SY + SYSIZE / 2);
3105 int src_x = sx_center - width / 2;
3106 int src_y = sy_center - height / 2;
3107 int dst_x = sx_center - xsize * tile_size / 2;
3108 int dst_y = sy_center - ysize * tile_size / 2;
3109 int xsize_size_left = (xsize - 1) * tile_size;
3110 int ysize_size_top = (ysize - 1) * tile_size;
3111 int max_xsize_pos = (max_xsize - 1) * tile_size;
3112 int max_ysize_pos = (max_ysize - 1) * tile_size;
3115 BlitBitmap(bitmap_db_store, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
3118 for (yy = 0; yy < 2; yy++)
3120 for (xx = 0; xx < 2; xx++)
3122 int src_xx = src_x + xx * max_xsize_pos;
3123 int src_yy = src_y + yy * max_ysize_pos;
3124 int dst_xx = dst_x + xx * xsize_size_left;
3125 int dst_yy = dst_y + yy * ysize_size_top;
3126 int xx_size = (xx ? tile_size : xsize_size_left);
3127 int yy_size = (yy ? tile_size : ysize_size_top);
3130 BlitBitmapMasked(bitmap_db_cross, backbuffer,
3131 src_xx, src_yy, xx_size, yy_size, dst_xx, dst_yy);
3133 BlitBitmap(bitmap_db_cross, backbuffer,
3134 src_xx, src_yy, xx_size, yy_size, dst_xx, dst_yy);
3138 BlitBitmap(bitmap_db_cross, backbuffer,
3140 xsize_size_left, ysize_size_top,
3142 BlitBitmap(bitmap_db_cross, backbuffer,
3143 src_x + max_xsize_pos, src_y,
3144 tile_size, ysize_size_top,
3145 dst_x + xsize_size_left, dst_y);
3146 BlitBitmap(bitmap_db_cross, backbuffer,
3147 src_x, src_y + max_ysize_pos,
3148 xsize_size_left, tile_size,
3149 dst_x, dst_y + ysize_size_top);
3150 BlitBitmap(bitmap_db_cross, backbuffer,
3151 src_x + max_xsize_pos, src_y + max_ysize_pos,
3152 tile_size, tile_size,
3153 dst_x + xsize_size_left, dst_y + ysize_size_top);
3157 redraw_mask = REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
3158 // redraw_mask |= REDRAW_ALL | REDRAW_FROM_BACKBUFFER;
3160 /* CHECK AGAIN (previous code reactivated) */
3161 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
3171 WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
3177 void AnimateEnvelopeRequest(char *text, int anim_mode, int action)
3180 int envelope_nr = 0;
3183 int graphic = IMG_BACKGROUND_REQUEST;
3185 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
3187 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
3188 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
3189 boolean ffwd_delay = (tape.playing && tape.fast_forward);
3190 boolean no_delay = (tape.warp_forward);
3191 unsigned int anim_delay = 0;
3192 int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
3193 int anim_delay_value = (no_delay ? 0 : frame_delay_value + 500 * 0);
3195 int max_word_len = maxWordLengthInString(text);
3196 int font_nr = (max_word_len > 7 ? FONT_TEXT_1 : FONT_TEXT_2);
3198 int font_nr = FONT_ENVELOPE_1 + envelope_nr;
3200 int font_width = getFontWidth(font_nr);
3201 int font_height = getFontHeight(font_nr);
3202 int line_spacing = 2 * 1;
3206 int max_xsize = DXSIZE / font_width;
3207 // int max_ysize = DYSIZE / font_height;
3208 int max_ysize = DYSIZE / (font_height + line_spacing);
3210 int max_xsize = 7; /* tools.c: MAX_REQUEST_LINE_FONT1_LEN == 7 */
3211 int max_ysize = 13; /* tools.c: MAX_REQUEST_LINES == 13 */
3215 int max_xsize = level.envelope[envelope_nr].xsize;
3216 int max_ysize = level.envelope[envelope_nr].ysize;
3218 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
3219 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
3220 int xend = max_xsize;
3221 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
3222 int xstep = (xstart < xend ? 1 : 0);
3223 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
3228 char *text_copy = getStringCopy(text);
3231 font_nr = FONT_TEXT_2;
3233 if (maxWordLengthInString(text) > 7) /* MAX_REQUEST_LINE_FONT1_LEN == 7 */
3235 max_xsize = 10; /* tools.c: MAX_REQUEST_LINE_FONT2_LEN == 10 */
3236 font_nr = FONT_TEXT_1;
3239 int max_word_len = 0;
3241 char *text_copy = getStringCopy(text);
3243 font_nr = FONT_TEXT_2;
3245 for (text_ptr = text; *text_ptr; text_ptr++)
3247 max_word_len = (*text_ptr != ' ' ? max_word_len + 1 : 0);
3249 if (max_word_len > 7) /* tools.c: MAX_REQUEST_LINE_FONT1_LEN == 7 */
3251 max_xsize = 10; /* tools.c: MAX_REQUEST_LINE_FONT2_LEN == 10 */
3252 font_nr = FONT_TEXT_1;
3261 for (text_ptr = text_copy; *text_ptr; text_ptr++)
3262 if (*text_ptr == ' ')
3267 dDX = SX + (SXSIZE - DXSIZE) / 2 - DX;
3268 dDY = SY + (SYSIZE - DYSIZE) / 2 - DY;
3270 dDX = SX + SXSIZE / 2 - max_xsize * font_width / 2 - DX;
3271 dDY = SY + SYSIZE / 2 - max_ysize * font_height / 2 - DY;
3274 for (x = xstart, y = ystart; x <= xend && y <= yend; x += xstep, y += ystep)
3276 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
3277 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
3278 int sx = SX + (SXSIZE - xsize * font_width) / 2;
3279 // int sy = SX + (SYSIZE - ysize * font_height) / 2;
3280 int sy = SY + (SYSIZE - ysize * (font_height + line_spacing)) / 2;
3284 BlitBitmap(bitmap_db_store, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
3286 SetDrawtoField(DRAW_BUFFERED);
3289 BlitScreenToBitmap(backbuffer);
3291 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
3294 SetDrawtoField(DRAW_BACKBUFFER);
3297 for (yy = 0; yy < ysize; yy++)
3298 for (xx = 0; xx < xsize; xx++)
3299 DrawEnvelopeBackgroundTiles(graphic, sx, sy, xx, yy, xsize, ysize,
3300 getFontWidth(font_nr),
3301 getFontHeight(font_nr) + line_spacing);
3306 DrawTextBuffer(sx + font_width, sy + font_height + 8,
3307 text_copy, font_nr, max_xsize,
3308 xsize - 2, ysize - 2, line_spacing, mask_mode,
3309 FALSE, TRUE, FALSE);
3311 DrawTextBuffer(sx + font_width, sy + font_height,
3312 level.envelope[envelope_nr].text, font_nr, max_xsize,
3313 xsize - 2, ysize - 2, 0, mask_mode,
3314 level.envelope[envelope_nr].autowrap,
3315 level.envelope[envelope_nr].centered, FALSE);
3319 DrawTextToTextArea(sx + font_width, sy + font_height,
3320 level.envelope[envelope_nr].text, font_nr, max_xsize,
3321 xsize - 2, ysize - 2, mask_mode);
3324 /* copy request gadgets to door backbuffer */
3327 if ((ysize - 2) > 13)
3328 BlitBitmap(bitmap_db_door, drawto,
3329 DOOR_GFX_PAGEX1 + (DXSIZE - (xsize - 2) * font_width) / 2,
3330 DOOR_GFX_PAGEY1 + 13 * font_height,
3331 (xsize - 2) * font_width,
3332 (ysize - 2 - 13) * font_height,
3334 sy + font_height * (1 + 13));
3336 if ((ysize - 2) > 13)
3337 BlitBitmap(bitmap_db_door, drawto,
3338 DOOR_GFX_PAGEX1 + (DXSIZE - (xsize - 2) * font_width) / 2,
3339 DOOR_GFX_PAGEY1 + 11 * (font_height + line_spacing * 0),
3340 (xsize - 2) * font_width,
3341 (ysize - 2 - 13) * (font_height + line_spacing),
3343 sy + (font_height + line_spacing) * (1 + 13));
3345 if ((ysize - 2) > 13)
3346 BlitBitmap(bitmap_db_door, drawto,
3347 DOOR_GFX_PAGEX1 + (DXSIZE - (xsize - 2) * font_width) / 2,
3348 DOOR_GFX_PAGEY1 + 13 * font_height,
3349 (xsize - 2) * font_width,
3350 (ysize - 2 - 13) * font_height,
3352 sy + font_height * (1 + 13));
3356 redraw_mask = REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
3357 // redraw_mask |= REDRAW_ALL | REDRAW_FROM_BACKBUFFER;
3359 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
3369 WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
3379 void ShowEnvelopeRequest(char *text, unsigned int req_state, int action)
3382 int last_game_status = game_status; /* save current game status */
3383 // int last_draw_background_mask = gfx.draw_background_mask;
3386 int graphic = IMG_BACKGROUND_REQUEST;
3387 int sound_opening = SND_REQUEST_OPENING;
3388 int sound_closing = SND_REQUEST_CLOSING;
3390 int envelope_nr = 0;
3391 int element = EL_ENVELOPE_1 + envelope_nr;
3392 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
3393 int sound_opening = element_info[element].sound[ACTION_OPENING];
3394 int sound_closing = element_info[element].sound[ACTION_CLOSING];
3397 boolean ffwd_delay = (tape.playing && tape.fast_forward);
3398 boolean no_delay = (tape.warp_forward);
3399 int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
3400 int wait_delay_value = (no_delay ? 0 : normal_delay_value);
3402 int anim_mode = graphic_info[graphic].anim_mode;
3403 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
3404 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
3406 char *text_copy = getStringCopy(text);
3409 for (text_ptr = text_copy; *text_ptr; text_ptr++)
3410 if (*text_ptr == ' ')
3415 if (game_status == GAME_MODE_PLAYING)
3419 BlitScreenToBitmap(backbuffer);
3421 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
3422 BlitScreenToBitmap_EM(backbuffer);
3423 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
3424 BlitScreenToBitmap_SP(backbuffer);
3426 BlitScreenToBitmap_RND(backbuffer);
3429 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
3430 BlitScreenToBitmap_EM(backbuffer);
3431 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
3432 BlitScreenToBitmap_SP(backbuffer);
3435 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
3440 SetDrawtoField(DRAW_BACKBUFFER);
3442 // SetDrawBackgroundMask(REDRAW_NONE);
3444 if (action == ACTION_OPENING)
3446 BlitBitmap(backbuffer, bitmap_db_store, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
3449 if (req_state & REQ_ASK)
3451 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
3452 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
3454 else if (req_state & REQ_CONFIRM)
3456 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
3458 else if (req_state & REQ_PLAYER)
3460 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
3461 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
3462 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
3463 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
3468 DrawEnvelopeRequest(text);
3470 DrawEnvelopeRequest(text_copy);
3473 if (game_status != GAME_MODE_MAIN)
3477 /* force DOOR font inside door area */
3478 game_status = GAME_MODE_PSEUDO_DOOR;
3481 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
3483 if (action == ACTION_OPENING)
3485 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
3487 if (anim_mode == ANIM_DEFAULT)
3488 AnimateEnvelopeRequest(ANIM_DEFAULT, ACTION_OPENING);
3490 AnimateEnvelopeRequest(main_anim_mode, ACTION_OPENING);
3494 Delay(wait_delay_value);
3496 WaitForEventToContinue();
3501 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
3503 if (anim_mode != ANIM_NONE)
3504 AnimateEnvelopeRequest(main_anim_mode, ACTION_CLOSING);
3506 if (anim_mode == ANIM_DEFAULT)
3507 AnimateEnvelopeRequest(ANIM_DEFAULT, ACTION_CLOSING);
3510 game.envelope_active = FALSE;
3513 // game_status = last_game_status; /* restore current game status */
3516 /* !!! CHECK AGAIN (SEE BELOW) !!! */
3517 game_status = last_game_status; /* restore current game status */
3520 if (action == ACTION_CLOSING)
3522 if (game_status != GAME_MODE_MAIN)
3525 BlitBitmap(bitmap_db_store, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
3528 SetDrawtoField(DRAW_BUFFERED);
3531 // SetDrawBackgroundMask(last_draw_background_mask);
3534 redraw_mask = REDRAW_FIELD;
3535 // redraw_mask |= REDRAW_ALL;
3537 /* CHECK AGAIN (previous code reactivated) */
3538 redraw_mask |= REDRAW_FIELD;
3542 if (game_status == GAME_MODE_MAIN)
3548 /* (important: after "BackToFront()", but before "SetDrawtoField()") */
3549 game_status = last_game_status; /* restore current game status */
3553 if (action == ACTION_CLOSING &&
3554 game_status == GAME_MODE_PLAYING &&
3555 level.game_engine_type == GAME_ENGINE_TYPE_RND)
3556 SetDrawtoField(DRAW_BUFFERED);
3558 if (game_status == GAME_MODE_PLAYING &&
3559 level.game_engine_type == GAME_ENGINE_TYPE_RND)
3560 SetDrawtoField(DRAW_BUFFERED);
3572 void DrawPreviewElement(int dst_x, int dst_y, int element, int tilesize)
3576 int graphic = el2preimg(element);
3578 getSizedGraphicSource(graphic, 0, tilesize, &src_bitmap, &src_x, &src_y);
3579 BlitBitmap(src_bitmap, drawto, src_x, src_y, tilesize, tilesize, dst_x,dst_y);
3582 void DrawLevel(int draw_background_mask)
3587 SetMainBackgroundImage(IMG_BACKGROUND_PLAYING);
3588 SetDrawBackgroundMask(draw_background_mask);
3591 SetMainBackgroundImage(IMG_BACKGROUND_PLAYING);
3592 SetDrawBackgroundMask(REDRAW_FIELD);
3594 SetDrawBackgroundMask(REDRAW_NONE);
3600 for (x = BX1; x <= BX2; x++)
3601 for (y = BY1; y <= BY2; y++)
3602 DrawScreenField(x, y);
3604 redraw_mask |= REDRAW_FIELD;
3607 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
3611 for (x = 0; x < size_x; x++)
3612 for (y = 0; y < size_y; y++)
3613 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
3615 redraw_mask |= REDRAW_FIELD;
3618 static void DrawPreviewLevelPlayfieldExt(int from_x, int from_y)
3620 boolean show_level_border = (BorderElement != EL_EMPTY);
3621 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
3622 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
3623 int tile_size = preview.tile_size;
3624 int preview_width = preview.xsize * tile_size;
3625 int preview_height = preview.ysize * tile_size;
3626 int real_preview_xsize = MIN(level_xsize, preview.xsize);
3627 int real_preview_ysize = MIN(level_ysize, preview.ysize);
3628 int real_preview_width = real_preview_xsize * tile_size;
3629 int real_preview_height = real_preview_ysize * tile_size;
3630 int dst_x = SX + ALIGNED_XPOS(preview.x, preview_width, preview.align);
3631 int dst_y = SY + ALIGNED_YPOS(preview.y, preview_height, preview.valign);
3635 if (!IN_GFX_FIELD_FULL(dst_x, dst_y + preview_height - 1))
3640 dst_x += (preview_width - real_preview_width) / 2;
3641 dst_y += (preview_height - real_preview_height) / 2;
3643 DrawBackground(dst_x, dst_y, real_preview_width, real_preview_height);
3645 DrawBackground(dst_x, dst_y, preview_width, preview_height);
3647 dst_x += (preview_width - real_preview_width) / 2;
3648 dst_y += (preview_height - real_preview_height) / 2;
3651 for (x = 0; x < real_preview_xsize; x++)
3653 for (y = 0; y < real_preview_ysize; y++)
3655 int lx = from_x + x + (show_level_border ? -1 : 0);
3656 int ly = from_y + y + (show_level_border ? -1 : 0);
3657 int element = (IN_LEV_FIELD(lx, ly) ? level.field[lx][ly] :
3658 getBorderElement(lx, ly));
3660 DrawPreviewElement(dst_x + x * tile_size, dst_y + y * tile_size,
3661 element, tile_size);
3665 redraw_mask |= REDRAW_MICROLEVEL;
3668 #define MICROLABEL_EMPTY 0
3669 #define MICROLABEL_LEVEL_NAME 1
3670 #define MICROLABEL_LEVEL_AUTHOR_HEAD 2
3671 #define MICROLABEL_LEVEL_AUTHOR 3
3672 #define MICROLABEL_IMPORTED_FROM_HEAD 4
3673 #define MICROLABEL_IMPORTED_FROM 5
3674 #define MICROLABEL_IMPORTED_BY_HEAD 6
3675 #define MICROLABEL_IMPORTED_BY 7
3677 static int getMaxTextLength(struct TextPosInfo *pos, int font_nr)
3679 int max_text_width = SXSIZE;
3680 int font_width = getFontWidth(font_nr);
3682 if (pos->align == ALIGN_CENTER)
3683 max_text_width = (pos->x < SXSIZE / 2 ? pos->x * 2 : (SXSIZE - pos->x) * 2);
3684 else if (pos->align == ALIGN_RIGHT)
3685 max_text_width = pos->x;
3687 max_text_width = SXSIZE - pos->x;
3689 return max_text_width / font_width;
3692 static void DrawPreviewLevelLabelExt(int mode)
3694 struct TextPosInfo *pos = &menu.main.text.level_info_2;
3695 char label_text[MAX_OUTPUT_LINESIZE + 1];
3696 int max_len_label_text;
3698 int font_nr = pos->font;
3701 if (!IN_GFX_FIELD_FULL(pos->x, pos->y + getFontHeight(pos->font)))
3704 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
3705 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
3706 mode == MICROLABEL_IMPORTED_BY_HEAD)
3707 font_nr = pos->font_alt;
3709 int font_nr = FONT_TEXT_2;
3712 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
3713 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
3714 mode == MICROLABEL_IMPORTED_BY_HEAD)
3715 font_nr = FONT_TEXT_3;
3719 max_len_label_text = getMaxTextLength(pos, font_nr);
3721 max_len_label_text = SXSIZE / getFontWidth(font_nr);
3725 if (pos->size != -1)
3726 max_len_label_text = pos->size;
3729 for (i = 0; i < max_len_label_text; i++)
3730 label_text[i] = ' ';
3731 label_text[max_len_label_text] = '\0';
3733 if (strlen(label_text) > 0)
3736 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
3738 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
3739 int lypos = MICROLABEL2_YPOS;
3741 DrawText(lxpos, lypos, label_text, font_nr);
3746 (mode == MICROLABEL_LEVEL_NAME ? level.name :
3747 mode == MICROLABEL_LEVEL_AUTHOR_HEAD ? "created by" :
3748 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
3749 mode == MICROLABEL_IMPORTED_FROM_HEAD ? "imported from" :
3750 mode == MICROLABEL_IMPORTED_FROM ? leveldir_current->imported_from :
3751 mode == MICROLABEL_IMPORTED_BY_HEAD ? "imported by" :
3752 mode == MICROLABEL_IMPORTED_BY ? leveldir_current->imported_by :""),
3753 max_len_label_text);
3754 label_text[max_len_label_text] = '\0';
3756 if (strlen(label_text) > 0)
3759 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
3761 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
3762 int lypos = MICROLABEL2_YPOS;
3764 DrawText(lxpos, lypos, label_text, font_nr);
3768 redraw_mask |= REDRAW_MICROLEVEL;
3771 static void DrawPreviewLevelExt(boolean restart)
3773 static unsigned int scroll_delay = 0;
3774 static unsigned int label_delay = 0;
3775 static int from_x, from_y, scroll_direction;
3776 static int label_state, label_counter;
3777 unsigned int scroll_delay_value = preview.step_delay;
3778 boolean show_level_border = (BorderElement != EL_EMPTY);
3779 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
3780 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
3781 int last_game_status = game_status; /* save current game status */
3784 /* force PREVIEW font on preview level */
3785 game_status = GAME_MODE_PSEUDO_PREVIEW;
3793 if (preview.anim_mode == ANIM_CENTERED)
3795 if (level_xsize > preview.xsize)
3796 from_x = (level_xsize - preview.xsize) / 2;
3797 if (level_ysize > preview.ysize)
3798 from_y = (level_ysize - preview.ysize) / 2;
3801 from_x += preview.xoffset;
3802 from_y += preview.yoffset;
3804 scroll_direction = MV_RIGHT;
3808 DrawPreviewLevelPlayfieldExt(from_x, from_y);
3809 DrawPreviewLevelLabelExt(label_state);
3811 /* initialize delay counters */
3812 DelayReached(&scroll_delay, 0);
3813 DelayReached(&label_delay, 0);
3815 if (leveldir_current->name)
3817 struct TextPosInfo *pos = &menu.main.text.level_info_1;
3818 char label_text[MAX_OUTPUT_LINESIZE + 1];
3820 int font_nr = pos->font;
3822 int font_nr = FONT_TEXT_1;
3825 int max_len_label_text = getMaxTextLength(pos, font_nr);
3827 int max_len_label_text = SXSIZE / getFontWidth(font_nr);
3835 if (pos->size != -1)
3836 max_len_label_text = pos->size;
3839 strncpy(label_text, leveldir_current->name, max_len_label_text);
3840 label_text[max_len_label_text] = '\0';
3843 if (IN_GFX_FIELD_FULL(pos->x, pos->y + getFontHeight(pos->font)))
3844 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
3846 lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
3847 lypos = SY + MICROLABEL1_YPOS;
3849 DrawText(lxpos, lypos, label_text, font_nr);
3853 game_status = last_game_status; /* restore current game status */
3858 /* scroll preview level, if needed */
3859 if (preview.anim_mode != ANIM_NONE &&
3860 (level_xsize > preview.xsize || level_ysize > preview.ysize) &&
3861 DelayReached(&scroll_delay, scroll_delay_value))
3863 switch (scroll_direction)
3868 from_x -= preview.step_offset;
3869 from_x = (from_x < 0 ? 0 : from_x);
3872 scroll_direction = MV_UP;
3876 if (from_x < level_xsize - preview.xsize)
3878 from_x += preview.step_offset;
3879 from_x = (from_x > level_xsize - preview.xsize ?
3880 level_xsize - preview.xsize : from_x);
3883 scroll_direction = MV_DOWN;
3889 from_y -= preview.step_offset;
3890 from_y = (from_y < 0 ? 0 : from_y);
3893 scroll_direction = MV_RIGHT;
3897 if (from_y < level_ysize - preview.ysize)
3899 from_y += preview.step_offset;
3900 from_y = (from_y > level_ysize - preview.ysize ?
3901 level_ysize - preview.ysize : from_y);
3904 scroll_direction = MV_LEFT;
3911 DrawPreviewLevelPlayfieldExt(from_x, from_y);
3914 /* !!! THIS ALL SUCKS -- SHOULD BE CLEANLY REWRITTEN !!! */
3915 /* redraw micro level label, if needed */
3916 if (!strEqual(level.name, NAMELESS_LEVEL_NAME) &&
3917 !strEqual(level.author, ANONYMOUS_NAME) &&
3918 !strEqual(level.author, leveldir_current->name) &&
3919 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
3921 int max_label_counter = 23;
3923 if (leveldir_current->imported_from != NULL &&
3924 strlen(leveldir_current->imported_from) > 0)
3925 max_label_counter += 14;
3926 if (leveldir_current->imported_by != NULL &&
3927 strlen(leveldir_current->imported_by) > 0)
3928 max_label_counter += 14;
3930 label_counter = (label_counter + 1) % max_label_counter;
3931 label_state = (label_counter >= 0 && label_counter <= 7 ?
3932 MICROLABEL_LEVEL_NAME :
3933 label_counter >= 9 && label_counter <= 12 ?
3934 MICROLABEL_LEVEL_AUTHOR_HEAD :
3935 label_counter >= 14 && label_counter <= 21 ?
3936 MICROLABEL_LEVEL_AUTHOR :
3937 label_counter >= 23 && label_counter <= 26 ?
3938 MICROLABEL_IMPORTED_FROM_HEAD :
3939 label_counter >= 28 && label_counter <= 35 ?
3940 MICROLABEL_IMPORTED_FROM :
3941 label_counter >= 37 && label_counter <= 40 ?
3942 MICROLABEL_IMPORTED_BY_HEAD :
3943 label_counter >= 42 && label_counter <= 49 ?
3944 MICROLABEL_IMPORTED_BY : MICROLABEL_EMPTY);
3946 if (leveldir_current->imported_from == NULL &&
3947 (label_state == MICROLABEL_IMPORTED_FROM_HEAD ||
3948 label_state == MICROLABEL_IMPORTED_FROM))
3949 label_state = (label_state == MICROLABEL_IMPORTED_FROM_HEAD ?
3950 MICROLABEL_IMPORTED_BY_HEAD : MICROLABEL_IMPORTED_BY);
3952 DrawPreviewLevelLabelExt(label_state);
3955 game_status = last_game_status; /* restore current game status */
3958 void DrawPreviewLevelInitial()
3960 DrawPreviewLevelExt(TRUE);
3963 void DrawPreviewLevelAnimation()
3965 DrawPreviewLevelExt(FALSE);
3968 inline void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
3969 int graphic, int sync_frame, int mask_mode)
3971 int frame = getGraphicAnimationFrame(graphic, sync_frame);
3973 if (mask_mode == USE_MASKING)
3974 DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
3976 DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
3979 inline void DrawFixedGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
3980 int graphic, int sync_frame,
3983 int frame = getGraphicAnimationFrame(graphic, sync_frame);
3985 if (mask_mode == USE_MASKING)
3986 DrawFixedGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
3988 DrawFixedGraphicExt(dst_bitmap, x, y, graphic, frame);
3991 inline void DrawGraphicAnimation(int x, int y, int graphic)
3993 int lx = LEVELX(x), ly = LEVELY(y);
3995 if (!IN_SCR_FIELD(x, y))
3999 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR,
4000 graphic, GfxFrame[lx][ly], NO_MASKING);
4002 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
4003 graphic, GfxFrame[lx][ly], NO_MASKING);
4005 MarkTileDirty(x, y);
4008 inline void DrawFixedGraphicAnimation(int x, int y, int graphic)
4010 int lx = LEVELX(x), ly = LEVELY(y);
4012 if (!IN_SCR_FIELD(x, y))
4015 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
4016 graphic, GfxFrame[lx][ly], NO_MASKING);
4017 MarkTileDirty(x, y);
4020 void DrawLevelGraphicAnimation(int x, int y, int graphic)
4022 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
4025 void DrawLevelElementAnimation(int x, int y, int element)
4027 int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
4029 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
4032 inline void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
4034 int sx = SCREENX(x), sy = SCREENY(y);
4036 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
4039 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
4042 DrawGraphicAnimation(sx, sy, graphic);
4045 if (GFX_CRUMBLED(TILE_GFX_ELEMENT(x, y)))
4046 DrawLevelFieldCrumbled(x, y);
4048 if (GFX_CRUMBLED(Feld[x][y]))
4049 DrawLevelFieldCrumbled(x, y);
4053 void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
4055 int sx = SCREENX(x), sy = SCREENY(y);
4058 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
4061 graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
4063 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
4066 DrawGraphicAnimation(sx, sy, graphic);
4068 if (GFX_CRUMBLED(element))
4069 DrawLevelFieldCrumbled(x, y);
4072 static int getPlayerGraphic(struct PlayerInfo *player, int move_dir)
4074 if (player->use_murphy)
4076 /* this works only because currently only one player can be "murphy" ... */
4077 static int last_horizontal_dir = MV_LEFT;
4078 int graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir);
4080 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
4081 last_horizontal_dir = move_dir;
4083 if (graphic == IMG_SP_MURPHY) /* undefined => use special graphic */
4085 int direction = (player->is_snapping ? move_dir : last_horizontal_dir);
4087 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
4093 return el_act_dir2img(player->artwork_element, player->GfxAction,move_dir);
4096 static boolean equalGraphics(int graphic1, int graphic2)
4098 struct GraphicInfo *g1 = &graphic_info[graphic1];
4099 struct GraphicInfo *g2 = &graphic_info[graphic2];
4101 return (g1->bitmap == g2->bitmap &&
4102 g1->src_x == g2->src_x &&
4103 g1->src_y == g2->src_y &&
4104 g1->anim_frames == g2->anim_frames &&
4105 g1->anim_delay == g2->anim_delay &&
4106 g1->anim_mode == g2->anim_mode);
4109 void DrawAllPlayers()
4113 for (i = 0; i < MAX_PLAYERS; i++)
4114 if (stored_player[i].active)
4115 DrawPlayer(&stored_player[i]);
4118 void DrawPlayerField(int x, int y)
4120 if (!IS_PLAYER(x, y))
4123 DrawPlayer(PLAYERINFO(x, y));
4126 #define DRAW_PLAYER_OVER_PUSHED_ELEMENT 1
4128 void DrawPlayer(struct PlayerInfo *player)
4130 int jx = player->jx;
4131 int jy = player->jy;
4132 int move_dir = player->MovDir;
4133 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? +1 : 0);
4134 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? +1 : 0);
4135 int last_jx = (player->is_moving ? jx - dx : jx);
4136 int last_jy = (player->is_moving ? jy - dy : jy);
4137 int next_jx = jx + dx;
4138 int next_jy = jy + dy;
4139 boolean player_is_moving = (player->MovPos ? TRUE : FALSE);
4140 boolean player_is_opaque = FALSE;
4141 int sx = SCREENX(jx), sy = SCREENY(jy);
4142 int sxx = 0, syy = 0;
4143 int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
4145 int action = ACTION_DEFAULT;
4146 int last_player_graphic = getPlayerGraphic(player, move_dir);
4147 int last_player_frame = player->Frame;
4150 /* GfxElement[][] is set to the element the player is digging or collecting;
4151 remove also for off-screen player if the player is not moving anymore */
4152 if (IN_LEV_FIELD(jx, jy) && !player_is_moving)
4153 GfxElement[jx][jy] = EL_UNDEFINED;
4155 if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
4159 if (!IN_LEV_FIELD(jx, jy))
4161 printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
4162 printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
4163 printf("DrawPlayerField(): This should never happen!\n");
4168 if (element == EL_EXPLOSION)
4171 action = (player->is_pushing ? ACTION_PUSHING :
4172 player->is_digging ? ACTION_DIGGING :
4173 player->is_collecting ? ACTION_COLLECTING :
4174 player->is_moving ? ACTION_MOVING :
4175 player->is_snapping ? ACTION_SNAPPING :
4176 player->is_dropping ? ACTION_DROPPING :
4177 player->is_waiting ? player->action_waiting : ACTION_DEFAULT);
4179 if (player->is_waiting)
4180 move_dir = player->dir_waiting;
4182 InitPlayerGfxAnimation(player, action, move_dir);
4184 /* ----------------------------------------------------------------------- */
4185 /* draw things in the field the player is leaving, if needed */
4186 /* ----------------------------------------------------------------------- */
4188 if (player->is_moving)
4190 if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
4192 DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
4194 if (last_element == EL_DYNAMITE_ACTIVE ||
4195 last_element == EL_EM_DYNAMITE_ACTIVE ||
4196 last_element == EL_SP_DISK_RED_ACTIVE)
4197 DrawDynamite(last_jx, last_jy);
4199 DrawLevelFieldThruMask(last_jx, last_jy);
4201 else if (last_element == EL_DYNAMITE_ACTIVE ||
4202 last_element == EL_EM_DYNAMITE_ACTIVE ||
4203 last_element == EL_SP_DISK_RED_ACTIVE)
4204 DrawDynamite(last_jx, last_jy);
4206 /* !!! this is not enough to prevent flickering of players which are
4207 moving next to each others without a free tile between them -- this
4208 can only be solved by drawing all players layer by layer (first the
4209 background, then the foreground etc.) !!! => TODO */
4210 else if (!IS_PLAYER(last_jx, last_jy))
4211 DrawLevelField(last_jx, last_jy);
4214 DrawLevelField(last_jx, last_jy);
4217 if (player->is_pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
4218 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
4221 if (!IN_SCR_FIELD(sx, sy))
4224 /* ----------------------------------------------------------------------- */
4225 /* draw things behind the player, if needed */
4226 /* ----------------------------------------------------------------------- */
4229 DrawLevelElement(jx, jy, Back[jx][jy]);
4230 else if (IS_ACTIVE_BOMB(element))
4231 DrawLevelElement(jx, jy, EL_EMPTY);
4234 if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
4236 int old_element = GfxElement[jx][jy];
4237 int old_graphic = el_act_dir2img(old_element, action, move_dir);
4238 int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
4240 if (GFX_CRUMBLED(old_element))
4241 DrawLevelFieldCrumbledDigging(jx, jy, move_dir, player->StepFrame);
4243 DrawGraphic(sx, sy, old_graphic, frame);
4245 if (graphic_info[old_graphic].anim_mode & ANIM_OPAQUE_PLAYER)
4246 player_is_opaque = TRUE;
4250 GfxElement[jx][jy] = EL_UNDEFINED;
4252 /* make sure that pushed elements are drawn with correct frame rate */
4254 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
4256 if (player->is_pushing && player->is_moving && !IS_ANIM_MODE_CE(graphic))
4257 GfxFrame[jx][jy] = player->StepFrame;
4259 if (player->is_pushing && player->is_moving)
4260 GfxFrame[jx][jy] = player->StepFrame;
4263 DrawLevelField(jx, jy);
4267 #if !DRAW_PLAYER_OVER_PUSHED_ELEMENT
4268 /* ----------------------------------------------------------------------- */
4269 /* draw player himself */
4270 /* ----------------------------------------------------------------------- */
4272 graphic = getPlayerGraphic(player, move_dir);
4274 /* in the case of changed player action or direction, prevent the current
4275 animation frame from being restarted for identical animations */
4276 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
4277 player->Frame = last_player_frame;
4279 frame = getGraphicAnimationFrame(graphic, player->Frame);
4283 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
4284 sxx = player->GfxPos;
4286 syy = player->GfxPos;
4289 if (!setup.soft_scrolling && ScreenMovPos)
4292 if (player_is_opaque)
4293 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
4295 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
4297 if (SHIELD_ON(player))
4299 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
4300 IMG_SHIELD_NORMAL_ACTIVE);
4301 int frame = getGraphicAnimationFrame(graphic, -1);
4303 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
4307 #if DRAW_PLAYER_OVER_PUSHED_ELEMENT
4310 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
4311 sxx = player->GfxPos;
4313 syy = player->GfxPos;
4317 /* ----------------------------------------------------------------------- */
4318 /* draw things the player is pushing, if needed */
4319 /* ----------------------------------------------------------------------- */
4322 printf("::: %d, %d [%d, %d] [%d]\n",
4323 player->is_pushing, player_is_moving, player->GfxAction,
4324 player->is_moving, player_is_moving);
4328 if (player->is_pushing && player->is_moving)
4330 int px = SCREENX(jx), py = SCREENY(jy);
4331 int pxx = (TILEX - ABS(sxx)) * dx;
4332 int pyy = (TILEY - ABS(syy)) * dy;
4333 int gfx_frame = GfxFrame[jx][jy];
4339 if (!IS_MOVING(jx, jy)) /* push movement already finished */
4341 element = Feld[next_jx][next_jy];
4342 gfx_frame = GfxFrame[next_jx][next_jy];
4345 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
4348 sync_frame = (IS_ANIM_MODE_CE(graphic) ? gfx_frame : player->StepFrame);
4349 frame = getGraphicAnimationFrame(graphic, sync_frame);
4351 frame = getGraphicAnimationFrame(graphic, player->StepFrame);
4354 /* draw background element under pushed element (like the Sokoban field) */
4356 if (game.use_masked_pushing && IS_MOVING(jx, jy))
4358 /* this allows transparent pushing animation over non-black background */
4361 DrawLevelElement(jx, jy, Back[jx][jy]);
4363 DrawLevelElement(jx, jy, EL_EMPTY);
4365 if (Back[next_jx][next_jy])
4366 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
4368 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
4370 else if (Back[next_jx][next_jy])
4371 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
4373 if (Back[next_jx][next_jy])
4374 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
4378 printf("::: %d, %d, %d, %d [%d] [%d, %d, %d] [%d] [%d, %d] [%d, %d]\n",
4379 jx, px, player->GfxPos, player->StepFrame,
4384 GfxFrame[jx][jy], GfxFrame[next_jx][next_jy]);
4388 /* do not draw (EM style) pushing animation when pushing is finished */
4389 /* (two-tile animations usually do not contain start and end frame) */
4390 if (graphic_info[graphic].double_movement && !IS_MOVING(jx, jy))
4391 DrawLevelElement(next_jx, next_jy, Feld[next_jx][next_jy]);
4393 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
4395 /* masked drawing is needed for EMC style (double) movement graphics */
4396 /* !!! (ONLY WHEN DRAWING PUSHED ELEMENT OVER THE PLAYER) !!! */
4397 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
4402 #if DRAW_PLAYER_OVER_PUSHED_ELEMENT
4403 /* ----------------------------------------------------------------------- */
4404 /* draw player himself */
4405 /* ----------------------------------------------------------------------- */
4407 graphic = getPlayerGraphic(player, move_dir);
4409 /* in the case of changed player action or direction, prevent the current
4410 animation frame from being restarted for identical animations */
4411 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
4412 player->Frame = last_player_frame;
4414 frame = getGraphicAnimationFrame(graphic, player->Frame);
4418 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
4419 sxx = player->GfxPos;
4421 syy = player->GfxPos;
4424 if (!setup.soft_scrolling && ScreenMovPos)
4427 if (player_is_opaque)
4428 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
4430 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
4432 if (SHIELD_ON(player))
4434 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
4435 IMG_SHIELD_NORMAL_ACTIVE);
4436 int frame = getGraphicAnimationFrame(graphic, -1);
4438 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
4442 /* ----------------------------------------------------------------------- */
4443 /* draw things in front of player (active dynamite or dynabombs) */
4444 /* ----------------------------------------------------------------------- */
4446 if (IS_ACTIVE_BOMB(element))
4448 graphic = el2img(element);
4449 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
4451 if (game.emulation == EMU_SUPAPLEX)
4452 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
4454 DrawGraphicThruMask(sx, sy, graphic, frame);
4457 if (player_is_moving && last_element == EL_EXPLOSION)
4459 int element = (GfxElement[last_jx][last_jy] != EL_UNDEFINED ?
4460 GfxElement[last_jx][last_jy] : EL_EMPTY);
4461 int graphic = el_act2img(element, ACTION_EXPLODING);
4462 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
4463 int phase = ExplodePhase[last_jx][last_jy] - 1;
4464 int frame = getGraphicAnimationFrame(graphic, phase - delay);
4467 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
4470 /* ----------------------------------------------------------------------- */
4471 /* draw elements the player is just walking/passing through/under */
4472 /* ----------------------------------------------------------------------- */
4474 if (player_is_moving)
4476 /* handle the field the player is leaving ... */
4477 if (IS_ACCESSIBLE_INSIDE(last_element))
4478 DrawLevelField(last_jx, last_jy);
4479 else if (IS_ACCESSIBLE_UNDER(last_element))
4480 DrawLevelFieldThruMask(last_jx, last_jy);
4483 /* do not redraw accessible elements if the player is just pushing them */
4484 if (!player_is_moving || !player->is_pushing)
4486 /* ... and the field the player is entering */
4487 if (IS_ACCESSIBLE_INSIDE(element))
4488 DrawLevelField(jx, jy);
4489 else if (IS_ACCESSIBLE_UNDER(element))
4490 DrawLevelFieldThruMask(jx, jy);
4493 MarkTileDirty(sx, sy);
4496 /* ------------------------------------------------------------------------- */
4498 void WaitForEventToContinue()
4500 boolean still_wait = TRUE;
4502 /* simulate releasing mouse button over last gadget, if still pressed */
4504 HandleGadgets(-1, -1, 0);
4506 button_status = MB_RELEASED;
4522 case EVENT_BUTTONPRESS:
4523 case EVENT_KEYPRESS:
4527 case EVENT_KEYRELEASE:
4528 ClearPlayerAction();
4532 HandleOtherEvents(&event);
4536 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
4543 /* don't eat all CPU time */
4548 #define MAX_REQUEST_LINES 13
4549 #define MAX_REQUEST_LINE_FONT1_LEN 7
4550 #define MAX_REQUEST_LINE_FONT2_LEN 10
4554 static int RequestHandleEvents(unsigned int req_state)
4556 int last_game_status = game_status; /* save current game status */
4560 button_status = MB_RELEASED;
4562 request_gadget_id = -1;
4575 case EVENT_BUTTONPRESS:
4576 case EVENT_BUTTONRELEASE:
4577 case EVENT_MOTIONNOTIFY:
4579 if (event.type == EVENT_MOTIONNOTIFY)
4581 if (!PointerInWindow(window))
4582 continue; /* window and pointer are on different screens */
4587 motion_status = TRUE;
4588 mx = ((MotionEvent *) &event)->x;
4589 my = ((MotionEvent *) &event)->y;
4593 motion_status = FALSE;
4594 mx = ((ButtonEvent *) &event)->x;
4595 my = ((ButtonEvent *) &event)->y;
4596 if (event.type == EVENT_BUTTONPRESS)
4597 button_status = ((ButtonEvent *) &event)->button;
4599 button_status = MB_RELEASED;
4602 /* this sets 'request_gadget_id' */
4603 HandleGadgets(mx, my, button_status);
4605 switch (request_gadget_id)
4607 case TOOL_CTRL_ID_YES:
4610 case TOOL_CTRL_ID_NO:
4613 case TOOL_CTRL_ID_CONFIRM:
4614 result = TRUE | FALSE;
4617 case TOOL_CTRL_ID_PLAYER_1:
4620 case TOOL_CTRL_ID_PLAYER_2:
4623 case TOOL_CTRL_ID_PLAYER_3:
4626 case TOOL_CTRL_ID_PLAYER_4:
4637 case EVENT_KEYPRESS:
4638 switch (GetEventKey((KeyEvent *)&event, TRUE))
4641 if (req_state & REQ_CONFIRM)
4646 #if defined(TARGET_SDL2)
4653 #if defined(TARGET_SDL2)
4663 if (req_state & REQ_PLAYER)
4667 case EVENT_KEYRELEASE:
4668 ClearPlayerAction();
4672 HandleOtherEvents(&event);
4676 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
4678 int joy = AnyJoystick();
4680 if (joy & JOY_BUTTON_1)
4682 else if (joy & JOY_BUTTON_2)
4688 if (game_status == GAME_MODE_PLAYING && local_player->LevelSolved_GameEnd)
4690 HandleGameActions();
4696 if (!PendingEvent()) /* delay only if no pending events */
4701 game_status = GAME_MODE_PSEUDO_DOOR;
4707 game_status = last_game_status; /* restore current game status */
4715 if (!PendingEvent()) /* delay only if no pending events */
4718 /* don't eat all CPU time */
4728 static boolean RequestDoor(char *text, unsigned int req_state)
4730 unsigned int old_door_state;
4731 int last_game_status = game_status; /* save current game status */
4732 int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
4733 int font_nr = FONT_TEXT_2;
4738 if (maxWordLengthInString(text) > MAX_REQUEST_LINE_FONT1_LEN)
4740 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
4741 font_nr = FONT_TEXT_1;
4744 if (game_status == GAME_MODE_PLAYING)
4747 BlitScreenToBitmap(backbuffer);
4749 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
4750 BlitScreenToBitmap_EM(backbuffer);
4751 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
4752 BlitScreenToBitmap_SP(backbuffer);
4756 /* disable deactivated drawing when quick-loading level tape recording */
4757 if (tape.playing && tape.deactivate_display)
4758 TapeDeactivateDisplayOff(TRUE);
4760 SetMouseCursor(CURSOR_DEFAULT);
4762 #if defined(NETWORK_AVALIABLE)
4763 /* pause network game while waiting for request to answer */
4764 if (options.network &&
4765 game_status == GAME_MODE_PLAYING &&
4766 req_state & REQUEST_WAIT_FOR_INPUT)
4767 SendToServer_PausePlaying();
4770 old_door_state = GetDoorState();
4772 /* simulate releasing mouse button over last gadget, if still pressed */
4774 HandleGadgets(-1, -1, 0);
4778 /* draw released gadget before proceeding */
4781 if (old_door_state & DOOR_OPEN_1)
4783 CloseDoor(DOOR_CLOSE_1);
4785 /* save old door content */
4787 BlitBitmap(bitmap_db_door_1, bitmap_db_door_1,
4788 0 * DXSIZE, 0, DXSIZE, DYSIZE, 1 * DXSIZE, 0);
4790 BlitBitmap(bitmap_db_door, bitmap_db_door,
4791 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
4792 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
4796 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
4797 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
4799 /* clear door drawing field */
4800 DrawBackground(DX, DY, DXSIZE, DYSIZE);
4802 /* force DOOR font inside door area */
4803 game_status = GAME_MODE_PSEUDO_DOOR;
4805 /* write text for request */
4806 for (text_ptr = text, ty = 0; ty < MAX_REQUEST_LINES; ty++)
4808 char text_line[max_request_line_len + 1];
4814 for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
4816 tc = *(text_ptr + tx);
4817 // if (!tc || tc == ' ')
4818 if (!tc || tc == ' ' || tc == '?' || tc == '!')
4822 if ((tc == '?' || tc == '!') && tl == 0)
4832 strncpy(text_line, text_ptr, tl);
4835 DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
4836 DY + 8 + ty * (getFontHeight(font_nr) + 2),
4837 text_line, font_nr);
4839 text_ptr += tl + (tc == ' ' ? 1 : 0);
4840 // text_ptr += tl + (tc == ' ' || tc == '?' || tc == '!' ? 1 : 0);
4843 game_status = last_game_status; /* restore current game status */
4845 if (req_state & REQ_ASK)
4847 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
4848 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
4850 else if (req_state & REQ_CONFIRM)
4852 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
4854 else if (req_state & REQ_PLAYER)
4856 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
4857 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
4858 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
4859 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
4862 /* copy request gadgets to door backbuffer */
4864 BlitBitmap(drawto, bitmap_db_door_1, DX, DY, DXSIZE, DYSIZE, 0, 0);
4866 BlitBitmap(drawto, bitmap_db_door,
4867 DX, DY, DXSIZE, DYSIZE,
4868 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
4871 OpenDoor(DOOR_OPEN_1);
4873 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
4875 if (game_status == GAME_MODE_PLAYING)
4877 SetPanelBackground();
4878 SetDrawBackgroundMask(REDRAW_DOOR_1);
4882 SetDrawBackgroundMask(REDRAW_FIELD);
4888 if (game_status != GAME_MODE_MAIN)
4891 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
4893 // ---------- handle request buttons ----------
4894 result = RequestHandleEvents(req_state);
4896 if (game_status != GAME_MODE_MAIN)
4901 if (!(req_state & REQ_STAY_OPEN))
4903 CloseDoor(DOOR_CLOSE_1);
4905 if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
4906 (req_state & REQ_REOPEN))
4907 OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
4912 if (game_status == GAME_MODE_PLAYING)
4914 SetPanelBackground();
4915 SetDrawBackgroundMask(REDRAW_DOOR_1);
4919 SetDrawBackgroundMask(REDRAW_FIELD);
4922 #if defined(NETWORK_AVALIABLE)
4923 /* continue network game after request */
4924 if (options.network &&
4925 game_status == GAME_MODE_PLAYING &&
4926 req_state & REQUEST_WAIT_FOR_INPUT)
4927 SendToServer_ContinuePlaying();
4930 /* restore deactivated drawing when quick-loading level tape recording */
4931 if (tape.playing && tape.deactivate_display)
4932 TapeDeactivateDisplayOn();
4937 static boolean RequestEnvelope(char *text, unsigned int req_state)
4944 if (game_status == GAME_MODE_PLAYING)
4948 BlitScreenToBitmap(backbuffer);
4950 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
4951 BlitScreenToBitmap_EM(backbuffer);
4952 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
4953 BlitScreenToBitmap_SP(backbuffer);
4955 BlitScreenToBitmap_RND(backbuffer);
4958 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
4959 BlitScreenToBitmap_EM(backbuffer);
4960 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
4961 BlitScreenToBitmap_SP(backbuffer);
4965 /* disable deactivated drawing when quick-loading level tape recording */
4966 if (tape.playing && tape.deactivate_display)
4967 TapeDeactivateDisplayOff(TRUE);
4969 SetMouseCursor(CURSOR_DEFAULT);
4971 #if defined(NETWORK_AVALIABLE)
4972 /* pause network game while waiting for request to answer */
4973 if (options.network &&
4974 game_status == GAME_MODE_PLAYING &&
4975 req_state & REQUEST_WAIT_FOR_INPUT)
4976 SendToServer_PausePlaying();
4979 /* simulate releasing mouse button over last gadget, if still pressed */
4981 HandleGadgets(-1, -1, 0);
4985 // (replace with setting corresponding request background)
4986 // SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
4987 // SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
4989 /* clear door drawing field */
4990 // DrawBackground(DX, DY, DXSIZE, DYSIZE);
4993 if (global.use_envelope_request)
4997 CreateToolButtons();
5003 if (req_state & REQ_ASK)
5005 MapGadgetExt(tool_gadget[TOOL_CTRL_ID_YES], FALSE);
5006 MapGadgetExt(tool_gadget[TOOL_CTRL_ID_NO], FALSE);
5008 else if (req_state & REQ_CONFIRM)
5010 MapGadgetExt(tool_gadget[TOOL_CTRL_ID_CONFIRM], FALSE);
5012 else if (req_state & REQ_PLAYER)
5014 MapGadgetExt(tool_gadget[TOOL_CTRL_ID_PLAYER_1], FALSE);
5015 MapGadgetExt(tool_gadget[TOOL_CTRL_ID_PLAYER_2], FALSE);
5016 MapGadgetExt(tool_gadget[TOOL_CTRL_ID_PLAYER_3], FALSE);
5017 MapGadgetExt(tool_gadget[TOOL_CTRL_ID_PLAYER_4], FALSE);
5020 if (req_state & REQ_ASK)
5022 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
5023 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
5025 else if (req_state & REQ_CONFIRM)
5027 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
5029 else if (req_state & REQ_PLAYER)
5031 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
5032 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
5033 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
5034 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
5039 ShowEnvelopeRequest(text, req_state, ACTION_OPENING);
5042 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
5044 if ((req_state & REQ_ASK && (i == TOOL_CTRL_ID_YES ||
5045 i == TOOL_CTRL_ID_NO)) ||
5046 (req_state & REQ_CONFIRM && i == TOOL_CTRL_ID_CONFIRM) ||
5047 (req_state & REQ_PLAYER && (i == TOOL_CTRL_ID_PLAYER_1 &&
5048 i == TOOL_CTRL_ID_PLAYER_2 &&
5049 i == TOOL_CTRL_ID_PLAYER_3 &&
5050 i == TOOL_CTRL_ID_PLAYER_4)))
5052 int x = tool_gadget[i]->x + dDX;
5053 int y = tool_gadget[i]->y + dDY;
5055 ModifyGadget(tool_gadget[i], GDI_X, x, GDI_Y, y, GDI_END);
5060 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
5062 if (game_status == GAME_MODE_PLAYING)
5064 SetPanelBackground();
5065 SetDrawBackgroundMask(REDRAW_DOOR_1);
5069 SetDrawBackgroundMask(REDRAW_FIELD);
5076 if (game_status != GAME_MODE_MAIN)
5080 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
5082 // ---------- handle request buttons ----------
5083 result = RequestHandleEvents(req_state);
5085 if (game_status != GAME_MODE_MAIN)
5090 ShowEnvelopeRequest(text, req_state, ACTION_CLOSING);
5094 if (game_status == GAME_MODE_PLAYING)
5096 SetPanelBackground();
5097 SetDrawBackgroundMask(REDRAW_DOOR_1);
5101 SetDrawBackgroundMask(REDRAW_FIELD);
5104 #if defined(NETWORK_AVALIABLE)
5105 /* continue network game after request */
5106 if (options.network &&
5107 game_status == GAME_MODE_PLAYING &&
5108 req_state & REQUEST_WAIT_FOR_INPUT)
5109 SendToServer_ContinuePlaying();
5112 /* restore deactivated drawing when quick-loading level tape recording */
5113 if (tape.playing && tape.deactivate_display)
5114 TapeDeactivateDisplayOn();
5119 boolean Request(char *text, unsigned int req_state)
5121 if (global.use_envelope_request)
5122 return RequestEnvelope(text, req_state);
5124 return RequestDoor(text, req_state);
5127 #else // =====================================================================
5129 boolean Request(char *text, unsigned int req_state)
5131 int mx, my, ty, result = -1;
5132 unsigned int old_door_state;
5133 int last_game_status = game_status; /* save current game status */
5134 int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
5135 int font_nr = FONT_TEXT_2;
5137 int max_word_len = 0;
5143 global.use_envelope_request = 1;
5147 if (maxWordLengthInString(text) > MAX_REQUEST_LINE_FONT1_LEN)
5149 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
5150 font_nr = FONT_TEXT_1;
5153 for (text_ptr = text; *text_ptr; text_ptr++)
5155 max_word_len = (*text_ptr != ' ' ? max_word_len + 1 : 0);
5157 if (max_word_len > MAX_REQUEST_LINE_FONT1_LEN)
5159 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
5161 font_nr = FONT_TEXT_1;
5163 font_nr = FONT_LEVEL_NUMBER;
5171 if (game_status == GAME_MODE_PLAYING)
5174 BlitScreenToBitmap(backbuffer);
5176 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
5177 BlitScreenToBitmap_EM(backbuffer);
5178 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
5179 BlitScreenToBitmap_SP(backbuffer);
5183 /* disable deactivated drawing when quick-loading level tape recording */
5184 if (tape.playing && tape.deactivate_display)
5185 TapeDeactivateDisplayOff(TRUE);
5187 SetMouseCursor(CURSOR_DEFAULT);
5189 #if defined(NETWORK_AVALIABLE)
5190 /* pause network game while waiting for request to answer */
5191 if (options.network &&
5192 game_status == GAME_MODE_PLAYING &&
5193 req_state & REQUEST_WAIT_FOR_INPUT)
5194 SendToServer_PausePlaying();
5197 old_door_state = GetDoorState();
5199 /* simulate releasing mouse button over last gadget, if still pressed */
5201 HandleGadgets(-1, -1, 0);
5205 /* draw released gadget before proceeding */
5209 if (old_door_state & DOOR_OPEN_1 && !global.use_envelope_request)
5211 if (old_door_state & DOOR_OPEN_1)
5215 if (!global.use_envelope_request)
5216 CloseDoor(DOOR_CLOSE_1);
5218 CloseDoor(DOOR_CLOSE_1);
5221 /* save old door content */
5222 BlitBitmap(bitmap_db_door, bitmap_db_door,
5223 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
5224 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
5228 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
5231 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
5233 /* clear door drawing field */
5234 DrawBackground(DX, DY, DXSIZE, DYSIZE);
5236 /* force DOOR font inside door area */
5237 game_status = GAME_MODE_PSEUDO_DOOR;
5239 /* write text for request */
5240 for (text_ptr = text, ty = 0; ty < MAX_REQUEST_LINES; ty++)
5242 char text_line[max_request_line_len + 1];
5248 for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
5250 tc = *(text_ptr + tx);
5251 if (!tc || tc == ' ')
5262 strncpy(text_line, text_ptr, tl);
5265 DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
5266 DY + 8 + ty * (getFontHeight(font_nr) + 2),
5267 text_line, font_nr);
5269 text_ptr += tl + (tc == ' ' ? 1 : 0);
5272 game_status = last_game_status; /* restore current game status */
5275 if (global.use_envelope_request)
5279 CreateToolButtons();
5283 if (req_state & REQ_ASK)
5285 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
5286 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
5288 else if (req_state & REQ_CONFIRM)
5290 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
5292 else if (req_state & REQ_PLAYER)
5294 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
5295 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
5296 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
5297 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
5300 /* copy request gadgets to door backbuffer */
5301 BlitBitmap(drawto, bitmap_db_door,
5302 DX, DY, DXSIZE, DYSIZE,
5303 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
5306 if (global.use_envelope_request)
5308 ShowEnvelopeRequest(text, ACTION_OPENING);
5310 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
5312 if ((req_state & REQ_ASK && (i == TOOL_CTRL_ID_YES ||
5313 i == TOOL_CTRL_ID_NO)) ||
5314 (req_state & REQ_CONFIRM && i == TOOL_CTRL_ID_CONFIRM) ||
5315 (req_state & REQ_PLAYER && (i == TOOL_CTRL_ID_PLAYER_1 &&
5316 i == TOOL_CTRL_ID_PLAYER_2 &&
5317 i == TOOL_CTRL_ID_PLAYER_3 &&
5318 i == TOOL_CTRL_ID_PLAYER_4)))
5320 int x = tool_gadget[i]->x + dDX;
5321 int y = tool_gadget[i]->y + dDY;
5323 ModifyGadget(tool_gadget[i], GDI_X, x, GDI_Y, y, GDI_END);
5330 if (!global.use_envelope_request)
5331 OpenDoor(DOOR_OPEN_1);
5333 OpenDoor(DOOR_OPEN_1);
5336 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
5338 if (game_status == GAME_MODE_PLAYING)
5340 SetPanelBackground();
5341 SetDrawBackgroundMask(REDRAW_DOOR_1);
5345 SetDrawBackgroundMask(REDRAW_FIELD);
5352 if (game_status != GAME_MODE_MAIN && !global.use_envelope_request)
5355 if (game_status != GAME_MODE_MAIN)
5359 button_status = MB_RELEASED;
5361 request_gadget_id = -1;
5363 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
5375 case EVENT_BUTTONPRESS:
5376 case EVENT_BUTTONRELEASE:
5377 case EVENT_MOTIONNOTIFY:
5379 if (event.type == EVENT_MOTIONNOTIFY)
5381 if (!PointerInWindow(window))
5382 continue; /* window and pointer are on different screens */
5387 motion_status = TRUE;
5388 mx = ((MotionEvent *) &event)->x;
5389 my = ((MotionEvent *) &event)->y;
5393 motion_status = FALSE;
5394 mx = ((ButtonEvent *) &event)->x;
5395 my = ((ButtonEvent *) &event)->y;
5396 if (event.type == EVENT_BUTTONPRESS)
5397 button_status = ((ButtonEvent *) &event)->button;
5399 button_status = MB_RELEASED;
5402 /* this sets 'request_gadget_id' */
5403 HandleGadgets(mx, my, button_status);
5405 switch (request_gadget_id)
5407 case TOOL_CTRL_ID_YES:
5410 case TOOL_CTRL_ID_NO:
5413 case TOOL_CTRL_ID_CONFIRM:
5414 result = TRUE | FALSE;
5417 case TOOL_CTRL_ID_PLAYER_1:
5420 case TOOL_CTRL_ID_PLAYER_2:
5423 case TOOL_CTRL_ID_PLAYER_3:
5426 case TOOL_CTRL_ID_PLAYER_4:
5437 case EVENT_KEYPRESS:
5438 switch (GetEventKey((KeyEvent *)&event, TRUE))
5441 if (req_state & REQ_CONFIRM)
5450 #if defined(TARGET_SDL2)
5460 if (req_state & REQ_PLAYER)
5464 case EVENT_KEYRELEASE:
5465 ClearPlayerAction();
5469 HandleOtherEvents(&event);
5473 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
5475 int joy = AnyJoystick();
5477 if (joy & JOY_BUTTON_1)
5479 else if (joy & JOY_BUTTON_2)
5485 if (game_status == GAME_MODE_PLAYING && local_player->LevelSolved_GameEnd)
5487 HandleGameActions();
5493 if (!PendingEvent()) /* delay only if no pending events */
5498 game_status = GAME_MODE_PSEUDO_DOOR;
5504 game_status = last_game_status; /* restore current game status */
5512 if (!PendingEvent()) /* delay only if no pending events */
5515 /* don't eat all CPU time */
5522 if (game_status != GAME_MODE_MAIN)
5528 if (global.use_envelope_request)
5529 ShowEnvelopeRequest(text, ACTION_CLOSING);
5533 if (!(req_state & REQ_STAY_OPEN) && !global.use_envelope_request)
5535 if (!(req_state & REQ_STAY_OPEN))
5538 CloseDoor(DOOR_CLOSE_1);
5540 if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
5541 (req_state & REQ_REOPEN))
5542 OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
5547 if (game_status == GAME_MODE_PLAYING)
5549 SetPanelBackground();
5550 SetDrawBackgroundMask(REDRAW_DOOR_1);
5554 SetDrawBackgroundMask(REDRAW_FIELD);
5557 #if defined(NETWORK_AVALIABLE)
5558 /* continue network game after request */
5559 if (options.network &&
5560 game_status == GAME_MODE_PLAYING &&
5561 req_state & REQUEST_WAIT_FOR_INPUT)
5562 SendToServer_ContinuePlaying();
5565 /* restore deactivated drawing when quick-loading level tape recording */
5566 if (tape.playing && tape.deactivate_display)
5567 TapeDeactivateDisplayOn();
5574 static int compareDoorPartOrderInfo(const void *object1, const void *object2)
5576 const struct DoorPartOrderInfo *dpo1 = (struct DoorPartOrderInfo *)object1;
5577 const struct DoorPartOrderInfo *dpo2 = (struct DoorPartOrderInfo *)object2;
5580 if (dpo1->sort_priority != dpo2->sort_priority)
5581 compare_result = dpo1->sort_priority - dpo2->sort_priority;
5583 compare_result = dpo1->nr - dpo2->nr;
5585 return compare_result;
5588 void InitGraphicCompatibilityInfo_Doors()
5594 struct DoorInfo *door;
5598 { DOOR_1, IMG_DOOR_1_GFX_PART_1, IMG_DOOR_1_GFX_PART_8, &door_1 },
5599 { DOOR_2, IMG_DOOR_2_GFX_PART_1, IMG_DOOR_2_GFX_PART_8, &door_2 },
5601 { -1, -1, -1, NULL }
5603 struct Rect door_rect_list[] =
5605 { DX, DY, DXSIZE, DYSIZE },
5606 { VX, VY, VXSIZE, VYSIZE }
5610 for (i = 0; doors[i].door_token != -1; i++)
5612 int door_token = doors[i].door_token;
5613 int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
5614 int part_1 = doors[i].part_1;
5615 int part_8 = doors[i].part_8;
5616 int part_2 = part_1 + 1;
5617 int part_3 = part_1 + 2;
5618 struct DoorInfo *door = doors[i].door;
5619 struct Rect *door_rect = &door_rect_list[door_index];
5620 boolean door_gfx_redefined = FALSE;
5622 /* check if any door part graphic definitions have been redefined */
5624 for (j = 0; door_part_controls[j].door_token != -1; j++)
5626 struct DoorPartControlInfo *dpc = &door_part_controls[j];
5627 struct FileInfo *fi = getImageListEntryFromImageID(dpc->graphic);
5629 if (dpc->door_token == door_token && fi->redefined)
5630 door_gfx_redefined = TRUE;
5633 /* check for old-style door graphic/animation modifications */
5635 if (!door_gfx_redefined)
5637 if (door->anim_mode & ANIM_STATIC_PANEL)
5639 door->panel.step_xoffset = 0;
5640 door->panel.step_yoffset = 0;
5643 if (door->anim_mode & (ANIM_HORIZONTAL | ANIM_VERTICAL))
5645 struct GraphicInfo *g_part_1 = &graphic_info[part_1];
5646 struct GraphicInfo *g_part_2 = &graphic_info[part_2];
5647 int num_door_steps, num_panel_steps;
5649 /* remove door part graphics other than the two default wings */
5651 for (j = 0; door_part_controls[j].door_token != -1; j++)
5653 struct DoorPartControlInfo *dpc = &door_part_controls[j];
5654 struct GraphicInfo *g = &graphic_info[dpc->graphic];
5656 if (dpc->graphic >= part_3 &&
5657 dpc->graphic <= part_8)
5661 /* set graphics and screen positions of the default wings */
5663 g_part_1->width = door_rect->width;
5664 g_part_1->height = door_rect->height;
5665 g_part_2->width = door_rect->width;
5666 g_part_2->height = door_rect->height;
5667 g_part_2->src_x = door_rect->width;
5668 g_part_2->src_y = g_part_1->src_y;
5670 door->part_2.x = door->part_1.x;
5671 door->part_2.y = door->part_1.y;
5673 if (door->width != -1)
5675 g_part_1->width = door->width;
5676 g_part_2->width = door->width;
5678 // special treatment for graphics and screen position of right wing
5679 g_part_2->src_x += door_rect->width - door->width;
5680 door->part_2.x += door_rect->width - door->width;
5683 if (door->height != -1)
5685 g_part_1->height = door->height;
5686 g_part_2->height = door->height;
5688 // special treatment for graphics and screen position of bottom wing
5689 g_part_2->src_y += door_rect->height - door->height;
5690 door->part_2.y += door_rect->height - door->height;
5693 /* set animation delays for the default wings and panels */
5695 door->part_1.step_delay = door->step_delay;
5696 door->part_2.step_delay = door->step_delay;
5697 door->panel.step_delay = door->step_delay;
5699 /* set animation draw order for the default wings */
5701 door->part_1.sort_priority = 2; /* draw left wing over ... */
5702 door->part_2.sort_priority = 1; /* ... right wing */
5704 /* set animation draw offset for the default wings */
5706 if (door->anim_mode & ANIM_HORIZONTAL)
5708 door->part_1.step_xoffset = door->step_offset;
5709 door->part_1.step_yoffset = 0;
5710 door->part_2.step_xoffset = door->step_offset * -1;
5711 door->part_2.step_yoffset = 0;
5713 num_door_steps = g_part_1->width / door->step_offset;
5715 else // ANIM_VERTICAL
5717 door->part_1.step_xoffset = 0;
5718 door->part_1.step_yoffset = door->step_offset;
5719 door->part_2.step_xoffset = 0;
5720 door->part_2.step_yoffset = door->step_offset * -1;
5722 num_door_steps = g_part_1->height / door->step_offset;
5725 /* set animation draw offset for the default panels */
5727 if (door->step_offset > 1)
5729 num_panel_steps = 2 * door_rect->height / door->step_offset;
5730 door->panel.start_step = num_panel_steps - num_door_steps;
5734 num_panel_steps = door_rect->height / door->step_offset;
5735 door->panel.start_step = num_panel_steps - num_door_steps / 2;
5736 door->panel.step_delay *= 2;
5747 for (i = 0; door_part_controls[i].door_token != -1; i++)
5749 struct DoorPartControlInfo *dpc = &door_part_controls[i];
5750 struct DoorPartOrderInfo *dpo = &door_part_order[i];
5752 /* initialize "start_step_opening" and "start_step_closing", if needed */
5753 if (dpc->pos->start_step_opening == 0 &&
5754 dpc->pos->start_step_closing == 0)
5756 // dpc->pos->start_step_opening = dpc->pos->start_step;
5757 dpc->pos->start_step_closing = dpc->pos->start_step;
5760 /* fill structure for door part draw order (sorted below) */
5762 dpo->sort_priority = dpc->pos->sort_priority;
5765 struct DoorPartPosInfo *pos = dpc->pos;
5767 printf(":0: step_xoffset == %d, step_yoffset == %d\n",
5768 pos->step_xoffset, pos->step_yoffset);
5772 /* sort door part controls according to sort_priority and graphic number */
5773 qsort(door_part_order, MAX_DOOR_PARTS,
5774 sizeof(struct DoorPartOrderInfo), compareDoorPartOrderInfo);
5777 unsigned int OpenDoor(unsigned int door_state)
5779 if (door_state & DOOR_COPY_BACK)
5782 if (door_state & DOOR_OPEN_1)
5783 BlitBitmap(bitmap_db_door_1, bitmap_db_door_1,
5784 1 * DXSIZE, 0, DXSIZE, DYSIZE, 0 * DXSIZE, 0);
5786 if (door_state & DOOR_OPEN_2)
5787 BlitBitmap(bitmap_db_door_2, bitmap_db_door_2,
5788 1 * VXSIZE, 0, VXSIZE, VYSIZE, 0 * VXSIZE, 0);
5790 if (door_state & DOOR_OPEN_1)
5791 BlitBitmap(bitmap_db_door, bitmap_db_door,
5792 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
5793 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
5795 if (door_state & DOOR_OPEN_2)
5796 BlitBitmap(bitmap_db_door, bitmap_db_door,
5797 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY2, VXSIZE, VYSIZE,
5798 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
5801 door_state &= ~DOOR_COPY_BACK;
5804 return MoveDoor(door_state);
5807 unsigned int CloseDoor(unsigned int door_state)
5809 unsigned int old_door_state = GetDoorState();
5811 if (!(door_state & DOOR_NO_COPY_BACK))
5814 if (old_door_state & DOOR_OPEN_1)
5815 BlitBitmap(backbuffer, bitmap_db_door_1,
5816 DX, DY, DXSIZE, DYSIZE, 0, 0);
5818 if (old_door_state & DOOR_OPEN_2)
5819 BlitBitmap(backbuffer, bitmap_db_door_2,
5820 VX, VY, VXSIZE, VYSIZE, 0, 0);
5822 if (old_door_state & DOOR_OPEN_1)
5823 BlitBitmap(backbuffer, bitmap_db_door,
5824 DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
5826 if (old_door_state & DOOR_OPEN_2)
5827 BlitBitmap(backbuffer, bitmap_db_door,
5828 VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
5831 door_state &= ~DOOR_NO_COPY_BACK;
5834 return MoveDoor(door_state);
5837 unsigned int GetDoorState()
5839 return MoveDoor(DOOR_GET_STATE);
5842 unsigned int SetDoorState(unsigned int door_state)
5844 return MoveDoor(door_state | DOOR_SET_STATE);
5849 // ========== TEST 1 ===========================================================
5851 int euclid(int a, int b)
5853 return (b ? euclid(b, a % b) : a);
5856 unsigned int MoveDoor(unsigned int door_state)
5859 struct XY panel_pos_list[] =
5861 { DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 },
5862 { DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 },
5865 struct Rect door_rect_list[] =
5867 { DX, DY, DXSIZE, DYSIZE },
5868 { VX, VY, VXSIZE, VYSIZE }
5870 static int door1 = DOOR_OPEN_1;
5871 static int door2 = DOOR_CLOSE_2;
5872 unsigned int door_delay = 0;
5873 unsigned int door_delay_value;
5877 if (door_1.width < 0 || door_1.width > DXSIZE)
5878 door_1.width = DXSIZE;
5879 if (door_1.height < 0 || door_1.height > DYSIZE)
5880 door_1.height = DYSIZE;
5881 if (door_2.width < 0 || door_2.width > VXSIZE)
5882 door_2.width = VXSIZE;
5883 if (door_2.height < 0 || door_2.height > VYSIZE)
5884 door_2.height = VYSIZE;
5887 if (door_state == DOOR_GET_STATE)
5888 return (door1 | door2);
5890 if (door_state & DOOR_SET_STATE)
5892 if (door_state & DOOR_ACTION_1)
5893 door1 = door_state & DOOR_ACTION_1;
5894 if (door_state & DOOR_ACTION_2)
5895 door2 = door_state & DOOR_ACTION_2;
5897 return (door1 | door2);
5900 if (!(door_state & DOOR_FORCE_REDRAW))
5902 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
5903 door_state &= ~DOOR_OPEN_1;
5904 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
5905 door_state &= ~DOOR_CLOSE_1;
5906 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
5907 door_state &= ~DOOR_OPEN_2;
5908 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
5909 door_state &= ~DOOR_CLOSE_2;
5913 door_delay_value = (door_state & DOOR_ACTION_1 ? door_1.step_delay :
5916 if (setup.quick_doors)
5918 stepsize = 20; /* must be chosen to always draw last frame */
5919 door_delay_value = 0;
5923 if (global.autoplay_leveldir)
5925 door_state |= DOOR_NO_DELAY;
5926 door_state &= ~DOOR_CLOSE_ALL;
5930 if (game_status == GAME_MODE_EDITOR)
5931 door_state |= DOOR_NO_DELAY;
5934 if (door_state & DOOR_ACTION)
5936 boolean door_panel_drawn[NUM_DOORS];
5937 boolean panel_has_doors[NUM_DOORS];
5938 boolean door_part_skip[MAX_DOOR_PARTS];
5939 boolean door_part_done[MAX_DOOR_PARTS];
5940 boolean door_part_done_all;
5941 int num_steps[MAX_DOOR_PARTS];
5942 int max_move_delay = 0; // delay for complete animations of all doors
5943 int max_step_delay = 0; // delay (ms) between two animation frames
5944 int num_move_steps = 0; // number of animation steps for all doors
5945 int current_move_delay = 0;
5948 for (i = 0; i < NUM_DOORS; i++)
5949 panel_has_doors[i] = FALSE;
5951 for (i = 0; i < MAX_DOOR_PARTS; i++)
5953 struct DoorPartControlInfo *dpc = &door_part_controls[i];
5954 struct GraphicInfo *g = &graphic_info[dpc->graphic];
5955 int door_token = dpc->door_token;
5957 door_part_done[i] = FALSE;
5958 door_part_skip[i] = (!(door_state & door_token) ||
5963 for (i = 0; i < MAX_DOOR_PARTS; i++)
5965 struct DoorPartControlInfo *dpc = &door_part_controls[i];
5966 struct DoorPartPosInfo *pos = dpc->pos;
5967 int start_step = pos->start_step;
5969 printf("::: ---> %d: start_step == %d [%d]\n",
5970 i, start_step, door_part_done[i]);
5974 for (i = 0; i < MAX_DOOR_PARTS; i++)
5976 int nr = door_part_order[i].nr;
5977 struct DoorPartControlInfo *dpc = &door_part_controls[nr];
5978 struct DoorPartPosInfo *pos = dpc->pos;
5979 struct GraphicInfo *g = &graphic_info[dpc->graphic];
5980 int door_token = dpc->door_token;
5981 int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
5982 boolean is_panel = DOOR_PART_IS_PANEL(nr);
5983 int step_xoffset = ABS(pos->step_xoffset);
5984 int step_yoffset = ABS(pos->step_yoffset);
5985 int step_delay = pos->step_delay;
5986 int current_door_state = door_state & door_token;
5987 boolean door_opening = ((current_door_state & DOOR_OPEN) != 0);
5988 boolean door_closing = ((current_door_state & DOOR_CLOSE) != 0);
5989 boolean part_opening = (is_panel ? door_closing : door_opening);
5990 int start_step = (part_opening ? pos->start_step_opening :
5991 pos->start_step_closing);
5992 float move_xsize = (step_xoffset ? g->width : 0);
5993 float move_ysize = (step_yoffset ? g->height : 0);
5994 int move_xsteps = (step_xoffset ? ceil(move_xsize / step_xoffset) : 0);
5995 int move_ysteps = (step_yoffset ? ceil(move_ysize / step_yoffset) : 0);
5996 int move_steps = (move_xsteps && move_ysteps ?
5997 MIN(move_xsteps, move_ysteps) :
5998 move_xsteps ? move_xsteps : move_ysteps) - start_step;
5999 int move_delay = move_steps * step_delay;
6001 if (door_part_skip[nr])
6005 panel_has_doors[door_index] = TRUE;
6007 max_move_delay = MAX(max_move_delay, move_delay);
6008 max_step_delay = (max_step_delay == 0 ? step_delay :
6009 euclid(max_step_delay, step_delay));
6010 num_steps[nr] = move_steps;
6014 printf("::: %d: move_delay == %d, start_step == %d [%d]\n",
6015 i, move_delay, start_step, door_part_order[i].nr);
6017 if (DOOR_PART_IS_PANEL(i))
6018 printf("::: %d: move_delay == %d, start_step == %d\n",
6019 i, move_delay, start_step);
6024 num_move_steps = max_move_delay / max_step_delay;
6026 door_delay_value = max_step_delay;
6029 door_delay_value *= 10;
6033 printf("::: num_move_steps == %d, max_move_delay == %d, max_step_delay == %d\n", num_move_steps, max_move_delay, max_step_delay);
6036 for (k = 0; k < num_move_steps; k++)
6038 door_part_done_all = TRUE;
6040 for (i = 0; i < NUM_DOORS; i++)
6041 door_panel_drawn[i] = FALSE;
6043 for (i = 0; i < MAX_DOOR_PARTS; i++)
6045 int nr = door_part_order[i].nr;
6046 struct DoorPartControlInfo *dpc = &door_part_controls[nr];
6047 struct DoorPartPosInfo *pos = dpc->pos;
6048 struct GraphicInfo *g = &graphic_info[dpc->graphic];
6049 int door_token = dpc->door_token;
6050 int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
6051 boolean is_panel = DOOR_PART_IS_PANEL(nr);
6053 struct XY *panel_pos = &panel_pos_list[door_index];
6055 struct Rect *door_rect = &door_rect_list[door_index];
6056 Bitmap *bitmap_db_door = (door_token == DOOR_1 ? bitmap_db_door_1 :
6058 Bitmap *bitmap = (is_panel ? bitmap_db_door : g->bitmap);
6059 int current_door_state = door_state & door_token;
6060 boolean door_opening = ((current_door_state & DOOR_OPEN) != 0);
6061 boolean door_closing = !door_opening;
6062 boolean part_opening = (is_panel ? door_closing : door_opening);
6063 boolean part_closing = !part_opening;
6064 int start_step = (part_opening ? pos->start_step_opening :
6065 pos->start_step_closing);
6066 int step_delay = pos->step_delay;
6067 int step_factor = step_delay / max_step_delay;
6068 int k1 = (step_factor ? k / step_factor + 1 : k);
6069 int k2 = (part_opening ? k1 + start_step : num_steps[nr] - k1);
6070 int kk = (k2 < 0 ? 0 : k2);
6071 int src_x, src_y, src_xx, src_yy;
6072 int dst_x, dst_y, dst_xx, dst_yy;
6076 if (k == 0 && is_panel && door_token == DOOR_2)
6077 printf("::: %d, %d\n", g->width, g->height);
6081 if (DOOR_PART_IS_PANEL(nr))
6083 int start_step = pos->start_step;
6085 k2 = (door_closing ? k1 : num_steps[nr] - k1);// - start_step;
6086 kk = (k2 < 0 ? 0 : k2);
6092 if (nr != 16 && nr != 0)
6103 if (door_part_skip[nr])
6107 if (!(door_state & door_token))
6114 if (current_move_delay % step_delay)
6120 if (!door_panel_drawn[door_index])
6123 ClearRectangle(drawto, door_rect->x, door_rect->y,
6124 door_rect->width, door_rect->height);
6126 BlitBitmap(bitmap_db_door, drawto, panel_pos->x, panel_pos->y,
6127 door_rect->width, door_rect->height,
6128 door_rect->x, door_rect->y);
6131 door_panel_drawn[door_index] = TRUE;
6134 // draw opening or closing door parts
6136 if (pos->step_xoffset < 0) // door part on right side
6139 dst_xx = pos->x + ABS(kk * pos->step_xoffset);
6142 if (dst_xx + width > door_rect->width)
6143 width = door_rect->width - dst_xx;
6145 else // door part on left side
6148 dst_xx = pos->x - kk * pos->step_xoffset;
6152 src_xx = ABS(dst_xx);
6156 width = g->width - src_xx;
6158 // printf("::: k == %d [%d] \n", k, start_step);
6161 if (pos->step_yoffset < 0) // door part on bottom side
6164 dst_yy = pos->y + ABS(kk * pos->step_yoffset);
6167 if (dst_yy + height > door_rect->height)
6168 height = door_rect->height - dst_yy;
6170 else // door part on top side
6173 dst_yy = pos->y - kk * pos->step_yoffset;
6177 src_yy = ABS(dst_yy);
6181 height = g->height - src_yy;
6190 src_x = panel_pos->x + src_xx;
6191 src_y = panel_pos->y + src_yy;
6196 src_x = g->src_x + src_xx;
6197 src_y = g->src_y + src_yy;
6200 dst_x = door_rect->x + dst_xx;
6201 dst_y = door_rect->y + dst_yy;
6204 if (DOOR_PART_IS_PANEL(nr))
6206 printf("::: width == %d, height == %d [%d, %d] [%d, %d]\n",
6207 width, height, g->width, g->height, src_x, src_y);
6211 if (width >= 0 && width <= g->width &&
6212 height >= 0 && height <= g->height)
6214 if (is_panel || !pos->draw_masked)
6215 BlitBitmap(bitmap, drawto, src_x, src_y, width, height,
6218 BlitBitmapMasked(bitmap, drawto, src_x, src_y, width, height,
6223 if (DOOR_PART_IS_PANEL(nr))
6225 bitmap = bitmap_db_door;
6226 src_x = panel_pos->x + src_xx;
6227 src_y = panel_pos->y + src_yy;
6229 printf("::: width == %d, height == %d [%d, %d] [%d, %d]\n",
6230 width, height, g->width, g->height, src_x, src_y);
6232 if (width >= 0 && width <= g->width &&
6233 height >= 0 && height <= g->height)
6234 BlitBitmap(bitmap, drawto, src_x, src_y,
6240 redraw_mask |= REDRAW_DOOR_FROM_TOKEN(door_token);
6243 if ((part_opening && (width < 0 || height < 0)) ||
6244 (part_closing && (width >= g->width && height >= g->height)))
6245 door_part_done[nr] = TRUE;
6247 if ((door_opening && (width < 0 || height < 0)) ||
6248 (door_closing && (width >= g->width && height >= g->height)))
6249 door_part_done[nr] = TRUE;
6253 // continue door part animations, but not panel after door has closed
6254 if (!door_part_done[nr] &&
6255 !(is_panel && door_closing && panel_has_doors[door_index]))
6256 door_part_done_all = FALSE;
6258 // continue door part animations, but not panel after door has closed
6259 if (!door_part_done[nr] && !(is_panel && door_closing))
6260 door_part_done_all = FALSE;
6264 if (!door_part_done[nr])
6265 printf("::: k == %d, nr == %d\n", k, nr);
6269 if (!(door_state & DOOR_NO_DELAY))
6273 if (game_status == GAME_MODE_MAIN)
6276 WaitUntilDelayReached(&door_delay, door_delay_value);
6278 current_move_delay += max_step_delay;
6282 door_part_done_all = TRUE;
6284 for (i = 0; i < MAX_DOOR_PARTS; i++)
6285 if (!door_part_done[i] &&
6286 !(DOOR_PART_IS_PANEL(i) && door_closing))
6287 door_part_done_all = FALSE;
6290 if (door_part_done_all)
6296 if (door_state & DOOR_ACTION_1)
6297 door1 = door_state & DOOR_ACTION_1;
6298 if (door_state & DOOR_ACTION_2)
6299 door2 = door_state & DOOR_ACTION_2;
6302 printf("::: DOORS DONE %08x\n", door_state);
6304 printf("::: GO!\n");
6307 return (door1 | door2);
6312 // ========== OLD ==============================================================
6314 unsigned int MoveDoor(unsigned int door_state)
6316 static int door1 = DOOR_OPEN_1;
6317 static int door2 = DOOR_CLOSE_2;
6318 unsigned int door_delay = 0;
6319 unsigned int door_delay_value;
6323 if (door_1.width < 0 || door_1.width > DXSIZE)
6324 door_1.width = DXSIZE;
6325 if (door_1.height < 0 || door_1.height > DYSIZE)
6326 door_1.height = DYSIZE;
6327 if (door_2.width < 0 || door_2.width > VXSIZE)
6328 door_2.width = VXSIZE;
6329 if (door_2.height < 0 || door_2.height > VYSIZE)
6330 door_2.height = VYSIZE;
6333 if (door_state == DOOR_GET_STATE)
6334 return (door1 | door2);
6336 if (door_state & DOOR_SET_STATE)
6338 if (door_state & DOOR_ACTION_1)
6339 door1 = door_state & DOOR_ACTION_1;
6340 if (door_state & DOOR_ACTION_2)
6341 door2 = door_state & DOOR_ACTION_2;
6343 return (door1 | door2);
6346 if (!(door_state & DOOR_FORCE_REDRAW))
6348 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
6349 door_state &= ~DOOR_OPEN_1;
6350 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
6351 door_state &= ~DOOR_CLOSE_1;
6352 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
6353 door_state &= ~DOOR_OPEN_2;
6354 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
6355 door_state &= ~DOOR_CLOSE_2;
6358 door_delay_value = (door_state & DOOR_ACTION_1 ? door_1.step_delay :
6361 // door_delay_value *= 4; // !!! TEST ONLY !!!
6363 if (setup.quick_doors)
6365 stepsize = 20; /* must be chosen to always draw last frame */
6366 door_delay_value = 0;
6369 if (global.autoplay_leveldir)
6371 door_state |= DOOR_NO_DELAY;
6372 door_state &= ~DOOR_CLOSE_ALL;
6376 if (game_status == GAME_MODE_EDITOR)
6377 door_state |= DOOR_NO_DELAY;
6380 if (door_state & DOOR_ACTION)
6383 struct GraphicInfo *g1_left = &graphic_info[IMG_DOOR_1_WING_LEFT];
6384 struct GraphicInfo *g1_right = &graphic_info[IMG_DOOR_1_WING_RIGHT];
6385 struct GraphicInfo *g2_left = &graphic_info[IMG_DOOR_2_WING_LEFT];
6386 struct GraphicInfo *g2_right = &graphic_info[IMG_DOOR_2_WING_RIGHT];
6387 int door_1_left_width = g1_left->width;
6388 int door_1_left_height = g1_left->height;
6389 int door_1_right_width = g1_right->width;
6390 int door_1_right_height = g1_right->height;
6391 int door_2_left_width = g2_left->width;
6392 int door_2_left_height = g2_left->height;
6393 int door_2_right_width = g2_right->width;
6394 int door_2_right_height = g2_right->height;
6395 int door_1_width = MAX(door_1_left_width, door_1_right_width);
6396 int door_1_height = MAX(door_1_left_height, door_1_right_height);
6397 int door_2_width = MAX(door_2_left_width, door_2_right_width);
6398 int door_2_height = MAX(door_2_left_height, door_2_right_height);
6400 boolean handle_door_1 = (door_state & DOOR_ACTION_1);
6401 boolean handle_door_2 = (door_state & DOOR_ACTION_2);
6402 boolean door_1_done = (!handle_door_1);
6403 boolean door_2_done = (!handle_door_2);
6404 boolean door_1_vertical = (door_1.anim_mode & ANIM_VERTICAL);
6405 boolean door_2_vertical = (door_2.anim_mode & ANIM_VERTICAL);
6408 int door_size_1 = (door_1_vertical ? door_1_height : door_1_width);
6409 int door_size_2 = (door_2_vertical ? door_2_height : door_2_width);
6411 int door_size_1 = (door_1_vertical ? DYSIZE : DXSIZE);
6412 int door_size_2 = (door_2_vertical ? VYSIZE : VXSIZE);
6415 int door_size_1 = (door_1_vertical ? door_1.height : door_1.width);
6416 int door_size_2 = (door_2_vertical ? door_2.height : door_2.width);
6418 int max_door_size_1 = (door_1_vertical ? DYSIZE : DXSIZE);
6419 int max_door_size_2 = (door_2_vertical ? VYSIZE : VXSIZE);
6420 // int door_size = (handle_door_1 ? door_size_1 : door_size_2);
6421 int door_size = (handle_door_2 ? door_size_2 : door_size_1);
6422 int max_door_size = (handle_door_1 ? max_door_size_1 : max_door_size_2);
6423 int door_skip = max_door_size - door_size;
6424 int end = door_size;
6425 int start = ((door_state & DOOR_NO_DELAY) ? end : 0);
6428 if (!(door_state & DOOR_NO_DELAY) && !setup.quick_doors)
6430 /* opening door sound has priority over simultaneously closing door */
6431 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
6432 PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
6433 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
6434 PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
6437 for (k = start; k <= end && !(door_1_done && door_2_done); k += stepsize)
6441 Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
6442 GC gc = bitmap->stored_clip_gc;
6445 if (door_state & DOOR_ACTION_1 &&
6446 x * door_1.step_offset <= door_size_1)
6448 int a = MIN(x * door_1.step_offset, end);
6449 int p = (door_state & DOOR_OPEN_1 ? end - a : a);
6453 int i = p + door_skip;
6457 struct GraphicInfo *g_left = &graphic_info[IMG_DOOR_1_WING_LEFT];
6458 struct GraphicInfo *g_right = &graphic_info[IMG_DOOR_1_WING_RIGHT];
6459 Bitmap *bm_left = g_left->bitmap;
6460 Bitmap *bm_right = g_right->bitmap;
6461 GC gc_left = bm_left->stored_clip_gc;
6462 GC gc_right = bm_right->stored_clip_gc;
6465 int classic_dxsize = 100;
6466 int classic_dysize = 280;
6467 boolean classic_door_1_size = (DXSIZE == classic_dxsize &&
6468 DYSIZE == classic_dysize);
6470 if (door_1.anim_mode & ANIM_STATIC_PANEL)
6472 BlitBitmap(bitmap_db_door, drawto,
6473 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1,
6474 DXSIZE, DYSIZE, DX, DY);
6478 BlitBitmap(bitmap_db_door, drawto,
6479 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + p / 2,
6480 DXSIZE, DYSIZE - p / 2, DX, DY);
6483 // printf("::: p == %d\n", p);
6484 ClearRectangle(drawto, DX, DY + DYSIZE - p / 2, DXSIZE, p / 2);
6488 if (door_1.anim_mode & ANIM_HORIZONTAL && x <= DXSIZE)
6491 int src1_x = g_right->src_x;
6492 int src1_y = g_right->src_y;
6493 int src2_x = g_left->src_x + g_left->width - i;
6494 int src2_y = g_left->src_y;
6495 int dst1_x = DX + DXSIZE - i;
6500 int height = DYSIZE;
6502 SetClipOrigin(bm_right, gc_right, dst1_x - src1_x, dst1_y - src1_y);
6503 BlitBitmapMasked(bm_right, drawto, src1_x, src1_y, width, height,
6506 SetClipOrigin(bm_left, gc_left, dst2_x - src2_x, dst2_y - src2_y);
6507 BlitBitmapMasked(bm_left, drawto, src2_x, src2_y, width, height,
6510 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
6511 int src2_x = DXSIZE - i, src2_y = DOOR_GFX_PAGEY1;
6512 int dst1_x = DX + DXSIZE - i, dst1_y = DY;
6513 int dst2_x = DX, dst2_y = DY;
6514 int width = i, height = DYSIZE;
6516 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
6517 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
6520 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
6521 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
6525 else if (door_1.anim_mode & ANIM_VERTICAL && x <= DYSIZE)
6528 int src1_x = g_right->src_x;
6529 int src1_y = g_right->src_y;
6530 int src2_x = g_left->src_x;
6531 int src2_y = g_left->src_y + g_left->height - i;
6533 int dst1_y = DY + DYSIZE - i;
6539 SetClipOrigin(bm_right, gc_right, dst1_x - src1_x, dst1_y - src1_y);
6540 BlitBitmapMasked(bm_right, drawto, src1_x, src1_y, width, height,
6543 SetClipOrigin(bm_left, gc_left, dst2_x - src2_x, dst2_y - src2_y);
6544 BlitBitmapMasked(bm_left, drawto, src2_x, src2_y, width, height,
6547 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
6548 int src2_x = 0, src2_y = DOOR_GFX_PAGEY1 + DYSIZE - i;
6549 int dst1_x = DX, dst1_y = DY + DYSIZE - i;
6550 int dst2_x = DX, dst2_y = DY;
6551 int width = DXSIZE, height = i;
6553 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
6554 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
6557 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
6558 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
6562 else if (classic_door_1_size && x <= DXSIZE) /* ANIM_DEFAULT */
6564 int j = (door_1.anim_mode == ANIM_DEFAULT ? (DXSIZE - i) / 3 : 0);
6567 int src1_x = g_right->src_x;
6568 int src1_y = g_right->src_y;
6569 int src2_x = g_left->src_x + g_left->width - i;
6570 int src2_y = g_left->src_y;
6571 int dst1_x = DX + DXSIZE - i;
6576 int height1 = 63, height2 = DYSIZE / 2 - height1;
6577 int ypos1 = 0, ypos2 = height2;
6578 int ypos3 = DYSIZE / 2, ypos4 = DYSIZE - height2;
6580 SetClipOrigin(bm_right, gc_right,
6581 dst1_x - src1_x, dst1_y - src1_y + j);
6582 BlitBitmapMasked(bm_right, drawto,
6583 src1_x, src1_y + ypos1, width, height2,
6584 dst1_x, dst1_y + ypos1 + j);
6585 BlitBitmapMasked(bm_right, drawto,
6586 src1_x, src1_y + ypos3, width, height1,
6587 dst1_x, dst1_y + ypos3 + j);
6588 SetClipOrigin(bm_left, gc_left,
6589 dst2_x - src2_x, dst2_y - src2_y - j);
6590 BlitBitmapMasked(bm_left, drawto,
6591 src2_x, src2_y + ypos1 + j, width, height2 - j,
6592 dst2_x, dst2_y + ypos1);
6593 BlitBitmapMasked(bm_left, drawto,
6594 src2_x, src2_y + ypos3, width, height1,
6595 dst2_x, dst2_y + ypos3 - j);
6597 SetClipOrigin(bm_left, gc_left,
6598 dst2_x - src2_x, dst2_y - src2_y - j);
6599 BlitBitmapMasked(bm_left, drawto,
6600 src2_x, src2_y + ypos2, width, height1,
6601 dst2_x, dst2_y + ypos2 - j);
6602 BlitBitmapMasked(bm_left, drawto,
6603 src2_x, src2_y + ypos4, width, height2,
6604 dst2_x, dst2_y + ypos4 - j);
6605 SetClipOrigin(bm_right, gc_right,
6606 dst1_x - src1_x, dst1_y - src1_y + j);
6607 BlitBitmapMasked(bm_right, drawto,
6608 src1_x, src1_y + ypos2, width, height1,
6609 dst1_x, dst1_y + ypos2 + j);
6610 BlitBitmapMasked(bm_right, drawto,
6611 src1_x, src1_y + ypos4, width, height2 - j,
6612 dst1_x, dst1_y + ypos4 + j);
6615 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
6616 int src2_x = DXSIZE - i, src2_y = DOOR_GFX_PAGEY1;
6617 int dst1_x = DX + DXSIZE - i, dst1_y = DY;
6618 int dst2_x = DX, dst2_y = DY;
6619 int width = i, height = DYSIZE;
6620 int ypos1 = 63, ypos2 = 77, ypos3 = 140, ypos4 = 203;
6622 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y + j);
6623 BlitBitmapMasked(bitmap, drawto,
6624 src1_x, src1_y, width, ypos2,
6625 dst1_x, dst1_y + j);
6626 BlitBitmapMasked(bitmap, drawto,
6627 src1_x, src1_y + ypos3, width, ypos1,
6628 dst1_x, dst1_y + ypos3 + j);
6629 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y - j);
6630 BlitBitmapMasked(bitmap, drawto,
6631 src2_x, src2_y + j, width, ypos2 - j,
6633 BlitBitmapMasked(bitmap, drawto,
6634 src2_x, src2_y + ypos3, width, ypos1,
6635 dst2_x, dst2_y + ypos3 - j);
6637 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y - j);
6638 BlitBitmapMasked(bitmap, drawto,
6639 src2_x, src2_y + ypos2, width, ypos1,
6640 dst2_x, dst2_y + ypos2 - j);
6641 BlitBitmapMasked(bitmap, drawto,
6642 src2_x, src2_y + ypos4, width, ypos2,
6643 dst2_x, dst2_y + ypos4 - j);
6644 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y + j);
6645 BlitBitmapMasked(bitmap, drawto,
6646 src1_x, src1_y + ypos2, width, ypos1,
6647 dst1_x, dst1_y + ypos2 + j);
6648 BlitBitmapMasked(bitmap, drawto,
6649 src1_x, src1_y + ypos4, width, ypos2 - j,
6650 dst1_x, dst1_y + ypos4 + j);
6653 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
6654 BlitBitmapMasked(bitmap, drawto,
6655 DXSIZE, DOOR_GFX_PAGEY1, i, 77,
6656 DX + DXSIZE - i, DY + j);
6657 BlitBitmapMasked(bitmap, drawto,
6658 DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
6659 DX + DXSIZE - i, DY + 140 + j);
6660 SetClipOrigin(bitmap, gc, DX - DXSIZE + i,
6661 DY - (DOOR_GFX_PAGEY1 + j));
6662 BlitBitmapMasked(bitmap, drawto,
6663 DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
6665 BlitBitmapMasked(bitmap, drawto,
6666 DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
6669 BlitBitmapMasked(bitmap, drawto,
6670 DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
6672 BlitBitmapMasked(bitmap, drawto,
6673 DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
6675 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
6676 BlitBitmapMasked(bitmap, drawto,
6677 DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
6678 DX + DXSIZE - i, DY + 77 + j);
6679 BlitBitmapMasked(bitmap, drawto,
6680 DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
6681 DX + DXSIZE - i, DY + 203 + j);
6686 redraw_mask |= REDRAW_DOOR_1;
6687 door_1_done = (a == end);
6690 if (door_state & DOOR_ACTION_2 &&
6691 x * door_2.step_offset <= door_size_2)
6693 int a = MIN(x * door_2.step_offset, door_size);
6694 int p = (door_state & DOOR_OPEN_2 ? door_size - a : a);
6695 int i = p + door_skip;
6698 struct GraphicInfo *g_left = &graphic_info[IMG_DOOR_2_WING_LEFT];
6699 struct GraphicInfo *g_right = &graphic_info[IMG_DOOR_2_WING_RIGHT];
6700 Bitmap *bm_left = g_left->bitmap;
6701 Bitmap *bm_right = g_right->bitmap;
6702 GC gc_left = bm_left->stored_clip_gc;
6703 GC gc_right = bm_right->stored_clip_gc;
6706 int classic_vxsize = 100;
6707 int classic_vysize = 100;
6708 boolean classic_door_2_size = (VXSIZE == classic_vxsize &&
6709 VYSIZE == classic_vysize);
6711 if (door_2.anim_mode & ANIM_STATIC_PANEL)
6713 BlitBitmap(bitmap_db_door, drawto,
6714 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2,
6715 VXSIZE, VYSIZE, VX, VY);
6717 else if (x <= VYSIZE)
6719 BlitBitmap(bitmap_db_door, drawto,
6720 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + p / 2,
6721 VXSIZE, VYSIZE - p / 2, VX, VY);
6723 ClearRectangle(drawto, VX, VY + VYSIZE - p / 2, VXSIZE, p / 2);
6726 if (door_2.anim_mode & ANIM_HORIZONTAL && x <= VXSIZE)
6729 int src1_x = g_right->src_x;
6730 int src1_y = g_right->src_y;
6731 int src2_x = g_left->src_x + g_left->width - i;
6732 int src2_y = g_left->src_y;
6733 int dst1_x = VX + VXSIZE - i;
6738 int height = VYSIZE;
6740 SetClipOrigin(bm_right, gc_right, dst1_x - src1_x, dst1_y - src1_y);
6741 BlitBitmapMasked(bm_right, drawto, src1_x, src1_y, width, height,
6744 SetClipOrigin(bm_left, gc_left, dst2_x - src2_x, dst2_y - src2_y);
6745 BlitBitmapMasked(bm_left, drawto, src2_x, src2_y, width, height,
6748 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
6749 int src2_x = VXSIZE - i, src2_y = DOOR_GFX_PAGEY2;
6750 int dst1_x = VX + VXSIZE - i, dst1_y = VY;
6751 int dst2_x = VX, dst2_y = VY;
6752 int width = i, height = VYSIZE;
6754 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
6755 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
6758 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
6759 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
6763 else if (door_2.anim_mode & ANIM_VERTICAL && x <= VYSIZE)
6766 int src1_x = g_right->src_x;
6767 int src1_y = g_right->src_y;
6768 int src2_x = g_left->src_x;
6769 int src2_y = g_left->src_y + g_left->height - i;
6771 int dst1_y = VY + VYSIZE - i;
6777 SetClipOrigin(bm_right, gc_right, dst1_x - src1_x, dst1_y - src1_y);
6778 BlitBitmapMasked(bm_right, drawto, src1_x, src1_y, width, height,
6781 SetClipOrigin(bm_left, gc_left, dst2_x - src2_x, dst2_y - src2_y);
6782 BlitBitmapMasked(bm_left, drawto, src2_x, src2_y, width, height,
6785 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
6786 int src2_x = 0, src2_y = DOOR_GFX_PAGEY2 + VYSIZE - i;
6787 int dst1_x = VX, dst1_y = VY + VYSIZE - i;
6788 int dst2_x = VX, dst2_y = VY;
6789 int width = VXSIZE, height = i;
6791 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
6792 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
6795 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
6796 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
6800 else if (classic_door_2_size && x <= VXSIZE) /* ANIM_DEFAULT */
6802 int j = (door_2.anim_mode == ANIM_DEFAULT ? (VXSIZE - i) / 3 : 0);
6805 int src1_x = g_right->src_x;
6806 int src1_y = g_right->src_y;
6807 int src2_x = g_left->src_x + g_left->width - i;
6808 int src2_y = g_left->src_y;
6809 int dst1_x = VX + VXSIZE - i;
6814 int height = VYSIZE / 2;
6815 int ypos1 = 0, ypos2 = VYSIZE / 2;
6817 SetClipOrigin(bm_right, gc_right,
6818 dst1_x - src1_x, dst1_y - src1_y + j);
6819 BlitBitmapMasked(bm_right, drawto,
6820 src1_x, src1_y + ypos1, width, height,
6821 dst1_x, dst1_y + ypos1 + j);
6822 SetClipOrigin(bm_left, gc_left,
6823 dst2_x - src2_x, dst2_y - src2_y - j);
6824 BlitBitmapMasked(bm_left, drawto,
6825 src2_x, src2_y + ypos1 + j, width, height - j,
6826 dst2_x, dst2_y + ypos1);
6828 SetClipOrigin(bm_left, gc_left,
6829 dst2_x - src2_x, dst2_y - src2_y - j);
6830 BlitBitmapMasked(bm_left, drawto,
6831 src2_x, src2_y + ypos2, width, height,
6832 dst2_x, dst2_y + ypos2 - j);
6833 SetClipOrigin(bm_right, gc_right,
6834 dst1_x - src1_x, dst1_y - src1_y + j);
6835 BlitBitmapMasked(bm_right, drawto,
6836 src1_x, src1_y + ypos2, width, height - j,
6837 dst1_x, dst1_y + ypos2 + j);
6839 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
6840 int src2_x = VXSIZE - i, src2_y = DOOR_GFX_PAGEY2;
6841 int dst1_x = VX + VXSIZE - i, dst1_y = VY;
6842 int dst2_x = VX, dst2_y = VY;
6843 int width = i, height = VYSIZE;
6844 int ypos = VYSIZE / 2;
6846 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y + j);
6847 BlitBitmapMasked(bitmap, drawto,
6848 src1_x, src1_y, width, ypos,
6849 dst1_x, dst1_y + j);
6850 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src1_y - j);
6851 BlitBitmapMasked(bitmap, drawto,
6852 src2_x, src2_y + j, width, ypos - j,
6855 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src1_y - j);
6856 BlitBitmapMasked(bitmap, drawto,
6857 src2_x, src2_y + ypos, width, ypos,
6858 dst2_x, dst2_y + ypos - j);
6859 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y + j);
6860 BlitBitmapMasked(bitmap, drawto,
6861 src1_x, src1_y + ypos, width, ypos - j,
6862 dst1_x, dst1_y + ypos + j);
6865 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
6866 BlitBitmapMasked(bitmap, drawto,
6867 VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
6868 VX + VXSIZE - i, VY + j);
6869 SetClipOrigin(bitmap, gc,
6870 VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
6871 BlitBitmapMasked(bitmap, drawto,
6872 VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
6875 BlitBitmapMasked(bitmap, drawto,
6876 VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
6877 i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
6878 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
6879 BlitBitmapMasked(bitmap, drawto,
6880 VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
6882 VX + VXSIZE - i, VY + VYSIZE / 2 + j);
6887 redraw_mask |= REDRAW_DOOR_2;
6888 door_2_done = (a == VXSIZE);
6891 if (!(door_state & DOOR_NO_DELAY))
6895 if (game_status == GAME_MODE_MAIN)
6898 WaitUntilDelayReached(&door_delay, door_delay_value);
6903 if (door_state & DOOR_ACTION_1)
6904 door1 = door_state & DOOR_ACTION_1;
6905 if (door_state & DOOR_ACTION_2)
6906 door2 = door_state & DOOR_ACTION_2;
6908 return (door1 | door2);
6913 void DrawSpecialEditorDoor()
6916 struct GraphicInfo *gfx1 = &graphic_info[IMG_DOOR_2_TOP_BORDER_CORRECTION];
6917 int top_border_width = gfx1->width;
6918 int top_border_height = gfx1->height;
6919 int outer_border = viewport.door_2[GAME_MODE_EDITOR].border_size;
6920 int ex = EX - outer_border;
6921 int ey = EY - outer_border;
6922 int vy = VY - outer_border;
6923 int exsize = EXSIZE + 2 * outer_border;
6925 CloseDoor(DOOR_CLOSE_2);
6927 /* draw bigger level editor toolbox window */
6928 BlitBitmap(gfx1->bitmap, drawto, gfx1->src_x, gfx1->src_y,
6929 top_border_width, top_border_height, ex, ey - top_border_height);
6930 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto, ex, vy,
6931 exsize, EYSIZE - VYSIZE + outer_border, ex, ey);
6933 /* draw bigger level editor toolbox window */
6934 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
6935 DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
6937 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
6938 EX - 6, VY - 4, EXSIZE + 12, EYSIZE - VYSIZE + 4,
6942 redraw_mask |= REDRAW_ALL;
6945 void UndrawSpecialEditorDoor()
6948 struct GraphicInfo *gfx1 = &graphic_info[IMG_DOOR_2_TOP_BORDER_CORRECTION];
6949 int top_border_width = gfx1->width;
6950 int top_border_height = gfx1->height;
6951 int outer_border = viewport.door_2[GAME_MODE_EDITOR].border_size;
6952 int ex = EX - outer_border;
6953 int ey = EY - outer_border;
6954 int ey_top = ey - top_border_height;
6955 int exsize = EXSIZE + 2 * outer_border;
6956 int eysize = EYSIZE + 2 * outer_border;
6958 /* draw normal tape recorder window */
6959 if (graphic_info[IMG_GLOBAL_BORDER].bitmap)
6961 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
6962 ex, ey_top, top_border_width, top_border_height,
6964 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
6965 ex, ey, exsize, eysize, ex, ey);
6969 // if screen background is set to "[NONE]", clear editor toolbox window
6970 ClearRectangle(drawto, ex, ey_top, top_border_width, top_border_height);
6971 ClearRectangle(drawto, ex, ey, exsize, eysize);
6974 /* draw normal tape recorder window */
6975 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
6976 EX - 6, EY - 12, EXSIZE + 12, EYSIZE - VYSIZE + 12,
6980 redraw_mask |= REDRAW_ALL;
6984 /* ---------- new tool button stuff ---------------------------------------- */
6991 struct TextPosInfo *pos;
6994 } toolbutton_info[NUM_TOOL_BUTTONS] =
6997 IMG_REQUEST_BUTTON_GFX_YES, &request.button.yes,
6998 TOOL_CTRL_ID_YES, "yes"
7001 IMG_REQUEST_BUTTON_GFX_NO, &request.button.no,
7002 TOOL_CTRL_ID_NO, "no"
7005 IMG_REQUEST_BUTTON_GFX_CONFIRM, &request.button.confirm,
7006 TOOL_CTRL_ID_CONFIRM, "confirm"
7009 IMG_REQUEST_BUTTON_GFX_PLAYER_1, &request.button.player_1,
7010 TOOL_CTRL_ID_PLAYER_1, "player 1"
7013 IMG_REQUEST_BUTTON_GFX_PLAYER_2, &request.button.player_2,
7014 TOOL_CTRL_ID_PLAYER_2, "player 2"
7017 IMG_REQUEST_BUTTON_GFX_PLAYER_3, &request.button.player_3,
7018 TOOL_CTRL_ID_PLAYER_3, "player 3"
7021 IMG_REQUEST_BUTTON_GFX_PLAYER_4, &request.button.player_4,
7022 TOOL_CTRL_ID_PLAYER_4, "player 4"
7026 void CreateToolButtons()
7030 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
7032 struct GraphicInfo *gfx = &graphic_info[toolbutton_info[i].graphic];
7033 struct TextPosInfo *pos = toolbutton_info[i].pos;
7034 struct GadgetInfo *gi;
7035 Bitmap *deco_bitmap = None;
7036 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
7037 unsigned int event_mask = GD_EVENT_RELEASED;
7040 int gd_x = gfx->src_x;
7041 int gd_y = gfx->src_y;
7042 int gd_xp = gfx->src_x + gfx->pressed_xoffset;
7043 int gd_yp = gfx->src_y + gfx->pressed_yoffset;
7046 if (global.use_envelope_request)
7047 setRequestPosition(&dx, &dy, TRUE);
7049 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
7051 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
7053 getSizedGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr), 0,
7054 pos->size, &deco_bitmap, &deco_x, &deco_y);
7055 deco_xpos = (gfx->width - pos->size) / 2;
7056 deco_ypos = (gfx->height - pos->size) / 2;
7059 gi = CreateGadget(GDI_CUSTOM_ID, id,
7060 GDI_INFO_TEXT, toolbutton_info[i].infotext,
7061 GDI_X, dx + GDI_ACTIVE_POS(pos->x),
7062 GDI_Y, dy + GDI_ACTIVE_POS(pos->y),
7063 GDI_WIDTH, gfx->width,
7064 GDI_HEIGHT, gfx->height,
7065 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
7066 GDI_STATE, GD_BUTTON_UNPRESSED,
7067 GDI_DESIGN_UNPRESSED, gfx->bitmap, gd_x, gd_y,
7068 GDI_DESIGN_PRESSED, gfx->bitmap, gd_xp, gd_yp,
7069 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
7070 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
7071 GDI_DECORATION_SIZE, pos->size, pos->size,
7072 GDI_DECORATION_SHIFTING, 1, 1,
7073 GDI_DIRECT_DRAW, FALSE,
7074 GDI_EVENT_MASK, event_mask,
7075 GDI_CALLBACK_ACTION, HandleToolButtons,
7079 Error(ERR_EXIT, "cannot create gadget");
7081 tool_gadget[id] = gi;
7087 /* graphic position values for tool buttons */
7088 #define TOOL_BUTTON_YES_XPOS 2
7089 #define TOOL_BUTTON_YES_YPOS 250
7090 #define TOOL_BUTTON_YES_GFX_YPOS 0
7091 #define TOOL_BUTTON_YES_XSIZE 46
7092 #define TOOL_BUTTON_YES_YSIZE 28
7093 #define TOOL_BUTTON_NO_XPOS 52
7094 #define TOOL_BUTTON_NO_YPOS TOOL_BUTTON_YES_YPOS
7095 #define TOOL_BUTTON_NO_GFX_YPOS TOOL_BUTTON_YES_GFX_YPOS
7096 #define TOOL_BUTTON_NO_XSIZE TOOL_BUTTON_YES_XSIZE
7097 #define TOOL_BUTTON_NO_YSIZE TOOL_BUTTON_YES_YSIZE
7098 #define TOOL_BUTTON_CONFIRM_XPOS TOOL_BUTTON_YES_XPOS
7099 #define TOOL_BUTTON_CONFIRM_YPOS TOOL_BUTTON_YES_YPOS
7100 #define TOOL_BUTTON_CONFIRM_GFX_YPOS 30
7101 #define TOOL_BUTTON_CONFIRM_XSIZE 96
7102 #define TOOL_BUTTON_CONFIRM_YSIZE TOOL_BUTTON_YES_YSIZE
7103 #define TOOL_BUTTON_PLAYER_XSIZE 30
7104 #define TOOL_BUTTON_PLAYER_YSIZE 30
7105 #define TOOL_BUTTON_PLAYER_GFX_XPOS 5
7106 #define TOOL_BUTTON_PLAYER_GFX_YPOS 185
7107 #define TOOL_BUTTON_PLAYER_XPOS (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
7108 #define TOOL_BUTTON_PLAYER_YPOS (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
7109 #define TOOL_BUTTON_PLAYER1_XPOS (TOOL_BUTTON_PLAYER_XPOS \
7110 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
7111 #define TOOL_BUTTON_PLAYER2_XPOS (TOOL_BUTTON_PLAYER_XPOS \
7112 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
7113 #define TOOL_BUTTON_PLAYER3_XPOS (TOOL_BUTTON_PLAYER_XPOS \
7114 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
7115 #define TOOL_BUTTON_PLAYER4_XPOS (TOOL_BUTTON_PLAYER_XPOS \
7116 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
7117 #define TOOL_BUTTON_PLAYER1_YPOS (TOOL_BUTTON_PLAYER_YPOS \
7118 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
7119 #define TOOL_BUTTON_PLAYER2_YPOS (TOOL_BUTTON_PLAYER_YPOS \
7120 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
7121 #define TOOL_BUTTON_PLAYER3_YPOS (TOOL_BUTTON_PLAYER_YPOS \
7122 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
7123 #define TOOL_BUTTON_PLAYER4_YPOS (TOOL_BUTTON_PLAYER_YPOS \
7124 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
7133 } toolbutton_info[NUM_TOOL_BUTTONS] =
7136 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_GFX_YPOS,
7137 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_YPOS,
7138 TOOL_BUTTON_YES_XSIZE, TOOL_BUTTON_YES_YSIZE,
7143 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_GFX_YPOS,
7144 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_YPOS,
7145 TOOL_BUTTON_NO_XSIZE, TOOL_BUTTON_NO_YSIZE,
7150 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_GFX_YPOS,
7151 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_YPOS,
7152 TOOL_BUTTON_CONFIRM_XSIZE, TOOL_BUTTON_CONFIRM_YSIZE,
7153 TOOL_CTRL_ID_CONFIRM,
7157 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
7158 TOOL_BUTTON_PLAYER1_XPOS, TOOL_BUTTON_PLAYER1_YPOS,
7159 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
7160 TOOL_CTRL_ID_PLAYER_1,
7164 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
7165 TOOL_BUTTON_PLAYER2_XPOS, TOOL_BUTTON_PLAYER2_YPOS,
7166 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
7167 TOOL_CTRL_ID_PLAYER_2,
7171 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
7172 TOOL_BUTTON_PLAYER3_XPOS, TOOL_BUTTON_PLAYER3_YPOS,
7173 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
7174 TOOL_CTRL_ID_PLAYER_3,
7178 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
7179 TOOL_BUTTON_PLAYER4_XPOS, TOOL_BUTTON_PLAYER4_YPOS,
7180 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
7181 TOOL_CTRL_ID_PLAYER_4,
7186 void CreateToolButtons()
7190 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
7192 Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
7193 Bitmap *deco_bitmap = None;
7194 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
7195 struct GadgetInfo *gi;
7196 unsigned int event_mask;
7197 int gd_xoffset, gd_yoffset;
7198 int gd_x1, gd_x2, gd_y;
7201 event_mask = GD_EVENT_RELEASED;
7203 gd_xoffset = toolbutton_info[i].xpos;
7204 gd_yoffset = toolbutton_info[i].ypos;
7205 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
7206 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
7207 gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
7209 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
7211 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
7213 getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr),
7214 &deco_bitmap, &deco_x, &deco_y);
7215 deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
7216 deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
7219 gi = CreateGadget(GDI_CUSTOM_ID, id,
7220 GDI_INFO_TEXT, toolbutton_info[i].infotext,
7221 GDI_X, DX + GDI_ACTIVE_POS(toolbutton_info[i].x),
7222 GDI_Y, DY + GDI_ACTIVE_POS(toolbutton_info[i].y),
7223 GDI_WIDTH, toolbutton_info[i].width,
7224 GDI_HEIGHT, toolbutton_info[i].height,
7225 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
7226 GDI_STATE, GD_BUTTON_UNPRESSED,
7227 GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
7228 GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
7229 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
7230 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
7231 GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
7232 GDI_DECORATION_SHIFTING, 1, 1,
7233 GDI_DIRECT_DRAW, FALSE,
7234 GDI_EVENT_MASK, event_mask,
7235 GDI_CALLBACK_ACTION, HandleToolButtons,
7239 Error(ERR_EXIT, "cannot create gadget");
7241 tool_gadget[id] = gi;
7247 void FreeToolButtons()
7251 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
7252 FreeGadget(tool_gadget[i]);
7255 static void UnmapToolButtons()
7259 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
7260 UnmapGadget(tool_gadget[i]);
7263 static void HandleToolButtons(struct GadgetInfo *gi)
7265 request_gadget_id = gi->custom_id;
7268 static struct Mapping_EM_to_RND_object
7271 boolean is_rnd_to_em_mapping; /* unique mapping EM <-> RND */
7272 boolean is_backside; /* backside of moving element */
7278 em_object_mapping_list[] =
7281 Xblank, TRUE, FALSE,
7285 Yacid_splash_eB, FALSE, FALSE,
7286 EL_ACID_SPLASH_RIGHT, -1, -1
7289 Yacid_splash_wB, FALSE, FALSE,
7290 EL_ACID_SPLASH_LEFT, -1, -1
7293 #ifdef EM_ENGINE_BAD_ROLL
7295 Xstone_force_e, FALSE, FALSE,
7296 EL_ROCK, -1, MV_BIT_RIGHT
7299 Xstone_force_w, FALSE, FALSE,
7300 EL_ROCK, -1, MV_BIT_LEFT
7303 Xnut_force_e, FALSE, FALSE,
7304 EL_NUT, -1, MV_BIT_RIGHT
7307 Xnut_force_w, FALSE, FALSE,
7308 EL_NUT, -1, MV_BIT_LEFT
7311 Xspring_force_e, FALSE, FALSE,
7312 EL_SPRING, -1, MV_BIT_RIGHT
7315 Xspring_force_w, FALSE, FALSE,
7316 EL_SPRING, -1, MV_BIT_LEFT
7319 Xemerald_force_e, FALSE, FALSE,
7320 EL_EMERALD, -1, MV_BIT_RIGHT
7323 Xemerald_force_w, FALSE, FALSE,
7324 EL_EMERALD, -1, MV_BIT_LEFT
7327 Xdiamond_force_e, FALSE, FALSE,
7328 EL_DIAMOND, -1, MV_BIT_RIGHT
7331 Xdiamond_force_w, FALSE, FALSE,
7332 EL_DIAMOND, -1, MV_BIT_LEFT
7335 Xbomb_force_e, FALSE, FALSE,
7336 EL_BOMB, -1, MV_BIT_RIGHT
7339 Xbomb_force_w, FALSE, FALSE,
7340 EL_BOMB, -1, MV_BIT_LEFT
7342 #endif /* EM_ENGINE_BAD_ROLL */
7345 Xstone, TRUE, FALSE,
7349 Xstone_pause, FALSE, FALSE,
7353 Xstone_fall, FALSE, FALSE,
7357 Ystone_s, FALSE, FALSE,
7358 EL_ROCK, ACTION_FALLING, -1
7361 Ystone_sB, FALSE, TRUE,
7362 EL_ROCK, ACTION_FALLING, -1
7365 Ystone_e, FALSE, FALSE,
7366 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
7369 Ystone_eB, FALSE, TRUE,
7370 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
7373 Ystone_w, FALSE, FALSE,
7374 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
7377 Ystone_wB, FALSE, TRUE,
7378 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
7385 Xnut_pause, FALSE, FALSE,
7389 Xnut_fall, FALSE, FALSE,
7393 Ynut_s, FALSE, FALSE,
7394 EL_NUT, ACTION_FALLING, -1
7397 Ynut_sB, FALSE, TRUE,
7398 EL_NUT, ACTION_FALLING, -1
7401 Ynut_e, FALSE, FALSE,
7402 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
7405 Ynut_eB, FALSE, TRUE,
7406 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
7409 Ynut_w, FALSE, FALSE,
7410 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
7413 Ynut_wB, FALSE, TRUE,
7414 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
7417 Xbug_n, TRUE, FALSE,
7421 Xbug_e, TRUE, FALSE,
7422 EL_BUG_RIGHT, -1, -1
7425 Xbug_s, TRUE, FALSE,
7429 Xbug_w, TRUE, FALSE,
7433 Xbug_gon, FALSE, FALSE,
7437 Xbug_goe, FALSE, FALSE,
7438 EL_BUG_RIGHT, -1, -1
7441 Xbug_gos, FALSE, FALSE,
7445 Xbug_gow, FALSE, FALSE,
7449 Ybug_n, FALSE, FALSE,
7450 EL_BUG, ACTION_MOVING, MV_BIT_UP
7453 Ybug_nB, FALSE, TRUE,
7454 EL_BUG, ACTION_MOVING, MV_BIT_UP
7457 Ybug_e, FALSE, FALSE,
7458 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
7461 Ybug_eB, FALSE, TRUE,
7462 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
7465 Ybug_s, FALSE, FALSE,
7466 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
7469 Ybug_sB, FALSE, TRUE,
7470 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
7473 Ybug_w, FALSE, FALSE,
7474 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
7477 Ybug_wB, FALSE, TRUE,
7478 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
7481 Ybug_w_n, FALSE, FALSE,
7482 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
7485 Ybug_n_e, FALSE, FALSE,
7486 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
7489 Ybug_e_s, FALSE, FALSE,
7490 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
7493 Ybug_s_w, FALSE, FALSE,
7494 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
7497 Ybug_e_n, FALSE, FALSE,
7498 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
7501 Ybug_s_e, FALSE, FALSE,
7502 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
7505 Ybug_w_s, FALSE, FALSE,
7506 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
7509 Ybug_n_w, FALSE, FALSE,
7510 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
7513 Ybug_stone, FALSE, FALSE,
7514 EL_BUG, ACTION_SMASHED_BY_ROCK, -1
7517 Ybug_spring, FALSE, FALSE,
7518 EL_BUG, ACTION_SMASHED_BY_SPRING, -1
7521 Xtank_n, TRUE, FALSE,
7522 EL_SPACESHIP_UP, -1, -1
7525 Xtank_e, TRUE, FALSE,
7526 EL_SPACESHIP_RIGHT, -1, -1
7529 Xtank_s, TRUE, FALSE,
7530 EL_SPACESHIP_DOWN, -1, -1
7533 Xtank_w, TRUE, FALSE,
7534 EL_SPACESHIP_LEFT, -1, -1
7537 Xtank_gon, FALSE, FALSE,
7538 EL_SPACESHIP_UP, -1, -1
7541 Xtank_goe, FALSE, FALSE,
7542 EL_SPACESHIP_RIGHT, -1, -1
7545 Xtank_gos, FALSE, FALSE,
7546 EL_SPACESHIP_DOWN, -1, -1
7549 Xtank_gow, FALSE, FALSE,
7550 EL_SPACESHIP_LEFT, -1, -1
7553 Ytank_n, FALSE, FALSE,
7554 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
7557 Ytank_nB, FALSE, TRUE,
7558 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
7561 Ytank_e, FALSE, FALSE,
7562 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
7565 Ytank_eB, FALSE, TRUE,
7566 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
7569 Ytank_s, FALSE, FALSE,
7570 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
7573 Ytank_sB, FALSE, TRUE,
7574 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
7577 Ytank_w, FALSE, FALSE,
7578 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
7581 Ytank_wB, FALSE, TRUE,
7582 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
7585 Ytank_w_n, FALSE, FALSE,
7586 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
7589 Ytank_n_e, FALSE, FALSE,
7590 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
7593 Ytank_e_s, FALSE, FALSE,
7594 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
7597 Ytank_s_w, FALSE, FALSE,
7598 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
7601 Ytank_e_n, FALSE, FALSE,
7602 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
7605 Ytank_s_e, FALSE, FALSE,
7606 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
7609 Ytank_w_s, FALSE, FALSE,
7610 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
7613 Ytank_n_w, FALSE, FALSE,
7614 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
7617 Ytank_stone, FALSE, FALSE,
7618 EL_SPACESHIP, ACTION_SMASHED_BY_ROCK, -1
7621 Ytank_spring, FALSE, FALSE,
7622 EL_SPACESHIP, ACTION_SMASHED_BY_SPRING, -1
7625 Xandroid, TRUE, FALSE,
7626 EL_EMC_ANDROID, ACTION_ACTIVE, -1
7629 Xandroid_1_n, FALSE, FALSE,
7630 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
7633 Xandroid_2_n, FALSE, FALSE,
7634 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
7637 Xandroid_1_e, FALSE, FALSE,
7638 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
7641 Xandroid_2_e, FALSE, FALSE,
7642 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
7645 Xandroid_1_w, FALSE, FALSE,
7646 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
7649 Xandroid_2_w, FALSE, FALSE,
7650 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
7653 Xandroid_1_s, FALSE, FALSE,
7654 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
7657 Xandroid_2_s, FALSE, FALSE,
7658 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
7661 Yandroid_n, FALSE, FALSE,
7662 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
7665 Yandroid_nB, FALSE, TRUE,
7666 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
7669 Yandroid_ne, FALSE, FALSE,
7670 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPRIGHT
7673 Yandroid_neB, FALSE, TRUE,
7674 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPRIGHT
7677 Yandroid_e, FALSE, FALSE,
7678 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
7681 Yandroid_eB, FALSE, TRUE,
7682 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
7685 Yandroid_se, FALSE, FALSE,
7686 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNRIGHT
7689 Yandroid_seB, FALSE, TRUE,
7690 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNRIGHT
7693 Yandroid_s, FALSE, FALSE,
7694 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
7697 Yandroid_sB, FALSE, TRUE,
7698 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
7701 Yandroid_sw, FALSE, FALSE,
7702 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNLEFT
7705 Yandroid_swB, FALSE, TRUE,
7706 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNLEFT
7709 Yandroid_w, FALSE, FALSE,
7710 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
7713 Yandroid_wB, FALSE, TRUE,
7714 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
7717 Yandroid_nw, FALSE, FALSE,
7718 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPLEFT
7721 Yandroid_nwB, FALSE, TRUE,
7722 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPLEFT
7725 Xspring, TRUE, FALSE,
7729 Xspring_pause, FALSE, FALSE,
7733 Xspring_e, FALSE, FALSE,
7737 Xspring_w, FALSE, FALSE,
7741 Xspring_fall, FALSE, FALSE,
7745 Yspring_s, FALSE, FALSE,
7746 EL_SPRING, ACTION_FALLING, -1
7749 Yspring_sB, FALSE, TRUE,
7750 EL_SPRING, ACTION_FALLING, -1
7753 Yspring_e, FALSE, FALSE,
7754 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
7757 Yspring_eB, FALSE, TRUE,
7758 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
7761 Yspring_w, FALSE, FALSE,
7762 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
7765 Yspring_wB, FALSE, TRUE,
7766 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
7769 Yspring_kill_e, FALSE, FALSE,
7770 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
7773 Yspring_kill_eB, FALSE, TRUE,
7774 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
7777 Yspring_kill_w, FALSE, FALSE,
7778 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
7781 Yspring_kill_wB, FALSE, TRUE,
7782 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
7785 Xeater_n, TRUE, FALSE,
7786 EL_YAMYAM_UP, -1, -1
7789 Xeater_e, TRUE, FALSE,
7790 EL_YAMYAM_RIGHT, -1, -1
7793 Xeater_w, TRUE, FALSE,
7794 EL_YAMYAM_LEFT, -1, -1
7797 Xeater_s, TRUE, FALSE,
7798 EL_YAMYAM_DOWN, -1, -1
7801 Yeater_n, FALSE, FALSE,
7802 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
7805 Yeater_nB, FALSE, TRUE,
7806 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
7809 Yeater_e, FALSE, FALSE,
7810 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
7813 Yeater_eB, FALSE, TRUE,
7814 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
7817 Yeater_s, FALSE, FALSE,
7818 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
7821 Yeater_sB, FALSE, TRUE,
7822 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
7825 Yeater_w, FALSE, FALSE,
7826 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
7829 Yeater_wB, FALSE, TRUE,
7830 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
7833 Yeater_stone, FALSE, FALSE,
7834 EL_YAMYAM, ACTION_SMASHED_BY_ROCK, -1
7837 Yeater_spring, FALSE, FALSE,
7838 EL_YAMYAM, ACTION_SMASHED_BY_SPRING, -1
7841 Xalien, TRUE, FALSE,
7845 Xalien_pause, FALSE, FALSE,
7849 Yalien_n, FALSE, FALSE,
7850 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
7853 Yalien_nB, FALSE, TRUE,
7854 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
7857 Yalien_e, FALSE, FALSE,
7858 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
7861 Yalien_eB, FALSE, TRUE,
7862 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
7865 Yalien_s, FALSE, FALSE,
7866 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
7869 Yalien_sB, FALSE, TRUE,
7870 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
7873 Yalien_w, FALSE, FALSE,
7874 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
7877 Yalien_wB, FALSE, TRUE,
7878 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
7881 Yalien_stone, FALSE, FALSE,
7882 EL_ROBOT, ACTION_SMASHED_BY_ROCK, -1
7885 Yalien_spring, FALSE, FALSE,
7886 EL_ROBOT, ACTION_SMASHED_BY_SPRING, -1
7889 Xemerald, TRUE, FALSE,
7893 Xemerald_pause, FALSE, FALSE,
7897 Xemerald_fall, FALSE, FALSE,
7901 Xemerald_shine, FALSE, FALSE,
7902 EL_EMERALD, ACTION_TWINKLING, -1
7905 Yemerald_s, FALSE, FALSE,
7906 EL_EMERALD, ACTION_FALLING, -1
7909 Yemerald_sB, FALSE, TRUE,
7910 EL_EMERALD, ACTION_FALLING, -1
7913 Yemerald_e, FALSE, FALSE,
7914 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
7917 Yemerald_eB, FALSE, TRUE,
7918 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
7921 Yemerald_w, FALSE, FALSE,
7922 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
7925 Yemerald_wB, FALSE, TRUE,
7926 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
7929 Yemerald_eat, FALSE, FALSE,
7930 EL_EMERALD, ACTION_COLLECTING, -1
7933 Yemerald_stone, FALSE, FALSE,
7934 EL_NUT, ACTION_BREAKING, -1
7937 Xdiamond, TRUE, FALSE,
7941 Xdiamond_pause, FALSE, FALSE,
7945 Xdiamond_fall, FALSE, FALSE,
7949 Xdiamond_shine, FALSE, FALSE,
7950 EL_DIAMOND, ACTION_TWINKLING, -1
7953 Ydiamond_s, FALSE, FALSE,
7954 EL_DIAMOND, ACTION_FALLING, -1
7957 Ydiamond_sB, FALSE, TRUE,
7958 EL_DIAMOND, ACTION_FALLING, -1
7961 Ydiamond_e, FALSE, FALSE,
7962 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
7965 Ydiamond_eB, FALSE, TRUE,
7966 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
7969 Ydiamond_w, FALSE, FALSE,
7970 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
7973 Ydiamond_wB, FALSE, TRUE,
7974 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
7977 Ydiamond_eat, FALSE, FALSE,
7978 EL_DIAMOND, ACTION_COLLECTING, -1
7981 Ydiamond_stone, FALSE, FALSE,
7982 EL_DIAMOND, ACTION_SMASHED_BY_ROCK, -1
7985 Xdrip_fall, TRUE, FALSE,
7986 EL_AMOEBA_DROP, -1, -1
7989 Xdrip_stretch, FALSE, FALSE,
7990 EL_AMOEBA_DROP, ACTION_FALLING, -1
7993 Xdrip_stretchB, FALSE, TRUE,
7994 EL_AMOEBA_DROP, ACTION_FALLING, -1
7997 Xdrip_eat, FALSE, FALSE,
7998 EL_AMOEBA_DROP, ACTION_GROWING, -1
8001 Ydrip_s1, FALSE, FALSE,
8002 EL_AMOEBA_DROP, ACTION_FALLING, -1
8005 Ydrip_s1B, FALSE, TRUE,
8006 EL_AMOEBA_DROP, ACTION_FALLING, -1
8009 Ydrip_s2, FALSE, FALSE,
8010 EL_AMOEBA_DROP, ACTION_FALLING, -1
8013 Ydrip_s2B, FALSE, TRUE,
8014 EL_AMOEBA_DROP, ACTION_FALLING, -1
8021 Xbomb_pause, FALSE, FALSE,
8025 Xbomb_fall, FALSE, FALSE,
8029 Ybomb_s, FALSE, FALSE,
8030 EL_BOMB, ACTION_FALLING, -1
8033 Ybomb_sB, FALSE, TRUE,
8034 EL_BOMB, ACTION_FALLING, -1
8037 Ybomb_e, FALSE, FALSE,
8038 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
8041 Ybomb_eB, FALSE, TRUE,
8042 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
8045 Ybomb_w, FALSE, FALSE,
8046 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
8049 Ybomb_wB, FALSE, TRUE,
8050 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
8053 Ybomb_eat, FALSE, FALSE,
8054 EL_BOMB, ACTION_ACTIVATING, -1
8057 Xballoon, TRUE, FALSE,
8061 Yballoon_n, FALSE, FALSE,
8062 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
8065 Yballoon_nB, FALSE, TRUE,
8066 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
8069 Yballoon_e, FALSE, FALSE,
8070 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
8073 Yballoon_eB, FALSE, TRUE,
8074 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
8077 Yballoon_s, FALSE, FALSE,
8078 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
8081 Yballoon_sB, FALSE, TRUE,
8082 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
8085 Yballoon_w, FALSE, FALSE,
8086 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
8089 Yballoon_wB, FALSE, TRUE,
8090 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
8093 Xgrass, TRUE, FALSE,
8094 EL_EMC_GRASS, -1, -1
8097 Ygrass_nB, FALSE, FALSE,
8098 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_UP
8101 Ygrass_eB, FALSE, FALSE,
8102 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_RIGHT
8105 Ygrass_sB, FALSE, FALSE,
8106 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_DOWN
8109 Ygrass_wB, FALSE, FALSE,
8110 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_LEFT
8117 Ydirt_nB, FALSE, FALSE,
8118 EL_SAND, ACTION_DIGGING, MV_BIT_UP
8121 Ydirt_eB, FALSE, FALSE,
8122 EL_SAND, ACTION_DIGGING, MV_BIT_RIGHT
8125 Ydirt_sB, FALSE, FALSE,
8126 EL_SAND, ACTION_DIGGING, MV_BIT_DOWN
8129 Ydirt_wB, FALSE, FALSE,
8130 EL_SAND, ACTION_DIGGING, MV_BIT_LEFT
8133 Xacid_ne, TRUE, FALSE,
8134 EL_ACID_POOL_TOPRIGHT, -1, -1
8137 Xacid_se, TRUE, FALSE,
8138 EL_ACID_POOL_BOTTOMRIGHT, -1, -1
8141 Xacid_s, TRUE, FALSE,
8142 EL_ACID_POOL_BOTTOM, -1, -1
8145 Xacid_sw, TRUE, FALSE,
8146 EL_ACID_POOL_BOTTOMLEFT, -1, -1
8149 Xacid_nw, TRUE, FALSE,
8150 EL_ACID_POOL_TOPLEFT, -1, -1
8153 Xacid_1, TRUE, FALSE,
8157 Xacid_2, FALSE, FALSE,
8161 Xacid_3, FALSE, FALSE,
8165 Xacid_4, FALSE, FALSE,
8169 Xacid_5, FALSE, FALSE,
8173 Xacid_6, FALSE, FALSE,
8177 Xacid_7, FALSE, FALSE,
8181 Xacid_8, FALSE, FALSE,
8185 Xball_1, TRUE, FALSE,
8186 EL_EMC_MAGIC_BALL, -1, -1
8189 Xball_1B, FALSE, FALSE,
8190 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
8193 Xball_2, FALSE, FALSE,
8194 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
8197 Xball_2B, FALSE, FALSE,
8198 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
8201 Yball_eat, FALSE, FALSE,
8202 EL_EMC_MAGIC_BALL, ACTION_DROPPING, -1
8205 Ykey_1_eat, FALSE, FALSE,
8206 EL_EM_KEY_1, ACTION_COLLECTING, -1
8209 Ykey_2_eat, FALSE, FALSE,
8210 EL_EM_KEY_2, ACTION_COLLECTING, -1
8213 Ykey_3_eat, FALSE, FALSE,
8214 EL_EM_KEY_3, ACTION_COLLECTING, -1
8217 Ykey_4_eat, FALSE, FALSE,
8218 EL_EM_KEY_4, ACTION_COLLECTING, -1
8221 Ykey_5_eat, FALSE, FALSE,
8222 EL_EMC_KEY_5, ACTION_COLLECTING, -1
8225 Ykey_6_eat, FALSE, FALSE,
8226 EL_EMC_KEY_6, ACTION_COLLECTING, -1
8229 Ykey_7_eat, FALSE, FALSE,
8230 EL_EMC_KEY_7, ACTION_COLLECTING, -1
8233 Ykey_8_eat, FALSE, FALSE,
8234 EL_EMC_KEY_8, ACTION_COLLECTING, -1
8237 Ylenses_eat, FALSE, FALSE,
8238 EL_EMC_LENSES, ACTION_COLLECTING, -1
8241 Ymagnify_eat, FALSE, FALSE,
8242 EL_EMC_MAGNIFIER, ACTION_COLLECTING, -1
8245 Ygrass_eat, FALSE, FALSE,
8246 EL_EMC_GRASS, ACTION_SNAPPING, -1
8249 Ydirt_eat, FALSE, FALSE,
8250 EL_SAND, ACTION_SNAPPING, -1
8253 Xgrow_ns, TRUE, FALSE,
8254 EL_EXPANDABLE_WALL_VERTICAL, -1, -1
8257 Ygrow_ns_eat, FALSE, FALSE,
8258 EL_EXPANDABLE_WALL_VERTICAL, ACTION_GROWING, -1
8261 Xgrow_ew, TRUE, FALSE,
8262 EL_EXPANDABLE_WALL_HORIZONTAL, -1, -1
8265 Ygrow_ew_eat, FALSE, FALSE,
8266 EL_EXPANDABLE_WALL_HORIZONTAL, ACTION_GROWING, -1
8269 Xwonderwall, TRUE, FALSE,
8270 EL_MAGIC_WALL, -1, -1
8273 XwonderwallB, FALSE, FALSE,
8274 EL_MAGIC_WALL, ACTION_ACTIVE, -1
8277 Xamoeba_1, TRUE, FALSE,
8278 EL_AMOEBA_DRY, ACTION_OTHER, -1
8281 Xamoeba_2, FALSE, FALSE,
8282 EL_AMOEBA_DRY, ACTION_OTHER, -1
8285 Xamoeba_3, FALSE, FALSE,
8286 EL_AMOEBA_DRY, ACTION_OTHER, -1
8289 Xamoeba_4, FALSE, FALSE,
8290 EL_AMOEBA_DRY, ACTION_OTHER, -1
8293 Xamoeba_5, TRUE, FALSE,
8294 EL_AMOEBA_WET, ACTION_OTHER, -1
8297 Xamoeba_6, FALSE, FALSE,
8298 EL_AMOEBA_WET, ACTION_OTHER, -1
8301 Xamoeba_7, FALSE, FALSE,
8302 EL_AMOEBA_WET, ACTION_OTHER, -1
8305 Xamoeba_8, FALSE, FALSE,
8306 EL_AMOEBA_WET, ACTION_OTHER, -1
8309 Xdoor_1, TRUE, FALSE,
8310 EL_EM_GATE_1, -1, -1
8313 Xdoor_2, TRUE, FALSE,
8314 EL_EM_GATE_2, -1, -1
8317 Xdoor_3, TRUE, FALSE,
8318 EL_EM_GATE_3, -1, -1
8321 Xdoor_4, TRUE, FALSE,
8322 EL_EM_GATE_4, -1, -1
8325 Xdoor_5, TRUE, FALSE,
8326 EL_EMC_GATE_5, -1, -1
8329 Xdoor_6, TRUE, FALSE,
8330 EL_EMC_GATE_6, -1, -1
8333 Xdoor_7, TRUE, FALSE,
8334 EL_EMC_GATE_7, -1, -1
8337 Xdoor_8, TRUE, FALSE,
8338 EL_EMC_GATE_8, -1, -1
8341 Xkey_1, TRUE, FALSE,
8345 Xkey_2, TRUE, FALSE,
8349 Xkey_3, TRUE, FALSE,
8353 Xkey_4, TRUE, FALSE,
8357 Xkey_5, TRUE, FALSE,
8358 EL_EMC_KEY_5, -1, -1
8361 Xkey_6, TRUE, FALSE,
8362 EL_EMC_KEY_6, -1, -1
8365 Xkey_7, TRUE, FALSE,
8366 EL_EMC_KEY_7, -1, -1
8369 Xkey_8, TRUE, FALSE,
8370 EL_EMC_KEY_8, -1, -1
8373 Xwind_n, TRUE, FALSE,
8374 EL_BALLOON_SWITCH_UP, -1, -1
8377 Xwind_e, TRUE, FALSE,
8378 EL_BALLOON_SWITCH_RIGHT, -1, -1
8381 Xwind_s, TRUE, FALSE,
8382 EL_BALLOON_SWITCH_DOWN, -1, -1
8385 Xwind_w, TRUE, FALSE,
8386 EL_BALLOON_SWITCH_LEFT, -1, -1
8389 Xwind_nesw, TRUE, FALSE,
8390 EL_BALLOON_SWITCH_ANY, -1, -1
8393 Xwind_stop, TRUE, FALSE,
8394 EL_BALLOON_SWITCH_NONE, -1, -1
8398 EL_EM_EXIT_CLOSED, -1, -1
8401 Xexit_1, TRUE, FALSE,
8402 EL_EM_EXIT_OPEN, -1, -1
8405 Xexit_2, FALSE, FALSE,
8406 EL_EM_EXIT_OPEN, -1, -1
8409 Xexit_3, FALSE, FALSE,
8410 EL_EM_EXIT_OPEN, -1, -1
8413 Xdynamite, TRUE, FALSE,
8414 EL_EM_DYNAMITE, -1, -1
8417 Ydynamite_eat, FALSE, FALSE,
8418 EL_EM_DYNAMITE, ACTION_COLLECTING, -1
8421 Xdynamite_1, TRUE, FALSE,
8422 EL_EM_DYNAMITE_ACTIVE, -1, -1
8425 Xdynamite_2, FALSE, FALSE,
8426 EL_EM_DYNAMITE_ACTIVE, -1, -1
8429 Xdynamite_3, FALSE, FALSE,
8430 EL_EM_DYNAMITE_ACTIVE, -1, -1
8433 Xdynamite_4, FALSE, FALSE,
8434 EL_EM_DYNAMITE_ACTIVE, -1, -1
8437 Xbumper, TRUE, FALSE,
8438 EL_EMC_SPRING_BUMPER, -1, -1
8441 XbumperB, FALSE, FALSE,
8442 EL_EMC_SPRING_BUMPER, ACTION_ACTIVE, -1
8445 Xwheel, TRUE, FALSE,
8446 EL_ROBOT_WHEEL, -1, -1
8449 XwheelB, FALSE, FALSE,
8450 EL_ROBOT_WHEEL, ACTION_ACTIVE, -1
8453 Xswitch, TRUE, FALSE,
8454 EL_EMC_MAGIC_BALL_SWITCH, -1, -1
8457 XswitchB, FALSE, FALSE,
8458 EL_EMC_MAGIC_BALL_SWITCH, ACTION_ACTIVE, -1
8462 EL_QUICKSAND_EMPTY, -1, -1
8465 Xsand_stone, TRUE, FALSE,
8466 EL_QUICKSAND_FULL, -1, -1
8469 Xsand_stonein_1, FALSE, TRUE,
8470 EL_ROCK, ACTION_FILLING, -1
8473 Xsand_stonein_2, FALSE, TRUE,
8474 EL_ROCK, ACTION_FILLING, -1
8477 Xsand_stonein_3, FALSE, TRUE,
8478 EL_ROCK, ACTION_FILLING, -1
8481 Xsand_stonein_4, FALSE, TRUE,
8482 EL_ROCK, ACTION_FILLING, -1
8486 Xsand_stonesand_1, FALSE, FALSE,
8487 EL_QUICKSAND_EMPTYING, -1, -1
8490 Xsand_stonesand_2, FALSE, FALSE,
8491 EL_QUICKSAND_EMPTYING, -1, -1
8494 Xsand_stonesand_3, FALSE, FALSE,
8495 EL_QUICKSAND_EMPTYING, -1, -1
8498 Xsand_stonesand_4, FALSE, FALSE,
8499 EL_QUICKSAND_EMPTYING, -1, -1
8502 Xsand_stonesand_quickout_1, FALSE, FALSE,
8503 EL_QUICKSAND_EMPTYING, -1, -1
8506 Xsand_stonesand_quickout_2, FALSE, FALSE,
8507 EL_QUICKSAND_EMPTYING, -1, -1
8511 Xsand_stonesand_1, FALSE, FALSE,
8512 EL_QUICKSAND_FULL, -1, -1
8515 Xsand_stonesand_2, FALSE, FALSE,
8516 EL_QUICKSAND_FULL, -1, -1
8519 Xsand_stonesand_3, FALSE, FALSE,
8520 EL_QUICKSAND_FULL, -1, -1
8523 Xsand_stonesand_4, FALSE, FALSE,
8524 EL_QUICKSAND_FULL, -1, -1
8528 Xsand_stoneout_1, FALSE, FALSE,
8529 EL_ROCK, ACTION_EMPTYING, -1
8532 Xsand_stoneout_2, FALSE, FALSE,
8533 EL_ROCK, ACTION_EMPTYING, -1
8537 Xsand_sandstone_1, FALSE, FALSE,
8538 EL_QUICKSAND_FILLING, -1, -1
8541 Xsand_sandstone_2, FALSE, FALSE,
8542 EL_QUICKSAND_FILLING, -1, -1
8545 Xsand_sandstone_3, FALSE, FALSE,
8546 EL_QUICKSAND_FILLING, -1, -1
8549 Xsand_sandstone_4, FALSE, FALSE,
8550 EL_QUICKSAND_FILLING, -1, -1
8554 Xsand_sandstone_1, FALSE, FALSE,
8555 EL_QUICKSAND_FULL, -1, -1
8558 Xsand_sandstone_2, FALSE, FALSE,
8559 EL_QUICKSAND_FULL, -1, -1
8562 Xsand_sandstone_3, FALSE, FALSE,
8563 EL_QUICKSAND_FULL, -1, -1
8566 Xsand_sandstone_4, FALSE, FALSE,
8567 EL_QUICKSAND_FULL, -1, -1
8571 Xplant, TRUE, FALSE,
8572 EL_EMC_PLANT, -1, -1
8575 Yplant, FALSE, FALSE,
8576 EL_EMC_PLANT, -1, -1
8579 Xlenses, TRUE, FALSE,
8580 EL_EMC_LENSES, -1, -1
8583 Xmagnify, TRUE, FALSE,
8584 EL_EMC_MAGNIFIER, -1, -1
8587 Xdripper, TRUE, FALSE,
8588 EL_EMC_DRIPPER, -1, -1
8591 XdripperB, FALSE, FALSE,
8592 EL_EMC_DRIPPER, ACTION_ACTIVE, -1
8595 Xfake_blank, TRUE, FALSE,
8596 EL_INVISIBLE_WALL, -1, -1
8599 Xfake_blankB, FALSE, FALSE,
8600 EL_INVISIBLE_WALL, ACTION_ACTIVE, -1
8603 Xfake_grass, TRUE, FALSE,
8604 EL_EMC_FAKE_GRASS, -1, -1
8607 Xfake_grassB, FALSE, FALSE,
8608 EL_EMC_FAKE_GRASS, ACTION_ACTIVE, -1
8611 Xfake_door_1, TRUE, FALSE,
8612 EL_EM_GATE_1_GRAY, -1, -1
8615 Xfake_door_2, TRUE, FALSE,
8616 EL_EM_GATE_2_GRAY, -1, -1
8619 Xfake_door_3, TRUE, FALSE,
8620 EL_EM_GATE_3_GRAY, -1, -1
8623 Xfake_door_4, TRUE, FALSE,
8624 EL_EM_GATE_4_GRAY, -1, -1
8627 Xfake_door_5, TRUE, FALSE,
8628 EL_EMC_GATE_5_GRAY, -1, -1
8631 Xfake_door_6, TRUE, FALSE,
8632 EL_EMC_GATE_6_GRAY, -1, -1
8635 Xfake_door_7, TRUE, FALSE,
8636 EL_EMC_GATE_7_GRAY, -1, -1
8639 Xfake_door_8, TRUE, FALSE,
8640 EL_EMC_GATE_8_GRAY, -1, -1
8643 Xfake_acid_1, TRUE, FALSE,
8644 EL_EMC_FAKE_ACID, -1, -1
8647 Xfake_acid_2, FALSE, FALSE,
8648 EL_EMC_FAKE_ACID, -1, -1
8651 Xfake_acid_3, FALSE, FALSE,
8652 EL_EMC_FAKE_ACID, -1, -1
8655 Xfake_acid_4, FALSE, FALSE,
8656 EL_EMC_FAKE_ACID, -1, -1
8659 Xfake_acid_5, FALSE, FALSE,
8660 EL_EMC_FAKE_ACID, -1, -1
8663 Xfake_acid_6, FALSE, FALSE,
8664 EL_EMC_FAKE_ACID, -1, -1
8667 Xfake_acid_7, FALSE, FALSE,
8668 EL_EMC_FAKE_ACID, -1, -1
8671 Xfake_acid_8, FALSE, FALSE,
8672 EL_EMC_FAKE_ACID, -1, -1
8675 Xsteel_1, TRUE, FALSE,
8676 EL_STEELWALL, -1, -1
8679 Xsteel_2, TRUE, FALSE,
8680 EL_EMC_STEELWALL_2, -1, -1
8683 Xsteel_3, TRUE, FALSE,
8684 EL_EMC_STEELWALL_3, -1, -1
8687 Xsteel_4, TRUE, FALSE,
8688 EL_EMC_STEELWALL_4, -1, -1
8691 Xwall_1, TRUE, FALSE,
8695 Xwall_2, TRUE, FALSE,
8696 EL_EMC_WALL_14, -1, -1
8699 Xwall_3, TRUE, FALSE,
8700 EL_EMC_WALL_15, -1, -1
8703 Xwall_4, TRUE, FALSE,
8704 EL_EMC_WALL_16, -1, -1
8707 Xround_wall_1, TRUE, FALSE,
8708 EL_WALL_SLIPPERY, -1, -1
8711 Xround_wall_2, TRUE, FALSE,
8712 EL_EMC_WALL_SLIPPERY_2, -1, -1
8715 Xround_wall_3, TRUE, FALSE,
8716 EL_EMC_WALL_SLIPPERY_3, -1, -1
8719 Xround_wall_4, TRUE, FALSE,
8720 EL_EMC_WALL_SLIPPERY_4, -1, -1
8723 Xdecor_1, TRUE, FALSE,
8724 EL_EMC_WALL_8, -1, -1
8727 Xdecor_2, TRUE, FALSE,
8728 EL_EMC_WALL_6, -1, -1
8731 Xdecor_3, TRUE, FALSE,
8732 EL_EMC_WALL_4, -1, -1
8735 Xdecor_4, TRUE, FALSE,
8736 EL_EMC_WALL_7, -1, -1
8739 Xdecor_5, TRUE, FALSE,
8740 EL_EMC_WALL_5, -1, -1
8743 Xdecor_6, TRUE, FALSE,
8744 EL_EMC_WALL_9, -1, -1
8747 Xdecor_7, TRUE, FALSE,
8748 EL_EMC_WALL_10, -1, -1
8751 Xdecor_8, TRUE, FALSE,
8752 EL_EMC_WALL_1, -1, -1
8755 Xdecor_9, TRUE, FALSE,
8756 EL_EMC_WALL_2, -1, -1
8759 Xdecor_10, TRUE, FALSE,
8760 EL_EMC_WALL_3, -1, -1
8763 Xdecor_11, TRUE, FALSE,
8764 EL_EMC_WALL_11, -1, -1
8767 Xdecor_12, TRUE, FALSE,
8768 EL_EMC_WALL_12, -1, -1
8771 Xalpha_0, TRUE, FALSE,
8772 EL_CHAR('0'), -1, -1
8775 Xalpha_1, TRUE, FALSE,
8776 EL_CHAR('1'), -1, -1
8779 Xalpha_2, TRUE, FALSE,
8780 EL_CHAR('2'), -1, -1
8783 Xalpha_3, TRUE, FALSE,
8784 EL_CHAR('3'), -1, -1
8787 Xalpha_4, TRUE, FALSE,
8788 EL_CHAR('4'), -1, -1
8791 Xalpha_5, TRUE, FALSE,
8792 EL_CHAR('5'), -1, -1
8795 Xalpha_6, TRUE, FALSE,
8796 EL_CHAR('6'), -1, -1
8799 Xalpha_7, TRUE, FALSE,
8800 EL_CHAR('7'), -1, -1
8803 Xalpha_8, TRUE, FALSE,
8804 EL_CHAR('8'), -1, -1
8807 Xalpha_9, TRUE, FALSE,
8808 EL_CHAR('9'), -1, -1
8811 Xalpha_excla, TRUE, FALSE,
8812 EL_CHAR('!'), -1, -1
8815 Xalpha_quote, TRUE, FALSE,
8816 EL_CHAR('"'), -1, -1
8819 Xalpha_comma, TRUE, FALSE,
8820 EL_CHAR(','), -1, -1
8823 Xalpha_minus, TRUE, FALSE,
8824 EL_CHAR('-'), -1, -1
8827 Xalpha_perio, TRUE, FALSE,
8828 EL_CHAR('.'), -1, -1
8831 Xalpha_colon, TRUE, FALSE,
8832 EL_CHAR(':'), -1, -1
8835 Xalpha_quest, TRUE, FALSE,
8836 EL_CHAR('?'), -1, -1
8839 Xalpha_a, TRUE, FALSE,
8840 EL_CHAR('A'), -1, -1
8843 Xalpha_b, TRUE, FALSE,
8844 EL_CHAR('B'), -1, -1
8847 Xalpha_c, TRUE, FALSE,
8848 EL_CHAR('C'), -1, -1
8851 Xalpha_d, TRUE, FALSE,
8852 EL_CHAR('D'), -1, -1
8855 Xalpha_e, TRUE, FALSE,
8856 EL_CHAR('E'), -1, -1
8859 Xalpha_f, TRUE, FALSE,
8860 EL_CHAR('F'), -1, -1
8863 Xalpha_g, TRUE, FALSE,
8864 EL_CHAR('G'), -1, -1
8867 Xalpha_h, TRUE, FALSE,
8868 EL_CHAR('H'), -1, -1
8871 Xalpha_i, TRUE, FALSE,
8872 EL_CHAR('I'), -1, -1
8875 Xalpha_j, TRUE, FALSE,
8876 EL_CHAR('J'), -1, -1
8879 Xalpha_k, TRUE, FALSE,
8880 EL_CHAR('K'), -1, -1
8883 Xalpha_l, TRUE, FALSE,
8884 EL_CHAR('L'), -1, -1
8887 Xalpha_m, TRUE, FALSE,
8888 EL_CHAR('M'), -1, -1
8891 Xalpha_n, TRUE, FALSE,
8892 EL_CHAR('N'), -1, -1
8895 Xalpha_o, TRUE, FALSE,
8896 EL_CHAR('O'), -1, -1
8899 Xalpha_p, TRUE, FALSE,
8900 EL_CHAR('P'), -1, -1
8903 Xalpha_q, TRUE, FALSE,
8904 EL_CHAR('Q'), -1, -1
8907 Xalpha_r, TRUE, FALSE,
8908 EL_CHAR('R'), -1, -1
8911 Xalpha_s, TRUE, FALSE,
8912 EL_CHAR('S'), -1, -1
8915 Xalpha_t, TRUE, FALSE,
8916 EL_CHAR('T'), -1, -1
8919 Xalpha_u, TRUE, FALSE,
8920 EL_CHAR('U'), -1, -1
8923 Xalpha_v, TRUE, FALSE,
8924 EL_CHAR('V'), -1, -1
8927 Xalpha_w, TRUE, FALSE,
8928 EL_CHAR('W'), -1, -1
8931 Xalpha_x, TRUE, FALSE,
8932 EL_CHAR('X'), -1, -1
8935 Xalpha_y, TRUE, FALSE,
8936 EL_CHAR('Y'), -1, -1
8939 Xalpha_z, TRUE, FALSE,
8940 EL_CHAR('Z'), -1, -1
8943 Xalpha_arrow_e, TRUE, FALSE,
8944 EL_CHAR('>'), -1, -1
8947 Xalpha_arrow_w, TRUE, FALSE,
8948 EL_CHAR('<'), -1, -1
8951 Xalpha_copyr, TRUE, FALSE,
8952 EL_CHAR('©'), -1, -1
8956 Xboom_bug, FALSE, FALSE,
8957 EL_BUG, ACTION_EXPLODING, -1
8960 Xboom_bomb, FALSE, FALSE,
8961 EL_BOMB, ACTION_EXPLODING, -1
8964 Xboom_android, FALSE, FALSE,
8965 EL_EMC_ANDROID, ACTION_OTHER, -1
8968 Xboom_1, FALSE, FALSE,
8969 EL_DEFAULT, ACTION_EXPLODING, -1
8972 Xboom_2, FALSE, FALSE,
8973 EL_DEFAULT, ACTION_EXPLODING, -1
8976 Znormal, FALSE, FALSE,
8980 Zdynamite, FALSE, FALSE,
8984 Zplayer, FALSE, FALSE,
8988 ZBORDER, FALSE, FALSE,
8998 static struct Mapping_EM_to_RND_player
9007 em_player_mapping_list[] =
9011 EL_PLAYER_1, ACTION_MOVING, MV_BIT_UP,
9015 EL_PLAYER_1, ACTION_MOVING, MV_BIT_RIGHT,
9019 EL_PLAYER_1, ACTION_MOVING, MV_BIT_DOWN,
9023 EL_PLAYER_1, ACTION_MOVING, MV_BIT_LEFT,
9027 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_UP,
9031 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_RIGHT,
9035 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_DOWN,
9039 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_LEFT,
9043 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_UP,
9047 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_RIGHT,
9051 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_DOWN,
9055 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_LEFT,
9059 EL_PLAYER_2, ACTION_MOVING, MV_BIT_UP,
9063 EL_PLAYER_2, ACTION_MOVING, MV_BIT_RIGHT,
9067 EL_PLAYER_2, ACTION_MOVING, MV_BIT_DOWN,
9071 EL_PLAYER_2, ACTION_MOVING, MV_BIT_LEFT,
9075 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_UP,
9079 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_RIGHT,
9083 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_DOWN,
9087 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_LEFT,
9091 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_UP,
9095 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_RIGHT,
9099 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_DOWN,
9103 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_LEFT,
9107 EL_PLAYER_1, ACTION_DEFAULT, -1,
9111 EL_PLAYER_2, ACTION_DEFAULT, -1,
9115 EL_PLAYER_3, ACTION_MOVING, MV_BIT_UP,
9119 EL_PLAYER_3, ACTION_MOVING, MV_BIT_RIGHT,
9123 EL_PLAYER_3, ACTION_MOVING, MV_BIT_DOWN,
9127 EL_PLAYER_3, ACTION_MOVING, MV_BIT_LEFT,
9131 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_UP,
9135 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_RIGHT,
9139 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_DOWN,
9143 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_LEFT,
9147 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_UP,
9151 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_RIGHT,
9155 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_DOWN,
9159 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_LEFT,
9163 EL_PLAYER_4, ACTION_MOVING, MV_BIT_UP,
9167 EL_PLAYER_4, ACTION_MOVING, MV_BIT_RIGHT,
9171 EL_PLAYER_4, ACTION_MOVING, MV_BIT_DOWN,
9175 EL_PLAYER_4, ACTION_MOVING, MV_BIT_LEFT,
9179 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_UP,
9183 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_RIGHT,
9187 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_DOWN,
9191 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_LEFT,
9195 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_UP,
9199 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_RIGHT,
9203 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_DOWN,
9207 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_LEFT,
9211 EL_PLAYER_3, ACTION_DEFAULT, -1,
9215 EL_PLAYER_4, ACTION_DEFAULT, -1,
9224 int map_element_RND_to_EM(int element_rnd)
9226 static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
9227 static boolean mapping_initialized = FALSE;
9229 if (!mapping_initialized)
9233 /* return "Xalpha_quest" for all undefined elements in mapping array */
9234 for (i = 0; i < NUM_FILE_ELEMENTS; i++)
9235 mapping_RND_to_EM[i] = Xalpha_quest;
9237 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
9238 if (em_object_mapping_list[i].is_rnd_to_em_mapping)
9239 mapping_RND_to_EM[em_object_mapping_list[i].element_rnd] =
9240 em_object_mapping_list[i].element_em;
9242 mapping_initialized = TRUE;
9245 if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
9246 return mapping_RND_to_EM[element_rnd];
9248 Error(ERR_WARN, "invalid RND level element %d", element_rnd);
9253 int map_element_EM_to_RND(int element_em)
9255 static unsigned short mapping_EM_to_RND[TILE_MAX];
9256 static boolean mapping_initialized = FALSE;
9258 if (!mapping_initialized)
9262 /* return "EL_UNKNOWN" for all undefined elements in mapping array */
9263 for (i = 0; i < TILE_MAX; i++)
9264 mapping_EM_to_RND[i] = EL_UNKNOWN;
9266 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
9267 mapping_EM_to_RND[em_object_mapping_list[i].element_em] =
9268 em_object_mapping_list[i].element_rnd;
9270 mapping_initialized = TRUE;
9273 if (element_em >= 0 && element_em < TILE_MAX)
9274 return mapping_EM_to_RND[element_em];
9276 Error(ERR_WARN, "invalid EM level element %d", element_em);
9281 void map_android_clone_elements_RND_to_EM(struct LevelInfo *level)
9283 struct LevelInfo_EM *level_em = level->native_em_level;
9284 struct LEVEL *lev = level_em->lev;
9287 for (i = 0; i < TILE_MAX; i++)
9288 lev->android_array[i] = Xblank;
9290 for (i = 0; i < level->num_android_clone_elements; i++)
9292 int element_rnd = level->android_clone_element[i];
9293 int element_em = map_element_RND_to_EM(element_rnd);
9295 for (j = 0; em_object_mapping_list[j].element_em != -1; j++)
9296 if (em_object_mapping_list[j].element_rnd == element_rnd)
9297 lev->android_array[em_object_mapping_list[j].element_em] = element_em;
9301 void map_android_clone_elements_EM_to_RND(struct LevelInfo *level)
9303 struct LevelInfo_EM *level_em = level->native_em_level;
9304 struct LEVEL *lev = level_em->lev;
9307 level->num_android_clone_elements = 0;
9309 for (i = 0; i < TILE_MAX; i++)
9311 int element_em = lev->android_array[i];
9313 boolean element_found = FALSE;
9315 if (element_em == Xblank)
9318 element_rnd = map_element_EM_to_RND(element_em);
9320 for (j = 0; j < level->num_android_clone_elements; j++)
9321 if (level->android_clone_element[j] == element_rnd)
9322 element_found = TRUE;
9326 level->android_clone_element[level->num_android_clone_elements++] =
9329 if (level->num_android_clone_elements == MAX_ANDROID_ELEMENTS)
9334 if (level->num_android_clone_elements == 0)
9336 level->num_android_clone_elements = 1;
9337 level->android_clone_element[0] = EL_EMPTY;
9341 int map_direction_RND_to_EM(int direction)
9343 return (direction == MV_UP ? 0 :
9344 direction == MV_RIGHT ? 1 :
9345 direction == MV_DOWN ? 2 :
9346 direction == MV_LEFT ? 3 :
9350 int map_direction_EM_to_RND(int direction)
9352 return (direction == 0 ? MV_UP :
9353 direction == 1 ? MV_RIGHT :
9354 direction == 2 ? MV_DOWN :
9355 direction == 3 ? MV_LEFT :
9359 int map_element_RND_to_SP(int element_rnd)
9361 int element_sp = 0x20; /* map unknown elements to yellow "hardware" */
9363 if (element_rnd >= EL_SP_START &&
9364 element_rnd <= EL_SP_END)
9365 element_sp = element_rnd - EL_SP_START;
9366 else if (element_rnd == EL_EMPTY_SPACE)
9368 else if (element_rnd == EL_INVISIBLE_WALL)
9374 int map_element_SP_to_RND(int element_sp)
9376 int element_rnd = EL_UNKNOWN;
9378 if (element_sp >= 0x00 &&
9380 element_rnd = EL_SP_START + element_sp;
9381 else if (element_sp == 0x28)
9382 element_rnd = EL_INVISIBLE_WALL;
9387 int map_action_SP_to_RND(int action_sp)
9391 case actActive: return ACTION_ACTIVE;
9392 case actImpact: return ACTION_IMPACT;
9393 case actExploding: return ACTION_EXPLODING;
9394 case actDigging: return ACTION_DIGGING;
9395 case actSnapping: return ACTION_SNAPPING;
9396 case actCollecting: return ACTION_COLLECTING;
9397 case actPassing: return ACTION_PASSING;
9398 case actPushing: return ACTION_PUSHING;
9399 case actDropping: return ACTION_DROPPING;
9401 default: return ACTION_DEFAULT;
9405 int get_next_element(int element)
9409 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
9410 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
9411 case EL_QUICKSAND_FAST_FILLING: return EL_QUICKSAND_FAST_FULL;
9412 case EL_QUICKSAND_FAST_EMPTYING: return EL_QUICKSAND_FAST_EMPTY;
9413 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
9414 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
9415 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
9416 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
9417 case EL_DC_MAGIC_WALL_FILLING: return EL_DC_MAGIC_WALL_FULL;
9418 case EL_DC_MAGIC_WALL_EMPTYING: return EL_DC_MAGIC_WALL_ACTIVE;
9419 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
9421 default: return element;
9426 int el_act_dir2img(int element, int action, int direction)
9428 element = GFX_ELEMENT(element);
9430 if (direction == MV_NONE)
9431 return element_info[element].graphic[action];
9433 direction = MV_DIR_TO_BIT(direction);
9435 return element_info[element].direction_graphic[action][direction];
9438 int el_act_dir2img(int element, int action, int direction)
9440 element = GFX_ELEMENT(element);
9441 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
9443 /* direction_graphic[][] == graphic[] for undefined direction graphics */
9444 return element_info[element].direction_graphic[action][direction];
9449 static int el_act_dir2crm(int element, int action, int direction)
9451 element = GFX_ELEMENT(element);
9453 if (direction == MV_NONE)
9454 return element_info[element].crumbled[action];
9456 direction = MV_DIR_TO_BIT(direction);
9458 return element_info[element].direction_crumbled[action][direction];
9461 static int el_act_dir2crm(int element, int action, int direction)
9463 element = GFX_ELEMENT(element);
9464 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
9466 /* direction_graphic[][] == graphic[] for undefined direction graphics */
9467 return element_info[element].direction_crumbled[action][direction];
9471 int el_act2img(int element, int action)
9473 element = GFX_ELEMENT(element);
9475 return element_info[element].graphic[action];
9478 int el_act2crm(int element, int action)
9480 element = GFX_ELEMENT(element);
9482 return element_info[element].crumbled[action];
9485 int el_dir2img(int element, int direction)
9487 element = GFX_ELEMENT(element);
9489 return el_act_dir2img(element, ACTION_DEFAULT, direction);
9492 int el2baseimg(int element)
9494 return element_info[element].graphic[ACTION_DEFAULT];
9497 int el2img(int element)
9499 element = GFX_ELEMENT(element);
9501 return element_info[element].graphic[ACTION_DEFAULT];
9504 int el2edimg(int element)
9506 element = GFX_ELEMENT(element);
9508 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
9511 int el2preimg(int element)
9513 element = GFX_ELEMENT(element);
9515 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
9518 int el2panelimg(int element)
9520 element = GFX_ELEMENT(element);
9522 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PANEL];
9525 int font2baseimg(int font_nr)
9527 return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
9530 int getBeltNrFromBeltElement(int element)
9532 return (element < EL_CONVEYOR_BELT_2_LEFT ? 0 :
9533 element < EL_CONVEYOR_BELT_3_LEFT ? 1 :
9534 element < EL_CONVEYOR_BELT_4_LEFT ? 2 : 3);
9537 int getBeltNrFromBeltActiveElement(int element)
9539 return (element < EL_CONVEYOR_BELT_2_LEFT_ACTIVE ? 0 :
9540 element < EL_CONVEYOR_BELT_3_LEFT_ACTIVE ? 1 :
9541 element < EL_CONVEYOR_BELT_4_LEFT_ACTIVE ? 2 : 3);
9544 int getBeltNrFromBeltSwitchElement(int element)
9546 return (element < EL_CONVEYOR_BELT_2_SWITCH_LEFT ? 0 :
9547 element < EL_CONVEYOR_BELT_3_SWITCH_LEFT ? 1 :
9548 element < EL_CONVEYOR_BELT_4_SWITCH_LEFT ? 2 : 3);
9551 int getBeltDirNrFromBeltElement(int element)
9553 static int belt_base_element[4] =
9555 EL_CONVEYOR_BELT_1_LEFT,
9556 EL_CONVEYOR_BELT_2_LEFT,
9557 EL_CONVEYOR_BELT_3_LEFT,
9558 EL_CONVEYOR_BELT_4_LEFT
9561 int belt_nr = getBeltNrFromBeltElement(element);
9562 int belt_dir_nr = element - belt_base_element[belt_nr];
9564 return (belt_dir_nr % 3);
9567 int getBeltDirNrFromBeltSwitchElement(int element)
9569 static int belt_base_element[4] =
9571 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
9572 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
9573 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
9574 EL_CONVEYOR_BELT_4_SWITCH_LEFT
9577 int belt_nr = getBeltNrFromBeltSwitchElement(element);
9578 int belt_dir_nr = element - belt_base_element[belt_nr];
9580 return (belt_dir_nr % 3);
9583 int getBeltDirFromBeltElement(int element)
9585 static int belt_move_dir[3] =
9592 int belt_dir_nr = getBeltDirNrFromBeltElement(element);
9594 return belt_move_dir[belt_dir_nr];
9597 int getBeltDirFromBeltSwitchElement(int element)
9599 static int belt_move_dir[3] =
9606 int belt_dir_nr = getBeltDirNrFromBeltSwitchElement(element);
9608 return belt_move_dir[belt_dir_nr];
9611 int getBeltElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
9613 static int belt_base_element[4] =
9615 EL_CONVEYOR_BELT_1_LEFT,
9616 EL_CONVEYOR_BELT_2_LEFT,
9617 EL_CONVEYOR_BELT_3_LEFT,
9618 EL_CONVEYOR_BELT_4_LEFT
9621 return belt_base_element[belt_nr] + belt_dir_nr;
9624 int getBeltElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
9626 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
9628 return getBeltElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
9631 int getBeltSwitchElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
9633 static int belt_base_element[4] =
9635 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
9636 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
9637 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
9638 EL_CONVEYOR_BELT_4_SWITCH_LEFT
9641 return belt_base_element[belt_nr] + belt_dir_nr;
9644 int getBeltSwitchElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
9646 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
9648 return getBeltSwitchElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
9652 boolean getTeamMode_EM()
9654 return game.team_mode;
9657 int getNumActivePlayers_EM()
9660 int num_players = 0;
9664 return (setup.team_mode ? MAX_PLAYERS : 1);
9666 for (i = 0; i < MAX_PLAYERS; i++)
9667 if (tape.player_participates[i])
9670 return (num_players > 1 ? MAX_PLAYERS : 1);
9674 int num_players = 0;
9677 /* when recording game, activate all connected players */
9681 for (i = 0; i < MAX_PLAYERS; i++)
9682 if (tape.player_participates[i])
9690 int getGameFrameDelay_EM(int native_em_game_frame_delay)
9692 int game_frame_delay_value;
9694 game_frame_delay_value =
9695 (tape.playing && tape.fast_forward ? FfwdFrameDelay :
9696 GameFrameDelay == GAME_FRAME_DELAY ? native_em_game_frame_delay :
9699 if (tape.playing && tape.warp_forward && !tape.pausing)
9700 game_frame_delay_value = 0;
9702 return game_frame_delay_value;
9705 unsigned int InitRND(int seed)
9707 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
9708 return InitEngineRandom_EM(seed);
9709 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
9710 return InitEngineRandom_SP(seed);
9712 return InitEngineRandom_RND(seed);
9716 static struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
9717 static struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
9720 inline static int get_effective_element_EM(int tile, int frame_em)
9722 int element = object_mapping[tile].element_rnd;
9723 int action = object_mapping[tile].action;
9724 boolean is_backside = object_mapping[tile].is_backside;
9725 boolean action_removing = (action == ACTION_DIGGING ||
9726 action == ACTION_SNAPPING ||
9727 action == ACTION_COLLECTING);
9733 case Yacid_splash_eB:
9734 case Yacid_splash_wB:
9735 return (frame_em > 5 ? EL_EMPTY : element);
9739 case Ydiamond_stone:
9740 // if (!game.use_native_emc_graphics_engine)
9748 else /* frame_em == 7 */
9752 case Yacid_splash_eB:
9753 case Yacid_splash_wB:
9756 case Yemerald_stone:
9759 case Ydiamond_stone:
9763 case Xdrip_stretchB:
9782 case Xsand_stonein_1:
9783 case Xsand_stonein_2:
9784 case Xsand_stonein_3:
9785 case Xsand_stonein_4:
9789 return (is_backside || action_removing ? EL_EMPTY : element);
9794 inline static boolean check_linear_animation_EM(int tile)
9798 case Xsand_stonesand_1:
9799 case Xsand_stonesand_quickout_1:
9800 case Xsand_sandstone_1:
9801 case Xsand_stonein_1:
9802 case Xsand_stoneout_1:
9822 case Yacid_splash_eB:
9823 case Yacid_splash_wB:
9824 case Yemerald_stone:
9832 inline static void set_crumbled_graphics_EM(struct GraphicInfo_EM *g_em,
9833 boolean has_crumbled_graphics,
9834 int crumbled, int sync_frame)
9836 /* if element can be crumbled, but certain action graphics are just empty
9837 space (like instantly snapping sand to empty space in 1 frame), do not
9838 treat these empty space graphics as crumbled graphics in EMC engine */
9839 if (crumbled == IMG_EMPTY_SPACE)
9840 has_crumbled_graphics = FALSE;
9842 if (has_crumbled_graphics)
9844 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
9845 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
9846 g_crumbled->anim_delay,
9847 g_crumbled->anim_mode,
9848 g_crumbled->anim_start_frame,
9851 getGraphicSource(crumbled, frame_crumbled, &g_em->crumbled_bitmap,
9852 &g_em->crumbled_src_x, &g_em->crumbled_src_y);
9854 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
9856 g_em->has_crumbled_graphics = TRUE;
9860 g_em->crumbled_bitmap = NULL;
9861 g_em->crumbled_src_x = 0;
9862 g_em->crumbled_src_y = 0;
9863 g_em->crumbled_border_size = 0;
9865 g_em->has_crumbled_graphics = FALSE;
9869 void ResetGfxAnimation_EM(int x, int y, int tile)
9874 void SetGfxAnimation_EM(struct GraphicInfo_EM *g_em,
9875 int tile, int frame_em, int x, int y)
9877 int action = object_mapping[tile].action;
9879 int direction = object_mapping[tile].direction;
9880 int effective_element = get_effective_element_EM(tile, frame_em);
9881 int graphic = (direction == MV_NONE ?
9882 el_act2img(effective_element, action) :
9883 el_act_dir2img(effective_element, action, direction));
9884 struct GraphicInfo *g = &graphic_info[graphic];
9887 boolean action_removing = (action == ACTION_DIGGING ||
9888 action == ACTION_SNAPPING ||
9889 action == ACTION_COLLECTING);
9890 boolean action_moving = (action == ACTION_FALLING ||
9891 action == ACTION_MOVING ||
9892 action == ACTION_PUSHING ||
9893 action == ACTION_EATING ||
9894 action == ACTION_FILLING ||
9895 action == ACTION_EMPTYING);
9896 boolean action_falling = (action == ACTION_FALLING ||
9897 action == ACTION_FILLING ||
9898 action == ACTION_EMPTYING);
9900 /* special case: graphic uses "2nd movement tile" and has defined
9901 7 frames for movement animation (or less) => use default graphic
9902 for last (8th) frame which ends the movement animation */
9903 if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
9905 action = ACTION_DEFAULT; /* (keep action_* unchanged for now) */
9906 graphic = (direction == MV_NONE ?
9907 el_act2img(effective_element, action) :
9908 el_act_dir2img(effective_element, action, direction));
9910 g = &graphic_info[graphic];
9914 if (tile == Xsand_stonesand_1 ||
9915 tile == Xsand_stonesand_2 ||
9916 tile == Xsand_stonesand_3 ||
9917 tile == Xsand_stonesand_4)
9918 printf("::: 1: quicksand frame %d [%d]\n", GfxFrame[x][y], tile);
9922 if ((action_removing || check_linear_animation_EM(tile)) && frame_em == 0)
9926 // printf("::: resetting... [%d]\n", tile);
9929 if (action_removing || check_linear_animation_EM(tile))
9931 GfxFrame[x][y] = frame_em;
9933 // printf("::: resetting... [%d]\n", tile);
9936 else if (action_moving)
9938 boolean is_backside = object_mapping[tile].is_backside;
9942 int direction = object_mapping[tile].direction;
9943 int move_dir = (action_falling ? MV_DOWN : direction);
9948 /* !!! TEST !!! NEW !!! DOES NOT WORK RIGHT YET !!! */
9949 if (g->double_movement && frame_em == 0)
9953 // printf("::: resetting... [%d]\n", tile);
9957 if (move_dir == MV_LEFT)
9958 GfxFrame[x - 1][y] = GfxFrame[x][y];
9959 else if (move_dir == MV_RIGHT)
9960 GfxFrame[x + 1][y] = GfxFrame[x][y];
9961 else if (move_dir == MV_UP)
9962 GfxFrame[x][y - 1] = GfxFrame[x][y];
9963 else if (move_dir == MV_DOWN)
9964 GfxFrame[x][y + 1] = GfxFrame[x][y];
9971 /* special case: animation for Xsand_stonesand_quickout_1/2 twice as fast */
9972 if (tile == Xsand_stonesand_quickout_1 ||
9973 tile == Xsand_stonesand_quickout_2)
9978 if (tile == Xsand_stonesand_1 ||
9979 tile == Xsand_stonesand_2 ||
9980 tile == Xsand_stonesand_3 ||
9981 tile == Xsand_stonesand_4)
9982 printf("::: 2: quicksand frame %d [%d]\n", GfxFrame[x][y], tile);
9986 if (graphic_info[graphic].anim_global_sync)
9987 sync_frame = FrameCounter;
9988 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
9989 sync_frame = GfxFrame[x][y];
9991 sync_frame = 0; /* playfield border (pseudo steel) */
9993 SetRandomAnimationValue(x, y);
9995 int frame = getAnimationFrame(g->anim_frames,
9998 g->anim_start_frame,
10001 g_em->unique_identifier =
10002 (graphic << 16) | ((frame % 8) << 12) | (g_em->width << 6) | g_em->height;
10006 void getGraphicSourceObjectExt_EM(struct GraphicInfo_EM *g_em,
10007 int tile, int frame_em, int x, int y)
10009 int action = object_mapping[tile].action;
10010 int direction = object_mapping[tile].direction;
10011 boolean is_backside = object_mapping[tile].is_backside;
10012 int effective_element = get_effective_element_EM(tile, frame_em);
10014 int effective_action = action;
10016 int effective_action = (frame_em < 7 ? action : ACTION_DEFAULT);
10018 int graphic = (direction == MV_NONE ?
10019 el_act2img(effective_element, effective_action) :
10020 el_act_dir2img(effective_element, effective_action,
10022 int crumbled = (direction == MV_NONE ?
10023 el_act2crm(effective_element, effective_action) :
10024 el_act_dir2crm(effective_element, effective_action,
10026 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
10027 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
10028 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
10029 struct GraphicInfo *g = &graphic_info[graphic];
10031 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
10035 /* special case: graphic uses "2nd movement tile" and has defined
10036 7 frames for movement animation (or less) => use default graphic
10037 for last (8th) frame which ends the movement animation */
10038 if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
10040 effective_action = ACTION_DEFAULT;
10041 graphic = (direction == MV_NONE ?
10042 el_act2img(effective_element, effective_action) :
10043 el_act_dir2img(effective_element, effective_action,
10045 crumbled = (direction == MV_NONE ?
10046 el_act2crm(effective_element, effective_action) :
10047 el_act_dir2crm(effective_element, effective_action,
10050 g = &graphic_info[graphic];
10060 if (frame_em == 0) /* reset animation frame for certain elements */
10062 if (check_linear_animation_EM(tile))
10063 GfxFrame[x][y] = 0;
10067 if (graphic_info[graphic].anim_global_sync)
10068 sync_frame = FrameCounter;
10069 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
10070 sync_frame = GfxFrame[x][y];
10072 sync_frame = 0; /* playfield border (pseudo steel) */
10074 SetRandomAnimationValue(x, y);
10079 int xxx_sync_frame = (i == Xdrip_stretch ? 7 :
10080 i == Xdrip_stretchB ? 7 :
10081 i == Ydrip_s2 ? j + 8 :
10082 i == Ydrip_s2B ? j + 8 :
10084 i == Xacid_2 ? 10 :
10085 i == Xacid_3 ? 20 :
10086 i == Xacid_4 ? 30 :
10087 i == Xacid_5 ? 40 :
10088 i == Xacid_6 ? 50 :
10089 i == Xacid_7 ? 60 :
10090 i == Xacid_8 ? 70 :
10091 i == Xfake_acid_1 ? 0 :
10092 i == Xfake_acid_2 ? 10 :
10093 i == Xfake_acid_3 ? 20 :
10094 i == Xfake_acid_4 ? 30 :
10095 i == Xfake_acid_5 ? 40 :
10096 i == Xfake_acid_6 ? 50 :
10097 i == Xfake_acid_7 ? 60 :
10098 i == Xfake_acid_8 ? 70 :
10100 i == Xball_2B ? j + 8 :
10101 i == Yball_eat ? j + 1 :
10102 i == Ykey_1_eat ? j + 1 :
10103 i == Ykey_2_eat ? j + 1 :
10104 i == Ykey_3_eat ? j + 1 :
10105 i == Ykey_4_eat ? j + 1 :
10106 i == Ykey_5_eat ? j + 1 :
10107 i == Ykey_6_eat ? j + 1 :
10108 i == Ykey_7_eat ? j + 1 :
10109 i == Ykey_8_eat ? j + 1 :
10110 i == Ylenses_eat ? j + 1 :
10111 i == Ymagnify_eat ? j + 1 :
10112 i == Ygrass_eat ? j + 1 :
10113 i == Ydirt_eat ? j + 1 :
10114 i == Xamoeba_1 ? 0 :
10115 i == Xamoeba_2 ? 1 :
10116 i == Xamoeba_3 ? 2 :
10117 i == Xamoeba_4 ? 3 :
10118 i == Xamoeba_5 ? 0 :
10119 i == Xamoeba_6 ? 1 :
10120 i == Xamoeba_7 ? 2 :
10121 i == Xamoeba_8 ? 3 :
10122 i == Xexit_2 ? j + 8 :
10123 i == Xexit_3 ? j + 16 :
10124 i == Xdynamite_1 ? 0 :
10125 i == Xdynamite_2 ? 8 :
10126 i == Xdynamite_3 ? 16 :
10127 i == Xdynamite_4 ? 24 :
10128 i == Xsand_stonein_1 ? j + 1 :
10129 i == Xsand_stonein_2 ? j + 9 :
10130 i == Xsand_stonein_3 ? j + 17 :
10131 i == Xsand_stonein_4 ? j + 25 :
10132 i == Xsand_stoneout_1 && j == 0 ? 0 :
10133 i == Xsand_stoneout_1 && j == 1 ? 0 :
10134 i == Xsand_stoneout_1 && j == 2 ? 1 :
10135 i == Xsand_stoneout_1 && j == 3 ? 2 :
10136 i == Xsand_stoneout_1 && j == 4 ? 2 :
10137 i == Xsand_stoneout_1 && j == 5 ? 3 :
10138 i == Xsand_stoneout_1 && j == 6 ? 4 :
10139 i == Xsand_stoneout_1 && j == 7 ? 4 :
10140 i == Xsand_stoneout_2 && j == 0 ? 5 :
10141 i == Xsand_stoneout_2 && j == 1 ? 6 :
10142 i == Xsand_stoneout_2 && j == 2 ? 7 :
10143 i == Xsand_stoneout_2 && j == 3 ? 8 :
10144 i == Xsand_stoneout_2 && j == 4 ? 9 :
10145 i == Xsand_stoneout_2 && j == 5 ? 11 :
10146 i == Xsand_stoneout_2 && j == 6 ? 13 :
10147 i == Xsand_stoneout_2 && j == 7 ? 15 :
10148 i == Xboom_bug && j == 1 ? 2 :
10149 i == Xboom_bug && j == 2 ? 2 :
10150 i == Xboom_bug && j == 3 ? 4 :
10151 i == Xboom_bug && j == 4 ? 4 :
10152 i == Xboom_bug && j == 5 ? 2 :
10153 i == Xboom_bug && j == 6 ? 2 :
10154 i == Xboom_bug && j == 7 ? 0 :
10155 i == Xboom_bomb && j == 1 ? 2 :
10156 i == Xboom_bomb && j == 2 ? 2 :
10157 i == Xboom_bomb && j == 3 ? 4 :
10158 i == Xboom_bomb && j == 4 ? 4 :
10159 i == Xboom_bomb && j == 5 ? 2 :
10160 i == Xboom_bomb && j == 6 ? 2 :
10161 i == Xboom_bomb && j == 7 ? 0 :
10162 i == Xboom_android && j == 7 ? 6 :
10163 i == Xboom_1 && j == 1 ? 2 :
10164 i == Xboom_1 && j == 2 ? 2 :
10165 i == Xboom_1 && j == 3 ? 4 :
10166 i == Xboom_1 && j == 4 ? 4 :
10167 i == Xboom_1 && j == 5 ? 6 :
10168 i == Xboom_1 && j == 6 ? 6 :
10169 i == Xboom_1 && j == 7 ? 8 :
10170 i == Xboom_2 && j == 0 ? 8 :
10171 i == Xboom_2 && j == 1 ? 8 :
10172 i == Xboom_2 && j == 2 ? 10 :
10173 i == Xboom_2 && j == 3 ? 10 :
10174 i == Xboom_2 && j == 4 ? 10 :
10175 i == Xboom_2 && j == 5 ? 12 :
10176 i == Xboom_2 && j == 6 ? 12 :
10177 i == Xboom_2 && j == 7 ? 12 :
10179 special_animation && j == 4 ? 3 :
10180 effective_action != action ? 0 :
10186 int xxx_effective_action;
10187 int xxx_has_action_graphics;
10190 int element = object_mapping[i].element_rnd;
10191 int action = object_mapping[i].action;
10192 int direction = object_mapping[i].direction;
10193 boolean is_backside = object_mapping[i].is_backside;
10195 boolean action_removing = (action == ACTION_DIGGING ||
10196 action == ACTION_SNAPPING ||
10197 action == ACTION_COLLECTING);
10199 boolean action_exploding = ((action == ACTION_EXPLODING ||
10200 action == ACTION_SMASHED_BY_ROCK ||
10201 action == ACTION_SMASHED_BY_SPRING) &&
10202 element != EL_DIAMOND);
10203 boolean action_active = (action == ACTION_ACTIVE);
10204 boolean action_other = (action == ACTION_OTHER);
10208 int effective_element = get_effective_element_EM(i, j);
10210 int effective_element = (j > 5 && i == Yacid_splash_eB ? EL_EMPTY :
10211 j > 5 && i == Yacid_splash_wB ? EL_EMPTY :
10213 i == Xdrip_stretch ? element :
10214 i == Xdrip_stretchB ? element :
10215 i == Ydrip_s1 ? element :
10216 i == Ydrip_s1B ? element :
10217 i == Xball_1B ? element :
10218 i == Xball_2 ? element :
10219 i == Xball_2B ? element :
10220 i == Yball_eat ? element :
10221 i == Ykey_1_eat ? element :
10222 i == Ykey_2_eat ? element :
10223 i == Ykey_3_eat ? element :
10224 i == Ykey_4_eat ? element :
10225 i == Ykey_5_eat ? element :
10226 i == Ykey_6_eat ? element :
10227 i == Ykey_7_eat ? element :
10228 i == Ykey_8_eat ? element :
10229 i == Ylenses_eat ? element :
10230 i == Ymagnify_eat ? element :
10231 i == Ygrass_eat ? element :
10232 i == Ydirt_eat ? element :
10233 i == Yemerald_stone ? EL_EMERALD :
10234 i == Ydiamond_stone ? EL_ROCK :
10235 i == Xsand_stonein_1 ? element :
10236 i == Xsand_stonein_2 ? element :
10237 i == Xsand_stonein_3 ? element :
10238 i == Xsand_stonein_4 ? element :
10239 is_backside ? EL_EMPTY :
10240 action_removing ? EL_EMPTY :
10243 int effective_action = (j < 7 ? action :
10244 i == Xdrip_stretch ? action :
10245 i == Xdrip_stretchB ? action :
10246 i == Ydrip_s1 ? action :
10247 i == Ydrip_s1B ? action :
10248 i == Xball_1B ? action :
10249 i == Xball_2 ? action :
10250 i == Xball_2B ? action :
10251 i == Yball_eat ? action :
10252 i == Ykey_1_eat ? action :
10253 i == Ykey_2_eat ? action :
10254 i == Ykey_3_eat ? action :
10255 i == Ykey_4_eat ? action :
10256 i == Ykey_5_eat ? action :
10257 i == Ykey_6_eat ? action :
10258 i == Ykey_7_eat ? action :
10259 i == Ykey_8_eat ? action :
10260 i == Ylenses_eat ? action :
10261 i == Ymagnify_eat ? action :
10262 i == Ygrass_eat ? action :
10263 i == Ydirt_eat ? action :
10264 i == Xsand_stonein_1 ? action :
10265 i == Xsand_stonein_2 ? action :
10266 i == Xsand_stonein_3 ? action :
10267 i == Xsand_stonein_4 ? action :
10268 i == Xsand_stoneout_1 ? action :
10269 i == Xsand_stoneout_2 ? action :
10270 i == Xboom_android ? ACTION_EXPLODING :
10271 action_exploding ? ACTION_EXPLODING :
10272 action_active ? action :
10273 action_other ? action :
10275 int graphic = (el_act_dir2img(effective_element, effective_action,
10277 int crumbled = (el_act_dir2crm(effective_element, effective_action,
10279 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
10280 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
10281 boolean has_action_graphics = (graphic != base_graphic);
10282 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
10283 struct GraphicInfo *g = &graphic_info[graphic];
10285 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
10287 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
10288 Bitmap *src_bitmap;
10290 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
10291 boolean special_animation = (action != ACTION_DEFAULT &&
10292 g->anim_frames == 3 &&
10293 g->anim_delay == 2 &&
10294 g->anim_mode & ANIM_LINEAR);
10295 xxx_sync_frame = (i == Xdrip_stretch ? 7 :
10296 i == Xdrip_stretchB ? 7 :
10297 i == Ydrip_s2 ? j + 8 :
10298 i == Ydrip_s2B ? j + 8 :
10300 i == Xacid_2 ? 10 :
10301 i == Xacid_3 ? 20 :
10302 i == Xacid_4 ? 30 :
10303 i == Xacid_5 ? 40 :
10304 i == Xacid_6 ? 50 :
10305 i == Xacid_7 ? 60 :
10306 i == Xacid_8 ? 70 :
10307 i == Xfake_acid_1 ? 0 :
10308 i == Xfake_acid_2 ? 10 :
10309 i == Xfake_acid_3 ? 20 :
10310 i == Xfake_acid_4 ? 30 :
10311 i == Xfake_acid_5 ? 40 :
10312 i == Xfake_acid_6 ? 50 :
10313 i == Xfake_acid_7 ? 60 :
10314 i == Xfake_acid_8 ? 70 :
10316 i == Xball_2B ? j + 8 :
10317 i == Yball_eat ? j + 1 :
10318 i == Ykey_1_eat ? j + 1 :
10319 i == Ykey_2_eat ? j + 1 :
10320 i == Ykey_3_eat ? j + 1 :
10321 i == Ykey_4_eat ? j + 1 :
10322 i == Ykey_5_eat ? j + 1 :
10323 i == Ykey_6_eat ? j + 1 :
10324 i == Ykey_7_eat ? j + 1 :
10325 i == Ykey_8_eat ? j + 1 :
10326 i == Ylenses_eat ? j + 1 :
10327 i == Ymagnify_eat ? j + 1 :
10328 i == Ygrass_eat ? j + 1 :
10329 i == Ydirt_eat ? j + 1 :
10330 i == Xamoeba_1 ? 0 :
10331 i == Xamoeba_2 ? 1 :
10332 i == Xamoeba_3 ? 2 :
10333 i == Xamoeba_4 ? 3 :
10334 i == Xamoeba_5 ? 0 :
10335 i == Xamoeba_6 ? 1 :
10336 i == Xamoeba_7 ? 2 :
10337 i == Xamoeba_8 ? 3 :
10338 i == Xexit_2 ? j + 8 :
10339 i == Xexit_3 ? j + 16 :
10340 i == Xdynamite_1 ? 0 :
10341 i == Xdynamite_2 ? 8 :
10342 i == Xdynamite_3 ? 16 :
10343 i == Xdynamite_4 ? 24 :
10344 i == Xsand_stonein_1 ? j + 1 :
10345 i == Xsand_stonein_2 ? j + 9 :
10346 i == Xsand_stonein_3 ? j + 17 :
10347 i == Xsand_stonein_4 ? j + 25 :
10348 i == Xsand_stoneout_1 && j == 0 ? 0 :
10349 i == Xsand_stoneout_1 && j == 1 ? 0 :
10350 i == Xsand_stoneout_1 && j == 2 ? 1 :
10351 i == Xsand_stoneout_1 && j == 3 ? 2 :
10352 i == Xsand_stoneout_1 && j == 4 ? 2 :
10353 i == Xsand_stoneout_1 && j == 5 ? 3 :
10354 i == Xsand_stoneout_1 && j == 6 ? 4 :
10355 i == Xsand_stoneout_1 && j == 7 ? 4 :
10356 i == Xsand_stoneout_2 && j == 0 ? 5 :
10357 i == Xsand_stoneout_2 && j == 1 ? 6 :
10358 i == Xsand_stoneout_2 && j == 2 ? 7 :
10359 i == Xsand_stoneout_2 && j == 3 ? 8 :
10360 i == Xsand_stoneout_2 && j == 4 ? 9 :
10361 i == Xsand_stoneout_2 && j == 5 ? 11 :
10362 i == Xsand_stoneout_2 && j == 6 ? 13 :
10363 i == Xsand_stoneout_2 && j == 7 ? 15 :
10364 i == Xboom_bug && j == 1 ? 2 :
10365 i == Xboom_bug && j == 2 ? 2 :
10366 i == Xboom_bug && j == 3 ? 4 :
10367 i == Xboom_bug && j == 4 ? 4 :
10368 i == Xboom_bug && j == 5 ? 2 :
10369 i == Xboom_bug && j == 6 ? 2 :
10370 i == Xboom_bug && j == 7 ? 0 :
10371 i == Xboom_bomb && j == 1 ? 2 :
10372 i == Xboom_bomb && j == 2 ? 2 :
10373 i == Xboom_bomb && j == 3 ? 4 :
10374 i == Xboom_bomb && j == 4 ? 4 :
10375 i == Xboom_bomb && j == 5 ? 2 :
10376 i == Xboom_bomb && j == 6 ? 2 :
10377 i == Xboom_bomb && j == 7 ? 0 :
10378 i == Xboom_android && j == 7 ? 6 :
10379 i == Xboom_1 && j == 1 ? 2 :
10380 i == Xboom_1 && j == 2 ? 2 :
10381 i == Xboom_1 && j == 3 ? 4 :
10382 i == Xboom_1 && j == 4 ? 4 :
10383 i == Xboom_1 && j == 5 ? 6 :
10384 i == Xboom_1 && j == 6 ? 6 :
10385 i == Xboom_1 && j == 7 ? 8 :
10386 i == Xboom_2 && j == 0 ? 8 :
10387 i == Xboom_2 && j == 1 ? 8 :
10388 i == Xboom_2 && j == 2 ? 10 :
10389 i == Xboom_2 && j == 3 ? 10 :
10390 i == Xboom_2 && j == 4 ? 10 :
10391 i == Xboom_2 && j == 5 ? 12 :
10392 i == Xboom_2 && j == 6 ? 12 :
10393 i == Xboom_2 && j == 7 ? 12 :
10394 special_animation && j == 4 ? 3 :
10395 effective_action != action ? 0 :
10398 xxx_effective_action = effective_action;
10399 xxx_has_action_graphics = has_action_graphics;
10404 int frame = getAnimationFrame(g->anim_frames,
10407 g->anim_start_frame,
10421 int old_src_x = g_em->src_x;
10422 int old_src_y = g_em->src_y;
10426 getGraphicSourceExt(graphic, frame, &g_em->bitmap, &g_em->src_x, &g_em->src_y,
10427 g->double_movement && is_backside);
10429 getGraphicSourceExt(graphic, frame, &g_em->bitmap,
10430 &g_em->src_x, &g_em->src_y, FALSE);
10435 if (tile == Ydiamond_stone)
10436 printf("::: stone smashing diamond... %d: %d, %d, %d, %d, %d -> %d [%d, %d, %d, %d, %d, %d] [%d]\n",
10441 g->anim_start_frame,
10444 g_em->src_x, g_em->src_y,
10445 g_em->src_offset_x, g_em->src_offset_y,
10446 g_em->dst_offset_x, g_em->dst_offset_y,
10458 if (graphic == IMG_BUG_MOVING_RIGHT)
10459 printf("::: %d, %d, %d: %d, %d [%d, %d -> %d, %d]\n", graphic, x, y,
10460 g->double_movement, is_backside,
10461 old_src_x, old_src_y, g_em->src_x, g_em->src_y);
10469 g_em->src_offset_x = 0;
10470 g_em->src_offset_y = 0;
10471 g_em->dst_offset_x = 0;
10472 g_em->dst_offset_y = 0;
10473 g_em->width = TILEX;
10474 g_em->height = TILEY;
10476 g_em->preserve_background = FALSE;
10479 /* (updating the "crumbled" graphic definitions is probably not really needed,
10480 as animations for crumbled graphics can't be longer than one EMC cycle) */
10482 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
10487 g_em->crumbled_bitmap = NULL;
10488 g_em->crumbled_src_x = 0;
10489 g_em->crumbled_src_y = 0;
10491 g_em->has_crumbled_graphics = FALSE;
10493 if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
10495 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
10496 g_crumbled->anim_delay,
10497 g_crumbled->anim_mode,
10498 g_crumbled->anim_start_frame,
10501 getGraphicSource(crumbled, frame_crumbled, &g_em->crumbled_bitmap,
10502 &g_em->crumbled_src_x, &g_em->crumbled_src_y);
10504 g_em->has_crumbled_graphics = TRUE;
10510 int effective_action = xxx_effective_action;
10511 int has_action_graphics = xxx_has_action_graphics;
10513 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
10514 effective_action == ACTION_MOVING ||
10515 effective_action == ACTION_PUSHING ||
10516 effective_action == ACTION_EATING)) ||
10517 (!has_action_graphics && (effective_action == ACTION_FILLING ||
10518 effective_action == ACTION_EMPTYING)))
10521 (effective_action == ACTION_FALLING ||
10522 effective_action == ACTION_FILLING ||
10523 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
10524 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
10525 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
10526 int num_steps = (i == Ydrip_s1 ? 16 :
10527 i == Ydrip_s1B ? 16 :
10528 i == Ydrip_s2 ? 16 :
10529 i == Ydrip_s2B ? 16 :
10530 i == Xsand_stonein_1 ? 32 :
10531 i == Xsand_stonein_2 ? 32 :
10532 i == Xsand_stonein_3 ? 32 :
10533 i == Xsand_stonein_4 ? 32 :
10534 i == Xsand_stoneout_1 ? 16 :
10535 i == Xsand_stoneout_2 ? 16 : 8);
10536 int cx = ABS(dx) * (TILEX / num_steps);
10537 int cy = ABS(dy) * (TILEY / num_steps);
10538 int step_frame = (i == Ydrip_s2 ? j + 8 :
10539 i == Ydrip_s2B ? j + 8 :
10540 i == Xsand_stonein_2 ? j + 8 :
10541 i == Xsand_stonein_3 ? j + 16 :
10542 i == Xsand_stonein_4 ? j + 24 :
10543 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
10544 int step = (is_backside ? step_frame : num_steps - step_frame);
10546 if (is_backside) /* tile where movement starts */
10548 if (dx < 0 || dy < 0)
10550 g_em->src_offset_x = cx * step;
10551 g_em->src_offset_y = cy * step;
10555 g_em->dst_offset_x = cx * step;
10556 g_em->dst_offset_y = cy * step;
10559 else /* tile where movement ends */
10561 if (dx < 0 || dy < 0)
10563 g_em->dst_offset_x = cx * step;
10564 g_em->dst_offset_y = cy * step;
10568 g_em->src_offset_x = cx * step;
10569 g_em->src_offset_y = cy * step;
10573 g_em->width = TILEX - cx * step;
10574 g_em->height = TILEY - cy * step;
10577 /* create unique graphic identifier to decide if tile must be redrawn */
10578 /* bit 31 - 16 (16 bit): EM style graphic
10579 bit 15 - 12 ( 4 bit): EM style frame
10580 bit 11 - 6 ( 6 bit): graphic width
10581 bit 5 - 0 ( 6 bit): graphic height */
10582 g_em->unique_identifier =
10583 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
10589 void getGraphicSourcePlayerExt_EM(struct GraphicInfo_EM *g_em,
10590 int player_nr, int anim, int frame_em)
10592 int element = player_mapping[player_nr][anim].element_rnd;
10593 int action = player_mapping[player_nr][anim].action;
10594 int direction = player_mapping[player_nr][anim].direction;
10595 int graphic = (direction == MV_NONE ?
10596 el_act2img(element, action) :
10597 el_act_dir2img(element, action, direction));
10598 struct GraphicInfo *g = &graphic_info[graphic];
10601 InitPlayerGfxAnimation(&stored_player[player_nr], action, direction);
10603 stored_player[player_nr].StepFrame = frame_em;
10605 sync_frame = stored_player[player_nr].Frame;
10607 int frame = getAnimationFrame(g->anim_frames,
10610 g->anim_start_frame,
10613 getGraphicSourceExt(graphic, frame, &g_em->bitmap,
10614 &g_em->src_x, &g_em->src_y, FALSE);
10617 printf("::: %d: %d, %d [%d]\n",
10619 stored_player[player_nr].Frame,
10620 stored_player[player_nr].StepFrame,
10625 void InitGraphicInfo_EM(void)
10628 struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
10629 struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
10634 int num_em_gfx_errors = 0;
10636 if (graphic_info_em_object[0][0].bitmap == NULL)
10638 /* EM graphics not yet initialized in em_open_all() */
10643 printf("::: [4 errors can be ignored (1 x 'bomb', 3 x 'em_dynamite']\n");
10646 /* always start with reliable default values */
10647 for (i = 0; i < TILE_MAX; i++)
10649 object_mapping[i].element_rnd = EL_UNKNOWN;
10650 object_mapping[i].is_backside = FALSE;
10651 object_mapping[i].action = ACTION_DEFAULT;
10652 object_mapping[i].direction = MV_NONE;
10655 /* always start with reliable default values */
10656 for (p = 0; p < MAX_PLAYERS; p++)
10658 for (i = 0; i < SPR_MAX; i++)
10660 player_mapping[p][i].element_rnd = EL_UNKNOWN;
10661 player_mapping[p][i].action = ACTION_DEFAULT;
10662 player_mapping[p][i].direction = MV_NONE;
10666 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
10668 int e = em_object_mapping_list[i].element_em;
10670 object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd;
10671 object_mapping[e].is_backside = em_object_mapping_list[i].is_backside;
10673 if (em_object_mapping_list[i].action != -1)
10674 object_mapping[e].action = em_object_mapping_list[i].action;
10676 if (em_object_mapping_list[i].direction != -1)
10677 object_mapping[e].direction =
10678 MV_DIR_FROM_BIT(em_object_mapping_list[i].direction);
10681 for (i = 0; em_player_mapping_list[i].action_em != -1; i++)
10683 int a = em_player_mapping_list[i].action_em;
10684 int p = em_player_mapping_list[i].player_nr;
10686 player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd;
10688 if (em_player_mapping_list[i].action != -1)
10689 player_mapping[p][a].action = em_player_mapping_list[i].action;
10691 if (em_player_mapping_list[i].direction != -1)
10692 player_mapping[p][a].direction =
10693 MV_DIR_FROM_BIT(em_player_mapping_list[i].direction);
10696 for (i = 0; i < TILE_MAX; i++)
10698 int element = object_mapping[i].element_rnd;
10699 int action = object_mapping[i].action;
10700 int direction = object_mapping[i].direction;
10701 boolean is_backside = object_mapping[i].is_backside;
10703 boolean action_removing = (action == ACTION_DIGGING ||
10704 action == ACTION_SNAPPING ||
10705 action == ACTION_COLLECTING);
10707 boolean action_exploding = ((action == ACTION_EXPLODING ||
10708 action == ACTION_SMASHED_BY_ROCK ||
10709 action == ACTION_SMASHED_BY_SPRING) &&
10710 element != EL_DIAMOND);
10711 boolean action_active = (action == ACTION_ACTIVE);
10712 boolean action_other = (action == ACTION_OTHER);
10714 for (j = 0; j < 8; j++)
10717 int effective_element = get_effective_element_EM(i, j);
10719 int effective_element = (j > 5 && i == Yacid_splash_eB ? EL_EMPTY :
10720 j > 5 && i == Yacid_splash_wB ? EL_EMPTY :
10722 i == Xdrip_stretch ? element :
10723 i == Xdrip_stretchB ? element :
10724 i == Ydrip_s1 ? element :
10725 i == Ydrip_s1B ? element :
10726 i == Xball_1B ? element :
10727 i == Xball_2 ? element :
10728 i == Xball_2B ? element :
10729 i == Yball_eat ? element :
10730 i == Ykey_1_eat ? element :
10731 i == Ykey_2_eat ? element :
10732 i == Ykey_3_eat ? element :
10733 i == Ykey_4_eat ? element :
10734 i == Ykey_5_eat ? element :
10735 i == Ykey_6_eat ? element :
10736 i == Ykey_7_eat ? element :
10737 i == Ykey_8_eat ? element :
10738 i == Ylenses_eat ? element :
10739 i == Ymagnify_eat ? element :
10740 i == Ygrass_eat ? element :
10741 i == Ydirt_eat ? element :
10742 i == Yemerald_stone ? EL_EMERALD :
10743 i == Ydiamond_stone ? EL_ROCK :
10744 i == Xsand_stonein_1 ? element :
10745 i == Xsand_stonein_2 ? element :
10746 i == Xsand_stonein_3 ? element :
10747 i == Xsand_stonein_4 ? element :
10748 is_backside ? EL_EMPTY :
10749 action_removing ? EL_EMPTY :
10752 int effective_action = (j < 7 ? action :
10753 i == Xdrip_stretch ? action :
10754 i == Xdrip_stretchB ? action :
10755 i == Ydrip_s1 ? action :
10756 i == Ydrip_s1B ? action :
10757 i == Xball_1B ? action :
10758 i == Xball_2 ? action :
10759 i == Xball_2B ? action :
10760 i == Yball_eat ? action :
10761 i == Ykey_1_eat ? action :
10762 i == Ykey_2_eat ? action :
10763 i == Ykey_3_eat ? action :
10764 i == Ykey_4_eat ? action :
10765 i == Ykey_5_eat ? action :
10766 i == Ykey_6_eat ? action :
10767 i == Ykey_7_eat ? action :
10768 i == Ykey_8_eat ? action :
10769 i == Ylenses_eat ? action :
10770 i == Ymagnify_eat ? action :
10771 i == Ygrass_eat ? action :
10772 i == Ydirt_eat ? action :
10773 i == Xsand_stonein_1 ? action :
10774 i == Xsand_stonein_2 ? action :
10775 i == Xsand_stonein_3 ? action :
10776 i == Xsand_stonein_4 ? action :
10777 i == Xsand_stoneout_1 ? action :
10778 i == Xsand_stoneout_2 ? action :
10779 i == Xboom_android ? ACTION_EXPLODING :
10780 action_exploding ? ACTION_EXPLODING :
10781 action_active ? action :
10782 action_other ? action :
10784 int graphic = (el_act_dir2img(effective_element, effective_action,
10786 int crumbled = (el_act_dir2crm(effective_element, effective_action,
10788 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
10789 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
10790 boolean has_action_graphics = (graphic != base_graphic);
10791 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
10792 struct GraphicInfo *g = &graphic_info[graphic];
10794 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
10796 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
10797 Bitmap *src_bitmap;
10799 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
10800 boolean special_animation = (action != ACTION_DEFAULT &&
10801 g->anim_frames == 3 &&
10802 g->anim_delay == 2 &&
10803 g->anim_mode & ANIM_LINEAR);
10804 int sync_frame = (i == Xdrip_stretch ? 7 :
10805 i == Xdrip_stretchB ? 7 :
10806 i == Ydrip_s2 ? j + 8 :
10807 i == Ydrip_s2B ? j + 8 :
10809 i == Xacid_2 ? 10 :
10810 i == Xacid_3 ? 20 :
10811 i == Xacid_4 ? 30 :
10812 i == Xacid_5 ? 40 :
10813 i == Xacid_6 ? 50 :
10814 i == Xacid_7 ? 60 :
10815 i == Xacid_8 ? 70 :
10816 i == Xfake_acid_1 ? 0 :
10817 i == Xfake_acid_2 ? 10 :
10818 i == Xfake_acid_3 ? 20 :
10819 i == Xfake_acid_4 ? 30 :
10820 i == Xfake_acid_5 ? 40 :
10821 i == Xfake_acid_6 ? 50 :
10822 i == Xfake_acid_7 ? 60 :
10823 i == Xfake_acid_8 ? 70 :
10825 i == Xball_2B ? j + 8 :
10826 i == Yball_eat ? j + 1 :
10827 i == Ykey_1_eat ? j + 1 :
10828 i == Ykey_2_eat ? j + 1 :
10829 i == Ykey_3_eat ? j + 1 :
10830 i == Ykey_4_eat ? j + 1 :
10831 i == Ykey_5_eat ? j + 1 :
10832 i == Ykey_6_eat ? j + 1 :
10833 i == Ykey_7_eat ? j + 1 :
10834 i == Ykey_8_eat ? j + 1 :
10835 i == Ylenses_eat ? j + 1 :
10836 i == Ymagnify_eat ? j + 1 :
10837 i == Ygrass_eat ? j + 1 :
10838 i == Ydirt_eat ? j + 1 :
10839 i == Xamoeba_1 ? 0 :
10840 i == Xamoeba_2 ? 1 :
10841 i == Xamoeba_3 ? 2 :
10842 i == Xamoeba_4 ? 3 :
10843 i == Xamoeba_5 ? 0 :
10844 i == Xamoeba_6 ? 1 :
10845 i == Xamoeba_7 ? 2 :
10846 i == Xamoeba_8 ? 3 :
10847 i == Xexit_2 ? j + 8 :
10848 i == Xexit_3 ? j + 16 :
10849 i == Xdynamite_1 ? 0 :
10850 i == Xdynamite_2 ? 8 :
10851 i == Xdynamite_3 ? 16 :
10852 i == Xdynamite_4 ? 24 :
10853 i == Xsand_stonein_1 ? j + 1 :
10854 i == Xsand_stonein_2 ? j + 9 :
10855 i == Xsand_stonein_3 ? j + 17 :
10856 i == Xsand_stonein_4 ? j + 25 :
10857 i == Xsand_stoneout_1 && j == 0 ? 0 :
10858 i == Xsand_stoneout_1 && j == 1 ? 0 :
10859 i == Xsand_stoneout_1 && j == 2 ? 1 :
10860 i == Xsand_stoneout_1 && j == 3 ? 2 :
10861 i == Xsand_stoneout_1 && j == 4 ? 2 :
10862 i == Xsand_stoneout_1 && j == 5 ? 3 :
10863 i == Xsand_stoneout_1 && j == 6 ? 4 :
10864 i == Xsand_stoneout_1 && j == 7 ? 4 :
10865 i == Xsand_stoneout_2 && j == 0 ? 5 :
10866 i == Xsand_stoneout_2 && j == 1 ? 6 :
10867 i == Xsand_stoneout_2 && j == 2 ? 7 :
10868 i == Xsand_stoneout_2 && j == 3 ? 8 :
10869 i == Xsand_stoneout_2 && j == 4 ? 9 :
10870 i == Xsand_stoneout_2 && j == 5 ? 11 :
10871 i == Xsand_stoneout_2 && j == 6 ? 13 :
10872 i == Xsand_stoneout_2 && j == 7 ? 15 :
10873 i == Xboom_bug && j == 1 ? 2 :
10874 i == Xboom_bug && j == 2 ? 2 :
10875 i == Xboom_bug && j == 3 ? 4 :
10876 i == Xboom_bug && j == 4 ? 4 :
10877 i == Xboom_bug && j == 5 ? 2 :
10878 i == Xboom_bug && j == 6 ? 2 :
10879 i == Xboom_bug && j == 7 ? 0 :
10880 i == Xboom_bomb && j == 1 ? 2 :
10881 i == Xboom_bomb && j == 2 ? 2 :
10882 i == Xboom_bomb && j == 3 ? 4 :
10883 i == Xboom_bomb && j == 4 ? 4 :
10884 i == Xboom_bomb && j == 5 ? 2 :
10885 i == Xboom_bomb && j == 6 ? 2 :
10886 i == Xboom_bomb && j == 7 ? 0 :
10887 i == Xboom_android && j == 7 ? 6 :
10888 i == Xboom_1 && j == 1 ? 2 :
10889 i == Xboom_1 && j == 2 ? 2 :
10890 i == Xboom_1 && j == 3 ? 4 :
10891 i == Xboom_1 && j == 4 ? 4 :
10892 i == Xboom_1 && j == 5 ? 6 :
10893 i == Xboom_1 && j == 6 ? 6 :
10894 i == Xboom_1 && j == 7 ? 8 :
10895 i == Xboom_2 && j == 0 ? 8 :
10896 i == Xboom_2 && j == 1 ? 8 :
10897 i == Xboom_2 && j == 2 ? 10 :
10898 i == Xboom_2 && j == 3 ? 10 :
10899 i == Xboom_2 && j == 4 ? 10 :
10900 i == Xboom_2 && j == 5 ? 12 :
10901 i == Xboom_2 && j == 6 ? 12 :
10902 i == Xboom_2 && j == 7 ? 12 :
10903 special_animation && j == 4 ? 3 :
10904 effective_action != action ? 0 :
10908 Bitmap *debug_bitmap = g_em->bitmap;
10909 int debug_src_x = g_em->src_x;
10910 int debug_src_y = g_em->src_y;
10913 int frame = getAnimationFrame(g->anim_frames,
10916 g->anim_start_frame,
10919 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y,
10920 g->double_movement && is_backside);
10922 g_em->bitmap = src_bitmap;
10923 g_em->src_x = src_x;
10924 g_em->src_y = src_y;
10925 g_em->src_offset_x = 0;
10926 g_em->src_offset_y = 0;
10927 g_em->dst_offset_x = 0;
10928 g_em->dst_offset_y = 0;
10929 g_em->width = TILEX;
10930 g_em->height = TILEY;
10932 g_em->preserve_background = FALSE;
10935 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
10940 g_em->crumbled_bitmap = NULL;
10941 g_em->crumbled_src_x = 0;
10942 g_em->crumbled_src_y = 0;
10943 g_em->crumbled_border_size = 0;
10945 g_em->has_crumbled_graphics = FALSE;
10948 if (has_crumbled_graphics && crumbled == IMG_EMPTY_SPACE)
10949 printf("::: empty crumbled: %d [%s], %d, %d\n",
10950 effective_element, element_info[effective_element].token_name,
10951 effective_action, direction);
10954 /* if element can be crumbled, but certain action graphics are just empty
10955 space (like instantly snapping sand to empty space in 1 frame), do not
10956 treat these empty space graphics as crumbled graphics in EMC engine */
10957 if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
10959 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
10960 g_crumbled->anim_delay,
10961 g_crumbled->anim_mode,
10962 g_crumbled->anim_start_frame,
10965 getGraphicSource(crumbled, frame_crumbled, &src_bitmap, &src_x, &src_y);
10967 g_em->has_crumbled_graphics = TRUE;
10968 g_em->crumbled_bitmap = src_bitmap;
10969 g_em->crumbled_src_x = src_x;
10970 g_em->crumbled_src_y = src_y;
10971 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
10975 if (g_em == &graphic_info_em_object[207][0])
10976 printf("... %d, %d [%d, %d, %d, %d] [%d, %d, %d, %d, %d, %d => %d]\n",
10977 graphic_info_em_object[207][0].crumbled_src_x,
10978 graphic_info_em_object[207][0].crumbled_src_y,
10980 crumbled, frame, src_x, src_y,
10985 g->anim_start_frame,
10987 gfx.anim_random_frame,
10992 printf("::: EMC tile %d is crumbled\n", i);
10998 if (element == EL_ROCK &&
10999 effective_action == ACTION_FILLING)
11000 printf("::: has_action_graphics == %d\n", has_action_graphics);
11003 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
11004 effective_action == ACTION_MOVING ||
11005 effective_action == ACTION_PUSHING ||
11006 effective_action == ACTION_EATING)) ||
11007 (!has_action_graphics && (effective_action == ACTION_FILLING ||
11008 effective_action == ACTION_EMPTYING)))
11011 (effective_action == ACTION_FALLING ||
11012 effective_action == ACTION_FILLING ||
11013 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
11014 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
11015 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
11016 int num_steps = (i == Ydrip_s1 ? 16 :
11017 i == Ydrip_s1B ? 16 :
11018 i == Ydrip_s2 ? 16 :
11019 i == Ydrip_s2B ? 16 :
11020 i == Xsand_stonein_1 ? 32 :
11021 i == Xsand_stonein_2 ? 32 :
11022 i == Xsand_stonein_3 ? 32 :
11023 i == Xsand_stonein_4 ? 32 :
11024 i == Xsand_stoneout_1 ? 16 :
11025 i == Xsand_stoneout_2 ? 16 : 8);
11026 int cx = ABS(dx) * (TILEX / num_steps);
11027 int cy = ABS(dy) * (TILEY / num_steps);
11028 int step_frame = (i == Ydrip_s2 ? j + 8 :
11029 i == Ydrip_s2B ? j + 8 :
11030 i == Xsand_stonein_2 ? j + 8 :
11031 i == Xsand_stonein_3 ? j + 16 :
11032 i == Xsand_stonein_4 ? j + 24 :
11033 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
11034 int step = (is_backside ? step_frame : num_steps - step_frame);
11036 if (is_backside) /* tile where movement starts */
11038 if (dx < 0 || dy < 0)
11040 g_em->src_offset_x = cx * step;
11041 g_em->src_offset_y = cy * step;
11045 g_em->dst_offset_x = cx * step;
11046 g_em->dst_offset_y = cy * step;
11049 else /* tile where movement ends */
11051 if (dx < 0 || dy < 0)
11053 g_em->dst_offset_x = cx * step;
11054 g_em->dst_offset_y = cy * step;
11058 g_em->src_offset_x = cx * step;
11059 g_em->src_offset_y = cy * step;
11063 g_em->width = TILEX - cx * step;
11064 g_em->height = TILEY - cy * step;
11067 /* create unique graphic identifier to decide if tile must be redrawn */
11068 /* bit 31 - 16 (16 bit): EM style graphic
11069 bit 15 - 12 ( 4 bit): EM style frame
11070 bit 11 - 6 ( 6 bit): graphic width
11071 bit 5 - 0 ( 6 bit): graphic height */
11072 g_em->unique_identifier =
11073 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
11077 /* skip check for EMC elements not contained in original EMC artwork */
11078 if (element == EL_EMC_FAKE_ACID)
11081 if (g_em->bitmap != debug_bitmap ||
11082 g_em->src_x != debug_src_x ||
11083 g_em->src_y != debug_src_y ||
11084 g_em->src_offset_x != 0 ||
11085 g_em->src_offset_y != 0 ||
11086 g_em->dst_offset_x != 0 ||
11087 g_em->dst_offset_y != 0 ||
11088 g_em->width != TILEX ||
11089 g_em->height != TILEY)
11091 static int last_i = -1;
11099 printf("::: EMC GFX ERROR for element %d -> %d ('%s', '%s', %d)",
11100 i, element, element_info[element].token_name,
11101 element_action_info[effective_action].suffix, direction);
11103 if (element != effective_element)
11104 printf(" [%d ('%s')]",
11106 element_info[effective_element].token_name);
11110 if (g_em->bitmap != debug_bitmap)
11111 printf(" %d (%d): different bitmap! (0x%08x != 0x%08x)\n",
11112 j, is_backside, (int)(g_em->bitmap), (int)(debug_bitmap));
11114 if (g_em->src_x != debug_src_x ||
11115 g_em->src_y != debug_src_y)
11116 printf(" frame %d (%c): %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
11117 j, (is_backside ? 'B' : 'F'),
11118 g_em->src_x, g_em->src_y,
11119 g_em->src_x / 32, g_em->src_y / 32,
11120 debug_src_x, debug_src_y,
11121 debug_src_x / 32, debug_src_y / 32);
11123 if (g_em->src_offset_x != 0 ||
11124 g_em->src_offset_y != 0 ||
11125 g_em->dst_offset_x != 0 ||
11126 g_em->dst_offset_y != 0)
11127 printf(" %d (%d): offsets %d,%d and %d,%d should be all 0\n",
11129 g_em->src_offset_x, g_em->src_offset_y,
11130 g_em->dst_offset_x, g_em->dst_offset_y);
11132 if (g_em->width != TILEX ||
11133 g_em->height != TILEY)
11134 printf(" %d (%d): size %d,%d should be %d,%d\n",
11136 g_em->width, g_em->height, TILEX, TILEY);
11138 num_em_gfx_errors++;
11145 for (i = 0; i < TILE_MAX; i++)
11147 for (j = 0; j < 8; j++)
11149 int element = object_mapping[i].element_rnd;
11150 int action = object_mapping[i].action;
11151 int direction = object_mapping[i].direction;
11152 boolean is_backside = object_mapping[i].is_backside;
11153 int graphic_action = el_act_dir2img(element, action, direction);
11154 int graphic_default = el_act_dir2img(element, ACTION_DEFAULT, direction);
11156 if ((action == ACTION_SMASHED_BY_ROCK ||
11157 action == ACTION_SMASHED_BY_SPRING ||
11158 action == ACTION_EATING) &&
11159 graphic_action == graphic_default)
11161 int e = (action == ACTION_SMASHED_BY_ROCK ? Ystone_s :
11162 action == ACTION_SMASHED_BY_SPRING ? Yspring_s :
11163 direction == MV_LEFT ? (is_backside? Yspring_wB: Yspring_w) :
11164 direction == MV_RIGHT ? (is_backside? Yspring_eB: Yspring_e) :
11167 /* no separate animation for "smashed by rock" -- use rock instead */
11168 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
11169 struct GraphicInfo_EM *g_xx = &graphic_info_em_object[e][7 - j];
11171 g_em->bitmap = g_xx->bitmap;
11172 g_em->src_x = g_xx->src_x;
11173 g_em->src_y = g_xx->src_y;
11174 g_em->src_offset_x = g_xx->src_offset_x;
11175 g_em->src_offset_y = g_xx->src_offset_y;
11176 g_em->dst_offset_x = g_xx->dst_offset_x;
11177 g_em->dst_offset_y = g_xx->dst_offset_y;
11178 g_em->width = g_xx->width;
11179 g_em->height = g_xx->height;
11180 g_em->unique_identifier = g_xx->unique_identifier;
11183 g_em->preserve_background = TRUE;
11188 for (p = 0; p < MAX_PLAYERS; p++)
11190 for (i = 0; i < SPR_MAX; i++)
11192 int element = player_mapping[p][i].element_rnd;
11193 int action = player_mapping[p][i].action;
11194 int direction = player_mapping[p][i].direction;
11196 for (j = 0; j < 8; j++)
11198 int effective_element = element;
11199 int effective_action = action;
11200 int graphic = (direction == MV_NONE ?
11201 el_act2img(effective_element, effective_action) :
11202 el_act_dir2img(effective_element, effective_action,
11204 struct GraphicInfo *g = &graphic_info[graphic];
11205 struct GraphicInfo_EM *g_em = &graphic_info_em_player[p][i][7 - j];
11206 Bitmap *src_bitmap;
11208 int sync_frame = j;
11211 Bitmap *debug_bitmap = g_em->bitmap;
11212 int debug_src_x = g_em->src_x;
11213 int debug_src_y = g_em->src_y;
11216 int frame = getAnimationFrame(g->anim_frames,
11219 g->anim_start_frame,
11222 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
11224 g_em->bitmap = src_bitmap;
11225 g_em->src_x = src_x;
11226 g_em->src_y = src_y;
11227 g_em->src_offset_x = 0;
11228 g_em->src_offset_y = 0;
11229 g_em->dst_offset_x = 0;
11230 g_em->dst_offset_y = 0;
11231 g_em->width = TILEX;
11232 g_em->height = TILEY;
11236 /* skip check for EMC elements not contained in original EMC artwork */
11237 if (element == EL_PLAYER_3 ||
11238 element == EL_PLAYER_4)
11241 if (g_em->bitmap != debug_bitmap ||
11242 g_em->src_x != debug_src_x ||
11243 g_em->src_y != debug_src_y)
11245 static int last_i = -1;
11253 printf("::: EMC GFX ERROR for p/a %d/%d -> %d ('%s', '%s', %d)",
11254 p, i, element, element_info[element].token_name,
11255 element_action_info[effective_action].suffix, direction);
11257 if (element != effective_element)
11258 printf(" [%d ('%s')]",
11260 element_info[effective_element].token_name);
11264 if (g_em->bitmap != debug_bitmap)
11265 printf(" %d: different bitmap! (0x%08x != 0x%08x)\n",
11266 j, (int)(g_em->bitmap), (int)(debug_bitmap));
11268 if (g_em->src_x != debug_src_x ||
11269 g_em->src_y != debug_src_y)
11270 printf(" frame %d: %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
11272 g_em->src_x, g_em->src_y,
11273 g_em->src_x / 32, g_em->src_y / 32,
11274 debug_src_x, debug_src_y,
11275 debug_src_x / 32, debug_src_y / 32);
11277 num_em_gfx_errors++;
11287 printf("::: [%d errors found]\n", num_em_gfx_errors);
11293 void CheckSingleStepMode_EM(byte action[MAX_PLAYERS], int frame,
11294 boolean any_player_moving,
11295 boolean player_is_dropping)
11297 if (tape.single_step && tape.recording && !tape.pausing)
11300 boolean active_players = FALSE;
11303 for (i = 0; i < MAX_PLAYERS; i++)
11304 if (action[i] != JOY_NO_ACTION)
11305 active_players = TRUE;
11309 if (frame == 0 && !player_is_dropping)
11310 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
11314 void CheckSingleStepMode_SP(boolean murphy_is_waiting,
11315 boolean murphy_is_dropping)
11318 printf("::: waiting: %d, dropping: %d\n",
11319 murphy_is_waiting, murphy_is_dropping);
11322 if (tape.single_step && tape.recording && !tape.pausing)
11324 // if (murphy_is_waiting || murphy_is_dropping)
11325 if (murphy_is_waiting)
11328 printf("::: murphy is waiting -> pause mode\n");
11331 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
11336 void getGraphicSource_SP(struct GraphicInfo_SP *g_sp,
11337 int graphic, int sync_frame, int x, int y)
11339 int frame = getGraphicAnimationFrame(graphic, sync_frame);
11341 getGraphicSource(graphic, frame, &g_sp->bitmap, &g_sp->src_x, &g_sp->src_y);
11344 boolean isNextAnimationFrame_SP(int graphic, int sync_frame)
11346 return (IS_NEXT_FRAME(sync_frame, graphic));
11349 int getGraphicInfo_Delay(int graphic)
11351 return graphic_info[graphic].anim_delay;
11354 void PlayMenuSoundExt(int sound)
11356 if (sound == SND_UNDEFINED)
11359 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
11360 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
11363 if (IS_LOOP_SOUND(sound))
11364 PlaySoundLoop(sound);
11369 void PlayMenuSound()
11371 PlayMenuSoundExt(menu.sound[game_status]);
11374 void PlayMenuSoundStereo(int sound, int stereo_position)
11376 if (sound == SND_UNDEFINED)
11379 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
11380 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
11383 if (IS_LOOP_SOUND(sound))
11384 PlaySoundExt(sound, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_LOOP);
11386 PlaySoundStereo(sound, stereo_position);
11389 void PlayMenuSoundIfLoopExt(int sound)
11391 if (sound == SND_UNDEFINED)
11394 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
11395 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
11398 if (IS_LOOP_SOUND(sound))
11399 PlaySoundLoop(sound);
11402 void PlayMenuSoundIfLoop()
11404 PlayMenuSoundIfLoopExt(menu.sound[game_status]);
11407 void PlayMenuMusicExt(int music)
11409 if (music == MUS_UNDEFINED)
11412 if (!setup.sound_music)
11418 void PlayMenuMusic()
11420 PlayMenuMusicExt(menu.music[game_status]);
11423 void PlaySoundActivating()
11426 PlaySound(SND_MENU_ITEM_ACTIVATING);
11430 void PlaySoundSelecting()
11433 PlaySound(SND_MENU_ITEM_SELECTING);
11437 void ToggleFullscreenOrChangeWindowScalingIfNeeded()
11439 boolean change_fullscreen = (setup.fullscreen !=
11440 video.fullscreen_enabled);
11441 boolean change_fullscreen_mode = (video.fullscreen_enabled &&
11442 !strEqual(setup.fullscreen_mode,
11443 video.fullscreen_mode_current));
11444 boolean change_window_scaling_percent = (!video.fullscreen_enabled &&
11445 setup.window_scaling_percent !=
11446 video.window_scaling_percent);
11448 if (change_window_scaling_percent && video.fullscreen_enabled)
11451 if (!change_window_scaling_percent && !video.fullscreen_available)
11454 #if defined(TARGET_SDL2)
11455 if (change_window_scaling_percent)
11457 SDLSetWindowScaling(setup.window_scaling_percent);
11461 else if (change_fullscreen)
11463 SDLSetWindowFullscreen(setup.fullscreen);
11465 /* set setup value according to successfully changed fullscreen mode */
11466 setup.fullscreen = video.fullscreen_enabled;
11472 if (change_fullscreen ||
11473 change_fullscreen_mode ||
11474 change_window_scaling_percent)
11476 Bitmap *tmp_backbuffer = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
11478 /* save backbuffer content which gets lost when toggling fullscreen mode */
11479 BlitBitmap(backbuffer, tmp_backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
11481 if (change_fullscreen_mode)
11483 /* keep fullscreen, but change fullscreen mode (screen resolution) */
11484 video.fullscreen_enabled = FALSE; /* force new fullscreen mode */
11487 if (change_window_scaling_percent)
11489 /* keep window mode, but change window scaling */
11490 video.fullscreen_enabled = TRUE; /* force new window scaling */
11493 /* toggle fullscreen */
11494 ChangeVideoModeIfNeeded(setup.fullscreen);
11496 /* set setup value according to successfully changed fullscreen mode */
11497 setup.fullscreen = video.fullscreen_enabled;
11499 /* restore backbuffer content from temporary backbuffer backup bitmap */
11500 BlitBitmap(tmp_backbuffer, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
11502 FreeBitmap(tmp_backbuffer);
11505 /* update visible window/screen */
11506 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
11508 redraw_mask = REDRAW_ALL;
11513 void ChangeViewportPropertiesIfNeeded()
11516 int *door_1_x = &DX;
11517 int *door_1_y = &DY;
11518 int *door_2_x = (game_status == GAME_MODE_EDITOR ? &EX : &VX);
11519 int *door_2_y = (game_status == GAME_MODE_EDITOR ? &EY : &VY);
11522 int gfx_game_mode = game_status;
11524 int gfx_game_mode = (game_status == GAME_MODE_PLAYING ||
11525 game_status == GAME_MODE_EDITOR ? game_status :
11528 int gfx_game_mode2 = (game_status == GAME_MODE_EDITOR ? GAME_MODE_DEFAULT :
11530 struct RectWithBorder *vp_playfield = &viewport.playfield[gfx_game_mode];
11531 struct RectWithBorder *vp_door_1 = &viewport.door_1[gfx_game_mode];
11532 struct RectWithBorder *vp_door_2 = &viewport.door_2[gfx_game_mode2];
11533 struct RectWithBorder *vp_door_3 = &viewport.door_2[GAME_MODE_EDITOR];
11534 int border_size = vp_playfield->border_size;
11535 int new_sx = vp_playfield->x + border_size;
11536 int new_sy = vp_playfield->y + border_size;
11537 int new_sxsize = vp_playfield->width - 2 * border_size;
11538 int new_sysize = vp_playfield->height - 2 * border_size;
11539 int new_real_sx = vp_playfield->x;
11540 int new_real_sy = vp_playfield->y;
11541 int new_full_sxsize = vp_playfield->width;
11542 int new_full_sysize = vp_playfield->height;
11543 int new_dx = vp_door_1->x;
11544 int new_dy = vp_door_1->y;
11545 int new_dxsize = vp_door_1->width;
11546 int new_dysize = vp_door_1->height;
11547 int new_vx = vp_door_2->x;
11548 int new_vy = vp_door_2->y;
11549 int new_vxsize = vp_door_2->width;
11550 int new_vysize = vp_door_2->height;
11551 int new_ex = vp_door_3->x;
11552 int new_ey = vp_door_3->y;
11553 int new_exsize = vp_door_3->width;
11554 int new_eysize = vp_door_3->height;
11557 #if NEW_GAME_TILESIZE
11558 int new_tilesize_var =
11559 (setup.small_game_graphics ? MINI_TILESIZE : game.tile_size);
11561 int new_tilesize_var = TILESIZE / (setup.small_game_graphics ? 2 : 1);
11564 int tilesize = (gfx_game_mode == GAME_MODE_PLAYING ? new_tilesize_var :
11565 gfx_game_mode == GAME_MODE_EDITOR ? MINI_TILESIZE : TILESIZE);
11566 int new_scr_fieldx = new_sxsize / tilesize;
11567 int new_scr_fieldy = new_sysize / tilesize;
11568 int new_scr_fieldx_buffers = new_sxsize / new_tilesize_var;
11569 int new_scr_fieldy_buffers = new_sysize / new_tilesize_var;
11571 int new_scr_fieldx = (vp_playfield->width - 2 * border_size) / TILESIZE;
11572 int new_scr_fieldy = (vp_playfield->height - 2 * border_size) / TILESIZE;
11574 boolean init_gfx_buffers = FALSE;
11575 boolean init_video_buffer = FALSE;
11576 boolean init_gadgets_and_toons = FALSE;
11577 boolean init_em_graphics = FALSE;
11580 /* !!! TEST ONLY !!! */
11581 // InitGfxBuffers();
11585 if (viewport.window.width != WIN_XSIZE ||
11586 viewport.window.height != WIN_YSIZE)
11588 WIN_XSIZE = viewport.window.width;
11589 WIN_YSIZE = viewport.window.height;
11592 init_video_buffer = TRUE;
11593 init_gfx_buffers = TRUE;
11595 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
11599 SetDrawDeactivationMask(REDRAW_NONE);
11600 SetDrawBackgroundMask(REDRAW_FIELD);
11602 // RedrawBackground();
11606 // printf("::: video: init_video_buffer, init_gfx_buffers\n");
11609 if (new_scr_fieldx != SCR_FIELDX ||
11610 new_scr_fieldy != SCR_FIELDY)
11612 /* this always toggles between MAIN and GAME when using small tile size */
11614 SCR_FIELDX = new_scr_fieldx;
11615 SCR_FIELDY = new_scr_fieldy;
11617 // printf("::: new_scr_fieldx != SCR_FIELDX ...\n");
11621 if (new_tilesize_var != TILESIZE_VAR &&
11622 gfx_game_mode == GAME_MODE_PLAYING)
11624 /* doing this outside GAME_MODE_PLAYING would give wrong playfield size */
11626 TILESIZE_VAR = new_tilesize_var;
11628 init_gfx_buffers = TRUE;
11630 // printf("::: tilesize: init_gfx_buffers\n");
11634 if (new_sx != SX ||
11642 new_sxsize != SXSIZE ||
11643 new_sysize != SYSIZE ||
11644 new_dxsize != DXSIZE ||
11645 new_dysize != DYSIZE ||
11646 new_vxsize != VXSIZE ||
11647 new_vysize != VYSIZE ||
11648 new_exsize != EXSIZE ||
11649 new_eysize != EYSIZE ||
11650 new_real_sx != REAL_SX ||
11651 new_real_sy != REAL_SY ||
11652 new_full_sxsize != FULL_SXSIZE ||
11653 new_full_sysize != FULL_SYSIZE ||
11654 new_tilesize_var != TILESIZE_VAR
11657 vp_door_1->x != *door_1_x ||
11658 vp_door_1->y != *door_1_y ||
11659 vp_door_2->x != *door_2_x ||
11660 vp_door_2->y != *door_2_y
11665 if (new_tilesize_var != TILESIZE_VAR)
11667 // printf("::: new_tilesize_var != TILESIZE_VAR\n");
11669 // changing tile size invalidates scroll values of engine snapshots
11670 FreeEngineSnapshot();
11672 // changing tile size requires update of graphic mapping for EM engine
11673 init_em_graphics = TRUE;
11685 SXSIZE = new_sxsize;
11686 SYSIZE = new_sysize;
11687 DXSIZE = new_dxsize;
11688 DYSIZE = new_dysize;
11689 VXSIZE = new_vxsize;
11690 VYSIZE = new_vysize;
11691 EXSIZE = new_exsize;
11692 EYSIZE = new_eysize;
11693 REAL_SX = new_real_sx;
11694 REAL_SY = new_real_sy;
11695 FULL_SXSIZE = new_full_sxsize;
11696 FULL_SYSIZE = new_full_sysize;
11697 TILESIZE_VAR = new_tilesize_var;
11700 printf("::: %d, %d, %d [%d]\n",
11701 SCR_FIELDX, SCR_FIELDY, TILESIZE_VAR,
11702 setup.small_game_graphics);
11706 *door_1_x = vp_door_1->x;
11707 *door_1_y = vp_door_1->y;
11708 *door_2_x = vp_door_2->x;
11709 *door_2_y = vp_door_2->y;
11713 init_gfx_buffers = TRUE;
11715 // printf("::: viewports: init_gfx_buffers\n");
11721 if (gfx_game_mode == GAME_MODE_MAIN)
11725 init_gadgets_and_toons = TRUE;
11727 // printf("::: viewports: init_gadgets_and_toons\n");
11735 if (init_gfx_buffers)
11737 // printf("::: init_gfx_buffers\n");
11739 SCR_FIELDX = new_scr_fieldx_buffers;
11740 SCR_FIELDY = new_scr_fieldy_buffers;
11744 SCR_FIELDX = new_scr_fieldx;
11745 SCR_FIELDY = new_scr_fieldy;
11748 if (init_video_buffer)
11750 // printf("::: init_video_buffer\n");
11752 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
11754 SetDrawDeactivationMask(REDRAW_NONE);
11755 SetDrawBackgroundMask(REDRAW_FIELD);
11758 if (init_gadgets_and_toons)
11760 // printf("::: init_gadgets_and_toons\n");
11766 if (init_em_graphics)
11768 InitGraphicInfo_EM();
11772 printf("::: %d, %d / %d, %d [%d]\n", VX, VY, EX, EY, game_status);