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);
1590 if (TILESIZE_VAR != TILESIZE)
1591 return getSizedGraphicSourceExt(graphic, frame, TILESIZE_VAR, bitmap, x, y,
1595 *bitmap = g->bitmap;
1597 if (g->offset_y == 0) /* frames are ordered horizontally */
1599 int max_width = g->anim_frames_per_line * g->width;
1600 int pos = (src_y / g->height) * max_width + src_x + frame * g->offset_x;
1602 *x = pos % max_width;
1603 *y = src_y % g->height + pos / max_width * g->height;
1605 else if (g->offset_x == 0) /* frames are ordered vertically */
1607 int max_height = g->anim_frames_per_line * g->height;
1608 int pos = (src_x / g->width) * max_height + src_y + frame * g->offset_y;
1610 *x = src_x % g->width + pos / max_height * g->width;
1611 *y = pos % max_height;
1613 else /* frames are ordered diagonally */
1615 *x = src_x + frame * g->offset_x;
1616 *y = src_y + frame * g->offset_y;
1620 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
1622 getGraphicSourceExt(graphic, frame, bitmap, x, y, FALSE);
1625 void DrawGraphic(int x, int y, int graphic, int frame)
1628 if (!IN_SCR_FIELD(x, y))
1630 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
1631 printf("DrawGraphic(): This should never happen!\n");
1637 DrawGraphicExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR, graphic,
1640 DrawGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic, frame);
1642 MarkTileDirty(x, y);
1645 void DrawFixedGraphic(int x, int y, int graphic, int frame)
1648 if (!IN_SCR_FIELD(x, y))
1650 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
1651 printf("DrawGraphic(): This should never happen!\n");
1656 DrawFixedGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic,
1658 MarkTileDirty(x, y);
1661 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
1667 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1669 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX_VAR, TILEY_VAR, x, y);
1671 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
1675 void DrawFixedGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
1681 getFixedGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1682 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
1685 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
1688 if (!IN_SCR_FIELD(x, y))
1690 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
1691 printf("DrawGraphicThruMask(): This should never happen!\n");
1697 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR,
1700 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic,
1703 MarkTileDirty(x, y);
1706 void DrawFixedGraphicThruMask(int x, int y, int graphic, int frame)
1709 if (!IN_SCR_FIELD(x, y))
1711 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
1712 printf("DrawGraphicThruMask(): This should never happen!\n");
1717 DrawFixedGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
1719 MarkTileDirty(x, y);
1722 void DrawGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y, int graphic,
1728 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1730 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1731 dst_x - src_x, dst_y - src_y);
1733 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX_VAR, TILEY_VAR,
1736 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dst_x, dst_y);
1740 void DrawFixedGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y,
1741 int graphic, int frame)
1746 getFixedGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1748 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1749 dst_x - src_x, dst_y - src_y);
1750 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dst_x, dst_y);
1753 void DrawSizedGraphic(int x, int y, int graphic, int frame, int tilesize)
1755 DrawSizedGraphicExt(drawto, SX + x * tilesize, SY + y * tilesize, graphic,
1757 MarkTileDirty(x / tilesize, y / tilesize);
1760 void DrawSizedGraphicExt(DrawBuffer *d, int x, int y, int graphic, int frame,
1766 getSizedGraphicSource(graphic, frame, tilesize, &src_bitmap, &src_x, &src_y);
1767 BlitBitmap(src_bitmap, d, src_x, src_y, tilesize, tilesize, x, y);
1770 void DrawMiniGraphic(int x, int y, int graphic)
1772 DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
1773 MarkTileDirty(x / 2, y / 2);
1776 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
1781 getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1782 BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
1785 inline static void DrawGraphicShiftedNormal(int x, int y, int dx, int dy,
1786 int graphic, int frame,
1787 int cut_mode, int mask_mode)
1792 int width = TILEX, height = TILEY;
1795 if (dx || dy) /* shifted graphic */
1797 if (x < BX1) /* object enters playfield from the left */
1804 else if (x > BX2) /* object enters playfield from the right */
1810 else if (x==BX1 && dx < 0) /* object leaves playfield to the left */
1816 else if (x==BX2 && dx > 0) /* object leaves playfield to the right */
1818 else if (dx) /* general horizontal movement */
1819 MarkTileDirty(x + SIGN(dx), y);
1821 if (y < BY1) /* object enters playfield from the top */
1823 if (cut_mode==CUT_BELOW) /* object completely above top border */
1831 else if (y > BY2) /* object enters playfield from the bottom */
1837 else if (y==BY1 && dy < 0) /* object leaves playfield to the top */
1843 else if (dy > 0 && cut_mode == CUT_ABOVE)
1845 if (y == BY2) /* object completely above bottom border */
1851 MarkTileDirty(x, y + 1);
1852 } /* object leaves playfield to the bottom */
1853 else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
1855 else if (dy) /* general vertical movement */
1856 MarkTileDirty(x, y + SIGN(dy));
1860 if (!IN_SCR_FIELD(x, y))
1862 printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
1863 printf("DrawGraphicShifted(): This should never happen!\n");
1869 width = width * TILESIZE_VAR / TILESIZE;
1870 height = height * TILESIZE_VAR / TILESIZE;
1871 cx = cx * TILESIZE_VAR / TILESIZE;
1872 cy = cy * TILESIZE_VAR / TILESIZE;
1873 dx = dx * TILESIZE_VAR / TILESIZE;
1874 dy = dy * TILESIZE_VAR / TILESIZE;
1877 if (width > 0 && height > 0)
1879 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1885 dst_x = FX + x * TILEX_VAR + dx;
1886 dst_y = FY + y * TILEY_VAR + dy;
1888 dst_x = FX + x * TILEX + dx;
1889 dst_y = FY + y * TILEY + dy;
1892 if (mask_mode == USE_MASKING)
1894 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1895 dst_x - src_x, dst_y - src_y);
1896 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1900 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1903 MarkTileDirty(x, y);
1907 inline static void DrawGraphicShiftedDouble(int x, int y, int dx, int dy,
1908 int graphic, int frame,
1909 int cut_mode, int mask_mode)
1915 int width = TILEX_VAR, height = TILEY_VAR;
1917 int width = TILEX, height = TILEY;
1921 int x2 = x + SIGN(dx);
1922 int y2 = y + SIGN(dy);
1924 /* !!! DOES NOT WORK FOR SLOW MOVEMENT !!! */
1925 int sync_frame = GfxFrame[LEVELX(x)][LEVELY(y)];
1927 /* movement with two-tile animations must be sync'ed with movement position,
1928 not with current GfxFrame (which can be higher when using slow movement) */
1929 int anim_pos = (dx ? ABS(dx) : ABS(dy));
1930 int anim_frames = graphic_info[graphic].anim_frames;
1932 /* (we also need anim_delay here for movement animations with less frames) */
1933 int anim_delay = graphic_info[graphic].anim_delay;
1934 int sync_frame = anim_pos * anim_frames * anim_delay / TILESIZE;
1936 int sync_frame = anim_pos * anim_frames / TILESIZE;
1939 boolean draw_start_tile = (cut_mode != CUT_ABOVE); /* only for falling! */
1940 boolean draw_end_tile = (cut_mode != CUT_BELOW); /* only for falling! */
1942 /* re-calculate animation frame for two-tile movement animation */
1943 frame = getGraphicAnimationFrame(graphic, sync_frame);
1947 printf("::: %d, %d, %d => %d [%d]\n",
1948 anim_pos, anim_frames, anim_delay, sync_frame, graphic);
1950 printf("::: %d, %d => %d\n",
1951 anim_pos, anim_frames, sync_frame);
1956 printf("::: %d [%d, %d] [%d] [%d]\n", frame, sync_frame, dy,
1957 GfxFrame[LEVELX(x)][LEVELY(y)], mask_mode);
1960 /* check if movement start graphic inside screen area and should be drawn */
1961 if (draw_start_tile && IN_SCR_FIELD(x1, y1))
1963 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, TRUE);
1966 dst_x = FX + x1 * TILEX_VAR;
1967 dst_y = FY + y1 * TILEY_VAR;
1969 dst_x = FX + x1 * TILEX;
1970 dst_y = FY + y1 * TILEY;
1973 if (mask_mode == USE_MASKING)
1975 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1976 dst_x - src_x, dst_y - src_y);
1977 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1981 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1984 MarkTileDirty(x1, y1);
1987 /* check if movement end graphic inside screen area and should be drawn */
1988 if (draw_end_tile && IN_SCR_FIELD(x2, y2))
1990 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
1993 dst_x = FX + x2 * TILEX_VAR;
1994 dst_y = FY + y2 * TILEY_VAR;
1996 dst_x = FX + x2 * TILEX;
1997 dst_y = FY + y2 * TILEY;
2000 if (mask_mode == USE_MASKING)
2002 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
2003 dst_x - src_x, dst_y - src_y);
2004 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
2008 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
2011 MarkTileDirty(x2, y2);
2015 static void DrawGraphicShifted(int x, int y, int dx, int dy,
2016 int graphic, int frame,
2017 int cut_mode, int mask_mode)
2021 DrawGraphic(x, y, graphic, frame);
2026 if (graphic_info[graphic].double_movement) /* EM style movement images */
2027 DrawGraphicShiftedDouble(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
2029 DrawGraphicShiftedNormal(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
2032 void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
2033 int frame, int cut_mode)
2035 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, USE_MASKING);
2038 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
2039 int cut_mode, int mask_mode)
2041 int lx = LEVELX(x), ly = LEVELY(y);
2045 if (IN_LEV_FIELD(lx, ly))
2047 SetRandomAnimationValue(lx, ly);
2049 graphic = el_act_dir2img(element, GfxAction[lx][ly], GfxDir[lx][ly]);
2050 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
2052 /* do not use double (EM style) movement graphic when not moving */
2053 if (graphic_info[graphic].double_movement && !dx && !dy)
2055 graphic = el_act_dir2img(element, ACTION_DEFAULT, GfxDir[lx][ly]);
2056 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
2059 else /* border element */
2061 graphic = el2img(element);
2062 frame = getGraphicAnimationFrame(graphic, -1);
2065 if (element == EL_EXPANDABLE_WALL)
2067 boolean left_stopped = FALSE, right_stopped = FALSE;
2069 if (!IN_LEV_FIELD(lx - 1, ly) || IS_WALL(Feld[lx - 1][ly]))
2070 left_stopped = TRUE;
2071 if (!IN_LEV_FIELD(lx + 1, ly) || IS_WALL(Feld[lx + 1][ly]))
2072 right_stopped = TRUE;
2074 if (left_stopped && right_stopped)
2076 else if (left_stopped)
2078 graphic = IMG_EXPANDABLE_WALL_GROWING_RIGHT;
2079 frame = graphic_info[graphic].anim_frames - 1;
2081 else if (right_stopped)
2083 graphic = IMG_EXPANDABLE_WALL_GROWING_LEFT;
2084 frame = graphic_info[graphic].anim_frames - 1;
2089 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
2090 else if (mask_mode == USE_MASKING)
2091 DrawGraphicThruMask(x, y, graphic, frame);
2093 DrawGraphic(x, y, graphic, frame);
2096 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
2097 int cut_mode, int mask_mode)
2099 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
2100 DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
2101 cut_mode, mask_mode);
2104 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
2107 DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
2110 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
2113 DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
2116 void DrawLevelElementThruMask(int x, int y, int element)
2118 DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
2121 void DrawLevelFieldThruMask(int x, int y)
2123 DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
2126 /* !!! implementation of quicksand is totally broken !!! */
2127 #define IS_CRUMBLED_TILE(x, y, e) \
2128 (GFX_CRUMBLED(e) && (!IN_LEV_FIELD(x, y) || \
2129 !IS_MOVING(x, y) || \
2130 (e) == EL_QUICKSAND_EMPTYING || \
2131 (e) == EL_QUICKSAND_FAST_EMPTYING))
2133 static void DrawLevelFieldCrumbledInnerCorners(int x, int y, int dx, int dy,
2138 int width, height, cx, cy;
2139 int sx = SCREENX(x), sy = SCREENY(y);
2140 int crumbled_border_size = graphic_info[graphic].border_size;
2143 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
2145 for (i = 1; i < 4; i++)
2147 int dxx = (i & 1 ? dx : 0);
2148 int dyy = (i & 2 ? dy : 0);
2151 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
2154 /* check if neighbour field is of same crumble type */
2155 boolean same = (IS_CRUMBLED_TILE(xx, yy, element) &&
2156 graphic_info[graphic].class ==
2157 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class);
2159 /* return if check prevents inner corner */
2160 if (same == (dxx == dx && dyy == dy))
2164 /* if we reach this point, we have an inner corner */
2166 getGraphicSource(graphic, 1, &src_bitmap, &src_x, &src_y);
2169 width = crumbled_border_size * TILESIZE_VAR / TILESIZE;
2170 height = crumbled_border_size * TILESIZE_VAR / TILESIZE;
2171 cx = (dx > 0 ? TILEX - crumbled_border_size : 0) * TILESIZE_VAR / TILESIZE;
2172 cy = (dy > 0 ? TILEY - crumbled_border_size : 0) * TILESIZE_VAR / TILESIZE;
2174 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
2175 width, height, FX + sx * TILEX_VAR + cx, FY + sy * TILEY_VAR + cy);
2177 width = crumbled_border_size;
2178 height = crumbled_border_size;
2179 cx = (dx > 0 ? TILEX - crumbled_border_size : 0);
2180 cy = (dy > 0 ? TILEY - crumbled_border_size : 0);
2182 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
2183 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
2187 static void DrawLevelFieldCrumbledBorders(int x, int y, int graphic, int frame,
2192 int width, height, bx, by, cx, cy;
2193 int sx = SCREENX(x), sy = SCREENY(y);
2194 int crumbled_border_size = graphic_info[graphic].border_size;
2197 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
2199 /* draw simple, sloppy, non-corner-accurate crumbled border */
2202 width = (dir == 1 || dir == 2 ? crumbled_border_size : TILEX);
2203 height = (dir == 0 || dir == 3 ? crumbled_border_size : TILEY);
2204 cx = (dir == 2 ? TILEX - crumbled_border_size : 0);
2205 cy = (dir == 3 ? TILEY - crumbled_border_size : 0);
2207 if (dir == 1 || dir == 2) /* left or right crumbled border */
2209 width = crumbled_border_size;
2211 cx = (dir == 2 ? TILEX - crumbled_border_size : 0);
2214 else /* top or bottom crumbled border */
2217 height = crumbled_border_size;
2219 cy = (dir == 3 ? TILEY - crumbled_border_size : 0);
2224 BlitBitmap(src_bitmap, drawto_field,
2225 src_x + cx * TILESIZE_VAR / TILESIZE,
2226 src_y + cy * TILESIZE_VAR / TILESIZE,
2227 width * TILESIZE_VAR / TILESIZE,
2228 height * TILESIZE_VAR / TILESIZE,
2229 FX + sx * TILEX_VAR + cx * TILESIZE_VAR / TILESIZE,
2230 FY + sy * TILEY_VAR + cy * TILESIZE_VAR / TILESIZE);
2232 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
2233 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
2236 /* (remaining middle border part must be at least as big as corner part) */
2237 if (!(graphic_info[graphic].style & STYLE_ACCURATE_BORDERS) ||
2238 crumbled_border_size >= TILESIZE / 3)
2241 /* correct corners of crumbled border, if needed */
2244 for (i = -1; i <= 1; i+=2)
2246 int xx = x + (dir == 0 || dir == 3 ? i : 0);
2247 int yy = y + (dir == 1 || dir == 2 ? i : 0);
2248 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
2251 /* check if neighbour field is of same crumble type */
2252 if (IS_CRUMBLED_TILE(xx, yy, element) &&
2253 graphic_info[graphic].class ==
2254 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
2256 /* no crumbled corner, but continued crumbled border */
2258 int c1 = (dir == 2 || dir == 3 ? TILESIZE - crumbled_border_size : 0);
2259 int c2 = (i == 1 ? TILESIZE - crumbled_border_size : 0);
2260 int b1 = (i == 1 ? crumbled_border_size :
2261 TILESIZE - 2 * crumbled_border_size);
2263 width = crumbled_border_size;
2264 height = crumbled_border_size;
2266 if (dir == 1 || dir == 2)
2282 BlitBitmap(src_bitmap, drawto_field,
2283 src_x + bx * TILESIZE_VAR / TILESIZE,
2284 src_y + by * TILESIZE_VAR / TILESIZE,
2285 width * TILESIZE_VAR / TILESIZE,
2286 height * TILESIZE_VAR / TILESIZE,
2287 FX + sx * TILEX_VAR + cx * TILESIZE_VAR / TILESIZE,
2288 FY + sy * TILEY_VAR + cy * TILESIZE_VAR / TILESIZE);
2290 BlitBitmap(src_bitmap, drawto_field, src_x + bx, src_y + by,
2291 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
2296 if (dir == 1 || dir == 2) /* left or right crumbled border */
2298 for (i = -1; i <= 1; i+=2)
2302 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
2305 /* check if neighbour field is of same crumble type */
2306 if (IS_CRUMBLED_TILE(xx, yy, element) &&
2307 graphic_info[graphic].class ==
2308 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
2310 /* no crumbled corner, but continued crumbled border */
2312 width = crumbled_border_size;
2313 height = crumbled_border_size;
2314 cx = (dir == 2 ? TILEX - crumbled_border_size : 0);
2315 cy = (i == 1 ? TILEY - crumbled_border_size : 0);
2317 by = (i == 1 ? crumbled_border_size :
2318 TILEY - 2 * crumbled_border_size);
2320 BlitBitmap(src_bitmap, drawto_field, src_x + bx, src_y + by,
2321 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
2325 else /* top or bottom crumbled border */
2327 for (i = -1; i <= 1; i+=2)
2331 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
2334 /* check if neighbour field is of same crumble type */
2335 if (IS_CRUMBLED_TILE(xx, yy, element) &&
2336 graphic_info[graphic].class ==
2337 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
2339 /* no crumbled corner, but continued crumbled border */
2341 width = crumbled_border_size;
2342 height = crumbled_border_size;
2343 cx = (i == 1 ? TILEX - crumbled_border_size : 0);
2344 cy = (dir == 3 ? TILEY - crumbled_border_size : 0);
2345 bx = (i == 1 ? crumbled_border_size :
2346 TILEX - 2 * crumbled_border_size);
2349 BlitBitmap(src_bitmap, drawto_field, src_x + bx, src_y + by,
2350 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
2357 static void DrawLevelFieldCrumbledExt(int x, int y, int graphic, int frame)
2359 int sx = SCREENX(x), sy = SCREENY(y);
2362 static int xy[4][2] =
2370 if (!IN_LEV_FIELD(x, y))
2373 element = TILE_GFX_ELEMENT(x, y);
2375 /* crumble field itself */
2376 if (IS_CRUMBLED_TILE(x, y, element))
2378 if (!IN_SCR_FIELD(sx, sy))
2381 for (i = 0; i < 4; i++)
2383 int xx = x + xy[i][0];
2384 int yy = y + xy[i][1];
2386 element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
2389 /* check if neighbour field is of same crumble type */
2391 if (IS_CRUMBLED_TILE(xx, yy, element) &&
2392 graphic_info[graphic].class ==
2393 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
2396 if (IS_CRUMBLED_TILE(xx, yy, element))
2400 DrawLevelFieldCrumbledBorders(x, y, graphic, frame, i);
2403 if ((graphic_info[graphic].style & STYLE_INNER_CORNERS) &&
2404 graphic_info[graphic].anim_frames == 2)
2406 for (i = 0; i < 4; i++)
2408 int dx = (i & 1 ? +1 : -1);
2409 int dy = (i & 2 ? +1 : -1);
2411 DrawLevelFieldCrumbledInnerCorners(x, y, dx, dy, graphic);
2415 MarkTileDirty(sx, sy);
2417 else /* center field not crumbled -- crumble neighbour fields */
2419 for (i = 0; i < 4; i++)
2421 int xx = x + xy[i][0];
2422 int yy = y + xy[i][1];
2423 int sxx = sx + xy[i][0];
2424 int syy = sy + xy[i][1];
2426 if (!IN_LEV_FIELD(xx, yy) ||
2427 !IN_SCR_FIELD(sxx, syy))
2430 if (Feld[xx][yy] == EL_ELEMENT_SNAPPING)
2433 element = TILE_GFX_ELEMENT(xx, yy);
2435 if (!IS_CRUMBLED_TILE(xx, yy, element))
2438 graphic = el_act2crm(element, ACTION_DEFAULT);
2440 DrawLevelFieldCrumbledBorders(xx, yy, graphic, 0, 3 - i);
2442 MarkTileDirty(sxx, syy);
2447 void DrawLevelFieldCrumbled(int x, int y)
2451 if (!IN_LEV_FIELD(x, y))
2455 /* !!! CHECK THIS !!! */
2458 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
2459 GFX_CRUMBLED(GfxElement[x][y]))
2462 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
2463 GfxElement[x][y] != EL_UNDEFINED &&
2464 GFX_CRUMBLED(GfxElement[x][y]))
2466 DrawLevelFieldCrumbledDigging(x, y, GfxDir[x][y], GfxFrame[x][y]);
2473 graphic = el_act2crm(TILE_GFX_ELEMENT(x, y), ACTION_DEFAULT);
2475 graphic = el_act2crm(Feld[x][y], ACTION_DEFAULT);
2478 DrawLevelFieldCrumbledExt(x, y, graphic, 0);
2481 void DrawLevelFieldCrumbledDigging(int x, int y, int direction,
2484 int graphic1 = el_act_dir2img(GfxElement[x][y], ACTION_DIGGING, direction);
2485 int graphic2 = el_act_dir2crm(GfxElement[x][y], ACTION_DIGGING, direction);
2486 int frame1 = getGraphicAnimationFrame(graphic1, step_frame);
2487 int frame2 = getGraphicAnimationFrame(graphic2, step_frame);
2488 int sx = SCREENX(x), sy = SCREENY(y);
2490 DrawGraphic(sx, sy, graphic1, frame1);
2491 DrawLevelFieldCrumbledExt(x, y, graphic2, frame2);
2494 void DrawLevelFieldCrumbledNeighbours(int x, int y)
2496 int sx = SCREENX(x), sy = SCREENY(y);
2497 static int xy[4][2] =
2506 for (i = 0; i < 4; i++)
2508 int xx = x + xy[i][0];
2509 int yy = y + xy[i][1];
2510 int sxx = sx + xy[i][0];
2511 int syy = sy + xy[i][1];
2513 if (!IN_LEV_FIELD(xx, yy) ||
2514 !IN_SCR_FIELD(sxx, syy) ||
2515 !GFX_CRUMBLED(Feld[xx][yy]) ||
2519 DrawLevelField(xx, yy);
2523 static int getBorderElement(int x, int y)
2527 { EL_STEELWALL_TOPLEFT, EL_INVISIBLE_STEELWALL_TOPLEFT },
2528 { EL_STEELWALL_TOPRIGHT, EL_INVISIBLE_STEELWALL_TOPRIGHT },
2529 { EL_STEELWALL_BOTTOMLEFT, EL_INVISIBLE_STEELWALL_BOTTOMLEFT },
2530 { EL_STEELWALL_BOTTOMRIGHT, EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
2531 { EL_STEELWALL_VERTICAL, EL_INVISIBLE_STEELWALL_VERTICAL },
2532 { EL_STEELWALL_HORIZONTAL, EL_INVISIBLE_STEELWALL_HORIZONTAL },
2533 { EL_STEELWALL, EL_INVISIBLE_STEELWALL }
2535 int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
2536 int steel_position = (x == -1 && y == -1 ? 0 :
2537 x == lev_fieldx && y == -1 ? 1 :
2538 x == -1 && y == lev_fieldy ? 2 :
2539 x == lev_fieldx && y == lev_fieldy ? 3 :
2540 x == -1 || x == lev_fieldx ? 4 :
2541 y == -1 || y == lev_fieldy ? 5 : 6);
2543 return border[steel_position][steel_type];
2546 void DrawScreenElement(int x, int y, int element)
2548 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
2549 DrawLevelFieldCrumbled(LEVELX(x), LEVELY(y));
2552 void DrawLevelElement(int x, int y, int element)
2554 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
2555 DrawScreenElement(SCREENX(x), SCREENY(y), element);
2558 void DrawScreenField(int x, int y)
2560 int lx = LEVELX(x), ly = LEVELY(y);
2561 int element, content;
2563 if (!IN_LEV_FIELD(lx, ly))
2565 if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
2568 element = getBorderElement(lx, ly);
2570 DrawScreenElement(x, y, element);
2575 element = Feld[lx][ly];
2576 content = Store[lx][ly];
2578 if (IS_MOVING(lx, ly))
2580 int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
2581 boolean cut_mode = NO_CUTTING;
2583 if (element == EL_QUICKSAND_EMPTYING ||
2584 element == EL_QUICKSAND_FAST_EMPTYING ||
2585 element == EL_MAGIC_WALL_EMPTYING ||
2586 element == EL_BD_MAGIC_WALL_EMPTYING ||
2587 element == EL_DC_MAGIC_WALL_EMPTYING ||
2588 element == EL_AMOEBA_DROPPING)
2589 cut_mode = CUT_ABOVE;
2590 else if (element == EL_QUICKSAND_FILLING ||
2591 element == EL_QUICKSAND_FAST_FILLING ||
2592 element == EL_MAGIC_WALL_FILLING ||
2593 element == EL_BD_MAGIC_WALL_FILLING ||
2594 element == EL_DC_MAGIC_WALL_FILLING)
2595 cut_mode = CUT_BELOW;
2598 if (lx == 9 && ly == 1)
2599 printf("::: %s [%d] [%d, %d] [%d]\n",
2600 EL_NAME(TILE_GFX_ELEMENT(lx, ly)),
2601 el_act2crm(TILE_GFX_ELEMENT(lx, ly), ACTION_DEFAULT),
2602 element_info[EL_QUICKSAND_EMPTYING].graphic[ACTION_DEFAULT],
2603 element_info[EL_QUICKSAND_EMPTYING].crumbled[ACTION_DEFAULT],
2604 GFX_CRUMBLED(TILE_GFX_ELEMENT(lx, ly)));
2607 if (cut_mode == CUT_ABOVE)
2609 DrawScreenElement(x, y, element);
2611 DrawScreenElementShifted(x, y, 0, 0, element, NO_CUTTING);
2614 DrawScreenElement(x, y, EL_EMPTY);
2617 DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
2618 else if (cut_mode == NO_CUTTING)
2619 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
2622 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
2625 if (cut_mode == CUT_BELOW &&
2626 IN_LEV_FIELD(lx, ly + 1) && IN_SCR_FIELD(x, y + 1))
2627 DrawLevelElement(lx, ly + 1, element);
2631 if (content == EL_ACID)
2633 int dir = MovDir[lx][ly];
2634 int newlx = lx + (dir == MV_LEFT ? -1 : dir == MV_RIGHT ? +1 : 0);
2635 int newly = ly + (dir == MV_UP ? -1 : dir == MV_DOWN ? +1 : 0);
2637 DrawLevelElementThruMask(newlx, newly, EL_ACID);
2640 else if (IS_BLOCKED(lx, ly))
2645 boolean cut_mode = NO_CUTTING;
2646 int element_old, content_old;
2648 Blocked2Moving(lx, ly, &oldx, &oldy);
2651 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
2652 MovDir[oldx][oldy] == MV_RIGHT);
2654 element_old = Feld[oldx][oldy];
2655 content_old = Store[oldx][oldy];
2657 if (element_old == EL_QUICKSAND_EMPTYING ||
2658 element_old == EL_QUICKSAND_FAST_EMPTYING ||
2659 element_old == EL_MAGIC_WALL_EMPTYING ||
2660 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
2661 element_old == EL_DC_MAGIC_WALL_EMPTYING ||
2662 element_old == EL_AMOEBA_DROPPING)
2663 cut_mode = CUT_ABOVE;
2665 DrawScreenElement(x, y, EL_EMPTY);
2668 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
2670 else if (cut_mode == NO_CUTTING)
2671 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
2674 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
2677 else if (IS_DRAWABLE(element))
2678 DrawScreenElement(x, y, element);
2680 DrawScreenElement(x, y, EL_EMPTY);
2683 void DrawLevelField(int x, int y)
2685 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
2686 DrawScreenField(SCREENX(x), SCREENY(y));
2687 else if (IS_MOVING(x, y))
2691 Moving2Blocked(x, y, &newx, &newy);
2692 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
2693 DrawScreenField(SCREENX(newx), SCREENY(newy));
2695 else if (IS_BLOCKED(x, y))
2699 Blocked2Moving(x, y, &oldx, &oldy);
2700 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
2701 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
2705 void DrawMiniElement(int x, int y, int element)
2709 graphic = el2edimg(element);
2710 DrawMiniGraphic(x, y, graphic);
2713 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
2715 int x = sx + scroll_x, y = sy + scroll_y;
2717 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
2718 DrawMiniElement(sx, sy, EL_EMPTY);
2719 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
2720 DrawMiniElement(sx, sy, Feld[x][y]);
2722 DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
2725 void DrawEnvelopeBackgroundTiles(int graphic, int startx, int starty,
2726 int x, int y, int xsize, int ysize,
2727 int tile_width, int tile_height)
2731 int dst_x = startx + x * tile_width;
2732 int dst_y = starty + y * tile_height;
2733 int width = graphic_info[graphic].width;
2734 int height = graphic_info[graphic].height;
2735 int inner_width_raw = MAX(width - 2 * tile_width, tile_width);
2736 int inner_height_raw = MAX(height - 2 * tile_height, tile_height);
2737 int inner_width = inner_width_raw - (inner_width_raw % tile_width);
2738 int inner_height = inner_height_raw - (inner_height_raw % tile_height);
2739 int inner_sx = (width >= 3 * tile_width ? tile_width : 0);
2740 int inner_sy = (height >= 3 * tile_height ? tile_height : 0);
2741 boolean draw_masked = graphic_info[graphic].draw_masked;
2743 getFixedGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
2745 if (src_bitmap == NULL || width < tile_width || height < tile_height)
2747 ClearRectangle(drawto, dst_x, dst_y, tile_width, tile_height);
2751 src_x += (x == 0 ? 0 : x == xsize - 1 ? width - tile_width :
2752 inner_sx + (x - 1) * tile_width % inner_width);
2753 src_y += (y == 0 ? 0 : y == ysize - 1 ? height - tile_height :
2754 inner_sy + (y - 1) * tile_height % inner_height);
2758 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
2759 dst_x - src_x, dst_y - src_y);
2760 BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, tile_width, tile_height,
2764 BlitBitmap(src_bitmap, drawto, src_x, src_y, tile_width, tile_height,
2768 void DrawEnvelopeBackground(int graphic, int startx, int starty,
2769 int x, int y, int xsize, int ysize, int font_nr)
2771 int font_width = getFontWidth(font_nr);
2772 int font_height = getFontHeight(font_nr);
2774 DrawEnvelopeBackgroundTiles(graphic, startx, starty, x, y, xsize, ysize,
2775 font_width, font_height);
2778 void AnimateEnvelope(int envelope_nr, int anim_mode, int action)
2780 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2781 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
2782 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
2783 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2784 boolean no_delay = (tape.warp_forward);
2785 unsigned int anim_delay = 0;
2786 int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
2787 int anim_delay_value = (no_delay ? 0 : frame_delay_value);
2788 int font_nr = FONT_ENVELOPE_1 + envelope_nr;
2789 int font_width = getFontWidth(font_nr);
2790 int font_height = getFontHeight(font_nr);
2791 int max_xsize = level.envelope[envelope_nr].xsize;
2792 int max_ysize = level.envelope[envelope_nr].ysize;
2793 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
2794 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
2795 int xend = max_xsize;
2796 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
2797 int xstep = (xstart < xend ? 1 : 0);
2798 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
2801 for (x = xstart, y = ystart; x <= xend && y <= yend; x += xstep, y += ystep)
2803 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
2804 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
2805 int sx = SX + (SXSIZE - xsize * font_width) / 2;
2806 int sy = SY + (SYSIZE - ysize * font_height) / 2;
2809 SetDrawtoField(DRAW_BUFFERED);
2812 BlitScreenToBitmap(backbuffer);
2814 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
2817 SetDrawtoField(DRAW_BACKBUFFER);
2819 for (yy = 0; yy < ysize; yy++)
2820 for (xx = 0; xx < xsize; xx++)
2821 DrawEnvelopeBackground(graphic, sx, sy, xx, yy, xsize, ysize, font_nr);
2824 DrawTextBuffer(sx + font_width, sy + font_height,
2825 level.envelope[envelope_nr].text, font_nr, max_xsize,
2826 xsize - 2, ysize - 2, 0, mask_mode,
2827 level.envelope[envelope_nr].autowrap,
2828 level.envelope[envelope_nr].centered, FALSE);
2830 DrawTextToTextArea(sx + font_width, sy + font_height,
2831 level.envelope[envelope_nr].text, font_nr, max_xsize,
2832 xsize - 2, ysize - 2, mask_mode);
2835 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
2838 WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
2842 void ShowEnvelope(int envelope_nr)
2844 int element = EL_ENVELOPE_1 + envelope_nr;
2845 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2846 int sound_opening = element_info[element].sound[ACTION_OPENING];
2847 int sound_closing = element_info[element].sound[ACTION_CLOSING];
2848 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2849 boolean no_delay = (tape.warp_forward);
2850 int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
2851 int wait_delay_value = (no_delay ? 0 : normal_delay_value);
2852 int anim_mode = graphic_info[graphic].anim_mode;
2853 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
2854 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
2856 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
2858 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
2860 if (anim_mode == ANIM_DEFAULT)
2861 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_OPENING);
2863 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_OPENING);
2866 Delay(wait_delay_value);
2868 WaitForEventToContinue();
2870 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
2872 if (anim_mode != ANIM_NONE)
2873 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_CLOSING);
2875 if (anim_mode == ANIM_DEFAULT)
2876 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_CLOSING);
2878 game.envelope_active = FALSE;
2880 SetDrawtoField(DRAW_BUFFERED);
2882 redraw_mask |= REDRAW_FIELD;
2886 static void setRequestPosition(int *x, int *y, boolean add_border_size)
2888 int border_size = request.border_size;
2889 int sx_center = (request.x != -1 ? request.x : SX + SXSIZE / 2);
2890 int sy_center = (request.y != -1 ? request.y : SY + SYSIZE / 2);
2891 int sx = sx_center - request.width / 2;
2892 int sy = sy_center - request.height / 2;
2894 if (add_border_size)
2904 void DrawEnvelopeRequest(char *text)
2906 char *text_final = text;
2907 char *text_door_style = NULL;
2908 int graphic = IMG_BACKGROUND_REQUEST;
2909 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
2910 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
2911 int font_nr = FONT_REQUEST;
2912 int font_width = getFontWidth(font_nr);
2913 int font_height = getFontHeight(font_nr);
2914 int border_size = request.border_size;
2915 int line_spacing = request.line_spacing;
2916 int line_height = font_height + line_spacing;
2917 int text_width = request.width - 2 * border_size;
2918 int text_height = request.height - 2 * border_size;
2919 int line_length = text_width / font_width;
2920 int max_lines = text_height / line_height;
2921 int width = request.width;
2922 int height = request.height;
2923 int tile_size = request.step_offset;
2924 int x_steps = width / tile_size;
2925 int y_steps = height / tile_size;
2929 if (request.wrap_single_words)
2931 char *src_text_ptr, *dst_text_ptr;
2933 text_door_style = checked_malloc(2 * strlen(text) + 1);
2935 src_text_ptr = text;
2936 dst_text_ptr = text_door_style;
2938 while (*src_text_ptr)
2940 if (*src_text_ptr == ' ' ||
2941 *src_text_ptr == '?' ||
2942 *src_text_ptr == '!')
2943 *dst_text_ptr++ = '\n';
2945 if (*src_text_ptr != ' ')
2946 *dst_text_ptr++ = *src_text_ptr;
2951 *dst_text_ptr = '\0';
2953 text_final = text_door_style;
2956 setRequestPosition(&sx, &sy, FALSE);
2958 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
2960 for (y = 0; y < y_steps; y++)
2961 for (x = 0; x < x_steps; x++)
2962 DrawEnvelopeBackgroundTiles(graphic, sx, sy,
2963 x, y, x_steps, y_steps,
2964 tile_size, tile_size);
2966 DrawTextBuffer(sx + border_size, sy + border_size, text_final, font_nr,
2967 line_length, -1, max_lines, line_spacing, mask_mode,
2968 request.autowrap, request.centered, FALSE);
2970 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
2971 RedrawGadget(tool_gadget[i]);
2973 // store readily prepared envelope request for later use when animating
2974 BlitBitmap(backbuffer, bitmap_db_cross, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2978 BlitBitmap(bitmap_db_store, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2979 BlitBitmap(bitmap_db_cross, backbuffer, sx, sy, width, height, sx, sy);
2981 redraw_mask = REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
2986 BlitBitmap(bitmap_db_store, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2988 redraw_mask = REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
2994 if (text_door_style)
2995 free(text_door_style);
3000 void AnimateEnvelopeRequest(int anim_mode, int action)
3002 int graphic = IMG_BACKGROUND_REQUEST;
3003 boolean draw_masked = graphic_info[graphic].draw_masked;
3005 int delay_value_normal = request.step_delay;
3006 int delay_value_fast = delay_value_normal / 2;
3008 int delay_value_normal = GameFrameDelay;
3009 int delay_value_fast = FfwdFrameDelay;
3011 boolean ffwd_delay = (tape.playing && tape.fast_forward);
3012 boolean no_delay = (tape.warp_forward);
3013 int delay_value = (ffwd_delay ? delay_value_fast : delay_value_normal);
3014 int anim_delay_value = (no_delay ? 0 : delay_value + 500 * 0);
3015 unsigned int anim_delay = 0;
3017 int width = request.width;
3018 int height = request.height;
3019 int tile_size = request.step_offset;
3020 int max_xsize = width / tile_size;
3021 int max_ysize = height / tile_size;
3022 int max_xsize_inner = max_xsize - 2;
3023 int max_ysize_inner = max_ysize - 2;
3025 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize_inner : 0);
3026 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize_inner : 0);
3027 int xend = max_xsize_inner;
3028 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize_inner : 0);
3029 int xstep = (xstart < xend ? 1 : 0);
3030 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
3033 for (x = xstart, y = ystart; x <= xend && y <= yend; x += xstep, y += ystep)
3035 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
3036 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
3037 int sx_center = (request.x != -1 ? request.x : SX + SXSIZE / 2);
3038 int sy_center = (request.y != -1 ? request.y : SY + SYSIZE / 2);
3039 int src_x = sx_center - width / 2;
3040 int src_y = sy_center - height / 2;
3041 int dst_x = sx_center - xsize * tile_size / 2;
3042 int dst_y = sy_center - ysize * tile_size / 2;
3043 int xsize_size_left = (xsize - 1) * tile_size;
3044 int ysize_size_top = (ysize - 1) * tile_size;
3045 int max_xsize_pos = (max_xsize - 1) * tile_size;
3046 int max_ysize_pos = (max_ysize - 1) * tile_size;
3049 BlitBitmap(bitmap_db_store, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
3052 for (yy = 0; yy < 2; yy++)
3054 for (xx = 0; xx < 2; xx++)
3056 int src_xx = src_x + xx * max_xsize_pos;
3057 int src_yy = src_y + yy * max_ysize_pos;
3058 int dst_xx = dst_x + xx * xsize_size_left;
3059 int dst_yy = dst_y + yy * ysize_size_top;
3060 int xx_size = (xx ? tile_size : xsize_size_left);
3061 int yy_size = (yy ? tile_size : ysize_size_top);
3064 BlitBitmapMasked(bitmap_db_cross, backbuffer,
3065 src_xx, src_yy, xx_size, yy_size, dst_xx, dst_yy);
3067 BlitBitmap(bitmap_db_cross, backbuffer,
3068 src_xx, src_yy, xx_size, yy_size, dst_xx, dst_yy);
3072 BlitBitmap(bitmap_db_cross, backbuffer,
3074 xsize_size_left, ysize_size_top,
3076 BlitBitmap(bitmap_db_cross, backbuffer,
3077 src_x + max_xsize_pos, src_y,
3078 tile_size, ysize_size_top,
3079 dst_x + xsize_size_left, dst_y);
3080 BlitBitmap(bitmap_db_cross, backbuffer,
3081 src_x, src_y + max_ysize_pos,
3082 xsize_size_left, tile_size,
3083 dst_x, dst_y + ysize_size_top);
3084 BlitBitmap(bitmap_db_cross, backbuffer,
3085 src_x + max_xsize_pos, src_y + max_ysize_pos,
3086 tile_size, tile_size,
3087 dst_x + xsize_size_left, dst_y + ysize_size_top);
3091 redraw_mask = REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
3092 // redraw_mask |= REDRAW_ALL | REDRAW_FROM_BACKBUFFER;
3094 /* CHECK AGAIN (previous code reactivated) */
3095 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
3105 WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
3111 void AnimateEnvelopeRequest(char *text, int anim_mode, int action)
3114 int envelope_nr = 0;
3117 int graphic = IMG_BACKGROUND_REQUEST;
3119 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
3121 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
3122 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
3123 boolean ffwd_delay = (tape.playing && tape.fast_forward);
3124 boolean no_delay = (tape.warp_forward);
3125 unsigned int anim_delay = 0;
3126 int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
3127 int anim_delay_value = (no_delay ? 0 : frame_delay_value + 500 * 0);
3129 int max_word_len = maxWordLengthInString(text);
3130 int font_nr = (max_word_len > 7 ? FONT_TEXT_1 : FONT_TEXT_2);
3132 int font_nr = FONT_ENVELOPE_1 + envelope_nr;
3134 int font_width = getFontWidth(font_nr);
3135 int font_height = getFontHeight(font_nr);
3136 int line_spacing = 2 * 1;
3140 int max_xsize = DXSIZE / font_width;
3141 // int max_ysize = DYSIZE / font_height;
3142 int max_ysize = DYSIZE / (font_height + line_spacing);
3144 int max_xsize = 7; /* tools.c: MAX_REQUEST_LINE_FONT1_LEN == 7 */
3145 int max_ysize = 13; /* tools.c: MAX_REQUEST_LINES == 13 */
3149 int max_xsize = level.envelope[envelope_nr].xsize;
3150 int max_ysize = level.envelope[envelope_nr].ysize;
3152 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
3153 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
3154 int xend = max_xsize;
3155 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
3156 int xstep = (xstart < xend ? 1 : 0);
3157 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
3162 char *text_copy = getStringCopy(text);
3165 font_nr = FONT_TEXT_2;
3167 if (maxWordLengthInString(text) > 7) /* MAX_REQUEST_LINE_FONT1_LEN == 7 */
3169 max_xsize = 10; /* tools.c: MAX_REQUEST_LINE_FONT2_LEN == 10 */
3170 font_nr = FONT_TEXT_1;
3173 int max_word_len = 0;
3175 char *text_copy = getStringCopy(text);
3177 font_nr = FONT_TEXT_2;
3179 for (text_ptr = text; *text_ptr; text_ptr++)
3181 max_word_len = (*text_ptr != ' ' ? max_word_len + 1 : 0);
3183 if (max_word_len > 7) /* tools.c: MAX_REQUEST_LINE_FONT1_LEN == 7 */
3185 max_xsize = 10; /* tools.c: MAX_REQUEST_LINE_FONT2_LEN == 10 */
3186 font_nr = FONT_TEXT_1;
3195 for (text_ptr = text_copy; *text_ptr; text_ptr++)
3196 if (*text_ptr == ' ')
3201 dDX = SX + (SXSIZE - DXSIZE) / 2 - DX;
3202 dDY = SY + (SYSIZE - DYSIZE) / 2 - DY;
3204 dDX = SX + SXSIZE / 2 - max_xsize * font_width / 2 - DX;
3205 dDY = SY + SYSIZE / 2 - max_ysize * font_height / 2 - DY;
3208 for (x = xstart, y = ystart; x <= xend && y <= yend; x += xstep, y += ystep)
3210 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
3211 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
3212 int sx = SX + (SXSIZE - xsize * font_width) / 2;
3213 // int sy = SX + (SYSIZE - ysize * font_height) / 2;
3214 int sy = SY + (SYSIZE - ysize * (font_height + line_spacing)) / 2;
3218 BlitBitmap(bitmap_db_store, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
3220 SetDrawtoField(DRAW_BUFFERED);
3223 BlitScreenToBitmap(backbuffer);
3225 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
3228 SetDrawtoField(DRAW_BACKBUFFER);
3231 for (yy = 0; yy < ysize; yy++)
3232 for (xx = 0; xx < xsize; xx++)
3233 DrawEnvelopeBackgroundTiles(graphic, sx, sy, xx, yy, xsize, ysize,
3234 getFontWidth(font_nr),
3235 getFontHeight(font_nr) + line_spacing);
3240 DrawTextBuffer(sx + font_width, sy + font_height + 8,
3241 text_copy, font_nr, max_xsize,
3242 xsize - 2, ysize - 2, line_spacing, mask_mode,
3243 FALSE, TRUE, FALSE);
3245 DrawTextBuffer(sx + font_width, sy + font_height,
3246 level.envelope[envelope_nr].text, font_nr, max_xsize,
3247 xsize - 2, ysize - 2, 0, mask_mode,
3248 level.envelope[envelope_nr].autowrap,
3249 level.envelope[envelope_nr].centered, FALSE);
3253 DrawTextToTextArea(sx + font_width, sy + font_height,
3254 level.envelope[envelope_nr].text, font_nr, max_xsize,
3255 xsize - 2, ysize - 2, mask_mode);
3258 /* copy request gadgets to door backbuffer */
3261 if ((ysize - 2) > 13)
3262 BlitBitmap(bitmap_db_door, drawto,
3263 DOOR_GFX_PAGEX1 + (DXSIZE - (xsize - 2) * font_width) / 2,
3264 DOOR_GFX_PAGEY1 + 13 * font_height,
3265 (xsize - 2) * font_width,
3266 (ysize - 2 - 13) * font_height,
3268 sy + font_height * (1 + 13));
3270 if ((ysize - 2) > 13)
3271 BlitBitmap(bitmap_db_door, drawto,
3272 DOOR_GFX_PAGEX1 + (DXSIZE - (xsize - 2) * font_width) / 2,
3273 DOOR_GFX_PAGEY1 + 11 * (font_height + line_spacing * 0),
3274 (xsize - 2) * font_width,
3275 (ysize - 2 - 13) * (font_height + line_spacing),
3277 sy + (font_height + line_spacing) * (1 + 13));
3279 if ((ysize - 2) > 13)
3280 BlitBitmap(bitmap_db_door, drawto,
3281 DOOR_GFX_PAGEX1 + (DXSIZE - (xsize - 2) * font_width) / 2,
3282 DOOR_GFX_PAGEY1 + 13 * font_height,
3283 (xsize - 2) * font_width,
3284 (ysize - 2 - 13) * font_height,
3286 sy + font_height * (1 + 13));
3290 redraw_mask = REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
3291 // redraw_mask |= REDRAW_ALL | REDRAW_FROM_BACKBUFFER;
3293 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
3303 WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
3313 void ShowEnvelopeRequest(char *text, unsigned int req_state, int action)
3316 int last_game_status = game_status; /* save current game status */
3317 // int last_draw_background_mask = gfx.draw_background_mask;
3320 int graphic = IMG_BACKGROUND_REQUEST;
3321 int sound_opening = SND_REQUEST_OPENING;
3322 int sound_closing = SND_REQUEST_CLOSING;
3324 int envelope_nr = 0;
3325 int element = EL_ENVELOPE_1 + envelope_nr;
3326 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
3327 int sound_opening = element_info[element].sound[ACTION_OPENING];
3328 int sound_closing = element_info[element].sound[ACTION_CLOSING];
3331 boolean ffwd_delay = (tape.playing && tape.fast_forward);
3332 boolean no_delay = (tape.warp_forward);
3333 int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
3334 int wait_delay_value = (no_delay ? 0 : normal_delay_value);
3336 int anim_mode = graphic_info[graphic].anim_mode;
3337 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
3338 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
3340 char *text_copy = getStringCopy(text);
3343 for (text_ptr = text_copy; *text_ptr; text_ptr++)
3344 if (*text_ptr == ' ')
3349 if (game_status == GAME_MODE_PLAYING)
3353 BlitScreenToBitmap(backbuffer);
3355 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
3356 BlitScreenToBitmap_EM(backbuffer);
3357 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
3358 BlitScreenToBitmap_SP(backbuffer);
3360 BlitScreenToBitmap_RND(backbuffer);
3363 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
3364 BlitScreenToBitmap_EM(backbuffer);
3365 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
3366 BlitScreenToBitmap_SP(backbuffer);
3369 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
3374 SetDrawtoField(DRAW_BACKBUFFER);
3376 // SetDrawBackgroundMask(REDRAW_NONE);
3378 if (action == ACTION_OPENING)
3380 BlitBitmap(backbuffer, bitmap_db_store, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
3383 if (req_state & REQ_ASK)
3385 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
3386 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
3388 else if (req_state & REQ_CONFIRM)
3390 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
3392 else if (req_state & REQ_PLAYER)
3394 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
3395 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
3396 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
3397 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
3402 DrawEnvelopeRequest(text);
3404 DrawEnvelopeRequest(text_copy);
3407 if (game_status != GAME_MODE_MAIN)
3411 /* force DOOR font inside door area */
3412 game_status = GAME_MODE_PSEUDO_DOOR;
3415 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
3417 if (action == ACTION_OPENING)
3419 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
3421 if (anim_mode == ANIM_DEFAULT)
3422 AnimateEnvelopeRequest(ANIM_DEFAULT, ACTION_OPENING);
3424 AnimateEnvelopeRequest(main_anim_mode, ACTION_OPENING);
3428 Delay(wait_delay_value);
3430 WaitForEventToContinue();
3435 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
3437 if (anim_mode != ANIM_NONE)
3438 AnimateEnvelopeRequest(main_anim_mode, ACTION_CLOSING);
3440 if (anim_mode == ANIM_DEFAULT)
3441 AnimateEnvelopeRequest(ANIM_DEFAULT, ACTION_CLOSING);
3444 game.envelope_active = FALSE;
3447 // game_status = last_game_status; /* restore current game status */
3450 /* !!! CHECK AGAIN (SEE BELOW) !!! */
3451 game_status = last_game_status; /* restore current game status */
3454 if (action == ACTION_CLOSING)
3456 if (game_status != GAME_MODE_MAIN)
3459 BlitBitmap(bitmap_db_store, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
3462 SetDrawtoField(DRAW_BUFFERED);
3465 // SetDrawBackgroundMask(last_draw_background_mask);
3468 redraw_mask = REDRAW_FIELD;
3469 // redraw_mask |= REDRAW_ALL;
3471 /* CHECK AGAIN (previous code reactivated) */
3472 redraw_mask |= REDRAW_FIELD;
3476 if (game_status == GAME_MODE_MAIN)
3482 /* (important: after "BackToFront()", but before "SetDrawtoField()") */
3483 game_status = last_game_status; /* restore current game status */
3487 if (action == ACTION_CLOSING &&
3488 game_status == GAME_MODE_PLAYING &&
3489 level.game_engine_type == GAME_ENGINE_TYPE_RND)
3490 SetDrawtoField(DRAW_BUFFERED);
3492 if (game_status == GAME_MODE_PLAYING &&
3493 level.game_engine_type == GAME_ENGINE_TYPE_RND)
3494 SetDrawtoField(DRAW_BUFFERED);
3506 void DrawPreviewElement(int dst_x, int dst_y, int element, int tilesize)
3510 int graphic = el2preimg(element);
3512 getSizedGraphicSource(graphic, 0, tilesize, &src_bitmap, &src_x, &src_y);
3513 BlitBitmap(src_bitmap, drawto, src_x, src_y, tilesize, tilesize, dst_x,dst_y);
3516 void DrawLevel(int draw_background_mask)
3521 SetMainBackgroundImage(IMG_BACKGROUND_PLAYING);
3522 SetDrawBackgroundMask(draw_background_mask);
3525 SetMainBackgroundImage(IMG_BACKGROUND_PLAYING);
3526 SetDrawBackgroundMask(REDRAW_FIELD);
3528 SetDrawBackgroundMask(REDRAW_NONE);
3534 for (x = BX1; x <= BX2; x++)
3535 for (y = BY1; y <= BY2; y++)
3536 DrawScreenField(x, y);
3538 redraw_mask |= REDRAW_FIELD;
3541 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
3545 for (x = 0; x < size_x; x++)
3546 for (y = 0; y < size_y; y++)
3547 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
3549 redraw_mask |= REDRAW_FIELD;
3552 static void DrawPreviewLevelPlayfieldExt(int from_x, int from_y)
3554 boolean show_level_border = (BorderElement != EL_EMPTY);
3555 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
3556 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
3557 int tile_size = preview.tile_size;
3558 int preview_width = preview.xsize * tile_size;
3559 int preview_height = preview.ysize * tile_size;
3560 int real_preview_xsize = MIN(level_xsize, preview.xsize);
3561 int real_preview_ysize = MIN(level_ysize, preview.ysize);
3562 int real_preview_width = real_preview_xsize * tile_size;
3563 int real_preview_height = real_preview_ysize * tile_size;
3564 int dst_x = SX + ALIGNED_XPOS(preview.x, preview_width, preview.align);
3565 int dst_y = SY + ALIGNED_YPOS(preview.y, preview_height, preview.valign);
3569 if (!IN_GFX_FIELD_FULL(dst_x, dst_y + preview_height - 1))
3574 dst_x += (preview_width - real_preview_width) / 2;
3575 dst_y += (preview_height - real_preview_height) / 2;
3577 DrawBackground(dst_x, dst_y, real_preview_width, real_preview_height);
3579 DrawBackground(dst_x, dst_y, preview_width, preview_height);
3581 dst_x += (preview_width - real_preview_width) / 2;
3582 dst_y += (preview_height - real_preview_height) / 2;
3585 for (x = 0; x < real_preview_xsize; x++)
3587 for (y = 0; y < real_preview_ysize; y++)
3589 int lx = from_x + x + (show_level_border ? -1 : 0);
3590 int ly = from_y + y + (show_level_border ? -1 : 0);
3591 int element = (IN_LEV_FIELD(lx, ly) ? level.field[lx][ly] :
3592 getBorderElement(lx, ly));
3594 DrawPreviewElement(dst_x + x * tile_size, dst_y + y * tile_size,
3595 element, tile_size);
3599 redraw_mask |= REDRAW_MICROLEVEL;
3602 #define MICROLABEL_EMPTY 0
3603 #define MICROLABEL_LEVEL_NAME 1
3604 #define MICROLABEL_LEVEL_AUTHOR_HEAD 2
3605 #define MICROLABEL_LEVEL_AUTHOR 3
3606 #define MICROLABEL_IMPORTED_FROM_HEAD 4
3607 #define MICROLABEL_IMPORTED_FROM 5
3608 #define MICROLABEL_IMPORTED_BY_HEAD 6
3609 #define MICROLABEL_IMPORTED_BY 7
3611 static int getMaxTextLength(struct TextPosInfo *pos, int font_nr)
3613 int max_text_width = SXSIZE;
3614 int font_width = getFontWidth(font_nr);
3616 if (pos->align == ALIGN_CENTER)
3617 max_text_width = (pos->x < SXSIZE / 2 ? pos->x * 2 : (SXSIZE - pos->x) * 2);
3618 else if (pos->align == ALIGN_RIGHT)
3619 max_text_width = pos->x;
3621 max_text_width = SXSIZE - pos->x;
3623 return max_text_width / font_width;
3626 static void DrawPreviewLevelLabelExt(int mode)
3628 struct TextPosInfo *pos = &menu.main.text.level_info_2;
3629 char label_text[MAX_OUTPUT_LINESIZE + 1];
3630 int max_len_label_text;
3632 int font_nr = pos->font;
3635 if (!IN_GFX_FIELD_FULL(pos->x, pos->y + getFontHeight(pos->font)))
3638 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
3639 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
3640 mode == MICROLABEL_IMPORTED_BY_HEAD)
3641 font_nr = pos->font_alt;
3643 int font_nr = FONT_TEXT_2;
3646 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
3647 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
3648 mode == MICROLABEL_IMPORTED_BY_HEAD)
3649 font_nr = FONT_TEXT_3;
3653 max_len_label_text = getMaxTextLength(pos, font_nr);
3655 max_len_label_text = SXSIZE / getFontWidth(font_nr);
3659 if (pos->size != -1)
3660 max_len_label_text = pos->size;
3663 for (i = 0; i < max_len_label_text; i++)
3664 label_text[i] = ' ';
3665 label_text[max_len_label_text] = '\0';
3667 if (strlen(label_text) > 0)
3670 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
3672 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
3673 int lypos = MICROLABEL2_YPOS;
3675 DrawText(lxpos, lypos, label_text, font_nr);
3680 (mode == MICROLABEL_LEVEL_NAME ? level.name :
3681 mode == MICROLABEL_LEVEL_AUTHOR_HEAD ? "created by" :
3682 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
3683 mode == MICROLABEL_IMPORTED_FROM_HEAD ? "imported from" :
3684 mode == MICROLABEL_IMPORTED_FROM ? leveldir_current->imported_from :
3685 mode == MICROLABEL_IMPORTED_BY_HEAD ? "imported by" :
3686 mode == MICROLABEL_IMPORTED_BY ? leveldir_current->imported_by :""),
3687 max_len_label_text);
3688 label_text[max_len_label_text] = '\0';
3690 if (strlen(label_text) > 0)
3693 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
3695 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
3696 int lypos = MICROLABEL2_YPOS;
3698 DrawText(lxpos, lypos, label_text, font_nr);
3702 redraw_mask |= REDRAW_MICROLEVEL;
3705 static void DrawPreviewLevelExt(boolean restart)
3707 static unsigned int scroll_delay = 0;
3708 static unsigned int label_delay = 0;
3709 static int from_x, from_y, scroll_direction;
3710 static int label_state, label_counter;
3711 unsigned int scroll_delay_value = preview.step_delay;
3712 boolean show_level_border = (BorderElement != EL_EMPTY);
3713 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
3714 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
3715 int last_game_status = game_status; /* save current game status */
3718 /* force PREVIEW font on preview level */
3719 game_status = GAME_MODE_PSEUDO_PREVIEW;
3727 if (preview.anim_mode == ANIM_CENTERED)
3729 if (level_xsize > preview.xsize)
3730 from_x = (level_xsize - preview.xsize) / 2;
3731 if (level_ysize > preview.ysize)
3732 from_y = (level_ysize - preview.ysize) / 2;
3735 from_x += preview.xoffset;
3736 from_y += preview.yoffset;
3738 scroll_direction = MV_RIGHT;
3742 DrawPreviewLevelPlayfieldExt(from_x, from_y);
3743 DrawPreviewLevelLabelExt(label_state);
3745 /* initialize delay counters */
3746 DelayReached(&scroll_delay, 0);
3747 DelayReached(&label_delay, 0);
3749 if (leveldir_current->name)
3751 struct TextPosInfo *pos = &menu.main.text.level_info_1;
3752 char label_text[MAX_OUTPUT_LINESIZE + 1];
3754 int font_nr = pos->font;
3756 int font_nr = FONT_TEXT_1;
3759 int max_len_label_text = getMaxTextLength(pos, font_nr);
3761 int max_len_label_text = SXSIZE / getFontWidth(font_nr);
3769 if (pos->size != -1)
3770 max_len_label_text = pos->size;
3773 strncpy(label_text, leveldir_current->name, max_len_label_text);
3774 label_text[max_len_label_text] = '\0';
3777 if (IN_GFX_FIELD_FULL(pos->x, pos->y + getFontHeight(pos->font)))
3778 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
3780 lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
3781 lypos = SY + MICROLABEL1_YPOS;
3783 DrawText(lxpos, lypos, label_text, font_nr);
3787 game_status = last_game_status; /* restore current game status */
3792 /* scroll preview level, if needed */
3793 if (preview.anim_mode != ANIM_NONE &&
3794 (level_xsize > preview.xsize || level_ysize > preview.ysize) &&
3795 DelayReached(&scroll_delay, scroll_delay_value))
3797 switch (scroll_direction)
3802 from_x -= preview.step_offset;
3803 from_x = (from_x < 0 ? 0 : from_x);
3806 scroll_direction = MV_UP;
3810 if (from_x < level_xsize - preview.xsize)
3812 from_x += preview.step_offset;
3813 from_x = (from_x > level_xsize - preview.xsize ?
3814 level_xsize - preview.xsize : from_x);
3817 scroll_direction = MV_DOWN;
3823 from_y -= preview.step_offset;
3824 from_y = (from_y < 0 ? 0 : from_y);
3827 scroll_direction = MV_RIGHT;
3831 if (from_y < level_ysize - preview.ysize)
3833 from_y += preview.step_offset;
3834 from_y = (from_y > level_ysize - preview.ysize ?
3835 level_ysize - preview.ysize : from_y);
3838 scroll_direction = MV_LEFT;
3845 DrawPreviewLevelPlayfieldExt(from_x, from_y);
3848 /* !!! THIS ALL SUCKS -- SHOULD BE CLEANLY REWRITTEN !!! */
3849 /* redraw micro level label, if needed */
3850 if (!strEqual(level.name, NAMELESS_LEVEL_NAME) &&
3851 !strEqual(level.author, ANONYMOUS_NAME) &&
3852 !strEqual(level.author, leveldir_current->name) &&
3853 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
3855 int max_label_counter = 23;
3857 if (leveldir_current->imported_from != NULL &&
3858 strlen(leveldir_current->imported_from) > 0)
3859 max_label_counter += 14;
3860 if (leveldir_current->imported_by != NULL &&
3861 strlen(leveldir_current->imported_by) > 0)
3862 max_label_counter += 14;
3864 label_counter = (label_counter + 1) % max_label_counter;
3865 label_state = (label_counter >= 0 && label_counter <= 7 ?
3866 MICROLABEL_LEVEL_NAME :
3867 label_counter >= 9 && label_counter <= 12 ?
3868 MICROLABEL_LEVEL_AUTHOR_HEAD :
3869 label_counter >= 14 && label_counter <= 21 ?
3870 MICROLABEL_LEVEL_AUTHOR :
3871 label_counter >= 23 && label_counter <= 26 ?
3872 MICROLABEL_IMPORTED_FROM_HEAD :
3873 label_counter >= 28 && label_counter <= 35 ?
3874 MICROLABEL_IMPORTED_FROM :
3875 label_counter >= 37 && label_counter <= 40 ?
3876 MICROLABEL_IMPORTED_BY_HEAD :
3877 label_counter >= 42 && label_counter <= 49 ?
3878 MICROLABEL_IMPORTED_BY : MICROLABEL_EMPTY);
3880 if (leveldir_current->imported_from == NULL &&
3881 (label_state == MICROLABEL_IMPORTED_FROM_HEAD ||
3882 label_state == MICROLABEL_IMPORTED_FROM))
3883 label_state = (label_state == MICROLABEL_IMPORTED_FROM_HEAD ?
3884 MICROLABEL_IMPORTED_BY_HEAD : MICROLABEL_IMPORTED_BY);
3886 DrawPreviewLevelLabelExt(label_state);
3889 game_status = last_game_status; /* restore current game status */
3892 void DrawPreviewLevelInitial()
3894 DrawPreviewLevelExt(TRUE);
3897 void DrawPreviewLevelAnimation()
3899 DrawPreviewLevelExt(FALSE);
3902 inline void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
3903 int graphic, int sync_frame, int mask_mode)
3905 int frame = getGraphicAnimationFrame(graphic, sync_frame);
3907 if (mask_mode == USE_MASKING)
3908 DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
3910 DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
3913 inline void DrawFixedGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
3914 int graphic, int sync_frame,
3917 int frame = getGraphicAnimationFrame(graphic, sync_frame);
3919 if (mask_mode == USE_MASKING)
3920 DrawFixedGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
3922 DrawFixedGraphicExt(dst_bitmap, x, y, graphic, frame);
3925 inline void DrawGraphicAnimation(int x, int y, int graphic)
3927 int lx = LEVELX(x), ly = LEVELY(y);
3929 if (!IN_SCR_FIELD(x, y))
3933 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR,
3934 graphic, GfxFrame[lx][ly], NO_MASKING);
3936 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
3937 graphic, GfxFrame[lx][ly], NO_MASKING);
3939 MarkTileDirty(x, y);
3942 inline void DrawFixedGraphicAnimation(int x, int y, int graphic)
3944 int lx = LEVELX(x), ly = LEVELY(y);
3946 if (!IN_SCR_FIELD(x, y))
3949 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
3950 graphic, GfxFrame[lx][ly], NO_MASKING);
3951 MarkTileDirty(x, y);
3954 void DrawLevelGraphicAnimation(int x, int y, int graphic)
3956 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
3959 void DrawLevelElementAnimation(int x, int y, int element)
3961 int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
3963 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
3966 inline void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
3968 int sx = SCREENX(x), sy = SCREENY(y);
3970 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
3973 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
3976 DrawGraphicAnimation(sx, sy, graphic);
3979 if (GFX_CRUMBLED(TILE_GFX_ELEMENT(x, y)))
3980 DrawLevelFieldCrumbled(x, y);
3982 if (GFX_CRUMBLED(Feld[x][y]))
3983 DrawLevelFieldCrumbled(x, y);
3987 void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
3989 int sx = SCREENX(x), sy = SCREENY(y);
3992 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
3995 graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
3997 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
4000 DrawGraphicAnimation(sx, sy, graphic);
4002 if (GFX_CRUMBLED(element))
4003 DrawLevelFieldCrumbled(x, y);
4006 static int getPlayerGraphic(struct PlayerInfo *player, int move_dir)
4008 if (player->use_murphy)
4010 /* this works only because currently only one player can be "murphy" ... */
4011 static int last_horizontal_dir = MV_LEFT;
4012 int graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir);
4014 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
4015 last_horizontal_dir = move_dir;
4017 if (graphic == IMG_SP_MURPHY) /* undefined => use special graphic */
4019 int direction = (player->is_snapping ? move_dir : last_horizontal_dir);
4021 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
4027 return el_act_dir2img(player->artwork_element, player->GfxAction,move_dir);
4030 static boolean equalGraphics(int graphic1, int graphic2)
4032 struct GraphicInfo *g1 = &graphic_info[graphic1];
4033 struct GraphicInfo *g2 = &graphic_info[graphic2];
4035 return (g1->bitmap == g2->bitmap &&
4036 g1->src_x == g2->src_x &&
4037 g1->src_y == g2->src_y &&
4038 g1->anim_frames == g2->anim_frames &&
4039 g1->anim_delay == g2->anim_delay &&
4040 g1->anim_mode == g2->anim_mode);
4043 void DrawAllPlayers()
4047 for (i = 0; i < MAX_PLAYERS; i++)
4048 if (stored_player[i].active)
4049 DrawPlayer(&stored_player[i]);
4052 void DrawPlayerField(int x, int y)
4054 if (!IS_PLAYER(x, y))
4057 DrawPlayer(PLAYERINFO(x, y));
4060 #define DRAW_PLAYER_OVER_PUSHED_ELEMENT 1
4062 void DrawPlayer(struct PlayerInfo *player)
4064 int jx = player->jx;
4065 int jy = player->jy;
4066 int move_dir = player->MovDir;
4067 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? +1 : 0);
4068 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? +1 : 0);
4069 int last_jx = (player->is_moving ? jx - dx : jx);
4070 int last_jy = (player->is_moving ? jy - dy : jy);
4071 int next_jx = jx + dx;
4072 int next_jy = jy + dy;
4073 boolean player_is_moving = (player->MovPos ? TRUE : FALSE);
4074 boolean player_is_opaque = FALSE;
4075 int sx = SCREENX(jx), sy = SCREENY(jy);
4076 int sxx = 0, syy = 0;
4077 int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
4079 int action = ACTION_DEFAULT;
4080 int last_player_graphic = getPlayerGraphic(player, move_dir);
4081 int last_player_frame = player->Frame;
4084 /* GfxElement[][] is set to the element the player is digging or collecting;
4085 remove also for off-screen player if the player is not moving anymore */
4086 if (IN_LEV_FIELD(jx, jy) && !player_is_moving)
4087 GfxElement[jx][jy] = EL_UNDEFINED;
4089 if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
4093 if (!IN_LEV_FIELD(jx, jy))
4095 printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
4096 printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
4097 printf("DrawPlayerField(): This should never happen!\n");
4102 if (element == EL_EXPLOSION)
4105 action = (player->is_pushing ? ACTION_PUSHING :
4106 player->is_digging ? ACTION_DIGGING :
4107 player->is_collecting ? ACTION_COLLECTING :
4108 player->is_moving ? ACTION_MOVING :
4109 player->is_snapping ? ACTION_SNAPPING :
4110 player->is_dropping ? ACTION_DROPPING :
4111 player->is_waiting ? player->action_waiting : ACTION_DEFAULT);
4113 if (player->is_waiting)
4114 move_dir = player->dir_waiting;
4116 InitPlayerGfxAnimation(player, action, move_dir);
4118 /* ----------------------------------------------------------------------- */
4119 /* draw things in the field the player is leaving, if needed */
4120 /* ----------------------------------------------------------------------- */
4122 if (player->is_moving)
4124 if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
4126 DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
4128 if (last_element == EL_DYNAMITE_ACTIVE ||
4129 last_element == EL_EM_DYNAMITE_ACTIVE ||
4130 last_element == EL_SP_DISK_RED_ACTIVE)
4131 DrawDynamite(last_jx, last_jy);
4133 DrawLevelFieldThruMask(last_jx, last_jy);
4135 else if (last_element == EL_DYNAMITE_ACTIVE ||
4136 last_element == EL_EM_DYNAMITE_ACTIVE ||
4137 last_element == EL_SP_DISK_RED_ACTIVE)
4138 DrawDynamite(last_jx, last_jy);
4140 /* !!! this is not enough to prevent flickering of players which are
4141 moving next to each others without a free tile between them -- this
4142 can only be solved by drawing all players layer by layer (first the
4143 background, then the foreground etc.) !!! => TODO */
4144 else if (!IS_PLAYER(last_jx, last_jy))
4145 DrawLevelField(last_jx, last_jy);
4148 DrawLevelField(last_jx, last_jy);
4151 if (player->is_pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
4152 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
4155 if (!IN_SCR_FIELD(sx, sy))
4158 /* ----------------------------------------------------------------------- */
4159 /* draw things behind the player, if needed */
4160 /* ----------------------------------------------------------------------- */
4163 DrawLevelElement(jx, jy, Back[jx][jy]);
4164 else if (IS_ACTIVE_BOMB(element))
4165 DrawLevelElement(jx, jy, EL_EMPTY);
4168 if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
4170 int old_element = GfxElement[jx][jy];
4171 int old_graphic = el_act_dir2img(old_element, action, move_dir);
4172 int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
4174 if (GFX_CRUMBLED(old_element))
4175 DrawLevelFieldCrumbledDigging(jx, jy, move_dir, player->StepFrame);
4177 DrawGraphic(sx, sy, old_graphic, frame);
4179 if (graphic_info[old_graphic].anim_mode & ANIM_OPAQUE_PLAYER)
4180 player_is_opaque = TRUE;
4184 GfxElement[jx][jy] = EL_UNDEFINED;
4186 /* make sure that pushed elements are drawn with correct frame rate */
4188 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
4190 if (player->is_pushing && player->is_moving && !IS_ANIM_MODE_CE(graphic))
4191 GfxFrame[jx][jy] = player->StepFrame;
4193 if (player->is_pushing && player->is_moving)
4194 GfxFrame[jx][jy] = player->StepFrame;
4197 DrawLevelField(jx, jy);
4201 #if !DRAW_PLAYER_OVER_PUSHED_ELEMENT
4202 /* ----------------------------------------------------------------------- */
4203 /* draw player himself */
4204 /* ----------------------------------------------------------------------- */
4206 graphic = getPlayerGraphic(player, move_dir);
4208 /* in the case of changed player action or direction, prevent the current
4209 animation frame from being restarted for identical animations */
4210 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
4211 player->Frame = last_player_frame;
4213 frame = getGraphicAnimationFrame(graphic, player->Frame);
4217 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
4218 sxx = player->GfxPos;
4220 syy = player->GfxPos;
4223 if (!setup.soft_scrolling && ScreenMovPos)
4226 if (player_is_opaque)
4227 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
4229 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
4231 if (SHIELD_ON(player))
4233 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
4234 IMG_SHIELD_NORMAL_ACTIVE);
4235 int frame = getGraphicAnimationFrame(graphic, -1);
4237 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
4241 #if DRAW_PLAYER_OVER_PUSHED_ELEMENT
4244 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
4245 sxx = player->GfxPos;
4247 syy = player->GfxPos;
4251 /* ----------------------------------------------------------------------- */
4252 /* draw things the player is pushing, if needed */
4253 /* ----------------------------------------------------------------------- */
4256 printf("::: %d, %d [%d, %d] [%d]\n",
4257 player->is_pushing, player_is_moving, player->GfxAction,
4258 player->is_moving, player_is_moving);
4262 if (player->is_pushing && player->is_moving)
4264 int px = SCREENX(jx), py = SCREENY(jy);
4265 int pxx = (TILEX - ABS(sxx)) * dx;
4266 int pyy = (TILEY - ABS(syy)) * dy;
4267 int gfx_frame = GfxFrame[jx][jy];
4273 if (!IS_MOVING(jx, jy)) /* push movement already finished */
4275 element = Feld[next_jx][next_jy];
4276 gfx_frame = GfxFrame[next_jx][next_jy];
4279 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
4282 sync_frame = (IS_ANIM_MODE_CE(graphic) ? gfx_frame : player->StepFrame);
4283 frame = getGraphicAnimationFrame(graphic, sync_frame);
4285 frame = getGraphicAnimationFrame(graphic, player->StepFrame);
4288 /* draw background element under pushed element (like the Sokoban field) */
4290 if (game.use_masked_pushing && IS_MOVING(jx, jy))
4292 /* this allows transparent pushing animation over non-black background */
4295 DrawLevelElement(jx, jy, Back[jx][jy]);
4297 DrawLevelElement(jx, jy, EL_EMPTY);
4299 if (Back[next_jx][next_jy])
4300 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
4302 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
4304 else if (Back[next_jx][next_jy])
4305 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
4307 if (Back[next_jx][next_jy])
4308 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
4312 printf("::: %d, %d, %d, %d [%d] [%d, %d, %d] [%d] [%d, %d] [%d, %d]\n",
4313 jx, px, player->GfxPos, player->StepFrame,
4318 GfxFrame[jx][jy], GfxFrame[next_jx][next_jy]);
4322 /* do not draw (EM style) pushing animation when pushing is finished */
4323 /* (two-tile animations usually do not contain start and end frame) */
4324 if (graphic_info[graphic].double_movement && !IS_MOVING(jx, jy))
4325 DrawLevelElement(next_jx, next_jy, Feld[next_jx][next_jy]);
4327 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
4329 /* masked drawing is needed for EMC style (double) movement graphics */
4330 /* !!! (ONLY WHEN DRAWING PUSHED ELEMENT OVER THE PLAYER) !!! */
4331 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
4336 #if DRAW_PLAYER_OVER_PUSHED_ELEMENT
4337 /* ----------------------------------------------------------------------- */
4338 /* draw player himself */
4339 /* ----------------------------------------------------------------------- */
4341 graphic = getPlayerGraphic(player, move_dir);
4343 /* in the case of changed player action or direction, prevent the current
4344 animation frame from being restarted for identical animations */
4345 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
4346 player->Frame = last_player_frame;
4348 frame = getGraphicAnimationFrame(graphic, player->Frame);
4352 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
4353 sxx = player->GfxPos;
4355 syy = player->GfxPos;
4358 if (!setup.soft_scrolling && ScreenMovPos)
4361 if (player_is_opaque)
4362 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
4364 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
4366 if (SHIELD_ON(player))
4368 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
4369 IMG_SHIELD_NORMAL_ACTIVE);
4370 int frame = getGraphicAnimationFrame(graphic, -1);
4372 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
4376 /* ----------------------------------------------------------------------- */
4377 /* draw things in front of player (active dynamite or dynabombs) */
4378 /* ----------------------------------------------------------------------- */
4380 if (IS_ACTIVE_BOMB(element))
4382 graphic = el2img(element);
4383 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
4385 if (game.emulation == EMU_SUPAPLEX)
4386 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
4388 DrawGraphicThruMask(sx, sy, graphic, frame);
4391 if (player_is_moving && last_element == EL_EXPLOSION)
4393 int element = (GfxElement[last_jx][last_jy] != EL_UNDEFINED ?
4394 GfxElement[last_jx][last_jy] : EL_EMPTY);
4395 int graphic = el_act2img(element, ACTION_EXPLODING);
4396 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
4397 int phase = ExplodePhase[last_jx][last_jy] - 1;
4398 int frame = getGraphicAnimationFrame(graphic, phase - delay);
4401 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
4404 /* ----------------------------------------------------------------------- */
4405 /* draw elements the player is just walking/passing through/under */
4406 /* ----------------------------------------------------------------------- */
4408 if (player_is_moving)
4410 /* handle the field the player is leaving ... */
4411 if (IS_ACCESSIBLE_INSIDE(last_element))
4412 DrawLevelField(last_jx, last_jy);
4413 else if (IS_ACCESSIBLE_UNDER(last_element))
4414 DrawLevelFieldThruMask(last_jx, last_jy);
4417 /* do not redraw accessible elements if the player is just pushing them */
4418 if (!player_is_moving || !player->is_pushing)
4420 /* ... and the field the player is entering */
4421 if (IS_ACCESSIBLE_INSIDE(element))
4422 DrawLevelField(jx, jy);
4423 else if (IS_ACCESSIBLE_UNDER(element))
4424 DrawLevelFieldThruMask(jx, jy);
4427 MarkTileDirty(sx, sy);
4430 /* ------------------------------------------------------------------------- */
4432 void WaitForEventToContinue()
4434 boolean still_wait = TRUE;
4436 /* simulate releasing mouse button over last gadget, if still pressed */
4438 HandleGadgets(-1, -1, 0);
4440 button_status = MB_RELEASED;
4456 case EVENT_BUTTONPRESS:
4457 case EVENT_KEYPRESS:
4461 case EVENT_KEYRELEASE:
4462 ClearPlayerAction();
4466 HandleOtherEvents(&event);
4470 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
4477 /* don't eat all CPU time */
4482 #define MAX_REQUEST_LINES 13
4483 #define MAX_REQUEST_LINE_FONT1_LEN 7
4484 #define MAX_REQUEST_LINE_FONT2_LEN 10
4488 static int RequestHandleEvents(unsigned int req_state)
4490 int last_game_status = game_status; /* save current game status */
4494 button_status = MB_RELEASED;
4496 request_gadget_id = -1;
4509 case EVENT_BUTTONPRESS:
4510 case EVENT_BUTTONRELEASE:
4511 case EVENT_MOTIONNOTIFY:
4513 if (event.type == EVENT_MOTIONNOTIFY)
4515 if (!PointerInWindow(window))
4516 continue; /* window and pointer are on different screens */
4521 motion_status = TRUE;
4522 mx = ((MotionEvent *) &event)->x;
4523 my = ((MotionEvent *) &event)->y;
4527 motion_status = FALSE;
4528 mx = ((ButtonEvent *) &event)->x;
4529 my = ((ButtonEvent *) &event)->y;
4530 if (event.type == EVENT_BUTTONPRESS)
4531 button_status = ((ButtonEvent *) &event)->button;
4533 button_status = MB_RELEASED;
4536 /* this sets 'request_gadget_id' */
4537 HandleGadgets(mx, my, button_status);
4539 switch (request_gadget_id)
4541 case TOOL_CTRL_ID_YES:
4544 case TOOL_CTRL_ID_NO:
4547 case TOOL_CTRL_ID_CONFIRM:
4548 result = TRUE | FALSE;
4551 case TOOL_CTRL_ID_PLAYER_1:
4554 case TOOL_CTRL_ID_PLAYER_2:
4557 case TOOL_CTRL_ID_PLAYER_3:
4560 case TOOL_CTRL_ID_PLAYER_4:
4571 case EVENT_KEYPRESS:
4572 switch (GetEventKey((KeyEvent *)&event, TRUE))
4575 if (req_state & REQ_CONFIRM)
4584 #if defined(TARGET_SDL2)
4594 if (req_state & REQ_PLAYER)
4598 case EVENT_KEYRELEASE:
4599 ClearPlayerAction();
4603 HandleOtherEvents(&event);
4607 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
4609 int joy = AnyJoystick();
4611 if (joy & JOY_BUTTON_1)
4613 else if (joy & JOY_BUTTON_2)
4619 if (game_status == GAME_MODE_PLAYING && local_player->LevelSolved_GameEnd)
4621 HandleGameActions();
4627 if (!PendingEvent()) /* delay only if no pending events */
4632 game_status = GAME_MODE_PSEUDO_DOOR;
4638 game_status = last_game_status; /* restore current game status */
4646 if (!PendingEvent()) /* delay only if no pending events */
4649 /* don't eat all CPU time */
4659 static boolean RequestDoor(char *text, unsigned int req_state)
4661 unsigned int old_door_state;
4662 int last_game_status = game_status; /* save current game status */
4663 int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
4664 int font_nr = FONT_TEXT_2;
4669 if (maxWordLengthInString(text) > MAX_REQUEST_LINE_FONT1_LEN)
4671 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
4672 font_nr = FONT_TEXT_1;
4675 if (game_status == GAME_MODE_PLAYING)
4678 BlitScreenToBitmap(backbuffer);
4680 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
4681 BlitScreenToBitmap_EM(backbuffer);
4682 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
4683 BlitScreenToBitmap_SP(backbuffer);
4687 /* disable deactivated drawing when quick-loading level tape recording */
4688 if (tape.playing && tape.deactivate_display)
4689 TapeDeactivateDisplayOff(TRUE);
4691 SetMouseCursor(CURSOR_DEFAULT);
4693 #if defined(NETWORK_AVALIABLE)
4694 /* pause network game while waiting for request to answer */
4695 if (options.network &&
4696 game_status == GAME_MODE_PLAYING &&
4697 req_state & REQUEST_WAIT_FOR_INPUT)
4698 SendToServer_PausePlaying();
4701 old_door_state = GetDoorState();
4703 /* simulate releasing mouse button over last gadget, if still pressed */
4705 HandleGadgets(-1, -1, 0);
4709 /* draw released gadget before proceeding */
4712 if (old_door_state & DOOR_OPEN_1)
4714 CloseDoor(DOOR_CLOSE_1);
4716 /* save old door content */
4718 BlitBitmap(bitmap_db_door_1, bitmap_db_door_1,
4719 0 * DXSIZE, 0, DXSIZE, DYSIZE, 1 * DXSIZE, 0);
4721 BlitBitmap(bitmap_db_door, bitmap_db_door,
4722 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
4723 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
4727 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
4728 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
4730 /* clear door drawing field */
4731 DrawBackground(DX, DY, DXSIZE, DYSIZE);
4733 /* force DOOR font inside door area */
4734 game_status = GAME_MODE_PSEUDO_DOOR;
4736 /* write text for request */
4737 for (text_ptr = text, ty = 0; ty < MAX_REQUEST_LINES; ty++)
4739 char text_line[max_request_line_len + 1];
4745 for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
4747 tc = *(text_ptr + tx);
4748 // if (!tc || tc == ' ')
4749 if (!tc || tc == ' ' || tc == '?' || tc == '!')
4753 if ((tc == '?' || tc == '!') && tl == 0)
4763 strncpy(text_line, text_ptr, tl);
4766 DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
4767 DY + 8 + ty * (getFontHeight(font_nr) + 2),
4768 text_line, font_nr);
4770 text_ptr += tl + (tc == ' ' ? 1 : 0);
4771 // text_ptr += tl + (tc == ' ' || tc == '?' || tc == '!' ? 1 : 0);
4774 game_status = last_game_status; /* restore current game status */
4776 if (req_state & REQ_ASK)
4778 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
4779 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
4781 else if (req_state & REQ_CONFIRM)
4783 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
4785 else if (req_state & REQ_PLAYER)
4787 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
4788 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
4789 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
4790 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
4793 /* copy request gadgets to door backbuffer */
4795 BlitBitmap(drawto, bitmap_db_door_1, DX, DY, DXSIZE, DYSIZE, 0, 0);
4797 BlitBitmap(drawto, bitmap_db_door,
4798 DX, DY, DXSIZE, DYSIZE,
4799 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
4802 OpenDoor(DOOR_OPEN_1);
4804 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
4806 if (game_status == GAME_MODE_PLAYING)
4808 SetPanelBackground();
4809 SetDrawBackgroundMask(REDRAW_DOOR_1);
4813 SetDrawBackgroundMask(REDRAW_FIELD);
4819 if (game_status != GAME_MODE_MAIN)
4822 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
4824 // ---------- handle request buttons ----------
4825 result = RequestHandleEvents(req_state);
4827 if (game_status != GAME_MODE_MAIN)
4832 if (!(req_state & REQ_STAY_OPEN))
4834 CloseDoor(DOOR_CLOSE_1);
4836 if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
4837 (req_state & REQ_REOPEN))
4838 OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
4843 if (game_status == GAME_MODE_PLAYING)
4845 SetPanelBackground();
4846 SetDrawBackgroundMask(REDRAW_DOOR_1);
4850 SetDrawBackgroundMask(REDRAW_FIELD);
4853 #if defined(NETWORK_AVALIABLE)
4854 /* continue network game after request */
4855 if (options.network &&
4856 game_status == GAME_MODE_PLAYING &&
4857 req_state & REQUEST_WAIT_FOR_INPUT)
4858 SendToServer_ContinuePlaying();
4861 /* restore deactivated drawing when quick-loading level tape recording */
4862 if (tape.playing && tape.deactivate_display)
4863 TapeDeactivateDisplayOn();
4868 static boolean RequestEnvelope(char *text, unsigned int req_state)
4875 if (game_status == GAME_MODE_PLAYING)
4879 BlitScreenToBitmap(backbuffer);
4881 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
4882 BlitScreenToBitmap_EM(backbuffer);
4883 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
4884 BlitScreenToBitmap_SP(backbuffer);
4886 BlitScreenToBitmap_RND(backbuffer);
4889 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
4890 BlitScreenToBitmap_EM(backbuffer);
4891 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
4892 BlitScreenToBitmap_SP(backbuffer);
4896 /* disable deactivated drawing when quick-loading level tape recording */
4897 if (tape.playing && tape.deactivate_display)
4898 TapeDeactivateDisplayOff(TRUE);
4900 SetMouseCursor(CURSOR_DEFAULT);
4902 #if defined(NETWORK_AVALIABLE)
4903 /* pause network game while waiting for request to answer */
4904 if (options.network &&
4905 game_status == GAME_MODE_PLAYING &&
4906 req_state & REQUEST_WAIT_FOR_INPUT)
4907 SendToServer_PausePlaying();
4910 /* simulate releasing mouse button over last gadget, if still pressed */
4912 HandleGadgets(-1, -1, 0);
4916 // (replace with setting corresponding request background)
4917 // SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
4918 // SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
4920 /* clear door drawing field */
4921 // DrawBackground(DX, DY, DXSIZE, DYSIZE);
4924 if (global.use_envelope_request)
4928 CreateToolButtons();
4934 if (req_state & REQ_ASK)
4936 MapGadgetExt(tool_gadget[TOOL_CTRL_ID_YES], FALSE);
4937 MapGadgetExt(tool_gadget[TOOL_CTRL_ID_NO], FALSE);
4939 else if (req_state & REQ_CONFIRM)
4941 MapGadgetExt(tool_gadget[TOOL_CTRL_ID_CONFIRM], FALSE);
4943 else if (req_state & REQ_PLAYER)
4945 MapGadgetExt(tool_gadget[TOOL_CTRL_ID_PLAYER_1], FALSE);
4946 MapGadgetExt(tool_gadget[TOOL_CTRL_ID_PLAYER_2], FALSE);
4947 MapGadgetExt(tool_gadget[TOOL_CTRL_ID_PLAYER_3], FALSE);
4948 MapGadgetExt(tool_gadget[TOOL_CTRL_ID_PLAYER_4], FALSE);
4951 if (req_state & REQ_ASK)
4953 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
4954 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
4956 else if (req_state & REQ_CONFIRM)
4958 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
4960 else if (req_state & REQ_PLAYER)
4962 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
4963 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
4964 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
4965 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
4970 ShowEnvelopeRequest(text, req_state, ACTION_OPENING);
4973 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4975 if ((req_state & REQ_ASK && (i == TOOL_CTRL_ID_YES ||
4976 i == TOOL_CTRL_ID_NO)) ||
4977 (req_state & REQ_CONFIRM && i == TOOL_CTRL_ID_CONFIRM) ||
4978 (req_state & REQ_PLAYER && (i == TOOL_CTRL_ID_PLAYER_1 &&
4979 i == TOOL_CTRL_ID_PLAYER_2 &&
4980 i == TOOL_CTRL_ID_PLAYER_3 &&
4981 i == TOOL_CTRL_ID_PLAYER_4)))
4983 int x = tool_gadget[i]->x + dDX;
4984 int y = tool_gadget[i]->y + dDY;
4986 ModifyGadget(tool_gadget[i], GDI_X, x, GDI_Y, y, GDI_END);
4991 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
4993 if (game_status == GAME_MODE_PLAYING)
4995 SetPanelBackground();
4996 SetDrawBackgroundMask(REDRAW_DOOR_1);
5000 SetDrawBackgroundMask(REDRAW_FIELD);
5007 if (game_status != GAME_MODE_MAIN)
5011 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
5013 // ---------- handle request buttons ----------
5014 result = RequestHandleEvents(req_state);
5016 if (game_status != GAME_MODE_MAIN)
5021 ShowEnvelopeRequest(text, req_state, ACTION_CLOSING);
5025 if (game_status == GAME_MODE_PLAYING)
5027 SetPanelBackground();
5028 SetDrawBackgroundMask(REDRAW_DOOR_1);
5032 SetDrawBackgroundMask(REDRAW_FIELD);
5035 #if defined(NETWORK_AVALIABLE)
5036 /* continue network game after request */
5037 if (options.network &&
5038 game_status == GAME_MODE_PLAYING &&
5039 req_state & REQUEST_WAIT_FOR_INPUT)
5040 SendToServer_ContinuePlaying();
5043 /* restore deactivated drawing when quick-loading level tape recording */
5044 if (tape.playing && tape.deactivate_display)
5045 TapeDeactivateDisplayOn();
5050 boolean Request(char *text, unsigned int req_state)
5052 if (global.use_envelope_request)
5053 return RequestEnvelope(text, req_state);
5055 return RequestDoor(text, req_state);
5058 #else // =====================================================================
5060 boolean Request(char *text, unsigned int req_state)
5062 int mx, my, ty, result = -1;
5063 unsigned int old_door_state;
5064 int last_game_status = game_status; /* save current game status */
5065 int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
5066 int font_nr = FONT_TEXT_2;
5068 int max_word_len = 0;
5074 global.use_envelope_request = 1;
5078 if (maxWordLengthInString(text) > MAX_REQUEST_LINE_FONT1_LEN)
5080 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
5081 font_nr = FONT_TEXT_1;
5084 for (text_ptr = text; *text_ptr; text_ptr++)
5086 max_word_len = (*text_ptr != ' ' ? max_word_len + 1 : 0);
5088 if (max_word_len > MAX_REQUEST_LINE_FONT1_LEN)
5090 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
5092 font_nr = FONT_TEXT_1;
5094 font_nr = FONT_LEVEL_NUMBER;
5102 if (game_status == GAME_MODE_PLAYING)
5105 BlitScreenToBitmap(backbuffer);
5107 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
5108 BlitScreenToBitmap_EM(backbuffer);
5109 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
5110 BlitScreenToBitmap_SP(backbuffer);
5114 /* disable deactivated drawing when quick-loading level tape recording */
5115 if (tape.playing && tape.deactivate_display)
5116 TapeDeactivateDisplayOff(TRUE);
5118 SetMouseCursor(CURSOR_DEFAULT);
5120 #if defined(NETWORK_AVALIABLE)
5121 /* pause network game while waiting for request to answer */
5122 if (options.network &&
5123 game_status == GAME_MODE_PLAYING &&
5124 req_state & REQUEST_WAIT_FOR_INPUT)
5125 SendToServer_PausePlaying();
5128 old_door_state = GetDoorState();
5130 /* simulate releasing mouse button over last gadget, if still pressed */
5132 HandleGadgets(-1, -1, 0);
5136 /* draw released gadget before proceeding */
5140 if (old_door_state & DOOR_OPEN_1 && !global.use_envelope_request)
5142 if (old_door_state & DOOR_OPEN_1)
5146 if (!global.use_envelope_request)
5147 CloseDoor(DOOR_CLOSE_1);
5149 CloseDoor(DOOR_CLOSE_1);
5152 /* save old door content */
5153 BlitBitmap(bitmap_db_door, bitmap_db_door,
5154 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
5155 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
5159 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
5162 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
5164 /* clear door drawing field */
5165 DrawBackground(DX, DY, DXSIZE, DYSIZE);
5167 /* force DOOR font inside door area */
5168 game_status = GAME_MODE_PSEUDO_DOOR;
5170 /* write text for request */
5171 for (text_ptr = text, ty = 0; ty < MAX_REQUEST_LINES; ty++)
5173 char text_line[max_request_line_len + 1];
5179 for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
5181 tc = *(text_ptr + tx);
5182 if (!tc || tc == ' ')
5193 strncpy(text_line, text_ptr, tl);
5196 DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
5197 DY + 8 + ty * (getFontHeight(font_nr) + 2),
5198 text_line, font_nr);
5200 text_ptr += tl + (tc == ' ' ? 1 : 0);
5203 game_status = last_game_status; /* restore current game status */
5206 if (global.use_envelope_request)
5210 CreateToolButtons();
5214 if (req_state & REQ_ASK)
5216 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
5217 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
5219 else if (req_state & REQ_CONFIRM)
5221 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
5223 else if (req_state & REQ_PLAYER)
5225 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
5226 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
5227 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
5228 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
5231 /* copy request gadgets to door backbuffer */
5232 BlitBitmap(drawto, bitmap_db_door,
5233 DX, DY, DXSIZE, DYSIZE,
5234 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
5237 if (global.use_envelope_request)
5239 ShowEnvelopeRequest(text, ACTION_OPENING);
5241 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
5243 if ((req_state & REQ_ASK && (i == TOOL_CTRL_ID_YES ||
5244 i == TOOL_CTRL_ID_NO)) ||
5245 (req_state & REQ_CONFIRM && i == TOOL_CTRL_ID_CONFIRM) ||
5246 (req_state & REQ_PLAYER && (i == TOOL_CTRL_ID_PLAYER_1 &&
5247 i == TOOL_CTRL_ID_PLAYER_2 &&
5248 i == TOOL_CTRL_ID_PLAYER_3 &&
5249 i == TOOL_CTRL_ID_PLAYER_4)))
5251 int x = tool_gadget[i]->x + dDX;
5252 int y = tool_gadget[i]->y + dDY;
5254 ModifyGadget(tool_gadget[i], GDI_X, x, GDI_Y, y, GDI_END);
5261 if (!global.use_envelope_request)
5262 OpenDoor(DOOR_OPEN_1);
5264 OpenDoor(DOOR_OPEN_1);
5267 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
5269 if (game_status == GAME_MODE_PLAYING)
5271 SetPanelBackground();
5272 SetDrawBackgroundMask(REDRAW_DOOR_1);
5276 SetDrawBackgroundMask(REDRAW_FIELD);
5283 if (game_status != GAME_MODE_MAIN && !global.use_envelope_request)
5286 if (game_status != GAME_MODE_MAIN)
5290 button_status = MB_RELEASED;
5292 request_gadget_id = -1;
5294 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
5306 case EVENT_BUTTONPRESS:
5307 case EVENT_BUTTONRELEASE:
5308 case EVENT_MOTIONNOTIFY:
5310 if (event.type == EVENT_MOTIONNOTIFY)
5312 if (!PointerInWindow(window))
5313 continue; /* window and pointer are on different screens */
5318 motion_status = TRUE;
5319 mx = ((MotionEvent *) &event)->x;
5320 my = ((MotionEvent *) &event)->y;
5324 motion_status = FALSE;
5325 mx = ((ButtonEvent *) &event)->x;
5326 my = ((ButtonEvent *) &event)->y;
5327 if (event.type == EVENT_BUTTONPRESS)
5328 button_status = ((ButtonEvent *) &event)->button;
5330 button_status = MB_RELEASED;
5333 /* this sets 'request_gadget_id' */
5334 HandleGadgets(mx, my, button_status);
5336 switch (request_gadget_id)
5338 case TOOL_CTRL_ID_YES:
5341 case TOOL_CTRL_ID_NO:
5344 case TOOL_CTRL_ID_CONFIRM:
5345 result = TRUE | FALSE;
5348 case TOOL_CTRL_ID_PLAYER_1:
5351 case TOOL_CTRL_ID_PLAYER_2:
5354 case TOOL_CTRL_ID_PLAYER_3:
5357 case TOOL_CTRL_ID_PLAYER_4:
5368 case EVENT_KEYPRESS:
5369 switch (GetEventKey((KeyEvent *)&event, TRUE))
5372 if (req_state & REQ_CONFIRM)
5381 #if defined(TARGET_SDL2)
5391 if (req_state & REQ_PLAYER)
5395 case EVENT_KEYRELEASE:
5396 ClearPlayerAction();
5400 HandleOtherEvents(&event);
5404 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
5406 int joy = AnyJoystick();
5408 if (joy & JOY_BUTTON_1)
5410 else if (joy & JOY_BUTTON_2)
5416 if (game_status == GAME_MODE_PLAYING && local_player->LevelSolved_GameEnd)
5418 HandleGameActions();
5424 if (!PendingEvent()) /* delay only if no pending events */
5429 game_status = GAME_MODE_PSEUDO_DOOR;
5435 game_status = last_game_status; /* restore current game status */
5443 if (!PendingEvent()) /* delay only if no pending events */
5446 /* don't eat all CPU time */
5453 if (game_status != GAME_MODE_MAIN)
5459 if (global.use_envelope_request)
5460 ShowEnvelopeRequest(text, ACTION_CLOSING);
5464 if (!(req_state & REQ_STAY_OPEN) && !global.use_envelope_request)
5466 if (!(req_state & REQ_STAY_OPEN))
5469 CloseDoor(DOOR_CLOSE_1);
5471 if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
5472 (req_state & REQ_REOPEN))
5473 OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
5478 if (game_status == GAME_MODE_PLAYING)
5480 SetPanelBackground();
5481 SetDrawBackgroundMask(REDRAW_DOOR_1);
5485 SetDrawBackgroundMask(REDRAW_FIELD);
5488 #if defined(NETWORK_AVALIABLE)
5489 /* continue network game after request */
5490 if (options.network &&
5491 game_status == GAME_MODE_PLAYING &&
5492 req_state & REQUEST_WAIT_FOR_INPUT)
5493 SendToServer_ContinuePlaying();
5496 /* restore deactivated drawing when quick-loading level tape recording */
5497 if (tape.playing && tape.deactivate_display)
5498 TapeDeactivateDisplayOn();
5505 static int compareDoorPartOrderInfo(const void *object1, const void *object2)
5507 const struct DoorPartOrderInfo *dpo1 = (struct DoorPartOrderInfo *)object1;
5508 const struct DoorPartOrderInfo *dpo2 = (struct DoorPartOrderInfo *)object2;
5511 if (dpo1->sort_priority != dpo2->sort_priority)
5512 compare_result = dpo1->sort_priority - dpo2->sort_priority;
5514 compare_result = dpo1->nr - dpo2->nr;
5516 return compare_result;
5519 void InitGraphicCompatibilityInfo_Doors()
5525 struct DoorInfo *door;
5529 { DOOR_1, IMG_DOOR_1_GFX_PART_1, IMG_DOOR_1_GFX_PART_8, &door_1 },
5530 { DOOR_2, IMG_DOOR_2_GFX_PART_1, IMG_DOOR_2_GFX_PART_8, &door_2 },
5532 { -1, -1, -1, NULL }
5534 struct Rect door_rect_list[] =
5536 { DX, DY, DXSIZE, DYSIZE },
5537 { VX, VY, VXSIZE, VYSIZE }
5541 for (i = 0; doors[i].door_token != -1; i++)
5543 int door_token = doors[i].door_token;
5544 int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
5545 int part_1 = doors[i].part_1;
5546 int part_8 = doors[i].part_8;
5547 int part_2 = part_1 + 1;
5548 int part_3 = part_1 + 2;
5549 struct DoorInfo *door = doors[i].door;
5550 struct Rect *door_rect = &door_rect_list[door_index];
5551 boolean door_gfx_redefined = FALSE;
5553 /* check if any door part graphic definitions have been redefined */
5555 for (j = 0; door_part_controls[j].door_token != -1; j++)
5557 struct DoorPartControlInfo *dpc = &door_part_controls[j];
5558 struct FileInfo *fi = getImageListEntryFromImageID(dpc->graphic);
5560 if (dpc->door_token == door_token && fi->redefined)
5561 door_gfx_redefined = TRUE;
5564 /* check for old-style door graphic/animation modifications */
5566 if (!door_gfx_redefined)
5568 if (door->anim_mode & ANIM_STATIC_PANEL)
5570 door->panel.step_xoffset = 0;
5571 door->panel.step_yoffset = 0;
5574 if (door->anim_mode & (ANIM_HORIZONTAL | ANIM_VERTICAL))
5576 struct GraphicInfo *g_part_1 = &graphic_info[part_1];
5577 struct GraphicInfo *g_part_2 = &graphic_info[part_2];
5578 int num_door_steps, num_panel_steps;
5580 /* remove door part graphics other than the two default wings */
5582 for (j = 0; door_part_controls[j].door_token != -1; j++)
5584 struct DoorPartControlInfo *dpc = &door_part_controls[j];
5585 struct GraphicInfo *g = &graphic_info[dpc->graphic];
5587 if (dpc->graphic >= part_3 &&
5588 dpc->graphic <= part_8)
5592 /* set graphics and screen positions of the default wings */
5594 g_part_1->width = door_rect->width;
5595 g_part_1->height = door_rect->height;
5596 g_part_2->width = door_rect->width;
5597 g_part_2->height = door_rect->height;
5598 g_part_2->src_x = door_rect->width;
5599 g_part_2->src_y = g_part_1->src_y;
5601 door->part_2.x = door->part_1.x;
5602 door->part_2.y = door->part_1.y;
5604 if (door->width != -1)
5606 g_part_1->width = door->width;
5607 g_part_2->width = door->width;
5609 // special treatment for graphics and screen position of right wing
5610 g_part_2->src_x += door_rect->width - door->width;
5611 door->part_2.x += door_rect->width - door->width;
5614 if (door->height != -1)
5616 g_part_1->height = door->height;
5617 g_part_2->height = door->height;
5619 // special treatment for graphics and screen position of bottom wing
5620 g_part_2->src_y += door_rect->height - door->height;
5621 door->part_2.y += door_rect->height - door->height;
5624 /* set animation delays for the default wings and panels */
5626 door->part_1.step_delay = door->step_delay;
5627 door->part_2.step_delay = door->step_delay;
5628 door->panel.step_delay = door->step_delay;
5630 /* set animation draw order for the default wings */
5632 door->part_1.sort_priority = 2; /* draw left wing over ... */
5633 door->part_2.sort_priority = 1; /* ... right wing */
5635 /* set animation draw offset for the default wings */
5637 if (door->anim_mode & ANIM_HORIZONTAL)
5639 door->part_1.step_xoffset = door->step_offset;
5640 door->part_1.step_yoffset = 0;
5641 door->part_2.step_xoffset = door->step_offset * -1;
5642 door->part_2.step_yoffset = 0;
5644 num_door_steps = g_part_1->width / door->step_offset;
5646 else // ANIM_VERTICAL
5648 door->part_1.step_xoffset = 0;
5649 door->part_1.step_yoffset = door->step_offset;
5650 door->part_2.step_xoffset = 0;
5651 door->part_2.step_yoffset = door->step_offset * -1;
5653 num_door_steps = g_part_1->height / door->step_offset;
5656 /* set animation draw offset for the default panels */
5658 if (door->step_offset > 1)
5660 num_panel_steps = 2 * door_rect->height / door->step_offset;
5661 door->panel.start_step = num_panel_steps - num_door_steps;
5665 num_panel_steps = door_rect->height / door->step_offset;
5666 door->panel.start_step = num_panel_steps - num_door_steps / 2;
5667 door->panel.step_delay *= 2;
5678 for (i = 0; door_part_controls[i].door_token != -1; i++)
5680 struct DoorPartControlInfo *dpc = &door_part_controls[i];
5681 struct DoorPartOrderInfo *dpo = &door_part_order[i];
5683 /* initialize "start_step_opening" and "start_step_closing", if needed */
5684 if (dpc->pos->start_step_opening == 0 &&
5685 dpc->pos->start_step_closing == 0)
5687 // dpc->pos->start_step_opening = dpc->pos->start_step;
5688 dpc->pos->start_step_closing = dpc->pos->start_step;
5691 /* fill structure for door part draw order (sorted below) */
5693 dpo->sort_priority = dpc->pos->sort_priority;
5696 struct DoorPartPosInfo *pos = dpc->pos;
5698 printf(":0: step_xoffset == %d, step_yoffset == %d\n",
5699 pos->step_xoffset, pos->step_yoffset);
5703 /* sort door part controls according to sort_priority and graphic number */
5704 qsort(door_part_order, MAX_DOOR_PARTS,
5705 sizeof(struct DoorPartOrderInfo), compareDoorPartOrderInfo);
5708 unsigned int OpenDoor(unsigned int door_state)
5710 if (door_state & DOOR_COPY_BACK)
5713 if (door_state & DOOR_OPEN_1)
5714 BlitBitmap(bitmap_db_door_1, bitmap_db_door_1,
5715 1 * DXSIZE, 0, DXSIZE, DYSIZE, 0 * DXSIZE, 0);
5717 if (door_state & DOOR_OPEN_2)
5718 BlitBitmap(bitmap_db_door_2, bitmap_db_door_2,
5719 1 * VXSIZE, 0, VXSIZE, VYSIZE, 0 * VXSIZE, 0);
5721 if (door_state & DOOR_OPEN_1)
5722 BlitBitmap(bitmap_db_door, bitmap_db_door,
5723 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
5724 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
5726 if (door_state & DOOR_OPEN_2)
5727 BlitBitmap(bitmap_db_door, bitmap_db_door,
5728 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY2, VXSIZE, VYSIZE,
5729 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
5732 door_state &= ~DOOR_COPY_BACK;
5735 return MoveDoor(door_state);
5738 unsigned int CloseDoor(unsigned int door_state)
5740 unsigned int old_door_state = GetDoorState();
5742 if (!(door_state & DOOR_NO_COPY_BACK))
5745 if (old_door_state & DOOR_OPEN_1)
5746 BlitBitmap(backbuffer, bitmap_db_door_1,
5747 DX, DY, DXSIZE, DYSIZE, 0, 0);
5749 if (old_door_state & DOOR_OPEN_2)
5750 BlitBitmap(backbuffer, bitmap_db_door_2,
5751 VX, VY, VXSIZE, VYSIZE, 0, 0);
5753 if (old_door_state & DOOR_OPEN_1)
5754 BlitBitmap(backbuffer, bitmap_db_door,
5755 DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
5757 if (old_door_state & DOOR_OPEN_2)
5758 BlitBitmap(backbuffer, bitmap_db_door,
5759 VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
5762 door_state &= ~DOOR_NO_COPY_BACK;
5765 return MoveDoor(door_state);
5768 unsigned int GetDoorState()
5770 return MoveDoor(DOOR_GET_STATE);
5773 unsigned int SetDoorState(unsigned int door_state)
5775 return MoveDoor(door_state | DOOR_SET_STATE);
5780 // ========== TEST 1 ===========================================================
5782 int euclid(int a, int b)
5784 return (b ? euclid(b, a % b) : a);
5787 unsigned int MoveDoor(unsigned int door_state)
5790 struct XY panel_pos_list[] =
5792 { DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 },
5793 { DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 },
5796 struct Rect door_rect_list[] =
5798 { DX, DY, DXSIZE, DYSIZE },
5799 { VX, VY, VXSIZE, VYSIZE }
5801 static int door1 = DOOR_OPEN_1;
5802 static int door2 = DOOR_CLOSE_2;
5803 unsigned int door_delay = 0;
5804 unsigned int door_delay_value;
5808 if (door_1.width < 0 || door_1.width > DXSIZE)
5809 door_1.width = DXSIZE;
5810 if (door_1.height < 0 || door_1.height > DYSIZE)
5811 door_1.height = DYSIZE;
5812 if (door_2.width < 0 || door_2.width > VXSIZE)
5813 door_2.width = VXSIZE;
5814 if (door_2.height < 0 || door_2.height > VYSIZE)
5815 door_2.height = VYSIZE;
5818 if (door_state == DOOR_GET_STATE)
5819 return (door1 | door2);
5821 if (door_state & DOOR_SET_STATE)
5823 if (door_state & DOOR_ACTION_1)
5824 door1 = door_state & DOOR_ACTION_1;
5825 if (door_state & DOOR_ACTION_2)
5826 door2 = door_state & DOOR_ACTION_2;
5828 return (door1 | door2);
5831 if (!(door_state & DOOR_FORCE_REDRAW))
5833 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
5834 door_state &= ~DOOR_OPEN_1;
5835 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
5836 door_state &= ~DOOR_CLOSE_1;
5837 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
5838 door_state &= ~DOOR_OPEN_2;
5839 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
5840 door_state &= ~DOOR_CLOSE_2;
5844 door_delay_value = (door_state & DOOR_ACTION_1 ? door_1.step_delay :
5847 if (setup.quick_doors)
5849 stepsize = 20; /* must be chosen to always draw last frame */
5850 door_delay_value = 0;
5854 if (global.autoplay_leveldir)
5856 door_state |= DOOR_NO_DELAY;
5857 door_state &= ~DOOR_CLOSE_ALL;
5861 if (game_status == GAME_MODE_EDITOR)
5862 door_state |= DOOR_NO_DELAY;
5865 if (door_state & DOOR_ACTION)
5867 boolean door_panel_drawn[NUM_DOORS];
5868 boolean panel_has_doors[NUM_DOORS];
5869 boolean door_part_skip[MAX_DOOR_PARTS];
5870 boolean door_part_done[MAX_DOOR_PARTS];
5871 boolean door_part_done_all;
5872 int num_steps[MAX_DOOR_PARTS];
5873 int max_move_delay = 0; // delay for complete animations of all doors
5874 int max_step_delay = 0; // delay (ms) between two animation frames
5875 int num_move_steps = 0; // number of animation steps for all doors
5876 int current_move_delay = 0;
5879 for (i = 0; i < NUM_DOORS; i++)
5880 panel_has_doors[i] = FALSE;
5882 for (i = 0; i < MAX_DOOR_PARTS; i++)
5884 struct DoorPartControlInfo *dpc = &door_part_controls[i];
5885 struct GraphicInfo *g = &graphic_info[dpc->graphic];
5886 int door_token = dpc->door_token;
5888 door_part_done[i] = FALSE;
5889 door_part_skip[i] = (!(door_state & door_token) ||
5894 for (i = 0; i < MAX_DOOR_PARTS; i++)
5896 struct DoorPartControlInfo *dpc = &door_part_controls[i];
5897 struct DoorPartPosInfo *pos = dpc->pos;
5898 int start_step = pos->start_step;
5900 printf("::: ---> %d: start_step == %d [%d]\n",
5901 i, start_step, door_part_done[i]);
5905 for (i = 0; i < MAX_DOOR_PARTS; i++)
5907 int nr = door_part_order[i].nr;
5908 struct DoorPartControlInfo *dpc = &door_part_controls[nr];
5909 struct DoorPartPosInfo *pos = dpc->pos;
5910 struct GraphicInfo *g = &graphic_info[dpc->graphic];
5911 int door_token = dpc->door_token;
5912 int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
5913 boolean is_panel = DOOR_PART_IS_PANEL(nr);
5914 int step_xoffset = ABS(pos->step_xoffset);
5915 int step_yoffset = ABS(pos->step_yoffset);
5916 int step_delay = pos->step_delay;
5917 int current_door_state = door_state & door_token;
5918 boolean door_opening = ((current_door_state & DOOR_OPEN) != 0);
5919 boolean door_closing = ((current_door_state & DOOR_CLOSE) != 0);
5920 boolean part_opening = (is_panel ? door_closing : door_opening);
5921 int start_step = (part_opening ? pos->start_step_opening :
5922 pos->start_step_closing);
5923 float move_xsize = (step_xoffset ? g->width : 0);
5924 float move_ysize = (step_yoffset ? g->height : 0);
5925 int move_xsteps = (step_xoffset ? ceil(move_xsize / step_xoffset) : 0);
5926 int move_ysteps = (step_yoffset ? ceil(move_ysize / step_yoffset) : 0);
5927 int move_steps = (move_xsteps && move_ysteps ?
5928 MIN(move_xsteps, move_ysteps) :
5929 move_xsteps ? move_xsteps : move_ysteps) - start_step;
5930 int move_delay = move_steps * step_delay;
5932 if (door_part_skip[nr])
5936 panel_has_doors[door_index] = TRUE;
5938 max_move_delay = MAX(max_move_delay, move_delay);
5939 max_step_delay = (max_step_delay == 0 ? step_delay :
5940 euclid(max_step_delay, step_delay));
5941 num_steps[nr] = move_steps;
5945 printf("::: %d: move_delay == %d, start_step == %d [%d]\n",
5946 i, move_delay, start_step, door_part_order[i].nr);
5948 if (DOOR_PART_IS_PANEL(i))
5949 printf("::: %d: move_delay == %d, start_step == %d\n",
5950 i, move_delay, start_step);
5955 num_move_steps = max_move_delay / max_step_delay;
5957 door_delay_value = max_step_delay;
5960 door_delay_value *= 10;
5964 printf("::: num_move_steps == %d, max_move_delay == %d, max_step_delay == %d\n", num_move_steps, max_move_delay, max_step_delay);
5967 for (k = 0; k < num_move_steps; k++)
5969 door_part_done_all = TRUE;
5971 for (i = 0; i < NUM_DOORS; i++)
5972 door_panel_drawn[i] = FALSE;
5974 for (i = 0; i < MAX_DOOR_PARTS; i++)
5976 int nr = door_part_order[i].nr;
5977 struct DoorPartControlInfo *dpc = &door_part_controls[nr];
5978 struct DoorPartPosInfo *pos = dpc->pos;
5979 struct GraphicInfo *g = &graphic_info[dpc->graphic];
5980 int door_token = dpc->door_token;
5981 int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
5982 boolean is_panel = DOOR_PART_IS_PANEL(nr);
5984 struct XY *panel_pos = &panel_pos_list[door_index];
5986 struct Rect *door_rect = &door_rect_list[door_index];
5987 Bitmap *bitmap_db_door = (door_token == DOOR_1 ? bitmap_db_door_1 :
5989 Bitmap *bitmap = (is_panel ? bitmap_db_door : g->bitmap);
5990 int current_door_state = door_state & door_token;
5991 boolean door_opening = ((current_door_state & DOOR_OPEN) != 0);
5992 boolean door_closing = !door_opening;
5993 boolean part_opening = (is_panel ? door_closing : door_opening);
5994 boolean part_closing = !part_opening;
5995 int start_step = (part_opening ? pos->start_step_opening :
5996 pos->start_step_closing);
5997 int step_delay = pos->step_delay;
5998 int step_factor = step_delay / max_step_delay;
5999 int k1 = (step_factor ? k / step_factor + 1 : k);
6000 int k2 = (part_opening ? k1 + start_step : num_steps[nr] - k1);
6001 int kk = (k2 < 0 ? 0 : k2);
6002 int src_x, src_y, src_xx, src_yy;
6003 int dst_x, dst_y, dst_xx, dst_yy;
6007 if (k == 0 && is_panel && door_token == DOOR_2)
6008 printf("::: %d, %d\n", g->width, g->height);
6012 if (DOOR_PART_IS_PANEL(nr))
6014 int start_step = pos->start_step;
6016 k2 = (door_closing ? k1 : num_steps[nr] - k1);// - start_step;
6017 kk = (k2 < 0 ? 0 : k2);
6023 if (nr != 16 && nr != 0)
6034 if (door_part_skip[nr])
6038 if (!(door_state & door_token))
6045 if (current_move_delay % step_delay)
6051 if (!door_panel_drawn[door_index])
6054 ClearRectangle(drawto, door_rect->x, door_rect->y,
6055 door_rect->width, door_rect->height);
6057 BlitBitmap(bitmap_db_door, drawto, panel_pos->x, panel_pos->y,
6058 door_rect->width, door_rect->height,
6059 door_rect->x, door_rect->y);
6062 door_panel_drawn[door_index] = TRUE;
6065 // draw opening or closing door parts
6067 if (pos->step_xoffset < 0) // door part on right side
6070 dst_xx = pos->x + ABS(kk * pos->step_xoffset);
6073 if (dst_xx + width > door_rect->width)
6074 width = door_rect->width - dst_xx;
6076 else // door part on left side
6079 dst_xx = pos->x - kk * pos->step_xoffset;
6083 src_xx = ABS(dst_xx);
6087 width = g->width - src_xx;
6089 // printf("::: k == %d [%d] \n", k, start_step);
6092 if (pos->step_yoffset < 0) // door part on bottom side
6095 dst_yy = pos->y + ABS(kk * pos->step_yoffset);
6098 if (dst_yy + height > door_rect->height)
6099 height = door_rect->height - dst_yy;
6101 else // door part on top side
6104 dst_yy = pos->y - kk * pos->step_yoffset;
6108 src_yy = ABS(dst_yy);
6112 height = g->height - src_yy;
6121 src_x = panel_pos->x + src_xx;
6122 src_y = panel_pos->y + src_yy;
6127 src_x = g->src_x + src_xx;
6128 src_y = g->src_y + src_yy;
6131 dst_x = door_rect->x + dst_xx;
6132 dst_y = door_rect->y + dst_yy;
6135 if (DOOR_PART_IS_PANEL(nr))
6137 printf("::: width == %d, height == %d [%d, %d] [%d, %d]\n",
6138 width, height, g->width, g->height, src_x, src_y);
6142 if (width >= 0 && width <= g->width &&
6143 height >= 0 && height <= g->height)
6145 if (is_panel || !pos->draw_masked)
6146 BlitBitmap(bitmap, drawto, src_x, src_y, width, height,
6149 BlitBitmapMasked(bitmap, drawto, src_x, src_y, width, height,
6154 if (DOOR_PART_IS_PANEL(nr))
6156 bitmap = bitmap_db_door;
6157 src_x = panel_pos->x + src_xx;
6158 src_y = panel_pos->y + src_yy;
6160 printf("::: width == %d, height == %d [%d, %d] [%d, %d]\n",
6161 width, height, g->width, g->height, src_x, src_y);
6163 if (width >= 0 && width <= g->width &&
6164 height >= 0 && height <= g->height)
6165 BlitBitmap(bitmap, drawto, src_x, src_y,
6171 redraw_mask |= REDRAW_DOOR_FROM_TOKEN(door_token);
6174 if ((part_opening && (width < 0 || height < 0)) ||
6175 (part_closing && (width >= g->width && height >= g->height)))
6176 door_part_done[nr] = TRUE;
6178 if ((door_opening && (width < 0 || height < 0)) ||
6179 (door_closing && (width >= g->width && height >= g->height)))
6180 door_part_done[nr] = TRUE;
6184 // continue door part animations, but not panel after door has closed
6185 if (!door_part_done[nr] &&
6186 !(is_panel && door_closing && panel_has_doors[door_index]))
6187 door_part_done_all = FALSE;
6189 // continue door part animations, but not panel after door has closed
6190 if (!door_part_done[nr] && !(is_panel && door_closing))
6191 door_part_done_all = FALSE;
6195 if (!door_part_done[nr])
6196 printf("::: k == %d, nr == %d\n", k, nr);
6200 if (!(door_state & DOOR_NO_DELAY))
6204 if (game_status == GAME_MODE_MAIN)
6207 WaitUntilDelayReached(&door_delay, door_delay_value);
6209 current_move_delay += max_step_delay;
6213 door_part_done_all = TRUE;
6215 for (i = 0; i < MAX_DOOR_PARTS; i++)
6216 if (!door_part_done[i] &&
6217 !(DOOR_PART_IS_PANEL(i) && door_closing))
6218 door_part_done_all = FALSE;
6221 if (door_part_done_all)
6227 if (door_state & DOOR_ACTION_1)
6228 door1 = door_state & DOOR_ACTION_1;
6229 if (door_state & DOOR_ACTION_2)
6230 door2 = door_state & DOOR_ACTION_2;
6233 printf("::: DOORS DONE %08x\n", door_state);
6235 printf("::: GO!\n");
6238 return (door1 | door2);
6243 // ========== OLD ==============================================================
6245 unsigned int MoveDoor(unsigned int door_state)
6247 static int door1 = DOOR_OPEN_1;
6248 static int door2 = DOOR_CLOSE_2;
6249 unsigned int door_delay = 0;
6250 unsigned int door_delay_value;
6254 if (door_1.width < 0 || door_1.width > DXSIZE)
6255 door_1.width = DXSIZE;
6256 if (door_1.height < 0 || door_1.height > DYSIZE)
6257 door_1.height = DYSIZE;
6258 if (door_2.width < 0 || door_2.width > VXSIZE)
6259 door_2.width = VXSIZE;
6260 if (door_2.height < 0 || door_2.height > VYSIZE)
6261 door_2.height = VYSIZE;
6264 if (door_state == DOOR_GET_STATE)
6265 return (door1 | door2);
6267 if (door_state & DOOR_SET_STATE)
6269 if (door_state & DOOR_ACTION_1)
6270 door1 = door_state & DOOR_ACTION_1;
6271 if (door_state & DOOR_ACTION_2)
6272 door2 = door_state & DOOR_ACTION_2;
6274 return (door1 | door2);
6277 if (!(door_state & DOOR_FORCE_REDRAW))
6279 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
6280 door_state &= ~DOOR_OPEN_1;
6281 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
6282 door_state &= ~DOOR_CLOSE_1;
6283 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
6284 door_state &= ~DOOR_OPEN_2;
6285 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
6286 door_state &= ~DOOR_CLOSE_2;
6289 door_delay_value = (door_state & DOOR_ACTION_1 ? door_1.step_delay :
6292 // door_delay_value *= 4; // !!! TEST ONLY !!!
6294 if (setup.quick_doors)
6296 stepsize = 20; /* must be chosen to always draw last frame */
6297 door_delay_value = 0;
6300 if (global.autoplay_leveldir)
6302 door_state |= DOOR_NO_DELAY;
6303 door_state &= ~DOOR_CLOSE_ALL;
6307 if (game_status == GAME_MODE_EDITOR)
6308 door_state |= DOOR_NO_DELAY;
6311 if (door_state & DOOR_ACTION)
6314 struct GraphicInfo *g1_left = &graphic_info[IMG_DOOR_1_WING_LEFT];
6315 struct GraphicInfo *g1_right = &graphic_info[IMG_DOOR_1_WING_RIGHT];
6316 struct GraphicInfo *g2_left = &graphic_info[IMG_DOOR_2_WING_LEFT];
6317 struct GraphicInfo *g2_right = &graphic_info[IMG_DOOR_2_WING_RIGHT];
6318 int door_1_left_width = g1_left->width;
6319 int door_1_left_height = g1_left->height;
6320 int door_1_right_width = g1_right->width;
6321 int door_1_right_height = g1_right->height;
6322 int door_2_left_width = g2_left->width;
6323 int door_2_left_height = g2_left->height;
6324 int door_2_right_width = g2_right->width;
6325 int door_2_right_height = g2_right->height;
6326 int door_1_width = MAX(door_1_left_width, door_1_right_width);
6327 int door_1_height = MAX(door_1_left_height, door_1_right_height);
6328 int door_2_width = MAX(door_2_left_width, door_2_right_width);
6329 int door_2_height = MAX(door_2_left_height, door_2_right_height);
6331 boolean handle_door_1 = (door_state & DOOR_ACTION_1);
6332 boolean handle_door_2 = (door_state & DOOR_ACTION_2);
6333 boolean door_1_done = (!handle_door_1);
6334 boolean door_2_done = (!handle_door_2);
6335 boolean door_1_vertical = (door_1.anim_mode & ANIM_VERTICAL);
6336 boolean door_2_vertical = (door_2.anim_mode & ANIM_VERTICAL);
6339 int door_size_1 = (door_1_vertical ? door_1_height : door_1_width);
6340 int door_size_2 = (door_2_vertical ? door_2_height : door_2_width);
6342 int door_size_1 = (door_1_vertical ? DYSIZE : DXSIZE);
6343 int door_size_2 = (door_2_vertical ? VYSIZE : VXSIZE);
6346 int door_size_1 = (door_1_vertical ? door_1.height : door_1.width);
6347 int door_size_2 = (door_2_vertical ? door_2.height : door_2.width);
6349 int max_door_size_1 = (door_1_vertical ? DYSIZE : DXSIZE);
6350 int max_door_size_2 = (door_2_vertical ? VYSIZE : VXSIZE);
6351 // int door_size = (handle_door_1 ? door_size_1 : door_size_2);
6352 int door_size = (handle_door_2 ? door_size_2 : door_size_1);
6353 int max_door_size = (handle_door_1 ? max_door_size_1 : max_door_size_2);
6354 int door_skip = max_door_size - door_size;
6355 int end = door_size;
6356 int start = ((door_state & DOOR_NO_DELAY) ? end : 0);
6359 if (!(door_state & DOOR_NO_DELAY) && !setup.quick_doors)
6361 /* opening door sound has priority over simultaneously closing door */
6362 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
6363 PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
6364 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
6365 PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
6368 for (k = start; k <= end && !(door_1_done && door_2_done); k += stepsize)
6372 Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
6373 GC gc = bitmap->stored_clip_gc;
6376 if (door_state & DOOR_ACTION_1 &&
6377 x * door_1.step_offset <= door_size_1)
6379 int a = MIN(x * door_1.step_offset, end);
6380 int p = (door_state & DOOR_OPEN_1 ? end - a : a);
6384 int i = p + door_skip;
6388 struct GraphicInfo *g_left = &graphic_info[IMG_DOOR_1_WING_LEFT];
6389 struct GraphicInfo *g_right = &graphic_info[IMG_DOOR_1_WING_RIGHT];
6390 Bitmap *bm_left = g_left->bitmap;
6391 Bitmap *bm_right = g_right->bitmap;
6392 GC gc_left = bm_left->stored_clip_gc;
6393 GC gc_right = bm_right->stored_clip_gc;
6396 int classic_dxsize = 100;
6397 int classic_dysize = 280;
6398 boolean classic_door_1_size = (DXSIZE == classic_dxsize &&
6399 DYSIZE == classic_dysize);
6401 if (door_1.anim_mode & ANIM_STATIC_PANEL)
6403 BlitBitmap(bitmap_db_door, drawto,
6404 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1,
6405 DXSIZE, DYSIZE, DX, DY);
6409 BlitBitmap(bitmap_db_door, drawto,
6410 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + p / 2,
6411 DXSIZE, DYSIZE - p / 2, DX, DY);
6414 // printf("::: p == %d\n", p);
6415 ClearRectangle(drawto, DX, DY + DYSIZE - p / 2, DXSIZE, p / 2);
6419 if (door_1.anim_mode & ANIM_HORIZONTAL && x <= DXSIZE)
6422 int src1_x = g_right->src_x;
6423 int src1_y = g_right->src_y;
6424 int src2_x = g_left->src_x + g_left->width - i;
6425 int src2_y = g_left->src_y;
6426 int dst1_x = DX + DXSIZE - i;
6431 int height = DYSIZE;
6433 SetClipOrigin(bm_right, gc_right, dst1_x - src1_x, dst1_y - src1_y);
6434 BlitBitmapMasked(bm_right, drawto, src1_x, src1_y, width, height,
6437 SetClipOrigin(bm_left, gc_left, dst2_x - src2_x, dst2_y - src2_y);
6438 BlitBitmapMasked(bm_left, drawto, src2_x, src2_y, width, height,
6441 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
6442 int src2_x = DXSIZE - i, src2_y = DOOR_GFX_PAGEY1;
6443 int dst1_x = DX + DXSIZE - i, dst1_y = DY;
6444 int dst2_x = DX, dst2_y = DY;
6445 int width = i, height = DYSIZE;
6447 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
6448 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
6451 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
6452 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
6456 else if (door_1.anim_mode & ANIM_VERTICAL && x <= DYSIZE)
6459 int src1_x = g_right->src_x;
6460 int src1_y = g_right->src_y;
6461 int src2_x = g_left->src_x;
6462 int src2_y = g_left->src_y + g_left->height - i;
6464 int dst1_y = DY + DYSIZE - i;
6470 SetClipOrigin(bm_right, gc_right, dst1_x - src1_x, dst1_y - src1_y);
6471 BlitBitmapMasked(bm_right, drawto, src1_x, src1_y, width, height,
6474 SetClipOrigin(bm_left, gc_left, dst2_x - src2_x, dst2_y - src2_y);
6475 BlitBitmapMasked(bm_left, drawto, src2_x, src2_y, width, height,
6478 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
6479 int src2_x = 0, src2_y = DOOR_GFX_PAGEY1 + DYSIZE - i;
6480 int dst1_x = DX, dst1_y = DY + DYSIZE - i;
6481 int dst2_x = DX, dst2_y = DY;
6482 int width = DXSIZE, height = i;
6484 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
6485 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
6488 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
6489 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
6493 else if (classic_door_1_size && x <= DXSIZE) /* ANIM_DEFAULT */
6495 int j = (door_1.anim_mode == ANIM_DEFAULT ? (DXSIZE - i) / 3 : 0);
6498 int src1_x = g_right->src_x;
6499 int src1_y = g_right->src_y;
6500 int src2_x = g_left->src_x + g_left->width - i;
6501 int src2_y = g_left->src_y;
6502 int dst1_x = DX + DXSIZE - i;
6507 int height1 = 63, height2 = DYSIZE / 2 - height1;
6508 int ypos1 = 0, ypos2 = height2;
6509 int ypos3 = DYSIZE / 2, ypos4 = DYSIZE - height2;
6511 SetClipOrigin(bm_right, gc_right,
6512 dst1_x - src1_x, dst1_y - src1_y + j);
6513 BlitBitmapMasked(bm_right, drawto,
6514 src1_x, src1_y + ypos1, width, height2,
6515 dst1_x, dst1_y + ypos1 + j);
6516 BlitBitmapMasked(bm_right, drawto,
6517 src1_x, src1_y + ypos3, width, height1,
6518 dst1_x, dst1_y + ypos3 + j);
6519 SetClipOrigin(bm_left, gc_left,
6520 dst2_x - src2_x, dst2_y - src2_y - j);
6521 BlitBitmapMasked(bm_left, drawto,
6522 src2_x, src2_y + ypos1 + j, width, height2 - j,
6523 dst2_x, dst2_y + ypos1);
6524 BlitBitmapMasked(bm_left, drawto,
6525 src2_x, src2_y + ypos3, width, height1,
6526 dst2_x, dst2_y + ypos3 - j);
6528 SetClipOrigin(bm_left, gc_left,
6529 dst2_x - src2_x, dst2_y - src2_y - j);
6530 BlitBitmapMasked(bm_left, drawto,
6531 src2_x, src2_y + ypos2, width, height1,
6532 dst2_x, dst2_y + ypos2 - j);
6533 BlitBitmapMasked(bm_left, drawto,
6534 src2_x, src2_y + ypos4, width, height2,
6535 dst2_x, dst2_y + ypos4 - j);
6536 SetClipOrigin(bm_right, gc_right,
6537 dst1_x - src1_x, dst1_y - src1_y + j);
6538 BlitBitmapMasked(bm_right, drawto,
6539 src1_x, src1_y + ypos2, width, height1,
6540 dst1_x, dst1_y + ypos2 + j);
6541 BlitBitmapMasked(bm_right, drawto,
6542 src1_x, src1_y + ypos4, width, height2 - j,
6543 dst1_x, dst1_y + ypos4 + j);
6546 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
6547 int src2_x = DXSIZE - i, src2_y = DOOR_GFX_PAGEY1;
6548 int dst1_x = DX + DXSIZE - i, dst1_y = DY;
6549 int dst2_x = DX, dst2_y = DY;
6550 int width = i, height = DYSIZE;
6551 int ypos1 = 63, ypos2 = 77, ypos3 = 140, ypos4 = 203;
6553 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y + j);
6554 BlitBitmapMasked(bitmap, drawto,
6555 src1_x, src1_y, width, ypos2,
6556 dst1_x, dst1_y + j);
6557 BlitBitmapMasked(bitmap, drawto,
6558 src1_x, src1_y + ypos3, width, ypos1,
6559 dst1_x, dst1_y + ypos3 + j);
6560 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y - j);
6561 BlitBitmapMasked(bitmap, drawto,
6562 src2_x, src2_y + j, width, ypos2 - j,
6564 BlitBitmapMasked(bitmap, drawto,
6565 src2_x, src2_y + ypos3, width, ypos1,
6566 dst2_x, dst2_y + ypos3 - j);
6568 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y - j);
6569 BlitBitmapMasked(bitmap, drawto,
6570 src2_x, src2_y + ypos2, width, ypos1,
6571 dst2_x, dst2_y + ypos2 - j);
6572 BlitBitmapMasked(bitmap, drawto,
6573 src2_x, src2_y + ypos4, width, ypos2,
6574 dst2_x, dst2_y + ypos4 - j);
6575 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y + j);
6576 BlitBitmapMasked(bitmap, drawto,
6577 src1_x, src1_y + ypos2, width, ypos1,
6578 dst1_x, dst1_y + ypos2 + j);
6579 BlitBitmapMasked(bitmap, drawto,
6580 src1_x, src1_y + ypos4, width, ypos2 - j,
6581 dst1_x, dst1_y + ypos4 + j);
6584 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
6585 BlitBitmapMasked(bitmap, drawto,
6586 DXSIZE, DOOR_GFX_PAGEY1, i, 77,
6587 DX + DXSIZE - i, DY + j);
6588 BlitBitmapMasked(bitmap, drawto,
6589 DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
6590 DX + DXSIZE - i, DY + 140 + j);
6591 SetClipOrigin(bitmap, gc, DX - DXSIZE + i,
6592 DY - (DOOR_GFX_PAGEY1 + j));
6593 BlitBitmapMasked(bitmap, drawto,
6594 DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
6596 BlitBitmapMasked(bitmap, drawto,
6597 DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
6600 BlitBitmapMasked(bitmap, drawto,
6601 DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
6603 BlitBitmapMasked(bitmap, drawto,
6604 DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
6606 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
6607 BlitBitmapMasked(bitmap, drawto,
6608 DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
6609 DX + DXSIZE - i, DY + 77 + j);
6610 BlitBitmapMasked(bitmap, drawto,
6611 DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
6612 DX + DXSIZE - i, DY + 203 + j);
6617 redraw_mask |= REDRAW_DOOR_1;
6618 door_1_done = (a == end);
6621 if (door_state & DOOR_ACTION_2 &&
6622 x * door_2.step_offset <= door_size_2)
6624 int a = MIN(x * door_2.step_offset, door_size);
6625 int p = (door_state & DOOR_OPEN_2 ? door_size - a : a);
6626 int i = p + door_skip;
6629 struct GraphicInfo *g_left = &graphic_info[IMG_DOOR_2_WING_LEFT];
6630 struct GraphicInfo *g_right = &graphic_info[IMG_DOOR_2_WING_RIGHT];
6631 Bitmap *bm_left = g_left->bitmap;
6632 Bitmap *bm_right = g_right->bitmap;
6633 GC gc_left = bm_left->stored_clip_gc;
6634 GC gc_right = bm_right->stored_clip_gc;
6637 int classic_vxsize = 100;
6638 int classic_vysize = 100;
6639 boolean classic_door_2_size = (VXSIZE == classic_vxsize &&
6640 VYSIZE == classic_vysize);
6642 if (door_2.anim_mode & ANIM_STATIC_PANEL)
6644 BlitBitmap(bitmap_db_door, drawto,
6645 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2,
6646 VXSIZE, VYSIZE, VX, VY);
6648 else if (x <= VYSIZE)
6650 BlitBitmap(bitmap_db_door, drawto,
6651 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + p / 2,
6652 VXSIZE, VYSIZE - p / 2, VX, VY);
6654 ClearRectangle(drawto, VX, VY + VYSIZE - p / 2, VXSIZE, p / 2);
6657 if (door_2.anim_mode & ANIM_HORIZONTAL && x <= VXSIZE)
6660 int src1_x = g_right->src_x;
6661 int src1_y = g_right->src_y;
6662 int src2_x = g_left->src_x + g_left->width - i;
6663 int src2_y = g_left->src_y;
6664 int dst1_x = VX + VXSIZE - i;
6669 int height = VYSIZE;
6671 SetClipOrigin(bm_right, gc_right, dst1_x - src1_x, dst1_y - src1_y);
6672 BlitBitmapMasked(bm_right, drawto, src1_x, src1_y, width, height,
6675 SetClipOrigin(bm_left, gc_left, dst2_x - src2_x, dst2_y - src2_y);
6676 BlitBitmapMasked(bm_left, drawto, src2_x, src2_y, width, height,
6679 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
6680 int src2_x = VXSIZE - i, src2_y = DOOR_GFX_PAGEY2;
6681 int dst1_x = VX + VXSIZE - i, dst1_y = VY;
6682 int dst2_x = VX, dst2_y = VY;
6683 int width = i, height = VYSIZE;
6685 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
6686 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
6689 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
6690 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
6694 else if (door_2.anim_mode & ANIM_VERTICAL && x <= VYSIZE)
6697 int src1_x = g_right->src_x;
6698 int src1_y = g_right->src_y;
6699 int src2_x = g_left->src_x;
6700 int src2_y = g_left->src_y + g_left->height - i;
6702 int dst1_y = VY + VYSIZE - i;
6708 SetClipOrigin(bm_right, gc_right, dst1_x - src1_x, dst1_y - src1_y);
6709 BlitBitmapMasked(bm_right, drawto, src1_x, src1_y, width, height,
6712 SetClipOrigin(bm_left, gc_left, dst2_x - src2_x, dst2_y - src2_y);
6713 BlitBitmapMasked(bm_left, drawto, src2_x, src2_y, width, height,
6716 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
6717 int src2_x = 0, src2_y = DOOR_GFX_PAGEY2 + VYSIZE - i;
6718 int dst1_x = VX, dst1_y = VY + VYSIZE - i;
6719 int dst2_x = VX, dst2_y = VY;
6720 int width = VXSIZE, height = i;
6722 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
6723 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
6726 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
6727 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
6731 else if (classic_door_2_size && x <= VXSIZE) /* ANIM_DEFAULT */
6733 int j = (door_2.anim_mode == ANIM_DEFAULT ? (VXSIZE - i) / 3 : 0);
6736 int src1_x = g_right->src_x;
6737 int src1_y = g_right->src_y;
6738 int src2_x = g_left->src_x + g_left->width - i;
6739 int src2_y = g_left->src_y;
6740 int dst1_x = VX + VXSIZE - i;
6745 int height = VYSIZE / 2;
6746 int ypos1 = 0, ypos2 = VYSIZE / 2;
6748 SetClipOrigin(bm_right, gc_right,
6749 dst1_x - src1_x, dst1_y - src1_y + j);
6750 BlitBitmapMasked(bm_right, drawto,
6751 src1_x, src1_y + ypos1, width, height,
6752 dst1_x, dst1_y + ypos1 + j);
6753 SetClipOrigin(bm_left, gc_left,
6754 dst2_x - src2_x, dst2_y - src2_y - j);
6755 BlitBitmapMasked(bm_left, drawto,
6756 src2_x, src2_y + ypos1 + j, width, height - j,
6757 dst2_x, dst2_y + ypos1);
6759 SetClipOrigin(bm_left, gc_left,
6760 dst2_x - src2_x, dst2_y - src2_y - j);
6761 BlitBitmapMasked(bm_left, drawto,
6762 src2_x, src2_y + ypos2, width, height,
6763 dst2_x, dst2_y + ypos2 - j);
6764 SetClipOrigin(bm_right, gc_right,
6765 dst1_x - src1_x, dst1_y - src1_y + j);
6766 BlitBitmapMasked(bm_right, drawto,
6767 src1_x, src1_y + ypos2, width, height - j,
6768 dst1_x, dst1_y + ypos2 + j);
6770 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
6771 int src2_x = VXSIZE - i, src2_y = DOOR_GFX_PAGEY2;
6772 int dst1_x = VX + VXSIZE - i, dst1_y = VY;
6773 int dst2_x = VX, dst2_y = VY;
6774 int width = i, height = VYSIZE;
6775 int ypos = VYSIZE / 2;
6777 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y + j);
6778 BlitBitmapMasked(bitmap, drawto,
6779 src1_x, src1_y, width, ypos,
6780 dst1_x, dst1_y + j);
6781 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src1_y - j);
6782 BlitBitmapMasked(bitmap, drawto,
6783 src2_x, src2_y + j, width, ypos - j,
6786 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src1_y - j);
6787 BlitBitmapMasked(bitmap, drawto,
6788 src2_x, src2_y + ypos, width, ypos,
6789 dst2_x, dst2_y + ypos - j);
6790 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y + j);
6791 BlitBitmapMasked(bitmap, drawto,
6792 src1_x, src1_y + ypos, width, ypos - j,
6793 dst1_x, dst1_y + ypos + j);
6796 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
6797 BlitBitmapMasked(bitmap, drawto,
6798 VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
6799 VX + VXSIZE - i, VY + j);
6800 SetClipOrigin(bitmap, gc,
6801 VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
6802 BlitBitmapMasked(bitmap, drawto,
6803 VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
6806 BlitBitmapMasked(bitmap, drawto,
6807 VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
6808 i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
6809 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
6810 BlitBitmapMasked(bitmap, drawto,
6811 VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
6813 VX + VXSIZE - i, VY + VYSIZE / 2 + j);
6818 redraw_mask |= REDRAW_DOOR_2;
6819 door_2_done = (a == VXSIZE);
6822 if (!(door_state & DOOR_NO_DELAY))
6826 if (game_status == GAME_MODE_MAIN)
6829 WaitUntilDelayReached(&door_delay, door_delay_value);
6834 if (door_state & DOOR_ACTION_1)
6835 door1 = door_state & DOOR_ACTION_1;
6836 if (door_state & DOOR_ACTION_2)
6837 door2 = door_state & DOOR_ACTION_2;
6839 return (door1 | door2);
6844 void DrawSpecialEditorDoor()
6847 struct GraphicInfo *gfx1 = &graphic_info[IMG_DOOR_2_TOP_BORDER_CORRECTION];
6848 int top_border_width = gfx1->width;
6849 int top_border_height = gfx1->height;
6850 int outer_border = viewport.door_2[GAME_MODE_EDITOR].border_size;
6851 int ex = EX - outer_border;
6852 int ey = EY - outer_border;
6853 int vy = VY - outer_border;
6854 int exsize = EXSIZE + 2 * outer_border;
6856 CloseDoor(DOOR_CLOSE_2);
6858 /* draw bigger level editor toolbox window */
6859 BlitBitmap(gfx1->bitmap, drawto, gfx1->src_x, gfx1->src_y,
6860 top_border_width, top_border_height, ex, ey - top_border_height);
6861 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto, ex, vy,
6862 exsize, EYSIZE - VYSIZE + outer_border, ex, ey);
6864 /* draw bigger level editor toolbox window */
6865 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
6866 DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
6868 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
6869 EX - 6, VY - 4, EXSIZE + 12, EYSIZE - VYSIZE + 4,
6873 redraw_mask |= REDRAW_ALL;
6876 void UndrawSpecialEditorDoor()
6879 struct GraphicInfo *gfx1 = &graphic_info[IMG_DOOR_2_TOP_BORDER_CORRECTION];
6880 int top_border_width = gfx1->width;
6881 int top_border_height = gfx1->height;
6882 int outer_border = viewport.door_2[GAME_MODE_EDITOR].border_size;
6883 int ex = EX - outer_border;
6884 int ey = EY - outer_border;
6885 int ey_top = ey - top_border_height;
6886 int exsize = EXSIZE + 2 * outer_border;
6887 int eysize = EYSIZE + 2 * outer_border;
6889 /* draw normal tape recorder window */
6890 if (graphic_info[IMG_GLOBAL_BORDER].bitmap)
6892 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
6893 ex, ey_top, top_border_width, top_border_height,
6895 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
6896 ex, ey, exsize, eysize, ex, ey);
6900 // if screen background is set to "[NONE]", clear editor toolbox window
6901 ClearRectangle(drawto, ex, ey_top, top_border_width, top_border_height);
6902 ClearRectangle(drawto, ex, ey, exsize, eysize);
6905 /* draw normal tape recorder window */
6906 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
6907 EX - 6, EY - 12, EXSIZE + 12, EYSIZE - VYSIZE + 12,
6911 redraw_mask |= REDRAW_ALL;
6915 /* ---------- new tool button stuff ---------------------------------------- */
6922 struct TextPosInfo *pos;
6925 } toolbutton_info[NUM_TOOL_BUTTONS] =
6928 IMG_REQUEST_BUTTON_GFX_YES, &request.button.yes,
6929 TOOL_CTRL_ID_YES, "yes"
6932 IMG_REQUEST_BUTTON_GFX_NO, &request.button.no,
6933 TOOL_CTRL_ID_NO, "no"
6936 IMG_REQUEST_BUTTON_GFX_CONFIRM, &request.button.confirm,
6937 TOOL_CTRL_ID_CONFIRM, "confirm"
6940 IMG_REQUEST_BUTTON_GFX_PLAYER_1, &request.button.player_1,
6941 TOOL_CTRL_ID_PLAYER_1, "player 1"
6944 IMG_REQUEST_BUTTON_GFX_PLAYER_2, &request.button.player_2,
6945 TOOL_CTRL_ID_PLAYER_2, "player 2"
6948 IMG_REQUEST_BUTTON_GFX_PLAYER_3, &request.button.player_3,
6949 TOOL_CTRL_ID_PLAYER_3, "player 3"
6952 IMG_REQUEST_BUTTON_GFX_PLAYER_4, &request.button.player_4,
6953 TOOL_CTRL_ID_PLAYER_4, "player 4"
6957 void CreateToolButtons()
6961 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
6963 struct GraphicInfo *gfx = &graphic_info[toolbutton_info[i].graphic];
6964 struct TextPosInfo *pos = toolbutton_info[i].pos;
6965 struct GadgetInfo *gi;
6966 Bitmap *deco_bitmap = None;
6967 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
6968 unsigned int event_mask = GD_EVENT_RELEASED;
6971 int gd_x = gfx->src_x;
6972 int gd_y = gfx->src_y;
6973 int gd_xp = gfx->src_x + gfx->pressed_xoffset;
6974 int gd_yp = gfx->src_y + gfx->pressed_yoffset;
6977 if (global.use_envelope_request)
6978 setRequestPosition(&dx, &dy, TRUE);
6980 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
6982 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
6984 getSizedGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr), 0,
6985 pos->size, &deco_bitmap, &deco_x, &deco_y);
6986 deco_xpos = (gfx->width - pos->size) / 2;
6987 deco_ypos = (gfx->height - pos->size) / 2;
6990 gi = CreateGadget(GDI_CUSTOM_ID, id,
6991 GDI_INFO_TEXT, toolbutton_info[i].infotext,
6992 GDI_X, dx + GDI_ACTIVE_POS(pos->x),
6993 GDI_Y, dy + GDI_ACTIVE_POS(pos->y),
6994 GDI_WIDTH, gfx->width,
6995 GDI_HEIGHT, gfx->height,
6996 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
6997 GDI_STATE, GD_BUTTON_UNPRESSED,
6998 GDI_DESIGN_UNPRESSED, gfx->bitmap, gd_x, gd_y,
6999 GDI_DESIGN_PRESSED, gfx->bitmap, gd_xp, gd_yp,
7000 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
7001 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
7002 GDI_DECORATION_SIZE, pos->size, pos->size,
7003 GDI_DECORATION_SHIFTING, 1, 1,
7004 GDI_DIRECT_DRAW, FALSE,
7005 GDI_EVENT_MASK, event_mask,
7006 GDI_CALLBACK_ACTION, HandleToolButtons,
7010 Error(ERR_EXIT, "cannot create gadget");
7012 tool_gadget[id] = gi;
7018 /* graphic position values for tool buttons */
7019 #define TOOL_BUTTON_YES_XPOS 2
7020 #define TOOL_BUTTON_YES_YPOS 250
7021 #define TOOL_BUTTON_YES_GFX_YPOS 0
7022 #define TOOL_BUTTON_YES_XSIZE 46
7023 #define TOOL_BUTTON_YES_YSIZE 28
7024 #define TOOL_BUTTON_NO_XPOS 52
7025 #define TOOL_BUTTON_NO_YPOS TOOL_BUTTON_YES_YPOS
7026 #define TOOL_BUTTON_NO_GFX_YPOS TOOL_BUTTON_YES_GFX_YPOS
7027 #define TOOL_BUTTON_NO_XSIZE TOOL_BUTTON_YES_XSIZE
7028 #define TOOL_BUTTON_NO_YSIZE TOOL_BUTTON_YES_YSIZE
7029 #define TOOL_BUTTON_CONFIRM_XPOS TOOL_BUTTON_YES_XPOS
7030 #define TOOL_BUTTON_CONFIRM_YPOS TOOL_BUTTON_YES_YPOS
7031 #define TOOL_BUTTON_CONFIRM_GFX_YPOS 30
7032 #define TOOL_BUTTON_CONFIRM_XSIZE 96
7033 #define TOOL_BUTTON_CONFIRM_YSIZE TOOL_BUTTON_YES_YSIZE
7034 #define TOOL_BUTTON_PLAYER_XSIZE 30
7035 #define TOOL_BUTTON_PLAYER_YSIZE 30
7036 #define TOOL_BUTTON_PLAYER_GFX_XPOS 5
7037 #define TOOL_BUTTON_PLAYER_GFX_YPOS 185
7038 #define TOOL_BUTTON_PLAYER_XPOS (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
7039 #define TOOL_BUTTON_PLAYER_YPOS (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
7040 #define TOOL_BUTTON_PLAYER1_XPOS (TOOL_BUTTON_PLAYER_XPOS \
7041 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
7042 #define TOOL_BUTTON_PLAYER2_XPOS (TOOL_BUTTON_PLAYER_XPOS \
7043 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
7044 #define TOOL_BUTTON_PLAYER3_XPOS (TOOL_BUTTON_PLAYER_XPOS \
7045 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
7046 #define TOOL_BUTTON_PLAYER4_XPOS (TOOL_BUTTON_PLAYER_XPOS \
7047 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
7048 #define TOOL_BUTTON_PLAYER1_YPOS (TOOL_BUTTON_PLAYER_YPOS \
7049 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
7050 #define TOOL_BUTTON_PLAYER2_YPOS (TOOL_BUTTON_PLAYER_YPOS \
7051 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
7052 #define TOOL_BUTTON_PLAYER3_YPOS (TOOL_BUTTON_PLAYER_YPOS \
7053 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
7054 #define TOOL_BUTTON_PLAYER4_YPOS (TOOL_BUTTON_PLAYER_YPOS \
7055 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
7064 } toolbutton_info[NUM_TOOL_BUTTONS] =
7067 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_GFX_YPOS,
7068 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_YPOS,
7069 TOOL_BUTTON_YES_XSIZE, TOOL_BUTTON_YES_YSIZE,
7074 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_GFX_YPOS,
7075 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_YPOS,
7076 TOOL_BUTTON_NO_XSIZE, TOOL_BUTTON_NO_YSIZE,
7081 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_GFX_YPOS,
7082 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_YPOS,
7083 TOOL_BUTTON_CONFIRM_XSIZE, TOOL_BUTTON_CONFIRM_YSIZE,
7084 TOOL_CTRL_ID_CONFIRM,
7088 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
7089 TOOL_BUTTON_PLAYER1_XPOS, TOOL_BUTTON_PLAYER1_YPOS,
7090 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
7091 TOOL_CTRL_ID_PLAYER_1,
7095 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
7096 TOOL_BUTTON_PLAYER2_XPOS, TOOL_BUTTON_PLAYER2_YPOS,
7097 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
7098 TOOL_CTRL_ID_PLAYER_2,
7102 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
7103 TOOL_BUTTON_PLAYER3_XPOS, TOOL_BUTTON_PLAYER3_YPOS,
7104 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
7105 TOOL_CTRL_ID_PLAYER_3,
7109 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
7110 TOOL_BUTTON_PLAYER4_XPOS, TOOL_BUTTON_PLAYER4_YPOS,
7111 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
7112 TOOL_CTRL_ID_PLAYER_4,
7117 void CreateToolButtons()
7121 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
7123 Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
7124 Bitmap *deco_bitmap = None;
7125 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
7126 struct GadgetInfo *gi;
7127 unsigned int event_mask;
7128 int gd_xoffset, gd_yoffset;
7129 int gd_x1, gd_x2, gd_y;
7132 event_mask = GD_EVENT_RELEASED;
7134 gd_xoffset = toolbutton_info[i].xpos;
7135 gd_yoffset = toolbutton_info[i].ypos;
7136 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
7137 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
7138 gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
7140 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
7142 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
7144 getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr),
7145 &deco_bitmap, &deco_x, &deco_y);
7146 deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
7147 deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
7150 gi = CreateGadget(GDI_CUSTOM_ID, id,
7151 GDI_INFO_TEXT, toolbutton_info[i].infotext,
7152 GDI_X, DX + GDI_ACTIVE_POS(toolbutton_info[i].x),
7153 GDI_Y, DY + GDI_ACTIVE_POS(toolbutton_info[i].y),
7154 GDI_WIDTH, toolbutton_info[i].width,
7155 GDI_HEIGHT, toolbutton_info[i].height,
7156 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
7157 GDI_STATE, GD_BUTTON_UNPRESSED,
7158 GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
7159 GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
7160 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
7161 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
7162 GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
7163 GDI_DECORATION_SHIFTING, 1, 1,
7164 GDI_DIRECT_DRAW, FALSE,
7165 GDI_EVENT_MASK, event_mask,
7166 GDI_CALLBACK_ACTION, HandleToolButtons,
7170 Error(ERR_EXIT, "cannot create gadget");
7172 tool_gadget[id] = gi;
7178 void FreeToolButtons()
7182 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
7183 FreeGadget(tool_gadget[i]);
7186 static void UnmapToolButtons()
7190 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
7191 UnmapGadget(tool_gadget[i]);
7194 static void HandleToolButtons(struct GadgetInfo *gi)
7196 request_gadget_id = gi->custom_id;
7199 static struct Mapping_EM_to_RND_object
7202 boolean is_rnd_to_em_mapping; /* unique mapping EM <-> RND */
7203 boolean is_backside; /* backside of moving element */
7209 em_object_mapping_list[] =
7212 Xblank, TRUE, FALSE,
7216 Yacid_splash_eB, FALSE, FALSE,
7217 EL_ACID_SPLASH_RIGHT, -1, -1
7220 Yacid_splash_wB, FALSE, FALSE,
7221 EL_ACID_SPLASH_LEFT, -1, -1
7224 #ifdef EM_ENGINE_BAD_ROLL
7226 Xstone_force_e, FALSE, FALSE,
7227 EL_ROCK, -1, MV_BIT_RIGHT
7230 Xstone_force_w, FALSE, FALSE,
7231 EL_ROCK, -1, MV_BIT_LEFT
7234 Xnut_force_e, FALSE, FALSE,
7235 EL_NUT, -1, MV_BIT_RIGHT
7238 Xnut_force_w, FALSE, FALSE,
7239 EL_NUT, -1, MV_BIT_LEFT
7242 Xspring_force_e, FALSE, FALSE,
7243 EL_SPRING, -1, MV_BIT_RIGHT
7246 Xspring_force_w, FALSE, FALSE,
7247 EL_SPRING, -1, MV_BIT_LEFT
7250 Xemerald_force_e, FALSE, FALSE,
7251 EL_EMERALD, -1, MV_BIT_RIGHT
7254 Xemerald_force_w, FALSE, FALSE,
7255 EL_EMERALD, -1, MV_BIT_LEFT
7258 Xdiamond_force_e, FALSE, FALSE,
7259 EL_DIAMOND, -1, MV_BIT_RIGHT
7262 Xdiamond_force_w, FALSE, FALSE,
7263 EL_DIAMOND, -1, MV_BIT_LEFT
7266 Xbomb_force_e, FALSE, FALSE,
7267 EL_BOMB, -1, MV_BIT_RIGHT
7270 Xbomb_force_w, FALSE, FALSE,
7271 EL_BOMB, -1, MV_BIT_LEFT
7273 #endif /* EM_ENGINE_BAD_ROLL */
7276 Xstone, TRUE, FALSE,
7280 Xstone_pause, FALSE, FALSE,
7284 Xstone_fall, FALSE, FALSE,
7288 Ystone_s, FALSE, FALSE,
7289 EL_ROCK, ACTION_FALLING, -1
7292 Ystone_sB, FALSE, TRUE,
7293 EL_ROCK, ACTION_FALLING, -1
7296 Ystone_e, FALSE, FALSE,
7297 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
7300 Ystone_eB, FALSE, TRUE,
7301 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
7304 Ystone_w, FALSE, FALSE,
7305 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
7308 Ystone_wB, FALSE, TRUE,
7309 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
7316 Xnut_pause, FALSE, FALSE,
7320 Xnut_fall, FALSE, FALSE,
7324 Ynut_s, FALSE, FALSE,
7325 EL_NUT, ACTION_FALLING, -1
7328 Ynut_sB, FALSE, TRUE,
7329 EL_NUT, ACTION_FALLING, -1
7332 Ynut_e, FALSE, FALSE,
7333 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
7336 Ynut_eB, FALSE, TRUE,
7337 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
7340 Ynut_w, FALSE, FALSE,
7341 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
7344 Ynut_wB, FALSE, TRUE,
7345 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
7348 Xbug_n, TRUE, FALSE,
7352 Xbug_e, TRUE, FALSE,
7353 EL_BUG_RIGHT, -1, -1
7356 Xbug_s, TRUE, FALSE,
7360 Xbug_w, TRUE, FALSE,
7364 Xbug_gon, FALSE, FALSE,
7368 Xbug_goe, FALSE, FALSE,
7369 EL_BUG_RIGHT, -1, -1
7372 Xbug_gos, FALSE, FALSE,
7376 Xbug_gow, FALSE, FALSE,
7380 Ybug_n, FALSE, FALSE,
7381 EL_BUG, ACTION_MOVING, MV_BIT_UP
7384 Ybug_nB, FALSE, TRUE,
7385 EL_BUG, ACTION_MOVING, MV_BIT_UP
7388 Ybug_e, FALSE, FALSE,
7389 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
7392 Ybug_eB, FALSE, TRUE,
7393 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
7396 Ybug_s, FALSE, FALSE,
7397 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
7400 Ybug_sB, FALSE, TRUE,
7401 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
7404 Ybug_w, FALSE, FALSE,
7405 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
7408 Ybug_wB, FALSE, TRUE,
7409 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
7412 Ybug_w_n, FALSE, FALSE,
7413 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
7416 Ybug_n_e, FALSE, FALSE,
7417 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
7420 Ybug_e_s, FALSE, FALSE,
7421 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
7424 Ybug_s_w, FALSE, FALSE,
7425 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
7428 Ybug_e_n, FALSE, FALSE,
7429 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
7432 Ybug_s_e, FALSE, FALSE,
7433 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
7436 Ybug_w_s, FALSE, FALSE,
7437 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
7440 Ybug_n_w, FALSE, FALSE,
7441 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
7444 Ybug_stone, FALSE, FALSE,
7445 EL_BUG, ACTION_SMASHED_BY_ROCK, -1
7448 Ybug_spring, FALSE, FALSE,
7449 EL_BUG, ACTION_SMASHED_BY_SPRING, -1
7452 Xtank_n, TRUE, FALSE,
7453 EL_SPACESHIP_UP, -1, -1
7456 Xtank_e, TRUE, FALSE,
7457 EL_SPACESHIP_RIGHT, -1, -1
7460 Xtank_s, TRUE, FALSE,
7461 EL_SPACESHIP_DOWN, -1, -1
7464 Xtank_w, TRUE, FALSE,
7465 EL_SPACESHIP_LEFT, -1, -1
7468 Xtank_gon, FALSE, FALSE,
7469 EL_SPACESHIP_UP, -1, -1
7472 Xtank_goe, FALSE, FALSE,
7473 EL_SPACESHIP_RIGHT, -1, -1
7476 Xtank_gos, FALSE, FALSE,
7477 EL_SPACESHIP_DOWN, -1, -1
7480 Xtank_gow, FALSE, FALSE,
7481 EL_SPACESHIP_LEFT, -1, -1
7484 Ytank_n, FALSE, FALSE,
7485 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
7488 Ytank_nB, FALSE, TRUE,
7489 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
7492 Ytank_e, FALSE, FALSE,
7493 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
7496 Ytank_eB, FALSE, TRUE,
7497 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
7500 Ytank_s, FALSE, FALSE,
7501 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
7504 Ytank_sB, FALSE, TRUE,
7505 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
7508 Ytank_w, FALSE, FALSE,
7509 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
7512 Ytank_wB, FALSE, TRUE,
7513 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
7516 Ytank_w_n, FALSE, FALSE,
7517 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
7520 Ytank_n_e, FALSE, FALSE,
7521 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
7524 Ytank_e_s, FALSE, FALSE,
7525 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
7528 Ytank_s_w, FALSE, FALSE,
7529 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
7532 Ytank_e_n, FALSE, FALSE,
7533 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
7536 Ytank_s_e, FALSE, FALSE,
7537 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
7540 Ytank_w_s, FALSE, FALSE,
7541 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
7544 Ytank_n_w, FALSE, FALSE,
7545 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
7548 Ytank_stone, FALSE, FALSE,
7549 EL_SPACESHIP, ACTION_SMASHED_BY_ROCK, -1
7552 Ytank_spring, FALSE, FALSE,
7553 EL_SPACESHIP, ACTION_SMASHED_BY_SPRING, -1
7556 Xandroid, TRUE, FALSE,
7557 EL_EMC_ANDROID, ACTION_ACTIVE, -1
7560 Xandroid_1_n, FALSE, FALSE,
7561 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
7564 Xandroid_2_n, FALSE, FALSE,
7565 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
7568 Xandroid_1_e, FALSE, FALSE,
7569 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
7572 Xandroid_2_e, FALSE, FALSE,
7573 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
7576 Xandroid_1_w, FALSE, FALSE,
7577 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
7580 Xandroid_2_w, FALSE, FALSE,
7581 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
7584 Xandroid_1_s, FALSE, FALSE,
7585 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
7588 Xandroid_2_s, FALSE, FALSE,
7589 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
7592 Yandroid_n, FALSE, FALSE,
7593 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
7596 Yandroid_nB, FALSE, TRUE,
7597 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
7600 Yandroid_ne, FALSE, FALSE,
7601 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPRIGHT
7604 Yandroid_neB, FALSE, TRUE,
7605 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPRIGHT
7608 Yandroid_e, FALSE, FALSE,
7609 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
7612 Yandroid_eB, FALSE, TRUE,
7613 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
7616 Yandroid_se, FALSE, FALSE,
7617 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNRIGHT
7620 Yandroid_seB, FALSE, TRUE,
7621 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNRIGHT
7624 Yandroid_s, FALSE, FALSE,
7625 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
7628 Yandroid_sB, FALSE, TRUE,
7629 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
7632 Yandroid_sw, FALSE, FALSE,
7633 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNLEFT
7636 Yandroid_swB, FALSE, TRUE,
7637 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNLEFT
7640 Yandroid_w, FALSE, FALSE,
7641 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
7644 Yandroid_wB, FALSE, TRUE,
7645 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
7648 Yandroid_nw, FALSE, FALSE,
7649 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPLEFT
7652 Yandroid_nwB, FALSE, TRUE,
7653 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPLEFT
7656 Xspring, TRUE, FALSE,
7660 Xspring_pause, FALSE, FALSE,
7664 Xspring_e, FALSE, FALSE,
7668 Xspring_w, FALSE, FALSE,
7672 Xspring_fall, FALSE, FALSE,
7676 Yspring_s, FALSE, FALSE,
7677 EL_SPRING, ACTION_FALLING, -1
7680 Yspring_sB, FALSE, TRUE,
7681 EL_SPRING, ACTION_FALLING, -1
7684 Yspring_e, FALSE, FALSE,
7685 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
7688 Yspring_eB, FALSE, TRUE,
7689 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
7692 Yspring_w, FALSE, FALSE,
7693 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
7696 Yspring_wB, FALSE, TRUE,
7697 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
7700 Yspring_kill_e, FALSE, FALSE,
7701 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
7704 Yspring_kill_eB, FALSE, TRUE,
7705 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
7708 Yspring_kill_w, FALSE, FALSE,
7709 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
7712 Yspring_kill_wB, FALSE, TRUE,
7713 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
7716 Xeater_n, TRUE, FALSE,
7717 EL_YAMYAM_UP, -1, -1
7720 Xeater_e, TRUE, FALSE,
7721 EL_YAMYAM_RIGHT, -1, -1
7724 Xeater_w, TRUE, FALSE,
7725 EL_YAMYAM_LEFT, -1, -1
7728 Xeater_s, TRUE, FALSE,
7729 EL_YAMYAM_DOWN, -1, -1
7732 Yeater_n, FALSE, FALSE,
7733 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
7736 Yeater_nB, FALSE, TRUE,
7737 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
7740 Yeater_e, FALSE, FALSE,
7741 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
7744 Yeater_eB, FALSE, TRUE,
7745 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
7748 Yeater_s, FALSE, FALSE,
7749 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
7752 Yeater_sB, FALSE, TRUE,
7753 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
7756 Yeater_w, FALSE, FALSE,
7757 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
7760 Yeater_wB, FALSE, TRUE,
7761 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
7764 Yeater_stone, FALSE, FALSE,
7765 EL_YAMYAM, ACTION_SMASHED_BY_ROCK, -1
7768 Yeater_spring, FALSE, FALSE,
7769 EL_YAMYAM, ACTION_SMASHED_BY_SPRING, -1
7772 Xalien, TRUE, FALSE,
7776 Xalien_pause, FALSE, FALSE,
7780 Yalien_n, FALSE, FALSE,
7781 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
7784 Yalien_nB, FALSE, TRUE,
7785 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
7788 Yalien_e, FALSE, FALSE,
7789 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
7792 Yalien_eB, FALSE, TRUE,
7793 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
7796 Yalien_s, FALSE, FALSE,
7797 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
7800 Yalien_sB, FALSE, TRUE,
7801 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
7804 Yalien_w, FALSE, FALSE,
7805 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
7808 Yalien_wB, FALSE, TRUE,
7809 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
7812 Yalien_stone, FALSE, FALSE,
7813 EL_ROBOT, ACTION_SMASHED_BY_ROCK, -1
7816 Yalien_spring, FALSE, FALSE,
7817 EL_ROBOT, ACTION_SMASHED_BY_SPRING, -1
7820 Xemerald, TRUE, FALSE,
7824 Xemerald_pause, FALSE, FALSE,
7828 Xemerald_fall, FALSE, FALSE,
7832 Xemerald_shine, FALSE, FALSE,
7833 EL_EMERALD, ACTION_TWINKLING, -1
7836 Yemerald_s, FALSE, FALSE,
7837 EL_EMERALD, ACTION_FALLING, -1
7840 Yemerald_sB, FALSE, TRUE,
7841 EL_EMERALD, ACTION_FALLING, -1
7844 Yemerald_e, FALSE, FALSE,
7845 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
7848 Yemerald_eB, FALSE, TRUE,
7849 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
7852 Yemerald_w, FALSE, FALSE,
7853 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
7856 Yemerald_wB, FALSE, TRUE,
7857 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
7860 Yemerald_eat, FALSE, FALSE,
7861 EL_EMERALD, ACTION_COLLECTING, -1
7864 Yemerald_stone, FALSE, FALSE,
7865 EL_NUT, ACTION_BREAKING, -1
7868 Xdiamond, TRUE, FALSE,
7872 Xdiamond_pause, FALSE, FALSE,
7876 Xdiamond_fall, FALSE, FALSE,
7880 Xdiamond_shine, FALSE, FALSE,
7881 EL_DIAMOND, ACTION_TWINKLING, -1
7884 Ydiamond_s, FALSE, FALSE,
7885 EL_DIAMOND, ACTION_FALLING, -1
7888 Ydiamond_sB, FALSE, TRUE,
7889 EL_DIAMOND, ACTION_FALLING, -1
7892 Ydiamond_e, FALSE, FALSE,
7893 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
7896 Ydiamond_eB, FALSE, TRUE,
7897 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
7900 Ydiamond_w, FALSE, FALSE,
7901 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
7904 Ydiamond_wB, FALSE, TRUE,
7905 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
7908 Ydiamond_eat, FALSE, FALSE,
7909 EL_DIAMOND, ACTION_COLLECTING, -1
7912 Ydiamond_stone, FALSE, FALSE,
7913 EL_DIAMOND, ACTION_SMASHED_BY_ROCK, -1
7916 Xdrip_fall, TRUE, FALSE,
7917 EL_AMOEBA_DROP, -1, -1
7920 Xdrip_stretch, FALSE, FALSE,
7921 EL_AMOEBA_DROP, ACTION_FALLING, -1
7924 Xdrip_stretchB, FALSE, TRUE,
7925 EL_AMOEBA_DROP, ACTION_FALLING, -1
7928 Xdrip_eat, FALSE, FALSE,
7929 EL_AMOEBA_DROP, ACTION_GROWING, -1
7932 Ydrip_s1, FALSE, FALSE,
7933 EL_AMOEBA_DROP, ACTION_FALLING, -1
7936 Ydrip_s1B, FALSE, TRUE,
7937 EL_AMOEBA_DROP, ACTION_FALLING, -1
7940 Ydrip_s2, FALSE, FALSE,
7941 EL_AMOEBA_DROP, ACTION_FALLING, -1
7944 Ydrip_s2B, FALSE, TRUE,
7945 EL_AMOEBA_DROP, ACTION_FALLING, -1
7952 Xbomb_pause, FALSE, FALSE,
7956 Xbomb_fall, FALSE, FALSE,
7960 Ybomb_s, FALSE, FALSE,
7961 EL_BOMB, ACTION_FALLING, -1
7964 Ybomb_sB, FALSE, TRUE,
7965 EL_BOMB, ACTION_FALLING, -1
7968 Ybomb_e, FALSE, FALSE,
7969 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
7972 Ybomb_eB, FALSE, TRUE,
7973 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
7976 Ybomb_w, FALSE, FALSE,
7977 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
7980 Ybomb_wB, FALSE, TRUE,
7981 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
7984 Ybomb_eat, FALSE, FALSE,
7985 EL_BOMB, ACTION_ACTIVATING, -1
7988 Xballoon, TRUE, FALSE,
7992 Yballoon_n, FALSE, FALSE,
7993 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
7996 Yballoon_nB, FALSE, TRUE,
7997 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
8000 Yballoon_e, FALSE, FALSE,
8001 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
8004 Yballoon_eB, FALSE, TRUE,
8005 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
8008 Yballoon_s, FALSE, FALSE,
8009 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
8012 Yballoon_sB, FALSE, TRUE,
8013 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
8016 Yballoon_w, FALSE, FALSE,
8017 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
8020 Yballoon_wB, FALSE, TRUE,
8021 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
8024 Xgrass, TRUE, FALSE,
8025 EL_EMC_GRASS, -1, -1
8028 Ygrass_nB, FALSE, FALSE,
8029 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_UP
8032 Ygrass_eB, FALSE, FALSE,
8033 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_RIGHT
8036 Ygrass_sB, FALSE, FALSE,
8037 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_DOWN
8040 Ygrass_wB, FALSE, FALSE,
8041 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_LEFT
8048 Ydirt_nB, FALSE, FALSE,
8049 EL_SAND, ACTION_DIGGING, MV_BIT_UP
8052 Ydirt_eB, FALSE, FALSE,
8053 EL_SAND, ACTION_DIGGING, MV_BIT_RIGHT
8056 Ydirt_sB, FALSE, FALSE,
8057 EL_SAND, ACTION_DIGGING, MV_BIT_DOWN
8060 Ydirt_wB, FALSE, FALSE,
8061 EL_SAND, ACTION_DIGGING, MV_BIT_LEFT
8064 Xacid_ne, TRUE, FALSE,
8065 EL_ACID_POOL_TOPRIGHT, -1, -1
8068 Xacid_se, TRUE, FALSE,
8069 EL_ACID_POOL_BOTTOMRIGHT, -1, -1
8072 Xacid_s, TRUE, FALSE,
8073 EL_ACID_POOL_BOTTOM, -1, -1
8076 Xacid_sw, TRUE, FALSE,
8077 EL_ACID_POOL_BOTTOMLEFT, -1, -1
8080 Xacid_nw, TRUE, FALSE,
8081 EL_ACID_POOL_TOPLEFT, -1, -1
8084 Xacid_1, TRUE, FALSE,
8088 Xacid_2, FALSE, FALSE,
8092 Xacid_3, FALSE, FALSE,
8096 Xacid_4, FALSE, FALSE,
8100 Xacid_5, FALSE, FALSE,
8104 Xacid_6, FALSE, FALSE,
8108 Xacid_7, FALSE, FALSE,
8112 Xacid_8, FALSE, FALSE,
8116 Xball_1, TRUE, FALSE,
8117 EL_EMC_MAGIC_BALL, -1, -1
8120 Xball_1B, FALSE, FALSE,
8121 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
8124 Xball_2, FALSE, FALSE,
8125 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
8128 Xball_2B, FALSE, FALSE,
8129 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
8132 Yball_eat, FALSE, FALSE,
8133 EL_EMC_MAGIC_BALL, ACTION_DROPPING, -1
8136 Ykey_1_eat, FALSE, FALSE,
8137 EL_EM_KEY_1, ACTION_COLLECTING, -1
8140 Ykey_2_eat, FALSE, FALSE,
8141 EL_EM_KEY_2, ACTION_COLLECTING, -1
8144 Ykey_3_eat, FALSE, FALSE,
8145 EL_EM_KEY_3, ACTION_COLLECTING, -1
8148 Ykey_4_eat, FALSE, FALSE,
8149 EL_EM_KEY_4, ACTION_COLLECTING, -1
8152 Ykey_5_eat, FALSE, FALSE,
8153 EL_EMC_KEY_5, ACTION_COLLECTING, -1
8156 Ykey_6_eat, FALSE, FALSE,
8157 EL_EMC_KEY_6, ACTION_COLLECTING, -1
8160 Ykey_7_eat, FALSE, FALSE,
8161 EL_EMC_KEY_7, ACTION_COLLECTING, -1
8164 Ykey_8_eat, FALSE, FALSE,
8165 EL_EMC_KEY_8, ACTION_COLLECTING, -1
8168 Ylenses_eat, FALSE, FALSE,
8169 EL_EMC_LENSES, ACTION_COLLECTING, -1
8172 Ymagnify_eat, FALSE, FALSE,
8173 EL_EMC_MAGNIFIER, ACTION_COLLECTING, -1
8176 Ygrass_eat, FALSE, FALSE,
8177 EL_EMC_GRASS, ACTION_SNAPPING, -1
8180 Ydirt_eat, FALSE, FALSE,
8181 EL_SAND, ACTION_SNAPPING, -1
8184 Xgrow_ns, TRUE, FALSE,
8185 EL_EXPANDABLE_WALL_VERTICAL, -1, -1
8188 Ygrow_ns_eat, FALSE, FALSE,
8189 EL_EXPANDABLE_WALL_VERTICAL, ACTION_GROWING, -1
8192 Xgrow_ew, TRUE, FALSE,
8193 EL_EXPANDABLE_WALL_HORIZONTAL, -1, -1
8196 Ygrow_ew_eat, FALSE, FALSE,
8197 EL_EXPANDABLE_WALL_HORIZONTAL, ACTION_GROWING, -1
8200 Xwonderwall, TRUE, FALSE,
8201 EL_MAGIC_WALL, -1, -1
8204 XwonderwallB, FALSE, FALSE,
8205 EL_MAGIC_WALL, ACTION_ACTIVE, -1
8208 Xamoeba_1, TRUE, FALSE,
8209 EL_AMOEBA_DRY, ACTION_OTHER, -1
8212 Xamoeba_2, FALSE, FALSE,
8213 EL_AMOEBA_DRY, ACTION_OTHER, -1
8216 Xamoeba_3, FALSE, FALSE,
8217 EL_AMOEBA_DRY, ACTION_OTHER, -1
8220 Xamoeba_4, FALSE, FALSE,
8221 EL_AMOEBA_DRY, ACTION_OTHER, -1
8224 Xamoeba_5, TRUE, FALSE,
8225 EL_AMOEBA_WET, ACTION_OTHER, -1
8228 Xamoeba_6, FALSE, FALSE,
8229 EL_AMOEBA_WET, ACTION_OTHER, -1
8232 Xamoeba_7, FALSE, FALSE,
8233 EL_AMOEBA_WET, ACTION_OTHER, -1
8236 Xamoeba_8, FALSE, FALSE,
8237 EL_AMOEBA_WET, ACTION_OTHER, -1
8240 Xdoor_1, TRUE, FALSE,
8241 EL_EM_GATE_1, -1, -1
8244 Xdoor_2, TRUE, FALSE,
8245 EL_EM_GATE_2, -1, -1
8248 Xdoor_3, TRUE, FALSE,
8249 EL_EM_GATE_3, -1, -1
8252 Xdoor_4, TRUE, FALSE,
8253 EL_EM_GATE_4, -1, -1
8256 Xdoor_5, TRUE, FALSE,
8257 EL_EMC_GATE_5, -1, -1
8260 Xdoor_6, TRUE, FALSE,
8261 EL_EMC_GATE_6, -1, -1
8264 Xdoor_7, TRUE, FALSE,
8265 EL_EMC_GATE_7, -1, -1
8268 Xdoor_8, TRUE, FALSE,
8269 EL_EMC_GATE_8, -1, -1
8272 Xkey_1, TRUE, FALSE,
8276 Xkey_2, TRUE, FALSE,
8280 Xkey_3, TRUE, FALSE,
8284 Xkey_4, TRUE, FALSE,
8288 Xkey_5, TRUE, FALSE,
8289 EL_EMC_KEY_5, -1, -1
8292 Xkey_6, TRUE, FALSE,
8293 EL_EMC_KEY_6, -1, -1
8296 Xkey_7, TRUE, FALSE,
8297 EL_EMC_KEY_7, -1, -1
8300 Xkey_8, TRUE, FALSE,
8301 EL_EMC_KEY_8, -1, -1
8304 Xwind_n, TRUE, FALSE,
8305 EL_BALLOON_SWITCH_UP, -1, -1
8308 Xwind_e, TRUE, FALSE,
8309 EL_BALLOON_SWITCH_RIGHT, -1, -1
8312 Xwind_s, TRUE, FALSE,
8313 EL_BALLOON_SWITCH_DOWN, -1, -1
8316 Xwind_w, TRUE, FALSE,
8317 EL_BALLOON_SWITCH_LEFT, -1, -1
8320 Xwind_nesw, TRUE, FALSE,
8321 EL_BALLOON_SWITCH_ANY, -1, -1
8324 Xwind_stop, TRUE, FALSE,
8325 EL_BALLOON_SWITCH_NONE, -1, -1
8329 EL_EM_EXIT_CLOSED, -1, -1
8332 Xexit_1, TRUE, FALSE,
8333 EL_EM_EXIT_OPEN, -1, -1
8336 Xexit_2, FALSE, FALSE,
8337 EL_EM_EXIT_OPEN, -1, -1
8340 Xexit_3, FALSE, FALSE,
8341 EL_EM_EXIT_OPEN, -1, -1
8344 Xdynamite, TRUE, FALSE,
8345 EL_EM_DYNAMITE, -1, -1
8348 Ydynamite_eat, FALSE, FALSE,
8349 EL_EM_DYNAMITE, ACTION_COLLECTING, -1
8352 Xdynamite_1, TRUE, FALSE,
8353 EL_EM_DYNAMITE_ACTIVE, -1, -1
8356 Xdynamite_2, FALSE, FALSE,
8357 EL_EM_DYNAMITE_ACTIVE, -1, -1
8360 Xdynamite_3, FALSE, FALSE,
8361 EL_EM_DYNAMITE_ACTIVE, -1, -1
8364 Xdynamite_4, FALSE, FALSE,
8365 EL_EM_DYNAMITE_ACTIVE, -1, -1
8368 Xbumper, TRUE, FALSE,
8369 EL_EMC_SPRING_BUMPER, -1, -1
8372 XbumperB, FALSE, FALSE,
8373 EL_EMC_SPRING_BUMPER, ACTION_ACTIVE, -1
8376 Xwheel, TRUE, FALSE,
8377 EL_ROBOT_WHEEL, -1, -1
8380 XwheelB, FALSE, FALSE,
8381 EL_ROBOT_WHEEL, ACTION_ACTIVE, -1
8384 Xswitch, TRUE, FALSE,
8385 EL_EMC_MAGIC_BALL_SWITCH, -1, -1
8388 XswitchB, FALSE, FALSE,
8389 EL_EMC_MAGIC_BALL_SWITCH, ACTION_ACTIVE, -1
8393 EL_QUICKSAND_EMPTY, -1, -1
8396 Xsand_stone, TRUE, FALSE,
8397 EL_QUICKSAND_FULL, -1, -1
8400 Xsand_stonein_1, FALSE, TRUE,
8401 EL_ROCK, ACTION_FILLING, -1
8404 Xsand_stonein_2, FALSE, TRUE,
8405 EL_ROCK, ACTION_FILLING, -1
8408 Xsand_stonein_3, FALSE, TRUE,
8409 EL_ROCK, ACTION_FILLING, -1
8412 Xsand_stonein_4, FALSE, TRUE,
8413 EL_ROCK, ACTION_FILLING, -1
8417 Xsand_stonesand_1, FALSE, FALSE,
8418 EL_QUICKSAND_EMPTYING, -1, -1
8421 Xsand_stonesand_2, FALSE, FALSE,
8422 EL_QUICKSAND_EMPTYING, -1, -1
8425 Xsand_stonesand_3, FALSE, FALSE,
8426 EL_QUICKSAND_EMPTYING, -1, -1
8429 Xsand_stonesand_4, FALSE, FALSE,
8430 EL_QUICKSAND_EMPTYING, -1, -1
8433 Xsand_stonesand_quickout_1, FALSE, FALSE,
8434 EL_QUICKSAND_EMPTYING, -1, -1
8437 Xsand_stonesand_quickout_2, FALSE, FALSE,
8438 EL_QUICKSAND_EMPTYING, -1, -1
8442 Xsand_stonesand_1, FALSE, FALSE,
8443 EL_QUICKSAND_FULL, -1, -1
8446 Xsand_stonesand_2, FALSE, FALSE,
8447 EL_QUICKSAND_FULL, -1, -1
8450 Xsand_stonesand_3, FALSE, FALSE,
8451 EL_QUICKSAND_FULL, -1, -1
8454 Xsand_stonesand_4, FALSE, FALSE,
8455 EL_QUICKSAND_FULL, -1, -1
8459 Xsand_stoneout_1, FALSE, FALSE,
8460 EL_ROCK, ACTION_EMPTYING, -1
8463 Xsand_stoneout_2, FALSE, FALSE,
8464 EL_ROCK, ACTION_EMPTYING, -1
8468 Xsand_sandstone_1, FALSE, FALSE,
8469 EL_QUICKSAND_FILLING, -1, -1
8472 Xsand_sandstone_2, FALSE, FALSE,
8473 EL_QUICKSAND_FILLING, -1, -1
8476 Xsand_sandstone_3, FALSE, FALSE,
8477 EL_QUICKSAND_FILLING, -1, -1
8480 Xsand_sandstone_4, FALSE, FALSE,
8481 EL_QUICKSAND_FILLING, -1, -1
8485 Xsand_sandstone_1, FALSE, FALSE,
8486 EL_QUICKSAND_FULL, -1, -1
8489 Xsand_sandstone_2, FALSE, FALSE,
8490 EL_QUICKSAND_FULL, -1, -1
8493 Xsand_sandstone_3, FALSE, FALSE,
8494 EL_QUICKSAND_FULL, -1, -1
8497 Xsand_sandstone_4, FALSE, FALSE,
8498 EL_QUICKSAND_FULL, -1, -1
8502 Xplant, TRUE, FALSE,
8503 EL_EMC_PLANT, -1, -1
8506 Yplant, FALSE, FALSE,
8507 EL_EMC_PLANT, -1, -1
8510 Xlenses, TRUE, FALSE,
8511 EL_EMC_LENSES, -1, -1
8514 Xmagnify, TRUE, FALSE,
8515 EL_EMC_MAGNIFIER, -1, -1
8518 Xdripper, TRUE, FALSE,
8519 EL_EMC_DRIPPER, -1, -1
8522 XdripperB, FALSE, FALSE,
8523 EL_EMC_DRIPPER, ACTION_ACTIVE, -1
8526 Xfake_blank, TRUE, FALSE,
8527 EL_INVISIBLE_WALL, -1, -1
8530 Xfake_blankB, FALSE, FALSE,
8531 EL_INVISIBLE_WALL, ACTION_ACTIVE, -1
8534 Xfake_grass, TRUE, FALSE,
8535 EL_EMC_FAKE_GRASS, -1, -1
8538 Xfake_grassB, FALSE, FALSE,
8539 EL_EMC_FAKE_GRASS, ACTION_ACTIVE, -1
8542 Xfake_door_1, TRUE, FALSE,
8543 EL_EM_GATE_1_GRAY, -1, -1
8546 Xfake_door_2, TRUE, FALSE,
8547 EL_EM_GATE_2_GRAY, -1, -1
8550 Xfake_door_3, TRUE, FALSE,
8551 EL_EM_GATE_3_GRAY, -1, -1
8554 Xfake_door_4, TRUE, FALSE,
8555 EL_EM_GATE_4_GRAY, -1, -1
8558 Xfake_door_5, TRUE, FALSE,
8559 EL_EMC_GATE_5_GRAY, -1, -1
8562 Xfake_door_6, TRUE, FALSE,
8563 EL_EMC_GATE_6_GRAY, -1, -1
8566 Xfake_door_7, TRUE, FALSE,
8567 EL_EMC_GATE_7_GRAY, -1, -1
8570 Xfake_door_8, TRUE, FALSE,
8571 EL_EMC_GATE_8_GRAY, -1, -1
8574 Xfake_acid_1, TRUE, FALSE,
8575 EL_EMC_FAKE_ACID, -1, -1
8578 Xfake_acid_2, FALSE, FALSE,
8579 EL_EMC_FAKE_ACID, -1, -1
8582 Xfake_acid_3, FALSE, FALSE,
8583 EL_EMC_FAKE_ACID, -1, -1
8586 Xfake_acid_4, FALSE, FALSE,
8587 EL_EMC_FAKE_ACID, -1, -1
8590 Xfake_acid_5, FALSE, FALSE,
8591 EL_EMC_FAKE_ACID, -1, -1
8594 Xfake_acid_6, FALSE, FALSE,
8595 EL_EMC_FAKE_ACID, -1, -1
8598 Xfake_acid_7, FALSE, FALSE,
8599 EL_EMC_FAKE_ACID, -1, -1
8602 Xfake_acid_8, FALSE, FALSE,
8603 EL_EMC_FAKE_ACID, -1, -1
8606 Xsteel_1, TRUE, FALSE,
8607 EL_STEELWALL, -1, -1
8610 Xsteel_2, TRUE, FALSE,
8611 EL_EMC_STEELWALL_2, -1, -1
8614 Xsteel_3, TRUE, FALSE,
8615 EL_EMC_STEELWALL_3, -1, -1
8618 Xsteel_4, TRUE, FALSE,
8619 EL_EMC_STEELWALL_4, -1, -1
8622 Xwall_1, TRUE, FALSE,
8626 Xwall_2, TRUE, FALSE,
8627 EL_EMC_WALL_14, -1, -1
8630 Xwall_3, TRUE, FALSE,
8631 EL_EMC_WALL_15, -1, -1
8634 Xwall_4, TRUE, FALSE,
8635 EL_EMC_WALL_16, -1, -1
8638 Xround_wall_1, TRUE, FALSE,
8639 EL_WALL_SLIPPERY, -1, -1
8642 Xround_wall_2, TRUE, FALSE,
8643 EL_EMC_WALL_SLIPPERY_2, -1, -1
8646 Xround_wall_3, TRUE, FALSE,
8647 EL_EMC_WALL_SLIPPERY_3, -1, -1
8650 Xround_wall_4, TRUE, FALSE,
8651 EL_EMC_WALL_SLIPPERY_4, -1, -1
8654 Xdecor_1, TRUE, FALSE,
8655 EL_EMC_WALL_8, -1, -1
8658 Xdecor_2, TRUE, FALSE,
8659 EL_EMC_WALL_6, -1, -1
8662 Xdecor_3, TRUE, FALSE,
8663 EL_EMC_WALL_4, -1, -1
8666 Xdecor_4, TRUE, FALSE,
8667 EL_EMC_WALL_7, -1, -1
8670 Xdecor_5, TRUE, FALSE,
8671 EL_EMC_WALL_5, -1, -1
8674 Xdecor_6, TRUE, FALSE,
8675 EL_EMC_WALL_9, -1, -1
8678 Xdecor_7, TRUE, FALSE,
8679 EL_EMC_WALL_10, -1, -1
8682 Xdecor_8, TRUE, FALSE,
8683 EL_EMC_WALL_1, -1, -1
8686 Xdecor_9, TRUE, FALSE,
8687 EL_EMC_WALL_2, -1, -1
8690 Xdecor_10, TRUE, FALSE,
8691 EL_EMC_WALL_3, -1, -1
8694 Xdecor_11, TRUE, FALSE,
8695 EL_EMC_WALL_11, -1, -1
8698 Xdecor_12, TRUE, FALSE,
8699 EL_EMC_WALL_12, -1, -1
8702 Xalpha_0, TRUE, FALSE,
8703 EL_CHAR('0'), -1, -1
8706 Xalpha_1, TRUE, FALSE,
8707 EL_CHAR('1'), -1, -1
8710 Xalpha_2, TRUE, FALSE,
8711 EL_CHAR('2'), -1, -1
8714 Xalpha_3, TRUE, FALSE,
8715 EL_CHAR('3'), -1, -1
8718 Xalpha_4, TRUE, FALSE,
8719 EL_CHAR('4'), -1, -1
8722 Xalpha_5, TRUE, FALSE,
8723 EL_CHAR('5'), -1, -1
8726 Xalpha_6, TRUE, FALSE,
8727 EL_CHAR('6'), -1, -1
8730 Xalpha_7, TRUE, FALSE,
8731 EL_CHAR('7'), -1, -1
8734 Xalpha_8, TRUE, FALSE,
8735 EL_CHAR('8'), -1, -1
8738 Xalpha_9, TRUE, FALSE,
8739 EL_CHAR('9'), -1, -1
8742 Xalpha_excla, TRUE, FALSE,
8743 EL_CHAR('!'), -1, -1
8746 Xalpha_quote, TRUE, FALSE,
8747 EL_CHAR('"'), -1, -1
8750 Xalpha_comma, TRUE, FALSE,
8751 EL_CHAR(','), -1, -1
8754 Xalpha_minus, TRUE, FALSE,
8755 EL_CHAR('-'), -1, -1
8758 Xalpha_perio, TRUE, FALSE,
8759 EL_CHAR('.'), -1, -1
8762 Xalpha_colon, TRUE, FALSE,
8763 EL_CHAR(':'), -1, -1
8766 Xalpha_quest, TRUE, FALSE,
8767 EL_CHAR('?'), -1, -1
8770 Xalpha_a, TRUE, FALSE,
8771 EL_CHAR('A'), -1, -1
8774 Xalpha_b, TRUE, FALSE,
8775 EL_CHAR('B'), -1, -1
8778 Xalpha_c, TRUE, FALSE,
8779 EL_CHAR('C'), -1, -1
8782 Xalpha_d, TRUE, FALSE,
8783 EL_CHAR('D'), -1, -1
8786 Xalpha_e, TRUE, FALSE,
8787 EL_CHAR('E'), -1, -1
8790 Xalpha_f, TRUE, FALSE,
8791 EL_CHAR('F'), -1, -1
8794 Xalpha_g, TRUE, FALSE,
8795 EL_CHAR('G'), -1, -1
8798 Xalpha_h, TRUE, FALSE,
8799 EL_CHAR('H'), -1, -1
8802 Xalpha_i, TRUE, FALSE,
8803 EL_CHAR('I'), -1, -1
8806 Xalpha_j, TRUE, FALSE,
8807 EL_CHAR('J'), -1, -1
8810 Xalpha_k, TRUE, FALSE,
8811 EL_CHAR('K'), -1, -1
8814 Xalpha_l, TRUE, FALSE,
8815 EL_CHAR('L'), -1, -1
8818 Xalpha_m, TRUE, FALSE,
8819 EL_CHAR('M'), -1, -1
8822 Xalpha_n, TRUE, FALSE,
8823 EL_CHAR('N'), -1, -1
8826 Xalpha_o, TRUE, FALSE,
8827 EL_CHAR('O'), -1, -1
8830 Xalpha_p, TRUE, FALSE,
8831 EL_CHAR('P'), -1, -1
8834 Xalpha_q, TRUE, FALSE,
8835 EL_CHAR('Q'), -1, -1
8838 Xalpha_r, TRUE, FALSE,
8839 EL_CHAR('R'), -1, -1
8842 Xalpha_s, TRUE, FALSE,
8843 EL_CHAR('S'), -1, -1
8846 Xalpha_t, TRUE, FALSE,
8847 EL_CHAR('T'), -1, -1
8850 Xalpha_u, TRUE, FALSE,
8851 EL_CHAR('U'), -1, -1
8854 Xalpha_v, TRUE, FALSE,
8855 EL_CHAR('V'), -1, -1
8858 Xalpha_w, TRUE, FALSE,
8859 EL_CHAR('W'), -1, -1
8862 Xalpha_x, TRUE, FALSE,
8863 EL_CHAR('X'), -1, -1
8866 Xalpha_y, TRUE, FALSE,
8867 EL_CHAR('Y'), -1, -1
8870 Xalpha_z, TRUE, FALSE,
8871 EL_CHAR('Z'), -1, -1
8874 Xalpha_arrow_e, TRUE, FALSE,
8875 EL_CHAR('>'), -1, -1
8878 Xalpha_arrow_w, TRUE, FALSE,
8879 EL_CHAR('<'), -1, -1
8882 Xalpha_copyr, TRUE, FALSE,
8883 EL_CHAR('©'), -1, -1
8887 Xboom_bug, FALSE, FALSE,
8888 EL_BUG, ACTION_EXPLODING, -1
8891 Xboom_bomb, FALSE, FALSE,
8892 EL_BOMB, ACTION_EXPLODING, -1
8895 Xboom_android, FALSE, FALSE,
8896 EL_EMC_ANDROID, ACTION_OTHER, -1
8899 Xboom_1, FALSE, FALSE,
8900 EL_DEFAULT, ACTION_EXPLODING, -1
8903 Xboom_2, FALSE, FALSE,
8904 EL_DEFAULT, ACTION_EXPLODING, -1
8907 Znormal, FALSE, FALSE,
8911 Zdynamite, FALSE, FALSE,
8915 Zplayer, FALSE, FALSE,
8919 ZBORDER, FALSE, FALSE,
8929 static struct Mapping_EM_to_RND_player
8938 em_player_mapping_list[] =
8942 EL_PLAYER_1, ACTION_MOVING, MV_BIT_UP,
8946 EL_PLAYER_1, ACTION_MOVING, MV_BIT_RIGHT,
8950 EL_PLAYER_1, ACTION_MOVING, MV_BIT_DOWN,
8954 EL_PLAYER_1, ACTION_MOVING, MV_BIT_LEFT,
8958 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_UP,
8962 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_RIGHT,
8966 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_DOWN,
8970 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_LEFT,
8974 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_UP,
8978 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_RIGHT,
8982 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_DOWN,
8986 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_LEFT,
8990 EL_PLAYER_2, ACTION_MOVING, MV_BIT_UP,
8994 EL_PLAYER_2, ACTION_MOVING, MV_BIT_RIGHT,
8998 EL_PLAYER_2, ACTION_MOVING, MV_BIT_DOWN,
9002 EL_PLAYER_2, ACTION_MOVING, MV_BIT_LEFT,
9006 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_UP,
9010 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_RIGHT,
9014 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_DOWN,
9018 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_LEFT,
9022 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_UP,
9026 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_RIGHT,
9030 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_DOWN,
9034 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_LEFT,
9038 EL_PLAYER_1, ACTION_DEFAULT, -1,
9042 EL_PLAYER_2, ACTION_DEFAULT, -1,
9046 EL_PLAYER_3, ACTION_MOVING, MV_BIT_UP,
9050 EL_PLAYER_3, ACTION_MOVING, MV_BIT_RIGHT,
9054 EL_PLAYER_3, ACTION_MOVING, MV_BIT_DOWN,
9058 EL_PLAYER_3, ACTION_MOVING, MV_BIT_LEFT,
9062 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_UP,
9066 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_RIGHT,
9070 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_DOWN,
9074 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_LEFT,
9078 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_UP,
9082 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_RIGHT,
9086 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_DOWN,
9090 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_LEFT,
9094 EL_PLAYER_4, ACTION_MOVING, MV_BIT_UP,
9098 EL_PLAYER_4, ACTION_MOVING, MV_BIT_RIGHT,
9102 EL_PLAYER_4, ACTION_MOVING, MV_BIT_DOWN,
9106 EL_PLAYER_4, ACTION_MOVING, MV_BIT_LEFT,
9110 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_UP,
9114 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_RIGHT,
9118 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_DOWN,
9122 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_LEFT,
9126 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_UP,
9130 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_RIGHT,
9134 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_DOWN,
9138 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_LEFT,
9142 EL_PLAYER_3, ACTION_DEFAULT, -1,
9146 EL_PLAYER_4, ACTION_DEFAULT, -1,
9155 int map_element_RND_to_EM(int element_rnd)
9157 static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
9158 static boolean mapping_initialized = FALSE;
9160 if (!mapping_initialized)
9164 /* return "Xalpha_quest" for all undefined elements in mapping array */
9165 for (i = 0; i < NUM_FILE_ELEMENTS; i++)
9166 mapping_RND_to_EM[i] = Xalpha_quest;
9168 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
9169 if (em_object_mapping_list[i].is_rnd_to_em_mapping)
9170 mapping_RND_to_EM[em_object_mapping_list[i].element_rnd] =
9171 em_object_mapping_list[i].element_em;
9173 mapping_initialized = TRUE;
9176 if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
9177 return mapping_RND_to_EM[element_rnd];
9179 Error(ERR_WARN, "invalid RND level element %d", element_rnd);
9184 int map_element_EM_to_RND(int element_em)
9186 static unsigned short mapping_EM_to_RND[TILE_MAX];
9187 static boolean mapping_initialized = FALSE;
9189 if (!mapping_initialized)
9193 /* return "EL_UNKNOWN" for all undefined elements in mapping array */
9194 for (i = 0; i < TILE_MAX; i++)
9195 mapping_EM_to_RND[i] = EL_UNKNOWN;
9197 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
9198 mapping_EM_to_RND[em_object_mapping_list[i].element_em] =
9199 em_object_mapping_list[i].element_rnd;
9201 mapping_initialized = TRUE;
9204 if (element_em >= 0 && element_em < TILE_MAX)
9205 return mapping_EM_to_RND[element_em];
9207 Error(ERR_WARN, "invalid EM level element %d", element_em);
9212 void map_android_clone_elements_RND_to_EM(struct LevelInfo *level)
9214 struct LevelInfo_EM *level_em = level->native_em_level;
9215 struct LEVEL *lev = level_em->lev;
9218 for (i = 0; i < TILE_MAX; i++)
9219 lev->android_array[i] = Xblank;
9221 for (i = 0; i < level->num_android_clone_elements; i++)
9223 int element_rnd = level->android_clone_element[i];
9224 int element_em = map_element_RND_to_EM(element_rnd);
9226 for (j = 0; em_object_mapping_list[j].element_em != -1; j++)
9227 if (em_object_mapping_list[j].element_rnd == element_rnd)
9228 lev->android_array[em_object_mapping_list[j].element_em] = element_em;
9232 void map_android_clone_elements_EM_to_RND(struct LevelInfo *level)
9234 struct LevelInfo_EM *level_em = level->native_em_level;
9235 struct LEVEL *lev = level_em->lev;
9238 level->num_android_clone_elements = 0;
9240 for (i = 0; i < TILE_MAX; i++)
9242 int element_em = lev->android_array[i];
9244 boolean element_found = FALSE;
9246 if (element_em == Xblank)
9249 element_rnd = map_element_EM_to_RND(element_em);
9251 for (j = 0; j < level->num_android_clone_elements; j++)
9252 if (level->android_clone_element[j] == element_rnd)
9253 element_found = TRUE;
9257 level->android_clone_element[level->num_android_clone_elements++] =
9260 if (level->num_android_clone_elements == MAX_ANDROID_ELEMENTS)
9265 if (level->num_android_clone_elements == 0)
9267 level->num_android_clone_elements = 1;
9268 level->android_clone_element[0] = EL_EMPTY;
9272 int map_direction_RND_to_EM(int direction)
9274 return (direction == MV_UP ? 0 :
9275 direction == MV_RIGHT ? 1 :
9276 direction == MV_DOWN ? 2 :
9277 direction == MV_LEFT ? 3 :
9281 int map_direction_EM_to_RND(int direction)
9283 return (direction == 0 ? MV_UP :
9284 direction == 1 ? MV_RIGHT :
9285 direction == 2 ? MV_DOWN :
9286 direction == 3 ? MV_LEFT :
9290 int map_element_RND_to_SP(int element_rnd)
9292 int element_sp = 0x20; /* map unknown elements to yellow "hardware" */
9294 if (element_rnd >= EL_SP_START &&
9295 element_rnd <= EL_SP_END)
9296 element_sp = element_rnd - EL_SP_START;
9297 else if (element_rnd == EL_EMPTY_SPACE)
9299 else if (element_rnd == EL_INVISIBLE_WALL)
9305 int map_element_SP_to_RND(int element_sp)
9307 int element_rnd = EL_UNKNOWN;
9309 if (element_sp >= 0x00 &&
9311 element_rnd = EL_SP_START + element_sp;
9312 else if (element_sp == 0x28)
9313 element_rnd = EL_INVISIBLE_WALL;
9318 int map_action_SP_to_RND(int action_sp)
9322 case actActive: return ACTION_ACTIVE;
9323 case actImpact: return ACTION_IMPACT;
9324 case actExploding: return ACTION_EXPLODING;
9325 case actDigging: return ACTION_DIGGING;
9326 case actSnapping: return ACTION_SNAPPING;
9327 case actCollecting: return ACTION_COLLECTING;
9328 case actPassing: return ACTION_PASSING;
9329 case actPushing: return ACTION_PUSHING;
9330 case actDropping: return ACTION_DROPPING;
9332 default: return ACTION_DEFAULT;
9336 int get_next_element(int element)
9340 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
9341 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
9342 case EL_QUICKSAND_FAST_FILLING: return EL_QUICKSAND_FAST_FULL;
9343 case EL_QUICKSAND_FAST_EMPTYING: return EL_QUICKSAND_FAST_EMPTY;
9344 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
9345 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
9346 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
9347 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
9348 case EL_DC_MAGIC_WALL_FILLING: return EL_DC_MAGIC_WALL_FULL;
9349 case EL_DC_MAGIC_WALL_EMPTYING: return EL_DC_MAGIC_WALL_ACTIVE;
9350 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
9352 default: return element;
9357 int el_act_dir2img(int element, int action, int direction)
9359 element = GFX_ELEMENT(element);
9361 if (direction == MV_NONE)
9362 return element_info[element].graphic[action];
9364 direction = MV_DIR_TO_BIT(direction);
9366 return element_info[element].direction_graphic[action][direction];
9369 int el_act_dir2img(int element, int action, int direction)
9371 element = GFX_ELEMENT(element);
9372 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
9374 /* direction_graphic[][] == graphic[] for undefined direction graphics */
9375 return element_info[element].direction_graphic[action][direction];
9380 static int el_act_dir2crm(int element, int action, int direction)
9382 element = GFX_ELEMENT(element);
9384 if (direction == MV_NONE)
9385 return element_info[element].crumbled[action];
9387 direction = MV_DIR_TO_BIT(direction);
9389 return element_info[element].direction_crumbled[action][direction];
9392 static int el_act_dir2crm(int element, int action, int direction)
9394 element = GFX_ELEMENT(element);
9395 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
9397 /* direction_graphic[][] == graphic[] for undefined direction graphics */
9398 return element_info[element].direction_crumbled[action][direction];
9402 int el_act2img(int element, int action)
9404 element = GFX_ELEMENT(element);
9406 return element_info[element].graphic[action];
9409 int el_act2crm(int element, int action)
9411 element = GFX_ELEMENT(element);
9413 return element_info[element].crumbled[action];
9416 int el_dir2img(int element, int direction)
9418 element = GFX_ELEMENT(element);
9420 return el_act_dir2img(element, ACTION_DEFAULT, direction);
9423 int el2baseimg(int element)
9425 return element_info[element].graphic[ACTION_DEFAULT];
9428 int el2img(int element)
9430 element = GFX_ELEMENT(element);
9432 return element_info[element].graphic[ACTION_DEFAULT];
9435 int el2edimg(int element)
9437 element = GFX_ELEMENT(element);
9439 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
9442 int el2preimg(int element)
9444 element = GFX_ELEMENT(element);
9446 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
9449 int el2panelimg(int element)
9451 element = GFX_ELEMENT(element);
9453 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PANEL];
9456 int font2baseimg(int font_nr)
9458 return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
9461 int getBeltNrFromBeltElement(int element)
9463 return (element < EL_CONVEYOR_BELT_2_LEFT ? 0 :
9464 element < EL_CONVEYOR_BELT_3_LEFT ? 1 :
9465 element < EL_CONVEYOR_BELT_4_LEFT ? 2 : 3);
9468 int getBeltNrFromBeltActiveElement(int element)
9470 return (element < EL_CONVEYOR_BELT_2_LEFT_ACTIVE ? 0 :
9471 element < EL_CONVEYOR_BELT_3_LEFT_ACTIVE ? 1 :
9472 element < EL_CONVEYOR_BELT_4_LEFT_ACTIVE ? 2 : 3);
9475 int getBeltNrFromBeltSwitchElement(int element)
9477 return (element < EL_CONVEYOR_BELT_2_SWITCH_LEFT ? 0 :
9478 element < EL_CONVEYOR_BELT_3_SWITCH_LEFT ? 1 :
9479 element < EL_CONVEYOR_BELT_4_SWITCH_LEFT ? 2 : 3);
9482 int getBeltDirNrFromBeltElement(int element)
9484 static int belt_base_element[4] =
9486 EL_CONVEYOR_BELT_1_LEFT,
9487 EL_CONVEYOR_BELT_2_LEFT,
9488 EL_CONVEYOR_BELT_3_LEFT,
9489 EL_CONVEYOR_BELT_4_LEFT
9492 int belt_nr = getBeltNrFromBeltElement(element);
9493 int belt_dir_nr = element - belt_base_element[belt_nr];
9495 return (belt_dir_nr % 3);
9498 int getBeltDirNrFromBeltSwitchElement(int element)
9500 static int belt_base_element[4] =
9502 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
9503 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
9504 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
9505 EL_CONVEYOR_BELT_4_SWITCH_LEFT
9508 int belt_nr = getBeltNrFromBeltSwitchElement(element);
9509 int belt_dir_nr = element - belt_base_element[belt_nr];
9511 return (belt_dir_nr % 3);
9514 int getBeltDirFromBeltElement(int element)
9516 static int belt_move_dir[3] =
9523 int belt_dir_nr = getBeltDirNrFromBeltElement(element);
9525 return belt_move_dir[belt_dir_nr];
9528 int getBeltDirFromBeltSwitchElement(int element)
9530 static int belt_move_dir[3] =
9537 int belt_dir_nr = getBeltDirNrFromBeltSwitchElement(element);
9539 return belt_move_dir[belt_dir_nr];
9542 int getBeltElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
9544 static int belt_base_element[4] =
9546 EL_CONVEYOR_BELT_1_LEFT,
9547 EL_CONVEYOR_BELT_2_LEFT,
9548 EL_CONVEYOR_BELT_3_LEFT,
9549 EL_CONVEYOR_BELT_4_LEFT
9552 return belt_base_element[belt_nr] + belt_dir_nr;
9555 int getBeltElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
9557 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
9559 return getBeltElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
9562 int getBeltSwitchElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
9564 static int belt_base_element[4] =
9566 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
9567 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
9568 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
9569 EL_CONVEYOR_BELT_4_SWITCH_LEFT
9572 return belt_base_element[belt_nr] + belt_dir_nr;
9575 int getBeltSwitchElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
9577 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
9579 return getBeltSwitchElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
9583 boolean getTeamMode_EM()
9585 return game.team_mode;
9588 int getNumActivePlayers_EM()
9591 int num_players = 0;
9595 return (setup.team_mode ? MAX_PLAYERS : 1);
9597 for (i = 0; i < MAX_PLAYERS; i++)
9598 if (tape.player_participates[i])
9601 return (num_players > 1 ? MAX_PLAYERS : 1);
9605 int num_players = 0;
9608 /* when recording game, activate all connected players */
9612 for (i = 0; i < MAX_PLAYERS; i++)
9613 if (tape.player_participates[i])
9621 int getGameFrameDelay_EM(int native_em_game_frame_delay)
9623 int game_frame_delay_value;
9625 game_frame_delay_value =
9626 (tape.playing && tape.fast_forward ? FfwdFrameDelay :
9627 GameFrameDelay == GAME_FRAME_DELAY ? native_em_game_frame_delay :
9630 if (tape.playing && tape.warp_forward && !tape.pausing)
9631 game_frame_delay_value = 0;
9633 return game_frame_delay_value;
9636 unsigned int InitRND(int seed)
9638 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
9639 return InitEngineRandom_EM(seed);
9640 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
9641 return InitEngineRandom_SP(seed);
9643 return InitEngineRandom_RND(seed);
9647 static struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
9648 static struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
9651 inline static int get_effective_element_EM(int tile, int frame_em)
9653 int element = object_mapping[tile].element_rnd;
9654 int action = object_mapping[tile].action;
9655 boolean is_backside = object_mapping[tile].is_backside;
9656 boolean action_removing = (action == ACTION_DIGGING ||
9657 action == ACTION_SNAPPING ||
9658 action == ACTION_COLLECTING);
9664 case Yacid_splash_eB:
9665 case Yacid_splash_wB:
9666 return (frame_em > 5 ? EL_EMPTY : element);
9670 case Ydiamond_stone:
9671 // if (!game.use_native_emc_graphics_engine)
9679 else /* frame_em == 7 */
9683 case Yacid_splash_eB:
9684 case Yacid_splash_wB:
9687 case Yemerald_stone:
9690 case Ydiamond_stone:
9694 case Xdrip_stretchB:
9713 case Xsand_stonein_1:
9714 case Xsand_stonein_2:
9715 case Xsand_stonein_3:
9716 case Xsand_stonein_4:
9720 return (is_backside || action_removing ? EL_EMPTY : element);
9725 inline static boolean check_linear_animation_EM(int tile)
9729 case Xsand_stonesand_1:
9730 case Xsand_stonesand_quickout_1:
9731 case Xsand_sandstone_1:
9732 case Xsand_stonein_1:
9733 case Xsand_stoneout_1:
9753 case Yacid_splash_eB:
9754 case Yacid_splash_wB:
9755 case Yemerald_stone:
9763 inline static void set_crumbled_graphics_EM(struct GraphicInfo_EM *g_em,
9764 boolean has_crumbled_graphics,
9765 int crumbled, int sync_frame)
9767 /* if element can be crumbled, but certain action graphics are just empty
9768 space (like instantly snapping sand to empty space in 1 frame), do not
9769 treat these empty space graphics as crumbled graphics in EMC engine */
9770 if (crumbled == IMG_EMPTY_SPACE)
9771 has_crumbled_graphics = FALSE;
9773 if (has_crumbled_graphics)
9775 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
9776 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
9777 g_crumbled->anim_delay,
9778 g_crumbled->anim_mode,
9779 g_crumbled->anim_start_frame,
9782 getGraphicSource(crumbled, frame_crumbled, &g_em->crumbled_bitmap,
9783 &g_em->crumbled_src_x, &g_em->crumbled_src_y);
9785 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
9787 g_em->has_crumbled_graphics = TRUE;
9791 g_em->crumbled_bitmap = NULL;
9792 g_em->crumbled_src_x = 0;
9793 g_em->crumbled_src_y = 0;
9794 g_em->crumbled_border_size = 0;
9796 g_em->has_crumbled_graphics = FALSE;
9800 void ResetGfxAnimation_EM(int x, int y, int tile)
9805 void SetGfxAnimation_EM(struct GraphicInfo_EM *g_em,
9806 int tile, int frame_em, int x, int y)
9808 int action = object_mapping[tile].action;
9810 int direction = object_mapping[tile].direction;
9811 int effective_element = get_effective_element_EM(tile, frame_em);
9812 int graphic = (direction == MV_NONE ?
9813 el_act2img(effective_element, action) :
9814 el_act_dir2img(effective_element, action, direction));
9815 struct GraphicInfo *g = &graphic_info[graphic];
9818 boolean action_removing = (action == ACTION_DIGGING ||
9819 action == ACTION_SNAPPING ||
9820 action == ACTION_COLLECTING);
9821 boolean action_moving = (action == ACTION_FALLING ||
9822 action == ACTION_MOVING ||
9823 action == ACTION_PUSHING ||
9824 action == ACTION_EATING ||
9825 action == ACTION_FILLING ||
9826 action == ACTION_EMPTYING);
9827 boolean action_falling = (action == ACTION_FALLING ||
9828 action == ACTION_FILLING ||
9829 action == ACTION_EMPTYING);
9831 /* special case: graphic uses "2nd movement tile" and has defined
9832 7 frames for movement animation (or less) => use default graphic
9833 for last (8th) frame which ends the movement animation */
9834 if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
9836 action = ACTION_DEFAULT; /* (keep action_* unchanged for now) */
9837 graphic = (direction == MV_NONE ?
9838 el_act2img(effective_element, action) :
9839 el_act_dir2img(effective_element, action, direction));
9841 g = &graphic_info[graphic];
9845 if (tile == Xsand_stonesand_1 ||
9846 tile == Xsand_stonesand_2 ||
9847 tile == Xsand_stonesand_3 ||
9848 tile == Xsand_stonesand_4)
9849 printf("::: 1: quicksand frame %d [%d]\n", GfxFrame[x][y], tile);
9853 if ((action_removing || check_linear_animation_EM(tile)) && frame_em == 0)
9857 // printf("::: resetting... [%d]\n", tile);
9860 if (action_removing || check_linear_animation_EM(tile))
9862 GfxFrame[x][y] = frame_em;
9864 // printf("::: resetting... [%d]\n", tile);
9867 else if (action_moving)
9869 boolean is_backside = object_mapping[tile].is_backside;
9873 int direction = object_mapping[tile].direction;
9874 int move_dir = (action_falling ? MV_DOWN : direction);
9879 /* !!! TEST !!! NEW !!! DOES NOT WORK RIGHT YET !!! */
9880 if (g->double_movement && frame_em == 0)
9884 // printf("::: resetting... [%d]\n", tile);
9888 if (move_dir == MV_LEFT)
9889 GfxFrame[x - 1][y] = GfxFrame[x][y];
9890 else if (move_dir == MV_RIGHT)
9891 GfxFrame[x + 1][y] = GfxFrame[x][y];
9892 else if (move_dir == MV_UP)
9893 GfxFrame[x][y - 1] = GfxFrame[x][y];
9894 else if (move_dir == MV_DOWN)
9895 GfxFrame[x][y + 1] = GfxFrame[x][y];
9902 /* special case: animation for Xsand_stonesand_quickout_1/2 twice as fast */
9903 if (tile == Xsand_stonesand_quickout_1 ||
9904 tile == Xsand_stonesand_quickout_2)
9909 if (tile == Xsand_stonesand_1 ||
9910 tile == Xsand_stonesand_2 ||
9911 tile == Xsand_stonesand_3 ||
9912 tile == Xsand_stonesand_4)
9913 printf("::: 2: quicksand frame %d [%d]\n", GfxFrame[x][y], tile);
9917 if (graphic_info[graphic].anim_global_sync)
9918 sync_frame = FrameCounter;
9919 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
9920 sync_frame = GfxFrame[x][y];
9922 sync_frame = 0; /* playfield border (pseudo steel) */
9924 SetRandomAnimationValue(x, y);
9926 int frame = getAnimationFrame(g->anim_frames,
9929 g->anim_start_frame,
9932 g_em->unique_identifier =
9933 (graphic << 16) | ((frame % 8) << 12) | (g_em->width << 6) | g_em->height;
9937 void getGraphicSourceObjectExt_EM(struct GraphicInfo_EM *g_em,
9938 int tile, int frame_em, int x, int y)
9940 int action = object_mapping[tile].action;
9941 int direction = object_mapping[tile].direction;
9942 boolean is_backside = object_mapping[tile].is_backside;
9943 int effective_element = get_effective_element_EM(tile, frame_em);
9945 int effective_action = action;
9947 int effective_action = (frame_em < 7 ? action : ACTION_DEFAULT);
9949 int graphic = (direction == MV_NONE ?
9950 el_act2img(effective_element, effective_action) :
9951 el_act_dir2img(effective_element, effective_action,
9953 int crumbled = (direction == MV_NONE ?
9954 el_act2crm(effective_element, effective_action) :
9955 el_act_dir2crm(effective_element, effective_action,
9957 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
9958 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
9959 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
9960 struct GraphicInfo *g = &graphic_info[graphic];
9962 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
9966 /* special case: graphic uses "2nd movement tile" and has defined
9967 7 frames for movement animation (or less) => use default graphic
9968 for last (8th) frame which ends the movement animation */
9969 if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
9971 effective_action = ACTION_DEFAULT;
9972 graphic = (direction == MV_NONE ?
9973 el_act2img(effective_element, effective_action) :
9974 el_act_dir2img(effective_element, effective_action,
9976 crumbled = (direction == MV_NONE ?
9977 el_act2crm(effective_element, effective_action) :
9978 el_act_dir2crm(effective_element, effective_action,
9981 g = &graphic_info[graphic];
9991 if (frame_em == 0) /* reset animation frame for certain elements */
9993 if (check_linear_animation_EM(tile))
9998 if (graphic_info[graphic].anim_global_sync)
9999 sync_frame = FrameCounter;
10000 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
10001 sync_frame = GfxFrame[x][y];
10003 sync_frame = 0; /* playfield border (pseudo steel) */
10005 SetRandomAnimationValue(x, y);
10010 int xxx_sync_frame = (i == Xdrip_stretch ? 7 :
10011 i == Xdrip_stretchB ? 7 :
10012 i == Ydrip_s2 ? j + 8 :
10013 i == Ydrip_s2B ? j + 8 :
10015 i == Xacid_2 ? 10 :
10016 i == Xacid_3 ? 20 :
10017 i == Xacid_4 ? 30 :
10018 i == Xacid_5 ? 40 :
10019 i == Xacid_6 ? 50 :
10020 i == Xacid_7 ? 60 :
10021 i == Xacid_8 ? 70 :
10022 i == Xfake_acid_1 ? 0 :
10023 i == Xfake_acid_2 ? 10 :
10024 i == Xfake_acid_3 ? 20 :
10025 i == Xfake_acid_4 ? 30 :
10026 i == Xfake_acid_5 ? 40 :
10027 i == Xfake_acid_6 ? 50 :
10028 i == Xfake_acid_7 ? 60 :
10029 i == Xfake_acid_8 ? 70 :
10031 i == Xball_2B ? j + 8 :
10032 i == Yball_eat ? j + 1 :
10033 i == Ykey_1_eat ? j + 1 :
10034 i == Ykey_2_eat ? j + 1 :
10035 i == Ykey_3_eat ? j + 1 :
10036 i == Ykey_4_eat ? j + 1 :
10037 i == Ykey_5_eat ? j + 1 :
10038 i == Ykey_6_eat ? j + 1 :
10039 i == Ykey_7_eat ? j + 1 :
10040 i == Ykey_8_eat ? j + 1 :
10041 i == Ylenses_eat ? j + 1 :
10042 i == Ymagnify_eat ? j + 1 :
10043 i == Ygrass_eat ? j + 1 :
10044 i == Ydirt_eat ? j + 1 :
10045 i == Xamoeba_1 ? 0 :
10046 i == Xamoeba_2 ? 1 :
10047 i == Xamoeba_3 ? 2 :
10048 i == Xamoeba_4 ? 3 :
10049 i == Xamoeba_5 ? 0 :
10050 i == Xamoeba_6 ? 1 :
10051 i == Xamoeba_7 ? 2 :
10052 i == Xamoeba_8 ? 3 :
10053 i == Xexit_2 ? j + 8 :
10054 i == Xexit_3 ? j + 16 :
10055 i == Xdynamite_1 ? 0 :
10056 i == Xdynamite_2 ? 8 :
10057 i == Xdynamite_3 ? 16 :
10058 i == Xdynamite_4 ? 24 :
10059 i == Xsand_stonein_1 ? j + 1 :
10060 i == Xsand_stonein_2 ? j + 9 :
10061 i == Xsand_stonein_3 ? j + 17 :
10062 i == Xsand_stonein_4 ? j + 25 :
10063 i == Xsand_stoneout_1 && j == 0 ? 0 :
10064 i == Xsand_stoneout_1 && j == 1 ? 0 :
10065 i == Xsand_stoneout_1 && j == 2 ? 1 :
10066 i == Xsand_stoneout_1 && j == 3 ? 2 :
10067 i == Xsand_stoneout_1 && j == 4 ? 2 :
10068 i == Xsand_stoneout_1 && j == 5 ? 3 :
10069 i == Xsand_stoneout_1 && j == 6 ? 4 :
10070 i == Xsand_stoneout_1 && j == 7 ? 4 :
10071 i == Xsand_stoneout_2 && j == 0 ? 5 :
10072 i == Xsand_stoneout_2 && j == 1 ? 6 :
10073 i == Xsand_stoneout_2 && j == 2 ? 7 :
10074 i == Xsand_stoneout_2 && j == 3 ? 8 :
10075 i == Xsand_stoneout_2 && j == 4 ? 9 :
10076 i == Xsand_stoneout_2 && j == 5 ? 11 :
10077 i == Xsand_stoneout_2 && j == 6 ? 13 :
10078 i == Xsand_stoneout_2 && j == 7 ? 15 :
10079 i == Xboom_bug && j == 1 ? 2 :
10080 i == Xboom_bug && j == 2 ? 2 :
10081 i == Xboom_bug && j == 3 ? 4 :
10082 i == Xboom_bug && j == 4 ? 4 :
10083 i == Xboom_bug && j == 5 ? 2 :
10084 i == Xboom_bug && j == 6 ? 2 :
10085 i == Xboom_bug && j == 7 ? 0 :
10086 i == Xboom_bomb && j == 1 ? 2 :
10087 i == Xboom_bomb && j == 2 ? 2 :
10088 i == Xboom_bomb && j == 3 ? 4 :
10089 i == Xboom_bomb && j == 4 ? 4 :
10090 i == Xboom_bomb && j == 5 ? 2 :
10091 i == Xboom_bomb && j == 6 ? 2 :
10092 i == Xboom_bomb && j == 7 ? 0 :
10093 i == Xboom_android && j == 7 ? 6 :
10094 i == Xboom_1 && j == 1 ? 2 :
10095 i == Xboom_1 && j == 2 ? 2 :
10096 i == Xboom_1 && j == 3 ? 4 :
10097 i == Xboom_1 && j == 4 ? 4 :
10098 i == Xboom_1 && j == 5 ? 6 :
10099 i == Xboom_1 && j == 6 ? 6 :
10100 i == Xboom_1 && j == 7 ? 8 :
10101 i == Xboom_2 && j == 0 ? 8 :
10102 i == Xboom_2 && j == 1 ? 8 :
10103 i == Xboom_2 && j == 2 ? 10 :
10104 i == Xboom_2 && j == 3 ? 10 :
10105 i == Xboom_2 && j == 4 ? 10 :
10106 i == Xboom_2 && j == 5 ? 12 :
10107 i == Xboom_2 && j == 6 ? 12 :
10108 i == Xboom_2 && j == 7 ? 12 :
10110 special_animation && j == 4 ? 3 :
10111 effective_action != action ? 0 :
10117 int xxx_effective_action;
10118 int xxx_has_action_graphics;
10121 int element = object_mapping[i].element_rnd;
10122 int action = object_mapping[i].action;
10123 int direction = object_mapping[i].direction;
10124 boolean is_backside = object_mapping[i].is_backside;
10126 boolean action_removing = (action == ACTION_DIGGING ||
10127 action == ACTION_SNAPPING ||
10128 action == ACTION_COLLECTING);
10130 boolean action_exploding = ((action == ACTION_EXPLODING ||
10131 action == ACTION_SMASHED_BY_ROCK ||
10132 action == ACTION_SMASHED_BY_SPRING) &&
10133 element != EL_DIAMOND);
10134 boolean action_active = (action == ACTION_ACTIVE);
10135 boolean action_other = (action == ACTION_OTHER);
10139 int effective_element = get_effective_element_EM(i, j);
10141 int effective_element = (j > 5 && i == Yacid_splash_eB ? EL_EMPTY :
10142 j > 5 && i == Yacid_splash_wB ? EL_EMPTY :
10144 i == Xdrip_stretch ? element :
10145 i == Xdrip_stretchB ? element :
10146 i == Ydrip_s1 ? element :
10147 i == Ydrip_s1B ? element :
10148 i == Xball_1B ? element :
10149 i == Xball_2 ? element :
10150 i == Xball_2B ? element :
10151 i == Yball_eat ? element :
10152 i == Ykey_1_eat ? element :
10153 i == Ykey_2_eat ? element :
10154 i == Ykey_3_eat ? element :
10155 i == Ykey_4_eat ? element :
10156 i == Ykey_5_eat ? element :
10157 i == Ykey_6_eat ? element :
10158 i == Ykey_7_eat ? element :
10159 i == Ykey_8_eat ? element :
10160 i == Ylenses_eat ? element :
10161 i == Ymagnify_eat ? element :
10162 i == Ygrass_eat ? element :
10163 i == Ydirt_eat ? element :
10164 i == Yemerald_stone ? EL_EMERALD :
10165 i == Ydiamond_stone ? EL_ROCK :
10166 i == Xsand_stonein_1 ? element :
10167 i == Xsand_stonein_2 ? element :
10168 i == Xsand_stonein_3 ? element :
10169 i == Xsand_stonein_4 ? element :
10170 is_backside ? EL_EMPTY :
10171 action_removing ? EL_EMPTY :
10174 int effective_action = (j < 7 ? action :
10175 i == Xdrip_stretch ? action :
10176 i == Xdrip_stretchB ? action :
10177 i == Ydrip_s1 ? action :
10178 i == Ydrip_s1B ? action :
10179 i == Xball_1B ? action :
10180 i == Xball_2 ? action :
10181 i == Xball_2B ? action :
10182 i == Yball_eat ? action :
10183 i == Ykey_1_eat ? action :
10184 i == Ykey_2_eat ? action :
10185 i == Ykey_3_eat ? action :
10186 i == Ykey_4_eat ? action :
10187 i == Ykey_5_eat ? action :
10188 i == Ykey_6_eat ? action :
10189 i == Ykey_7_eat ? action :
10190 i == Ykey_8_eat ? action :
10191 i == Ylenses_eat ? action :
10192 i == Ymagnify_eat ? action :
10193 i == Ygrass_eat ? action :
10194 i == Ydirt_eat ? action :
10195 i == Xsand_stonein_1 ? action :
10196 i == Xsand_stonein_2 ? action :
10197 i == Xsand_stonein_3 ? action :
10198 i == Xsand_stonein_4 ? action :
10199 i == Xsand_stoneout_1 ? action :
10200 i == Xsand_stoneout_2 ? action :
10201 i == Xboom_android ? ACTION_EXPLODING :
10202 action_exploding ? ACTION_EXPLODING :
10203 action_active ? action :
10204 action_other ? action :
10206 int graphic = (el_act_dir2img(effective_element, effective_action,
10208 int crumbled = (el_act_dir2crm(effective_element, effective_action,
10210 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
10211 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
10212 boolean has_action_graphics = (graphic != base_graphic);
10213 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
10214 struct GraphicInfo *g = &graphic_info[graphic];
10216 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
10218 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
10219 Bitmap *src_bitmap;
10221 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
10222 boolean special_animation = (action != ACTION_DEFAULT &&
10223 g->anim_frames == 3 &&
10224 g->anim_delay == 2 &&
10225 g->anim_mode & ANIM_LINEAR);
10226 xxx_sync_frame = (i == Xdrip_stretch ? 7 :
10227 i == Xdrip_stretchB ? 7 :
10228 i == Ydrip_s2 ? j + 8 :
10229 i == Ydrip_s2B ? j + 8 :
10231 i == Xacid_2 ? 10 :
10232 i == Xacid_3 ? 20 :
10233 i == Xacid_4 ? 30 :
10234 i == Xacid_5 ? 40 :
10235 i == Xacid_6 ? 50 :
10236 i == Xacid_7 ? 60 :
10237 i == Xacid_8 ? 70 :
10238 i == Xfake_acid_1 ? 0 :
10239 i == Xfake_acid_2 ? 10 :
10240 i == Xfake_acid_3 ? 20 :
10241 i == Xfake_acid_4 ? 30 :
10242 i == Xfake_acid_5 ? 40 :
10243 i == Xfake_acid_6 ? 50 :
10244 i == Xfake_acid_7 ? 60 :
10245 i == Xfake_acid_8 ? 70 :
10247 i == Xball_2B ? j + 8 :
10248 i == Yball_eat ? j + 1 :
10249 i == Ykey_1_eat ? j + 1 :
10250 i == Ykey_2_eat ? j + 1 :
10251 i == Ykey_3_eat ? j + 1 :
10252 i == Ykey_4_eat ? j + 1 :
10253 i == Ykey_5_eat ? j + 1 :
10254 i == Ykey_6_eat ? j + 1 :
10255 i == Ykey_7_eat ? j + 1 :
10256 i == Ykey_8_eat ? j + 1 :
10257 i == Ylenses_eat ? j + 1 :
10258 i == Ymagnify_eat ? j + 1 :
10259 i == Ygrass_eat ? j + 1 :
10260 i == Ydirt_eat ? j + 1 :
10261 i == Xamoeba_1 ? 0 :
10262 i == Xamoeba_2 ? 1 :
10263 i == Xamoeba_3 ? 2 :
10264 i == Xamoeba_4 ? 3 :
10265 i == Xamoeba_5 ? 0 :
10266 i == Xamoeba_6 ? 1 :
10267 i == Xamoeba_7 ? 2 :
10268 i == Xamoeba_8 ? 3 :
10269 i == Xexit_2 ? j + 8 :
10270 i == Xexit_3 ? j + 16 :
10271 i == Xdynamite_1 ? 0 :
10272 i == Xdynamite_2 ? 8 :
10273 i == Xdynamite_3 ? 16 :
10274 i == Xdynamite_4 ? 24 :
10275 i == Xsand_stonein_1 ? j + 1 :
10276 i == Xsand_stonein_2 ? j + 9 :
10277 i == Xsand_stonein_3 ? j + 17 :
10278 i == Xsand_stonein_4 ? j + 25 :
10279 i == Xsand_stoneout_1 && j == 0 ? 0 :
10280 i == Xsand_stoneout_1 && j == 1 ? 0 :
10281 i == Xsand_stoneout_1 && j == 2 ? 1 :
10282 i == Xsand_stoneout_1 && j == 3 ? 2 :
10283 i == Xsand_stoneout_1 && j == 4 ? 2 :
10284 i == Xsand_stoneout_1 && j == 5 ? 3 :
10285 i == Xsand_stoneout_1 && j == 6 ? 4 :
10286 i == Xsand_stoneout_1 && j == 7 ? 4 :
10287 i == Xsand_stoneout_2 && j == 0 ? 5 :
10288 i == Xsand_stoneout_2 && j == 1 ? 6 :
10289 i == Xsand_stoneout_2 && j == 2 ? 7 :
10290 i == Xsand_stoneout_2 && j == 3 ? 8 :
10291 i == Xsand_stoneout_2 && j == 4 ? 9 :
10292 i == Xsand_stoneout_2 && j == 5 ? 11 :
10293 i == Xsand_stoneout_2 && j == 6 ? 13 :
10294 i == Xsand_stoneout_2 && j == 7 ? 15 :
10295 i == Xboom_bug && j == 1 ? 2 :
10296 i == Xboom_bug && j == 2 ? 2 :
10297 i == Xboom_bug && j == 3 ? 4 :
10298 i == Xboom_bug && j == 4 ? 4 :
10299 i == Xboom_bug && j == 5 ? 2 :
10300 i == Xboom_bug && j == 6 ? 2 :
10301 i == Xboom_bug && j == 7 ? 0 :
10302 i == Xboom_bomb && j == 1 ? 2 :
10303 i == Xboom_bomb && j == 2 ? 2 :
10304 i == Xboom_bomb && j == 3 ? 4 :
10305 i == Xboom_bomb && j == 4 ? 4 :
10306 i == Xboom_bomb && j == 5 ? 2 :
10307 i == Xboom_bomb && j == 6 ? 2 :
10308 i == Xboom_bomb && j == 7 ? 0 :
10309 i == Xboom_android && j == 7 ? 6 :
10310 i == Xboom_1 && j == 1 ? 2 :
10311 i == Xboom_1 && j == 2 ? 2 :
10312 i == Xboom_1 && j == 3 ? 4 :
10313 i == Xboom_1 && j == 4 ? 4 :
10314 i == Xboom_1 && j == 5 ? 6 :
10315 i == Xboom_1 && j == 6 ? 6 :
10316 i == Xboom_1 && j == 7 ? 8 :
10317 i == Xboom_2 && j == 0 ? 8 :
10318 i == Xboom_2 && j == 1 ? 8 :
10319 i == Xboom_2 && j == 2 ? 10 :
10320 i == Xboom_2 && j == 3 ? 10 :
10321 i == Xboom_2 && j == 4 ? 10 :
10322 i == Xboom_2 && j == 5 ? 12 :
10323 i == Xboom_2 && j == 6 ? 12 :
10324 i == Xboom_2 && j == 7 ? 12 :
10325 special_animation && j == 4 ? 3 :
10326 effective_action != action ? 0 :
10329 xxx_effective_action = effective_action;
10330 xxx_has_action_graphics = has_action_graphics;
10335 int frame = getAnimationFrame(g->anim_frames,
10338 g->anim_start_frame,
10352 int old_src_x = g_em->src_x;
10353 int old_src_y = g_em->src_y;
10357 getGraphicSourceExt(graphic, frame, &g_em->bitmap, &g_em->src_x, &g_em->src_y,
10358 g->double_movement && is_backside);
10360 getGraphicSourceExt(graphic, frame, &g_em->bitmap,
10361 &g_em->src_x, &g_em->src_y, FALSE);
10366 if (tile == Ydiamond_stone)
10367 printf("::: stone smashing diamond... %d: %d, %d, %d, %d, %d -> %d [%d, %d, %d, %d, %d, %d] [%d]\n",
10372 g->anim_start_frame,
10375 g_em->src_x, g_em->src_y,
10376 g_em->src_offset_x, g_em->src_offset_y,
10377 g_em->dst_offset_x, g_em->dst_offset_y,
10389 if (graphic == IMG_BUG_MOVING_RIGHT)
10390 printf("::: %d, %d, %d: %d, %d [%d, %d -> %d, %d]\n", graphic, x, y,
10391 g->double_movement, is_backside,
10392 old_src_x, old_src_y, g_em->src_x, g_em->src_y);
10400 g_em->src_offset_x = 0;
10401 g_em->src_offset_y = 0;
10402 g_em->dst_offset_x = 0;
10403 g_em->dst_offset_y = 0;
10404 g_em->width = TILEX;
10405 g_em->height = TILEY;
10407 g_em->preserve_background = FALSE;
10410 /* (updating the "crumbled" graphic definitions is probably not really needed,
10411 as animations for crumbled graphics can't be longer than one EMC cycle) */
10413 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
10418 g_em->crumbled_bitmap = NULL;
10419 g_em->crumbled_src_x = 0;
10420 g_em->crumbled_src_y = 0;
10422 g_em->has_crumbled_graphics = FALSE;
10424 if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
10426 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
10427 g_crumbled->anim_delay,
10428 g_crumbled->anim_mode,
10429 g_crumbled->anim_start_frame,
10432 getGraphicSource(crumbled, frame_crumbled, &g_em->crumbled_bitmap,
10433 &g_em->crumbled_src_x, &g_em->crumbled_src_y);
10435 g_em->has_crumbled_graphics = TRUE;
10441 int effective_action = xxx_effective_action;
10442 int has_action_graphics = xxx_has_action_graphics;
10444 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
10445 effective_action == ACTION_MOVING ||
10446 effective_action == ACTION_PUSHING ||
10447 effective_action == ACTION_EATING)) ||
10448 (!has_action_graphics && (effective_action == ACTION_FILLING ||
10449 effective_action == ACTION_EMPTYING)))
10452 (effective_action == ACTION_FALLING ||
10453 effective_action == ACTION_FILLING ||
10454 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
10455 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
10456 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
10457 int num_steps = (i == Ydrip_s1 ? 16 :
10458 i == Ydrip_s1B ? 16 :
10459 i == Ydrip_s2 ? 16 :
10460 i == Ydrip_s2B ? 16 :
10461 i == Xsand_stonein_1 ? 32 :
10462 i == Xsand_stonein_2 ? 32 :
10463 i == Xsand_stonein_3 ? 32 :
10464 i == Xsand_stonein_4 ? 32 :
10465 i == Xsand_stoneout_1 ? 16 :
10466 i == Xsand_stoneout_2 ? 16 : 8);
10467 int cx = ABS(dx) * (TILEX / num_steps);
10468 int cy = ABS(dy) * (TILEY / num_steps);
10469 int step_frame = (i == Ydrip_s2 ? j + 8 :
10470 i == Ydrip_s2B ? j + 8 :
10471 i == Xsand_stonein_2 ? j + 8 :
10472 i == Xsand_stonein_3 ? j + 16 :
10473 i == Xsand_stonein_4 ? j + 24 :
10474 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
10475 int step = (is_backside ? step_frame : num_steps - step_frame);
10477 if (is_backside) /* tile where movement starts */
10479 if (dx < 0 || dy < 0)
10481 g_em->src_offset_x = cx * step;
10482 g_em->src_offset_y = cy * step;
10486 g_em->dst_offset_x = cx * step;
10487 g_em->dst_offset_y = cy * step;
10490 else /* tile where movement ends */
10492 if (dx < 0 || dy < 0)
10494 g_em->dst_offset_x = cx * step;
10495 g_em->dst_offset_y = cy * step;
10499 g_em->src_offset_x = cx * step;
10500 g_em->src_offset_y = cy * step;
10504 g_em->width = TILEX - cx * step;
10505 g_em->height = TILEY - cy * step;
10508 /* create unique graphic identifier to decide if tile must be redrawn */
10509 /* bit 31 - 16 (16 bit): EM style graphic
10510 bit 15 - 12 ( 4 bit): EM style frame
10511 bit 11 - 6 ( 6 bit): graphic width
10512 bit 5 - 0 ( 6 bit): graphic height */
10513 g_em->unique_identifier =
10514 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
10520 void getGraphicSourcePlayerExt_EM(struct GraphicInfo_EM *g_em,
10521 int player_nr, int anim, int frame_em)
10523 int element = player_mapping[player_nr][anim].element_rnd;
10524 int action = player_mapping[player_nr][anim].action;
10525 int direction = player_mapping[player_nr][anim].direction;
10526 int graphic = (direction == MV_NONE ?
10527 el_act2img(element, action) :
10528 el_act_dir2img(element, action, direction));
10529 struct GraphicInfo *g = &graphic_info[graphic];
10532 InitPlayerGfxAnimation(&stored_player[player_nr], action, direction);
10534 stored_player[player_nr].StepFrame = frame_em;
10536 sync_frame = stored_player[player_nr].Frame;
10538 int frame = getAnimationFrame(g->anim_frames,
10541 g->anim_start_frame,
10544 getGraphicSourceExt(graphic, frame, &g_em->bitmap,
10545 &g_em->src_x, &g_em->src_y, FALSE);
10548 printf("::: %d: %d, %d [%d]\n",
10550 stored_player[player_nr].Frame,
10551 stored_player[player_nr].StepFrame,
10556 void InitGraphicInfo_EM(void)
10559 struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
10560 struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
10565 int num_em_gfx_errors = 0;
10567 if (graphic_info_em_object[0][0].bitmap == NULL)
10569 /* EM graphics not yet initialized in em_open_all() */
10574 printf("::: [4 errors can be ignored (1 x 'bomb', 3 x 'em_dynamite']\n");
10577 /* always start with reliable default values */
10578 for (i = 0; i < TILE_MAX; i++)
10580 object_mapping[i].element_rnd = EL_UNKNOWN;
10581 object_mapping[i].is_backside = FALSE;
10582 object_mapping[i].action = ACTION_DEFAULT;
10583 object_mapping[i].direction = MV_NONE;
10586 /* always start with reliable default values */
10587 for (p = 0; p < MAX_PLAYERS; p++)
10589 for (i = 0; i < SPR_MAX; i++)
10591 player_mapping[p][i].element_rnd = EL_UNKNOWN;
10592 player_mapping[p][i].action = ACTION_DEFAULT;
10593 player_mapping[p][i].direction = MV_NONE;
10597 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
10599 int e = em_object_mapping_list[i].element_em;
10601 object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd;
10602 object_mapping[e].is_backside = em_object_mapping_list[i].is_backside;
10604 if (em_object_mapping_list[i].action != -1)
10605 object_mapping[e].action = em_object_mapping_list[i].action;
10607 if (em_object_mapping_list[i].direction != -1)
10608 object_mapping[e].direction =
10609 MV_DIR_FROM_BIT(em_object_mapping_list[i].direction);
10612 for (i = 0; em_player_mapping_list[i].action_em != -1; i++)
10614 int a = em_player_mapping_list[i].action_em;
10615 int p = em_player_mapping_list[i].player_nr;
10617 player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd;
10619 if (em_player_mapping_list[i].action != -1)
10620 player_mapping[p][a].action = em_player_mapping_list[i].action;
10622 if (em_player_mapping_list[i].direction != -1)
10623 player_mapping[p][a].direction =
10624 MV_DIR_FROM_BIT(em_player_mapping_list[i].direction);
10627 for (i = 0; i < TILE_MAX; i++)
10629 int element = object_mapping[i].element_rnd;
10630 int action = object_mapping[i].action;
10631 int direction = object_mapping[i].direction;
10632 boolean is_backside = object_mapping[i].is_backside;
10634 boolean action_removing = (action == ACTION_DIGGING ||
10635 action == ACTION_SNAPPING ||
10636 action == ACTION_COLLECTING);
10638 boolean action_exploding = ((action == ACTION_EXPLODING ||
10639 action == ACTION_SMASHED_BY_ROCK ||
10640 action == ACTION_SMASHED_BY_SPRING) &&
10641 element != EL_DIAMOND);
10642 boolean action_active = (action == ACTION_ACTIVE);
10643 boolean action_other = (action == ACTION_OTHER);
10645 for (j = 0; j < 8; j++)
10648 int effective_element = get_effective_element_EM(i, j);
10650 int effective_element = (j > 5 && i == Yacid_splash_eB ? EL_EMPTY :
10651 j > 5 && i == Yacid_splash_wB ? EL_EMPTY :
10653 i == Xdrip_stretch ? element :
10654 i == Xdrip_stretchB ? element :
10655 i == Ydrip_s1 ? element :
10656 i == Ydrip_s1B ? element :
10657 i == Xball_1B ? element :
10658 i == Xball_2 ? element :
10659 i == Xball_2B ? element :
10660 i == Yball_eat ? element :
10661 i == Ykey_1_eat ? element :
10662 i == Ykey_2_eat ? element :
10663 i == Ykey_3_eat ? element :
10664 i == Ykey_4_eat ? element :
10665 i == Ykey_5_eat ? element :
10666 i == Ykey_6_eat ? element :
10667 i == Ykey_7_eat ? element :
10668 i == Ykey_8_eat ? element :
10669 i == Ylenses_eat ? element :
10670 i == Ymagnify_eat ? element :
10671 i == Ygrass_eat ? element :
10672 i == Ydirt_eat ? element :
10673 i == Yemerald_stone ? EL_EMERALD :
10674 i == Ydiamond_stone ? EL_ROCK :
10675 i == Xsand_stonein_1 ? element :
10676 i == Xsand_stonein_2 ? element :
10677 i == Xsand_stonein_3 ? element :
10678 i == Xsand_stonein_4 ? element :
10679 is_backside ? EL_EMPTY :
10680 action_removing ? EL_EMPTY :
10683 int effective_action = (j < 7 ? action :
10684 i == Xdrip_stretch ? action :
10685 i == Xdrip_stretchB ? action :
10686 i == Ydrip_s1 ? action :
10687 i == Ydrip_s1B ? action :
10688 i == Xball_1B ? action :
10689 i == Xball_2 ? action :
10690 i == Xball_2B ? action :
10691 i == Yball_eat ? action :
10692 i == Ykey_1_eat ? action :
10693 i == Ykey_2_eat ? action :
10694 i == Ykey_3_eat ? action :
10695 i == Ykey_4_eat ? action :
10696 i == Ykey_5_eat ? action :
10697 i == Ykey_6_eat ? action :
10698 i == Ykey_7_eat ? action :
10699 i == Ykey_8_eat ? action :
10700 i == Ylenses_eat ? action :
10701 i == Ymagnify_eat ? action :
10702 i == Ygrass_eat ? action :
10703 i == Ydirt_eat ? action :
10704 i == Xsand_stonein_1 ? action :
10705 i == Xsand_stonein_2 ? action :
10706 i == Xsand_stonein_3 ? action :
10707 i == Xsand_stonein_4 ? action :
10708 i == Xsand_stoneout_1 ? action :
10709 i == Xsand_stoneout_2 ? action :
10710 i == Xboom_android ? ACTION_EXPLODING :
10711 action_exploding ? ACTION_EXPLODING :
10712 action_active ? action :
10713 action_other ? action :
10715 int graphic = (el_act_dir2img(effective_element, effective_action,
10717 int crumbled = (el_act_dir2crm(effective_element, effective_action,
10719 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
10720 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
10721 boolean has_action_graphics = (graphic != base_graphic);
10722 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
10723 struct GraphicInfo *g = &graphic_info[graphic];
10725 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
10727 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
10728 Bitmap *src_bitmap;
10730 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
10731 boolean special_animation = (action != ACTION_DEFAULT &&
10732 g->anim_frames == 3 &&
10733 g->anim_delay == 2 &&
10734 g->anim_mode & ANIM_LINEAR);
10735 int sync_frame = (i == Xdrip_stretch ? 7 :
10736 i == Xdrip_stretchB ? 7 :
10737 i == Ydrip_s2 ? j + 8 :
10738 i == Ydrip_s2B ? j + 8 :
10740 i == Xacid_2 ? 10 :
10741 i == Xacid_3 ? 20 :
10742 i == Xacid_4 ? 30 :
10743 i == Xacid_5 ? 40 :
10744 i == Xacid_6 ? 50 :
10745 i == Xacid_7 ? 60 :
10746 i == Xacid_8 ? 70 :
10747 i == Xfake_acid_1 ? 0 :
10748 i == Xfake_acid_2 ? 10 :
10749 i == Xfake_acid_3 ? 20 :
10750 i == Xfake_acid_4 ? 30 :
10751 i == Xfake_acid_5 ? 40 :
10752 i == Xfake_acid_6 ? 50 :
10753 i == Xfake_acid_7 ? 60 :
10754 i == Xfake_acid_8 ? 70 :
10756 i == Xball_2B ? j + 8 :
10757 i == Yball_eat ? j + 1 :
10758 i == Ykey_1_eat ? j + 1 :
10759 i == Ykey_2_eat ? j + 1 :
10760 i == Ykey_3_eat ? j + 1 :
10761 i == Ykey_4_eat ? j + 1 :
10762 i == Ykey_5_eat ? j + 1 :
10763 i == Ykey_6_eat ? j + 1 :
10764 i == Ykey_7_eat ? j + 1 :
10765 i == Ykey_8_eat ? j + 1 :
10766 i == Ylenses_eat ? j + 1 :
10767 i == Ymagnify_eat ? j + 1 :
10768 i == Ygrass_eat ? j + 1 :
10769 i == Ydirt_eat ? j + 1 :
10770 i == Xamoeba_1 ? 0 :
10771 i == Xamoeba_2 ? 1 :
10772 i == Xamoeba_3 ? 2 :
10773 i == Xamoeba_4 ? 3 :
10774 i == Xamoeba_5 ? 0 :
10775 i == Xamoeba_6 ? 1 :
10776 i == Xamoeba_7 ? 2 :
10777 i == Xamoeba_8 ? 3 :
10778 i == Xexit_2 ? j + 8 :
10779 i == Xexit_3 ? j + 16 :
10780 i == Xdynamite_1 ? 0 :
10781 i == Xdynamite_2 ? 8 :
10782 i == Xdynamite_3 ? 16 :
10783 i == Xdynamite_4 ? 24 :
10784 i == Xsand_stonein_1 ? j + 1 :
10785 i == Xsand_stonein_2 ? j + 9 :
10786 i == Xsand_stonein_3 ? j + 17 :
10787 i == Xsand_stonein_4 ? j + 25 :
10788 i == Xsand_stoneout_1 && j == 0 ? 0 :
10789 i == Xsand_stoneout_1 && j == 1 ? 0 :
10790 i == Xsand_stoneout_1 && j == 2 ? 1 :
10791 i == Xsand_stoneout_1 && j == 3 ? 2 :
10792 i == Xsand_stoneout_1 && j == 4 ? 2 :
10793 i == Xsand_stoneout_1 && j == 5 ? 3 :
10794 i == Xsand_stoneout_1 && j == 6 ? 4 :
10795 i == Xsand_stoneout_1 && j == 7 ? 4 :
10796 i == Xsand_stoneout_2 && j == 0 ? 5 :
10797 i == Xsand_stoneout_2 && j == 1 ? 6 :
10798 i == Xsand_stoneout_2 && j == 2 ? 7 :
10799 i == Xsand_stoneout_2 && j == 3 ? 8 :
10800 i == Xsand_stoneout_2 && j == 4 ? 9 :
10801 i == Xsand_stoneout_2 && j == 5 ? 11 :
10802 i == Xsand_stoneout_2 && j == 6 ? 13 :
10803 i == Xsand_stoneout_2 && j == 7 ? 15 :
10804 i == Xboom_bug && j == 1 ? 2 :
10805 i == Xboom_bug && j == 2 ? 2 :
10806 i == Xboom_bug && j == 3 ? 4 :
10807 i == Xboom_bug && j == 4 ? 4 :
10808 i == Xboom_bug && j == 5 ? 2 :
10809 i == Xboom_bug && j == 6 ? 2 :
10810 i == Xboom_bug && j == 7 ? 0 :
10811 i == Xboom_bomb && j == 1 ? 2 :
10812 i == Xboom_bomb && j == 2 ? 2 :
10813 i == Xboom_bomb && j == 3 ? 4 :
10814 i == Xboom_bomb && j == 4 ? 4 :
10815 i == Xboom_bomb && j == 5 ? 2 :
10816 i == Xboom_bomb && j == 6 ? 2 :
10817 i == Xboom_bomb && j == 7 ? 0 :
10818 i == Xboom_android && j == 7 ? 6 :
10819 i == Xboom_1 && j == 1 ? 2 :
10820 i == Xboom_1 && j == 2 ? 2 :
10821 i == Xboom_1 && j == 3 ? 4 :
10822 i == Xboom_1 && j == 4 ? 4 :
10823 i == Xboom_1 && j == 5 ? 6 :
10824 i == Xboom_1 && j == 6 ? 6 :
10825 i == Xboom_1 && j == 7 ? 8 :
10826 i == Xboom_2 && j == 0 ? 8 :
10827 i == Xboom_2 && j == 1 ? 8 :
10828 i == Xboom_2 && j == 2 ? 10 :
10829 i == Xboom_2 && j == 3 ? 10 :
10830 i == Xboom_2 && j == 4 ? 10 :
10831 i == Xboom_2 && j == 5 ? 12 :
10832 i == Xboom_2 && j == 6 ? 12 :
10833 i == Xboom_2 && j == 7 ? 12 :
10834 special_animation && j == 4 ? 3 :
10835 effective_action != action ? 0 :
10839 Bitmap *debug_bitmap = g_em->bitmap;
10840 int debug_src_x = g_em->src_x;
10841 int debug_src_y = g_em->src_y;
10844 int frame = getAnimationFrame(g->anim_frames,
10847 g->anim_start_frame,
10850 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y,
10851 g->double_movement && is_backside);
10853 g_em->bitmap = src_bitmap;
10854 g_em->src_x = src_x;
10855 g_em->src_y = src_y;
10856 g_em->src_offset_x = 0;
10857 g_em->src_offset_y = 0;
10858 g_em->dst_offset_x = 0;
10859 g_em->dst_offset_y = 0;
10860 g_em->width = TILEX;
10861 g_em->height = TILEY;
10863 g_em->preserve_background = FALSE;
10866 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
10871 g_em->crumbled_bitmap = NULL;
10872 g_em->crumbled_src_x = 0;
10873 g_em->crumbled_src_y = 0;
10874 g_em->crumbled_border_size = 0;
10876 g_em->has_crumbled_graphics = FALSE;
10879 if (has_crumbled_graphics && crumbled == IMG_EMPTY_SPACE)
10880 printf("::: empty crumbled: %d [%s], %d, %d\n",
10881 effective_element, element_info[effective_element].token_name,
10882 effective_action, direction);
10885 /* if element can be crumbled, but certain action graphics are just empty
10886 space (like instantly snapping sand to empty space in 1 frame), do not
10887 treat these empty space graphics as crumbled graphics in EMC engine */
10888 if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
10890 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
10891 g_crumbled->anim_delay,
10892 g_crumbled->anim_mode,
10893 g_crumbled->anim_start_frame,
10896 getGraphicSource(crumbled, frame_crumbled, &src_bitmap, &src_x, &src_y);
10898 g_em->has_crumbled_graphics = TRUE;
10899 g_em->crumbled_bitmap = src_bitmap;
10900 g_em->crumbled_src_x = src_x;
10901 g_em->crumbled_src_y = src_y;
10902 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
10906 if (g_em == &graphic_info_em_object[207][0])
10907 printf("... %d, %d [%d, %d, %d, %d] [%d, %d, %d, %d, %d, %d => %d]\n",
10908 graphic_info_em_object[207][0].crumbled_src_x,
10909 graphic_info_em_object[207][0].crumbled_src_y,
10911 crumbled, frame, src_x, src_y,
10916 g->anim_start_frame,
10918 gfx.anim_random_frame,
10923 printf("::: EMC tile %d is crumbled\n", i);
10929 if (element == EL_ROCK &&
10930 effective_action == ACTION_FILLING)
10931 printf("::: has_action_graphics == %d\n", has_action_graphics);
10934 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
10935 effective_action == ACTION_MOVING ||
10936 effective_action == ACTION_PUSHING ||
10937 effective_action == ACTION_EATING)) ||
10938 (!has_action_graphics && (effective_action == ACTION_FILLING ||
10939 effective_action == ACTION_EMPTYING)))
10942 (effective_action == ACTION_FALLING ||
10943 effective_action == ACTION_FILLING ||
10944 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
10945 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
10946 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
10947 int num_steps = (i == Ydrip_s1 ? 16 :
10948 i == Ydrip_s1B ? 16 :
10949 i == Ydrip_s2 ? 16 :
10950 i == Ydrip_s2B ? 16 :
10951 i == Xsand_stonein_1 ? 32 :
10952 i == Xsand_stonein_2 ? 32 :
10953 i == Xsand_stonein_3 ? 32 :
10954 i == Xsand_stonein_4 ? 32 :
10955 i == Xsand_stoneout_1 ? 16 :
10956 i == Xsand_stoneout_2 ? 16 : 8);
10957 int cx = ABS(dx) * (TILEX / num_steps);
10958 int cy = ABS(dy) * (TILEY / num_steps);
10959 int step_frame = (i == Ydrip_s2 ? j + 8 :
10960 i == Ydrip_s2B ? j + 8 :
10961 i == Xsand_stonein_2 ? j + 8 :
10962 i == Xsand_stonein_3 ? j + 16 :
10963 i == Xsand_stonein_4 ? j + 24 :
10964 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
10965 int step = (is_backside ? step_frame : num_steps - step_frame);
10967 if (is_backside) /* tile where movement starts */
10969 if (dx < 0 || dy < 0)
10971 g_em->src_offset_x = cx * step;
10972 g_em->src_offset_y = cy * step;
10976 g_em->dst_offset_x = cx * step;
10977 g_em->dst_offset_y = cy * step;
10980 else /* tile where movement ends */
10982 if (dx < 0 || dy < 0)
10984 g_em->dst_offset_x = cx * step;
10985 g_em->dst_offset_y = cy * step;
10989 g_em->src_offset_x = cx * step;
10990 g_em->src_offset_y = cy * step;
10994 g_em->width = TILEX - cx * step;
10995 g_em->height = TILEY - cy * step;
10998 /* create unique graphic identifier to decide if tile must be redrawn */
10999 /* bit 31 - 16 (16 bit): EM style graphic
11000 bit 15 - 12 ( 4 bit): EM style frame
11001 bit 11 - 6 ( 6 bit): graphic width
11002 bit 5 - 0 ( 6 bit): graphic height */
11003 g_em->unique_identifier =
11004 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
11008 /* skip check for EMC elements not contained in original EMC artwork */
11009 if (element == EL_EMC_FAKE_ACID)
11012 if (g_em->bitmap != debug_bitmap ||
11013 g_em->src_x != debug_src_x ||
11014 g_em->src_y != debug_src_y ||
11015 g_em->src_offset_x != 0 ||
11016 g_em->src_offset_y != 0 ||
11017 g_em->dst_offset_x != 0 ||
11018 g_em->dst_offset_y != 0 ||
11019 g_em->width != TILEX ||
11020 g_em->height != TILEY)
11022 static int last_i = -1;
11030 printf("::: EMC GFX ERROR for element %d -> %d ('%s', '%s', %d)",
11031 i, element, element_info[element].token_name,
11032 element_action_info[effective_action].suffix, direction);
11034 if (element != effective_element)
11035 printf(" [%d ('%s')]",
11037 element_info[effective_element].token_name);
11041 if (g_em->bitmap != debug_bitmap)
11042 printf(" %d (%d): different bitmap! (0x%08x != 0x%08x)\n",
11043 j, is_backside, (int)(g_em->bitmap), (int)(debug_bitmap));
11045 if (g_em->src_x != debug_src_x ||
11046 g_em->src_y != debug_src_y)
11047 printf(" frame %d (%c): %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
11048 j, (is_backside ? 'B' : 'F'),
11049 g_em->src_x, g_em->src_y,
11050 g_em->src_x / 32, g_em->src_y / 32,
11051 debug_src_x, debug_src_y,
11052 debug_src_x / 32, debug_src_y / 32);
11054 if (g_em->src_offset_x != 0 ||
11055 g_em->src_offset_y != 0 ||
11056 g_em->dst_offset_x != 0 ||
11057 g_em->dst_offset_y != 0)
11058 printf(" %d (%d): offsets %d,%d and %d,%d should be all 0\n",
11060 g_em->src_offset_x, g_em->src_offset_y,
11061 g_em->dst_offset_x, g_em->dst_offset_y);
11063 if (g_em->width != TILEX ||
11064 g_em->height != TILEY)
11065 printf(" %d (%d): size %d,%d should be %d,%d\n",
11067 g_em->width, g_em->height, TILEX, TILEY);
11069 num_em_gfx_errors++;
11076 for (i = 0; i < TILE_MAX; i++)
11078 for (j = 0; j < 8; j++)
11080 int element = object_mapping[i].element_rnd;
11081 int action = object_mapping[i].action;
11082 int direction = object_mapping[i].direction;
11083 boolean is_backside = object_mapping[i].is_backside;
11084 int graphic_action = el_act_dir2img(element, action, direction);
11085 int graphic_default = el_act_dir2img(element, ACTION_DEFAULT, direction);
11087 if ((action == ACTION_SMASHED_BY_ROCK ||
11088 action == ACTION_SMASHED_BY_SPRING ||
11089 action == ACTION_EATING) &&
11090 graphic_action == graphic_default)
11092 int e = (action == ACTION_SMASHED_BY_ROCK ? Ystone_s :
11093 action == ACTION_SMASHED_BY_SPRING ? Yspring_s :
11094 direction == MV_LEFT ? (is_backside? Yspring_wB: Yspring_w) :
11095 direction == MV_RIGHT ? (is_backside? Yspring_eB: Yspring_e) :
11098 /* no separate animation for "smashed by rock" -- use rock instead */
11099 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
11100 struct GraphicInfo_EM *g_xx = &graphic_info_em_object[e][7 - j];
11102 g_em->bitmap = g_xx->bitmap;
11103 g_em->src_x = g_xx->src_x;
11104 g_em->src_y = g_xx->src_y;
11105 g_em->src_offset_x = g_xx->src_offset_x;
11106 g_em->src_offset_y = g_xx->src_offset_y;
11107 g_em->dst_offset_x = g_xx->dst_offset_x;
11108 g_em->dst_offset_y = g_xx->dst_offset_y;
11109 g_em->width = g_xx->width;
11110 g_em->height = g_xx->height;
11111 g_em->unique_identifier = g_xx->unique_identifier;
11114 g_em->preserve_background = TRUE;
11119 for (p = 0; p < MAX_PLAYERS; p++)
11121 for (i = 0; i < SPR_MAX; i++)
11123 int element = player_mapping[p][i].element_rnd;
11124 int action = player_mapping[p][i].action;
11125 int direction = player_mapping[p][i].direction;
11127 for (j = 0; j < 8; j++)
11129 int effective_element = element;
11130 int effective_action = action;
11131 int graphic = (direction == MV_NONE ?
11132 el_act2img(effective_element, effective_action) :
11133 el_act_dir2img(effective_element, effective_action,
11135 struct GraphicInfo *g = &graphic_info[graphic];
11136 struct GraphicInfo_EM *g_em = &graphic_info_em_player[p][i][7 - j];
11137 Bitmap *src_bitmap;
11139 int sync_frame = j;
11142 Bitmap *debug_bitmap = g_em->bitmap;
11143 int debug_src_x = g_em->src_x;
11144 int debug_src_y = g_em->src_y;
11147 int frame = getAnimationFrame(g->anim_frames,
11150 g->anim_start_frame,
11153 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
11155 g_em->bitmap = src_bitmap;
11156 g_em->src_x = src_x;
11157 g_em->src_y = src_y;
11158 g_em->src_offset_x = 0;
11159 g_em->src_offset_y = 0;
11160 g_em->dst_offset_x = 0;
11161 g_em->dst_offset_y = 0;
11162 g_em->width = TILEX;
11163 g_em->height = TILEY;
11167 /* skip check for EMC elements not contained in original EMC artwork */
11168 if (element == EL_PLAYER_3 ||
11169 element == EL_PLAYER_4)
11172 if (g_em->bitmap != debug_bitmap ||
11173 g_em->src_x != debug_src_x ||
11174 g_em->src_y != debug_src_y)
11176 static int last_i = -1;
11184 printf("::: EMC GFX ERROR for p/a %d/%d -> %d ('%s', '%s', %d)",
11185 p, i, element, element_info[element].token_name,
11186 element_action_info[effective_action].suffix, direction);
11188 if (element != effective_element)
11189 printf(" [%d ('%s')]",
11191 element_info[effective_element].token_name);
11195 if (g_em->bitmap != debug_bitmap)
11196 printf(" %d: different bitmap! (0x%08x != 0x%08x)\n",
11197 j, (int)(g_em->bitmap), (int)(debug_bitmap));
11199 if (g_em->src_x != debug_src_x ||
11200 g_em->src_y != debug_src_y)
11201 printf(" frame %d: %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
11203 g_em->src_x, g_em->src_y,
11204 g_em->src_x / 32, g_em->src_y / 32,
11205 debug_src_x, debug_src_y,
11206 debug_src_x / 32, debug_src_y / 32);
11208 num_em_gfx_errors++;
11218 printf("::: [%d errors found]\n", num_em_gfx_errors);
11224 void CheckSingleStepMode_EM(byte action[MAX_PLAYERS], int frame,
11225 boolean any_player_moving,
11226 boolean player_is_dropping)
11228 if (tape.single_step && tape.recording && !tape.pausing)
11231 boolean active_players = FALSE;
11234 for (i = 0; i < MAX_PLAYERS; i++)
11235 if (action[i] != JOY_NO_ACTION)
11236 active_players = TRUE;
11240 if (frame == 0 && !player_is_dropping)
11241 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
11245 void CheckSingleStepMode_SP(boolean murphy_is_waiting,
11246 boolean murphy_is_dropping)
11249 printf("::: waiting: %d, dropping: %d\n",
11250 murphy_is_waiting, murphy_is_dropping);
11253 if (tape.single_step && tape.recording && !tape.pausing)
11255 // if (murphy_is_waiting || murphy_is_dropping)
11256 if (murphy_is_waiting)
11259 printf("::: murphy is waiting -> pause mode\n");
11262 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
11267 void getGraphicSource_SP(struct GraphicInfo_SP *g_sp,
11268 int graphic, int sync_frame, int x, int y)
11270 int frame = getGraphicAnimationFrame(graphic, sync_frame);
11272 getGraphicSource(graphic, frame, &g_sp->bitmap, &g_sp->src_x, &g_sp->src_y);
11275 boolean isNextAnimationFrame_SP(int graphic, int sync_frame)
11277 return (IS_NEXT_FRAME(sync_frame, graphic));
11280 int getGraphicInfo_Delay(int graphic)
11282 return graphic_info[graphic].anim_delay;
11285 void PlayMenuSoundExt(int sound)
11287 if (sound == SND_UNDEFINED)
11290 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
11291 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
11294 if (IS_LOOP_SOUND(sound))
11295 PlaySoundLoop(sound);
11300 void PlayMenuSound()
11302 PlayMenuSoundExt(menu.sound[game_status]);
11305 void PlayMenuSoundStereo(int sound, int stereo_position)
11307 if (sound == SND_UNDEFINED)
11310 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
11311 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
11314 if (IS_LOOP_SOUND(sound))
11315 PlaySoundExt(sound, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_LOOP);
11317 PlaySoundStereo(sound, stereo_position);
11320 void PlayMenuSoundIfLoopExt(int sound)
11322 if (sound == SND_UNDEFINED)
11325 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
11326 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
11329 if (IS_LOOP_SOUND(sound))
11330 PlaySoundLoop(sound);
11333 void PlayMenuSoundIfLoop()
11335 PlayMenuSoundIfLoopExt(menu.sound[game_status]);
11338 void PlayMenuMusicExt(int music)
11340 if (music == MUS_UNDEFINED)
11343 if (!setup.sound_music)
11349 void PlayMenuMusic()
11351 PlayMenuMusicExt(menu.music[game_status]);
11354 void PlaySoundActivating()
11357 PlaySound(SND_MENU_ITEM_ACTIVATING);
11361 void PlaySoundSelecting()
11364 PlaySound(SND_MENU_ITEM_SELECTING);
11368 void ToggleFullscreenOrChangeWindowScalingIfNeeded()
11370 boolean change_fullscreen = (setup.fullscreen !=
11371 video.fullscreen_enabled);
11372 boolean change_fullscreen_mode = (video.fullscreen_enabled &&
11373 !strEqual(setup.fullscreen_mode,
11374 video.fullscreen_mode_current));
11375 boolean change_window_scaling_percent = (!video.fullscreen_enabled &&
11376 setup.window_scaling_percent !=
11377 video.window_scaling_percent);
11379 if (change_window_scaling_percent && video.fullscreen_enabled)
11382 if (!change_window_scaling_percent && !video.fullscreen_available)
11385 #if defined(TARGET_SDL2)
11386 if (change_window_scaling_percent)
11388 SDLSetWindowScaling(setup.window_scaling_percent);
11392 else if (change_fullscreen)
11394 SDLSetWindowFullscreen(setup.fullscreen);
11396 /* set setup value according to successfully changed fullscreen mode */
11397 setup.fullscreen = video.fullscreen_enabled;
11403 if (change_fullscreen ||
11404 change_fullscreen_mode ||
11405 change_window_scaling_percent)
11407 Bitmap *tmp_backbuffer = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
11409 /* save backbuffer content which gets lost when toggling fullscreen mode */
11410 BlitBitmap(backbuffer, tmp_backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
11412 if (change_fullscreen_mode)
11414 /* keep fullscreen, but change fullscreen mode (screen resolution) */
11415 video.fullscreen_enabled = FALSE; /* force new fullscreen mode */
11418 if (change_window_scaling_percent)
11420 /* keep window mode, but change window scaling */
11421 video.fullscreen_enabled = TRUE; /* force new window scaling */
11424 /* toggle fullscreen */
11425 ChangeVideoModeIfNeeded(setup.fullscreen);
11427 /* set setup value according to successfully changed fullscreen mode */
11428 setup.fullscreen = video.fullscreen_enabled;
11430 /* restore backbuffer content from temporary backbuffer backup bitmap */
11431 BlitBitmap(tmp_backbuffer, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
11433 FreeBitmap(tmp_backbuffer);
11436 /* update visible window/screen */
11437 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
11439 redraw_mask = REDRAW_ALL;
11444 void ChangeViewportPropertiesIfNeeded()
11447 int *door_1_x = &DX;
11448 int *door_1_y = &DY;
11449 int *door_2_x = (game_status == GAME_MODE_EDITOR ? &EX : &VX);
11450 int *door_2_y = (game_status == GAME_MODE_EDITOR ? &EY : &VY);
11453 int gfx_game_mode = game_status;
11455 int gfx_game_mode = (game_status == GAME_MODE_PLAYING ||
11456 game_status == GAME_MODE_EDITOR ? game_status :
11459 int gfx_game_mode2 = (game_status == GAME_MODE_EDITOR ? GAME_MODE_DEFAULT :
11461 struct RectWithBorder *vp_playfield = &viewport.playfield[gfx_game_mode];
11462 struct RectWithBorder *vp_door_1 = &viewport.door_1[gfx_game_mode];
11463 struct RectWithBorder *vp_door_2 = &viewport.door_2[gfx_game_mode2];
11464 struct RectWithBorder *vp_door_3 = &viewport.door_2[GAME_MODE_EDITOR];
11465 int border_size = vp_playfield->border_size;
11466 int new_sx = vp_playfield->x + border_size;
11467 int new_sy = vp_playfield->y + border_size;
11468 int new_sxsize = vp_playfield->width - 2 * border_size;
11469 int new_sysize = vp_playfield->height - 2 * border_size;
11470 int new_real_sx = vp_playfield->x;
11471 int new_real_sy = vp_playfield->y;
11472 int new_full_sxsize = vp_playfield->width;
11473 int new_full_sysize = vp_playfield->height;
11474 int new_dx = vp_door_1->x;
11475 int new_dy = vp_door_1->y;
11476 int new_dxsize = vp_door_1->width;
11477 int new_dysize = vp_door_1->height;
11478 int new_vx = vp_door_2->x;
11479 int new_vy = vp_door_2->y;
11480 int new_vxsize = vp_door_2->width;
11481 int new_vysize = vp_door_2->height;
11482 int new_ex = vp_door_3->x;
11483 int new_ey = vp_door_3->y;
11484 int new_exsize = vp_door_3->width;
11485 int new_eysize = vp_door_3->height;
11487 int new_tilesize_var = TILESIZE / (setup.small_game_graphics ? 2 : 1);
11488 int tilesize = (gfx_game_mode == GAME_MODE_PLAYING ? new_tilesize_var :
11489 gfx_game_mode == GAME_MODE_EDITOR ? MINI_TILESIZE : TILESIZE);
11490 int new_scr_fieldx = new_sxsize / tilesize;
11491 int new_scr_fieldy = new_sysize / tilesize;
11492 int new_scr_fieldx_buffers = new_sxsize / new_tilesize_var;
11493 int new_scr_fieldy_buffers = new_sysize / new_tilesize_var;
11495 int new_scr_fieldx = (vp_playfield->width - 2 * border_size) / TILESIZE;
11496 int new_scr_fieldy = (vp_playfield->height - 2 * border_size) / TILESIZE;
11498 boolean init_gfx_buffers = FALSE;
11499 boolean init_video_buffer = FALSE;
11500 boolean init_gadgets_and_toons = FALSE;
11503 /* !!! TEST ONLY !!! */
11504 // InitGfxBuffers();
11508 if (viewport.window.width != WIN_XSIZE ||
11509 viewport.window.height != WIN_YSIZE)
11511 WIN_XSIZE = viewport.window.width;
11512 WIN_YSIZE = viewport.window.height;
11515 init_video_buffer = TRUE;
11516 init_gfx_buffers = TRUE;
11518 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
11522 SetDrawDeactivationMask(REDRAW_NONE);
11523 SetDrawBackgroundMask(REDRAW_FIELD);
11525 // RedrawBackground();
11529 // printf("::: video: init_video_buffer, init_gfx_buffers\n");
11532 if (new_scr_fieldx != SCR_FIELDX ||
11533 new_scr_fieldy != SCR_FIELDY)
11535 /* this always toggles between MAIN and GAME when using small tile size */
11537 SCR_FIELDX = new_scr_fieldx;
11538 SCR_FIELDY = new_scr_fieldy;
11540 // printf("::: new_scr_fieldx != SCR_FIELDX ...\n");
11544 if (new_tilesize_var != TILESIZE_VAR &&
11545 gfx_game_mode == GAME_MODE_PLAYING)
11547 /* doing this outside GAME_MODE_PLAYING would give wrong playfield size */
11549 TILESIZE_VAR = new_tilesize_var;
11551 init_gfx_buffers = TRUE;
11553 // printf("::: tilesize: init_gfx_buffers\n");
11557 if (new_sx != SX ||
11565 new_sxsize != SXSIZE ||
11566 new_sysize != SYSIZE ||
11567 new_dxsize != DXSIZE ||
11568 new_dysize != DYSIZE ||
11569 new_vxsize != VXSIZE ||
11570 new_vysize != VYSIZE ||
11571 new_exsize != EXSIZE ||
11572 new_eysize != EYSIZE ||
11573 new_real_sx != REAL_SX ||
11574 new_real_sy != REAL_SY ||
11575 new_full_sxsize != FULL_SXSIZE ||
11576 new_full_sysize != FULL_SYSIZE ||
11577 new_tilesize_var != TILESIZE_VAR
11580 vp_door_1->x != *door_1_x ||
11581 vp_door_1->y != *door_1_y ||
11582 vp_door_2->x != *door_2_x ||
11583 vp_door_2->y != *door_2_y
11588 // changing tile size invalidates scroll values of engine snapshots
11589 if (new_tilesize_var != TILESIZE_VAR)
11591 // printf("::: new_tilesize_var != TILESIZE_VAR\n");
11593 FreeEngineSnapshot();
11605 SXSIZE = new_sxsize;
11606 SYSIZE = new_sysize;
11607 DXSIZE = new_dxsize;
11608 DYSIZE = new_dysize;
11609 VXSIZE = new_vxsize;
11610 VYSIZE = new_vysize;
11611 EXSIZE = new_exsize;
11612 EYSIZE = new_eysize;
11613 REAL_SX = new_real_sx;
11614 REAL_SY = new_real_sy;
11615 FULL_SXSIZE = new_full_sxsize;
11616 FULL_SYSIZE = new_full_sysize;
11617 TILESIZE_VAR = new_tilesize_var;
11620 printf("::: %d, %d, %d [%d]\n",
11621 SCR_FIELDX, SCR_FIELDY, TILESIZE_VAR,
11622 setup.small_game_graphics);
11626 *door_1_x = vp_door_1->x;
11627 *door_1_y = vp_door_1->y;
11628 *door_2_x = vp_door_2->x;
11629 *door_2_y = vp_door_2->y;
11633 init_gfx_buffers = TRUE;
11635 // printf("::: viewports: init_gfx_buffers\n");
11641 if (gfx_game_mode == GAME_MODE_MAIN)
11645 init_gadgets_and_toons = TRUE;
11647 // printf("::: viewports: init_gadgets_and_toons\n");
11655 if (init_gfx_buffers)
11657 // printf("::: init_gfx_buffers\n");
11659 SCR_FIELDX = new_scr_fieldx_buffers;
11660 SCR_FIELDY = new_scr_fieldy_buffers;
11664 SCR_FIELDX = new_scr_fieldx;
11665 SCR_FIELDY = new_scr_fieldy;
11668 if (init_video_buffer)
11670 // printf("::: init_video_buffer\n");
11672 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
11674 SetDrawDeactivationMask(REDRAW_NONE);
11675 SetDrawBackgroundMask(REDRAW_FIELD);
11678 if (init_gadgets_and_toons)
11680 // printf("::: init_gadgets_and_toons\n");
11687 printf("::: %d, %d / %d, %d [%d]\n", VX, VY, EX, EY, game_status);