1 /***********************************************************
2 * Rocks'n'Diamonds -- McDuffin Strikes Back! *
3 *----------------------------------------------------------*
4 * (c) 1995-2006 Artsoft Entertainment *
6 * Detmolder Strasse 189 *
9 * e-mail: info@artsoft.org *
10 *----------------------------------------------------------*
12 ***********************************************************/
16 #include "libgame/libgame.h"
28 /* select level set with EMC X11 graphics before activating EM GFX debugging */
29 #define DEBUG_EM_GFX 0
31 /* tool button identifiers */
32 #define TOOL_CTRL_ID_YES 0
33 #define TOOL_CTRL_ID_NO 1
34 #define TOOL_CTRL_ID_CONFIRM 2
35 #define TOOL_CTRL_ID_PLAYER_1 3
36 #define TOOL_CTRL_ID_PLAYER_2 4
37 #define TOOL_CTRL_ID_PLAYER_3 5
38 #define TOOL_CTRL_ID_PLAYER_4 6
40 #define NUM_TOOL_BUTTONS 7
42 /* constants for number of doors and door parts */
44 #define NUM_PANELS NUM_DOORS
45 // #define NUM_PANELS 0
46 #define MAX_PARTS_PER_DOOR 8
47 #define MAX_DOOR_PARTS (NUM_DOORS * MAX_PARTS_PER_DOOR + NUM_PANELS)
48 #define DOOR_PART_IS_PANEL(i) ((i) >= NUM_DOORS * MAX_PARTS_PER_DOOR)
51 struct DoorPartOrderInfo
57 static struct DoorPartOrderInfo door_part_order[MAX_DOOR_PARTS];
59 struct DoorPartControlInfo
63 struct DoorPartPosInfo *pos;
66 static struct DoorPartControlInfo door_part_controls[] =
70 IMG_DOOR_1_GFX_PART_1,
75 IMG_DOOR_1_GFX_PART_2,
80 IMG_DOOR_1_GFX_PART_3,
85 IMG_DOOR_1_GFX_PART_4,
90 IMG_DOOR_1_GFX_PART_5,
95 IMG_DOOR_1_GFX_PART_6,
100 IMG_DOOR_1_GFX_PART_7,
105 IMG_DOOR_1_GFX_PART_8,
111 IMG_DOOR_2_GFX_PART_1,
116 IMG_DOOR_2_GFX_PART_2,
121 IMG_DOOR_2_GFX_PART_3,
126 IMG_DOOR_2_GFX_PART_4,
131 IMG_DOOR_2_GFX_PART_5,
136 IMG_DOOR_2_GFX_PART_6,
141 IMG_DOOR_2_GFX_PART_7,
146 IMG_DOOR_2_GFX_PART_8,
152 IMG_BACKGROUND_PANEL,
169 /* forward declaration for internal use */
170 static void UnmapToolButtons();
171 static void HandleToolButtons(struct GadgetInfo *);
172 static int el_act_dir2crm(int, int, int);
173 static int el_act2crm(int, int);
175 static struct GadgetInfo *tool_gadget[NUM_TOOL_BUTTONS];
176 static int request_gadget_id = -1;
178 static char *print_if_not_empty(int element)
180 static char *s = NULL;
181 char *token_name = element_info[element].token_name;
186 s = checked_malloc(strlen(token_name) + 10 + 1);
188 if (element != EL_EMPTY)
189 sprintf(s, "%d\t['%s']", element, token_name);
191 sprintf(s, "%d", element);
196 void DumpTile(int x, int y)
201 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
207 printf_line("-", 79);
208 printf("Field Info: SCREEN(%d, %d), LEVEL(%d, %d)\n", sx, sy, x, y);
209 printf_line("-", 79);
211 if (!IN_LEV_FIELD(x, y))
213 printf("(not in level field)\n");
219 printf(" Feld: %d\t['%s']\n", Feld[x][y],
220 element_info[Feld[x][y]].token_name);
221 printf(" Back: %s\n", print_if_not_empty(Back[x][y]));
222 printf(" Store: %s\n", print_if_not_empty(Store[x][y]));
223 printf(" Store2: %s\n", print_if_not_empty(Store2[x][y]));
224 printf(" StorePlayer: %s\n", print_if_not_empty(StorePlayer[x][y]));
225 printf(" MovPos: %d\n", MovPos[x][y]);
226 printf(" MovDir: %d\n", MovDir[x][y]);
227 printf(" MovDelay: %d\n", MovDelay[x][y]);
228 printf(" ChangeDelay: %d\n", ChangeDelay[x][y]);
229 printf(" CustomValue: %d\n", CustomValue[x][y]);
230 printf(" GfxElement: %d\n", GfxElement[x][y]);
231 printf(" GfxAction: %d\n", GfxAction[x][y]);
232 printf(" GfxFrame: %d\n", GfxFrame[x][y]);
236 void SetDrawtoField(int mode)
238 if (mode == DRAW_BUFFERED && setup.soft_scrolling)
246 BX2 = SCR_FIELDX + 1;
247 BY2 = SCR_FIELDY + 1;
266 BX2 = SCR_FIELDX + 1;
267 BY2 = SCR_FIELDY + 1;
282 drawto_field = fieldbuffer;
284 else /* DRAW_BACKBUFFER */
290 BX2 = SCR_FIELDX - 1;
291 BY2 = SCR_FIELDY - 1;
295 drawto_field = backbuffer;
301 static void RedrawPlayfield_RND()
303 if (game.envelope_active)
307 DrawLevel(REDRAW_ALL);
311 SetMainBackgroundImage(IMG_BACKGROUND_PLAYING);
312 // SetDrawBackgroundMask(REDRAW_FIELD); // !!! CHECK THIS !!!
313 SetDrawBackgroundMask(REDRAW_ALL); // !!! CHECK THIS !!!
315 for (x = BX1; x <= BX2; x++)
316 for (y = BY1; y <= BY2; y++)
317 DrawScreenField(x, y);
319 redraw_mask |= REDRAW_FIELD;
325 BlitScreenToBitmap(backbuffer);
327 /* blit playfield from scroll buffer to normal back buffer */
328 if (setup.soft_scrolling)
330 int fx = FX, fy = FY;
332 fx += (ScreenMovDir & (MV_LEFT|MV_RIGHT) ? ScreenGfxPos : 0);
333 fy += (ScreenMovDir & (MV_UP|MV_DOWN) ? ScreenGfxPos : 0);
335 BlitBitmap(fieldbuffer, backbuffer, fx,fy, SXSIZE,SYSIZE, SX,SY);
341 void RedrawPlayfield()
343 if (game_status != GAME_MODE_PLAYING)
346 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
347 RedrawPlayfield_EM(TRUE);
348 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
349 RedrawPlayfield_SP(TRUE);
350 else if (level.game_engine_type == GAME_ENGINE_TYPE_RND)
351 RedrawPlayfield_RND();
353 BlitScreenToBitmap(backbuffer);
355 BlitBitmap(drawto, window, gfx.sx, gfx.sy, gfx.sxsize, gfx.sysize,
361 void RedrawPlayfield(boolean force_redraw, int x, int y, int width, int height)
363 if (game_status == GAME_MODE_PLAYING &&
364 level.game_engine_type == GAME_ENGINE_TYPE_EM)
366 /* currently there is no partial redraw -- always redraw whole playfield */
367 RedrawPlayfield_EM(TRUE);
369 /* blit playfield from scroll buffer to normal back buffer for fading in */
370 BlitScreenToBitmap_EM(backbuffer);
372 else if (game_status == GAME_MODE_PLAYING &&
373 level.game_engine_type == GAME_ENGINE_TYPE_SP)
375 /* currently there is no partial redraw -- always redraw whole playfield */
376 RedrawPlayfield_SP(TRUE);
378 /* blit playfield from scroll buffer to normal back buffer for fading in */
379 BlitScreenToBitmap_SP(backbuffer);
381 else if (game_status == GAME_MODE_PLAYING &&
382 !game.envelope_active)
388 width = gfx.sxsize + 2 * TILEX;
389 height = gfx.sysize + 2 * TILEY;
395 int x1 = (x - SX) / TILEX, y1 = (y - SY) / TILEY;
396 int x2 = (x - SX + width) / TILEX, y2 = (y - SY + height) / TILEY;
398 for (xx = BX1; xx <= BX2; xx++)
399 for (yy = BY1; yy <= BY2; yy++)
400 if (xx >= x1 && xx <= x2 && yy >= y1 && yy <= y2)
401 DrawScreenField(xx, yy);
405 if (setup.soft_scrolling)
407 int fx = FX, fy = FY;
409 fx += (ScreenMovDir & (MV_LEFT|MV_RIGHT) ? ScreenGfxPos : 0);
410 fy += (ScreenMovDir & (MV_UP|MV_DOWN) ? ScreenGfxPos : 0);
412 BlitBitmap(fieldbuffer, backbuffer, fx,fy, SXSIZE,SYSIZE, SX,SY);
424 BlitBitmap(drawto, window, x, y, width, height, x, y);
429 void DrawMaskedBorder_Rect(int x, int y, int width, int height)
431 Bitmap *bitmap = graphic_info[IMG_GLOBAL_BORDER].bitmap;
433 SetClipOrigin(bitmap, bitmap->stored_clip_gc, 0, 0);
434 BlitBitmapMasked(bitmap, backbuffer, x, y, width, height, x, y);
437 void DrawMaskedBorder_FIELD()
439 if (global.border_status >= GAME_MODE_TITLE &&
440 global.border_status <= GAME_MODE_PLAYING &&
441 border.draw_masked[global.border_status])
442 DrawMaskedBorder_Rect(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
445 void DrawMaskedBorder_DOOR_1()
447 if (border.draw_masked[GFX_SPECIAL_ARG_DOOR] &&
448 (global.border_status != GAME_MODE_EDITOR ||
449 border.draw_masked[GFX_SPECIAL_ARG_EDITOR]))
450 DrawMaskedBorder_Rect(DX, DY, DXSIZE, DYSIZE);
453 void DrawMaskedBorder_DOOR_2()
455 if (border.draw_masked[GFX_SPECIAL_ARG_DOOR] &&
456 global.border_status != GAME_MODE_EDITOR)
457 DrawMaskedBorder_Rect(VX, VY, VXSIZE, VYSIZE);
460 void DrawMaskedBorder_DOOR_3()
462 /* currently not available */
465 void DrawMaskedBorder_ALL()
467 DrawMaskedBorder_FIELD();
468 DrawMaskedBorder_DOOR_1();
469 DrawMaskedBorder_DOOR_2();
470 DrawMaskedBorder_DOOR_3();
473 void DrawMaskedBorder(int redraw_mask)
475 /* never draw masked screen borders on borderless screens */
476 if (effectiveGameStatus() == GAME_MODE_LOADING ||
477 effectiveGameStatus() == GAME_MODE_TITLE)
480 /* never draw masked screen borders when displaying request outside door */
481 if (effectiveGameStatus() == GAME_MODE_PSEUDO_DOOR &&
482 global.use_envelope_request)
485 if (redraw_mask & REDRAW_ALL)
486 DrawMaskedBorder_ALL();
489 if (redraw_mask & REDRAW_FIELD)
490 DrawMaskedBorder_FIELD();
491 if (redraw_mask & REDRAW_DOOR_1)
492 DrawMaskedBorder_DOOR_1();
493 if (redraw_mask & REDRAW_DOOR_2)
494 DrawMaskedBorder_DOOR_2();
495 if (redraw_mask & REDRAW_DOOR_3)
496 DrawMaskedBorder_DOOR_3();
500 static void BlitScreenToBitmap_RND(Bitmap *target_bitmap)
502 DrawBuffer *buffer = (drawto_field == window ? backbuffer : drawto_field);
503 int fx = FX, fy = FY;
504 int full_lev_fieldx = lev_fieldx + (BorderElement != EL_EMPTY ? 2 : 0);
505 int full_lev_fieldy = lev_fieldy + (BorderElement != EL_EMPTY ? 2 : 0);
508 int dx = (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
509 int dy = (ScreenMovDir & (MV_UP | MV_DOWN) ? ScreenGfxPos : 0);
510 int dx_var = dx * TILESIZE_VAR / TILESIZE;
511 int dy_var = dy * TILESIZE_VAR / TILESIZE;
514 // fx += dx * TILESIZE_VAR / TILESIZE;
515 // fy += dy * TILESIZE_VAR / TILESIZE;
517 fx += (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
518 fy += (ScreenMovDir & (MV_UP | MV_DOWN) ? ScreenGfxPos : 0);
521 ffx = (scroll_x - SBX_Left) * TILEX_VAR + dx_var;
522 ffy = (scroll_y - SBY_Upper) * TILEY_VAR + dy_var;
524 if (EVEN(SCR_FIELDX))
526 if (ffx < SBX_Right * TILEX_VAR + TILEX_VAR / 2 + TILEX_VAR)
527 fx += dx_var - MIN(ffx, TILEX_VAR / 2) + TILEX_VAR;
529 fx += (dx_var > 0 ? TILEX_VAR : 0);
536 if (EVEN(SCR_FIELDY))
538 if (ffy < SBY_Lower * TILEY_VAR + TILEY_VAR / 2 + TILEY_VAR)
539 fy += dy_var - MIN(ffy, TILEY_VAR / 2) + TILEY_VAR;
541 fy += (dy_var > 0 ? TILEY_VAR : 0);
549 printf("::: (%d, %d) [(%d / %d, %d / %d)] => %d, %d\n",
552 SBY_Upper, SBY_Lower,
557 if (full_lev_fieldx <= SCR_FIELDX)
559 // printf(":1: PLAYFIELD FITS TO SCREEN [%d, %d, %d]\n", fx, ffx, dx_var);
561 if (EVEN(SCR_FIELDX))
562 fx = 2 * TILEX_VAR - (ODD(lev_fieldx) ? TILEX_VAR / 2 : 0);
564 fx = 2 * TILEX_VAR - (EVEN(lev_fieldx) ? TILEX_VAR / 2 : 0);
566 // printf(":2: PLAYFIELD FITS TO SCREEN [%d, %d, %d]\n", fx, ffx, dx_var);
569 if (full_lev_fieldy <= SCR_FIELDY)
571 if (EVEN(SCR_FIELDY))
572 fy = 2 * TILEY_VAR - (ODD(lev_fieldy) ? TILEY_VAR / 2 : 0);
574 fy = 2 * TILEY_VAR - (EVEN(lev_fieldy) ? TILEY_VAR / 2 : 0);
578 if (border.draw_masked[GAME_MODE_PLAYING])
580 if (buffer != backbuffer)
582 /* copy playfield buffer to backbuffer to add masked border */
583 BlitBitmap(buffer, backbuffer, fx, fy, SXSIZE, SYSIZE, SX, SY);
584 DrawMaskedBorder(REDRAW_FIELD);
587 BlitBitmap(backbuffer, target_bitmap,
588 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
593 BlitBitmap(buffer, target_bitmap, fx, fy, SXSIZE, SYSIZE, SX, SY);
597 void BlitScreenToBitmap(Bitmap *target_bitmap)
599 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
600 BlitScreenToBitmap_EM(target_bitmap);
601 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
602 BlitScreenToBitmap_SP(target_bitmap);
603 else if (level.game_engine_type == GAME_ENGINE_TYPE_RND)
604 BlitScreenToBitmap_RND(target_bitmap);
610 DrawBuffer *buffer = (drawto_field == window ? backbuffer : drawto_field);
613 printf("::: TILES TO REFRESH: %d\n", redraw_tiles);
614 for (x = 0; x < SCR_FIELDX; x++)
615 for (y = 0 ; y < SCR_FIELDY; y++)
616 if (redraw[redraw_x1 + x][redraw_y1 + y])
617 printf("::: - %d, %d [%s]\n",
618 LEVELX(x), LEVELY(y),
619 EL_NAME(Feld[LEVELX(x)][LEVELY(y)]));
622 if (redraw_mask & REDRAW_TILES && redraw_tiles > REDRAWTILES_THRESHOLD)
623 redraw_mask |= REDRAW_FIELD;
626 // never redraw single tiles, always redraw the whole field
627 // (redrawing single tiles up to a certain threshold was faster on old,
628 // now legacy graphics, but slows things down on modern graphics now)
629 // UPDATE: this is now globally defined by value of REDRAWTILES_THRESHOLD
630 if (redraw_mask & REDRAW_TILES)
631 redraw_mask |= REDRAW_FIELD;
635 /* !!! TEST ONLY !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */
636 /* (force full redraw) */
637 if (game_status == GAME_MODE_PLAYING)
638 redraw_mask |= REDRAW_FIELD;
641 if (redraw_mask & REDRAW_FIELD)
642 redraw_mask &= ~REDRAW_TILES;
644 if (redraw_mask == REDRAW_NONE)
649 if (redraw_mask & REDRAW_ALL)
650 printf("[REDRAW_ALL]");
651 if (redraw_mask & REDRAW_FIELD)
652 printf("[REDRAW_FIELD]");
653 if (redraw_mask & REDRAW_TILES)
654 printf("[REDRAW_TILES]");
655 if (redraw_mask & REDRAW_DOOR_1)
656 printf("[REDRAW_DOOR_1]");
657 if (redraw_mask & REDRAW_DOOR_2)
658 printf("[REDRAW_DOOR_2]");
659 if (redraw_mask & REDRAW_FROM_BACKBUFFER)
660 printf("[REDRAW_FROM_BACKBUFFER]");
661 printf(" [%d]\n", FrameCounter);
664 if (redraw_mask & REDRAW_TILES &&
665 game_status == GAME_MODE_PLAYING &&
666 border.draw_masked[GAME_MODE_PLAYING])
667 redraw_mask |= REDRAW_FIELD;
669 if (global.fps_slowdown && game_status == GAME_MODE_PLAYING)
671 static boolean last_frame_skipped = FALSE;
672 boolean skip_even_when_not_scrolling = TRUE;
673 boolean just_scrolling = (ScreenMovDir != 0);
674 boolean verbose = FALSE;
676 if (global.fps_slowdown_factor > 1 &&
677 (FrameCounter % global.fps_slowdown_factor) &&
678 (just_scrolling || skip_even_when_not_scrolling))
680 redraw_mask &= ~REDRAW_MAIN;
682 last_frame_skipped = TRUE;
685 printf("FRAME SKIPPED\n");
689 if (last_frame_skipped)
690 redraw_mask |= REDRAW_FIELD;
692 last_frame_skipped = FALSE;
695 printf("frame not skipped\n");
699 /* synchronize X11 graphics at this point; if we would synchronize the
700 display immediately after the buffer switching (after the XFlush),
701 this could mean that we have to wait for the graphics to complete,
702 although we could go on doing calculations for the next frame */
706 /* never draw masked border to backbuffer when using playfield buffer */
707 if (game_status != GAME_MODE_PLAYING ||
708 redraw_mask & REDRAW_FROM_BACKBUFFER ||
709 buffer == backbuffer)
710 DrawMaskedBorder(redraw_mask);
712 DrawMaskedBorder(redraw_mask & REDRAW_DOORS);
714 if (redraw_mask & REDRAW_ALL)
716 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
718 redraw_mask = REDRAW_NONE;
721 if (redraw_mask & REDRAW_FIELD)
724 printf("::: REDRAW_FIELD\n");
727 if (game_status != GAME_MODE_PLAYING ||
728 redraw_mask & REDRAW_FROM_BACKBUFFER)
730 BlitBitmap(backbuffer, window,
731 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE, REAL_SX, REAL_SY);
736 BlitScreenToBitmap_RND(window);
738 int fx = FX, fy = FY;
741 int dx = (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
742 int dy = (ScreenMovDir & (MV_UP | MV_DOWN) ? ScreenGfxPos : 0);
743 int dx_var = dx * TILESIZE_VAR / TILESIZE;
744 int dy_var = dy * TILESIZE_VAR / TILESIZE;
747 // fx += dx * TILESIZE_VAR / TILESIZE;
748 // fy += dy * TILESIZE_VAR / TILESIZE;
750 fx += (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
751 fy += (ScreenMovDir & (MV_UP | MV_DOWN) ? ScreenGfxPos : 0);
754 /* !!! THIS WORKS !!! */
756 printf("::: %d, %d\n", scroll_x, scroll_y);
758 ffx = (scroll_x - SBX_Left) * TILEX_VAR + dx_var;
759 ffy = (scroll_y - SBY_Upper) * TILEY_VAR + dy_var;
761 if (EVEN(SCR_FIELDX))
763 if (ffx < SBX_Right * TILEX_VAR + TILEX_VAR / 2 + TILEX_VAR)
764 fx += dx_var - MIN(ffx, TILEX_VAR / 2) + TILEX_VAR;
766 fx += (dx > 0 ? TILEX_VAR : 0);
773 if (EVEN(SCR_FIELDY))
775 if (ffy < SBY_Lower * TILEY_VAR + TILEY_VAR / 2 + TILEY_VAR)
776 fy += dy_var - MIN(ffy, TILEY_VAR / 2) + TILEY_VAR;
778 fy += (dy > 0 ? TILEY_VAR : 0);
785 if (border.draw_masked[GAME_MODE_PLAYING])
787 if (buffer != backbuffer)
789 /* copy playfield buffer to backbuffer to add masked border */
790 BlitBitmap(buffer, backbuffer, fx, fy, SXSIZE, SYSIZE, SX, SY);
791 DrawMaskedBorder(REDRAW_FIELD);
794 BlitBitmap(backbuffer, window,
795 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
800 BlitBitmap(buffer, window, fx, fy, SXSIZE, SYSIZE, SX, SY);
806 printf("redrawing all (ScreenGfxPos == %d) because %s\n",
808 (setup.soft_scrolling ?
809 "setup.soft_scrolling" :
810 ABS(ScreenGfxPos) + ScrollStepSize == TILEX ?
811 "ABS(ScreenGfxPos) + ScrollStepSize == TILEX" :
812 ABS(ScreenGfxPos) == ScrollStepSize ?
813 "ABS(ScreenGfxPos) == ScrollStepSize" :
814 "redraw_tiles > REDRAWTILES_THRESHOLD"));
819 redraw_mask &= ~REDRAW_MAIN;
822 if (redraw_mask & REDRAW_DOORS)
824 if (redraw_mask & REDRAW_DOOR_1)
825 BlitBitmap(backbuffer, window, DX, DY, DXSIZE, DYSIZE, DX, DY);
827 if (redraw_mask & REDRAW_DOOR_2)
828 BlitBitmap(backbuffer, window, VX, VY, VXSIZE, VYSIZE, VX, VY);
830 if (redraw_mask & REDRAW_DOOR_3)
831 BlitBitmap(backbuffer, window, EX, EY, EXSIZE, EYSIZE, EX, EY);
833 redraw_mask &= ~REDRAW_DOORS;
836 if (redraw_mask & REDRAW_MICROLEVEL)
838 BlitBitmap(backbuffer, window, SX, SY + 10 * TILEY, SXSIZE, 7 * TILEY,
839 SX, SY + 10 * TILEY);
841 redraw_mask &= ~REDRAW_MICROLEVEL;
844 if (redraw_mask & REDRAW_TILES)
847 printf("::: REDRAW_TILES\n");
853 InitGfxClipRegion(TRUE, SX, SY, SXSIZE, SYSIZE);
856 int sx = SX; // - (EVEN(SCR_FIELDX) ? TILEX_VAR / 2 : 0);
857 int sy = SY; // + (EVEN(SCR_FIELDY) ? TILEY_VAR / 2 : 0);
860 int dx_var = dx * TILESIZE_VAR / TILESIZE;
861 int dy_var = dy * TILESIZE_VAR / TILESIZE;
863 int fx = FX, fy = FY;
865 int scr_fieldx = SCR_FIELDX + (EVEN(SCR_FIELDX) ? 2 : 0);
866 int scr_fieldy = SCR_FIELDY + (EVEN(SCR_FIELDY) ? 2 : 0);
868 ffx = (scroll_x - SBX_Left) * TILEX_VAR + dx_var;
869 ffy = (scroll_y - SBY_Upper) * TILEY_VAR + dy_var;
871 if (EVEN(SCR_FIELDX))
873 if (ffx < SBX_Right * TILEX_VAR + TILEX_VAR / 2 + TILEX_VAR)
875 fx += dx_var - MIN(ffx, TILEX_VAR / 2) + TILEX_VAR;
884 fx += (dx_var > 0 ? TILEX_VAR : 0);
888 if (EVEN(SCR_FIELDY))
890 if (ffy < SBY_Lower * TILEY_VAR + TILEY_VAR / 2 + TILEY_VAR)
892 fy += dy_var - MIN(ffy, TILEY_VAR / 2) + TILEY_VAR;
901 fy += (dy_var > 0 ? TILEY_VAR : 0);
906 printf("::: %d, %d, %d, %d\n", sx, sy, SCR_FIELDX, SCR_FIELDY);
909 for (x = 0; x < scr_fieldx; x++)
910 for (y = 0 ; y < scr_fieldy; y++)
911 if (redraw[redraw_x1 + x][redraw_y1 + y])
912 BlitBitmap(buffer, window,
913 FX + x * TILEX_VAR, FY + y * TILEY_VAR,
914 TILEX_VAR, TILEY_VAR,
915 sx + x * TILEX_VAR, sy + y * TILEY_VAR);
918 InitGfxClipRegion(FALSE, -1, -1, -1, -1);
920 for (x = 0; x < SCR_FIELDX; x++)
921 for (y = 0 ; y < SCR_FIELDY; y++)
922 if (redraw[redraw_x1 + x][redraw_y1 + y])
923 BlitBitmap(buffer, window,
924 FX + x * TILEX_VAR, FY + y * TILEY_VAR,
925 TILEX_VAR, TILEY_VAR,
926 SX + x * TILEX_VAR, SY + y * TILEY_VAR);
930 for (x = 0; x < SCR_FIELDX; x++)
931 for (y = 0 ; y < SCR_FIELDY; y++)
932 if (redraw[redraw_x1 + x][redraw_y1 + y])
933 BlitBitmap(buffer, window,
934 FX + x * TILEX, FY + y * TILEY, TILEX, TILEY,
935 SX + x * TILEX, SY + y * TILEY);
939 if (redraw_mask & REDRAW_FPS) /* display frames per second */
944 sprintf(info1, " (only every %d. frame)", global.fps_slowdown_factor);
945 if (!global.fps_slowdown)
948 sprintf(text, "%04.1f fps%s", global.frames_per_second, info1);
950 DrawTextExt(window, SX + SXSIZE + SX, 0, text, FONT_TEXT_2, BLIT_OPAQUE);
952 DrawTextExt(window, SX, SY, text, FONT_TEXT_2, BLIT_OPAQUE);
958 for (x = 0; x < MAX_BUF_XSIZE; x++)
959 for (y = 0; y < MAX_BUF_YSIZE; y++)
962 redraw_mask = REDRAW_NONE;
965 static void FadeCrossSaveBackbuffer()
967 BlitBitmap(backbuffer, bitmap_db_cross, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
970 static void FadeExt(int fade_mask, int fade_mode, int fade_type)
972 static int fade_type_skip = FADE_TYPE_NONE;
973 void (*draw_border_function)(void) = NULL;
974 Bitmap *bitmap = (fade_mode & FADE_TYPE_TRANSFORM ? bitmap_db_cross : NULL);
975 int x, y, width, height;
976 int fade_delay, post_delay;
978 if (fade_type == FADE_TYPE_FADE_OUT)
980 if (fade_type_skip != FADE_TYPE_NONE)
983 printf("::: skipping %d ... [%d] (X)\n", fade_mode, fade_type_skip);
986 /* skip all fade operations until specified fade operation */
987 if (fade_type & fade_type_skip)
988 fade_type_skip = FADE_TYPE_NONE;
993 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
995 FadeCrossSaveBackbuffer();
1001 redraw_mask |= fade_mask;
1003 if (fade_type == FADE_TYPE_SKIP)
1006 printf("::: will skip %d ... [%d]\n", fade_mode, fade_type_skip);
1009 fade_type_skip = fade_mode;
1015 printf("::: !!! FADING %d ... [%d] [%d]\n", fade_mode, fade_type,
1020 fade_delay = fading.fade_delay;
1021 post_delay = (fade_mode == FADE_MODE_FADE_OUT ? fading.post_delay : 0);
1024 if (fade_type_skip != FADE_TYPE_NONE)
1027 printf("::: skipping %d ... [%d]\n", fade_mode, fade_type_skip);
1030 /* skip all fade operations until specified fade operation */
1031 if (fade_type & fade_type_skip)
1032 fade_type_skip = FADE_TYPE_NONE;
1042 if (global.autoplay_leveldir)
1044 // fading.fade_mode = FADE_MODE_NONE;
1051 if (fading.fade_mode == FADE_MODE_NONE)
1059 /* !!! what about fade_mask == REDRAW_FIELD | REDRAW_ALL ??? !!! */
1062 printf("::: NOW FADING %d ... [%d]\n", fade_mode, fade_type);
1066 if (fade_mask == REDRAW_NONE)
1067 fade_mask = REDRAW_FIELD;
1070 // if (fade_mask & REDRAW_FIELD)
1071 if (fade_mask == REDRAW_FIELD)
1075 width = FULL_SXSIZE;
1076 height = FULL_SYSIZE;
1079 fade_delay = fading.fade_delay;
1080 post_delay = (fade_mode == FADE_MODE_FADE_OUT ? fading.post_delay : 0);
1083 if (border.draw_masked_when_fading)
1084 draw_border_function = DrawMaskedBorder_FIELD; /* update when fading */
1086 DrawMaskedBorder_FIELD(); /* draw once */
1088 else /* REDRAW_ALL */
1096 fade_delay = fading.fade_delay;
1097 post_delay = (fade_mode == FADE_MODE_FADE_OUT ? fading.post_delay : 0);
1102 if (!setup.fade_screens ||
1104 fading.fade_mode == FADE_MODE_NONE)
1106 if (!setup.fade_screens || fade_delay == 0)
1109 if (fade_mode == FADE_MODE_FADE_OUT)
1113 if (fade_mode == FADE_MODE_FADE_OUT &&
1114 fading.fade_mode != FADE_MODE_NONE)
1115 ClearRectangle(backbuffer, x, y, width, height);
1121 BlitBitmap(backbuffer, window, x, y, width, height, x, y);
1123 redraw_mask &= ~fade_mask;
1125 /* always redraw area that was explicitly marked to fade */
1126 redraw_mask |= fade_mask;
1134 BlitBitmap(backbuffer, window, x, y, width, height, x, y);
1135 redraw_mask = REDRAW_NONE;
1136 // (^^^ WRONG; should be "redraw_mask &= ~fade_mask" if done this way)
1145 FadeRectangle(bitmap, x, y, width, height, fade_mode, fade_delay, post_delay,
1146 draw_border_function);
1148 redraw_mask &= ~fade_mask;
1151 void FadeIn(int fade_mask)
1153 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
1154 FadeExt(fade_mask, fading.fade_mode, FADE_TYPE_FADE_IN);
1156 FadeExt(fade_mask, FADE_MODE_FADE_IN, FADE_TYPE_FADE_IN);
1159 void FadeOut(int fade_mask)
1161 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
1162 FadeExt(fade_mask, fading.fade_mode, FADE_TYPE_FADE_OUT);
1164 FadeExt(fade_mask, FADE_MODE_FADE_OUT, FADE_TYPE_FADE_OUT);
1166 global.border_status = game_status;
1169 static void FadeSetLeaveNext(struct TitleFadingInfo fading_leave, boolean set)
1171 static struct TitleFadingInfo fading_leave_stored;
1174 fading_leave_stored = fading_leave;
1176 fading = fading_leave_stored;
1179 void FadeSetEnterMenu()
1181 fading = menu.enter_menu;
1184 printf("::: storing enter_menu\n");
1187 FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
1190 void FadeSetLeaveMenu()
1192 fading = menu.leave_menu;
1195 printf("::: storing leave_menu\n");
1198 FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
1201 void FadeSetEnterScreen()
1203 fading = menu.enter_screen[game_status];
1206 printf("::: storing leave_screen[%d]\n", game_status);
1209 FadeSetLeaveNext(menu.leave_screen[game_status], TRUE); /* store */
1212 void FadeSetNextScreen()
1214 fading = menu.next_screen;
1217 printf("::: storing next_screen\n");
1220 // (do not overwrite fade mode set by FadeSetEnterScreen)
1221 // FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
1224 void FadeSetLeaveScreen()
1227 printf("::: recalling last stored value\n");
1230 FadeSetLeaveNext(menu.leave_screen[game_status], FALSE); /* recall */
1233 void FadeSetFromType(int type)
1235 if (type & TYPE_ENTER_SCREEN)
1236 FadeSetEnterScreen();
1237 else if (type & TYPE_ENTER)
1239 else if (type & TYPE_LEAVE)
1243 void FadeSetDisabled()
1245 static struct TitleFadingInfo fading_none = { FADE_MODE_NONE, -1, -1, -1 };
1247 fading = fading_none;
1250 void FadeSkipNextFadeIn()
1252 FadeExt(0, FADE_MODE_SKIP_FADE_IN, FADE_TYPE_SKIP);
1255 void FadeSkipNextFadeOut()
1257 FadeExt(0, FADE_MODE_SKIP_FADE_OUT, FADE_TYPE_SKIP);
1260 void SetWindowBackgroundImageIfDefined(int graphic)
1262 if (graphic_info[graphic].bitmap)
1263 SetWindowBackgroundBitmap(graphic_info[graphic].bitmap);
1266 void SetMainBackgroundImageIfDefined(int graphic)
1268 if (graphic_info[graphic].bitmap)
1269 SetMainBackgroundBitmap(graphic_info[graphic].bitmap);
1272 void SetDoorBackgroundImageIfDefined(int graphic)
1274 if (graphic_info[graphic].bitmap)
1275 SetDoorBackgroundBitmap(graphic_info[graphic].bitmap);
1278 void SetWindowBackgroundImage(int graphic)
1280 SetWindowBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
1281 graphic_info[graphic].bitmap ?
1282 graphic_info[graphic].bitmap :
1283 graphic_info[IMG_BACKGROUND].bitmap);
1286 void SetMainBackgroundImage(int graphic)
1288 SetMainBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
1289 graphic_info[graphic].bitmap ?
1290 graphic_info[graphic].bitmap :
1291 graphic_info[IMG_BACKGROUND].bitmap);
1294 void SetDoorBackgroundImage(int graphic)
1296 SetDoorBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
1297 graphic_info[graphic].bitmap ?
1298 graphic_info[graphic].bitmap :
1299 graphic_info[IMG_BACKGROUND].bitmap);
1302 void SetPanelBackground()
1305 struct GraphicInfo *gfx = &graphic_info[IMG_BACKGROUND_PANEL];
1308 BlitBitmapTiled(gfx->bitmap, bitmap_db_panel, gfx->src_x, gfx->src_y,
1309 gfx->width, gfx->height, 0, 0, DXSIZE, DYSIZE);
1311 /* (ClearRectangle() only needed if panel bitmap is smaller than panel) */
1312 ClearRectangle(bitmap_db_panel, DX, DY, DXSIZE, DYSIZE);
1313 BlitBitmap(gfx->bitmap, bitmap_db_panel, gfx->src_x, gfx->src_y,
1314 MIN(gfx->width, DXSIZE), MIN(gfx->height, DYSIZE), 0, 0);
1317 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, bitmap_db_panel,
1318 DOOR_GFX_PAGEX5, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE, 0, 0);
1321 SetDoorBackgroundBitmap(bitmap_db_panel);
1324 void DrawBackground(int x, int y, int width, int height)
1326 /* !!! "drawto" might still point to playfield buffer here (see below) !!! */
1327 /* (when entering hall of fame after playing) */
1329 ClearRectangleOnBackground(drawto, x, y, width, height);
1331 ClearRectangleOnBackground(backbuffer, x, y, width, height);
1337 if (IN_GFX_FIELD_FULL(x, y))
1338 redraw_mask |= REDRAW_FIELD;
1339 else if (IN_GFX_DOOR_1(x, y))
1340 redraw_mask |= REDRAW_DOOR_1;
1341 else if (IN_GFX_DOOR_2(x, y))
1342 redraw_mask |= REDRAW_DOOR_2;
1343 else if (IN_GFX_DOOR_3(x, y))
1344 redraw_mask |= REDRAW_DOOR_3;
1346 /* (this only works for the current arrangement of playfield and panels) */
1348 redraw_mask |= REDRAW_FIELD;
1349 else if (y < gfx.vy)
1350 redraw_mask |= REDRAW_DOOR_1;
1352 redraw_mask |= REDRAW_DOOR_2;
1356 /* (this is just wrong (when drawing to one of the two door panel areas)) */
1357 redraw_mask |= REDRAW_FIELD;
1361 void DrawBackgroundForFont(int x, int y, int width, int height, int font_nr)
1363 struct FontBitmapInfo *font = getFontBitmapInfo(font_nr);
1365 if (font->bitmap == NULL)
1368 DrawBackground(x, y, width, height);
1371 void DrawBackgroundForGraphic(int x, int y, int width, int height, int graphic)
1373 struct GraphicInfo *g = &graphic_info[graphic];
1375 if (g->bitmap == NULL)
1378 DrawBackground(x, y, width, height);
1383 /* !!! "drawto" might still point to playfield buffer here (see above) !!! */
1384 /* (when entering hall of fame after playing) */
1385 DrawBackground(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
1387 /* !!! maybe this should be done before clearing the background !!! */
1388 if (setup.soft_scrolling && game_status == GAME_MODE_PLAYING)
1390 ClearRectangle(fieldbuffer, 0, 0, FXSIZE, FYSIZE);
1391 SetDrawtoField(DRAW_BUFFERED);
1394 SetDrawtoField(DRAW_BACKBUFFER);
1397 void MarkTileDirty(int x, int y)
1399 int xx = redraw_x1 + x;
1400 int yy = redraw_y1 + y;
1402 if (!redraw[xx][yy])
1405 redraw[xx][yy] = TRUE;
1406 redraw_mask |= REDRAW_TILES;
1409 void SetBorderElement()
1413 BorderElement = EL_EMPTY;
1415 for (y = 0; y < lev_fieldy && BorderElement == EL_EMPTY; y++)
1417 for (x = 0; x < lev_fieldx; x++)
1419 if (!IS_INDESTRUCTIBLE(Feld[x][y]))
1420 BorderElement = EL_STEELWALL;
1422 if (y != 0 && y != lev_fieldy - 1 && x != lev_fieldx - 1)
1428 void FloodFillLevel(int from_x, int from_y, int fill_element,
1429 short field[MAX_LEV_FIELDX][MAX_LEV_FIELDY],
1430 int max_fieldx, int max_fieldy)
1434 static int check[4][2] = { { -1, 0 }, { 0, -1 }, { 1, 0 }, { 0, 1 } };
1435 static int safety = 0;
1437 /* check if starting field still has the desired content */
1438 if (field[from_x][from_y] == fill_element)
1443 if (safety > max_fieldx * max_fieldy)
1444 Error(ERR_EXIT, "Something went wrong in 'FloodFill()'. Please debug.");
1446 old_element = field[from_x][from_y];
1447 field[from_x][from_y] = fill_element;
1449 for (i = 0; i < 4; i++)
1451 x = from_x + check[i][0];
1452 y = from_y + check[i][1];
1454 if (IN_FIELD(x, y, max_fieldx, max_fieldy) && field[x][y] == old_element)
1455 FloodFillLevel(x, y, fill_element, field, max_fieldx, max_fieldy);
1461 void SetRandomAnimationValue(int x, int y)
1463 gfx.anim_random_frame = GfxRandom[x][y];
1466 inline int getGraphicAnimationFrame(int graphic, int sync_frame)
1468 /* animation synchronized with global frame counter, not move position */
1469 if (graphic_info[graphic].anim_global_sync || sync_frame < 0)
1470 sync_frame = FrameCounter;
1472 return getAnimationFrame(graphic_info[graphic].anim_frames,
1473 graphic_info[graphic].anim_delay,
1474 graphic_info[graphic].anim_mode,
1475 graphic_info[graphic].anim_start_frame,
1479 void getSizedGraphicSourceExt(int graphic, int frame, int tilesize_raw,
1480 Bitmap **bitmap, int *x, int *y,
1481 boolean get_backside)
1485 int width_mult, width_div;
1486 int height_mult, height_div;
1490 { 15, 16, 2, 3 }, /* 1 x 1 */
1491 { 7, 8, 2, 3 }, /* 2 x 2 */
1492 { 3, 4, 2, 3 }, /* 4 x 4 */
1493 { 1, 2, 2, 3 }, /* 8 x 8 */
1494 { 0, 1, 2, 3 }, /* 16 x 16 */
1495 { 0, 1, 0, 1 }, /* 32 x 32 */
1497 struct GraphicInfo *g = &graphic_info[graphic];
1498 Bitmap *src_bitmap = g->bitmap;
1499 int tilesize = MIN(MAX(1, tilesize_raw), TILESIZE);
1500 int offset_calc_pos = log_2(tilesize);
1501 int width_mult = offset_calc[offset_calc_pos].width_mult;
1502 int width_div = offset_calc[offset_calc_pos].width_div;
1503 int height_mult = offset_calc[offset_calc_pos].height_mult;
1504 int height_div = offset_calc[offset_calc_pos].height_div;
1505 int startx = src_bitmap->width * width_mult / width_div;
1506 int starty = src_bitmap->height * height_mult / height_div;
1508 int src_x = (g->src_x + (get_backside ? g->offset2_x : 0)) *
1509 tilesize / TILESIZE;
1510 int src_y = (g->src_y + (get_backside ? g->offset2_y : 0)) *
1511 tilesize / TILESIZE;
1513 int src_x = g->src_x * tilesize / TILESIZE;
1514 int src_y = g->src_y * tilesize / TILESIZE;
1516 int width = g->width * tilesize / TILESIZE;
1517 int height = g->height * tilesize / TILESIZE;
1518 int offset_x = g->offset_x * tilesize / TILESIZE;
1519 int offset_y = g->offset_y * tilesize / TILESIZE;
1521 if (g->offset_y == 0) /* frames are ordered horizontally */
1523 int max_width = g->anim_frames_per_line * width;
1524 int pos = (src_y / height) * max_width + src_x + frame * offset_x;
1526 src_x = pos % max_width;
1527 src_y = src_y % height + pos / max_width * height;
1529 else if (g->offset_x == 0) /* frames are ordered vertically */
1531 int max_height = g->anim_frames_per_line * height;
1532 int pos = (src_x / width) * max_height + src_y + frame * offset_y;
1534 src_x = src_x % width + pos / max_height * width;
1535 src_y = pos % max_height;
1537 else /* frames are ordered diagonally */
1539 src_x = src_x + frame * offset_x;
1540 src_y = src_y + frame * offset_y;
1543 *bitmap = src_bitmap;
1544 *x = startx + src_x;
1545 *y = starty + src_y;
1548 void getFixedGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
1549 int *x, int *y, boolean get_backside)
1551 getSizedGraphicSourceExt(graphic, frame, TILESIZE, bitmap, x, y,
1555 void getSizedGraphicSource(int graphic, int frame, int tilesize_raw,
1556 Bitmap **bitmap, int *x, int *y)
1558 getSizedGraphicSourceExt(graphic, frame, tilesize_raw, bitmap, x, y, FALSE);
1561 void getFixedGraphicSource(int graphic, int frame,
1562 Bitmap **bitmap, int *x, int *y)
1564 getSizedGraphicSourceExt(graphic, frame, TILESIZE, bitmap, x, y, FALSE);
1567 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
1570 getSizedGraphicSource(graphic, 0, MINI_TILESIZE, bitmap, x, y);
1572 struct GraphicInfo *g = &graphic_info[graphic];
1573 int mini_startx = 0;
1574 int mini_starty = g->bitmap->height * 2 / 3;
1576 *bitmap = g->bitmap;
1577 *x = mini_startx + g->src_x / 2;
1578 *y = mini_starty + g->src_y / 2;
1582 inline void getGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
1583 int *x, int *y, boolean get_backside)
1585 struct GraphicInfo *g = &graphic_info[graphic];
1586 int src_x = g->src_x + (get_backside ? g->offset2_x : 0);
1587 int src_y = g->src_y + (get_backside ? g->offset2_y : 0);
1591 if (TILESIZE_VAR != TILESIZE)
1592 return getSizedGraphicSourceExt(graphic, frame, TILESIZE_VAR, bitmap, x, y,
1596 *bitmap = g->bitmap;
1598 if (g->offset_y == 0) /* frames are ordered horizontally */
1600 int max_width = g->anim_frames_per_line * g->width;
1601 int pos = (src_y / g->height) * max_width + src_x + frame * g->offset_x;
1603 *x = pos % max_width;
1604 *y = src_y % g->height + pos / max_width * g->height;
1606 else if (g->offset_x == 0) /* frames are ordered vertically */
1608 int max_height = g->anim_frames_per_line * g->height;
1609 int pos = (src_x / g->width) * max_height + src_y + frame * g->offset_y;
1611 *x = src_x % g->width + pos / max_height * g->width;
1612 *y = pos % max_height;
1614 else /* frames are ordered diagonally */
1616 *x = src_x + frame * g->offset_x;
1617 *y = src_y + frame * g->offset_y;
1621 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
1623 getGraphicSourceExt(graphic, frame, bitmap, x, y, FALSE);
1626 void DrawGraphic(int x, int y, int graphic, int frame)
1629 if (!IN_SCR_FIELD(x, y))
1631 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
1632 printf("DrawGraphic(): This should never happen!\n");
1638 DrawGraphicExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR, graphic,
1641 DrawGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic, frame);
1643 MarkTileDirty(x, y);
1646 void DrawFixedGraphic(int x, int y, int graphic, int frame)
1649 if (!IN_SCR_FIELD(x, y))
1651 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
1652 printf("DrawGraphic(): This should never happen!\n");
1657 DrawFixedGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic,
1659 MarkTileDirty(x, y);
1662 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
1668 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1670 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX_VAR, TILEY_VAR, x, y);
1672 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
1676 void DrawFixedGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
1682 getFixedGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1683 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
1686 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
1689 if (!IN_SCR_FIELD(x, y))
1691 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
1692 printf("DrawGraphicThruMask(): This should never happen!\n");
1698 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR,
1701 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic,
1704 MarkTileDirty(x, y);
1707 void DrawFixedGraphicThruMask(int x, int y, int graphic, int frame)
1710 if (!IN_SCR_FIELD(x, y))
1712 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
1713 printf("DrawGraphicThruMask(): This should never happen!\n");
1718 DrawFixedGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
1720 MarkTileDirty(x, y);
1723 void DrawGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y, int graphic,
1729 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1731 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1732 dst_x - src_x, dst_y - src_y);
1734 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX_VAR, TILEY_VAR,
1737 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dst_x, dst_y);
1741 void DrawFixedGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y,
1742 int graphic, int frame)
1747 getFixedGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1749 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1750 dst_x - src_x, dst_y - src_y);
1751 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dst_x, dst_y);
1754 void DrawSizedGraphic(int x, int y, int graphic, int frame, int tilesize)
1756 DrawSizedGraphicExt(drawto, SX + x * tilesize, SY + y * tilesize, graphic,
1758 MarkTileDirty(x / tilesize, y / tilesize);
1761 void DrawSizedGraphicExt(DrawBuffer *d, int x, int y, int graphic, int frame,
1767 getSizedGraphicSource(graphic, frame, tilesize, &src_bitmap, &src_x, &src_y);
1768 BlitBitmap(src_bitmap, d, src_x, src_y, tilesize, tilesize, x, y);
1771 void DrawMiniGraphic(int x, int y, int graphic)
1773 DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
1774 MarkTileDirty(x / 2, y / 2);
1777 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
1782 getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1783 BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
1786 inline static void DrawGraphicShiftedNormal(int x, int y, int dx, int dy,
1787 int graphic, int frame,
1788 int cut_mode, int mask_mode)
1793 int width = TILEX, height = TILEY;
1796 if (dx || dy) /* shifted graphic */
1798 if (x < BX1) /* object enters playfield from the left */
1805 else if (x > BX2) /* object enters playfield from the right */
1811 else if (x==BX1 && dx < 0) /* object leaves playfield to the left */
1817 else if (x==BX2 && dx > 0) /* object leaves playfield to the right */
1819 else if (dx) /* general horizontal movement */
1820 MarkTileDirty(x + SIGN(dx), y);
1822 if (y < BY1) /* object enters playfield from the top */
1824 if (cut_mode==CUT_BELOW) /* object completely above top border */
1832 else if (y > BY2) /* object enters playfield from the bottom */
1838 else if (y==BY1 && dy < 0) /* object leaves playfield to the top */
1844 else if (dy > 0 && cut_mode == CUT_ABOVE)
1846 if (y == BY2) /* object completely above bottom border */
1852 MarkTileDirty(x, y + 1);
1853 } /* object leaves playfield to the bottom */
1854 else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
1856 else if (dy) /* general vertical movement */
1857 MarkTileDirty(x, y + SIGN(dy));
1861 if (!IN_SCR_FIELD(x, y))
1863 printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
1864 printf("DrawGraphicShifted(): This should never happen!\n");
1870 width = width * TILESIZE_VAR / TILESIZE;
1871 height = height * TILESIZE_VAR / TILESIZE;
1872 cx = cx * TILESIZE_VAR / TILESIZE;
1873 cy = cy * TILESIZE_VAR / TILESIZE;
1874 dx = dx * TILESIZE_VAR / TILESIZE;
1875 dy = dy * TILESIZE_VAR / TILESIZE;
1878 if (width > 0 && height > 0)
1880 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1886 dst_x = FX + x * TILEX_VAR + dx;
1887 dst_y = FY + y * TILEY_VAR + dy;
1889 dst_x = FX + x * TILEX + dx;
1890 dst_y = FY + y * TILEY + dy;
1893 if (mask_mode == USE_MASKING)
1895 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1896 dst_x - src_x, dst_y - src_y);
1897 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1901 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1904 MarkTileDirty(x, y);
1908 inline static void DrawGraphicShiftedDouble(int x, int y, int dx, int dy,
1909 int graphic, int frame,
1910 int cut_mode, int mask_mode)
1916 int width = TILEX_VAR, height = TILEY_VAR;
1918 int width = TILEX, height = TILEY;
1922 int x2 = x + SIGN(dx);
1923 int y2 = y + SIGN(dy);
1925 /* !!! DOES NOT WORK FOR SLOW MOVEMENT !!! */
1926 int sync_frame = GfxFrame[LEVELX(x)][LEVELY(y)];
1928 /* movement with two-tile animations must be sync'ed with movement position,
1929 not with current GfxFrame (which can be higher when using slow movement) */
1930 int anim_pos = (dx ? ABS(dx) : ABS(dy));
1931 int anim_frames = graphic_info[graphic].anim_frames;
1933 /* (we also need anim_delay here for movement animations with less frames) */
1934 int anim_delay = graphic_info[graphic].anim_delay;
1935 int sync_frame = anim_pos * anim_frames * anim_delay / TILESIZE;
1937 int sync_frame = anim_pos * anim_frames / TILESIZE;
1940 boolean draw_start_tile = (cut_mode != CUT_ABOVE); /* only for falling! */
1941 boolean draw_end_tile = (cut_mode != CUT_BELOW); /* only for falling! */
1943 /* re-calculate animation frame for two-tile movement animation */
1944 frame = getGraphicAnimationFrame(graphic, sync_frame);
1948 printf("::: %d, %d, %d => %d [%d]\n",
1949 anim_pos, anim_frames, anim_delay, sync_frame, graphic);
1951 printf("::: %d, %d => %d\n",
1952 anim_pos, anim_frames, sync_frame);
1957 printf("::: %d [%d, %d] [%d] [%d]\n", frame, sync_frame, dy,
1958 GfxFrame[LEVELX(x)][LEVELY(y)], mask_mode);
1961 /* check if movement start graphic inside screen area and should be drawn */
1962 if (draw_start_tile && IN_SCR_FIELD(x1, y1))
1964 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, TRUE);
1967 dst_x = FX + x1 * TILEX_VAR;
1968 dst_y = FY + y1 * TILEY_VAR;
1970 dst_x = FX + x1 * TILEX;
1971 dst_y = FY + y1 * TILEY;
1974 if (mask_mode == USE_MASKING)
1976 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1977 dst_x - src_x, dst_y - src_y);
1978 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1982 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1985 MarkTileDirty(x1, y1);
1988 /* check if movement end graphic inside screen area and should be drawn */
1989 if (draw_end_tile && IN_SCR_FIELD(x2, y2))
1991 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
1994 dst_x = FX + x2 * TILEX_VAR;
1995 dst_y = FY + y2 * TILEY_VAR;
1997 dst_x = FX + x2 * TILEX;
1998 dst_y = FY + y2 * TILEY;
2001 if (mask_mode == USE_MASKING)
2003 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
2004 dst_x - src_x, dst_y - src_y);
2005 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
2009 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
2012 MarkTileDirty(x2, y2);
2016 static void DrawGraphicShifted(int x, int y, int dx, int dy,
2017 int graphic, int frame,
2018 int cut_mode, int mask_mode)
2022 DrawGraphic(x, y, graphic, frame);
2027 if (graphic_info[graphic].double_movement) /* EM style movement images */
2028 DrawGraphicShiftedDouble(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
2030 DrawGraphicShiftedNormal(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
2033 void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
2034 int frame, int cut_mode)
2036 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, USE_MASKING);
2039 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
2040 int cut_mode, int mask_mode)
2042 int lx = LEVELX(x), ly = LEVELY(y);
2046 if (IN_LEV_FIELD(lx, ly))
2048 SetRandomAnimationValue(lx, ly);
2050 graphic = el_act_dir2img(element, GfxAction[lx][ly], GfxDir[lx][ly]);
2051 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
2053 /* do not use double (EM style) movement graphic when not moving */
2054 if (graphic_info[graphic].double_movement && !dx && !dy)
2056 graphic = el_act_dir2img(element, ACTION_DEFAULT, GfxDir[lx][ly]);
2057 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
2060 else /* border element */
2062 graphic = el2img(element);
2063 frame = getGraphicAnimationFrame(graphic, -1);
2066 if (element == EL_EXPANDABLE_WALL)
2068 boolean left_stopped = FALSE, right_stopped = FALSE;
2070 if (!IN_LEV_FIELD(lx - 1, ly) || IS_WALL(Feld[lx - 1][ly]))
2071 left_stopped = TRUE;
2072 if (!IN_LEV_FIELD(lx + 1, ly) || IS_WALL(Feld[lx + 1][ly]))
2073 right_stopped = TRUE;
2075 if (left_stopped && right_stopped)
2077 else if (left_stopped)
2079 graphic = IMG_EXPANDABLE_WALL_GROWING_RIGHT;
2080 frame = graphic_info[graphic].anim_frames - 1;
2082 else if (right_stopped)
2084 graphic = IMG_EXPANDABLE_WALL_GROWING_LEFT;
2085 frame = graphic_info[graphic].anim_frames - 1;
2090 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
2091 else if (mask_mode == USE_MASKING)
2092 DrawGraphicThruMask(x, y, graphic, frame);
2094 DrawGraphic(x, y, graphic, frame);
2097 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
2098 int cut_mode, int mask_mode)
2100 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
2101 DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
2102 cut_mode, mask_mode);
2105 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
2108 DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
2111 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
2114 DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
2117 void DrawLevelElementThruMask(int x, int y, int element)
2119 DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
2122 void DrawLevelFieldThruMask(int x, int y)
2124 DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
2127 /* !!! implementation of quicksand is totally broken !!! */
2128 #define IS_CRUMBLED_TILE(x, y, e) \
2129 (GFX_CRUMBLED(e) && (!IN_LEV_FIELD(x, y) || \
2130 !IS_MOVING(x, y) || \
2131 (e) == EL_QUICKSAND_EMPTYING || \
2132 (e) == EL_QUICKSAND_FAST_EMPTYING))
2134 static void DrawLevelFieldCrumbledInnerCorners(int x, int y, int dx, int dy,
2139 int width, height, cx, cy;
2140 int sx = SCREENX(x), sy = SCREENY(y);
2141 int crumbled_border_size = graphic_info[graphic].border_size;
2144 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
2146 for (i = 1; i < 4; i++)
2148 int dxx = (i & 1 ? dx : 0);
2149 int dyy = (i & 2 ? dy : 0);
2152 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
2155 /* check if neighbour field is of same crumble type */
2156 boolean same = (IS_CRUMBLED_TILE(xx, yy, element) &&
2157 graphic_info[graphic].class ==
2158 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class);
2160 /* return if check prevents inner corner */
2161 if (same == (dxx == dx && dyy == dy))
2165 /* if we reach this point, we have an inner corner */
2167 getGraphicSource(graphic, 1, &src_bitmap, &src_x, &src_y);
2170 width = crumbled_border_size * TILESIZE_VAR / TILESIZE;
2171 height = crumbled_border_size * TILESIZE_VAR / TILESIZE;
2172 cx = (dx > 0 ? TILEX - crumbled_border_size : 0) * TILESIZE_VAR / TILESIZE;
2173 cy = (dy > 0 ? TILEY - crumbled_border_size : 0) * TILESIZE_VAR / TILESIZE;
2175 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
2176 width, height, FX + sx * TILEX_VAR + cx, FY + sy * TILEY_VAR + cy);
2178 width = crumbled_border_size;
2179 height = crumbled_border_size;
2180 cx = (dx > 0 ? TILEX - crumbled_border_size : 0);
2181 cy = (dy > 0 ? TILEY - crumbled_border_size : 0);
2183 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
2184 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
2188 static void DrawLevelFieldCrumbledBorders(int x, int y, int graphic, int frame,
2193 int width, height, bx, by, cx, cy;
2194 int sx = SCREENX(x), sy = SCREENY(y);
2195 int crumbled_border_size = graphic_info[graphic].border_size;
2198 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
2200 /* draw simple, sloppy, non-corner-accurate crumbled border */
2203 width = (dir == 1 || dir == 2 ? crumbled_border_size : TILEX);
2204 height = (dir == 0 || dir == 3 ? crumbled_border_size : TILEY);
2205 cx = (dir == 2 ? TILEX - crumbled_border_size : 0);
2206 cy = (dir == 3 ? TILEY - crumbled_border_size : 0);
2208 if (dir == 1 || dir == 2) /* left or right crumbled border */
2210 width = crumbled_border_size;
2212 cx = (dir == 2 ? TILEX - crumbled_border_size : 0);
2215 else /* top or bottom crumbled border */
2218 height = crumbled_border_size;
2220 cy = (dir == 3 ? TILEY - crumbled_border_size : 0);
2225 BlitBitmap(src_bitmap, drawto_field,
2226 src_x + cx * TILESIZE_VAR / TILESIZE,
2227 src_y + cy * TILESIZE_VAR / TILESIZE,
2228 width * TILESIZE_VAR / TILESIZE,
2229 height * TILESIZE_VAR / TILESIZE,
2230 FX + sx * TILEX_VAR + cx * TILESIZE_VAR / TILESIZE,
2231 FY + sy * TILEY_VAR + cy * TILESIZE_VAR / TILESIZE);
2233 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
2234 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
2237 /* (remaining middle border part must be at least as big as corner part) */
2238 if (!(graphic_info[graphic].style & STYLE_ACCURATE_BORDERS) ||
2239 crumbled_border_size >= TILESIZE / 3)
2242 /* correct corners of crumbled border, if needed */
2245 for (i = -1; i <= 1; i+=2)
2247 int xx = x + (dir == 0 || dir == 3 ? i : 0);
2248 int yy = y + (dir == 1 || dir == 2 ? i : 0);
2249 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
2252 /* check if neighbour field is of same crumble type */
2253 if (IS_CRUMBLED_TILE(xx, yy, element) &&
2254 graphic_info[graphic].class ==
2255 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
2257 /* no crumbled corner, but continued crumbled border */
2259 int c1 = (dir == 2 || dir == 3 ? TILESIZE - crumbled_border_size : 0);
2260 int c2 = (i == 1 ? TILESIZE - crumbled_border_size : 0);
2261 int b1 = (i == 1 ? crumbled_border_size :
2262 TILESIZE - 2 * crumbled_border_size);
2264 width = crumbled_border_size;
2265 height = crumbled_border_size;
2267 if (dir == 1 || dir == 2)
2283 BlitBitmap(src_bitmap, drawto_field,
2284 src_x + bx * TILESIZE_VAR / TILESIZE,
2285 src_y + by * TILESIZE_VAR / TILESIZE,
2286 width * TILESIZE_VAR / TILESIZE,
2287 height * TILESIZE_VAR / TILESIZE,
2288 FX + sx * TILEX_VAR + cx * TILESIZE_VAR / TILESIZE,
2289 FY + sy * TILEY_VAR + cy * TILESIZE_VAR / TILESIZE);
2291 BlitBitmap(src_bitmap, drawto_field, src_x + bx, src_y + by,
2292 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
2297 if (dir == 1 || dir == 2) /* left or right crumbled border */
2299 for (i = -1; i <= 1; i+=2)
2303 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
2306 /* check if neighbour field is of same crumble type */
2307 if (IS_CRUMBLED_TILE(xx, yy, element) &&
2308 graphic_info[graphic].class ==
2309 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
2311 /* no crumbled corner, but continued crumbled border */
2313 width = crumbled_border_size;
2314 height = crumbled_border_size;
2315 cx = (dir == 2 ? TILEX - crumbled_border_size : 0);
2316 cy = (i == 1 ? TILEY - crumbled_border_size : 0);
2318 by = (i == 1 ? crumbled_border_size :
2319 TILEY - 2 * crumbled_border_size);
2321 BlitBitmap(src_bitmap, drawto_field, src_x + bx, src_y + by,
2322 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
2326 else /* top or bottom crumbled border */
2328 for (i = -1; i <= 1; i+=2)
2332 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
2335 /* check if neighbour field is of same crumble type */
2336 if (IS_CRUMBLED_TILE(xx, yy, element) &&
2337 graphic_info[graphic].class ==
2338 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
2340 /* no crumbled corner, but continued crumbled border */
2342 width = crumbled_border_size;
2343 height = crumbled_border_size;
2344 cx = (i == 1 ? TILEX - crumbled_border_size : 0);
2345 cy = (dir == 3 ? TILEY - crumbled_border_size : 0);
2346 bx = (i == 1 ? crumbled_border_size :
2347 TILEX - 2 * crumbled_border_size);
2350 BlitBitmap(src_bitmap, drawto_field, src_x + bx, src_y + by,
2351 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
2358 static void DrawLevelFieldCrumbledExt(int x, int y, int graphic, int frame)
2360 int sx = SCREENX(x), sy = SCREENY(y);
2363 static int xy[4][2] =
2371 if (!IN_LEV_FIELD(x, y))
2374 element = TILE_GFX_ELEMENT(x, y);
2376 /* crumble field itself */
2377 if (IS_CRUMBLED_TILE(x, y, element))
2379 if (!IN_SCR_FIELD(sx, sy))
2382 for (i = 0; i < 4; i++)
2384 int xx = x + xy[i][0];
2385 int yy = y + xy[i][1];
2387 element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
2390 /* check if neighbour field is of same crumble type */
2392 if (IS_CRUMBLED_TILE(xx, yy, element) &&
2393 graphic_info[graphic].class ==
2394 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
2397 if (IS_CRUMBLED_TILE(xx, yy, element))
2401 DrawLevelFieldCrumbledBorders(x, y, graphic, frame, i);
2404 if ((graphic_info[graphic].style & STYLE_INNER_CORNERS) &&
2405 graphic_info[graphic].anim_frames == 2)
2407 for (i = 0; i < 4; i++)
2409 int dx = (i & 1 ? +1 : -1);
2410 int dy = (i & 2 ? +1 : -1);
2412 DrawLevelFieldCrumbledInnerCorners(x, y, dx, dy, graphic);
2416 MarkTileDirty(sx, sy);
2418 else /* center field not crumbled -- crumble neighbour fields */
2420 for (i = 0; i < 4; i++)
2422 int xx = x + xy[i][0];
2423 int yy = y + xy[i][1];
2424 int sxx = sx + xy[i][0];
2425 int syy = sy + xy[i][1];
2427 if (!IN_LEV_FIELD(xx, yy) ||
2428 !IN_SCR_FIELD(sxx, syy))
2431 if (Feld[xx][yy] == EL_ELEMENT_SNAPPING)
2434 element = TILE_GFX_ELEMENT(xx, yy);
2436 if (!IS_CRUMBLED_TILE(xx, yy, element))
2439 graphic = el_act2crm(element, ACTION_DEFAULT);
2441 DrawLevelFieldCrumbledBorders(xx, yy, graphic, 0, 3 - i);
2443 MarkTileDirty(sxx, syy);
2448 void DrawLevelFieldCrumbled(int x, int y)
2452 if (!IN_LEV_FIELD(x, y))
2456 /* !!! CHECK THIS !!! */
2459 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
2460 GFX_CRUMBLED(GfxElement[x][y]))
2463 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
2464 GfxElement[x][y] != EL_UNDEFINED &&
2465 GFX_CRUMBLED(GfxElement[x][y]))
2467 DrawLevelFieldCrumbledDigging(x, y, GfxDir[x][y], GfxFrame[x][y]);
2474 graphic = el_act2crm(TILE_GFX_ELEMENT(x, y), ACTION_DEFAULT);
2476 graphic = el_act2crm(Feld[x][y], ACTION_DEFAULT);
2479 DrawLevelFieldCrumbledExt(x, y, graphic, 0);
2482 void DrawLevelFieldCrumbledDigging(int x, int y, int direction,
2485 int graphic1 = el_act_dir2img(GfxElement[x][y], ACTION_DIGGING, direction);
2486 int graphic2 = el_act_dir2crm(GfxElement[x][y], ACTION_DIGGING, direction);
2487 int frame1 = getGraphicAnimationFrame(graphic1, step_frame);
2488 int frame2 = getGraphicAnimationFrame(graphic2, step_frame);
2489 int sx = SCREENX(x), sy = SCREENY(y);
2491 DrawGraphic(sx, sy, graphic1, frame1);
2492 DrawLevelFieldCrumbledExt(x, y, graphic2, frame2);
2495 void DrawLevelFieldCrumbledNeighbours(int x, int y)
2497 int sx = SCREENX(x), sy = SCREENY(y);
2498 static int xy[4][2] =
2507 for (i = 0; i < 4; i++)
2509 int xx = x + xy[i][0];
2510 int yy = y + xy[i][1];
2511 int sxx = sx + xy[i][0];
2512 int syy = sy + xy[i][1];
2514 if (!IN_LEV_FIELD(xx, yy) ||
2515 !IN_SCR_FIELD(sxx, syy) ||
2516 !GFX_CRUMBLED(Feld[xx][yy]) ||
2520 DrawLevelField(xx, yy);
2524 static int getBorderElement(int x, int y)
2528 { EL_STEELWALL_TOPLEFT, EL_INVISIBLE_STEELWALL_TOPLEFT },
2529 { EL_STEELWALL_TOPRIGHT, EL_INVISIBLE_STEELWALL_TOPRIGHT },
2530 { EL_STEELWALL_BOTTOMLEFT, EL_INVISIBLE_STEELWALL_BOTTOMLEFT },
2531 { EL_STEELWALL_BOTTOMRIGHT, EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
2532 { EL_STEELWALL_VERTICAL, EL_INVISIBLE_STEELWALL_VERTICAL },
2533 { EL_STEELWALL_HORIZONTAL, EL_INVISIBLE_STEELWALL_HORIZONTAL },
2534 { EL_STEELWALL, EL_INVISIBLE_STEELWALL }
2536 int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
2537 int steel_position = (x == -1 && y == -1 ? 0 :
2538 x == lev_fieldx && y == -1 ? 1 :
2539 x == -1 && y == lev_fieldy ? 2 :
2540 x == lev_fieldx && y == lev_fieldy ? 3 :
2541 x == -1 || x == lev_fieldx ? 4 :
2542 y == -1 || y == lev_fieldy ? 5 : 6);
2544 return border[steel_position][steel_type];
2547 void DrawScreenElement(int x, int y, int element)
2549 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
2550 DrawLevelFieldCrumbled(LEVELX(x), LEVELY(y));
2553 void DrawLevelElement(int x, int y, int element)
2555 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
2556 DrawScreenElement(SCREENX(x), SCREENY(y), element);
2559 void DrawScreenField(int x, int y)
2561 int lx = LEVELX(x), ly = LEVELY(y);
2562 int element, content;
2564 if (!IN_LEV_FIELD(lx, ly))
2566 if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
2569 element = getBorderElement(lx, ly);
2571 DrawScreenElement(x, y, element);
2576 element = Feld[lx][ly];
2577 content = Store[lx][ly];
2579 if (IS_MOVING(lx, ly))
2581 int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
2582 boolean cut_mode = NO_CUTTING;
2584 if (element == EL_QUICKSAND_EMPTYING ||
2585 element == EL_QUICKSAND_FAST_EMPTYING ||
2586 element == EL_MAGIC_WALL_EMPTYING ||
2587 element == EL_BD_MAGIC_WALL_EMPTYING ||
2588 element == EL_DC_MAGIC_WALL_EMPTYING ||
2589 element == EL_AMOEBA_DROPPING)
2590 cut_mode = CUT_ABOVE;
2591 else if (element == EL_QUICKSAND_FILLING ||
2592 element == EL_QUICKSAND_FAST_FILLING ||
2593 element == EL_MAGIC_WALL_FILLING ||
2594 element == EL_BD_MAGIC_WALL_FILLING ||
2595 element == EL_DC_MAGIC_WALL_FILLING)
2596 cut_mode = CUT_BELOW;
2599 if (lx == 9 && ly == 1)
2600 printf("::: %s [%d] [%d, %d] [%d]\n",
2601 EL_NAME(TILE_GFX_ELEMENT(lx, ly)),
2602 el_act2crm(TILE_GFX_ELEMENT(lx, ly), ACTION_DEFAULT),
2603 element_info[EL_QUICKSAND_EMPTYING].graphic[ACTION_DEFAULT],
2604 element_info[EL_QUICKSAND_EMPTYING].crumbled[ACTION_DEFAULT],
2605 GFX_CRUMBLED(TILE_GFX_ELEMENT(lx, ly)));
2608 if (cut_mode == CUT_ABOVE)
2610 DrawScreenElement(x, y, element);
2612 DrawScreenElementShifted(x, y, 0, 0, element, NO_CUTTING);
2615 DrawScreenElement(x, y, EL_EMPTY);
2618 DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
2619 else if (cut_mode == NO_CUTTING)
2620 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
2623 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
2626 if (cut_mode == CUT_BELOW &&
2627 IN_LEV_FIELD(lx, ly + 1) && IN_SCR_FIELD(x, y + 1))
2628 DrawLevelElement(lx, ly + 1, element);
2632 if (content == EL_ACID)
2634 int dir = MovDir[lx][ly];
2635 int newlx = lx + (dir == MV_LEFT ? -1 : dir == MV_RIGHT ? +1 : 0);
2636 int newly = ly + (dir == MV_UP ? -1 : dir == MV_DOWN ? +1 : 0);
2638 DrawLevelElementThruMask(newlx, newly, EL_ACID);
2641 else if (IS_BLOCKED(lx, ly))
2646 boolean cut_mode = NO_CUTTING;
2647 int element_old, content_old;
2649 Blocked2Moving(lx, ly, &oldx, &oldy);
2652 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
2653 MovDir[oldx][oldy] == MV_RIGHT);
2655 element_old = Feld[oldx][oldy];
2656 content_old = Store[oldx][oldy];
2658 if (element_old == EL_QUICKSAND_EMPTYING ||
2659 element_old == EL_QUICKSAND_FAST_EMPTYING ||
2660 element_old == EL_MAGIC_WALL_EMPTYING ||
2661 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
2662 element_old == EL_DC_MAGIC_WALL_EMPTYING ||
2663 element_old == EL_AMOEBA_DROPPING)
2664 cut_mode = CUT_ABOVE;
2666 DrawScreenElement(x, y, EL_EMPTY);
2669 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
2671 else if (cut_mode == NO_CUTTING)
2672 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
2675 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
2678 else if (IS_DRAWABLE(element))
2679 DrawScreenElement(x, y, element);
2681 DrawScreenElement(x, y, EL_EMPTY);
2684 void DrawLevelField(int x, int y)
2686 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
2687 DrawScreenField(SCREENX(x), SCREENY(y));
2688 else if (IS_MOVING(x, y))
2692 Moving2Blocked(x, y, &newx, &newy);
2693 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
2694 DrawScreenField(SCREENX(newx), SCREENY(newy));
2696 else if (IS_BLOCKED(x, y))
2700 Blocked2Moving(x, y, &oldx, &oldy);
2701 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
2702 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
2706 void DrawMiniElement(int x, int y, int element)
2710 graphic = el2edimg(element);
2711 DrawMiniGraphic(x, y, graphic);
2714 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
2716 int x = sx + scroll_x, y = sy + scroll_y;
2718 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
2719 DrawMiniElement(sx, sy, EL_EMPTY);
2720 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
2721 DrawMiniElement(sx, sy, Feld[x][y]);
2723 DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
2726 void DrawEnvelopeBackgroundTiles(int graphic, int startx, int starty,
2727 int x, int y, int xsize, int ysize,
2728 int tile_width, int tile_height)
2732 int dst_x = startx + x * tile_width;
2733 int dst_y = starty + y * tile_height;
2734 int width = graphic_info[graphic].width;
2735 int height = graphic_info[graphic].height;
2736 int inner_width_raw = MAX(width - 2 * tile_width, tile_width);
2737 int inner_height_raw = MAX(height - 2 * tile_height, tile_height);
2738 int inner_width = inner_width_raw - (inner_width_raw % tile_width);
2739 int inner_height = inner_height_raw - (inner_height_raw % tile_height);
2740 int inner_sx = (width >= 3 * tile_width ? tile_width : 0);
2741 int inner_sy = (height >= 3 * tile_height ? tile_height : 0);
2742 boolean draw_masked = graphic_info[graphic].draw_masked;
2744 getFixedGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
2746 if (src_bitmap == NULL || width < tile_width || height < tile_height)
2748 ClearRectangle(drawto, dst_x, dst_y, tile_width, tile_height);
2752 src_x += (x == 0 ? 0 : x == xsize - 1 ? width - tile_width :
2753 inner_sx + (x - 1) * tile_width % inner_width);
2754 src_y += (y == 0 ? 0 : y == ysize - 1 ? height - tile_height :
2755 inner_sy + (y - 1) * tile_height % inner_height);
2759 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
2760 dst_x - src_x, dst_y - src_y);
2761 BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, tile_width, tile_height,
2765 BlitBitmap(src_bitmap, drawto, src_x, src_y, tile_width, tile_height,
2769 void DrawEnvelopeBackground(int graphic, int startx, int starty,
2770 int x, int y, int xsize, int ysize, int font_nr)
2772 int font_width = getFontWidth(font_nr);
2773 int font_height = getFontHeight(font_nr);
2775 DrawEnvelopeBackgroundTiles(graphic, startx, starty, x, y, xsize, ysize,
2776 font_width, font_height);
2779 void AnimateEnvelope(int envelope_nr, int anim_mode, int action)
2781 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2782 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
2783 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
2784 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2785 boolean no_delay = (tape.warp_forward);
2786 unsigned int anim_delay = 0;
2787 int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
2788 int anim_delay_value = (no_delay ? 0 : frame_delay_value);
2789 int font_nr = FONT_ENVELOPE_1 + envelope_nr;
2790 int font_width = getFontWidth(font_nr);
2791 int font_height = getFontHeight(font_nr);
2792 int max_xsize = level.envelope[envelope_nr].xsize;
2793 int max_ysize = level.envelope[envelope_nr].ysize;
2794 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
2795 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
2796 int xend = max_xsize;
2797 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
2798 int xstep = (xstart < xend ? 1 : 0);
2799 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
2802 for (x = xstart, y = ystart; x <= xend && y <= yend; x += xstep, y += ystep)
2804 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
2805 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
2806 int sx = SX + (SXSIZE - xsize * font_width) / 2;
2807 int sy = SY + (SYSIZE - ysize * font_height) / 2;
2810 SetDrawtoField(DRAW_BUFFERED);
2813 BlitScreenToBitmap(backbuffer);
2815 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
2818 SetDrawtoField(DRAW_BACKBUFFER);
2820 for (yy = 0; yy < ysize; yy++)
2821 for (xx = 0; xx < xsize; xx++)
2822 DrawEnvelopeBackground(graphic, sx, sy, xx, yy, xsize, ysize, font_nr);
2825 DrawTextBuffer(sx + font_width, sy + font_height,
2826 level.envelope[envelope_nr].text, font_nr, max_xsize,
2827 xsize - 2, ysize - 2, 0, mask_mode,
2828 level.envelope[envelope_nr].autowrap,
2829 level.envelope[envelope_nr].centered, FALSE);
2831 DrawTextToTextArea(sx + font_width, sy + font_height,
2832 level.envelope[envelope_nr].text, font_nr, max_xsize,
2833 xsize - 2, ysize - 2, mask_mode);
2836 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
2839 WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
2843 void ShowEnvelope(int envelope_nr)
2845 int element = EL_ENVELOPE_1 + envelope_nr;
2846 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2847 int sound_opening = element_info[element].sound[ACTION_OPENING];
2848 int sound_closing = element_info[element].sound[ACTION_CLOSING];
2849 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2850 boolean no_delay = (tape.warp_forward);
2851 int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
2852 int wait_delay_value = (no_delay ? 0 : normal_delay_value);
2853 int anim_mode = graphic_info[graphic].anim_mode;
2854 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
2855 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
2857 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
2859 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
2861 if (anim_mode == ANIM_DEFAULT)
2862 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_OPENING);
2864 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_OPENING);
2867 Delay(wait_delay_value);
2869 WaitForEventToContinue();
2871 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
2873 if (anim_mode != ANIM_NONE)
2874 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_CLOSING);
2876 if (anim_mode == ANIM_DEFAULT)
2877 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_CLOSING);
2879 game.envelope_active = FALSE;
2881 SetDrawtoField(DRAW_BUFFERED);
2883 redraw_mask |= REDRAW_FIELD;
2887 static void setRequestPosition(int *x, int *y, boolean add_border_size)
2889 int border_size = request.border_size;
2890 int sx_center = (request.x != -1 ? request.x : SX + SXSIZE / 2);
2891 int sy_center = (request.y != -1 ? request.y : SY + SYSIZE / 2);
2892 int sx = sx_center - request.width / 2;
2893 int sy = sy_center - request.height / 2;
2895 if (add_border_size)
2905 void DrawEnvelopeRequest(char *text)
2907 char *text_final = text;
2908 char *text_door_style = NULL;
2909 int graphic = IMG_BACKGROUND_REQUEST;
2910 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
2911 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
2912 int font_nr = FONT_REQUEST;
2913 int font_width = getFontWidth(font_nr);
2914 int font_height = getFontHeight(font_nr);
2915 int border_size = request.border_size;
2916 int line_spacing = request.line_spacing;
2917 int line_height = font_height + line_spacing;
2918 int text_width = request.width - 2 * border_size;
2919 int text_height = request.height - 2 * border_size;
2920 int line_length = text_width / font_width;
2921 int max_lines = text_height / line_height;
2922 int width = request.width;
2923 int height = request.height;
2924 int tile_size = request.step_offset;
2925 int x_steps = width / tile_size;
2926 int y_steps = height / tile_size;
2930 if (request.wrap_single_words)
2932 char *src_text_ptr, *dst_text_ptr;
2934 text_door_style = checked_malloc(2 * strlen(text) + 1);
2936 src_text_ptr = text;
2937 dst_text_ptr = text_door_style;
2939 while (*src_text_ptr)
2941 if (*src_text_ptr == ' ' ||
2942 *src_text_ptr == '?' ||
2943 *src_text_ptr == '!')
2944 *dst_text_ptr++ = '\n';
2946 if (*src_text_ptr != ' ')
2947 *dst_text_ptr++ = *src_text_ptr;
2952 *dst_text_ptr = '\0';
2954 text_final = text_door_style;
2957 setRequestPosition(&sx, &sy, FALSE);
2959 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
2961 for (y = 0; y < y_steps; y++)
2962 for (x = 0; x < x_steps; x++)
2963 DrawEnvelopeBackgroundTiles(graphic, sx, sy,
2964 x, y, x_steps, y_steps,
2965 tile_size, tile_size);
2967 DrawTextBuffer(sx + border_size, sy + border_size, text_final, font_nr,
2968 line_length, -1, max_lines, line_spacing, mask_mode,
2969 request.autowrap, request.centered, FALSE);
2971 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
2972 RedrawGadget(tool_gadget[i]);
2974 // store readily prepared envelope request for later use when animating
2975 BlitBitmap(backbuffer, bitmap_db_cross, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2979 BlitBitmap(bitmap_db_store, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2980 BlitBitmap(bitmap_db_cross, backbuffer, sx, sy, width, height, sx, sy);
2982 redraw_mask = REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
2987 BlitBitmap(bitmap_db_store, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2989 redraw_mask = REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
2995 if (text_door_style)
2996 free(text_door_style);
3001 void AnimateEnvelopeRequest(int anim_mode, int action)
3003 int graphic = IMG_BACKGROUND_REQUEST;
3004 boolean draw_masked = graphic_info[graphic].draw_masked;
3006 int delay_value_normal = request.step_delay;
3007 int delay_value_fast = delay_value_normal / 2;
3009 int delay_value_normal = GameFrameDelay;
3010 int delay_value_fast = FfwdFrameDelay;
3012 boolean ffwd_delay = (tape.playing && tape.fast_forward);
3013 boolean no_delay = (tape.warp_forward);
3014 int delay_value = (ffwd_delay ? delay_value_fast : delay_value_normal);
3015 int anim_delay_value = (no_delay ? 0 : delay_value + 500 * 0);
3016 unsigned int anim_delay = 0;
3018 int width = request.width;
3019 int height = request.height;
3020 int tile_size = request.step_offset;
3021 int max_xsize = width / tile_size;
3022 int max_ysize = height / tile_size;
3023 int max_xsize_inner = max_xsize - 2;
3024 int max_ysize_inner = max_ysize - 2;
3026 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize_inner : 0);
3027 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize_inner : 0);
3028 int xend = max_xsize_inner;
3029 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize_inner : 0);
3030 int xstep = (xstart < xend ? 1 : 0);
3031 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
3034 for (x = xstart, y = ystart; x <= xend && y <= yend; x += xstep, y += ystep)
3036 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
3037 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
3038 int sx_center = (request.x != -1 ? request.x : SX + SXSIZE / 2);
3039 int sy_center = (request.y != -1 ? request.y : SY + SYSIZE / 2);
3040 int src_x = sx_center - width / 2;
3041 int src_y = sy_center - height / 2;
3042 int dst_x = sx_center - xsize * tile_size / 2;
3043 int dst_y = sy_center - ysize * tile_size / 2;
3044 int xsize_size_left = (xsize - 1) * tile_size;
3045 int ysize_size_top = (ysize - 1) * tile_size;
3046 int max_xsize_pos = (max_xsize - 1) * tile_size;
3047 int max_ysize_pos = (max_ysize - 1) * tile_size;
3050 BlitBitmap(bitmap_db_store, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
3053 for (yy = 0; yy < 2; yy++)
3055 for (xx = 0; xx < 2; xx++)
3057 int src_xx = src_x + xx * max_xsize_pos;
3058 int src_yy = src_y + yy * max_ysize_pos;
3059 int dst_xx = dst_x + xx * xsize_size_left;
3060 int dst_yy = dst_y + yy * ysize_size_top;
3061 int xx_size = (xx ? tile_size : xsize_size_left);
3062 int yy_size = (yy ? tile_size : ysize_size_top);
3065 BlitBitmapMasked(bitmap_db_cross, backbuffer,
3066 src_xx, src_yy, xx_size, yy_size, dst_xx, dst_yy);
3068 BlitBitmap(bitmap_db_cross, backbuffer,
3069 src_xx, src_yy, xx_size, yy_size, dst_xx, dst_yy);
3073 BlitBitmap(bitmap_db_cross, backbuffer,
3075 xsize_size_left, ysize_size_top,
3077 BlitBitmap(bitmap_db_cross, backbuffer,
3078 src_x + max_xsize_pos, src_y,
3079 tile_size, ysize_size_top,
3080 dst_x + xsize_size_left, dst_y);
3081 BlitBitmap(bitmap_db_cross, backbuffer,
3082 src_x, src_y + max_ysize_pos,
3083 xsize_size_left, tile_size,
3084 dst_x, dst_y + ysize_size_top);
3085 BlitBitmap(bitmap_db_cross, backbuffer,
3086 src_x + max_xsize_pos, src_y + max_ysize_pos,
3087 tile_size, tile_size,
3088 dst_x + xsize_size_left, dst_y + ysize_size_top);
3092 redraw_mask = REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
3093 // redraw_mask |= REDRAW_ALL | REDRAW_FROM_BACKBUFFER;
3095 /* CHECK AGAIN (previous code reactivated) */
3096 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
3106 WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
3112 void AnimateEnvelopeRequest(char *text, int anim_mode, int action)
3115 int envelope_nr = 0;
3118 int graphic = IMG_BACKGROUND_REQUEST;
3120 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
3122 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
3123 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
3124 boolean ffwd_delay = (tape.playing && tape.fast_forward);
3125 boolean no_delay = (tape.warp_forward);
3126 unsigned int anim_delay = 0;
3127 int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
3128 int anim_delay_value = (no_delay ? 0 : frame_delay_value + 500 * 0);
3130 int max_word_len = maxWordLengthInString(text);
3131 int font_nr = (max_word_len > 7 ? FONT_TEXT_1 : FONT_TEXT_2);
3133 int font_nr = FONT_ENVELOPE_1 + envelope_nr;
3135 int font_width = getFontWidth(font_nr);
3136 int font_height = getFontHeight(font_nr);
3137 int line_spacing = 2 * 1;
3141 int max_xsize = DXSIZE / font_width;
3142 // int max_ysize = DYSIZE / font_height;
3143 int max_ysize = DYSIZE / (font_height + line_spacing);
3145 int max_xsize = 7; /* tools.c: MAX_REQUEST_LINE_FONT1_LEN == 7 */
3146 int max_ysize = 13; /* tools.c: MAX_REQUEST_LINES == 13 */
3150 int max_xsize = level.envelope[envelope_nr].xsize;
3151 int max_ysize = level.envelope[envelope_nr].ysize;
3153 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
3154 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
3155 int xend = max_xsize;
3156 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
3157 int xstep = (xstart < xend ? 1 : 0);
3158 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
3163 char *text_copy = getStringCopy(text);
3166 font_nr = FONT_TEXT_2;
3168 if (maxWordLengthInString(text) > 7) /* MAX_REQUEST_LINE_FONT1_LEN == 7 */
3170 max_xsize = 10; /* tools.c: MAX_REQUEST_LINE_FONT2_LEN == 10 */
3171 font_nr = FONT_TEXT_1;
3174 int max_word_len = 0;
3176 char *text_copy = getStringCopy(text);
3178 font_nr = FONT_TEXT_2;
3180 for (text_ptr = text; *text_ptr; text_ptr++)
3182 max_word_len = (*text_ptr != ' ' ? max_word_len + 1 : 0);
3184 if (max_word_len > 7) /* tools.c: MAX_REQUEST_LINE_FONT1_LEN == 7 */
3186 max_xsize = 10; /* tools.c: MAX_REQUEST_LINE_FONT2_LEN == 10 */
3187 font_nr = FONT_TEXT_1;
3196 for (text_ptr = text_copy; *text_ptr; text_ptr++)
3197 if (*text_ptr == ' ')
3202 dDX = SX + (SXSIZE - DXSIZE) / 2 - DX;
3203 dDY = SY + (SYSIZE - DYSIZE) / 2 - DY;
3205 dDX = SX + SXSIZE / 2 - max_xsize * font_width / 2 - DX;
3206 dDY = SY + SYSIZE / 2 - max_ysize * font_height / 2 - DY;
3209 for (x = xstart, y = ystart; x <= xend && y <= yend; x += xstep, y += ystep)
3211 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
3212 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
3213 int sx = SX + (SXSIZE - xsize * font_width) / 2;
3214 // int sy = SX + (SYSIZE - ysize * font_height) / 2;
3215 int sy = SY + (SYSIZE - ysize * (font_height + line_spacing)) / 2;
3219 BlitBitmap(bitmap_db_store, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
3221 SetDrawtoField(DRAW_BUFFERED);
3224 BlitScreenToBitmap(backbuffer);
3226 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
3229 SetDrawtoField(DRAW_BACKBUFFER);
3232 for (yy = 0; yy < ysize; yy++)
3233 for (xx = 0; xx < xsize; xx++)
3234 DrawEnvelopeBackgroundTiles(graphic, sx, sy, xx, yy, xsize, ysize,
3235 getFontWidth(font_nr),
3236 getFontHeight(font_nr) + line_spacing);
3241 DrawTextBuffer(sx + font_width, sy + font_height + 8,
3242 text_copy, font_nr, max_xsize,
3243 xsize - 2, ysize - 2, line_spacing, mask_mode,
3244 FALSE, TRUE, FALSE);
3246 DrawTextBuffer(sx + font_width, sy + font_height,
3247 level.envelope[envelope_nr].text, font_nr, max_xsize,
3248 xsize - 2, ysize - 2, 0, mask_mode,
3249 level.envelope[envelope_nr].autowrap,
3250 level.envelope[envelope_nr].centered, FALSE);
3254 DrawTextToTextArea(sx + font_width, sy + font_height,
3255 level.envelope[envelope_nr].text, font_nr, max_xsize,
3256 xsize - 2, ysize - 2, mask_mode);
3259 /* copy request gadgets to door backbuffer */
3262 if ((ysize - 2) > 13)
3263 BlitBitmap(bitmap_db_door, drawto,
3264 DOOR_GFX_PAGEX1 + (DXSIZE - (xsize - 2) * font_width) / 2,
3265 DOOR_GFX_PAGEY1 + 13 * font_height,
3266 (xsize - 2) * font_width,
3267 (ysize - 2 - 13) * font_height,
3269 sy + font_height * (1 + 13));
3271 if ((ysize - 2) > 13)
3272 BlitBitmap(bitmap_db_door, drawto,
3273 DOOR_GFX_PAGEX1 + (DXSIZE - (xsize - 2) * font_width) / 2,
3274 DOOR_GFX_PAGEY1 + 11 * (font_height + line_spacing * 0),
3275 (xsize - 2) * font_width,
3276 (ysize - 2 - 13) * (font_height + line_spacing),
3278 sy + (font_height + line_spacing) * (1 + 13));
3280 if ((ysize - 2) > 13)
3281 BlitBitmap(bitmap_db_door, drawto,
3282 DOOR_GFX_PAGEX1 + (DXSIZE - (xsize - 2) * font_width) / 2,
3283 DOOR_GFX_PAGEY1 + 13 * font_height,
3284 (xsize - 2) * font_width,
3285 (ysize - 2 - 13) * font_height,
3287 sy + font_height * (1 + 13));
3291 redraw_mask = REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
3292 // redraw_mask |= REDRAW_ALL | REDRAW_FROM_BACKBUFFER;
3294 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
3304 WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
3314 void ShowEnvelopeRequest(char *text, unsigned int req_state, int action)
3317 int last_game_status = game_status; /* save current game status */
3318 // int last_draw_background_mask = gfx.draw_background_mask;
3321 int graphic = IMG_BACKGROUND_REQUEST;
3322 int sound_opening = SND_REQUEST_OPENING;
3323 int sound_closing = SND_REQUEST_CLOSING;
3325 int envelope_nr = 0;
3326 int element = EL_ENVELOPE_1 + envelope_nr;
3327 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
3328 int sound_opening = element_info[element].sound[ACTION_OPENING];
3329 int sound_closing = element_info[element].sound[ACTION_CLOSING];
3332 boolean ffwd_delay = (tape.playing && tape.fast_forward);
3333 boolean no_delay = (tape.warp_forward);
3334 int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
3335 int wait_delay_value = (no_delay ? 0 : normal_delay_value);
3337 int anim_mode = graphic_info[graphic].anim_mode;
3338 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
3339 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
3341 char *text_copy = getStringCopy(text);
3344 for (text_ptr = text_copy; *text_ptr; text_ptr++)
3345 if (*text_ptr == ' ')
3350 if (game_status == GAME_MODE_PLAYING)
3354 BlitScreenToBitmap(backbuffer);
3356 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
3357 BlitScreenToBitmap_EM(backbuffer);
3358 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
3359 BlitScreenToBitmap_SP(backbuffer);
3361 BlitScreenToBitmap_RND(backbuffer);
3364 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
3365 BlitScreenToBitmap_EM(backbuffer);
3366 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
3367 BlitScreenToBitmap_SP(backbuffer);
3370 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
3375 SetDrawtoField(DRAW_BACKBUFFER);
3377 // SetDrawBackgroundMask(REDRAW_NONE);
3379 if (action == ACTION_OPENING)
3381 BlitBitmap(backbuffer, bitmap_db_store, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
3384 if (req_state & REQ_ASK)
3386 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
3387 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
3389 else if (req_state & REQ_CONFIRM)
3391 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
3393 else if (req_state & REQ_PLAYER)
3395 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
3396 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
3397 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
3398 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
3403 DrawEnvelopeRequest(text);
3405 DrawEnvelopeRequest(text_copy);
3408 if (game_status != GAME_MODE_MAIN)
3412 /* force DOOR font inside door area */
3413 game_status = GAME_MODE_PSEUDO_DOOR;
3416 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
3418 if (action == ACTION_OPENING)
3420 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
3422 if (anim_mode == ANIM_DEFAULT)
3423 AnimateEnvelopeRequest(ANIM_DEFAULT, ACTION_OPENING);
3425 AnimateEnvelopeRequest(main_anim_mode, ACTION_OPENING);
3429 Delay(wait_delay_value);
3431 WaitForEventToContinue();
3436 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
3438 if (anim_mode != ANIM_NONE)
3439 AnimateEnvelopeRequest(main_anim_mode, ACTION_CLOSING);
3441 if (anim_mode == ANIM_DEFAULT)
3442 AnimateEnvelopeRequest(ANIM_DEFAULT, ACTION_CLOSING);
3445 game.envelope_active = FALSE;
3448 // game_status = last_game_status; /* restore current game status */
3451 /* !!! CHECK AGAIN (SEE BELOW) !!! */
3452 game_status = last_game_status; /* restore current game status */
3455 if (action == ACTION_CLOSING)
3457 if (game_status != GAME_MODE_MAIN)
3460 BlitBitmap(bitmap_db_store, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
3463 SetDrawtoField(DRAW_BUFFERED);
3466 // SetDrawBackgroundMask(last_draw_background_mask);
3469 redraw_mask = REDRAW_FIELD;
3470 // redraw_mask |= REDRAW_ALL;
3472 /* CHECK AGAIN (previous code reactivated) */
3473 redraw_mask |= REDRAW_FIELD;
3477 if (game_status == GAME_MODE_MAIN)
3483 /* (important: after "BackToFront()", but before "SetDrawtoField()") */
3484 game_status = last_game_status; /* restore current game status */
3488 if (action == ACTION_CLOSING &&
3489 game_status == GAME_MODE_PLAYING &&
3490 level.game_engine_type == GAME_ENGINE_TYPE_RND)
3491 SetDrawtoField(DRAW_BUFFERED);
3493 if (game_status == GAME_MODE_PLAYING &&
3494 level.game_engine_type == GAME_ENGINE_TYPE_RND)
3495 SetDrawtoField(DRAW_BUFFERED);
3507 void DrawPreviewElement(int dst_x, int dst_y, int element, int tilesize)
3511 int graphic = el2preimg(element);
3513 getSizedGraphicSource(graphic, 0, tilesize, &src_bitmap, &src_x, &src_y);
3514 BlitBitmap(src_bitmap, drawto, src_x, src_y, tilesize, tilesize, dst_x,dst_y);
3517 void DrawLevel(int draw_background_mask)
3522 SetMainBackgroundImage(IMG_BACKGROUND_PLAYING);
3523 SetDrawBackgroundMask(draw_background_mask);
3526 SetMainBackgroundImage(IMG_BACKGROUND_PLAYING);
3527 SetDrawBackgroundMask(REDRAW_FIELD);
3529 SetDrawBackgroundMask(REDRAW_NONE);
3535 for (x = BX1; x <= BX2; x++)
3536 for (y = BY1; y <= BY2; y++)
3537 DrawScreenField(x, y);
3539 redraw_mask |= REDRAW_FIELD;
3542 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
3546 for (x = 0; x < size_x; x++)
3547 for (y = 0; y < size_y; y++)
3548 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
3550 redraw_mask |= REDRAW_FIELD;
3553 static void DrawPreviewLevelPlayfieldExt(int from_x, int from_y)
3555 boolean show_level_border = (BorderElement != EL_EMPTY);
3556 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
3557 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
3558 int tile_size = preview.tile_size;
3559 int preview_width = preview.xsize * tile_size;
3560 int preview_height = preview.ysize * tile_size;
3561 int real_preview_xsize = MIN(level_xsize, preview.xsize);
3562 int real_preview_ysize = MIN(level_ysize, preview.ysize);
3563 int real_preview_width = real_preview_xsize * tile_size;
3564 int real_preview_height = real_preview_ysize * tile_size;
3565 int dst_x = SX + ALIGNED_XPOS(preview.x, preview_width, preview.align);
3566 int dst_y = SY + ALIGNED_YPOS(preview.y, preview_height, preview.valign);
3570 if (!IN_GFX_FIELD_FULL(dst_x, dst_y + preview_height - 1))
3575 dst_x += (preview_width - real_preview_width) / 2;
3576 dst_y += (preview_height - real_preview_height) / 2;
3578 DrawBackground(dst_x, dst_y, real_preview_width, real_preview_height);
3580 DrawBackground(dst_x, dst_y, preview_width, preview_height);
3582 dst_x += (preview_width - real_preview_width) / 2;
3583 dst_y += (preview_height - real_preview_height) / 2;
3586 for (x = 0; x < real_preview_xsize; x++)
3588 for (y = 0; y < real_preview_ysize; y++)
3590 int lx = from_x + x + (show_level_border ? -1 : 0);
3591 int ly = from_y + y + (show_level_border ? -1 : 0);
3592 int element = (IN_LEV_FIELD(lx, ly) ? level.field[lx][ly] :
3593 getBorderElement(lx, ly));
3595 DrawPreviewElement(dst_x + x * tile_size, dst_y + y * tile_size,
3596 element, tile_size);
3600 redraw_mask |= REDRAW_MICROLEVEL;
3603 #define MICROLABEL_EMPTY 0
3604 #define MICROLABEL_LEVEL_NAME 1
3605 #define MICROLABEL_LEVEL_AUTHOR_HEAD 2
3606 #define MICROLABEL_LEVEL_AUTHOR 3
3607 #define MICROLABEL_IMPORTED_FROM_HEAD 4
3608 #define MICROLABEL_IMPORTED_FROM 5
3609 #define MICROLABEL_IMPORTED_BY_HEAD 6
3610 #define MICROLABEL_IMPORTED_BY 7
3612 static int getMaxTextLength(struct TextPosInfo *pos, int font_nr)
3614 int max_text_width = SXSIZE;
3615 int font_width = getFontWidth(font_nr);
3617 if (pos->align == ALIGN_CENTER)
3618 max_text_width = (pos->x < SXSIZE / 2 ? pos->x * 2 : (SXSIZE - pos->x) * 2);
3619 else if (pos->align == ALIGN_RIGHT)
3620 max_text_width = pos->x;
3622 max_text_width = SXSIZE - pos->x;
3624 return max_text_width / font_width;
3627 static void DrawPreviewLevelLabelExt(int mode)
3629 struct TextPosInfo *pos = &menu.main.text.level_info_2;
3630 char label_text[MAX_OUTPUT_LINESIZE + 1];
3631 int max_len_label_text;
3633 int font_nr = pos->font;
3636 if (!IN_GFX_FIELD_FULL(pos->x, pos->y + getFontHeight(pos->font)))
3639 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
3640 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
3641 mode == MICROLABEL_IMPORTED_BY_HEAD)
3642 font_nr = pos->font_alt;
3644 int font_nr = FONT_TEXT_2;
3647 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
3648 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
3649 mode == MICROLABEL_IMPORTED_BY_HEAD)
3650 font_nr = FONT_TEXT_3;
3654 max_len_label_text = getMaxTextLength(pos, font_nr);
3656 max_len_label_text = SXSIZE / getFontWidth(font_nr);
3660 if (pos->size != -1)
3661 max_len_label_text = pos->size;
3664 for (i = 0; i < max_len_label_text; i++)
3665 label_text[i] = ' ';
3666 label_text[max_len_label_text] = '\0';
3668 if (strlen(label_text) > 0)
3671 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
3673 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
3674 int lypos = MICROLABEL2_YPOS;
3676 DrawText(lxpos, lypos, label_text, font_nr);
3681 (mode == MICROLABEL_LEVEL_NAME ? level.name :
3682 mode == MICROLABEL_LEVEL_AUTHOR_HEAD ? "created by" :
3683 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
3684 mode == MICROLABEL_IMPORTED_FROM_HEAD ? "imported from" :
3685 mode == MICROLABEL_IMPORTED_FROM ? leveldir_current->imported_from :
3686 mode == MICROLABEL_IMPORTED_BY_HEAD ? "imported by" :
3687 mode == MICROLABEL_IMPORTED_BY ? leveldir_current->imported_by :""),
3688 max_len_label_text);
3689 label_text[max_len_label_text] = '\0';
3691 if (strlen(label_text) > 0)
3694 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
3696 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
3697 int lypos = MICROLABEL2_YPOS;
3699 DrawText(lxpos, lypos, label_text, font_nr);
3703 redraw_mask |= REDRAW_MICROLEVEL;
3706 static void DrawPreviewLevelExt(boolean restart)
3708 static unsigned int scroll_delay = 0;
3709 static unsigned int label_delay = 0;
3710 static int from_x, from_y, scroll_direction;
3711 static int label_state, label_counter;
3712 unsigned int scroll_delay_value = preview.step_delay;
3713 boolean show_level_border = (BorderElement != EL_EMPTY);
3714 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
3715 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
3716 int last_game_status = game_status; /* save current game status */
3719 /* force PREVIEW font on preview level */
3720 game_status = GAME_MODE_PSEUDO_PREVIEW;
3728 if (preview.anim_mode == ANIM_CENTERED)
3730 if (level_xsize > preview.xsize)
3731 from_x = (level_xsize - preview.xsize) / 2;
3732 if (level_ysize > preview.ysize)
3733 from_y = (level_ysize - preview.ysize) / 2;
3736 from_x += preview.xoffset;
3737 from_y += preview.yoffset;
3739 scroll_direction = MV_RIGHT;
3743 DrawPreviewLevelPlayfieldExt(from_x, from_y);
3744 DrawPreviewLevelLabelExt(label_state);
3746 /* initialize delay counters */
3747 DelayReached(&scroll_delay, 0);
3748 DelayReached(&label_delay, 0);
3750 if (leveldir_current->name)
3752 struct TextPosInfo *pos = &menu.main.text.level_info_1;
3753 char label_text[MAX_OUTPUT_LINESIZE + 1];
3755 int font_nr = pos->font;
3757 int font_nr = FONT_TEXT_1;
3760 int max_len_label_text = getMaxTextLength(pos, font_nr);
3762 int max_len_label_text = SXSIZE / getFontWidth(font_nr);
3770 if (pos->size != -1)
3771 max_len_label_text = pos->size;
3774 strncpy(label_text, leveldir_current->name, max_len_label_text);
3775 label_text[max_len_label_text] = '\0';
3778 if (IN_GFX_FIELD_FULL(pos->x, pos->y + getFontHeight(pos->font)))
3779 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
3781 lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
3782 lypos = SY + MICROLABEL1_YPOS;
3784 DrawText(lxpos, lypos, label_text, font_nr);
3788 game_status = last_game_status; /* restore current game status */
3793 /* scroll preview level, if needed */
3794 if (preview.anim_mode != ANIM_NONE &&
3795 (level_xsize > preview.xsize || level_ysize > preview.ysize) &&
3796 DelayReached(&scroll_delay, scroll_delay_value))
3798 switch (scroll_direction)
3803 from_x -= preview.step_offset;
3804 from_x = (from_x < 0 ? 0 : from_x);
3807 scroll_direction = MV_UP;
3811 if (from_x < level_xsize - preview.xsize)
3813 from_x += preview.step_offset;
3814 from_x = (from_x > level_xsize - preview.xsize ?
3815 level_xsize - preview.xsize : from_x);
3818 scroll_direction = MV_DOWN;
3824 from_y -= preview.step_offset;
3825 from_y = (from_y < 0 ? 0 : from_y);
3828 scroll_direction = MV_RIGHT;
3832 if (from_y < level_ysize - preview.ysize)
3834 from_y += preview.step_offset;
3835 from_y = (from_y > level_ysize - preview.ysize ?
3836 level_ysize - preview.ysize : from_y);
3839 scroll_direction = MV_LEFT;
3846 DrawPreviewLevelPlayfieldExt(from_x, from_y);
3849 /* !!! THIS ALL SUCKS -- SHOULD BE CLEANLY REWRITTEN !!! */
3850 /* redraw micro level label, if needed */
3851 if (!strEqual(level.name, NAMELESS_LEVEL_NAME) &&
3852 !strEqual(level.author, ANONYMOUS_NAME) &&
3853 !strEqual(level.author, leveldir_current->name) &&
3854 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
3856 int max_label_counter = 23;
3858 if (leveldir_current->imported_from != NULL &&
3859 strlen(leveldir_current->imported_from) > 0)
3860 max_label_counter += 14;
3861 if (leveldir_current->imported_by != NULL &&
3862 strlen(leveldir_current->imported_by) > 0)
3863 max_label_counter += 14;
3865 label_counter = (label_counter + 1) % max_label_counter;
3866 label_state = (label_counter >= 0 && label_counter <= 7 ?
3867 MICROLABEL_LEVEL_NAME :
3868 label_counter >= 9 && label_counter <= 12 ?
3869 MICROLABEL_LEVEL_AUTHOR_HEAD :
3870 label_counter >= 14 && label_counter <= 21 ?
3871 MICROLABEL_LEVEL_AUTHOR :
3872 label_counter >= 23 && label_counter <= 26 ?
3873 MICROLABEL_IMPORTED_FROM_HEAD :
3874 label_counter >= 28 && label_counter <= 35 ?
3875 MICROLABEL_IMPORTED_FROM :
3876 label_counter >= 37 && label_counter <= 40 ?
3877 MICROLABEL_IMPORTED_BY_HEAD :
3878 label_counter >= 42 && label_counter <= 49 ?
3879 MICROLABEL_IMPORTED_BY : MICROLABEL_EMPTY);
3881 if (leveldir_current->imported_from == NULL &&
3882 (label_state == MICROLABEL_IMPORTED_FROM_HEAD ||
3883 label_state == MICROLABEL_IMPORTED_FROM))
3884 label_state = (label_state == MICROLABEL_IMPORTED_FROM_HEAD ?
3885 MICROLABEL_IMPORTED_BY_HEAD : MICROLABEL_IMPORTED_BY);
3887 DrawPreviewLevelLabelExt(label_state);
3890 game_status = last_game_status; /* restore current game status */
3893 void DrawPreviewLevelInitial()
3895 DrawPreviewLevelExt(TRUE);
3898 void DrawPreviewLevelAnimation()
3900 DrawPreviewLevelExt(FALSE);
3903 inline void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
3904 int graphic, int sync_frame, int mask_mode)
3906 int frame = getGraphicAnimationFrame(graphic, sync_frame);
3908 if (mask_mode == USE_MASKING)
3909 DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
3911 DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
3914 inline void DrawFixedGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
3915 int graphic, int sync_frame,
3918 int frame = getGraphicAnimationFrame(graphic, sync_frame);
3920 if (mask_mode == USE_MASKING)
3921 DrawFixedGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
3923 DrawFixedGraphicExt(dst_bitmap, x, y, graphic, frame);
3926 inline void DrawGraphicAnimation(int x, int y, int graphic)
3928 int lx = LEVELX(x), ly = LEVELY(y);
3930 if (!IN_SCR_FIELD(x, y))
3934 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR,
3935 graphic, GfxFrame[lx][ly], NO_MASKING);
3937 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
3938 graphic, GfxFrame[lx][ly], NO_MASKING);
3940 MarkTileDirty(x, y);
3943 inline void DrawFixedGraphicAnimation(int x, int y, int graphic)
3945 int lx = LEVELX(x), ly = LEVELY(y);
3947 if (!IN_SCR_FIELD(x, y))
3950 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
3951 graphic, GfxFrame[lx][ly], NO_MASKING);
3952 MarkTileDirty(x, y);
3955 void DrawLevelGraphicAnimation(int x, int y, int graphic)
3957 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
3960 void DrawLevelElementAnimation(int x, int y, int element)
3962 int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
3964 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
3967 inline void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
3969 int sx = SCREENX(x), sy = SCREENY(y);
3971 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
3974 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
3977 DrawGraphicAnimation(sx, sy, graphic);
3980 if (GFX_CRUMBLED(TILE_GFX_ELEMENT(x, y)))
3981 DrawLevelFieldCrumbled(x, y);
3983 if (GFX_CRUMBLED(Feld[x][y]))
3984 DrawLevelFieldCrumbled(x, y);
3988 void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
3990 int sx = SCREENX(x), sy = SCREENY(y);
3993 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
3996 graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
3998 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
4001 DrawGraphicAnimation(sx, sy, graphic);
4003 if (GFX_CRUMBLED(element))
4004 DrawLevelFieldCrumbled(x, y);
4007 static int getPlayerGraphic(struct PlayerInfo *player, int move_dir)
4009 if (player->use_murphy)
4011 /* this works only because currently only one player can be "murphy" ... */
4012 static int last_horizontal_dir = MV_LEFT;
4013 int graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir);
4015 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
4016 last_horizontal_dir = move_dir;
4018 if (graphic == IMG_SP_MURPHY) /* undefined => use special graphic */
4020 int direction = (player->is_snapping ? move_dir : last_horizontal_dir);
4022 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
4028 return el_act_dir2img(player->artwork_element, player->GfxAction,move_dir);
4031 static boolean equalGraphics(int graphic1, int graphic2)
4033 struct GraphicInfo *g1 = &graphic_info[graphic1];
4034 struct GraphicInfo *g2 = &graphic_info[graphic2];
4036 return (g1->bitmap == g2->bitmap &&
4037 g1->src_x == g2->src_x &&
4038 g1->src_y == g2->src_y &&
4039 g1->anim_frames == g2->anim_frames &&
4040 g1->anim_delay == g2->anim_delay &&
4041 g1->anim_mode == g2->anim_mode);
4044 void DrawAllPlayers()
4048 for (i = 0; i < MAX_PLAYERS; i++)
4049 if (stored_player[i].active)
4050 DrawPlayer(&stored_player[i]);
4053 void DrawPlayerField(int x, int y)
4055 if (!IS_PLAYER(x, y))
4058 DrawPlayer(PLAYERINFO(x, y));
4061 #define DRAW_PLAYER_OVER_PUSHED_ELEMENT 1
4063 void DrawPlayer(struct PlayerInfo *player)
4065 int jx = player->jx;
4066 int jy = player->jy;
4067 int move_dir = player->MovDir;
4068 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? +1 : 0);
4069 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? +1 : 0);
4070 int last_jx = (player->is_moving ? jx - dx : jx);
4071 int last_jy = (player->is_moving ? jy - dy : jy);
4072 int next_jx = jx + dx;
4073 int next_jy = jy + dy;
4074 boolean player_is_moving = (player->MovPos ? TRUE : FALSE);
4075 boolean player_is_opaque = FALSE;
4076 int sx = SCREENX(jx), sy = SCREENY(jy);
4077 int sxx = 0, syy = 0;
4078 int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
4080 int action = ACTION_DEFAULT;
4081 int last_player_graphic = getPlayerGraphic(player, move_dir);
4082 int last_player_frame = player->Frame;
4085 /* GfxElement[][] is set to the element the player is digging or collecting;
4086 remove also for off-screen player if the player is not moving anymore */
4087 if (IN_LEV_FIELD(jx, jy) && !player_is_moving)
4088 GfxElement[jx][jy] = EL_UNDEFINED;
4090 if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
4094 if (!IN_LEV_FIELD(jx, jy))
4096 printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
4097 printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
4098 printf("DrawPlayerField(): This should never happen!\n");
4103 if (element == EL_EXPLOSION)
4106 action = (player->is_pushing ? ACTION_PUSHING :
4107 player->is_digging ? ACTION_DIGGING :
4108 player->is_collecting ? ACTION_COLLECTING :
4109 player->is_moving ? ACTION_MOVING :
4110 player->is_snapping ? ACTION_SNAPPING :
4111 player->is_dropping ? ACTION_DROPPING :
4112 player->is_waiting ? player->action_waiting : ACTION_DEFAULT);
4114 if (player->is_waiting)
4115 move_dir = player->dir_waiting;
4117 InitPlayerGfxAnimation(player, action, move_dir);
4119 /* ----------------------------------------------------------------------- */
4120 /* draw things in the field the player is leaving, if needed */
4121 /* ----------------------------------------------------------------------- */
4123 if (player->is_moving)
4125 if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
4127 DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
4129 if (last_element == EL_DYNAMITE_ACTIVE ||
4130 last_element == EL_EM_DYNAMITE_ACTIVE ||
4131 last_element == EL_SP_DISK_RED_ACTIVE)
4132 DrawDynamite(last_jx, last_jy);
4134 DrawLevelFieldThruMask(last_jx, last_jy);
4136 else if (last_element == EL_DYNAMITE_ACTIVE ||
4137 last_element == EL_EM_DYNAMITE_ACTIVE ||
4138 last_element == EL_SP_DISK_RED_ACTIVE)
4139 DrawDynamite(last_jx, last_jy);
4141 /* !!! this is not enough to prevent flickering of players which are
4142 moving next to each others without a free tile between them -- this
4143 can only be solved by drawing all players layer by layer (first the
4144 background, then the foreground etc.) !!! => TODO */
4145 else if (!IS_PLAYER(last_jx, last_jy))
4146 DrawLevelField(last_jx, last_jy);
4149 DrawLevelField(last_jx, last_jy);
4152 if (player->is_pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
4153 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
4156 if (!IN_SCR_FIELD(sx, sy))
4159 /* ----------------------------------------------------------------------- */
4160 /* draw things behind the player, if needed */
4161 /* ----------------------------------------------------------------------- */
4164 DrawLevelElement(jx, jy, Back[jx][jy]);
4165 else if (IS_ACTIVE_BOMB(element))
4166 DrawLevelElement(jx, jy, EL_EMPTY);
4169 if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
4171 int old_element = GfxElement[jx][jy];
4172 int old_graphic = el_act_dir2img(old_element, action, move_dir);
4173 int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
4175 if (GFX_CRUMBLED(old_element))
4176 DrawLevelFieldCrumbledDigging(jx, jy, move_dir, player->StepFrame);
4178 DrawGraphic(sx, sy, old_graphic, frame);
4180 if (graphic_info[old_graphic].anim_mode & ANIM_OPAQUE_PLAYER)
4181 player_is_opaque = TRUE;
4185 GfxElement[jx][jy] = EL_UNDEFINED;
4187 /* make sure that pushed elements are drawn with correct frame rate */
4189 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
4191 if (player->is_pushing && player->is_moving && !IS_ANIM_MODE_CE(graphic))
4192 GfxFrame[jx][jy] = player->StepFrame;
4194 if (player->is_pushing && player->is_moving)
4195 GfxFrame[jx][jy] = player->StepFrame;
4198 DrawLevelField(jx, jy);
4202 #if !DRAW_PLAYER_OVER_PUSHED_ELEMENT
4203 /* ----------------------------------------------------------------------- */
4204 /* draw player himself */
4205 /* ----------------------------------------------------------------------- */
4207 graphic = getPlayerGraphic(player, move_dir);
4209 /* in the case of changed player action or direction, prevent the current
4210 animation frame from being restarted for identical animations */
4211 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
4212 player->Frame = last_player_frame;
4214 frame = getGraphicAnimationFrame(graphic, player->Frame);
4218 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
4219 sxx = player->GfxPos;
4221 syy = player->GfxPos;
4224 if (!setup.soft_scrolling && ScreenMovPos)
4227 if (player_is_opaque)
4228 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
4230 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
4232 if (SHIELD_ON(player))
4234 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
4235 IMG_SHIELD_NORMAL_ACTIVE);
4236 int frame = getGraphicAnimationFrame(graphic, -1);
4238 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
4242 #if DRAW_PLAYER_OVER_PUSHED_ELEMENT
4245 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
4246 sxx = player->GfxPos;
4248 syy = player->GfxPos;
4252 /* ----------------------------------------------------------------------- */
4253 /* draw things the player is pushing, if needed */
4254 /* ----------------------------------------------------------------------- */
4257 printf("::: %d, %d [%d, %d] [%d]\n",
4258 player->is_pushing, player_is_moving, player->GfxAction,
4259 player->is_moving, player_is_moving);
4263 if (player->is_pushing && player->is_moving)
4265 int px = SCREENX(jx), py = SCREENY(jy);
4266 int pxx = (TILEX - ABS(sxx)) * dx;
4267 int pyy = (TILEY - ABS(syy)) * dy;
4268 int gfx_frame = GfxFrame[jx][jy];
4274 if (!IS_MOVING(jx, jy)) /* push movement already finished */
4276 element = Feld[next_jx][next_jy];
4277 gfx_frame = GfxFrame[next_jx][next_jy];
4280 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
4283 sync_frame = (IS_ANIM_MODE_CE(graphic) ? gfx_frame : player->StepFrame);
4284 frame = getGraphicAnimationFrame(graphic, sync_frame);
4286 frame = getGraphicAnimationFrame(graphic, player->StepFrame);
4289 /* draw background element under pushed element (like the Sokoban field) */
4291 if (game.use_masked_pushing && IS_MOVING(jx, jy))
4293 /* this allows transparent pushing animation over non-black background */
4296 DrawLevelElement(jx, jy, Back[jx][jy]);
4298 DrawLevelElement(jx, jy, EL_EMPTY);
4300 if (Back[next_jx][next_jy])
4301 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
4303 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
4305 else if (Back[next_jx][next_jy])
4306 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
4308 if (Back[next_jx][next_jy])
4309 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
4313 printf("::: %d, %d, %d, %d [%d] [%d, %d, %d] [%d] [%d, %d] [%d, %d]\n",
4314 jx, px, player->GfxPos, player->StepFrame,
4319 GfxFrame[jx][jy], GfxFrame[next_jx][next_jy]);
4323 /* do not draw (EM style) pushing animation when pushing is finished */
4324 /* (two-tile animations usually do not contain start and end frame) */
4325 if (graphic_info[graphic].double_movement && !IS_MOVING(jx, jy))
4326 DrawLevelElement(next_jx, next_jy, Feld[next_jx][next_jy]);
4328 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
4330 /* masked drawing is needed for EMC style (double) movement graphics */
4331 /* !!! (ONLY WHEN DRAWING PUSHED ELEMENT OVER THE PLAYER) !!! */
4332 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
4337 #if DRAW_PLAYER_OVER_PUSHED_ELEMENT
4338 /* ----------------------------------------------------------------------- */
4339 /* draw player himself */
4340 /* ----------------------------------------------------------------------- */
4342 graphic = getPlayerGraphic(player, move_dir);
4344 /* in the case of changed player action or direction, prevent the current
4345 animation frame from being restarted for identical animations */
4346 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
4347 player->Frame = last_player_frame;
4349 frame = getGraphicAnimationFrame(graphic, player->Frame);
4353 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
4354 sxx = player->GfxPos;
4356 syy = player->GfxPos;
4359 if (!setup.soft_scrolling && ScreenMovPos)
4362 if (player_is_opaque)
4363 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
4365 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
4367 if (SHIELD_ON(player))
4369 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
4370 IMG_SHIELD_NORMAL_ACTIVE);
4371 int frame = getGraphicAnimationFrame(graphic, -1);
4373 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
4377 /* ----------------------------------------------------------------------- */
4378 /* draw things in front of player (active dynamite or dynabombs) */
4379 /* ----------------------------------------------------------------------- */
4381 if (IS_ACTIVE_BOMB(element))
4383 graphic = el2img(element);
4384 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
4386 if (game.emulation == EMU_SUPAPLEX)
4387 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
4389 DrawGraphicThruMask(sx, sy, graphic, frame);
4392 if (player_is_moving && last_element == EL_EXPLOSION)
4394 int element = (GfxElement[last_jx][last_jy] != EL_UNDEFINED ?
4395 GfxElement[last_jx][last_jy] : EL_EMPTY);
4396 int graphic = el_act2img(element, ACTION_EXPLODING);
4397 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
4398 int phase = ExplodePhase[last_jx][last_jy] - 1;
4399 int frame = getGraphicAnimationFrame(graphic, phase - delay);
4402 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
4405 /* ----------------------------------------------------------------------- */
4406 /* draw elements the player is just walking/passing through/under */
4407 /* ----------------------------------------------------------------------- */
4409 if (player_is_moving)
4411 /* handle the field the player is leaving ... */
4412 if (IS_ACCESSIBLE_INSIDE(last_element))
4413 DrawLevelField(last_jx, last_jy);
4414 else if (IS_ACCESSIBLE_UNDER(last_element))
4415 DrawLevelFieldThruMask(last_jx, last_jy);
4418 /* do not redraw accessible elements if the player is just pushing them */
4419 if (!player_is_moving || !player->is_pushing)
4421 /* ... and the field the player is entering */
4422 if (IS_ACCESSIBLE_INSIDE(element))
4423 DrawLevelField(jx, jy);
4424 else if (IS_ACCESSIBLE_UNDER(element))
4425 DrawLevelFieldThruMask(jx, jy);
4428 MarkTileDirty(sx, sy);
4431 /* ------------------------------------------------------------------------- */
4433 void WaitForEventToContinue()
4435 boolean still_wait = TRUE;
4437 /* simulate releasing mouse button over last gadget, if still pressed */
4439 HandleGadgets(-1, -1, 0);
4441 button_status = MB_RELEASED;
4457 case EVENT_BUTTONPRESS:
4458 case EVENT_KEYPRESS:
4462 case EVENT_KEYRELEASE:
4463 ClearPlayerAction();
4467 HandleOtherEvents(&event);
4471 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
4478 /* don't eat all CPU time */
4483 #define MAX_REQUEST_LINES 13
4484 #define MAX_REQUEST_LINE_FONT1_LEN 7
4485 #define MAX_REQUEST_LINE_FONT2_LEN 10
4489 static int RequestHandleEvents(unsigned int req_state)
4491 int last_game_status = game_status; /* save current game status */
4495 button_status = MB_RELEASED;
4497 request_gadget_id = -1;
4510 case EVENT_BUTTONPRESS:
4511 case EVENT_BUTTONRELEASE:
4512 case EVENT_MOTIONNOTIFY:
4514 if (event.type == EVENT_MOTIONNOTIFY)
4516 if (!PointerInWindow(window))
4517 continue; /* window and pointer are on different screens */
4522 motion_status = TRUE;
4523 mx = ((MotionEvent *) &event)->x;
4524 my = ((MotionEvent *) &event)->y;
4528 motion_status = FALSE;
4529 mx = ((ButtonEvent *) &event)->x;
4530 my = ((ButtonEvent *) &event)->y;
4531 if (event.type == EVENT_BUTTONPRESS)
4532 button_status = ((ButtonEvent *) &event)->button;
4534 button_status = MB_RELEASED;
4537 /* this sets 'request_gadget_id' */
4538 HandleGadgets(mx, my, button_status);
4540 switch (request_gadget_id)
4542 case TOOL_CTRL_ID_YES:
4545 case TOOL_CTRL_ID_NO:
4548 case TOOL_CTRL_ID_CONFIRM:
4549 result = TRUE | FALSE;
4552 case TOOL_CTRL_ID_PLAYER_1:
4555 case TOOL_CTRL_ID_PLAYER_2:
4558 case TOOL_CTRL_ID_PLAYER_3:
4561 case TOOL_CTRL_ID_PLAYER_4:
4572 case EVENT_KEYPRESS:
4573 switch (GetEventKey((KeyEvent *)&event, TRUE))
4576 if (req_state & REQ_CONFIRM)
4585 #if defined(TARGET_SDL2)
4595 if (req_state & REQ_PLAYER)
4599 case EVENT_KEYRELEASE:
4600 ClearPlayerAction();
4604 HandleOtherEvents(&event);
4608 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
4610 int joy = AnyJoystick();
4612 if (joy & JOY_BUTTON_1)
4614 else if (joy & JOY_BUTTON_2)
4620 if (game_status == GAME_MODE_PLAYING && local_player->LevelSolved_GameEnd)
4622 HandleGameActions();
4628 if (!PendingEvent()) /* delay only if no pending events */
4633 game_status = GAME_MODE_PSEUDO_DOOR;
4639 game_status = last_game_status; /* restore current game status */
4647 if (!PendingEvent()) /* delay only if no pending events */
4650 /* don't eat all CPU time */
4660 static boolean RequestDoor(char *text, unsigned int req_state)
4662 unsigned int old_door_state;
4663 int last_game_status = game_status; /* save current game status */
4664 int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
4665 int font_nr = FONT_TEXT_2;
4670 if (maxWordLengthInString(text) > MAX_REQUEST_LINE_FONT1_LEN)
4672 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
4673 font_nr = FONT_TEXT_1;
4676 if (game_status == GAME_MODE_PLAYING)
4679 BlitScreenToBitmap(backbuffer);
4681 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
4682 BlitScreenToBitmap_EM(backbuffer);
4683 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
4684 BlitScreenToBitmap_SP(backbuffer);
4688 /* disable deactivated drawing when quick-loading level tape recording */
4689 if (tape.playing && tape.deactivate_display)
4690 TapeDeactivateDisplayOff(TRUE);
4692 SetMouseCursor(CURSOR_DEFAULT);
4694 #if defined(NETWORK_AVALIABLE)
4695 /* pause network game while waiting for request to answer */
4696 if (options.network &&
4697 game_status == GAME_MODE_PLAYING &&
4698 req_state & REQUEST_WAIT_FOR_INPUT)
4699 SendToServer_PausePlaying();
4702 old_door_state = GetDoorState();
4704 /* simulate releasing mouse button over last gadget, if still pressed */
4706 HandleGadgets(-1, -1, 0);
4710 /* draw released gadget before proceeding */
4713 if (old_door_state & DOOR_OPEN_1)
4715 CloseDoor(DOOR_CLOSE_1);
4717 /* save old door content */
4719 BlitBitmap(bitmap_db_door_1, bitmap_db_door_1,
4720 0 * DXSIZE, 0, DXSIZE, DYSIZE, 1 * DXSIZE, 0);
4722 BlitBitmap(bitmap_db_door, bitmap_db_door,
4723 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
4724 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
4728 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
4729 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
4731 /* clear door drawing field */
4732 DrawBackground(DX, DY, DXSIZE, DYSIZE);
4734 /* force DOOR font inside door area */
4735 game_status = GAME_MODE_PSEUDO_DOOR;
4737 /* write text for request */
4738 for (text_ptr = text, ty = 0; ty < MAX_REQUEST_LINES; ty++)
4740 char text_line[max_request_line_len + 1];
4746 for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
4748 tc = *(text_ptr + tx);
4749 // if (!tc || tc == ' ')
4750 if (!tc || tc == ' ' || tc == '?' || tc == '!')
4754 if ((tc == '?' || tc == '!') && tl == 0)
4764 strncpy(text_line, text_ptr, tl);
4767 DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
4768 DY + 8 + ty * (getFontHeight(font_nr) + 2),
4769 text_line, font_nr);
4771 text_ptr += tl + (tc == ' ' ? 1 : 0);
4772 // text_ptr += tl + (tc == ' ' || tc == '?' || tc == '!' ? 1 : 0);
4775 game_status = last_game_status; /* restore current game status */
4777 if (req_state & REQ_ASK)
4779 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
4780 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
4782 else if (req_state & REQ_CONFIRM)
4784 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
4786 else if (req_state & REQ_PLAYER)
4788 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
4789 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
4790 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
4791 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
4794 /* copy request gadgets to door backbuffer */
4796 BlitBitmap(drawto, bitmap_db_door_1, DX, DY, DXSIZE, DYSIZE, 0, 0);
4798 BlitBitmap(drawto, bitmap_db_door,
4799 DX, DY, DXSIZE, DYSIZE,
4800 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
4803 OpenDoor(DOOR_OPEN_1);
4805 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
4807 if (game_status == GAME_MODE_PLAYING)
4809 SetPanelBackground();
4810 SetDrawBackgroundMask(REDRAW_DOOR_1);
4814 SetDrawBackgroundMask(REDRAW_FIELD);
4820 if (game_status != GAME_MODE_MAIN)
4823 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
4825 // ---------- handle request buttons ----------
4826 result = RequestHandleEvents(req_state);
4828 if (game_status != GAME_MODE_MAIN)
4833 if (!(req_state & REQ_STAY_OPEN))
4835 CloseDoor(DOOR_CLOSE_1);
4837 if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
4838 (req_state & REQ_REOPEN))
4839 OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
4844 if (game_status == GAME_MODE_PLAYING)
4846 SetPanelBackground();
4847 SetDrawBackgroundMask(REDRAW_DOOR_1);
4851 SetDrawBackgroundMask(REDRAW_FIELD);
4854 #if defined(NETWORK_AVALIABLE)
4855 /* continue network game after request */
4856 if (options.network &&
4857 game_status == GAME_MODE_PLAYING &&
4858 req_state & REQUEST_WAIT_FOR_INPUT)
4859 SendToServer_ContinuePlaying();
4862 /* restore deactivated drawing when quick-loading level tape recording */
4863 if (tape.playing && tape.deactivate_display)
4864 TapeDeactivateDisplayOn();
4869 static boolean RequestEnvelope(char *text, unsigned int req_state)
4876 if (game_status == GAME_MODE_PLAYING)
4880 BlitScreenToBitmap(backbuffer);
4882 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
4883 BlitScreenToBitmap_EM(backbuffer);
4884 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
4885 BlitScreenToBitmap_SP(backbuffer);
4887 BlitScreenToBitmap_RND(backbuffer);
4890 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
4891 BlitScreenToBitmap_EM(backbuffer);
4892 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
4893 BlitScreenToBitmap_SP(backbuffer);
4897 /* disable deactivated drawing when quick-loading level tape recording */
4898 if (tape.playing && tape.deactivate_display)
4899 TapeDeactivateDisplayOff(TRUE);
4901 SetMouseCursor(CURSOR_DEFAULT);
4903 #if defined(NETWORK_AVALIABLE)
4904 /* pause network game while waiting for request to answer */
4905 if (options.network &&
4906 game_status == GAME_MODE_PLAYING &&
4907 req_state & REQUEST_WAIT_FOR_INPUT)
4908 SendToServer_PausePlaying();
4911 /* simulate releasing mouse button over last gadget, if still pressed */
4913 HandleGadgets(-1, -1, 0);
4917 // (replace with setting corresponding request background)
4918 // SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
4919 // SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
4921 /* clear door drawing field */
4922 // DrawBackground(DX, DY, DXSIZE, DYSIZE);
4925 if (global.use_envelope_request)
4929 CreateToolButtons();
4935 if (req_state & REQ_ASK)
4937 MapGadgetExt(tool_gadget[TOOL_CTRL_ID_YES], FALSE);
4938 MapGadgetExt(tool_gadget[TOOL_CTRL_ID_NO], FALSE);
4940 else if (req_state & REQ_CONFIRM)
4942 MapGadgetExt(tool_gadget[TOOL_CTRL_ID_CONFIRM], FALSE);
4944 else if (req_state & REQ_PLAYER)
4946 MapGadgetExt(tool_gadget[TOOL_CTRL_ID_PLAYER_1], FALSE);
4947 MapGadgetExt(tool_gadget[TOOL_CTRL_ID_PLAYER_2], FALSE);
4948 MapGadgetExt(tool_gadget[TOOL_CTRL_ID_PLAYER_3], FALSE);
4949 MapGadgetExt(tool_gadget[TOOL_CTRL_ID_PLAYER_4], FALSE);
4952 if (req_state & REQ_ASK)
4954 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
4955 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
4957 else if (req_state & REQ_CONFIRM)
4959 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
4961 else if (req_state & REQ_PLAYER)
4963 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
4964 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
4965 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
4966 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
4971 ShowEnvelopeRequest(text, req_state, ACTION_OPENING);
4974 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4976 if ((req_state & REQ_ASK && (i == TOOL_CTRL_ID_YES ||
4977 i == TOOL_CTRL_ID_NO)) ||
4978 (req_state & REQ_CONFIRM && i == TOOL_CTRL_ID_CONFIRM) ||
4979 (req_state & REQ_PLAYER && (i == TOOL_CTRL_ID_PLAYER_1 &&
4980 i == TOOL_CTRL_ID_PLAYER_2 &&
4981 i == TOOL_CTRL_ID_PLAYER_3 &&
4982 i == TOOL_CTRL_ID_PLAYER_4)))
4984 int x = tool_gadget[i]->x + dDX;
4985 int y = tool_gadget[i]->y + dDY;
4987 ModifyGadget(tool_gadget[i], GDI_X, x, GDI_Y, y, GDI_END);
4992 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
4994 if (game_status == GAME_MODE_PLAYING)
4996 SetPanelBackground();
4997 SetDrawBackgroundMask(REDRAW_DOOR_1);
5001 SetDrawBackgroundMask(REDRAW_FIELD);
5008 if (game_status != GAME_MODE_MAIN)
5012 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
5014 // ---------- handle request buttons ----------
5015 result = RequestHandleEvents(req_state);
5017 if (game_status != GAME_MODE_MAIN)
5022 ShowEnvelopeRequest(text, req_state, ACTION_CLOSING);
5026 if (game_status == GAME_MODE_PLAYING)
5028 SetPanelBackground();
5029 SetDrawBackgroundMask(REDRAW_DOOR_1);
5033 SetDrawBackgroundMask(REDRAW_FIELD);
5036 #if defined(NETWORK_AVALIABLE)
5037 /* continue network game after request */
5038 if (options.network &&
5039 game_status == GAME_MODE_PLAYING &&
5040 req_state & REQUEST_WAIT_FOR_INPUT)
5041 SendToServer_ContinuePlaying();
5044 /* restore deactivated drawing when quick-loading level tape recording */
5045 if (tape.playing && tape.deactivate_display)
5046 TapeDeactivateDisplayOn();
5051 boolean Request(char *text, unsigned int req_state)
5053 if (global.use_envelope_request)
5054 return RequestEnvelope(text, req_state);
5056 return RequestDoor(text, req_state);
5059 #else // =====================================================================
5061 boolean Request(char *text, unsigned int req_state)
5063 int mx, my, ty, result = -1;
5064 unsigned int old_door_state;
5065 int last_game_status = game_status; /* save current game status */
5066 int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
5067 int font_nr = FONT_TEXT_2;
5069 int max_word_len = 0;
5075 global.use_envelope_request = 1;
5079 if (maxWordLengthInString(text) > MAX_REQUEST_LINE_FONT1_LEN)
5081 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
5082 font_nr = FONT_TEXT_1;
5085 for (text_ptr = text; *text_ptr; text_ptr++)
5087 max_word_len = (*text_ptr != ' ' ? max_word_len + 1 : 0);
5089 if (max_word_len > MAX_REQUEST_LINE_FONT1_LEN)
5091 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
5093 font_nr = FONT_TEXT_1;
5095 font_nr = FONT_LEVEL_NUMBER;
5103 if (game_status == GAME_MODE_PLAYING)
5106 BlitScreenToBitmap(backbuffer);
5108 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
5109 BlitScreenToBitmap_EM(backbuffer);
5110 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
5111 BlitScreenToBitmap_SP(backbuffer);
5115 /* disable deactivated drawing when quick-loading level tape recording */
5116 if (tape.playing && tape.deactivate_display)
5117 TapeDeactivateDisplayOff(TRUE);
5119 SetMouseCursor(CURSOR_DEFAULT);
5121 #if defined(NETWORK_AVALIABLE)
5122 /* pause network game while waiting for request to answer */
5123 if (options.network &&
5124 game_status == GAME_MODE_PLAYING &&
5125 req_state & REQUEST_WAIT_FOR_INPUT)
5126 SendToServer_PausePlaying();
5129 old_door_state = GetDoorState();
5131 /* simulate releasing mouse button over last gadget, if still pressed */
5133 HandleGadgets(-1, -1, 0);
5137 /* draw released gadget before proceeding */
5141 if (old_door_state & DOOR_OPEN_1 && !global.use_envelope_request)
5143 if (old_door_state & DOOR_OPEN_1)
5147 if (!global.use_envelope_request)
5148 CloseDoor(DOOR_CLOSE_1);
5150 CloseDoor(DOOR_CLOSE_1);
5153 /* save old door content */
5154 BlitBitmap(bitmap_db_door, bitmap_db_door,
5155 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
5156 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
5160 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
5163 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
5165 /* clear door drawing field */
5166 DrawBackground(DX, DY, DXSIZE, DYSIZE);
5168 /* force DOOR font inside door area */
5169 game_status = GAME_MODE_PSEUDO_DOOR;
5171 /* write text for request */
5172 for (text_ptr = text, ty = 0; ty < MAX_REQUEST_LINES; ty++)
5174 char text_line[max_request_line_len + 1];
5180 for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
5182 tc = *(text_ptr + tx);
5183 if (!tc || tc == ' ')
5194 strncpy(text_line, text_ptr, tl);
5197 DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
5198 DY + 8 + ty * (getFontHeight(font_nr) + 2),
5199 text_line, font_nr);
5201 text_ptr += tl + (tc == ' ' ? 1 : 0);
5204 game_status = last_game_status; /* restore current game status */
5207 if (global.use_envelope_request)
5211 CreateToolButtons();
5215 if (req_state & REQ_ASK)
5217 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
5218 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
5220 else if (req_state & REQ_CONFIRM)
5222 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
5224 else if (req_state & REQ_PLAYER)
5226 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
5227 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
5228 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
5229 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
5232 /* copy request gadgets to door backbuffer */
5233 BlitBitmap(drawto, bitmap_db_door,
5234 DX, DY, DXSIZE, DYSIZE,
5235 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
5238 if (global.use_envelope_request)
5240 ShowEnvelopeRequest(text, ACTION_OPENING);
5242 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
5244 if ((req_state & REQ_ASK && (i == TOOL_CTRL_ID_YES ||
5245 i == TOOL_CTRL_ID_NO)) ||
5246 (req_state & REQ_CONFIRM && i == TOOL_CTRL_ID_CONFIRM) ||
5247 (req_state & REQ_PLAYER && (i == TOOL_CTRL_ID_PLAYER_1 &&
5248 i == TOOL_CTRL_ID_PLAYER_2 &&
5249 i == TOOL_CTRL_ID_PLAYER_3 &&
5250 i == TOOL_CTRL_ID_PLAYER_4)))
5252 int x = tool_gadget[i]->x + dDX;
5253 int y = tool_gadget[i]->y + dDY;
5255 ModifyGadget(tool_gadget[i], GDI_X, x, GDI_Y, y, GDI_END);
5262 if (!global.use_envelope_request)
5263 OpenDoor(DOOR_OPEN_1);
5265 OpenDoor(DOOR_OPEN_1);
5268 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
5270 if (game_status == GAME_MODE_PLAYING)
5272 SetPanelBackground();
5273 SetDrawBackgroundMask(REDRAW_DOOR_1);
5277 SetDrawBackgroundMask(REDRAW_FIELD);
5284 if (game_status != GAME_MODE_MAIN && !global.use_envelope_request)
5287 if (game_status != GAME_MODE_MAIN)
5291 button_status = MB_RELEASED;
5293 request_gadget_id = -1;
5295 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
5307 case EVENT_BUTTONPRESS:
5308 case EVENT_BUTTONRELEASE:
5309 case EVENT_MOTIONNOTIFY:
5311 if (event.type == EVENT_MOTIONNOTIFY)
5313 if (!PointerInWindow(window))
5314 continue; /* window and pointer are on different screens */
5319 motion_status = TRUE;
5320 mx = ((MotionEvent *) &event)->x;
5321 my = ((MotionEvent *) &event)->y;
5325 motion_status = FALSE;
5326 mx = ((ButtonEvent *) &event)->x;
5327 my = ((ButtonEvent *) &event)->y;
5328 if (event.type == EVENT_BUTTONPRESS)
5329 button_status = ((ButtonEvent *) &event)->button;
5331 button_status = MB_RELEASED;
5334 /* this sets 'request_gadget_id' */
5335 HandleGadgets(mx, my, button_status);
5337 switch (request_gadget_id)
5339 case TOOL_CTRL_ID_YES:
5342 case TOOL_CTRL_ID_NO:
5345 case TOOL_CTRL_ID_CONFIRM:
5346 result = TRUE | FALSE;
5349 case TOOL_CTRL_ID_PLAYER_1:
5352 case TOOL_CTRL_ID_PLAYER_2:
5355 case TOOL_CTRL_ID_PLAYER_3:
5358 case TOOL_CTRL_ID_PLAYER_4:
5369 case EVENT_KEYPRESS:
5370 switch (GetEventKey((KeyEvent *)&event, TRUE))
5373 if (req_state & REQ_CONFIRM)
5382 #if defined(TARGET_SDL2)
5392 if (req_state & REQ_PLAYER)
5396 case EVENT_KEYRELEASE:
5397 ClearPlayerAction();
5401 HandleOtherEvents(&event);
5405 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
5407 int joy = AnyJoystick();
5409 if (joy & JOY_BUTTON_1)
5411 else if (joy & JOY_BUTTON_2)
5417 if (game_status == GAME_MODE_PLAYING && local_player->LevelSolved_GameEnd)
5419 HandleGameActions();
5425 if (!PendingEvent()) /* delay only if no pending events */
5430 game_status = GAME_MODE_PSEUDO_DOOR;
5436 game_status = last_game_status; /* restore current game status */
5444 if (!PendingEvent()) /* delay only if no pending events */
5447 /* don't eat all CPU time */
5454 if (game_status != GAME_MODE_MAIN)
5460 if (global.use_envelope_request)
5461 ShowEnvelopeRequest(text, ACTION_CLOSING);
5465 if (!(req_state & REQ_STAY_OPEN) && !global.use_envelope_request)
5467 if (!(req_state & REQ_STAY_OPEN))
5470 CloseDoor(DOOR_CLOSE_1);
5472 if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
5473 (req_state & REQ_REOPEN))
5474 OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
5479 if (game_status == GAME_MODE_PLAYING)
5481 SetPanelBackground();
5482 SetDrawBackgroundMask(REDRAW_DOOR_1);
5486 SetDrawBackgroundMask(REDRAW_FIELD);
5489 #if defined(NETWORK_AVALIABLE)
5490 /* continue network game after request */
5491 if (options.network &&
5492 game_status == GAME_MODE_PLAYING &&
5493 req_state & REQUEST_WAIT_FOR_INPUT)
5494 SendToServer_ContinuePlaying();
5497 /* restore deactivated drawing when quick-loading level tape recording */
5498 if (tape.playing && tape.deactivate_display)
5499 TapeDeactivateDisplayOn();
5506 static int compareDoorPartOrderInfo(const void *object1, const void *object2)
5508 const struct DoorPartOrderInfo *dpo1 = (struct DoorPartOrderInfo *)object1;
5509 const struct DoorPartOrderInfo *dpo2 = (struct DoorPartOrderInfo *)object2;
5512 if (dpo1->sort_priority != dpo2->sort_priority)
5513 compare_result = dpo1->sort_priority - dpo2->sort_priority;
5515 compare_result = dpo1->nr - dpo2->nr;
5517 return compare_result;
5520 void InitGraphicCompatibilityInfo_Doors()
5526 struct DoorInfo *door;
5530 { DOOR_1, IMG_DOOR_1_GFX_PART_1, IMG_DOOR_1_GFX_PART_8, &door_1 },
5531 { DOOR_2, IMG_DOOR_2_GFX_PART_1, IMG_DOOR_2_GFX_PART_8, &door_2 },
5533 { -1, -1, -1, NULL }
5535 struct Rect door_rect_list[] =
5537 { DX, DY, DXSIZE, DYSIZE },
5538 { VX, VY, VXSIZE, VYSIZE }
5542 for (i = 0; doors[i].door_token != -1; i++)
5544 int door_token = doors[i].door_token;
5545 int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
5546 int part_1 = doors[i].part_1;
5547 int part_8 = doors[i].part_8;
5548 int part_2 = part_1 + 1;
5549 int part_3 = part_1 + 2;
5550 struct DoorInfo *door = doors[i].door;
5551 struct Rect *door_rect = &door_rect_list[door_index];
5552 boolean door_gfx_redefined = FALSE;
5554 /* check if any door part graphic definitions have been redefined */
5556 for (j = 0; door_part_controls[j].door_token != -1; j++)
5558 struct DoorPartControlInfo *dpc = &door_part_controls[j];
5559 struct FileInfo *fi = getImageListEntryFromImageID(dpc->graphic);
5561 if (dpc->door_token == door_token && fi->redefined)
5562 door_gfx_redefined = TRUE;
5565 /* check for old-style door graphic/animation modifications */
5567 if (!door_gfx_redefined)
5569 if (door->anim_mode & ANIM_STATIC_PANEL)
5571 door->panel.step_xoffset = 0;
5572 door->panel.step_yoffset = 0;
5575 if (door->anim_mode & (ANIM_HORIZONTAL | ANIM_VERTICAL))
5577 struct GraphicInfo *g_part_1 = &graphic_info[part_1];
5578 struct GraphicInfo *g_part_2 = &graphic_info[part_2];
5579 int num_door_steps, num_panel_steps;
5581 /* remove door part graphics other than the two default wings */
5583 for (j = 0; door_part_controls[j].door_token != -1; j++)
5585 struct DoorPartControlInfo *dpc = &door_part_controls[j];
5586 struct GraphicInfo *g = &graphic_info[dpc->graphic];
5588 if (dpc->graphic >= part_3 &&
5589 dpc->graphic <= part_8)
5593 /* set graphics and screen positions of the default wings */
5595 g_part_1->width = door_rect->width;
5596 g_part_1->height = door_rect->height;
5597 g_part_2->width = door_rect->width;
5598 g_part_2->height = door_rect->height;
5599 g_part_2->src_x = door_rect->width;
5600 g_part_2->src_y = g_part_1->src_y;
5602 door->part_2.x = door->part_1.x;
5603 door->part_2.y = door->part_1.y;
5605 if (door->width != -1)
5607 g_part_1->width = door->width;
5608 g_part_2->width = door->width;
5610 // special treatment for graphics and screen position of right wing
5611 g_part_2->src_x += door_rect->width - door->width;
5612 door->part_2.x += door_rect->width - door->width;
5615 if (door->height != -1)
5617 g_part_1->height = door->height;
5618 g_part_2->height = door->height;
5620 // special treatment for graphics and screen position of bottom wing
5621 g_part_2->src_y += door_rect->height - door->height;
5622 door->part_2.y += door_rect->height - door->height;
5625 /* set animation delays for the default wings and panels */
5627 door->part_1.step_delay = door->step_delay;
5628 door->part_2.step_delay = door->step_delay;
5629 door->panel.step_delay = door->step_delay;
5631 /* set animation draw order for the default wings */
5633 door->part_1.sort_priority = 2; /* draw left wing over ... */
5634 door->part_2.sort_priority = 1; /* ... right wing */
5636 /* set animation draw offset for the default wings */
5638 if (door->anim_mode & ANIM_HORIZONTAL)
5640 door->part_1.step_xoffset = door->step_offset;
5641 door->part_1.step_yoffset = 0;
5642 door->part_2.step_xoffset = door->step_offset * -1;
5643 door->part_2.step_yoffset = 0;
5645 num_door_steps = g_part_1->width / door->step_offset;
5647 else // ANIM_VERTICAL
5649 door->part_1.step_xoffset = 0;
5650 door->part_1.step_yoffset = door->step_offset;
5651 door->part_2.step_xoffset = 0;
5652 door->part_2.step_yoffset = door->step_offset * -1;
5654 num_door_steps = g_part_1->height / door->step_offset;
5657 /* set animation draw offset for the default panels */
5659 if (door->step_offset > 1)
5661 num_panel_steps = 2 * door_rect->height / door->step_offset;
5662 door->panel.start_step = num_panel_steps - num_door_steps;
5666 num_panel_steps = door_rect->height / door->step_offset;
5667 door->panel.start_step = num_panel_steps - num_door_steps / 2;
5668 door->panel.step_delay *= 2;
5679 for (i = 0; door_part_controls[i].door_token != -1; i++)
5681 struct DoorPartControlInfo *dpc = &door_part_controls[i];
5682 struct DoorPartOrderInfo *dpo = &door_part_order[i];
5684 /* initialize "start_step_opening" and "start_step_closing", if needed */
5685 if (dpc->pos->start_step_opening == 0 &&
5686 dpc->pos->start_step_closing == 0)
5688 // dpc->pos->start_step_opening = dpc->pos->start_step;
5689 dpc->pos->start_step_closing = dpc->pos->start_step;
5692 /* fill structure for door part draw order (sorted below) */
5694 dpo->sort_priority = dpc->pos->sort_priority;
5697 struct DoorPartPosInfo *pos = dpc->pos;
5699 printf(":0: step_xoffset == %d, step_yoffset == %d\n",
5700 pos->step_xoffset, pos->step_yoffset);
5704 /* sort door part controls according to sort_priority and graphic number */
5705 qsort(door_part_order, MAX_DOOR_PARTS,
5706 sizeof(struct DoorPartOrderInfo), compareDoorPartOrderInfo);
5709 unsigned int OpenDoor(unsigned int door_state)
5711 if (door_state & DOOR_COPY_BACK)
5714 if (door_state & DOOR_OPEN_1)
5715 BlitBitmap(bitmap_db_door_1, bitmap_db_door_1,
5716 1 * DXSIZE, 0, DXSIZE, DYSIZE, 0 * DXSIZE, 0);
5718 if (door_state & DOOR_OPEN_2)
5719 BlitBitmap(bitmap_db_door_2, bitmap_db_door_2,
5720 1 * VXSIZE, 0, VXSIZE, VYSIZE, 0 * VXSIZE, 0);
5722 if (door_state & DOOR_OPEN_1)
5723 BlitBitmap(bitmap_db_door, bitmap_db_door,
5724 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
5725 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
5727 if (door_state & DOOR_OPEN_2)
5728 BlitBitmap(bitmap_db_door, bitmap_db_door,
5729 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY2, VXSIZE, VYSIZE,
5730 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
5733 door_state &= ~DOOR_COPY_BACK;
5736 return MoveDoor(door_state);
5739 unsigned int CloseDoor(unsigned int door_state)
5741 unsigned int old_door_state = GetDoorState();
5743 if (!(door_state & DOOR_NO_COPY_BACK))
5746 if (old_door_state & DOOR_OPEN_1)
5747 BlitBitmap(backbuffer, bitmap_db_door_1,
5748 DX, DY, DXSIZE, DYSIZE, 0, 0);
5750 if (old_door_state & DOOR_OPEN_2)
5751 BlitBitmap(backbuffer, bitmap_db_door_2,
5752 VX, VY, VXSIZE, VYSIZE, 0, 0);
5754 if (old_door_state & DOOR_OPEN_1)
5755 BlitBitmap(backbuffer, bitmap_db_door,
5756 DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
5758 if (old_door_state & DOOR_OPEN_2)
5759 BlitBitmap(backbuffer, bitmap_db_door,
5760 VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
5763 door_state &= ~DOOR_NO_COPY_BACK;
5766 return MoveDoor(door_state);
5769 unsigned int GetDoorState()
5771 return MoveDoor(DOOR_GET_STATE);
5774 unsigned int SetDoorState(unsigned int door_state)
5776 return MoveDoor(door_state | DOOR_SET_STATE);
5781 // ========== TEST 1 ===========================================================
5783 int euclid(int a, int b)
5785 return (b ? euclid(b, a % b) : a);
5788 unsigned int MoveDoor(unsigned int door_state)
5791 struct XY panel_pos_list[] =
5793 { DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 },
5794 { DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 },
5797 struct Rect door_rect_list[] =
5799 { DX, DY, DXSIZE, DYSIZE },
5800 { VX, VY, VXSIZE, VYSIZE }
5802 static int door1 = DOOR_OPEN_1;
5803 static int door2 = DOOR_CLOSE_2;
5804 unsigned int door_delay = 0;
5805 unsigned int door_delay_value;
5809 if (door_1.width < 0 || door_1.width > DXSIZE)
5810 door_1.width = DXSIZE;
5811 if (door_1.height < 0 || door_1.height > DYSIZE)
5812 door_1.height = DYSIZE;
5813 if (door_2.width < 0 || door_2.width > VXSIZE)
5814 door_2.width = VXSIZE;
5815 if (door_2.height < 0 || door_2.height > VYSIZE)
5816 door_2.height = VYSIZE;
5819 if (door_state == DOOR_GET_STATE)
5820 return (door1 | door2);
5822 if (door_state & DOOR_SET_STATE)
5824 if (door_state & DOOR_ACTION_1)
5825 door1 = door_state & DOOR_ACTION_1;
5826 if (door_state & DOOR_ACTION_2)
5827 door2 = door_state & DOOR_ACTION_2;
5829 return (door1 | door2);
5832 if (!(door_state & DOOR_FORCE_REDRAW))
5834 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
5835 door_state &= ~DOOR_OPEN_1;
5836 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
5837 door_state &= ~DOOR_CLOSE_1;
5838 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
5839 door_state &= ~DOOR_OPEN_2;
5840 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
5841 door_state &= ~DOOR_CLOSE_2;
5845 door_delay_value = (door_state & DOOR_ACTION_1 ? door_1.step_delay :
5848 if (setup.quick_doors)
5850 stepsize = 20; /* must be chosen to always draw last frame */
5851 door_delay_value = 0;
5855 if (global.autoplay_leveldir)
5857 door_state |= DOOR_NO_DELAY;
5858 door_state &= ~DOOR_CLOSE_ALL;
5862 if (game_status == GAME_MODE_EDITOR)
5863 door_state |= DOOR_NO_DELAY;
5866 if (door_state & DOOR_ACTION)
5868 boolean door_panel_drawn[NUM_DOORS];
5869 boolean panel_has_doors[NUM_DOORS];
5870 boolean door_part_skip[MAX_DOOR_PARTS];
5871 boolean door_part_done[MAX_DOOR_PARTS];
5872 boolean door_part_done_all;
5873 int num_steps[MAX_DOOR_PARTS];
5874 int max_move_delay = 0; // delay for complete animations of all doors
5875 int max_step_delay = 0; // delay (ms) between two animation frames
5876 int num_move_steps = 0; // number of animation steps for all doors
5877 int current_move_delay = 0;
5880 for (i = 0; i < NUM_DOORS; i++)
5881 panel_has_doors[i] = FALSE;
5883 for (i = 0; i < MAX_DOOR_PARTS; i++)
5885 struct DoorPartControlInfo *dpc = &door_part_controls[i];
5886 struct GraphicInfo *g = &graphic_info[dpc->graphic];
5887 int door_token = dpc->door_token;
5889 door_part_done[i] = FALSE;
5890 door_part_skip[i] = (!(door_state & door_token) ||
5895 for (i = 0; i < MAX_DOOR_PARTS; i++)
5897 struct DoorPartControlInfo *dpc = &door_part_controls[i];
5898 struct DoorPartPosInfo *pos = dpc->pos;
5899 int start_step = pos->start_step;
5901 printf("::: ---> %d: start_step == %d [%d]\n",
5902 i, start_step, door_part_done[i]);
5906 for (i = 0; i < MAX_DOOR_PARTS; i++)
5908 int nr = door_part_order[i].nr;
5909 struct DoorPartControlInfo *dpc = &door_part_controls[nr];
5910 struct DoorPartPosInfo *pos = dpc->pos;
5911 struct GraphicInfo *g = &graphic_info[dpc->graphic];
5912 int door_token = dpc->door_token;
5913 int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
5914 boolean is_panel = DOOR_PART_IS_PANEL(nr);
5915 int step_xoffset = ABS(pos->step_xoffset);
5916 int step_yoffset = ABS(pos->step_yoffset);
5917 int step_delay = pos->step_delay;
5918 int current_door_state = door_state & door_token;
5919 boolean door_opening = ((current_door_state & DOOR_OPEN) != 0);
5920 boolean door_closing = ((current_door_state & DOOR_CLOSE) != 0);
5921 boolean part_opening = (is_panel ? door_closing : door_opening);
5922 int start_step = (part_opening ? pos->start_step_opening :
5923 pos->start_step_closing);
5924 float move_xsize = (step_xoffset ? g->width : 0);
5925 float move_ysize = (step_yoffset ? g->height : 0);
5926 int move_xsteps = (step_xoffset ? ceil(move_xsize / step_xoffset) : 0);
5927 int move_ysteps = (step_yoffset ? ceil(move_ysize / step_yoffset) : 0);
5928 int move_steps = (move_xsteps && move_ysteps ?
5929 MIN(move_xsteps, move_ysteps) :
5930 move_xsteps ? move_xsteps : move_ysteps) - start_step;
5931 int move_delay = move_steps * step_delay;
5933 if (door_part_skip[nr])
5937 panel_has_doors[door_index] = TRUE;
5939 max_move_delay = MAX(max_move_delay, move_delay);
5940 max_step_delay = (max_step_delay == 0 ? step_delay :
5941 euclid(max_step_delay, step_delay));
5942 num_steps[nr] = move_steps;
5946 printf("::: %d: move_delay == %d, start_step == %d [%d]\n",
5947 i, move_delay, start_step, door_part_order[i].nr);
5949 if (DOOR_PART_IS_PANEL(i))
5950 printf("::: %d: move_delay == %d, start_step == %d\n",
5951 i, move_delay, start_step);
5956 num_move_steps = max_move_delay / max_step_delay;
5958 door_delay_value = max_step_delay;
5961 door_delay_value *= 10;
5965 printf("::: num_move_steps == %d, max_move_delay == %d, max_step_delay == %d\n", num_move_steps, max_move_delay, max_step_delay);
5968 for (k = 0; k < num_move_steps; k++)
5970 door_part_done_all = TRUE;
5972 for (i = 0; i < NUM_DOORS; i++)
5973 door_panel_drawn[i] = FALSE;
5975 for (i = 0; i < MAX_DOOR_PARTS; i++)
5977 int nr = door_part_order[i].nr;
5978 struct DoorPartControlInfo *dpc = &door_part_controls[nr];
5979 struct DoorPartPosInfo *pos = dpc->pos;
5980 struct GraphicInfo *g = &graphic_info[dpc->graphic];
5981 int door_token = dpc->door_token;
5982 int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
5983 boolean is_panel = DOOR_PART_IS_PANEL(nr);
5985 struct XY *panel_pos = &panel_pos_list[door_index];
5987 struct Rect *door_rect = &door_rect_list[door_index];
5988 Bitmap *bitmap_db_door = (door_token == DOOR_1 ? bitmap_db_door_1 :
5990 Bitmap *bitmap = (is_panel ? bitmap_db_door : g->bitmap);
5991 int current_door_state = door_state & door_token;
5992 boolean door_opening = ((current_door_state & DOOR_OPEN) != 0);
5993 boolean door_closing = !door_opening;
5994 boolean part_opening = (is_panel ? door_closing : door_opening);
5995 boolean part_closing = !part_opening;
5996 int start_step = (part_opening ? pos->start_step_opening :
5997 pos->start_step_closing);
5998 int step_delay = pos->step_delay;
5999 int step_factor = step_delay / max_step_delay;
6000 int k1 = (step_factor ? k / step_factor + 1 : k);
6001 int k2 = (part_opening ? k1 + start_step : num_steps[nr] - k1);
6002 int kk = (k2 < 0 ? 0 : k2);
6003 int src_x, src_y, src_xx, src_yy;
6004 int dst_x, dst_y, dst_xx, dst_yy;
6008 if (k == 0 && is_panel && door_token == DOOR_2)
6009 printf("::: %d, %d\n", g->width, g->height);
6013 if (DOOR_PART_IS_PANEL(nr))
6015 int start_step = pos->start_step;
6017 k2 = (door_closing ? k1 : num_steps[nr] - k1);// - start_step;
6018 kk = (k2 < 0 ? 0 : k2);
6024 if (nr != 16 && nr != 0)
6035 if (door_part_skip[nr])
6039 if (!(door_state & door_token))
6046 if (current_move_delay % step_delay)
6052 if (!door_panel_drawn[door_index])
6055 ClearRectangle(drawto, door_rect->x, door_rect->y,
6056 door_rect->width, door_rect->height);
6058 BlitBitmap(bitmap_db_door, drawto, panel_pos->x, panel_pos->y,
6059 door_rect->width, door_rect->height,
6060 door_rect->x, door_rect->y);
6063 door_panel_drawn[door_index] = TRUE;
6066 // draw opening or closing door parts
6068 if (pos->step_xoffset < 0) // door part on right side
6071 dst_xx = pos->x + ABS(kk * pos->step_xoffset);
6074 if (dst_xx + width > door_rect->width)
6075 width = door_rect->width - dst_xx;
6077 else // door part on left side
6080 dst_xx = pos->x - kk * pos->step_xoffset;
6084 src_xx = ABS(dst_xx);
6088 width = g->width - src_xx;
6090 // printf("::: k == %d [%d] \n", k, start_step);
6093 if (pos->step_yoffset < 0) // door part on bottom side
6096 dst_yy = pos->y + ABS(kk * pos->step_yoffset);
6099 if (dst_yy + height > door_rect->height)
6100 height = door_rect->height - dst_yy;
6102 else // door part on top side
6105 dst_yy = pos->y - kk * pos->step_yoffset;
6109 src_yy = ABS(dst_yy);
6113 height = g->height - src_yy;
6122 src_x = panel_pos->x + src_xx;
6123 src_y = panel_pos->y + src_yy;
6128 src_x = g->src_x + src_xx;
6129 src_y = g->src_y + src_yy;
6132 dst_x = door_rect->x + dst_xx;
6133 dst_y = door_rect->y + dst_yy;
6136 if (DOOR_PART_IS_PANEL(nr))
6138 printf("::: width == %d, height == %d [%d, %d] [%d, %d]\n",
6139 width, height, g->width, g->height, src_x, src_y);
6143 if (width >= 0 && width <= g->width &&
6144 height >= 0 && height <= g->height)
6146 if (is_panel || !pos->draw_masked)
6147 BlitBitmap(bitmap, drawto, src_x, src_y, width, height,
6150 BlitBitmapMasked(bitmap, drawto, src_x, src_y, width, height,
6155 if (DOOR_PART_IS_PANEL(nr))
6157 bitmap = bitmap_db_door;
6158 src_x = panel_pos->x + src_xx;
6159 src_y = panel_pos->y + src_yy;
6161 printf("::: width == %d, height == %d [%d, %d] [%d, %d]\n",
6162 width, height, g->width, g->height, src_x, src_y);
6164 if (width >= 0 && width <= g->width &&
6165 height >= 0 && height <= g->height)
6166 BlitBitmap(bitmap, drawto, src_x, src_y,
6172 redraw_mask |= REDRAW_DOOR_FROM_TOKEN(door_token);
6175 if ((part_opening && (width < 0 || height < 0)) ||
6176 (part_closing && (width >= g->width && height >= g->height)))
6177 door_part_done[nr] = TRUE;
6179 if ((door_opening && (width < 0 || height < 0)) ||
6180 (door_closing && (width >= g->width && height >= g->height)))
6181 door_part_done[nr] = TRUE;
6185 // continue door part animations, but not panel after door has closed
6186 if (!door_part_done[nr] &&
6187 !(is_panel && door_closing && panel_has_doors[door_index]))
6188 door_part_done_all = FALSE;
6190 // continue door part animations, but not panel after door has closed
6191 if (!door_part_done[nr] && !(is_panel && door_closing))
6192 door_part_done_all = FALSE;
6196 if (!door_part_done[nr])
6197 printf("::: k == %d, nr == %d\n", k, nr);
6201 if (!(door_state & DOOR_NO_DELAY))
6205 if (game_status == GAME_MODE_MAIN)
6208 WaitUntilDelayReached(&door_delay, door_delay_value);
6210 current_move_delay += max_step_delay;
6214 door_part_done_all = TRUE;
6216 for (i = 0; i < MAX_DOOR_PARTS; i++)
6217 if (!door_part_done[i] &&
6218 !(DOOR_PART_IS_PANEL(i) && door_closing))
6219 door_part_done_all = FALSE;
6222 if (door_part_done_all)
6228 if (door_state & DOOR_ACTION_1)
6229 door1 = door_state & DOOR_ACTION_1;
6230 if (door_state & DOOR_ACTION_2)
6231 door2 = door_state & DOOR_ACTION_2;
6234 printf("::: DOORS DONE %08x\n", door_state);
6236 printf("::: GO!\n");
6239 return (door1 | door2);
6244 // ========== OLD ==============================================================
6246 unsigned int MoveDoor(unsigned int door_state)
6248 static int door1 = DOOR_OPEN_1;
6249 static int door2 = DOOR_CLOSE_2;
6250 unsigned int door_delay = 0;
6251 unsigned int door_delay_value;
6255 if (door_1.width < 0 || door_1.width > DXSIZE)
6256 door_1.width = DXSIZE;
6257 if (door_1.height < 0 || door_1.height > DYSIZE)
6258 door_1.height = DYSIZE;
6259 if (door_2.width < 0 || door_2.width > VXSIZE)
6260 door_2.width = VXSIZE;
6261 if (door_2.height < 0 || door_2.height > VYSIZE)
6262 door_2.height = VYSIZE;
6265 if (door_state == DOOR_GET_STATE)
6266 return (door1 | door2);
6268 if (door_state & DOOR_SET_STATE)
6270 if (door_state & DOOR_ACTION_1)
6271 door1 = door_state & DOOR_ACTION_1;
6272 if (door_state & DOOR_ACTION_2)
6273 door2 = door_state & DOOR_ACTION_2;
6275 return (door1 | door2);
6278 if (!(door_state & DOOR_FORCE_REDRAW))
6280 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
6281 door_state &= ~DOOR_OPEN_1;
6282 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
6283 door_state &= ~DOOR_CLOSE_1;
6284 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
6285 door_state &= ~DOOR_OPEN_2;
6286 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
6287 door_state &= ~DOOR_CLOSE_2;
6290 door_delay_value = (door_state & DOOR_ACTION_1 ? door_1.step_delay :
6293 // door_delay_value *= 4; // !!! TEST ONLY !!!
6295 if (setup.quick_doors)
6297 stepsize = 20; /* must be chosen to always draw last frame */
6298 door_delay_value = 0;
6301 if (global.autoplay_leveldir)
6303 door_state |= DOOR_NO_DELAY;
6304 door_state &= ~DOOR_CLOSE_ALL;
6308 if (game_status == GAME_MODE_EDITOR)
6309 door_state |= DOOR_NO_DELAY;
6312 if (door_state & DOOR_ACTION)
6315 struct GraphicInfo *g1_left = &graphic_info[IMG_DOOR_1_WING_LEFT];
6316 struct GraphicInfo *g1_right = &graphic_info[IMG_DOOR_1_WING_RIGHT];
6317 struct GraphicInfo *g2_left = &graphic_info[IMG_DOOR_2_WING_LEFT];
6318 struct GraphicInfo *g2_right = &graphic_info[IMG_DOOR_2_WING_RIGHT];
6319 int door_1_left_width = g1_left->width;
6320 int door_1_left_height = g1_left->height;
6321 int door_1_right_width = g1_right->width;
6322 int door_1_right_height = g1_right->height;
6323 int door_2_left_width = g2_left->width;
6324 int door_2_left_height = g2_left->height;
6325 int door_2_right_width = g2_right->width;
6326 int door_2_right_height = g2_right->height;
6327 int door_1_width = MAX(door_1_left_width, door_1_right_width);
6328 int door_1_height = MAX(door_1_left_height, door_1_right_height);
6329 int door_2_width = MAX(door_2_left_width, door_2_right_width);
6330 int door_2_height = MAX(door_2_left_height, door_2_right_height);
6332 boolean handle_door_1 = (door_state & DOOR_ACTION_1);
6333 boolean handle_door_2 = (door_state & DOOR_ACTION_2);
6334 boolean door_1_done = (!handle_door_1);
6335 boolean door_2_done = (!handle_door_2);
6336 boolean door_1_vertical = (door_1.anim_mode & ANIM_VERTICAL);
6337 boolean door_2_vertical = (door_2.anim_mode & ANIM_VERTICAL);
6340 int door_size_1 = (door_1_vertical ? door_1_height : door_1_width);
6341 int door_size_2 = (door_2_vertical ? door_2_height : door_2_width);
6343 int door_size_1 = (door_1_vertical ? DYSIZE : DXSIZE);
6344 int door_size_2 = (door_2_vertical ? VYSIZE : VXSIZE);
6347 int door_size_1 = (door_1_vertical ? door_1.height : door_1.width);
6348 int door_size_2 = (door_2_vertical ? door_2.height : door_2.width);
6350 int max_door_size_1 = (door_1_vertical ? DYSIZE : DXSIZE);
6351 int max_door_size_2 = (door_2_vertical ? VYSIZE : VXSIZE);
6352 // int door_size = (handle_door_1 ? door_size_1 : door_size_2);
6353 int door_size = (handle_door_2 ? door_size_2 : door_size_1);
6354 int max_door_size = (handle_door_1 ? max_door_size_1 : max_door_size_2);
6355 int door_skip = max_door_size - door_size;
6356 int end = door_size;
6357 int start = ((door_state & DOOR_NO_DELAY) ? end : 0);
6360 if (!(door_state & DOOR_NO_DELAY) && !setup.quick_doors)
6362 /* opening door sound has priority over simultaneously closing door */
6363 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
6364 PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
6365 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
6366 PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
6369 for (k = start; k <= end && !(door_1_done && door_2_done); k += stepsize)
6373 Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
6374 GC gc = bitmap->stored_clip_gc;
6377 if (door_state & DOOR_ACTION_1 &&
6378 x * door_1.step_offset <= door_size_1)
6380 int a = MIN(x * door_1.step_offset, end);
6381 int p = (door_state & DOOR_OPEN_1 ? end - a : a);
6385 int i = p + door_skip;
6389 struct GraphicInfo *g_left = &graphic_info[IMG_DOOR_1_WING_LEFT];
6390 struct GraphicInfo *g_right = &graphic_info[IMG_DOOR_1_WING_RIGHT];
6391 Bitmap *bm_left = g_left->bitmap;
6392 Bitmap *bm_right = g_right->bitmap;
6393 GC gc_left = bm_left->stored_clip_gc;
6394 GC gc_right = bm_right->stored_clip_gc;
6397 int classic_dxsize = 100;
6398 int classic_dysize = 280;
6399 boolean classic_door_1_size = (DXSIZE == classic_dxsize &&
6400 DYSIZE == classic_dysize);
6402 if (door_1.anim_mode & ANIM_STATIC_PANEL)
6404 BlitBitmap(bitmap_db_door, drawto,
6405 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1,
6406 DXSIZE, DYSIZE, DX, DY);
6410 BlitBitmap(bitmap_db_door, drawto,
6411 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + p / 2,
6412 DXSIZE, DYSIZE - p / 2, DX, DY);
6415 // printf("::: p == %d\n", p);
6416 ClearRectangle(drawto, DX, DY + DYSIZE - p / 2, DXSIZE, p / 2);
6420 if (door_1.anim_mode & ANIM_HORIZONTAL && x <= DXSIZE)
6423 int src1_x = g_right->src_x;
6424 int src1_y = g_right->src_y;
6425 int src2_x = g_left->src_x + g_left->width - i;
6426 int src2_y = g_left->src_y;
6427 int dst1_x = DX + DXSIZE - i;
6432 int height = DYSIZE;
6434 SetClipOrigin(bm_right, gc_right, dst1_x - src1_x, dst1_y - src1_y);
6435 BlitBitmapMasked(bm_right, drawto, src1_x, src1_y, width, height,
6438 SetClipOrigin(bm_left, gc_left, dst2_x - src2_x, dst2_y - src2_y);
6439 BlitBitmapMasked(bm_left, drawto, src2_x, src2_y, width, height,
6442 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
6443 int src2_x = DXSIZE - i, src2_y = DOOR_GFX_PAGEY1;
6444 int dst1_x = DX + DXSIZE - i, dst1_y = DY;
6445 int dst2_x = DX, dst2_y = DY;
6446 int width = i, height = DYSIZE;
6448 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
6449 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
6452 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
6453 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
6457 else if (door_1.anim_mode & ANIM_VERTICAL && x <= DYSIZE)
6460 int src1_x = g_right->src_x;
6461 int src1_y = g_right->src_y;
6462 int src2_x = g_left->src_x;
6463 int src2_y = g_left->src_y + g_left->height - i;
6465 int dst1_y = DY + DYSIZE - i;
6471 SetClipOrigin(bm_right, gc_right, dst1_x - src1_x, dst1_y - src1_y);
6472 BlitBitmapMasked(bm_right, drawto, src1_x, src1_y, width, height,
6475 SetClipOrigin(bm_left, gc_left, dst2_x - src2_x, dst2_y - src2_y);
6476 BlitBitmapMasked(bm_left, drawto, src2_x, src2_y, width, height,
6479 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
6480 int src2_x = 0, src2_y = DOOR_GFX_PAGEY1 + DYSIZE - i;
6481 int dst1_x = DX, dst1_y = DY + DYSIZE - i;
6482 int dst2_x = DX, dst2_y = DY;
6483 int width = DXSIZE, height = i;
6485 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
6486 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
6489 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
6490 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
6494 else if (classic_door_1_size && x <= DXSIZE) /* ANIM_DEFAULT */
6496 int j = (door_1.anim_mode == ANIM_DEFAULT ? (DXSIZE - i) / 3 : 0);
6499 int src1_x = g_right->src_x;
6500 int src1_y = g_right->src_y;
6501 int src2_x = g_left->src_x + g_left->width - i;
6502 int src2_y = g_left->src_y;
6503 int dst1_x = DX + DXSIZE - i;
6508 int height1 = 63, height2 = DYSIZE / 2 - height1;
6509 int ypos1 = 0, ypos2 = height2;
6510 int ypos3 = DYSIZE / 2, ypos4 = DYSIZE - height2;
6512 SetClipOrigin(bm_right, gc_right,
6513 dst1_x - src1_x, dst1_y - src1_y + j);
6514 BlitBitmapMasked(bm_right, drawto,
6515 src1_x, src1_y + ypos1, width, height2,
6516 dst1_x, dst1_y + ypos1 + j);
6517 BlitBitmapMasked(bm_right, drawto,
6518 src1_x, src1_y + ypos3, width, height1,
6519 dst1_x, dst1_y + ypos3 + j);
6520 SetClipOrigin(bm_left, gc_left,
6521 dst2_x - src2_x, dst2_y - src2_y - j);
6522 BlitBitmapMasked(bm_left, drawto,
6523 src2_x, src2_y + ypos1 + j, width, height2 - j,
6524 dst2_x, dst2_y + ypos1);
6525 BlitBitmapMasked(bm_left, drawto,
6526 src2_x, src2_y + ypos3, width, height1,
6527 dst2_x, dst2_y + ypos3 - j);
6529 SetClipOrigin(bm_left, gc_left,
6530 dst2_x - src2_x, dst2_y - src2_y - j);
6531 BlitBitmapMasked(bm_left, drawto,
6532 src2_x, src2_y + ypos2, width, height1,
6533 dst2_x, dst2_y + ypos2 - j);
6534 BlitBitmapMasked(bm_left, drawto,
6535 src2_x, src2_y + ypos4, width, height2,
6536 dst2_x, dst2_y + ypos4 - j);
6537 SetClipOrigin(bm_right, gc_right,
6538 dst1_x - src1_x, dst1_y - src1_y + j);
6539 BlitBitmapMasked(bm_right, drawto,
6540 src1_x, src1_y + ypos2, width, height1,
6541 dst1_x, dst1_y + ypos2 + j);
6542 BlitBitmapMasked(bm_right, drawto,
6543 src1_x, src1_y + ypos4, width, height2 - j,
6544 dst1_x, dst1_y + ypos4 + j);
6547 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
6548 int src2_x = DXSIZE - i, src2_y = DOOR_GFX_PAGEY1;
6549 int dst1_x = DX + DXSIZE - i, dst1_y = DY;
6550 int dst2_x = DX, dst2_y = DY;
6551 int width = i, height = DYSIZE;
6552 int ypos1 = 63, ypos2 = 77, ypos3 = 140, ypos4 = 203;
6554 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y + j);
6555 BlitBitmapMasked(bitmap, drawto,
6556 src1_x, src1_y, width, ypos2,
6557 dst1_x, dst1_y + j);
6558 BlitBitmapMasked(bitmap, drawto,
6559 src1_x, src1_y + ypos3, width, ypos1,
6560 dst1_x, dst1_y + ypos3 + j);
6561 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y - j);
6562 BlitBitmapMasked(bitmap, drawto,
6563 src2_x, src2_y + j, width, ypos2 - j,
6565 BlitBitmapMasked(bitmap, drawto,
6566 src2_x, src2_y + ypos3, width, ypos1,
6567 dst2_x, dst2_y + ypos3 - j);
6569 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y - j);
6570 BlitBitmapMasked(bitmap, drawto,
6571 src2_x, src2_y + ypos2, width, ypos1,
6572 dst2_x, dst2_y + ypos2 - j);
6573 BlitBitmapMasked(bitmap, drawto,
6574 src2_x, src2_y + ypos4, width, ypos2,
6575 dst2_x, dst2_y + ypos4 - j);
6576 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y + j);
6577 BlitBitmapMasked(bitmap, drawto,
6578 src1_x, src1_y + ypos2, width, ypos1,
6579 dst1_x, dst1_y + ypos2 + j);
6580 BlitBitmapMasked(bitmap, drawto,
6581 src1_x, src1_y + ypos4, width, ypos2 - j,
6582 dst1_x, dst1_y + ypos4 + j);
6585 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
6586 BlitBitmapMasked(bitmap, drawto,
6587 DXSIZE, DOOR_GFX_PAGEY1, i, 77,
6588 DX + DXSIZE - i, DY + j);
6589 BlitBitmapMasked(bitmap, drawto,
6590 DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
6591 DX + DXSIZE - i, DY + 140 + j);
6592 SetClipOrigin(bitmap, gc, DX - DXSIZE + i,
6593 DY - (DOOR_GFX_PAGEY1 + j));
6594 BlitBitmapMasked(bitmap, drawto,
6595 DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
6597 BlitBitmapMasked(bitmap, drawto,
6598 DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
6601 BlitBitmapMasked(bitmap, drawto,
6602 DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
6604 BlitBitmapMasked(bitmap, drawto,
6605 DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
6607 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
6608 BlitBitmapMasked(bitmap, drawto,
6609 DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
6610 DX + DXSIZE - i, DY + 77 + j);
6611 BlitBitmapMasked(bitmap, drawto,
6612 DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
6613 DX + DXSIZE - i, DY + 203 + j);
6618 redraw_mask |= REDRAW_DOOR_1;
6619 door_1_done = (a == end);
6622 if (door_state & DOOR_ACTION_2 &&
6623 x * door_2.step_offset <= door_size_2)
6625 int a = MIN(x * door_2.step_offset, door_size);
6626 int p = (door_state & DOOR_OPEN_2 ? door_size - a : a);
6627 int i = p + door_skip;
6630 struct GraphicInfo *g_left = &graphic_info[IMG_DOOR_2_WING_LEFT];
6631 struct GraphicInfo *g_right = &graphic_info[IMG_DOOR_2_WING_RIGHT];
6632 Bitmap *bm_left = g_left->bitmap;
6633 Bitmap *bm_right = g_right->bitmap;
6634 GC gc_left = bm_left->stored_clip_gc;
6635 GC gc_right = bm_right->stored_clip_gc;
6638 int classic_vxsize = 100;
6639 int classic_vysize = 100;
6640 boolean classic_door_2_size = (VXSIZE == classic_vxsize &&
6641 VYSIZE == classic_vysize);
6643 if (door_2.anim_mode & ANIM_STATIC_PANEL)
6645 BlitBitmap(bitmap_db_door, drawto,
6646 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2,
6647 VXSIZE, VYSIZE, VX, VY);
6649 else if (x <= VYSIZE)
6651 BlitBitmap(bitmap_db_door, drawto,
6652 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + p / 2,
6653 VXSIZE, VYSIZE - p / 2, VX, VY);
6655 ClearRectangle(drawto, VX, VY + VYSIZE - p / 2, VXSIZE, p / 2);
6658 if (door_2.anim_mode & ANIM_HORIZONTAL && x <= VXSIZE)
6661 int src1_x = g_right->src_x;
6662 int src1_y = g_right->src_y;
6663 int src2_x = g_left->src_x + g_left->width - i;
6664 int src2_y = g_left->src_y;
6665 int dst1_x = VX + VXSIZE - i;
6670 int height = VYSIZE;
6672 SetClipOrigin(bm_right, gc_right, dst1_x - src1_x, dst1_y - src1_y);
6673 BlitBitmapMasked(bm_right, drawto, src1_x, src1_y, width, height,
6676 SetClipOrigin(bm_left, gc_left, dst2_x - src2_x, dst2_y - src2_y);
6677 BlitBitmapMasked(bm_left, drawto, src2_x, src2_y, width, height,
6680 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
6681 int src2_x = VXSIZE - i, src2_y = DOOR_GFX_PAGEY2;
6682 int dst1_x = VX + VXSIZE - i, dst1_y = VY;
6683 int dst2_x = VX, dst2_y = VY;
6684 int width = i, height = VYSIZE;
6686 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
6687 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
6690 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
6691 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
6695 else if (door_2.anim_mode & ANIM_VERTICAL && x <= VYSIZE)
6698 int src1_x = g_right->src_x;
6699 int src1_y = g_right->src_y;
6700 int src2_x = g_left->src_x;
6701 int src2_y = g_left->src_y + g_left->height - i;
6703 int dst1_y = VY + VYSIZE - i;
6709 SetClipOrigin(bm_right, gc_right, dst1_x - src1_x, dst1_y - src1_y);
6710 BlitBitmapMasked(bm_right, drawto, src1_x, src1_y, width, height,
6713 SetClipOrigin(bm_left, gc_left, dst2_x - src2_x, dst2_y - src2_y);
6714 BlitBitmapMasked(bm_left, drawto, src2_x, src2_y, width, height,
6717 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
6718 int src2_x = 0, src2_y = DOOR_GFX_PAGEY2 + VYSIZE - i;
6719 int dst1_x = VX, dst1_y = VY + VYSIZE - i;
6720 int dst2_x = VX, dst2_y = VY;
6721 int width = VXSIZE, height = i;
6723 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
6724 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
6727 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
6728 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
6732 else if (classic_door_2_size && x <= VXSIZE) /* ANIM_DEFAULT */
6734 int j = (door_2.anim_mode == ANIM_DEFAULT ? (VXSIZE - i) / 3 : 0);
6737 int src1_x = g_right->src_x;
6738 int src1_y = g_right->src_y;
6739 int src2_x = g_left->src_x + g_left->width - i;
6740 int src2_y = g_left->src_y;
6741 int dst1_x = VX + VXSIZE - i;
6746 int height = VYSIZE / 2;
6747 int ypos1 = 0, ypos2 = VYSIZE / 2;
6749 SetClipOrigin(bm_right, gc_right,
6750 dst1_x - src1_x, dst1_y - src1_y + j);
6751 BlitBitmapMasked(bm_right, drawto,
6752 src1_x, src1_y + ypos1, width, height,
6753 dst1_x, dst1_y + ypos1 + j);
6754 SetClipOrigin(bm_left, gc_left,
6755 dst2_x - src2_x, dst2_y - src2_y - j);
6756 BlitBitmapMasked(bm_left, drawto,
6757 src2_x, src2_y + ypos1 + j, width, height - j,
6758 dst2_x, dst2_y + ypos1);
6760 SetClipOrigin(bm_left, gc_left,
6761 dst2_x - src2_x, dst2_y - src2_y - j);
6762 BlitBitmapMasked(bm_left, drawto,
6763 src2_x, src2_y + ypos2, width, height,
6764 dst2_x, dst2_y + ypos2 - j);
6765 SetClipOrigin(bm_right, gc_right,
6766 dst1_x - src1_x, dst1_y - src1_y + j);
6767 BlitBitmapMasked(bm_right, drawto,
6768 src1_x, src1_y + ypos2, width, height - j,
6769 dst1_x, dst1_y + ypos2 + j);
6771 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
6772 int src2_x = VXSIZE - i, src2_y = DOOR_GFX_PAGEY2;
6773 int dst1_x = VX + VXSIZE - i, dst1_y = VY;
6774 int dst2_x = VX, dst2_y = VY;
6775 int width = i, height = VYSIZE;
6776 int ypos = VYSIZE / 2;
6778 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y + j);
6779 BlitBitmapMasked(bitmap, drawto,
6780 src1_x, src1_y, width, ypos,
6781 dst1_x, dst1_y + j);
6782 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src1_y - j);
6783 BlitBitmapMasked(bitmap, drawto,
6784 src2_x, src2_y + j, width, ypos - j,
6787 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src1_y - j);
6788 BlitBitmapMasked(bitmap, drawto,
6789 src2_x, src2_y + ypos, width, ypos,
6790 dst2_x, dst2_y + ypos - j);
6791 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y + j);
6792 BlitBitmapMasked(bitmap, drawto,
6793 src1_x, src1_y + ypos, width, ypos - j,
6794 dst1_x, dst1_y + ypos + j);
6797 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
6798 BlitBitmapMasked(bitmap, drawto,
6799 VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
6800 VX + VXSIZE - i, VY + j);
6801 SetClipOrigin(bitmap, gc,
6802 VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
6803 BlitBitmapMasked(bitmap, drawto,
6804 VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
6807 BlitBitmapMasked(bitmap, drawto,
6808 VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
6809 i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
6810 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
6811 BlitBitmapMasked(bitmap, drawto,
6812 VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
6814 VX + VXSIZE - i, VY + VYSIZE / 2 + j);
6819 redraw_mask |= REDRAW_DOOR_2;
6820 door_2_done = (a == VXSIZE);
6823 if (!(door_state & DOOR_NO_DELAY))
6827 if (game_status == GAME_MODE_MAIN)
6830 WaitUntilDelayReached(&door_delay, door_delay_value);
6835 if (door_state & DOOR_ACTION_1)
6836 door1 = door_state & DOOR_ACTION_1;
6837 if (door_state & DOOR_ACTION_2)
6838 door2 = door_state & DOOR_ACTION_2;
6840 return (door1 | door2);
6845 void DrawSpecialEditorDoor()
6848 struct GraphicInfo *gfx1 = &graphic_info[IMG_DOOR_2_TOP_BORDER_CORRECTION];
6849 int top_border_width = gfx1->width;
6850 int top_border_height = gfx1->height;
6851 int outer_border = viewport.door_2[GAME_MODE_EDITOR].border_size;
6852 int ex = EX - outer_border;
6853 int ey = EY - outer_border;
6854 int vy = VY - outer_border;
6855 int exsize = EXSIZE + 2 * outer_border;
6857 CloseDoor(DOOR_CLOSE_2);
6859 /* draw bigger level editor toolbox window */
6860 BlitBitmap(gfx1->bitmap, drawto, gfx1->src_x, gfx1->src_y,
6861 top_border_width, top_border_height, ex, ey - top_border_height);
6862 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto, ex, vy,
6863 exsize, EYSIZE - VYSIZE + outer_border, ex, ey);
6865 /* draw bigger level editor toolbox window */
6866 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
6867 DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
6869 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
6870 EX - 6, VY - 4, EXSIZE + 12, EYSIZE - VYSIZE + 4,
6874 redraw_mask |= REDRAW_ALL;
6877 void UndrawSpecialEditorDoor()
6880 struct GraphicInfo *gfx1 = &graphic_info[IMG_DOOR_2_TOP_BORDER_CORRECTION];
6881 int top_border_width = gfx1->width;
6882 int top_border_height = gfx1->height;
6883 int outer_border = viewport.door_2[GAME_MODE_EDITOR].border_size;
6884 int ex = EX - outer_border;
6885 int ey = EY - outer_border;
6886 int ey_top = ey - top_border_height;
6887 int exsize = EXSIZE + 2 * outer_border;
6888 int eysize = EYSIZE + 2 * outer_border;
6890 /* draw normal tape recorder window */
6891 if (graphic_info[IMG_GLOBAL_BORDER].bitmap)
6893 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
6894 ex, ey_top, top_border_width, top_border_height,
6896 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
6897 ex, ey, exsize, eysize, ex, ey);
6901 // if screen background is set to "[NONE]", clear editor toolbox window
6902 ClearRectangle(drawto, ex, ey_top, top_border_width, top_border_height);
6903 ClearRectangle(drawto, ex, ey, exsize, eysize);
6906 /* draw normal tape recorder window */
6907 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
6908 EX - 6, EY - 12, EXSIZE + 12, EYSIZE - VYSIZE + 12,
6912 redraw_mask |= REDRAW_ALL;
6916 /* ---------- new tool button stuff ---------------------------------------- */
6923 struct TextPosInfo *pos;
6926 } toolbutton_info[NUM_TOOL_BUTTONS] =
6929 IMG_REQUEST_BUTTON_GFX_YES, &request.button.yes,
6930 TOOL_CTRL_ID_YES, "yes"
6933 IMG_REQUEST_BUTTON_GFX_NO, &request.button.no,
6934 TOOL_CTRL_ID_NO, "no"
6937 IMG_REQUEST_BUTTON_GFX_CONFIRM, &request.button.confirm,
6938 TOOL_CTRL_ID_CONFIRM, "confirm"
6941 IMG_REQUEST_BUTTON_GFX_PLAYER_1, &request.button.player_1,
6942 TOOL_CTRL_ID_PLAYER_1, "player 1"
6945 IMG_REQUEST_BUTTON_GFX_PLAYER_2, &request.button.player_2,
6946 TOOL_CTRL_ID_PLAYER_2, "player 2"
6949 IMG_REQUEST_BUTTON_GFX_PLAYER_3, &request.button.player_3,
6950 TOOL_CTRL_ID_PLAYER_3, "player 3"
6953 IMG_REQUEST_BUTTON_GFX_PLAYER_4, &request.button.player_4,
6954 TOOL_CTRL_ID_PLAYER_4, "player 4"
6958 void CreateToolButtons()
6962 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
6964 struct GraphicInfo *gfx = &graphic_info[toolbutton_info[i].graphic];
6965 struct TextPosInfo *pos = toolbutton_info[i].pos;
6966 struct GadgetInfo *gi;
6967 Bitmap *deco_bitmap = None;
6968 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
6969 unsigned int event_mask = GD_EVENT_RELEASED;
6972 int gd_x = gfx->src_x;
6973 int gd_y = gfx->src_y;
6974 int gd_xp = gfx->src_x + gfx->pressed_xoffset;
6975 int gd_yp = gfx->src_y + gfx->pressed_yoffset;
6978 if (global.use_envelope_request)
6979 setRequestPosition(&dx, &dy, TRUE);
6981 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
6983 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
6985 getSizedGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr), 0,
6986 pos->size, &deco_bitmap, &deco_x, &deco_y);
6987 deco_xpos = (gfx->width - pos->size) / 2;
6988 deco_ypos = (gfx->height - pos->size) / 2;
6991 gi = CreateGadget(GDI_CUSTOM_ID, id,
6992 GDI_INFO_TEXT, toolbutton_info[i].infotext,
6993 GDI_X, dx + GDI_ACTIVE_POS(pos->x),
6994 GDI_Y, dy + GDI_ACTIVE_POS(pos->y),
6995 GDI_WIDTH, gfx->width,
6996 GDI_HEIGHT, gfx->height,
6997 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
6998 GDI_STATE, GD_BUTTON_UNPRESSED,
6999 GDI_DESIGN_UNPRESSED, gfx->bitmap, gd_x, gd_y,
7000 GDI_DESIGN_PRESSED, gfx->bitmap, gd_xp, gd_yp,
7001 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
7002 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
7003 GDI_DECORATION_SIZE, pos->size, pos->size,
7004 GDI_DECORATION_SHIFTING, 1, 1,
7005 GDI_DIRECT_DRAW, FALSE,
7006 GDI_EVENT_MASK, event_mask,
7007 GDI_CALLBACK_ACTION, HandleToolButtons,
7011 Error(ERR_EXIT, "cannot create gadget");
7013 tool_gadget[id] = gi;
7019 /* graphic position values for tool buttons */
7020 #define TOOL_BUTTON_YES_XPOS 2
7021 #define TOOL_BUTTON_YES_YPOS 250
7022 #define TOOL_BUTTON_YES_GFX_YPOS 0
7023 #define TOOL_BUTTON_YES_XSIZE 46
7024 #define TOOL_BUTTON_YES_YSIZE 28
7025 #define TOOL_BUTTON_NO_XPOS 52
7026 #define TOOL_BUTTON_NO_YPOS TOOL_BUTTON_YES_YPOS
7027 #define TOOL_BUTTON_NO_GFX_YPOS TOOL_BUTTON_YES_GFX_YPOS
7028 #define TOOL_BUTTON_NO_XSIZE TOOL_BUTTON_YES_XSIZE
7029 #define TOOL_BUTTON_NO_YSIZE TOOL_BUTTON_YES_YSIZE
7030 #define TOOL_BUTTON_CONFIRM_XPOS TOOL_BUTTON_YES_XPOS
7031 #define TOOL_BUTTON_CONFIRM_YPOS TOOL_BUTTON_YES_YPOS
7032 #define TOOL_BUTTON_CONFIRM_GFX_YPOS 30
7033 #define TOOL_BUTTON_CONFIRM_XSIZE 96
7034 #define TOOL_BUTTON_CONFIRM_YSIZE TOOL_BUTTON_YES_YSIZE
7035 #define TOOL_BUTTON_PLAYER_XSIZE 30
7036 #define TOOL_BUTTON_PLAYER_YSIZE 30
7037 #define TOOL_BUTTON_PLAYER_GFX_XPOS 5
7038 #define TOOL_BUTTON_PLAYER_GFX_YPOS 185
7039 #define TOOL_BUTTON_PLAYER_XPOS (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
7040 #define TOOL_BUTTON_PLAYER_YPOS (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
7041 #define TOOL_BUTTON_PLAYER1_XPOS (TOOL_BUTTON_PLAYER_XPOS \
7042 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
7043 #define TOOL_BUTTON_PLAYER2_XPOS (TOOL_BUTTON_PLAYER_XPOS \
7044 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
7045 #define TOOL_BUTTON_PLAYER3_XPOS (TOOL_BUTTON_PLAYER_XPOS \
7046 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
7047 #define TOOL_BUTTON_PLAYER4_XPOS (TOOL_BUTTON_PLAYER_XPOS \
7048 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
7049 #define TOOL_BUTTON_PLAYER1_YPOS (TOOL_BUTTON_PLAYER_YPOS \
7050 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
7051 #define TOOL_BUTTON_PLAYER2_YPOS (TOOL_BUTTON_PLAYER_YPOS \
7052 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
7053 #define TOOL_BUTTON_PLAYER3_YPOS (TOOL_BUTTON_PLAYER_YPOS \
7054 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
7055 #define TOOL_BUTTON_PLAYER4_YPOS (TOOL_BUTTON_PLAYER_YPOS \
7056 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
7065 } toolbutton_info[NUM_TOOL_BUTTONS] =
7068 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_GFX_YPOS,
7069 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_YPOS,
7070 TOOL_BUTTON_YES_XSIZE, TOOL_BUTTON_YES_YSIZE,
7075 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_GFX_YPOS,
7076 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_YPOS,
7077 TOOL_BUTTON_NO_XSIZE, TOOL_BUTTON_NO_YSIZE,
7082 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_GFX_YPOS,
7083 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_YPOS,
7084 TOOL_BUTTON_CONFIRM_XSIZE, TOOL_BUTTON_CONFIRM_YSIZE,
7085 TOOL_CTRL_ID_CONFIRM,
7089 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
7090 TOOL_BUTTON_PLAYER1_XPOS, TOOL_BUTTON_PLAYER1_YPOS,
7091 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
7092 TOOL_CTRL_ID_PLAYER_1,
7096 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
7097 TOOL_BUTTON_PLAYER2_XPOS, TOOL_BUTTON_PLAYER2_YPOS,
7098 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
7099 TOOL_CTRL_ID_PLAYER_2,
7103 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
7104 TOOL_BUTTON_PLAYER3_XPOS, TOOL_BUTTON_PLAYER3_YPOS,
7105 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
7106 TOOL_CTRL_ID_PLAYER_3,
7110 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
7111 TOOL_BUTTON_PLAYER4_XPOS, TOOL_BUTTON_PLAYER4_YPOS,
7112 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
7113 TOOL_CTRL_ID_PLAYER_4,
7118 void CreateToolButtons()
7122 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
7124 Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
7125 Bitmap *deco_bitmap = None;
7126 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
7127 struct GadgetInfo *gi;
7128 unsigned int event_mask;
7129 int gd_xoffset, gd_yoffset;
7130 int gd_x1, gd_x2, gd_y;
7133 event_mask = GD_EVENT_RELEASED;
7135 gd_xoffset = toolbutton_info[i].xpos;
7136 gd_yoffset = toolbutton_info[i].ypos;
7137 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
7138 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
7139 gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
7141 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
7143 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
7145 getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr),
7146 &deco_bitmap, &deco_x, &deco_y);
7147 deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
7148 deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
7151 gi = CreateGadget(GDI_CUSTOM_ID, id,
7152 GDI_INFO_TEXT, toolbutton_info[i].infotext,
7153 GDI_X, DX + GDI_ACTIVE_POS(toolbutton_info[i].x),
7154 GDI_Y, DY + GDI_ACTIVE_POS(toolbutton_info[i].y),
7155 GDI_WIDTH, toolbutton_info[i].width,
7156 GDI_HEIGHT, toolbutton_info[i].height,
7157 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
7158 GDI_STATE, GD_BUTTON_UNPRESSED,
7159 GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
7160 GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
7161 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
7162 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
7163 GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
7164 GDI_DECORATION_SHIFTING, 1, 1,
7165 GDI_DIRECT_DRAW, FALSE,
7166 GDI_EVENT_MASK, event_mask,
7167 GDI_CALLBACK_ACTION, HandleToolButtons,
7171 Error(ERR_EXIT, "cannot create gadget");
7173 tool_gadget[id] = gi;
7179 void FreeToolButtons()
7183 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
7184 FreeGadget(tool_gadget[i]);
7187 static void UnmapToolButtons()
7191 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
7192 UnmapGadget(tool_gadget[i]);
7195 static void HandleToolButtons(struct GadgetInfo *gi)
7197 request_gadget_id = gi->custom_id;
7200 static struct Mapping_EM_to_RND_object
7203 boolean is_rnd_to_em_mapping; /* unique mapping EM <-> RND */
7204 boolean is_backside; /* backside of moving element */
7210 em_object_mapping_list[] =
7213 Xblank, TRUE, FALSE,
7217 Yacid_splash_eB, FALSE, FALSE,
7218 EL_ACID_SPLASH_RIGHT, -1, -1
7221 Yacid_splash_wB, FALSE, FALSE,
7222 EL_ACID_SPLASH_LEFT, -1, -1
7225 #ifdef EM_ENGINE_BAD_ROLL
7227 Xstone_force_e, FALSE, FALSE,
7228 EL_ROCK, -1, MV_BIT_RIGHT
7231 Xstone_force_w, FALSE, FALSE,
7232 EL_ROCK, -1, MV_BIT_LEFT
7235 Xnut_force_e, FALSE, FALSE,
7236 EL_NUT, -1, MV_BIT_RIGHT
7239 Xnut_force_w, FALSE, FALSE,
7240 EL_NUT, -1, MV_BIT_LEFT
7243 Xspring_force_e, FALSE, FALSE,
7244 EL_SPRING, -1, MV_BIT_RIGHT
7247 Xspring_force_w, FALSE, FALSE,
7248 EL_SPRING, -1, MV_BIT_LEFT
7251 Xemerald_force_e, FALSE, FALSE,
7252 EL_EMERALD, -1, MV_BIT_RIGHT
7255 Xemerald_force_w, FALSE, FALSE,
7256 EL_EMERALD, -1, MV_BIT_LEFT
7259 Xdiamond_force_e, FALSE, FALSE,
7260 EL_DIAMOND, -1, MV_BIT_RIGHT
7263 Xdiamond_force_w, FALSE, FALSE,
7264 EL_DIAMOND, -1, MV_BIT_LEFT
7267 Xbomb_force_e, FALSE, FALSE,
7268 EL_BOMB, -1, MV_BIT_RIGHT
7271 Xbomb_force_w, FALSE, FALSE,
7272 EL_BOMB, -1, MV_BIT_LEFT
7274 #endif /* EM_ENGINE_BAD_ROLL */
7277 Xstone, TRUE, FALSE,
7281 Xstone_pause, FALSE, FALSE,
7285 Xstone_fall, FALSE, FALSE,
7289 Ystone_s, FALSE, FALSE,
7290 EL_ROCK, ACTION_FALLING, -1
7293 Ystone_sB, FALSE, TRUE,
7294 EL_ROCK, ACTION_FALLING, -1
7297 Ystone_e, FALSE, FALSE,
7298 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
7301 Ystone_eB, FALSE, TRUE,
7302 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
7305 Ystone_w, FALSE, FALSE,
7306 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
7309 Ystone_wB, FALSE, TRUE,
7310 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
7317 Xnut_pause, FALSE, FALSE,
7321 Xnut_fall, FALSE, FALSE,
7325 Ynut_s, FALSE, FALSE,
7326 EL_NUT, ACTION_FALLING, -1
7329 Ynut_sB, FALSE, TRUE,
7330 EL_NUT, ACTION_FALLING, -1
7333 Ynut_e, FALSE, FALSE,
7334 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
7337 Ynut_eB, FALSE, TRUE,
7338 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
7341 Ynut_w, FALSE, FALSE,
7342 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
7345 Ynut_wB, FALSE, TRUE,
7346 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
7349 Xbug_n, TRUE, FALSE,
7353 Xbug_e, TRUE, FALSE,
7354 EL_BUG_RIGHT, -1, -1
7357 Xbug_s, TRUE, FALSE,
7361 Xbug_w, TRUE, FALSE,
7365 Xbug_gon, FALSE, FALSE,
7369 Xbug_goe, FALSE, FALSE,
7370 EL_BUG_RIGHT, -1, -1
7373 Xbug_gos, FALSE, FALSE,
7377 Xbug_gow, FALSE, FALSE,
7381 Ybug_n, FALSE, FALSE,
7382 EL_BUG, ACTION_MOVING, MV_BIT_UP
7385 Ybug_nB, FALSE, TRUE,
7386 EL_BUG, ACTION_MOVING, MV_BIT_UP
7389 Ybug_e, FALSE, FALSE,
7390 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
7393 Ybug_eB, FALSE, TRUE,
7394 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
7397 Ybug_s, FALSE, FALSE,
7398 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
7401 Ybug_sB, FALSE, TRUE,
7402 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
7405 Ybug_w, FALSE, FALSE,
7406 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
7409 Ybug_wB, FALSE, TRUE,
7410 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
7413 Ybug_w_n, FALSE, FALSE,
7414 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
7417 Ybug_n_e, FALSE, FALSE,
7418 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
7421 Ybug_e_s, FALSE, FALSE,
7422 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
7425 Ybug_s_w, FALSE, FALSE,
7426 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
7429 Ybug_e_n, FALSE, FALSE,
7430 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
7433 Ybug_s_e, FALSE, FALSE,
7434 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
7437 Ybug_w_s, FALSE, FALSE,
7438 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
7441 Ybug_n_w, FALSE, FALSE,
7442 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
7445 Ybug_stone, FALSE, FALSE,
7446 EL_BUG, ACTION_SMASHED_BY_ROCK, -1
7449 Ybug_spring, FALSE, FALSE,
7450 EL_BUG, ACTION_SMASHED_BY_SPRING, -1
7453 Xtank_n, TRUE, FALSE,
7454 EL_SPACESHIP_UP, -1, -1
7457 Xtank_e, TRUE, FALSE,
7458 EL_SPACESHIP_RIGHT, -1, -1
7461 Xtank_s, TRUE, FALSE,
7462 EL_SPACESHIP_DOWN, -1, -1
7465 Xtank_w, TRUE, FALSE,
7466 EL_SPACESHIP_LEFT, -1, -1
7469 Xtank_gon, FALSE, FALSE,
7470 EL_SPACESHIP_UP, -1, -1
7473 Xtank_goe, FALSE, FALSE,
7474 EL_SPACESHIP_RIGHT, -1, -1
7477 Xtank_gos, FALSE, FALSE,
7478 EL_SPACESHIP_DOWN, -1, -1
7481 Xtank_gow, FALSE, FALSE,
7482 EL_SPACESHIP_LEFT, -1, -1
7485 Ytank_n, FALSE, FALSE,
7486 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
7489 Ytank_nB, FALSE, TRUE,
7490 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
7493 Ytank_e, FALSE, FALSE,
7494 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
7497 Ytank_eB, FALSE, TRUE,
7498 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
7501 Ytank_s, FALSE, FALSE,
7502 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
7505 Ytank_sB, FALSE, TRUE,
7506 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
7509 Ytank_w, FALSE, FALSE,
7510 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
7513 Ytank_wB, FALSE, TRUE,
7514 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
7517 Ytank_w_n, FALSE, FALSE,
7518 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
7521 Ytank_n_e, FALSE, FALSE,
7522 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
7525 Ytank_e_s, FALSE, FALSE,
7526 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
7529 Ytank_s_w, FALSE, FALSE,
7530 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
7533 Ytank_e_n, FALSE, FALSE,
7534 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
7537 Ytank_s_e, FALSE, FALSE,
7538 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
7541 Ytank_w_s, FALSE, FALSE,
7542 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
7545 Ytank_n_w, FALSE, FALSE,
7546 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
7549 Ytank_stone, FALSE, FALSE,
7550 EL_SPACESHIP, ACTION_SMASHED_BY_ROCK, -1
7553 Ytank_spring, FALSE, FALSE,
7554 EL_SPACESHIP, ACTION_SMASHED_BY_SPRING, -1
7557 Xandroid, TRUE, FALSE,
7558 EL_EMC_ANDROID, ACTION_ACTIVE, -1
7561 Xandroid_1_n, FALSE, FALSE,
7562 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
7565 Xandroid_2_n, FALSE, FALSE,
7566 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
7569 Xandroid_1_e, FALSE, FALSE,
7570 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
7573 Xandroid_2_e, FALSE, FALSE,
7574 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
7577 Xandroid_1_w, FALSE, FALSE,
7578 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
7581 Xandroid_2_w, FALSE, FALSE,
7582 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
7585 Xandroid_1_s, FALSE, FALSE,
7586 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
7589 Xandroid_2_s, FALSE, FALSE,
7590 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
7593 Yandroid_n, FALSE, FALSE,
7594 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
7597 Yandroid_nB, FALSE, TRUE,
7598 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
7601 Yandroid_ne, FALSE, FALSE,
7602 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPRIGHT
7605 Yandroid_neB, FALSE, TRUE,
7606 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPRIGHT
7609 Yandroid_e, FALSE, FALSE,
7610 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
7613 Yandroid_eB, FALSE, TRUE,
7614 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
7617 Yandroid_se, FALSE, FALSE,
7618 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNRIGHT
7621 Yandroid_seB, FALSE, TRUE,
7622 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNRIGHT
7625 Yandroid_s, FALSE, FALSE,
7626 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
7629 Yandroid_sB, FALSE, TRUE,
7630 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
7633 Yandroid_sw, FALSE, FALSE,
7634 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNLEFT
7637 Yandroid_swB, FALSE, TRUE,
7638 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNLEFT
7641 Yandroid_w, FALSE, FALSE,
7642 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
7645 Yandroid_wB, FALSE, TRUE,
7646 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
7649 Yandroid_nw, FALSE, FALSE,
7650 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPLEFT
7653 Yandroid_nwB, FALSE, TRUE,
7654 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPLEFT
7657 Xspring, TRUE, FALSE,
7661 Xspring_pause, FALSE, FALSE,
7665 Xspring_e, FALSE, FALSE,
7669 Xspring_w, FALSE, FALSE,
7673 Xspring_fall, FALSE, FALSE,
7677 Yspring_s, FALSE, FALSE,
7678 EL_SPRING, ACTION_FALLING, -1
7681 Yspring_sB, FALSE, TRUE,
7682 EL_SPRING, ACTION_FALLING, -1
7685 Yspring_e, FALSE, FALSE,
7686 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
7689 Yspring_eB, FALSE, TRUE,
7690 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
7693 Yspring_w, FALSE, FALSE,
7694 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
7697 Yspring_wB, FALSE, TRUE,
7698 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
7701 Yspring_kill_e, FALSE, FALSE,
7702 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
7705 Yspring_kill_eB, FALSE, TRUE,
7706 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
7709 Yspring_kill_w, FALSE, FALSE,
7710 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
7713 Yspring_kill_wB, FALSE, TRUE,
7714 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
7717 Xeater_n, TRUE, FALSE,
7718 EL_YAMYAM_UP, -1, -1
7721 Xeater_e, TRUE, FALSE,
7722 EL_YAMYAM_RIGHT, -1, -1
7725 Xeater_w, TRUE, FALSE,
7726 EL_YAMYAM_LEFT, -1, -1
7729 Xeater_s, TRUE, FALSE,
7730 EL_YAMYAM_DOWN, -1, -1
7733 Yeater_n, FALSE, FALSE,
7734 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
7737 Yeater_nB, FALSE, TRUE,
7738 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
7741 Yeater_e, FALSE, FALSE,
7742 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
7745 Yeater_eB, FALSE, TRUE,
7746 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
7749 Yeater_s, FALSE, FALSE,
7750 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
7753 Yeater_sB, FALSE, TRUE,
7754 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
7757 Yeater_w, FALSE, FALSE,
7758 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
7761 Yeater_wB, FALSE, TRUE,
7762 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
7765 Yeater_stone, FALSE, FALSE,
7766 EL_YAMYAM, ACTION_SMASHED_BY_ROCK, -1
7769 Yeater_spring, FALSE, FALSE,
7770 EL_YAMYAM, ACTION_SMASHED_BY_SPRING, -1
7773 Xalien, TRUE, FALSE,
7777 Xalien_pause, FALSE, FALSE,
7781 Yalien_n, FALSE, FALSE,
7782 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
7785 Yalien_nB, FALSE, TRUE,
7786 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
7789 Yalien_e, FALSE, FALSE,
7790 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
7793 Yalien_eB, FALSE, TRUE,
7794 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
7797 Yalien_s, FALSE, FALSE,
7798 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
7801 Yalien_sB, FALSE, TRUE,
7802 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
7805 Yalien_w, FALSE, FALSE,
7806 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
7809 Yalien_wB, FALSE, TRUE,
7810 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
7813 Yalien_stone, FALSE, FALSE,
7814 EL_ROBOT, ACTION_SMASHED_BY_ROCK, -1
7817 Yalien_spring, FALSE, FALSE,
7818 EL_ROBOT, ACTION_SMASHED_BY_SPRING, -1
7821 Xemerald, TRUE, FALSE,
7825 Xemerald_pause, FALSE, FALSE,
7829 Xemerald_fall, FALSE, FALSE,
7833 Xemerald_shine, FALSE, FALSE,
7834 EL_EMERALD, ACTION_TWINKLING, -1
7837 Yemerald_s, FALSE, FALSE,
7838 EL_EMERALD, ACTION_FALLING, -1
7841 Yemerald_sB, FALSE, TRUE,
7842 EL_EMERALD, ACTION_FALLING, -1
7845 Yemerald_e, FALSE, FALSE,
7846 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
7849 Yemerald_eB, FALSE, TRUE,
7850 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
7853 Yemerald_w, FALSE, FALSE,
7854 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
7857 Yemerald_wB, FALSE, TRUE,
7858 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
7861 Yemerald_eat, FALSE, FALSE,
7862 EL_EMERALD, ACTION_COLLECTING, -1
7865 Yemerald_stone, FALSE, FALSE,
7866 EL_NUT, ACTION_BREAKING, -1
7869 Xdiamond, TRUE, FALSE,
7873 Xdiamond_pause, FALSE, FALSE,
7877 Xdiamond_fall, FALSE, FALSE,
7881 Xdiamond_shine, FALSE, FALSE,
7882 EL_DIAMOND, ACTION_TWINKLING, -1
7885 Ydiamond_s, FALSE, FALSE,
7886 EL_DIAMOND, ACTION_FALLING, -1
7889 Ydiamond_sB, FALSE, TRUE,
7890 EL_DIAMOND, ACTION_FALLING, -1
7893 Ydiamond_e, FALSE, FALSE,
7894 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
7897 Ydiamond_eB, FALSE, TRUE,
7898 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
7901 Ydiamond_w, FALSE, FALSE,
7902 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
7905 Ydiamond_wB, FALSE, TRUE,
7906 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
7909 Ydiamond_eat, FALSE, FALSE,
7910 EL_DIAMOND, ACTION_COLLECTING, -1
7913 Ydiamond_stone, FALSE, FALSE,
7914 EL_DIAMOND, ACTION_SMASHED_BY_ROCK, -1
7917 Xdrip_fall, TRUE, FALSE,
7918 EL_AMOEBA_DROP, -1, -1
7921 Xdrip_stretch, FALSE, FALSE,
7922 EL_AMOEBA_DROP, ACTION_FALLING, -1
7925 Xdrip_stretchB, FALSE, TRUE,
7926 EL_AMOEBA_DROP, ACTION_FALLING, -1
7929 Xdrip_eat, FALSE, FALSE,
7930 EL_AMOEBA_DROP, ACTION_GROWING, -1
7933 Ydrip_s1, FALSE, FALSE,
7934 EL_AMOEBA_DROP, ACTION_FALLING, -1
7937 Ydrip_s1B, FALSE, TRUE,
7938 EL_AMOEBA_DROP, ACTION_FALLING, -1
7941 Ydrip_s2, FALSE, FALSE,
7942 EL_AMOEBA_DROP, ACTION_FALLING, -1
7945 Ydrip_s2B, FALSE, TRUE,
7946 EL_AMOEBA_DROP, ACTION_FALLING, -1
7953 Xbomb_pause, FALSE, FALSE,
7957 Xbomb_fall, FALSE, FALSE,
7961 Ybomb_s, FALSE, FALSE,
7962 EL_BOMB, ACTION_FALLING, -1
7965 Ybomb_sB, FALSE, TRUE,
7966 EL_BOMB, ACTION_FALLING, -1
7969 Ybomb_e, FALSE, FALSE,
7970 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
7973 Ybomb_eB, FALSE, TRUE,
7974 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
7977 Ybomb_w, FALSE, FALSE,
7978 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
7981 Ybomb_wB, FALSE, TRUE,
7982 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
7985 Ybomb_eat, FALSE, FALSE,
7986 EL_BOMB, ACTION_ACTIVATING, -1
7989 Xballoon, TRUE, FALSE,
7993 Yballoon_n, FALSE, FALSE,
7994 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
7997 Yballoon_nB, FALSE, TRUE,
7998 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
8001 Yballoon_e, FALSE, FALSE,
8002 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
8005 Yballoon_eB, FALSE, TRUE,
8006 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
8009 Yballoon_s, FALSE, FALSE,
8010 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
8013 Yballoon_sB, FALSE, TRUE,
8014 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
8017 Yballoon_w, FALSE, FALSE,
8018 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
8021 Yballoon_wB, FALSE, TRUE,
8022 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
8025 Xgrass, TRUE, FALSE,
8026 EL_EMC_GRASS, -1, -1
8029 Ygrass_nB, FALSE, FALSE,
8030 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_UP
8033 Ygrass_eB, FALSE, FALSE,
8034 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_RIGHT
8037 Ygrass_sB, FALSE, FALSE,
8038 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_DOWN
8041 Ygrass_wB, FALSE, FALSE,
8042 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_LEFT
8049 Ydirt_nB, FALSE, FALSE,
8050 EL_SAND, ACTION_DIGGING, MV_BIT_UP
8053 Ydirt_eB, FALSE, FALSE,
8054 EL_SAND, ACTION_DIGGING, MV_BIT_RIGHT
8057 Ydirt_sB, FALSE, FALSE,
8058 EL_SAND, ACTION_DIGGING, MV_BIT_DOWN
8061 Ydirt_wB, FALSE, FALSE,
8062 EL_SAND, ACTION_DIGGING, MV_BIT_LEFT
8065 Xacid_ne, TRUE, FALSE,
8066 EL_ACID_POOL_TOPRIGHT, -1, -1
8069 Xacid_se, TRUE, FALSE,
8070 EL_ACID_POOL_BOTTOMRIGHT, -1, -1
8073 Xacid_s, TRUE, FALSE,
8074 EL_ACID_POOL_BOTTOM, -1, -1
8077 Xacid_sw, TRUE, FALSE,
8078 EL_ACID_POOL_BOTTOMLEFT, -1, -1
8081 Xacid_nw, TRUE, FALSE,
8082 EL_ACID_POOL_TOPLEFT, -1, -1
8085 Xacid_1, TRUE, FALSE,
8089 Xacid_2, FALSE, FALSE,
8093 Xacid_3, FALSE, FALSE,
8097 Xacid_4, FALSE, FALSE,
8101 Xacid_5, FALSE, FALSE,
8105 Xacid_6, FALSE, FALSE,
8109 Xacid_7, FALSE, FALSE,
8113 Xacid_8, FALSE, FALSE,
8117 Xball_1, TRUE, FALSE,
8118 EL_EMC_MAGIC_BALL, -1, -1
8121 Xball_1B, FALSE, FALSE,
8122 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
8125 Xball_2, FALSE, FALSE,
8126 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
8129 Xball_2B, FALSE, FALSE,
8130 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
8133 Yball_eat, FALSE, FALSE,
8134 EL_EMC_MAGIC_BALL, ACTION_DROPPING, -1
8137 Ykey_1_eat, FALSE, FALSE,
8138 EL_EM_KEY_1, ACTION_COLLECTING, -1
8141 Ykey_2_eat, FALSE, FALSE,
8142 EL_EM_KEY_2, ACTION_COLLECTING, -1
8145 Ykey_3_eat, FALSE, FALSE,
8146 EL_EM_KEY_3, ACTION_COLLECTING, -1
8149 Ykey_4_eat, FALSE, FALSE,
8150 EL_EM_KEY_4, ACTION_COLLECTING, -1
8153 Ykey_5_eat, FALSE, FALSE,
8154 EL_EMC_KEY_5, ACTION_COLLECTING, -1
8157 Ykey_6_eat, FALSE, FALSE,
8158 EL_EMC_KEY_6, ACTION_COLLECTING, -1
8161 Ykey_7_eat, FALSE, FALSE,
8162 EL_EMC_KEY_7, ACTION_COLLECTING, -1
8165 Ykey_8_eat, FALSE, FALSE,
8166 EL_EMC_KEY_8, ACTION_COLLECTING, -1
8169 Ylenses_eat, FALSE, FALSE,
8170 EL_EMC_LENSES, ACTION_COLLECTING, -1
8173 Ymagnify_eat, FALSE, FALSE,
8174 EL_EMC_MAGNIFIER, ACTION_COLLECTING, -1
8177 Ygrass_eat, FALSE, FALSE,
8178 EL_EMC_GRASS, ACTION_SNAPPING, -1
8181 Ydirt_eat, FALSE, FALSE,
8182 EL_SAND, ACTION_SNAPPING, -1
8185 Xgrow_ns, TRUE, FALSE,
8186 EL_EXPANDABLE_WALL_VERTICAL, -1, -1
8189 Ygrow_ns_eat, FALSE, FALSE,
8190 EL_EXPANDABLE_WALL_VERTICAL, ACTION_GROWING, -1
8193 Xgrow_ew, TRUE, FALSE,
8194 EL_EXPANDABLE_WALL_HORIZONTAL, -1, -1
8197 Ygrow_ew_eat, FALSE, FALSE,
8198 EL_EXPANDABLE_WALL_HORIZONTAL, ACTION_GROWING, -1
8201 Xwonderwall, TRUE, FALSE,
8202 EL_MAGIC_WALL, -1, -1
8205 XwonderwallB, FALSE, FALSE,
8206 EL_MAGIC_WALL, ACTION_ACTIVE, -1
8209 Xamoeba_1, TRUE, FALSE,
8210 EL_AMOEBA_DRY, ACTION_OTHER, -1
8213 Xamoeba_2, FALSE, FALSE,
8214 EL_AMOEBA_DRY, ACTION_OTHER, -1
8217 Xamoeba_3, FALSE, FALSE,
8218 EL_AMOEBA_DRY, ACTION_OTHER, -1
8221 Xamoeba_4, FALSE, FALSE,
8222 EL_AMOEBA_DRY, ACTION_OTHER, -1
8225 Xamoeba_5, TRUE, FALSE,
8226 EL_AMOEBA_WET, ACTION_OTHER, -1
8229 Xamoeba_6, FALSE, FALSE,
8230 EL_AMOEBA_WET, ACTION_OTHER, -1
8233 Xamoeba_7, FALSE, FALSE,
8234 EL_AMOEBA_WET, ACTION_OTHER, -1
8237 Xamoeba_8, FALSE, FALSE,
8238 EL_AMOEBA_WET, ACTION_OTHER, -1
8241 Xdoor_1, TRUE, FALSE,
8242 EL_EM_GATE_1, -1, -1
8245 Xdoor_2, TRUE, FALSE,
8246 EL_EM_GATE_2, -1, -1
8249 Xdoor_3, TRUE, FALSE,
8250 EL_EM_GATE_3, -1, -1
8253 Xdoor_4, TRUE, FALSE,
8254 EL_EM_GATE_4, -1, -1
8257 Xdoor_5, TRUE, FALSE,
8258 EL_EMC_GATE_5, -1, -1
8261 Xdoor_6, TRUE, FALSE,
8262 EL_EMC_GATE_6, -1, -1
8265 Xdoor_7, TRUE, FALSE,
8266 EL_EMC_GATE_7, -1, -1
8269 Xdoor_8, TRUE, FALSE,
8270 EL_EMC_GATE_8, -1, -1
8273 Xkey_1, TRUE, FALSE,
8277 Xkey_2, TRUE, FALSE,
8281 Xkey_3, TRUE, FALSE,
8285 Xkey_4, TRUE, FALSE,
8289 Xkey_5, TRUE, FALSE,
8290 EL_EMC_KEY_5, -1, -1
8293 Xkey_6, TRUE, FALSE,
8294 EL_EMC_KEY_6, -1, -1
8297 Xkey_7, TRUE, FALSE,
8298 EL_EMC_KEY_7, -1, -1
8301 Xkey_8, TRUE, FALSE,
8302 EL_EMC_KEY_8, -1, -1
8305 Xwind_n, TRUE, FALSE,
8306 EL_BALLOON_SWITCH_UP, -1, -1
8309 Xwind_e, TRUE, FALSE,
8310 EL_BALLOON_SWITCH_RIGHT, -1, -1
8313 Xwind_s, TRUE, FALSE,
8314 EL_BALLOON_SWITCH_DOWN, -1, -1
8317 Xwind_w, TRUE, FALSE,
8318 EL_BALLOON_SWITCH_LEFT, -1, -1
8321 Xwind_nesw, TRUE, FALSE,
8322 EL_BALLOON_SWITCH_ANY, -1, -1
8325 Xwind_stop, TRUE, FALSE,
8326 EL_BALLOON_SWITCH_NONE, -1, -1
8330 EL_EM_EXIT_CLOSED, -1, -1
8333 Xexit_1, TRUE, FALSE,
8334 EL_EM_EXIT_OPEN, -1, -1
8337 Xexit_2, FALSE, FALSE,
8338 EL_EM_EXIT_OPEN, -1, -1
8341 Xexit_3, FALSE, FALSE,
8342 EL_EM_EXIT_OPEN, -1, -1
8345 Xdynamite, TRUE, FALSE,
8346 EL_EM_DYNAMITE, -1, -1
8349 Ydynamite_eat, FALSE, FALSE,
8350 EL_EM_DYNAMITE, ACTION_COLLECTING, -1
8353 Xdynamite_1, TRUE, FALSE,
8354 EL_EM_DYNAMITE_ACTIVE, -1, -1
8357 Xdynamite_2, FALSE, FALSE,
8358 EL_EM_DYNAMITE_ACTIVE, -1, -1
8361 Xdynamite_3, FALSE, FALSE,
8362 EL_EM_DYNAMITE_ACTIVE, -1, -1
8365 Xdynamite_4, FALSE, FALSE,
8366 EL_EM_DYNAMITE_ACTIVE, -1, -1
8369 Xbumper, TRUE, FALSE,
8370 EL_EMC_SPRING_BUMPER, -1, -1
8373 XbumperB, FALSE, FALSE,
8374 EL_EMC_SPRING_BUMPER, ACTION_ACTIVE, -1
8377 Xwheel, TRUE, FALSE,
8378 EL_ROBOT_WHEEL, -1, -1
8381 XwheelB, FALSE, FALSE,
8382 EL_ROBOT_WHEEL, ACTION_ACTIVE, -1
8385 Xswitch, TRUE, FALSE,
8386 EL_EMC_MAGIC_BALL_SWITCH, -1, -1
8389 XswitchB, FALSE, FALSE,
8390 EL_EMC_MAGIC_BALL_SWITCH, ACTION_ACTIVE, -1
8394 EL_QUICKSAND_EMPTY, -1, -1
8397 Xsand_stone, TRUE, FALSE,
8398 EL_QUICKSAND_FULL, -1, -1
8401 Xsand_stonein_1, FALSE, TRUE,
8402 EL_ROCK, ACTION_FILLING, -1
8405 Xsand_stonein_2, FALSE, TRUE,
8406 EL_ROCK, ACTION_FILLING, -1
8409 Xsand_stonein_3, FALSE, TRUE,
8410 EL_ROCK, ACTION_FILLING, -1
8413 Xsand_stonein_4, FALSE, TRUE,
8414 EL_ROCK, ACTION_FILLING, -1
8418 Xsand_stonesand_1, FALSE, FALSE,
8419 EL_QUICKSAND_EMPTYING, -1, -1
8422 Xsand_stonesand_2, FALSE, FALSE,
8423 EL_QUICKSAND_EMPTYING, -1, -1
8426 Xsand_stonesand_3, FALSE, FALSE,
8427 EL_QUICKSAND_EMPTYING, -1, -1
8430 Xsand_stonesand_4, FALSE, FALSE,
8431 EL_QUICKSAND_EMPTYING, -1, -1
8434 Xsand_stonesand_quickout_1, FALSE, FALSE,
8435 EL_QUICKSAND_EMPTYING, -1, -1
8438 Xsand_stonesand_quickout_2, FALSE, FALSE,
8439 EL_QUICKSAND_EMPTYING, -1, -1
8443 Xsand_stonesand_1, FALSE, FALSE,
8444 EL_QUICKSAND_FULL, -1, -1
8447 Xsand_stonesand_2, FALSE, FALSE,
8448 EL_QUICKSAND_FULL, -1, -1
8451 Xsand_stonesand_3, FALSE, FALSE,
8452 EL_QUICKSAND_FULL, -1, -1
8455 Xsand_stonesand_4, FALSE, FALSE,
8456 EL_QUICKSAND_FULL, -1, -1
8460 Xsand_stoneout_1, FALSE, FALSE,
8461 EL_ROCK, ACTION_EMPTYING, -1
8464 Xsand_stoneout_2, FALSE, FALSE,
8465 EL_ROCK, ACTION_EMPTYING, -1
8469 Xsand_sandstone_1, FALSE, FALSE,
8470 EL_QUICKSAND_FILLING, -1, -1
8473 Xsand_sandstone_2, FALSE, FALSE,
8474 EL_QUICKSAND_FILLING, -1, -1
8477 Xsand_sandstone_3, FALSE, FALSE,
8478 EL_QUICKSAND_FILLING, -1, -1
8481 Xsand_sandstone_4, FALSE, FALSE,
8482 EL_QUICKSAND_FILLING, -1, -1
8486 Xsand_sandstone_1, FALSE, FALSE,
8487 EL_QUICKSAND_FULL, -1, -1
8490 Xsand_sandstone_2, FALSE, FALSE,
8491 EL_QUICKSAND_FULL, -1, -1
8494 Xsand_sandstone_3, FALSE, FALSE,
8495 EL_QUICKSAND_FULL, -1, -1
8498 Xsand_sandstone_4, FALSE, FALSE,
8499 EL_QUICKSAND_FULL, -1, -1
8503 Xplant, TRUE, FALSE,
8504 EL_EMC_PLANT, -1, -1
8507 Yplant, FALSE, FALSE,
8508 EL_EMC_PLANT, -1, -1
8511 Xlenses, TRUE, FALSE,
8512 EL_EMC_LENSES, -1, -1
8515 Xmagnify, TRUE, FALSE,
8516 EL_EMC_MAGNIFIER, -1, -1
8519 Xdripper, TRUE, FALSE,
8520 EL_EMC_DRIPPER, -1, -1
8523 XdripperB, FALSE, FALSE,
8524 EL_EMC_DRIPPER, ACTION_ACTIVE, -1
8527 Xfake_blank, TRUE, FALSE,
8528 EL_INVISIBLE_WALL, -1, -1
8531 Xfake_blankB, FALSE, FALSE,
8532 EL_INVISIBLE_WALL, ACTION_ACTIVE, -1
8535 Xfake_grass, TRUE, FALSE,
8536 EL_EMC_FAKE_GRASS, -1, -1
8539 Xfake_grassB, FALSE, FALSE,
8540 EL_EMC_FAKE_GRASS, ACTION_ACTIVE, -1
8543 Xfake_door_1, TRUE, FALSE,
8544 EL_EM_GATE_1_GRAY, -1, -1
8547 Xfake_door_2, TRUE, FALSE,
8548 EL_EM_GATE_2_GRAY, -1, -1
8551 Xfake_door_3, TRUE, FALSE,
8552 EL_EM_GATE_3_GRAY, -1, -1
8555 Xfake_door_4, TRUE, FALSE,
8556 EL_EM_GATE_4_GRAY, -1, -1
8559 Xfake_door_5, TRUE, FALSE,
8560 EL_EMC_GATE_5_GRAY, -1, -1
8563 Xfake_door_6, TRUE, FALSE,
8564 EL_EMC_GATE_6_GRAY, -1, -1
8567 Xfake_door_7, TRUE, FALSE,
8568 EL_EMC_GATE_7_GRAY, -1, -1
8571 Xfake_door_8, TRUE, FALSE,
8572 EL_EMC_GATE_8_GRAY, -1, -1
8575 Xfake_acid_1, TRUE, FALSE,
8576 EL_EMC_FAKE_ACID, -1, -1
8579 Xfake_acid_2, FALSE, FALSE,
8580 EL_EMC_FAKE_ACID, -1, -1
8583 Xfake_acid_3, FALSE, FALSE,
8584 EL_EMC_FAKE_ACID, -1, -1
8587 Xfake_acid_4, FALSE, FALSE,
8588 EL_EMC_FAKE_ACID, -1, -1
8591 Xfake_acid_5, FALSE, FALSE,
8592 EL_EMC_FAKE_ACID, -1, -1
8595 Xfake_acid_6, FALSE, FALSE,
8596 EL_EMC_FAKE_ACID, -1, -1
8599 Xfake_acid_7, FALSE, FALSE,
8600 EL_EMC_FAKE_ACID, -1, -1
8603 Xfake_acid_8, FALSE, FALSE,
8604 EL_EMC_FAKE_ACID, -1, -1
8607 Xsteel_1, TRUE, FALSE,
8608 EL_STEELWALL, -1, -1
8611 Xsteel_2, TRUE, FALSE,
8612 EL_EMC_STEELWALL_2, -1, -1
8615 Xsteel_3, TRUE, FALSE,
8616 EL_EMC_STEELWALL_3, -1, -1
8619 Xsteel_4, TRUE, FALSE,
8620 EL_EMC_STEELWALL_4, -1, -1
8623 Xwall_1, TRUE, FALSE,
8627 Xwall_2, TRUE, FALSE,
8628 EL_EMC_WALL_14, -1, -1
8631 Xwall_3, TRUE, FALSE,
8632 EL_EMC_WALL_15, -1, -1
8635 Xwall_4, TRUE, FALSE,
8636 EL_EMC_WALL_16, -1, -1
8639 Xround_wall_1, TRUE, FALSE,
8640 EL_WALL_SLIPPERY, -1, -1
8643 Xround_wall_2, TRUE, FALSE,
8644 EL_EMC_WALL_SLIPPERY_2, -1, -1
8647 Xround_wall_3, TRUE, FALSE,
8648 EL_EMC_WALL_SLIPPERY_3, -1, -1
8651 Xround_wall_4, TRUE, FALSE,
8652 EL_EMC_WALL_SLIPPERY_4, -1, -1
8655 Xdecor_1, TRUE, FALSE,
8656 EL_EMC_WALL_8, -1, -1
8659 Xdecor_2, TRUE, FALSE,
8660 EL_EMC_WALL_6, -1, -1
8663 Xdecor_3, TRUE, FALSE,
8664 EL_EMC_WALL_4, -1, -1
8667 Xdecor_4, TRUE, FALSE,
8668 EL_EMC_WALL_7, -1, -1
8671 Xdecor_5, TRUE, FALSE,
8672 EL_EMC_WALL_5, -1, -1
8675 Xdecor_6, TRUE, FALSE,
8676 EL_EMC_WALL_9, -1, -1
8679 Xdecor_7, TRUE, FALSE,
8680 EL_EMC_WALL_10, -1, -1
8683 Xdecor_8, TRUE, FALSE,
8684 EL_EMC_WALL_1, -1, -1
8687 Xdecor_9, TRUE, FALSE,
8688 EL_EMC_WALL_2, -1, -1
8691 Xdecor_10, TRUE, FALSE,
8692 EL_EMC_WALL_3, -1, -1
8695 Xdecor_11, TRUE, FALSE,
8696 EL_EMC_WALL_11, -1, -1
8699 Xdecor_12, TRUE, FALSE,
8700 EL_EMC_WALL_12, -1, -1
8703 Xalpha_0, TRUE, FALSE,
8704 EL_CHAR('0'), -1, -1
8707 Xalpha_1, TRUE, FALSE,
8708 EL_CHAR('1'), -1, -1
8711 Xalpha_2, TRUE, FALSE,
8712 EL_CHAR('2'), -1, -1
8715 Xalpha_3, TRUE, FALSE,
8716 EL_CHAR('3'), -1, -1
8719 Xalpha_4, TRUE, FALSE,
8720 EL_CHAR('4'), -1, -1
8723 Xalpha_5, TRUE, FALSE,
8724 EL_CHAR('5'), -1, -1
8727 Xalpha_6, TRUE, FALSE,
8728 EL_CHAR('6'), -1, -1
8731 Xalpha_7, TRUE, FALSE,
8732 EL_CHAR('7'), -1, -1
8735 Xalpha_8, TRUE, FALSE,
8736 EL_CHAR('8'), -1, -1
8739 Xalpha_9, TRUE, FALSE,
8740 EL_CHAR('9'), -1, -1
8743 Xalpha_excla, TRUE, FALSE,
8744 EL_CHAR('!'), -1, -1
8747 Xalpha_quote, TRUE, FALSE,
8748 EL_CHAR('"'), -1, -1
8751 Xalpha_comma, TRUE, FALSE,
8752 EL_CHAR(','), -1, -1
8755 Xalpha_minus, TRUE, FALSE,
8756 EL_CHAR('-'), -1, -1
8759 Xalpha_perio, TRUE, FALSE,
8760 EL_CHAR('.'), -1, -1
8763 Xalpha_colon, TRUE, FALSE,
8764 EL_CHAR(':'), -1, -1
8767 Xalpha_quest, TRUE, FALSE,
8768 EL_CHAR('?'), -1, -1
8771 Xalpha_a, TRUE, FALSE,
8772 EL_CHAR('A'), -1, -1
8775 Xalpha_b, TRUE, FALSE,
8776 EL_CHAR('B'), -1, -1
8779 Xalpha_c, TRUE, FALSE,
8780 EL_CHAR('C'), -1, -1
8783 Xalpha_d, TRUE, FALSE,
8784 EL_CHAR('D'), -1, -1
8787 Xalpha_e, TRUE, FALSE,
8788 EL_CHAR('E'), -1, -1
8791 Xalpha_f, TRUE, FALSE,
8792 EL_CHAR('F'), -1, -1
8795 Xalpha_g, TRUE, FALSE,
8796 EL_CHAR('G'), -1, -1
8799 Xalpha_h, TRUE, FALSE,
8800 EL_CHAR('H'), -1, -1
8803 Xalpha_i, TRUE, FALSE,
8804 EL_CHAR('I'), -1, -1
8807 Xalpha_j, TRUE, FALSE,
8808 EL_CHAR('J'), -1, -1
8811 Xalpha_k, TRUE, FALSE,
8812 EL_CHAR('K'), -1, -1
8815 Xalpha_l, TRUE, FALSE,
8816 EL_CHAR('L'), -1, -1
8819 Xalpha_m, TRUE, FALSE,
8820 EL_CHAR('M'), -1, -1
8823 Xalpha_n, TRUE, FALSE,
8824 EL_CHAR('N'), -1, -1
8827 Xalpha_o, TRUE, FALSE,
8828 EL_CHAR('O'), -1, -1
8831 Xalpha_p, TRUE, FALSE,
8832 EL_CHAR('P'), -1, -1
8835 Xalpha_q, TRUE, FALSE,
8836 EL_CHAR('Q'), -1, -1
8839 Xalpha_r, TRUE, FALSE,
8840 EL_CHAR('R'), -1, -1
8843 Xalpha_s, TRUE, FALSE,
8844 EL_CHAR('S'), -1, -1
8847 Xalpha_t, TRUE, FALSE,
8848 EL_CHAR('T'), -1, -1
8851 Xalpha_u, TRUE, FALSE,
8852 EL_CHAR('U'), -1, -1
8855 Xalpha_v, TRUE, FALSE,
8856 EL_CHAR('V'), -1, -1
8859 Xalpha_w, TRUE, FALSE,
8860 EL_CHAR('W'), -1, -1
8863 Xalpha_x, TRUE, FALSE,
8864 EL_CHAR('X'), -1, -1
8867 Xalpha_y, TRUE, FALSE,
8868 EL_CHAR('Y'), -1, -1
8871 Xalpha_z, TRUE, FALSE,
8872 EL_CHAR('Z'), -1, -1
8875 Xalpha_arrow_e, TRUE, FALSE,
8876 EL_CHAR('>'), -1, -1
8879 Xalpha_arrow_w, TRUE, FALSE,
8880 EL_CHAR('<'), -1, -1
8883 Xalpha_copyr, TRUE, FALSE,
8884 EL_CHAR('©'), -1, -1
8888 Xboom_bug, FALSE, FALSE,
8889 EL_BUG, ACTION_EXPLODING, -1
8892 Xboom_bomb, FALSE, FALSE,
8893 EL_BOMB, ACTION_EXPLODING, -1
8896 Xboom_android, FALSE, FALSE,
8897 EL_EMC_ANDROID, ACTION_OTHER, -1
8900 Xboom_1, FALSE, FALSE,
8901 EL_DEFAULT, ACTION_EXPLODING, -1
8904 Xboom_2, FALSE, FALSE,
8905 EL_DEFAULT, ACTION_EXPLODING, -1
8908 Znormal, FALSE, FALSE,
8912 Zdynamite, FALSE, FALSE,
8916 Zplayer, FALSE, FALSE,
8920 ZBORDER, FALSE, FALSE,
8930 static struct Mapping_EM_to_RND_player
8939 em_player_mapping_list[] =
8943 EL_PLAYER_1, ACTION_MOVING, MV_BIT_UP,
8947 EL_PLAYER_1, ACTION_MOVING, MV_BIT_RIGHT,
8951 EL_PLAYER_1, ACTION_MOVING, MV_BIT_DOWN,
8955 EL_PLAYER_1, ACTION_MOVING, MV_BIT_LEFT,
8959 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_UP,
8963 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_RIGHT,
8967 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_DOWN,
8971 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_LEFT,
8975 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_UP,
8979 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_RIGHT,
8983 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_DOWN,
8987 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_LEFT,
8991 EL_PLAYER_2, ACTION_MOVING, MV_BIT_UP,
8995 EL_PLAYER_2, ACTION_MOVING, MV_BIT_RIGHT,
8999 EL_PLAYER_2, ACTION_MOVING, MV_BIT_DOWN,
9003 EL_PLAYER_2, ACTION_MOVING, MV_BIT_LEFT,
9007 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_UP,
9011 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_RIGHT,
9015 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_DOWN,
9019 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_LEFT,
9023 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_UP,
9027 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_RIGHT,
9031 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_DOWN,
9035 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_LEFT,
9039 EL_PLAYER_1, ACTION_DEFAULT, -1,
9043 EL_PLAYER_2, ACTION_DEFAULT, -1,
9047 EL_PLAYER_3, ACTION_MOVING, MV_BIT_UP,
9051 EL_PLAYER_3, ACTION_MOVING, MV_BIT_RIGHT,
9055 EL_PLAYER_3, ACTION_MOVING, MV_BIT_DOWN,
9059 EL_PLAYER_3, ACTION_MOVING, MV_BIT_LEFT,
9063 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_UP,
9067 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_RIGHT,
9071 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_DOWN,
9075 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_LEFT,
9079 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_UP,
9083 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_RIGHT,
9087 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_DOWN,
9091 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_LEFT,
9095 EL_PLAYER_4, ACTION_MOVING, MV_BIT_UP,
9099 EL_PLAYER_4, ACTION_MOVING, MV_BIT_RIGHT,
9103 EL_PLAYER_4, ACTION_MOVING, MV_BIT_DOWN,
9107 EL_PLAYER_4, ACTION_MOVING, MV_BIT_LEFT,
9111 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_UP,
9115 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_RIGHT,
9119 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_DOWN,
9123 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_LEFT,
9127 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_UP,
9131 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_RIGHT,
9135 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_DOWN,
9139 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_LEFT,
9143 EL_PLAYER_3, ACTION_DEFAULT, -1,
9147 EL_PLAYER_4, ACTION_DEFAULT, -1,
9156 int map_element_RND_to_EM(int element_rnd)
9158 static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
9159 static boolean mapping_initialized = FALSE;
9161 if (!mapping_initialized)
9165 /* return "Xalpha_quest" for all undefined elements in mapping array */
9166 for (i = 0; i < NUM_FILE_ELEMENTS; i++)
9167 mapping_RND_to_EM[i] = Xalpha_quest;
9169 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
9170 if (em_object_mapping_list[i].is_rnd_to_em_mapping)
9171 mapping_RND_to_EM[em_object_mapping_list[i].element_rnd] =
9172 em_object_mapping_list[i].element_em;
9174 mapping_initialized = TRUE;
9177 if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
9178 return mapping_RND_to_EM[element_rnd];
9180 Error(ERR_WARN, "invalid RND level element %d", element_rnd);
9185 int map_element_EM_to_RND(int element_em)
9187 static unsigned short mapping_EM_to_RND[TILE_MAX];
9188 static boolean mapping_initialized = FALSE;
9190 if (!mapping_initialized)
9194 /* return "EL_UNKNOWN" for all undefined elements in mapping array */
9195 for (i = 0; i < TILE_MAX; i++)
9196 mapping_EM_to_RND[i] = EL_UNKNOWN;
9198 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
9199 mapping_EM_to_RND[em_object_mapping_list[i].element_em] =
9200 em_object_mapping_list[i].element_rnd;
9202 mapping_initialized = TRUE;
9205 if (element_em >= 0 && element_em < TILE_MAX)
9206 return mapping_EM_to_RND[element_em];
9208 Error(ERR_WARN, "invalid EM level element %d", element_em);
9213 void map_android_clone_elements_RND_to_EM(struct LevelInfo *level)
9215 struct LevelInfo_EM *level_em = level->native_em_level;
9216 struct LEVEL *lev = level_em->lev;
9219 for (i = 0; i < TILE_MAX; i++)
9220 lev->android_array[i] = Xblank;
9222 for (i = 0; i < level->num_android_clone_elements; i++)
9224 int element_rnd = level->android_clone_element[i];
9225 int element_em = map_element_RND_to_EM(element_rnd);
9227 for (j = 0; em_object_mapping_list[j].element_em != -1; j++)
9228 if (em_object_mapping_list[j].element_rnd == element_rnd)
9229 lev->android_array[em_object_mapping_list[j].element_em] = element_em;
9233 void map_android_clone_elements_EM_to_RND(struct LevelInfo *level)
9235 struct LevelInfo_EM *level_em = level->native_em_level;
9236 struct LEVEL *lev = level_em->lev;
9239 level->num_android_clone_elements = 0;
9241 for (i = 0; i < TILE_MAX; i++)
9243 int element_em = lev->android_array[i];
9245 boolean element_found = FALSE;
9247 if (element_em == Xblank)
9250 element_rnd = map_element_EM_to_RND(element_em);
9252 for (j = 0; j < level->num_android_clone_elements; j++)
9253 if (level->android_clone_element[j] == element_rnd)
9254 element_found = TRUE;
9258 level->android_clone_element[level->num_android_clone_elements++] =
9261 if (level->num_android_clone_elements == MAX_ANDROID_ELEMENTS)
9266 if (level->num_android_clone_elements == 0)
9268 level->num_android_clone_elements = 1;
9269 level->android_clone_element[0] = EL_EMPTY;
9273 int map_direction_RND_to_EM(int direction)
9275 return (direction == MV_UP ? 0 :
9276 direction == MV_RIGHT ? 1 :
9277 direction == MV_DOWN ? 2 :
9278 direction == MV_LEFT ? 3 :
9282 int map_direction_EM_to_RND(int direction)
9284 return (direction == 0 ? MV_UP :
9285 direction == 1 ? MV_RIGHT :
9286 direction == 2 ? MV_DOWN :
9287 direction == 3 ? MV_LEFT :
9291 int map_element_RND_to_SP(int element_rnd)
9293 int element_sp = 0x20; /* map unknown elements to yellow "hardware" */
9295 if (element_rnd >= EL_SP_START &&
9296 element_rnd <= EL_SP_END)
9297 element_sp = element_rnd - EL_SP_START;
9298 else if (element_rnd == EL_EMPTY_SPACE)
9300 else if (element_rnd == EL_INVISIBLE_WALL)
9306 int map_element_SP_to_RND(int element_sp)
9308 int element_rnd = EL_UNKNOWN;
9310 if (element_sp >= 0x00 &&
9312 element_rnd = EL_SP_START + element_sp;
9313 else if (element_sp == 0x28)
9314 element_rnd = EL_INVISIBLE_WALL;
9319 int map_action_SP_to_RND(int action_sp)
9323 case actActive: return ACTION_ACTIVE;
9324 case actImpact: return ACTION_IMPACT;
9325 case actExploding: return ACTION_EXPLODING;
9326 case actDigging: return ACTION_DIGGING;
9327 case actSnapping: return ACTION_SNAPPING;
9328 case actCollecting: return ACTION_COLLECTING;
9329 case actPassing: return ACTION_PASSING;
9330 case actPushing: return ACTION_PUSHING;
9331 case actDropping: return ACTION_DROPPING;
9333 default: return ACTION_DEFAULT;
9337 int get_next_element(int element)
9341 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
9342 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
9343 case EL_QUICKSAND_FAST_FILLING: return EL_QUICKSAND_FAST_FULL;
9344 case EL_QUICKSAND_FAST_EMPTYING: return EL_QUICKSAND_FAST_EMPTY;
9345 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
9346 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
9347 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
9348 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
9349 case EL_DC_MAGIC_WALL_FILLING: return EL_DC_MAGIC_WALL_FULL;
9350 case EL_DC_MAGIC_WALL_EMPTYING: return EL_DC_MAGIC_WALL_ACTIVE;
9351 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
9353 default: return element;
9358 int el_act_dir2img(int element, int action, int direction)
9360 element = GFX_ELEMENT(element);
9362 if (direction == MV_NONE)
9363 return element_info[element].graphic[action];
9365 direction = MV_DIR_TO_BIT(direction);
9367 return element_info[element].direction_graphic[action][direction];
9370 int el_act_dir2img(int element, int action, int direction)
9372 element = GFX_ELEMENT(element);
9373 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
9375 /* direction_graphic[][] == graphic[] for undefined direction graphics */
9376 return element_info[element].direction_graphic[action][direction];
9381 static int el_act_dir2crm(int element, int action, int direction)
9383 element = GFX_ELEMENT(element);
9385 if (direction == MV_NONE)
9386 return element_info[element].crumbled[action];
9388 direction = MV_DIR_TO_BIT(direction);
9390 return element_info[element].direction_crumbled[action][direction];
9393 static int el_act_dir2crm(int element, int action, int direction)
9395 element = GFX_ELEMENT(element);
9396 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
9398 /* direction_graphic[][] == graphic[] for undefined direction graphics */
9399 return element_info[element].direction_crumbled[action][direction];
9403 int el_act2img(int element, int action)
9405 element = GFX_ELEMENT(element);
9407 return element_info[element].graphic[action];
9410 int el_act2crm(int element, int action)
9412 element = GFX_ELEMENT(element);
9414 return element_info[element].crumbled[action];
9417 int el_dir2img(int element, int direction)
9419 element = GFX_ELEMENT(element);
9421 return el_act_dir2img(element, ACTION_DEFAULT, direction);
9424 int el2baseimg(int element)
9426 return element_info[element].graphic[ACTION_DEFAULT];
9429 int el2img(int element)
9431 element = GFX_ELEMENT(element);
9433 return element_info[element].graphic[ACTION_DEFAULT];
9436 int el2edimg(int element)
9438 element = GFX_ELEMENT(element);
9440 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
9443 int el2preimg(int element)
9445 element = GFX_ELEMENT(element);
9447 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
9450 int el2panelimg(int element)
9452 element = GFX_ELEMENT(element);
9454 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PANEL];
9457 int font2baseimg(int font_nr)
9459 return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
9462 int getBeltNrFromBeltElement(int element)
9464 return (element < EL_CONVEYOR_BELT_2_LEFT ? 0 :
9465 element < EL_CONVEYOR_BELT_3_LEFT ? 1 :
9466 element < EL_CONVEYOR_BELT_4_LEFT ? 2 : 3);
9469 int getBeltNrFromBeltActiveElement(int element)
9471 return (element < EL_CONVEYOR_BELT_2_LEFT_ACTIVE ? 0 :
9472 element < EL_CONVEYOR_BELT_3_LEFT_ACTIVE ? 1 :
9473 element < EL_CONVEYOR_BELT_4_LEFT_ACTIVE ? 2 : 3);
9476 int getBeltNrFromBeltSwitchElement(int element)
9478 return (element < EL_CONVEYOR_BELT_2_SWITCH_LEFT ? 0 :
9479 element < EL_CONVEYOR_BELT_3_SWITCH_LEFT ? 1 :
9480 element < EL_CONVEYOR_BELT_4_SWITCH_LEFT ? 2 : 3);
9483 int getBeltDirNrFromBeltElement(int element)
9485 static int belt_base_element[4] =
9487 EL_CONVEYOR_BELT_1_LEFT,
9488 EL_CONVEYOR_BELT_2_LEFT,
9489 EL_CONVEYOR_BELT_3_LEFT,
9490 EL_CONVEYOR_BELT_4_LEFT
9493 int belt_nr = getBeltNrFromBeltElement(element);
9494 int belt_dir_nr = element - belt_base_element[belt_nr];
9496 return (belt_dir_nr % 3);
9499 int getBeltDirNrFromBeltSwitchElement(int element)
9501 static int belt_base_element[4] =
9503 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
9504 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
9505 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
9506 EL_CONVEYOR_BELT_4_SWITCH_LEFT
9509 int belt_nr = getBeltNrFromBeltSwitchElement(element);
9510 int belt_dir_nr = element - belt_base_element[belt_nr];
9512 return (belt_dir_nr % 3);
9515 int getBeltDirFromBeltElement(int element)
9517 static int belt_move_dir[3] =
9524 int belt_dir_nr = getBeltDirNrFromBeltElement(element);
9526 return belt_move_dir[belt_dir_nr];
9529 int getBeltDirFromBeltSwitchElement(int element)
9531 static int belt_move_dir[3] =
9538 int belt_dir_nr = getBeltDirNrFromBeltSwitchElement(element);
9540 return belt_move_dir[belt_dir_nr];
9543 int getBeltElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
9545 static int belt_base_element[4] =
9547 EL_CONVEYOR_BELT_1_LEFT,
9548 EL_CONVEYOR_BELT_2_LEFT,
9549 EL_CONVEYOR_BELT_3_LEFT,
9550 EL_CONVEYOR_BELT_4_LEFT
9553 return belt_base_element[belt_nr] + belt_dir_nr;
9556 int getBeltElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
9558 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
9560 return getBeltElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
9563 int getBeltSwitchElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
9565 static int belt_base_element[4] =
9567 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
9568 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
9569 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
9570 EL_CONVEYOR_BELT_4_SWITCH_LEFT
9573 return belt_base_element[belt_nr] + belt_dir_nr;
9576 int getBeltSwitchElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
9578 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
9580 return getBeltSwitchElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
9584 boolean getTeamMode_EM()
9586 return game.team_mode;
9589 int getNumActivePlayers_EM()
9592 int num_players = 0;
9596 return (setup.team_mode ? MAX_PLAYERS : 1);
9598 for (i = 0; i < MAX_PLAYERS; i++)
9599 if (tape.player_participates[i])
9602 return (num_players > 1 ? MAX_PLAYERS : 1);
9606 int num_players = 0;
9609 /* when recording game, activate all connected players */
9613 for (i = 0; i < MAX_PLAYERS; i++)
9614 if (tape.player_participates[i])
9622 int getGameFrameDelay_EM(int native_em_game_frame_delay)
9624 int game_frame_delay_value;
9626 game_frame_delay_value =
9627 (tape.playing && tape.fast_forward ? FfwdFrameDelay :
9628 GameFrameDelay == GAME_FRAME_DELAY ? native_em_game_frame_delay :
9631 if (tape.playing && tape.warp_forward && !tape.pausing)
9632 game_frame_delay_value = 0;
9634 return game_frame_delay_value;
9637 unsigned int InitRND(int seed)
9639 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
9640 return InitEngineRandom_EM(seed);
9641 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
9642 return InitEngineRandom_SP(seed);
9644 return InitEngineRandom_RND(seed);
9648 static struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
9649 static struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
9652 inline static int get_effective_element_EM(int tile, int frame_em)
9654 int element = object_mapping[tile].element_rnd;
9655 int action = object_mapping[tile].action;
9656 boolean is_backside = object_mapping[tile].is_backside;
9657 boolean action_removing = (action == ACTION_DIGGING ||
9658 action == ACTION_SNAPPING ||
9659 action == ACTION_COLLECTING);
9665 case Yacid_splash_eB:
9666 case Yacid_splash_wB:
9667 return (frame_em > 5 ? EL_EMPTY : element);
9671 case Ydiamond_stone:
9672 // if (!game.use_native_emc_graphics_engine)
9680 else /* frame_em == 7 */
9684 case Yacid_splash_eB:
9685 case Yacid_splash_wB:
9688 case Yemerald_stone:
9691 case Ydiamond_stone:
9695 case Xdrip_stretchB:
9714 case Xsand_stonein_1:
9715 case Xsand_stonein_2:
9716 case Xsand_stonein_3:
9717 case Xsand_stonein_4:
9721 return (is_backside || action_removing ? EL_EMPTY : element);
9726 inline static boolean check_linear_animation_EM(int tile)
9730 case Xsand_stonesand_1:
9731 case Xsand_stonesand_quickout_1:
9732 case Xsand_sandstone_1:
9733 case Xsand_stonein_1:
9734 case Xsand_stoneout_1:
9754 case Yacid_splash_eB:
9755 case Yacid_splash_wB:
9756 case Yemerald_stone:
9764 inline static void set_crumbled_graphics_EM(struct GraphicInfo_EM *g_em,
9765 boolean has_crumbled_graphics,
9766 int crumbled, int sync_frame)
9768 /* if element can be crumbled, but certain action graphics are just empty
9769 space (like instantly snapping sand to empty space in 1 frame), do not
9770 treat these empty space graphics as crumbled graphics in EMC engine */
9771 if (crumbled == IMG_EMPTY_SPACE)
9772 has_crumbled_graphics = FALSE;
9774 if (has_crumbled_graphics)
9776 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
9777 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
9778 g_crumbled->anim_delay,
9779 g_crumbled->anim_mode,
9780 g_crumbled->anim_start_frame,
9783 getGraphicSource(crumbled, frame_crumbled, &g_em->crumbled_bitmap,
9784 &g_em->crumbled_src_x, &g_em->crumbled_src_y);
9786 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
9788 g_em->has_crumbled_graphics = TRUE;
9792 g_em->crumbled_bitmap = NULL;
9793 g_em->crumbled_src_x = 0;
9794 g_em->crumbled_src_y = 0;
9795 g_em->crumbled_border_size = 0;
9797 g_em->has_crumbled_graphics = FALSE;
9801 void ResetGfxAnimation_EM(int x, int y, int tile)
9806 void SetGfxAnimation_EM(struct GraphicInfo_EM *g_em,
9807 int tile, int frame_em, int x, int y)
9809 int action = object_mapping[tile].action;
9811 int direction = object_mapping[tile].direction;
9812 int effective_element = get_effective_element_EM(tile, frame_em);
9813 int graphic = (direction == MV_NONE ?
9814 el_act2img(effective_element, action) :
9815 el_act_dir2img(effective_element, action, direction));
9816 struct GraphicInfo *g = &graphic_info[graphic];
9819 boolean action_removing = (action == ACTION_DIGGING ||
9820 action == ACTION_SNAPPING ||
9821 action == ACTION_COLLECTING);
9822 boolean action_moving = (action == ACTION_FALLING ||
9823 action == ACTION_MOVING ||
9824 action == ACTION_PUSHING ||
9825 action == ACTION_EATING ||
9826 action == ACTION_FILLING ||
9827 action == ACTION_EMPTYING);
9828 boolean action_falling = (action == ACTION_FALLING ||
9829 action == ACTION_FILLING ||
9830 action == ACTION_EMPTYING);
9832 /* special case: graphic uses "2nd movement tile" and has defined
9833 7 frames for movement animation (or less) => use default graphic
9834 for last (8th) frame which ends the movement animation */
9835 if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
9837 action = ACTION_DEFAULT; /* (keep action_* unchanged for now) */
9838 graphic = (direction == MV_NONE ?
9839 el_act2img(effective_element, action) :
9840 el_act_dir2img(effective_element, action, direction));
9842 g = &graphic_info[graphic];
9846 if (tile == Xsand_stonesand_1 ||
9847 tile == Xsand_stonesand_2 ||
9848 tile == Xsand_stonesand_3 ||
9849 tile == Xsand_stonesand_4)
9850 printf("::: 1: quicksand frame %d [%d]\n", GfxFrame[x][y], tile);
9854 if ((action_removing || check_linear_animation_EM(tile)) && frame_em == 0)
9858 // printf("::: resetting... [%d]\n", tile);
9861 if (action_removing || check_linear_animation_EM(tile))
9863 GfxFrame[x][y] = frame_em;
9865 // printf("::: resetting... [%d]\n", tile);
9868 else if (action_moving)
9870 boolean is_backside = object_mapping[tile].is_backside;
9874 int direction = object_mapping[tile].direction;
9875 int move_dir = (action_falling ? MV_DOWN : direction);
9880 /* !!! TEST !!! NEW !!! DOES NOT WORK RIGHT YET !!! */
9881 if (g->double_movement && frame_em == 0)
9885 // printf("::: resetting... [%d]\n", tile);
9889 if (move_dir == MV_LEFT)
9890 GfxFrame[x - 1][y] = GfxFrame[x][y];
9891 else if (move_dir == MV_RIGHT)
9892 GfxFrame[x + 1][y] = GfxFrame[x][y];
9893 else if (move_dir == MV_UP)
9894 GfxFrame[x][y - 1] = GfxFrame[x][y];
9895 else if (move_dir == MV_DOWN)
9896 GfxFrame[x][y + 1] = GfxFrame[x][y];
9903 /* special case: animation for Xsand_stonesand_quickout_1/2 twice as fast */
9904 if (tile == Xsand_stonesand_quickout_1 ||
9905 tile == Xsand_stonesand_quickout_2)
9910 if (tile == Xsand_stonesand_1 ||
9911 tile == Xsand_stonesand_2 ||
9912 tile == Xsand_stonesand_3 ||
9913 tile == Xsand_stonesand_4)
9914 printf("::: 2: quicksand frame %d [%d]\n", GfxFrame[x][y], tile);
9918 if (graphic_info[graphic].anim_global_sync)
9919 sync_frame = FrameCounter;
9920 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
9921 sync_frame = GfxFrame[x][y];
9923 sync_frame = 0; /* playfield border (pseudo steel) */
9925 SetRandomAnimationValue(x, y);
9927 int frame = getAnimationFrame(g->anim_frames,
9930 g->anim_start_frame,
9933 g_em->unique_identifier =
9934 (graphic << 16) | ((frame % 8) << 12) | (g_em->width << 6) | g_em->height;
9938 void getGraphicSourceObjectExt_EM(struct GraphicInfo_EM *g_em,
9939 int tile, int frame_em, int x, int y)
9941 int action = object_mapping[tile].action;
9942 int direction = object_mapping[tile].direction;
9943 boolean is_backside = object_mapping[tile].is_backside;
9944 int effective_element = get_effective_element_EM(tile, frame_em);
9946 int effective_action = action;
9948 int effective_action = (frame_em < 7 ? action : ACTION_DEFAULT);
9950 int graphic = (direction == MV_NONE ?
9951 el_act2img(effective_element, effective_action) :
9952 el_act_dir2img(effective_element, effective_action,
9954 int crumbled = (direction == MV_NONE ?
9955 el_act2crm(effective_element, effective_action) :
9956 el_act_dir2crm(effective_element, effective_action,
9958 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
9959 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
9960 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
9961 struct GraphicInfo *g = &graphic_info[graphic];
9963 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
9967 /* special case: graphic uses "2nd movement tile" and has defined
9968 7 frames for movement animation (or less) => use default graphic
9969 for last (8th) frame which ends the movement animation */
9970 if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
9972 effective_action = ACTION_DEFAULT;
9973 graphic = (direction == MV_NONE ?
9974 el_act2img(effective_element, effective_action) :
9975 el_act_dir2img(effective_element, effective_action,
9977 crumbled = (direction == MV_NONE ?
9978 el_act2crm(effective_element, effective_action) :
9979 el_act_dir2crm(effective_element, effective_action,
9982 g = &graphic_info[graphic];
9992 if (frame_em == 0) /* reset animation frame for certain elements */
9994 if (check_linear_animation_EM(tile))
9999 if (graphic_info[graphic].anim_global_sync)
10000 sync_frame = FrameCounter;
10001 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
10002 sync_frame = GfxFrame[x][y];
10004 sync_frame = 0; /* playfield border (pseudo steel) */
10006 SetRandomAnimationValue(x, y);
10011 int xxx_sync_frame = (i == Xdrip_stretch ? 7 :
10012 i == Xdrip_stretchB ? 7 :
10013 i == Ydrip_s2 ? j + 8 :
10014 i == Ydrip_s2B ? j + 8 :
10016 i == Xacid_2 ? 10 :
10017 i == Xacid_3 ? 20 :
10018 i == Xacid_4 ? 30 :
10019 i == Xacid_5 ? 40 :
10020 i == Xacid_6 ? 50 :
10021 i == Xacid_7 ? 60 :
10022 i == Xacid_8 ? 70 :
10023 i == Xfake_acid_1 ? 0 :
10024 i == Xfake_acid_2 ? 10 :
10025 i == Xfake_acid_3 ? 20 :
10026 i == Xfake_acid_4 ? 30 :
10027 i == Xfake_acid_5 ? 40 :
10028 i == Xfake_acid_6 ? 50 :
10029 i == Xfake_acid_7 ? 60 :
10030 i == Xfake_acid_8 ? 70 :
10032 i == Xball_2B ? j + 8 :
10033 i == Yball_eat ? j + 1 :
10034 i == Ykey_1_eat ? j + 1 :
10035 i == Ykey_2_eat ? j + 1 :
10036 i == Ykey_3_eat ? j + 1 :
10037 i == Ykey_4_eat ? j + 1 :
10038 i == Ykey_5_eat ? j + 1 :
10039 i == Ykey_6_eat ? j + 1 :
10040 i == Ykey_7_eat ? j + 1 :
10041 i == Ykey_8_eat ? j + 1 :
10042 i == Ylenses_eat ? j + 1 :
10043 i == Ymagnify_eat ? j + 1 :
10044 i == Ygrass_eat ? j + 1 :
10045 i == Ydirt_eat ? j + 1 :
10046 i == Xamoeba_1 ? 0 :
10047 i == Xamoeba_2 ? 1 :
10048 i == Xamoeba_3 ? 2 :
10049 i == Xamoeba_4 ? 3 :
10050 i == Xamoeba_5 ? 0 :
10051 i == Xamoeba_6 ? 1 :
10052 i == Xamoeba_7 ? 2 :
10053 i == Xamoeba_8 ? 3 :
10054 i == Xexit_2 ? j + 8 :
10055 i == Xexit_3 ? j + 16 :
10056 i == Xdynamite_1 ? 0 :
10057 i == Xdynamite_2 ? 8 :
10058 i == Xdynamite_3 ? 16 :
10059 i == Xdynamite_4 ? 24 :
10060 i == Xsand_stonein_1 ? j + 1 :
10061 i == Xsand_stonein_2 ? j + 9 :
10062 i == Xsand_stonein_3 ? j + 17 :
10063 i == Xsand_stonein_4 ? j + 25 :
10064 i == Xsand_stoneout_1 && j == 0 ? 0 :
10065 i == Xsand_stoneout_1 && j == 1 ? 0 :
10066 i == Xsand_stoneout_1 && j == 2 ? 1 :
10067 i == Xsand_stoneout_1 && j == 3 ? 2 :
10068 i == Xsand_stoneout_1 && j == 4 ? 2 :
10069 i == Xsand_stoneout_1 && j == 5 ? 3 :
10070 i == Xsand_stoneout_1 && j == 6 ? 4 :
10071 i == Xsand_stoneout_1 && j == 7 ? 4 :
10072 i == Xsand_stoneout_2 && j == 0 ? 5 :
10073 i == Xsand_stoneout_2 && j == 1 ? 6 :
10074 i == Xsand_stoneout_2 && j == 2 ? 7 :
10075 i == Xsand_stoneout_2 && j == 3 ? 8 :
10076 i == Xsand_stoneout_2 && j == 4 ? 9 :
10077 i == Xsand_stoneout_2 && j == 5 ? 11 :
10078 i == Xsand_stoneout_2 && j == 6 ? 13 :
10079 i == Xsand_stoneout_2 && j == 7 ? 15 :
10080 i == Xboom_bug && j == 1 ? 2 :
10081 i == Xboom_bug && j == 2 ? 2 :
10082 i == Xboom_bug && j == 3 ? 4 :
10083 i == Xboom_bug && j == 4 ? 4 :
10084 i == Xboom_bug && j == 5 ? 2 :
10085 i == Xboom_bug && j == 6 ? 2 :
10086 i == Xboom_bug && j == 7 ? 0 :
10087 i == Xboom_bomb && j == 1 ? 2 :
10088 i == Xboom_bomb && j == 2 ? 2 :
10089 i == Xboom_bomb && j == 3 ? 4 :
10090 i == Xboom_bomb && j == 4 ? 4 :
10091 i == Xboom_bomb && j == 5 ? 2 :
10092 i == Xboom_bomb && j == 6 ? 2 :
10093 i == Xboom_bomb && j == 7 ? 0 :
10094 i == Xboom_android && j == 7 ? 6 :
10095 i == Xboom_1 && j == 1 ? 2 :
10096 i == Xboom_1 && j == 2 ? 2 :
10097 i == Xboom_1 && j == 3 ? 4 :
10098 i == Xboom_1 && j == 4 ? 4 :
10099 i == Xboom_1 && j == 5 ? 6 :
10100 i == Xboom_1 && j == 6 ? 6 :
10101 i == Xboom_1 && j == 7 ? 8 :
10102 i == Xboom_2 && j == 0 ? 8 :
10103 i == Xboom_2 && j == 1 ? 8 :
10104 i == Xboom_2 && j == 2 ? 10 :
10105 i == Xboom_2 && j == 3 ? 10 :
10106 i == Xboom_2 && j == 4 ? 10 :
10107 i == Xboom_2 && j == 5 ? 12 :
10108 i == Xboom_2 && j == 6 ? 12 :
10109 i == Xboom_2 && j == 7 ? 12 :
10111 special_animation && j == 4 ? 3 :
10112 effective_action != action ? 0 :
10118 int xxx_effective_action;
10119 int xxx_has_action_graphics;
10122 int element = object_mapping[i].element_rnd;
10123 int action = object_mapping[i].action;
10124 int direction = object_mapping[i].direction;
10125 boolean is_backside = object_mapping[i].is_backside;
10127 boolean action_removing = (action == ACTION_DIGGING ||
10128 action == ACTION_SNAPPING ||
10129 action == ACTION_COLLECTING);
10131 boolean action_exploding = ((action == ACTION_EXPLODING ||
10132 action == ACTION_SMASHED_BY_ROCK ||
10133 action == ACTION_SMASHED_BY_SPRING) &&
10134 element != EL_DIAMOND);
10135 boolean action_active = (action == ACTION_ACTIVE);
10136 boolean action_other = (action == ACTION_OTHER);
10140 int effective_element = get_effective_element_EM(i, j);
10142 int effective_element = (j > 5 && i == Yacid_splash_eB ? EL_EMPTY :
10143 j > 5 && i == Yacid_splash_wB ? EL_EMPTY :
10145 i == Xdrip_stretch ? element :
10146 i == Xdrip_stretchB ? element :
10147 i == Ydrip_s1 ? element :
10148 i == Ydrip_s1B ? element :
10149 i == Xball_1B ? element :
10150 i == Xball_2 ? element :
10151 i == Xball_2B ? element :
10152 i == Yball_eat ? element :
10153 i == Ykey_1_eat ? element :
10154 i == Ykey_2_eat ? element :
10155 i == Ykey_3_eat ? element :
10156 i == Ykey_4_eat ? element :
10157 i == Ykey_5_eat ? element :
10158 i == Ykey_6_eat ? element :
10159 i == Ykey_7_eat ? element :
10160 i == Ykey_8_eat ? element :
10161 i == Ylenses_eat ? element :
10162 i == Ymagnify_eat ? element :
10163 i == Ygrass_eat ? element :
10164 i == Ydirt_eat ? element :
10165 i == Yemerald_stone ? EL_EMERALD :
10166 i == Ydiamond_stone ? EL_ROCK :
10167 i == Xsand_stonein_1 ? element :
10168 i == Xsand_stonein_2 ? element :
10169 i == Xsand_stonein_3 ? element :
10170 i == Xsand_stonein_4 ? element :
10171 is_backside ? EL_EMPTY :
10172 action_removing ? EL_EMPTY :
10175 int effective_action = (j < 7 ? action :
10176 i == Xdrip_stretch ? action :
10177 i == Xdrip_stretchB ? action :
10178 i == Ydrip_s1 ? action :
10179 i == Ydrip_s1B ? action :
10180 i == Xball_1B ? action :
10181 i == Xball_2 ? action :
10182 i == Xball_2B ? action :
10183 i == Yball_eat ? action :
10184 i == Ykey_1_eat ? action :
10185 i == Ykey_2_eat ? action :
10186 i == Ykey_3_eat ? action :
10187 i == Ykey_4_eat ? action :
10188 i == Ykey_5_eat ? action :
10189 i == Ykey_6_eat ? action :
10190 i == Ykey_7_eat ? action :
10191 i == Ykey_8_eat ? action :
10192 i == Ylenses_eat ? action :
10193 i == Ymagnify_eat ? action :
10194 i == Ygrass_eat ? action :
10195 i == Ydirt_eat ? action :
10196 i == Xsand_stonein_1 ? action :
10197 i == Xsand_stonein_2 ? action :
10198 i == Xsand_stonein_3 ? action :
10199 i == Xsand_stonein_4 ? action :
10200 i == Xsand_stoneout_1 ? action :
10201 i == Xsand_stoneout_2 ? action :
10202 i == Xboom_android ? ACTION_EXPLODING :
10203 action_exploding ? ACTION_EXPLODING :
10204 action_active ? action :
10205 action_other ? action :
10207 int graphic = (el_act_dir2img(effective_element, effective_action,
10209 int crumbled = (el_act_dir2crm(effective_element, effective_action,
10211 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
10212 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
10213 boolean has_action_graphics = (graphic != base_graphic);
10214 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
10215 struct GraphicInfo *g = &graphic_info[graphic];
10217 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
10219 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
10220 Bitmap *src_bitmap;
10222 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
10223 boolean special_animation = (action != ACTION_DEFAULT &&
10224 g->anim_frames == 3 &&
10225 g->anim_delay == 2 &&
10226 g->anim_mode & ANIM_LINEAR);
10227 xxx_sync_frame = (i == Xdrip_stretch ? 7 :
10228 i == Xdrip_stretchB ? 7 :
10229 i == Ydrip_s2 ? j + 8 :
10230 i == Ydrip_s2B ? j + 8 :
10232 i == Xacid_2 ? 10 :
10233 i == Xacid_3 ? 20 :
10234 i == Xacid_4 ? 30 :
10235 i == Xacid_5 ? 40 :
10236 i == Xacid_6 ? 50 :
10237 i == Xacid_7 ? 60 :
10238 i == Xacid_8 ? 70 :
10239 i == Xfake_acid_1 ? 0 :
10240 i == Xfake_acid_2 ? 10 :
10241 i == Xfake_acid_3 ? 20 :
10242 i == Xfake_acid_4 ? 30 :
10243 i == Xfake_acid_5 ? 40 :
10244 i == Xfake_acid_6 ? 50 :
10245 i == Xfake_acid_7 ? 60 :
10246 i == Xfake_acid_8 ? 70 :
10248 i == Xball_2B ? j + 8 :
10249 i == Yball_eat ? j + 1 :
10250 i == Ykey_1_eat ? j + 1 :
10251 i == Ykey_2_eat ? j + 1 :
10252 i == Ykey_3_eat ? j + 1 :
10253 i == Ykey_4_eat ? j + 1 :
10254 i == Ykey_5_eat ? j + 1 :
10255 i == Ykey_6_eat ? j + 1 :
10256 i == Ykey_7_eat ? j + 1 :
10257 i == Ykey_8_eat ? j + 1 :
10258 i == Ylenses_eat ? j + 1 :
10259 i == Ymagnify_eat ? j + 1 :
10260 i == Ygrass_eat ? j + 1 :
10261 i == Ydirt_eat ? j + 1 :
10262 i == Xamoeba_1 ? 0 :
10263 i == Xamoeba_2 ? 1 :
10264 i == Xamoeba_3 ? 2 :
10265 i == Xamoeba_4 ? 3 :
10266 i == Xamoeba_5 ? 0 :
10267 i == Xamoeba_6 ? 1 :
10268 i == Xamoeba_7 ? 2 :
10269 i == Xamoeba_8 ? 3 :
10270 i == Xexit_2 ? j + 8 :
10271 i == Xexit_3 ? j + 16 :
10272 i == Xdynamite_1 ? 0 :
10273 i == Xdynamite_2 ? 8 :
10274 i == Xdynamite_3 ? 16 :
10275 i == Xdynamite_4 ? 24 :
10276 i == Xsand_stonein_1 ? j + 1 :
10277 i == Xsand_stonein_2 ? j + 9 :
10278 i == Xsand_stonein_3 ? j + 17 :
10279 i == Xsand_stonein_4 ? j + 25 :
10280 i == Xsand_stoneout_1 && j == 0 ? 0 :
10281 i == Xsand_stoneout_1 && j == 1 ? 0 :
10282 i == Xsand_stoneout_1 && j == 2 ? 1 :
10283 i == Xsand_stoneout_1 && j == 3 ? 2 :
10284 i == Xsand_stoneout_1 && j == 4 ? 2 :
10285 i == Xsand_stoneout_1 && j == 5 ? 3 :
10286 i == Xsand_stoneout_1 && j == 6 ? 4 :
10287 i == Xsand_stoneout_1 && j == 7 ? 4 :
10288 i == Xsand_stoneout_2 && j == 0 ? 5 :
10289 i == Xsand_stoneout_2 && j == 1 ? 6 :
10290 i == Xsand_stoneout_2 && j == 2 ? 7 :
10291 i == Xsand_stoneout_2 && j == 3 ? 8 :
10292 i == Xsand_stoneout_2 && j == 4 ? 9 :
10293 i == Xsand_stoneout_2 && j == 5 ? 11 :
10294 i == Xsand_stoneout_2 && j == 6 ? 13 :
10295 i == Xsand_stoneout_2 && j == 7 ? 15 :
10296 i == Xboom_bug && j == 1 ? 2 :
10297 i == Xboom_bug && j == 2 ? 2 :
10298 i == Xboom_bug && j == 3 ? 4 :
10299 i == Xboom_bug && j == 4 ? 4 :
10300 i == Xboom_bug && j == 5 ? 2 :
10301 i == Xboom_bug && j == 6 ? 2 :
10302 i == Xboom_bug && j == 7 ? 0 :
10303 i == Xboom_bomb && j == 1 ? 2 :
10304 i == Xboom_bomb && j == 2 ? 2 :
10305 i == Xboom_bomb && j == 3 ? 4 :
10306 i == Xboom_bomb && j == 4 ? 4 :
10307 i == Xboom_bomb && j == 5 ? 2 :
10308 i == Xboom_bomb && j == 6 ? 2 :
10309 i == Xboom_bomb && j == 7 ? 0 :
10310 i == Xboom_android && j == 7 ? 6 :
10311 i == Xboom_1 && j == 1 ? 2 :
10312 i == Xboom_1 && j == 2 ? 2 :
10313 i == Xboom_1 && j == 3 ? 4 :
10314 i == Xboom_1 && j == 4 ? 4 :
10315 i == Xboom_1 && j == 5 ? 6 :
10316 i == Xboom_1 && j == 6 ? 6 :
10317 i == Xboom_1 && j == 7 ? 8 :
10318 i == Xboom_2 && j == 0 ? 8 :
10319 i == Xboom_2 && j == 1 ? 8 :
10320 i == Xboom_2 && j == 2 ? 10 :
10321 i == Xboom_2 && j == 3 ? 10 :
10322 i == Xboom_2 && j == 4 ? 10 :
10323 i == Xboom_2 && j == 5 ? 12 :
10324 i == Xboom_2 && j == 6 ? 12 :
10325 i == Xboom_2 && j == 7 ? 12 :
10326 special_animation && j == 4 ? 3 :
10327 effective_action != action ? 0 :
10330 xxx_effective_action = effective_action;
10331 xxx_has_action_graphics = has_action_graphics;
10336 int frame = getAnimationFrame(g->anim_frames,
10339 g->anim_start_frame,
10353 int old_src_x = g_em->src_x;
10354 int old_src_y = g_em->src_y;
10358 getGraphicSourceExt(graphic, frame, &g_em->bitmap, &g_em->src_x, &g_em->src_y,
10359 g->double_movement && is_backside);
10361 getGraphicSourceExt(graphic, frame, &g_em->bitmap,
10362 &g_em->src_x, &g_em->src_y, FALSE);
10367 if (tile == Ydiamond_stone)
10368 printf("::: stone smashing diamond... %d: %d, %d, %d, %d, %d -> %d [%d, %d, %d, %d, %d, %d] [%d]\n",
10373 g->anim_start_frame,
10376 g_em->src_x, g_em->src_y,
10377 g_em->src_offset_x, g_em->src_offset_y,
10378 g_em->dst_offset_x, g_em->dst_offset_y,
10390 if (graphic == IMG_BUG_MOVING_RIGHT)
10391 printf("::: %d, %d, %d: %d, %d [%d, %d -> %d, %d]\n", graphic, x, y,
10392 g->double_movement, is_backside,
10393 old_src_x, old_src_y, g_em->src_x, g_em->src_y);
10401 g_em->src_offset_x = 0;
10402 g_em->src_offset_y = 0;
10403 g_em->dst_offset_x = 0;
10404 g_em->dst_offset_y = 0;
10405 g_em->width = TILEX;
10406 g_em->height = TILEY;
10408 g_em->preserve_background = FALSE;
10411 /* (updating the "crumbled" graphic definitions is probably not really needed,
10412 as animations for crumbled graphics can't be longer than one EMC cycle) */
10414 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
10419 g_em->crumbled_bitmap = NULL;
10420 g_em->crumbled_src_x = 0;
10421 g_em->crumbled_src_y = 0;
10423 g_em->has_crumbled_graphics = FALSE;
10425 if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
10427 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
10428 g_crumbled->anim_delay,
10429 g_crumbled->anim_mode,
10430 g_crumbled->anim_start_frame,
10433 getGraphicSource(crumbled, frame_crumbled, &g_em->crumbled_bitmap,
10434 &g_em->crumbled_src_x, &g_em->crumbled_src_y);
10436 g_em->has_crumbled_graphics = TRUE;
10442 int effective_action = xxx_effective_action;
10443 int has_action_graphics = xxx_has_action_graphics;
10445 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
10446 effective_action == ACTION_MOVING ||
10447 effective_action == ACTION_PUSHING ||
10448 effective_action == ACTION_EATING)) ||
10449 (!has_action_graphics && (effective_action == ACTION_FILLING ||
10450 effective_action == ACTION_EMPTYING)))
10453 (effective_action == ACTION_FALLING ||
10454 effective_action == ACTION_FILLING ||
10455 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
10456 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
10457 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
10458 int num_steps = (i == Ydrip_s1 ? 16 :
10459 i == Ydrip_s1B ? 16 :
10460 i == Ydrip_s2 ? 16 :
10461 i == Ydrip_s2B ? 16 :
10462 i == Xsand_stonein_1 ? 32 :
10463 i == Xsand_stonein_2 ? 32 :
10464 i == Xsand_stonein_3 ? 32 :
10465 i == Xsand_stonein_4 ? 32 :
10466 i == Xsand_stoneout_1 ? 16 :
10467 i == Xsand_stoneout_2 ? 16 : 8);
10468 int cx = ABS(dx) * (TILEX / num_steps);
10469 int cy = ABS(dy) * (TILEY / num_steps);
10470 int step_frame = (i == Ydrip_s2 ? j + 8 :
10471 i == Ydrip_s2B ? j + 8 :
10472 i == Xsand_stonein_2 ? j + 8 :
10473 i == Xsand_stonein_3 ? j + 16 :
10474 i == Xsand_stonein_4 ? j + 24 :
10475 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
10476 int step = (is_backside ? step_frame : num_steps - step_frame);
10478 if (is_backside) /* tile where movement starts */
10480 if (dx < 0 || dy < 0)
10482 g_em->src_offset_x = cx * step;
10483 g_em->src_offset_y = cy * step;
10487 g_em->dst_offset_x = cx * step;
10488 g_em->dst_offset_y = cy * step;
10491 else /* tile where movement ends */
10493 if (dx < 0 || dy < 0)
10495 g_em->dst_offset_x = cx * step;
10496 g_em->dst_offset_y = cy * step;
10500 g_em->src_offset_x = cx * step;
10501 g_em->src_offset_y = cy * step;
10505 g_em->width = TILEX - cx * step;
10506 g_em->height = TILEY - cy * step;
10509 /* create unique graphic identifier to decide if tile must be redrawn */
10510 /* bit 31 - 16 (16 bit): EM style graphic
10511 bit 15 - 12 ( 4 bit): EM style frame
10512 bit 11 - 6 ( 6 bit): graphic width
10513 bit 5 - 0 ( 6 bit): graphic height */
10514 g_em->unique_identifier =
10515 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
10521 void getGraphicSourcePlayerExt_EM(struct GraphicInfo_EM *g_em,
10522 int player_nr, int anim, int frame_em)
10524 int element = player_mapping[player_nr][anim].element_rnd;
10525 int action = player_mapping[player_nr][anim].action;
10526 int direction = player_mapping[player_nr][anim].direction;
10527 int graphic = (direction == MV_NONE ?
10528 el_act2img(element, action) :
10529 el_act_dir2img(element, action, direction));
10530 struct GraphicInfo *g = &graphic_info[graphic];
10533 InitPlayerGfxAnimation(&stored_player[player_nr], action, direction);
10535 stored_player[player_nr].StepFrame = frame_em;
10537 sync_frame = stored_player[player_nr].Frame;
10539 int frame = getAnimationFrame(g->anim_frames,
10542 g->anim_start_frame,
10545 getGraphicSourceExt(graphic, frame, &g_em->bitmap,
10546 &g_em->src_x, &g_em->src_y, FALSE);
10549 printf("::: %d: %d, %d [%d]\n",
10551 stored_player[player_nr].Frame,
10552 stored_player[player_nr].StepFrame,
10557 void InitGraphicInfo_EM(void)
10560 struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
10561 struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
10566 int num_em_gfx_errors = 0;
10568 if (graphic_info_em_object[0][0].bitmap == NULL)
10570 /* EM graphics not yet initialized in em_open_all() */
10575 printf("::: [4 errors can be ignored (1 x 'bomb', 3 x 'em_dynamite']\n");
10578 /* always start with reliable default values */
10579 for (i = 0; i < TILE_MAX; i++)
10581 object_mapping[i].element_rnd = EL_UNKNOWN;
10582 object_mapping[i].is_backside = FALSE;
10583 object_mapping[i].action = ACTION_DEFAULT;
10584 object_mapping[i].direction = MV_NONE;
10587 /* always start with reliable default values */
10588 for (p = 0; p < MAX_PLAYERS; p++)
10590 for (i = 0; i < SPR_MAX; i++)
10592 player_mapping[p][i].element_rnd = EL_UNKNOWN;
10593 player_mapping[p][i].action = ACTION_DEFAULT;
10594 player_mapping[p][i].direction = MV_NONE;
10598 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
10600 int e = em_object_mapping_list[i].element_em;
10602 object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd;
10603 object_mapping[e].is_backside = em_object_mapping_list[i].is_backside;
10605 if (em_object_mapping_list[i].action != -1)
10606 object_mapping[e].action = em_object_mapping_list[i].action;
10608 if (em_object_mapping_list[i].direction != -1)
10609 object_mapping[e].direction =
10610 MV_DIR_FROM_BIT(em_object_mapping_list[i].direction);
10613 for (i = 0; em_player_mapping_list[i].action_em != -1; i++)
10615 int a = em_player_mapping_list[i].action_em;
10616 int p = em_player_mapping_list[i].player_nr;
10618 player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd;
10620 if (em_player_mapping_list[i].action != -1)
10621 player_mapping[p][a].action = em_player_mapping_list[i].action;
10623 if (em_player_mapping_list[i].direction != -1)
10624 player_mapping[p][a].direction =
10625 MV_DIR_FROM_BIT(em_player_mapping_list[i].direction);
10628 for (i = 0; i < TILE_MAX; i++)
10630 int element = object_mapping[i].element_rnd;
10631 int action = object_mapping[i].action;
10632 int direction = object_mapping[i].direction;
10633 boolean is_backside = object_mapping[i].is_backside;
10635 boolean action_removing = (action == ACTION_DIGGING ||
10636 action == ACTION_SNAPPING ||
10637 action == ACTION_COLLECTING);
10639 boolean action_exploding = ((action == ACTION_EXPLODING ||
10640 action == ACTION_SMASHED_BY_ROCK ||
10641 action == ACTION_SMASHED_BY_SPRING) &&
10642 element != EL_DIAMOND);
10643 boolean action_active = (action == ACTION_ACTIVE);
10644 boolean action_other = (action == ACTION_OTHER);
10646 for (j = 0; j < 8; j++)
10649 int effective_element = get_effective_element_EM(i, j);
10651 int effective_element = (j > 5 && i == Yacid_splash_eB ? EL_EMPTY :
10652 j > 5 && i == Yacid_splash_wB ? EL_EMPTY :
10654 i == Xdrip_stretch ? element :
10655 i == Xdrip_stretchB ? element :
10656 i == Ydrip_s1 ? element :
10657 i == Ydrip_s1B ? element :
10658 i == Xball_1B ? element :
10659 i == Xball_2 ? element :
10660 i == Xball_2B ? element :
10661 i == Yball_eat ? element :
10662 i == Ykey_1_eat ? element :
10663 i == Ykey_2_eat ? element :
10664 i == Ykey_3_eat ? element :
10665 i == Ykey_4_eat ? element :
10666 i == Ykey_5_eat ? element :
10667 i == Ykey_6_eat ? element :
10668 i == Ykey_7_eat ? element :
10669 i == Ykey_8_eat ? element :
10670 i == Ylenses_eat ? element :
10671 i == Ymagnify_eat ? element :
10672 i == Ygrass_eat ? element :
10673 i == Ydirt_eat ? element :
10674 i == Yemerald_stone ? EL_EMERALD :
10675 i == Ydiamond_stone ? EL_ROCK :
10676 i == Xsand_stonein_1 ? element :
10677 i == Xsand_stonein_2 ? element :
10678 i == Xsand_stonein_3 ? element :
10679 i == Xsand_stonein_4 ? element :
10680 is_backside ? EL_EMPTY :
10681 action_removing ? EL_EMPTY :
10684 int effective_action = (j < 7 ? action :
10685 i == Xdrip_stretch ? action :
10686 i == Xdrip_stretchB ? action :
10687 i == Ydrip_s1 ? action :
10688 i == Ydrip_s1B ? action :
10689 i == Xball_1B ? action :
10690 i == Xball_2 ? action :
10691 i == Xball_2B ? action :
10692 i == Yball_eat ? action :
10693 i == Ykey_1_eat ? action :
10694 i == Ykey_2_eat ? action :
10695 i == Ykey_3_eat ? action :
10696 i == Ykey_4_eat ? action :
10697 i == Ykey_5_eat ? action :
10698 i == Ykey_6_eat ? action :
10699 i == Ykey_7_eat ? action :
10700 i == Ykey_8_eat ? action :
10701 i == Ylenses_eat ? action :
10702 i == Ymagnify_eat ? action :
10703 i == Ygrass_eat ? action :
10704 i == Ydirt_eat ? action :
10705 i == Xsand_stonein_1 ? action :
10706 i == Xsand_stonein_2 ? action :
10707 i == Xsand_stonein_3 ? action :
10708 i == Xsand_stonein_4 ? action :
10709 i == Xsand_stoneout_1 ? action :
10710 i == Xsand_stoneout_2 ? action :
10711 i == Xboom_android ? ACTION_EXPLODING :
10712 action_exploding ? ACTION_EXPLODING :
10713 action_active ? action :
10714 action_other ? action :
10716 int graphic = (el_act_dir2img(effective_element, effective_action,
10718 int crumbled = (el_act_dir2crm(effective_element, effective_action,
10720 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
10721 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
10722 boolean has_action_graphics = (graphic != base_graphic);
10723 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
10724 struct GraphicInfo *g = &graphic_info[graphic];
10726 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
10728 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
10729 Bitmap *src_bitmap;
10731 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
10732 boolean special_animation = (action != ACTION_DEFAULT &&
10733 g->anim_frames == 3 &&
10734 g->anim_delay == 2 &&
10735 g->anim_mode & ANIM_LINEAR);
10736 int sync_frame = (i == Xdrip_stretch ? 7 :
10737 i == Xdrip_stretchB ? 7 :
10738 i == Ydrip_s2 ? j + 8 :
10739 i == Ydrip_s2B ? j + 8 :
10741 i == Xacid_2 ? 10 :
10742 i == Xacid_3 ? 20 :
10743 i == Xacid_4 ? 30 :
10744 i == Xacid_5 ? 40 :
10745 i == Xacid_6 ? 50 :
10746 i == Xacid_7 ? 60 :
10747 i == Xacid_8 ? 70 :
10748 i == Xfake_acid_1 ? 0 :
10749 i == Xfake_acid_2 ? 10 :
10750 i == Xfake_acid_3 ? 20 :
10751 i == Xfake_acid_4 ? 30 :
10752 i == Xfake_acid_5 ? 40 :
10753 i == Xfake_acid_6 ? 50 :
10754 i == Xfake_acid_7 ? 60 :
10755 i == Xfake_acid_8 ? 70 :
10757 i == Xball_2B ? j + 8 :
10758 i == Yball_eat ? j + 1 :
10759 i == Ykey_1_eat ? j + 1 :
10760 i == Ykey_2_eat ? j + 1 :
10761 i == Ykey_3_eat ? j + 1 :
10762 i == Ykey_4_eat ? j + 1 :
10763 i == Ykey_5_eat ? j + 1 :
10764 i == Ykey_6_eat ? j + 1 :
10765 i == Ykey_7_eat ? j + 1 :
10766 i == Ykey_8_eat ? j + 1 :
10767 i == Ylenses_eat ? j + 1 :
10768 i == Ymagnify_eat ? j + 1 :
10769 i == Ygrass_eat ? j + 1 :
10770 i == Ydirt_eat ? j + 1 :
10771 i == Xamoeba_1 ? 0 :
10772 i == Xamoeba_2 ? 1 :
10773 i == Xamoeba_3 ? 2 :
10774 i == Xamoeba_4 ? 3 :
10775 i == Xamoeba_5 ? 0 :
10776 i == Xamoeba_6 ? 1 :
10777 i == Xamoeba_7 ? 2 :
10778 i == Xamoeba_8 ? 3 :
10779 i == Xexit_2 ? j + 8 :
10780 i == Xexit_3 ? j + 16 :
10781 i == Xdynamite_1 ? 0 :
10782 i == Xdynamite_2 ? 8 :
10783 i == Xdynamite_3 ? 16 :
10784 i == Xdynamite_4 ? 24 :
10785 i == Xsand_stonein_1 ? j + 1 :
10786 i == Xsand_stonein_2 ? j + 9 :
10787 i == Xsand_stonein_3 ? j + 17 :
10788 i == Xsand_stonein_4 ? j + 25 :
10789 i == Xsand_stoneout_1 && j == 0 ? 0 :
10790 i == Xsand_stoneout_1 && j == 1 ? 0 :
10791 i == Xsand_stoneout_1 && j == 2 ? 1 :
10792 i == Xsand_stoneout_1 && j == 3 ? 2 :
10793 i == Xsand_stoneout_1 && j == 4 ? 2 :
10794 i == Xsand_stoneout_1 && j == 5 ? 3 :
10795 i == Xsand_stoneout_1 && j == 6 ? 4 :
10796 i == Xsand_stoneout_1 && j == 7 ? 4 :
10797 i == Xsand_stoneout_2 && j == 0 ? 5 :
10798 i == Xsand_stoneout_2 && j == 1 ? 6 :
10799 i == Xsand_stoneout_2 && j == 2 ? 7 :
10800 i == Xsand_stoneout_2 && j == 3 ? 8 :
10801 i == Xsand_stoneout_2 && j == 4 ? 9 :
10802 i == Xsand_stoneout_2 && j == 5 ? 11 :
10803 i == Xsand_stoneout_2 && j == 6 ? 13 :
10804 i == Xsand_stoneout_2 && j == 7 ? 15 :
10805 i == Xboom_bug && j == 1 ? 2 :
10806 i == Xboom_bug && j == 2 ? 2 :
10807 i == Xboom_bug && j == 3 ? 4 :
10808 i == Xboom_bug && j == 4 ? 4 :
10809 i == Xboom_bug && j == 5 ? 2 :
10810 i == Xboom_bug && j == 6 ? 2 :
10811 i == Xboom_bug && j == 7 ? 0 :
10812 i == Xboom_bomb && j == 1 ? 2 :
10813 i == Xboom_bomb && j == 2 ? 2 :
10814 i == Xboom_bomb && j == 3 ? 4 :
10815 i == Xboom_bomb && j == 4 ? 4 :
10816 i == Xboom_bomb && j == 5 ? 2 :
10817 i == Xboom_bomb && j == 6 ? 2 :
10818 i == Xboom_bomb && j == 7 ? 0 :
10819 i == Xboom_android && j == 7 ? 6 :
10820 i == Xboom_1 && j == 1 ? 2 :
10821 i == Xboom_1 && j == 2 ? 2 :
10822 i == Xboom_1 && j == 3 ? 4 :
10823 i == Xboom_1 && j == 4 ? 4 :
10824 i == Xboom_1 && j == 5 ? 6 :
10825 i == Xboom_1 && j == 6 ? 6 :
10826 i == Xboom_1 && j == 7 ? 8 :
10827 i == Xboom_2 && j == 0 ? 8 :
10828 i == Xboom_2 && j == 1 ? 8 :
10829 i == Xboom_2 && j == 2 ? 10 :
10830 i == Xboom_2 && j == 3 ? 10 :
10831 i == Xboom_2 && j == 4 ? 10 :
10832 i == Xboom_2 && j == 5 ? 12 :
10833 i == Xboom_2 && j == 6 ? 12 :
10834 i == Xboom_2 && j == 7 ? 12 :
10835 special_animation && j == 4 ? 3 :
10836 effective_action != action ? 0 :
10840 Bitmap *debug_bitmap = g_em->bitmap;
10841 int debug_src_x = g_em->src_x;
10842 int debug_src_y = g_em->src_y;
10845 int frame = getAnimationFrame(g->anim_frames,
10848 g->anim_start_frame,
10851 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y,
10852 g->double_movement && is_backside);
10854 g_em->bitmap = src_bitmap;
10855 g_em->src_x = src_x;
10856 g_em->src_y = src_y;
10857 g_em->src_offset_x = 0;
10858 g_em->src_offset_y = 0;
10859 g_em->dst_offset_x = 0;
10860 g_em->dst_offset_y = 0;
10861 g_em->width = TILEX;
10862 g_em->height = TILEY;
10864 g_em->preserve_background = FALSE;
10867 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
10872 g_em->crumbled_bitmap = NULL;
10873 g_em->crumbled_src_x = 0;
10874 g_em->crumbled_src_y = 0;
10875 g_em->crumbled_border_size = 0;
10877 g_em->has_crumbled_graphics = FALSE;
10880 if (has_crumbled_graphics && crumbled == IMG_EMPTY_SPACE)
10881 printf("::: empty crumbled: %d [%s], %d, %d\n",
10882 effective_element, element_info[effective_element].token_name,
10883 effective_action, direction);
10886 /* if element can be crumbled, but certain action graphics are just empty
10887 space (like instantly snapping sand to empty space in 1 frame), do not
10888 treat these empty space graphics as crumbled graphics in EMC engine */
10889 if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
10891 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
10892 g_crumbled->anim_delay,
10893 g_crumbled->anim_mode,
10894 g_crumbled->anim_start_frame,
10897 getGraphicSource(crumbled, frame_crumbled, &src_bitmap, &src_x, &src_y);
10899 g_em->has_crumbled_graphics = TRUE;
10900 g_em->crumbled_bitmap = src_bitmap;
10901 g_em->crumbled_src_x = src_x;
10902 g_em->crumbled_src_y = src_y;
10903 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
10907 if (g_em == &graphic_info_em_object[207][0])
10908 printf("... %d, %d [%d, %d, %d, %d] [%d, %d, %d, %d, %d, %d => %d]\n",
10909 graphic_info_em_object[207][0].crumbled_src_x,
10910 graphic_info_em_object[207][0].crumbled_src_y,
10912 crumbled, frame, src_x, src_y,
10917 g->anim_start_frame,
10919 gfx.anim_random_frame,
10924 printf("::: EMC tile %d is crumbled\n", i);
10930 if (element == EL_ROCK &&
10931 effective_action == ACTION_FILLING)
10932 printf("::: has_action_graphics == %d\n", has_action_graphics);
10935 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
10936 effective_action == ACTION_MOVING ||
10937 effective_action == ACTION_PUSHING ||
10938 effective_action == ACTION_EATING)) ||
10939 (!has_action_graphics && (effective_action == ACTION_FILLING ||
10940 effective_action == ACTION_EMPTYING)))
10943 (effective_action == ACTION_FALLING ||
10944 effective_action == ACTION_FILLING ||
10945 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
10946 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
10947 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
10948 int num_steps = (i == Ydrip_s1 ? 16 :
10949 i == Ydrip_s1B ? 16 :
10950 i == Ydrip_s2 ? 16 :
10951 i == Ydrip_s2B ? 16 :
10952 i == Xsand_stonein_1 ? 32 :
10953 i == Xsand_stonein_2 ? 32 :
10954 i == Xsand_stonein_3 ? 32 :
10955 i == Xsand_stonein_4 ? 32 :
10956 i == Xsand_stoneout_1 ? 16 :
10957 i == Xsand_stoneout_2 ? 16 : 8);
10958 int cx = ABS(dx) * (TILEX / num_steps);
10959 int cy = ABS(dy) * (TILEY / num_steps);
10960 int step_frame = (i == Ydrip_s2 ? j + 8 :
10961 i == Ydrip_s2B ? j + 8 :
10962 i == Xsand_stonein_2 ? j + 8 :
10963 i == Xsand_stonein_3 ? j + 16 :
10964 i == Xsand_stonein_4 ? j + 24 :
10965 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
10966 int step = (is_backside ? step_frame : num_steps - step_frame);
10968 if (is_backside) /* tile where movement starts */
10970 if (dx < 0 || dy < 0)
10972 g_em->src_offset_x = cx * step;
10973 g_em->src_offset_y = cy * step;
10977 g_em->dst_offset_x = cx * step;
10978 g_em->dst_offset_y = cy * step;
10981 else /* tile where movement ends */
10983 if (dx < 0 || dy < 0)
10985 g_em->dst_offset_x = cx * step;
10986 g_em->dst_offset_y = cy * step;
10990 g_em->src_offset_x = cx * step;
10991 g_em->src_offset_y = cy * step;
10995 g_em->width = TILEX - cx * step;
10996 g_em->height = TILEY - cy * step;
10999 /* create unique graphic identifier to decide if tile must be redrawn */
11000 /* bit 31 - 16 (16 bit): EM style graphic
11001 bit 15 - 12 ( 4 bit): EM style frame
11002 bit 11 - 6 ( 6 bit): graphic width
11003 bit 5 - 0 ( 6 bit): graphic height */
11004 g_em->unique_identifier =
11005 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
11009 /* skip check for EMC elements not contained in original EMC artwork */
11010 if (element == EL_EMC_FAKE_ACID)
11013 if (g_em->bitmap != debug_bitmap ||
11014 g_em->src_x != debug_src_x ||
11015 g_em->src_y != debug_src_y ||
11016 g_em->src_offset_x != 0 ||
11017 g_em->src_offset_y != 0 ||
11018 g_em->dst_offset_x != 0 ||
11019 g_em->dst_offset_y != 0 ||
11020 g_em->width != TILEX ||
11021 g_em->height != TILEY)
11023 static int last_i = -1;
11031 printf("::: EMC GFX ERROR for element %d -> %d ('%s', '%s', %d)",
11032 i, element, element_info[element].token_name,
11033 element_action_info[effective_action].suffix, direction);
11035 if (element != effective_element)
11036 printf(" [%d ('%s')]",
11038 element_info[effective_element].token_name);
11042 if (g_em->bitmap != debug_bitmap)
11043 printf(" %d (%d): different bitmap! (0x%08x != 0x%08x)\n",
11044 j, is_backside, (int)(g_em->bitmap), (int)(debug_bitmap));
11046 if (g_em->src_x != debug_src_x ||
11047 g_em->src_y != debug_src_y)
11048 printf(" frame %d (%c): %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
11049 j, (is_backside ? 'B' : 'F'),
11050 g_em->src_x, g_em->src_y,
11051 g_em->src_x / 32, g_em->src_y / 32,
11052 debug_src_x, debug_src_y,
11053 debug_src_x / 32, debug_src_y / 32);
11055 if (g_em->src_offset_x != 0 ||
11056 g_em->src_offset_y != 0 ||
11057 g_em->dst_offset_x != 0 ||
11058 g_em->dst_offset_y != 0)
11059 printf(" %d (%d): offsets %d,%d and %d,%d should be all 0\n",
11061 g_em->src_offset_x, g_em->src_offset_y,
11062 g_em->dst_offset_x, g_em->dst_offset_y);
11064 if (g_em->width != TILEX ||
11065 g_em->height != TILEY)
11066 printf(" %d (%d): size %d,%d should be %d,%d\n",
11068 g_em->width, g_em->height, TILEX, TILEY);
11070 num_em_gfx_errors++;
11077 for (i = 0; i < TILE_MAX; i++)
11079 for (j = 0; j < 8; j++)
11081 int element = object_mapping[i].element_rnd;
11082 int action = object_mapping[i].action;
11083 int direction = object_mapping[i].direction;
11084 boolean is_backside = object_mapping[i].is_backside;
11085 int graphic_action = el_act_dir2img(element, action, direction);
11086 int graphic_default = el_act_dir2img(element, ACTION_DEFAULT, direction);
11088 if ((action == ACTION_SMASHED_BY_ROCK ||
11089 action == ACTION_SMASHED_BY_SPRING ||
11090 action == ACTION_EATING) &&
11091 graphic_action == graphic_default)
11093 int e = (action == ACTION_SMASHED_BY_ROCK ? Ystone_s :
11094 action == ACTION_SMASHED_BY_SPRING ? Yspring_s :
11095 direction == MV_LEFT ? (is_backside? Yspring_wB: Yspring_w) :
11096 direction == MV_RIGHT ? (is_backside? Yspring_eB: Yspring_e) :
11099 /* no separate animation for "smashed by rock" -- use rock instead */
11100 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
11101 struct GraphicInfo_EM *g_xx = &graphic_info_em_object[e][7 - j];
11103 g_em->bitmap = g_xx->bitmap;
11104 g_em->src_x = g_xx->src_x;
11105 g_em->src_y = g_xx->src_y;
11106 g_em->src_offset_x = g_xx->src_offset_x;
11107 g_em->src_offset_y = g_xx->src_offset_y;
11108 g_em->dst_offset_x = g_xx->dst_offset_x;
11109 g_em->dst_offset_y = g_xx->dst_offset_y;
11110 g_em->width = g_xx->width;
11111 g_em->height = g_xx->height;
11112 g_em->unique_identifier = g_xx->unique_identifier;
11115 g_em->preserve_background = TRUE;
11120 for (p = 0; p < MAX_PLAYERS; p++)
11122 for (i = 0; i < SPR_MAX; i++)
11124 int element = player_mapping[p][i].element_rnd;
11125 int action = player_mapping[p][i].action;
11126 int direction = player_mapping[p][i].direction;
11128 for (j = 0; j < 8; j++)
11130 int effective_element = element;
11131 int effective_action = action;
11132 int graphic = (direction == MV_NONE ?
11133 el_act2img(effective_element, effective_action) :
11134 el_act_dir2img(effective_element, effective_action,
11136 struct GraphicInfo *g = &graphic_info[graphic];
11137 struct GraphicInfo_EM *g_em = &graphic_info_em_player[p][i][7 - j];
11138 Bitmap *src_bitmap;
11140 int sync_frame = j;
11143 Bitmap *debug_bitmap = g_em->bitmap;
11144 int debug_src_x = g_em->src_x;
11145 int debug_src_y = g_em->src_y;
11148 int frame = getAnimationFrame(g->anim_frames,
11151 g->anim_start_frame,
11154 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
11156 g_em->bitmap = src_bitmap;
11157 g_em->src_x = src_x;
11158 g_em->src_y = src_y;
11159 g_em->src_offset_x = 0;
11160 g_em->src_offset_y = 0;
11161 g_em->dst_offset_x = 0;
11162 g_em->dst_offset_y = 0;
11163 g_em->width = TILEX;
11164 g_em->height = TILEY;
11168 /* skip check for EMC elements not contained in original EMC artwork */
11169 if (element == EL_PLAYER_3 ||
11170 element == EL_PLAYER_4)
11173 if (g_em->bitmap != debug_bitmap ||
11174 g_em->src_x != debug_src_x ||
11175 g_em->src_y != debug_src_y)
11177 static int last_i = -1;
11185 printf("::: EMC GFX ERROR for p/a %d/%d -> %d ('%s', '%s', %d)",
11186 p, i, element, element_info[element].token_name,
11187 element_action_info[effective_action].suffix, direction);
11189 if (element != effective_element)
11190 printf(" [%d ('%s')]",
11192 element_info[effective_element].token_name);
11196 if (g_em->bitmap != debug_bitmap)
11197 printf(" %d: different bitmap! (0x%08x != 0x%08x)\n",
11198 j, (int)(g_em->bitmap), (int)(debug_bitmap));
11200 if (g_em->src_x != debug_src_x ||
11201 g_em->src_y != debug_src_y)
11202 printf(" frame %d: %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
11204 g_em->src_x, g_em->src_y,
11205 g_em->src_x / 32, g_em->src_y / 32,
11206 debug_src_x, debug_src_y,
11207 debug_src_x / 32, debug_src_y / 32);
11209 num_em_gfx_errors++;
11219 printf("::: [%d errors found]\n", num_em_gfx_errors);
11225 void CheckSingleStepMode_EM(byte action[MAX_PLAYERS], int frame,
11226 boolean any_player_moving,
11227 boolean player_is_dropping)
11229 if (tape.single_step && tape.recording && !tape.pausing)
11232 boolean active_players = FALSE;
11235 for (i = 0; i < MAX_PLAYERS; i++)
11236 if (action[i] != JOY_NO_ACTION)
11237 active_players = TRUE;
11241 if (frame == 0 && !player_is_dropping)
11242 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
11246 void CheckSingleStepMode_SP(boolean murphy_is_waiting,
11247 boolean murphy_is_dropping)
11250 printf("::: waiting: %d, dropping: %d\n",
11251 murphy_is_waiting, murphy_is_dropping);
11254 if (tape.single_step && tape.recording && !tape.pausing)
11256 // if (murphy_is_waiting || murphy_is_dropping)
11257 if (murphy_is_waiting)
11260 printf("::: murphy is waiting -> pause mode\n");
11263 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
11268 void getGraphicSource_SP(struct GraphicInfo_SP *g_sp,
11269 int graphic, int sync_frame, int x, int y)
11271 int frame = getGraphicAnimationFrame(graphic, sync_frame);
11273 getGraphicSource(graphic, frame, &g_sp->bitmap, &g_sp->src_x, &g_sp->src_y);
11276 boolean isNextAnimationFrame_SP(int graphic, int sync_frame)
11278 return (IS_NEXT_FRAME(sync_frame, graphic));
11281 int getGraphicInfo_Delay(int graphic)
11283 return graphic_info[graphic].anim_delay;
11286 void PlayMenuSoundExt(int sound)
11288 if (sound == SND_UNDEFINED)
11291 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
11292 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
11295 if (IS_LOOP_SOUND(sound))
11296 PlaySoundLoop(sound);
11301 void PlayMenuSound()
11303 PlayMenuSoundExt(menu.sound[game_status]);
11306 void PlayMenuSoundStereo(int sound, int stereo_position)
11308 if (sound == SND_UNDEFINED)
11311 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
11312 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
11315 if (IS_LOOP_SOUND(sound))
11316 PlaySoundExt(sound, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_LOOP);
11318 PlaySoundStereo(sound, stereo_position);
11321 void PlayMenuSoundIfLoopExt(int sound)
11323 if (sound == SND_UNDEFINED)
11326 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
11327 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
11330 if (IS_LOOP_SOUND(sound))
11331 PlaySoundLoop(sound);
11334 void PlayMenuSoundIfLoop()
11336 PlayMenuSoundIfLoopExt(menu.sound[game_status]);
11339 void PlayMenuMusicExt(int music)
11341 if (music == MUS_UNDEFINED)
11344 if (!setup.sound_music)
11350 void PlayMenuMusic()
11352 PlayMenuMusicExt(menu.music[game_status]);
11355 void PlaySoundActivating()
11358 PlaySound(SND_MENU_ITEM_ACTIVATING);
11362 void PlaySoundSelecting()
11365 PlaySound(SND_MENU_ITEM_SELECTING);
11369 void ToggleFullscreenOrChangeWindowScalingIfNeeded()
11371 boolean change_fullscreen = (setup.fullscreen !=
11372 video.fullscreen_enabled);
11373 boolean change_fullscreen_mode = (video.fullscreen_enabled &&
11374 !strEqual(setup.fullscreen_mode,
11375 video.fullscreen_mode_current));
11376 boolean change_window_scaling_percent = (!video.fullscreen_enabled &&
11377 setup.window_scaling_percent !=
11378 video.window_scaling_percent);
11380 if (change_window_scaling_percent && video.fullscreen_enabled)
11383 if (!change_window_scaling_percent && !video.fullscreen_available)
11386 #if defined(TARGET_SDL2)
11387 if (change_window_scaling_percent)
11389 SDLSetWindowScaling(setup.window_scaling_percent);
11393 else if (change_fullscreen)
11395 SDLSetWindowFullscreen(setup.fullscreen);
11397 /* set setup value according to successfully changed fullscreen mode */
11398 setup.fullscreen = video.fullscreen_enabled;
11404 if (change_fullscreen ||
11405 change_fullscreen_mode ||
11406 change_window_scaling_percent)
11408 Bitmap *tmp_backbuffer = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
11410 /* save backbuffer content which gets lost when toggling fullscreen mode */
11411 BlitBitmap(backbuffer, tmp_backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
11413 if (change_fullscreen_mode)
11415 /* keep fullscreen, but change fullscreen mode (screen resolution) */
11416 video.fullscreen_enabled = FALSE; /* force new fullscreen mode */
11419 if (change_window_scaling_percent)
11421 /* keep window mode, but change window scaling */
11422 video.fullscreen_enabled = TRUE; /* force new window scaling */
11425 /* toggle fullscreen */
11426 ChangeVideoModeIfNeeded(setup.fullscreen);
11428 /* set setup value according to successfully changed fullscreen mode */
11429 setup.fullscreen = video.fullscreen_enabled;
11431 /* restore backbuffer content from temporary backbuffer backup bitmap */
11432 BlitBitmap(tmp_backbuffer, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
11434 FreeBitmap(tmp_backbuffer);
11437 /* update visible window/screen */
11438 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
11440 redraw_mask = REDRAW_ALL;
11445 void ChangeViewportPropertiesIfNeeded()
11448 int *door_1_x = &DX;
11449 int *door_1_y = &DY;
11450 int *door_2_x = (game_status == GAME_MODE_EDITOR ? &EX : &VX);
11451 int *door_2_y = (game_status == GAME_MODE_EDITOR ? &EY : &VY);
11454 int gfx_game_mode = game_status;
11456 int gfx_game_mode = (game_status == GAME_MODE_PLAYING ||
11457 game_status == GAME_MODE_EDITOR ? game_status :
11460 int gfx_game_mode2 = (game_status == GAME_MODE_EDITOR ? GAME_MODE_DEFAULT :
11462 struct RectWithBorder *vp_playfield = &viewport.playfield[gfx_game_mode];
11463 struct RectWithBorder *vp_door_1 = &viewport.door_1[gfx_game_mode];
11464 struct RectWithBorder *vp_door_2 = &viewport.door_2[gfx_game_mode2];
11465 struct RectWithBorder *vp_door_3 = &viewport.door_2[GAME_MODE_EDITOR];
11466 int border_size = vp_playfield->border_size;
11467 int new_sx = vp_playfield->x + border_size;
11468 int new_sy = vp_playfield->y + border_size;
11469 int new_sxsize = vp_playfield->width - 2 * border_size;
11470 int new_sysize = vp_playfield->height - 2 * border_size;
11471 int new_real_sx = vp_playfield->x;
11472 int new_real_sy = vp_playfield->y;
11473 int new_full_sxsize = vp_playfield->width;
11474 int new_full_sysize = vp_playfield->height;
11475 int new_dx = vp_door_1->x;
11476 int new_dy = vp_door_1->y;
11477 int new_dxsize = vp_door_1->width;
11478 int new_dysize = vp_door_1->height;
11479 int new_vx = vp_door_2->x;
11480 int new_vy = vp_door_2->y;
11481 int new_vxsize = vp_door_2->width;
11482 int new_vysize = vp_door_2->height;
11483 int new_ex = vp_door_3->x;
11484 int new_ey = vp_door_3->y;
11485 int new_exsize = vp_door_3->width;
11486 int new_eysize = vp_door_3->height;
11488 int new_tilesize_var = TILESIZE / (setup.small_game_graphics ? 2 : 1);
11489 int tilesize = (gfx_game_mode == GAME_MODE_PLAYING ? new_tilesize_var :
11490 gfx_game_mode == GAME_MODE_EDITOR ? MINI_TILESIZE : TILESIZE);
11491 int new_scr_fieldx = new_sxsize / tilesize;
11492 int new_scr_fieldy = new_sysize / tilesize;
11493 int new_scr_fieldx_buffers = new_sxsize / new_tilesize_var;
11494 int new_scr_fieldy_buffers = new_sysize / new_tilesize_var;
11496 int new_scr_fieldx = (vp_playfield->width - 2 * border_size) / TILESIZE;
11497 int new_scr_fieldy = (vp_playfield->height - 2 * border_size) / TILESIZE;
11499 boolean init_gfx_buffers = FALSE;
11500 boolean init_video_buffer = FALSE;
11501 boolean init_gadgets_and_toons = FALSE;
11502 boolean init_em_graphics = FALSE;
11505 /* !!! TEST ONLY !!! */
11506 // InitGfxBuffers();
11510 if (viewport.window.width != WIN_XSIZE ||
11511 viewport.window.height != WIN_YSIZE)
11513 WIN_XSIZE = viewport.window.width;
11514 WIN_YSIZE = viewport.window.height;
11517 init_video_buffer = TRUE;
11518 init_gfx_buffers = TRUE;
11520 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
11524 SetDrawDeactivationMask(REDRAW_NONE);
11525 SetDrawBackgroundMask(REDRAW_FIELD);
11527 // RedrawBackground();
11531 // printf("::: video: init_video_buffer, init_gfx_buffers\n");
11534 if (new_scr_fieldx != SCR_FIELDX ||
11535 new_scr_fieldy != SCR_FIELDY)
11537 /* this always toggles between MAIN and GAME when using small tile size */
11539 SCR_FIELDX = new_scr_fieldx;
11540 SCR_FIELDY = new_scr_fieldy;
11542 // printf("::: new_scr_fieldx != SCR_FIELDX ...\n");
11546 if (new_tilesize_var != TILESIZE_VAR &&
11547 gfx_game_mode == GAME_MODE_PLAYING)
11549 /* doing this outside GAME_MODE_PLAYING would give wrong playfield size */
11551 TILESIZE_VAR = new_tilesize_var;
11553 init_gfx_buffers = TRUE;
11555 // printf("::: tilesize: init_gfx_buffers\n");
11559 if (new_sx != SX ||
11567 new_sxsize != SXSIZE ||
11568 new_sysize != SYSIZE ||
11569 new_dxsize != DXSIZE ||
11570 new_dysize != DYSIZE ||
11571 new_vxsize != VXSIZE ||
11572 new_vysize != VYSIZE ||
11573 new_exsize != EXSIZE ||
11574 new_eysize != EYSIZE ||
11575 new_real_sx != REAL_SX ||
11576 new_real_sy != REAL_SY ||
11577 new_full_sxsize != FULL_SXSIZE ||
11578 new_full_sysize != FULL_SYSIZE ||
11579 new_tilesize_var != TILESIZE_VAR
11582 vp_door_1->x != *door_1_x ||
11583 vp_door_1->y != *door_1_y ||
11584 vp_door_2->x != *door_2_x ||
11585 vp_door_2->y != *door_2_y
11590 if (new_tilesize_var != TILESIZE_VAR)
11592 // printf("::: new_tilesize_var != TILESIZE_VAR\n");
11594 // changing tile size invalidates scroll values of engine snapshots
11595 FreeEngineSnapshot();
11597 // changing tile size requires update of graphic mapping for EM engine
11598 init_em_graphics = TRUE;
11610 SXSIZE = new_sxsize;
11611 SYSIZE = new_sysize;
11612 DXSIZE = new_dxsize;
11613 DYSIZE = new_dysize;
11614 VXSIZE = new_vxsize;
11615 VYSIZE = new_vysize;
11616 EXSIZE = new_exsize;
11617 EYSIZE = new_eysize;
11618 REAL_SX = new_real_sx;
11619 REAL_SY = new_real_sy;
11620 FULL_SXSIZE = new_full_sxsize;
11621 FULL_SYSIZE = new_full_sysize;
11622 TILESIZE_VAR = new_tilesize_var;
11625 printf("::: %d, %d, %d [%d]\n",
11626 SCR_FIELDX, SCR_FIELDY, TILESIZE_VAR,
11627 setup.small_game_graphics);
11631 *door_1_x = vp_door_1->x;
11632 *door_1_y = vp_door_1->y;
11633 *door_2_x = vp_door_2->x;
11634 *door_2_y = vp_door_2->y;
11638 init_gfx_buffers = TRUE;
11640 // printf("::: viewports: init_gfx_buffers\n");
11646 if (gfx_game_mode == GAME_MODE_MAIN)
11650 init_gadgets_and_toons = TRUE;
11652 // printf("::: viewports: init_gadgets_and_toons\n");
11660 if (init_gfx_buffers)
11662 // printf("::: init_gfx_buffers\n");
11664 SCR_FIELDX = new_scr_fieldx_buffers;
11665 SCR_FIELDY = new_scr_fieldy_buffers;
11669 SCR_FIELDX = new_scr_fieldx;
11670 SCR_FIELDY = new_scr_fieldy;
11673 if (init_video_buffer)
11675 // printf("::: init_video_buffer\n");
11677 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
11679 SetDrawDeactivationMask(REDRAW_NONE);
11680 SetDrawBackgroundMask(REDRAW_FIELD);
11683 if (init_gadgets_and_toons)
11685 // printf("::: init_gadgets_and_toons\n");
11691 if (init_em_graphics)
11693 InitGraphicInfo_EM();
11697 printf("::: %d, %d / %d, %d [%d]\n", VX, VY, EX, EY, game_status);