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 void RedrawPlayfield(boolean force_redraw, int x, int y, int width, int height)
303 if (game_status == GAME_MODE_PLAYING &&
304 level.game_engine_type == GAME_ENGINE_TYPE_EM)
306 /* currently there is no partial redraw -- always redraw whole playfield */
307 RedrawPlayfield_EM(TRUE);
309 /* blit playfield from scroll buffer to normal back buffer for fading in */
310 BlitScreenToBitmap_EM(backbuffer);
312 else if (game_status == GAME_MODE_PLAYING &&
313 level.game_engine_type == GAME_ENGINE_TYPE_SP)
315 /* currently there is no partial redraw -- always redraw whole playfield */
316 RedrawPlayfield_SP(TRUE);
318 /* blit playfield from scroll buffer to normal back buffer for fading in */
319 BlitScreenToBitmap_SP(backbuffer);
321 else if (game_status == GAME_MODE_PLAYING &&
322 !game.envelope_active)
328 SetMainBackgroundImage(IMG_BACKGROUND_PLAYING);
329 // SetDrawBackgroundMask(REDRAW_FIELD); // !!! CHECK THIS !!!
331 for (x = BX1; x <= BX2; x++)
332 for (y = BY1; y <= BY2; y++)
333 DrawScreenField(x, y);
335 redraw_mask |= REDRAW_FIELD;
340 BlitScreenToBitmap(backbuffer);
342 /* blit playfield from scroll buffer to normal back buffer */
343 if (setup.soft_scrolling)
345 int fx = FX, fy = FY;
347 fx += (ScreenMovDir & (MV_LEFT|MV_RIGHT) ? ScreenGfxPos : 0);
348 fy += (ScreenMovDir & (MV_UP|MV_DOWN) ? ScreenGfxPos : 0);
350 BlitBitmap(fieldbuffer, backbuffer, fx,fy, SXSIZE,SYSIZE, SX,SY);
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 void BlitScreenToBitmap(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);
600 DrawBuffer *buffer = (drawto_field == window ? backbuffer : drawto_field);
603 printf("::: TILES TO REFRESH: %d\n", redraw_tiles);
604 for (x = 0; x < SCR_FIELDX; x++)
605 for (y = 0 ; y < SCR_FIELDY; y++)
606 if (redraw[redraw_x1 + x][redraw_y1 + y])
607 printf("::: - %d, %d [%s]\n",
608 LEVELX(x), LEVELY(y),
609 EL_NAME(Feld[LEVELX(x)][LEVELY(y)]));
612 if (redraw_mask & REDRAW_TILES && redraw_tiles > REDRAWTILES_THRESHOLD)
613 redraw_mask |= REDRAW_FIELD;
616 // never redraw single tiles, always redraw the whole field
617 // (redrawing single tiles up to a certain threshold was faster on old,
618 // now legacy graphics, but slows things down on modern graphics now)
619 // UPDATE: this is now globally defined by value of REDRAWTILES_THRESHOLD
620 if (redraw_mask & REDRAW_TILES)
621 redraw_mask |= REDRAW_FIELD;
625 /* !!! TEST ONLY !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */
626 /* (force full redraw) */
627 if (game_status == GAME_MODE_PLAYING)
628 redraw_mask |= REDRAW_FIELD;
631 if (redraw_mask & REDRAW_FIELD)
632 redraw_mask &= ~REDRAW_TILES;
634 if (redraw_mask == REDRAW_NONE)
639 if (redraw_mask & REDRAW_ALL)
640 printf("[REDRAW_ALL]");
641 if (redraw_mask & REDRAW_FIELD)
642 printf("[REDRAW_FIELD]");
643 if (redraw_mask & REDRAW_TILES)
644 printf("[REDRAW_TILES]");
645 if (redraw_mask & REDRAW_DOOR_1)
646 printf("[REDRAW_DOOR_1]");
647 if (redraw_mask & REDRAW_DOOR_2)
648 printf("[REDRAW_DOOR_2]");
649 if (redraw_mask & REDRAW_FROM_BACKBUFFER)
650 printf("[REDRAW_FROM_BACKBUFFER]");
651 printf(" [%d]\n", FrameCounter);
654 if (redraw_mask & REDRAW_TILES &&
655 game_status == GAME_MODE_PLAYING &&
656 border.draw_masked[GAME_MODE_PLAYING])
657 redraw_mask |= REDRAW_FIELD;
659 if (global.fps_slowdown && game_status == GAME_MODE_PLAYING)
661 static boolean last_frame_skipped = FALSE;
662 boolean skip_even_when_not_scrolling = TRUE;
663 boolean just_scrolling = (ScreenMovDir != 0);
664 boolean verbose = FALSE;
666 if (global.fps_slowdown_factor > 1 &&
667 (FrameCounter % global.fps_slowdown_factor) &&
668 (just_scrolling || skip_even_when_not_scrolling))
670 redraw_mask &= ~REDRAW_MAIN;
672 last_frame_skipped = TRUE;
675 printf("FRAME SKIPPED\n");
679 if (last_frame_skipped)
680 redraw_mask |= REDRAW_FIELD;
682 last_frame_skipped = FALSE;
685 printf("frame not skipped\n");
689 /* synchronize X11 graphics at this point; if we would synchronize the
690 display immediately after the buffer switching (after the XFlush),
691 this could mean that we have to wait for the graphics to complete,
692 although we could go on doing calculations for the next frame */
696 /* never draw masked border to backbuffer when using playfield buffer */
697 if (game_status != GAME_MODE_PLAYING ||
698 redraw_mask & REDRAW_FROM_BACKBUFFER ||
699 buffer == backbuffer)
700 DrawMaskedBorder(redraw_mask);
702 DrawMaskedBorder(redraw_mask & REDRAW_DOORS);
704 if (redraw_mask & REDRAW_ALL)
706 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
708 redraw_mask = REDRAW_NONE;
711 if (redraw_mask & REDRAW_FIELD)
714 printf("::: REDRAW_FIELD\n");
717 if (game_status != GAME_MODE_PLAYING ||
718 redraw_mask & REDRAW_FROM_BACKBUFFER)
720 BlitBitmap(backbuffer, window,
721 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE, REAL_SX, REAL_SY);
726 BlitScreenToBitmap(window);
728 int fx = FX, fy = FY;
731 int dx = (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
732 int dy = (ScreenMovDir & (MV_UP | MV_DOWN) ? ScreenGfxPos : 0);
733 int dx_var = dx * TILESIZE_VAR / TILESIZE;
734 int dy_var = dy * TILESIZE_VAR / TILESIZE;
737 // fx += dx * TILESIZE_VAR / TILESIZE;
738 // fy += dy * TILESIZE_VAR / TILESIZE;
740 fx += (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
741 fy += (ScreenMovDir & (MV_UP | MV_DOWN) ? ScreenGfxPos : 0);
744 /* !!! THIS WORKS !!! */
746 printf("::: %d, %d\n", scroll_x, scroll_y);
748 ffx = (scroll_x - SBX_Left) * TILEX_VAR + dx_var;
749 ffy = (scroll_y - SBY_Upper) * TILEY_VAR + dy_var;
751 if (EVEN(SCR_FIELDX))
753 if (ffx < SBX_Right * TILEX_VAR + TILEX_VAR / 2 + TILEX_VAR)
754 fx += dx_var - MIN(ffx, TILEX_VAR / 2) + TILEX_VAR;
756 fx += (dx > 0 ? TILEX_VAR : 0);
763 if (EVEN(SCR_FIELDY))
765 if (ffy < SBY_Lower * TILEY_VAR + TILEY_VAR / 2 + TILEY_VAR)
766 fy += dy_var - MIN(ffy, TILEY_VAR / 2) + TILEY_VAR;
768 fy += (dy > 0 ? TILEY_VAR : 0);
775 if (border.draw_masked[GAME_MODE_PLAYING])
777 if (buffer != backbuffer)
779 /* copy playfield buffer to backbuffer to add masked border */
780 BlitBitmap(buffer, backbuffer, fx, fy, SXSIZE, SYSIZE, SX, SY);
781 DrawMaskedBorder(REDRAW_FIELD);
784 BlitBitmap(backbuffer, window,
785 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
790 BlitBitmap(buffer, window, fx, fy, SXSIZE, SYSIZE, SX, SY);
796 printf("redrawing all (ScreenGfxPos == %d) because %s\n",
798 (setup.soft_scrolling ?
799 "setup.soft_scrolling" :
800 ABS(ScreenGfxPos) + ScrollStepSize == TILEX ?
801 "ABS(ScreenGfxPos) + ScrollStepSize == TILEX" :
802 ABS(ScreenGfxPos) == ScrollStepSize ?
803 "ABS(ScreenGfxPos) == ScrollStepSize" :
804 "redraw_tiles > REDRAWTILES_THRESHOLD"));
809 redraw_mask &= ~REDRAW_MAIN;
812 if (redraw_mask & REDRAW_DOORS)
814 if (redraw_mask & REDRAW_DOOR_1)
815 BlitBitmap(backbuffer, window, DX, DY, DXSIZE, DYSIZE, DX, DY);
817 if (redraw_mask & REDRAW_DOOR_2)
818 BlitBitmap(backbuffer, window, VX, VY, VXSIZE, VYSIZE, VX, VY);
820 if (redraw_mask & REDRAW_DOOR_3)
821 BlitBitmap(backbuffer, window, EX, EY, EXSIZE, EYSIZE, EX, EY);
823 redraw_mask &= ~REDRAW_DOORS;
826 if (redraw_mask & REDRAW_MICROLEVEL)
828 BlitBitmap(backbuffer, window, SX, SY + 10 * TILEY, SXSIZE, 7 * TILEY,
829 SX, SY + 10 * TILEY);
831 redraw_mask &= ~REDRAW_MICROLEVEL;
834 if (redraw_mask & REDRAW_TILES)
837 printf("::: REDRAW_TILES\n");
843 InitGfxClipRegion(TRUE, SX, SY, SXSIZE, SYSIZE);
846 int sx = SX; // - (EVEN(SCR_FIELDX) ? TILEX_VAR / 2 : 0);
847 int sy = SY; // + (EVEN(SCR_FIELDY) ? TILEY_VAR / 2 : 0);
850 int dx_var = dx * TILESIZE_VAR / TILESIZE;
851 int dy_var = dy * TILESIZE_VAR / TILESIZE;
853 int fx = FX, fy = FY;
855 int scr_fieldx = SCR_FIELDX + (EVEN(SCR_FIELDX) ? 2 : 0);
856 int scr_fieldy = SCR_FIELDY + (EVEN(SCR_FIELDY) ? 2 : 0);
858 ffx = (scroll_x - SBX_Left) * TILEX_VAR + dx_var;
859 ffy = (scroll_y - SBY_Upper) * TILEY_VAR + dy_var;
861 if (EVEN(SCR_FIELDX))
863 if (ffx < SBX_Right * TILEX_VAR + TILEX_VAR / 2 + TILEX_VAR)
865 fx += dx_var - MIN(ffx, TILEX_VAR / 2) + TILEX_VAR;
874 fx += (dx_var > 0 ? TILEX_VAR : 0);
878 if (EVEN(SCR_FIELDY))
880 if (ffy < SBY_Lower * TILEY_VAR + TILEY_VAR / 2 + TILEY_VAR)
882 fy += dy_var - MIN(ffy, TILEY_VAR / 2) + TILEY_VAR;
891 fy += (dy_var > 0 ? TILEY_VAR : 0);
896 printf("::: %d, %d, %d, %d\n", sx, sy, SCR_FIELDX, SCR_FIELDY);
899 for (x = 0; x < scr_fieldx; x++)
900 for (y = 0 ; y < scr_fieldy; y++)
901 if (redraw[redraw_x1 + x][redraw_y1 + y])
902 BlitBitmap(buffer, window,
903 FX + x * TILEX_VAR, FY + y * TILEY_VAR,
904 TILEX_VAR, TILEY_VAR,
905 sx + x * TILEX_VAR, sy + y * TILEY_VAR);
908 InitGfxClipRegion(FALSE, -1, -1, -1, -1);
910 for (x = 0; x < SCR_FIELDX; x++)
911 for (y = 0 ; y < SCR_FIELDY; y++)
912 if (redraw[redraw_x1 + x][redraw_y1 + y])
913 BlitBitmap(buffer, window,
914 FX + x * TILEX_VAR, FY + y * TILEY_VAR,
915 TILEX_VAR, TILEY_VAR,
916 SX + x * TILEX_VAR, SY + y * TILEY_VAR);
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, FY + y * TILEY, TILEX, TILEY,
925 SX + x * TILEX, SY + y * TILEY);
929 if (redraw_mask & REDRAW_FPS) /* display frames per second */
934 sprintf(info1, " (only every %d. frame)", global.fps_slowdown_factor);
935 if (!global.fps_slowdown)
938 sprintf(text, "%04.1f fps%s", global.frames_per_second, info1);
940 DrawTextExt(window, SX + SXSIZE + SX, 0, text, FONT_TEXT_2, BLIT_OPAQUE);
942 DrawTextExt(window, SX, SY, text, FONT_TEXT_2, BLIT_OPAQUE);
948 for (x = 0; x < MAX_BUF_XSIZE; x++)
949 for (y = 0; y < MAX_BUF_YSIZE; y++)
952 redraw_mask = REDRAW_NONE;
955 static void FadeCrossSaveBackbuffer()
957 BlitBitmap(backbuffer, bitmap_db_cross, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
960 static void FadeExt(int fade_mask, int fade_mode, int fade_type)
962 static int fade_type_skip = FADE_TYPE_NONE;
963 void (*draw_border_function)(void) = NULL;
964 Bitmap *bitmap = (fade_mode & FADE_TYPE_TRANSFORM ? bitmap_db_cross : NULL);
965 int x, y, width, height;
966 int fade_delay, post_delay;
968 if (fade_type == FADE_TYPE_FADE_OUT)
970 if (fade_type_skip != FADE_TYPE_NONE)
973 printf("::: skipping %d ... [%d] (X)\n", fade_mode, fade_type_skip);
976 /* skip all fade operations until specified fade operation */
977 if (fade_type & fade_type_skip)
978 fade_type_skip = FADE_TYPE_NONE;
983 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
985 FadeCrossSaveBackbuffer();
991 redraw_mask |= fade_mask;
993 if (fade_type == FADE_TYPE_SKIP)
996 printf("::: will skip %d ... [%d]\n", fade_mode, fade_type_skip);
999 fade_type_skip = fade_mode;
1005 printf("::: !!! FADING %d ... [%d] [%d]\n", fade_mode, fade_type,
1010 fade_delay = fading.fade_delay;
1011 post_delay = (fade_mode == FADE_MODE_FADE_OUT ? fading.post_delay : 0);
1014 if (fade_type_skip != FADE_TYPE_NONE)
1017 printf("::: skipping %d ... [%d]\n", fade_mode, fade_type_skip);
1020 /* skip all fade operations until specified fade operation */
1021 if (fade_type & fade_type_skip)
1022 fade_type_skip = FADE_TYPE_NONE;
1032 if (global.autoplay_leveldir)
1034 // fading.fade_mode = FADE_MODE_NONE;
1041 if (fading.fade_mode == FADE_MODE_NONE)
1049 /* !!! what about fade_mask == REDRAW_FIELD | REDRAW_ALL ??? !!! */
1052 printf("::: NOW FADING %d ... [%d]\n", fade_mode, fade_type);
1056 if (fade_mask == REDRAW_NONE)
1057 fade_mask = REDRAW_FIELD;
1060 // if (fade_mask & REDRAW_FIELD)
1061 if (fade_mask == REDRAW_FIELD)
1065 width = FULL_SXSIZE;
1066 height = FULL_SYSIZE;
1069 fade_delay = fading.fade_delay;
1070 post_delay = (fade_mode == FADE_MODE_FADE_OUT ? fading.post_delay : 0);
1073 if (border.draw_masked_when_fading)
1074 draw_border_function = DrawMaskedBorder_FIELD; /* update when fading */
1076 DrawMaskedBorder_FIELD(); /* draw once */
1078 else /* REDRAW_ALL */
1086 fade_delay = fading.fade_delay;
1087 post_delay = (fade_mode == FADE_MODE_FADE_OUT ? fading.post_delay : 0);
1092 if (!setup.fade_screens ||
1094 fading.fade_mode == FADE_MODE_NONE)
1096 if (!setup.fade_screens || fade_delay == 0)
1099 if (fade_mode == FADE_MODE_FADE_OUT)
1103 if (fade_mode == FADE_MODE_FADE_OUT &&
1104 fading.fade_mode != FADE_MODE_NONE)
1105 ClearRectangle(backbuffer, x, y, width, height);
1111 BlitBitmap(backbuffer, window, x, y, width, height, x, y);
1113 redraw_mask &= ~fade_mask;
1115 /* always redraw area that was explicitly marked to fade */
1116 redraw_mask |= fade_mask;
1124 BlitBitmap(backbuffer, window, x, y, width, height, x, y);
1125 redraw_mask = REDRAW_NONE;
1126 // (^^^ WRONG; should be "redraw_mask &= ~fade_mask" if done this way)
1135 FadeRectangle(bitmap, x, y, width, height, fade_mode, fade_delay, post_delay,
1136 draw_border_function);
1138 redraw_mask &= ~fade_mask;
1141 void FadeIn(int fade_mask)
1143 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
1144 FadeExt(fade_mask, fading.fade_mode, FADE_TYPE_FADE_IN);
1146 FadeExt(fade_mask, FADE_MODE_FADE_IN, FADE_TYPE_FADE_IN);
1149 void FadeOut(int fade_mask)
1151 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
1152 FadeExt(fade_mask, fading.fade_mode, FADE_TYPE_FADE_OUT);
1154 FadeExt(fade_mask, FADE_MODE_FADE_OUT, FADE_TYPE_FADE_OUT);
1156 global.border_status = game_status;
1159 static void FadeSetLeaveNext(struct TitleFadingInfo fading_leave, boolean set)
1161 static struct TitleFadingInfo fading_leave_stored;
1164 fading_leave_stored = fading_leave;
1166 fading = fading_leave_stored;
1169 void FadeSetEnterMenu()
1171 fading = menu.enter_menu;
1174 printf("::: storing enter_menu\n");
1177 FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
1180 void FadeSetLeaveMenu()
1182 fading = menu.leave_menu;
1185 printf("::: storing leave_menu\n");
1188 FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
1191 void FadeSetEnterScreen()
1193 fading = menu.enter_screen[game_status];
1196 printf("::: storing leave_screen[%d]\n", game_status);
1199 FadeSetLeaveNext(menu.leave_screen[game_status], TRUE); /* store */
1202 void FadeSetNextScreen()
1204 fading = menu.next_screen;
1207 printf("::: storing next_screen\n");
1210 // (do not overwrite fade mode set by FadeSetEnterScreen)
1211 // FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
1214 void FadeSetLeaveScreen()
1217 printf("::: recalling last stored value\n");
1220 FadeSetLeaveNext(menu.leave_screen[game_status], FALSE); /* recall */
1223 void FadeSetFromType(int type)
1225 if (type & TYPE_ENTER_SCREEN)
1226 FadeSetEnterScreen();
1227 else if (type & TYPE_ENTER)
1229 else if (type & TYPE_LEAVE)
1233 void FadeSetDisabled()
1235 static struct TitleFadingInfo fading_none = { FADE_MODE_NONE, -1, -1, -1 };
1237 fading = fading_none;
1240 void FadeSkipNextFadeIn()
1242 FadeExt(0, FADE_MODE_SKIP_FADE_IN, FADE_TYPE_SKIP);
1245 void FadeSkipNextFadeOut()
1247 FadeExt(0, FADE_MODE_SKIP_FADE_OUT, FADE_TYPE_SKIP);
1250 void SetWindowBackgroundImageIfDefined(int graphic)
1252 if (graphic_info[graphic].bitmap)
1253 SetWindowBackgroundBitmap(graphic_info[graphic].bitmap);
1256 void SetMainBackgroundImageIfDefined(int graphic)
1258 if (graphic_info[graphic].bitmap)
1259 SetMainBackgroundBitmap(graphic_info[graphic].bitmap);
1262 void SetDoorBackgroundImageIfDefined(int graphic)
1264 if (graphic_info[graphic].bitmap)
1265 SetDoorBackgroundBitmap(graphic_info[graphic].bitmap);
1268 void SetWindowBackgroundImage(int graphic)
1270 SetWindowBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
1271 graphic_info[graphic].bitmap ?
1272 graphic_info[graphic].bitmap :
1273 graphic_info[IMG_BACKGROUND].bitmap);
1276 void SetMainBackgroundImage(int graphic)
1278 SetMainBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
1279 graphic_info[graphic].bitmap ?
1280 graphic_info[graphic].bitmap :
1281 graphic_info[IMG_BACKGROUND].bitmap);
1284 void SetDoorBackgroundImage(int graphic)
1286 SetDoorBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
1287 graphic_info[graphic].bitmap ?
1288 graphic_info[graphic].bitmap :
1289 graphic_info[IMG_BACKGROUND].bitmap);
1292 void SetPanelBackground()
1295 struct GraphicInfo *gfx = &graphic_info[IMG_BACKGROUND_PANEL];
1298 BlitBitmapTiled(gfx->bitmap, bitmap_db_panel, gfx->src_x, gfx->src_y,
1299 gfx->width, gfx->height, 0, 0, DXSIZE, DYSIZE);
1301 /* (ClearRectangle() only needed if panel bitmap is smaller than panel) */
1302 ClearRectangle(bitmap_db_panel, DX, DY, DXSIZE, DYSIZE);
1303 BlitBitmap(gfx->bitmap, bitmap_db_panel, gfx->src_x, gfx->src_y,
1304 MIN(gfx->width, DXSIZE), MIN(gfx->height, DYSIZE), 0, 0);
1307 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, bitmap_db_panel,
1308 DOOR_GFX_PAGEX5, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE, 0, 0);
1311 SetDoorBackgroundBitmap(bitmap_db_panel);
1314 void DrawBackground(int x, int y, int width, int height)
1316 /* !!! "drawto" might still point to playfield buffer here (see below) !!! */
1317 /* (when entering hall of fame after playing) */
1319 ClearRectangleOnBackground(drawto, x, y, width, height);
1321 ClearRectangleOnBackground(backbuffer, x, y, width, height);
1327 if (IN_GFX_FIELD_FULL(x, y))
1328 redraw_mask |= REDRAW_FIELD;
1329 else if (IN_GFX_DOOR_1(x, y))
1330 redraw_mask |= REDRAW_DOOR_1;
1331 else if (IN_GFX_DOOR_2(x, y))
1332 redraw_mask |= REDRAW_DOOR_2;
1333 else if (IN_GFX_DOOR_3(x, y))
1334 redraw_mask |= REDRAW_DOOR_3;
1336 /* (this only works for the current arrangement of playfield and panels) */
1338 redraw_mask |= REDRAW_FIELD;
1339 else if (y < gfx.vy)
1340 redraw_mask |= REDRAW_DOOR_1;
1342 redraw_mask |= REDRAW_DOOR_2;
1346 /* (this is just wrong (when drawing to one of the two door panel areas)) */
1347 redraw_mask |= REDRAW_FIELD;
1351 void DrawBackgroundForFont(int x, int y, int width, int height, int font_nr)
1353 struct FontBitmapInfo *font = getFontBitmapInfo(font_nr);
1355 if (font->bitmap == NULL)
1358 DrawBackground(x, y, width, height);
1361 void DrawBackgroundForGraphic(int x, int y, int width, int height, int graphic)
1363 struct GraphicInfo *g = &graphic_info[graphic];
1365 if (g->bitmap == NULL)
1368 DrawBackground(x, y, width, height);
1373 /* !!! "drawto" might still point to playfield buffer here (see above) !!! */
1374 /* (when entering hall of fame after playing) */
1375 DrawBackground(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
1377 /* !!! maybe this should be done before clearing the background !!! */
1378 if (setup.soft_scrolling && game_status == GAME_MODE_PLAYING)
1380 ClearRectangle(fieldbuffer, 0, 0, FXSIZE, FYSIZE);
1381 SetDrawtoField(DRAW_BUFFERED);
1384 SetDrawtoField(DRAW_BACKBUFFER);
1387 void MarkTileDirty(int x, int y)
1389 int xx = redraw_x1 + x;
1390 int yy = redraw_y1 + y;
1392 if (!redraw[xx][yy])
1395 redraw[xx][yy] = TRUE;
1396 redraw_mask |= REDRAW_TILES;
1399 void SetBorderElement()
1403 BorderElement = EL_EMPTY;
1405 for (y = 0; y < lev_fieldy && BorderElement == EL_EMPTY; y++)
1407 for (x = 0; x < lev_fieldx; x++)
1409 if (!IS_INDESTRUCTIBLE(Feld[x][y]))
1410 BorderElement = EL_STEELWALL;
1412 if (y != 0 && y != lev_fieldy - 1 && x != lev_fieldx - 1)
1418 void FloodFillLevel(int from_x, int from_y, int fill_element,
1419 short field[MAX_LEV_FIELDX][MAX_LEV_FIELDY],
1420 int max_fieldx, int max_fieldy)
1424 static int check[4][2] = { { -1, 0 }, { 0, -1 }, { 1, 0 }, { 0, 1 } };
1425 static int safety = 0;
1427 /* check if starting field still has the desired content */
1428 if (field[from_x][from_y] == fill_element)
1433 if (safety > max_fieldx * max_fieldy)
1434 Error(ERR_EXIT, "Something went wrong in 'FloodFill()'. Please debug.");
1436 old_element = field[from_x][from_y];
1437 field[from_x][from_y] = fill_element;
1439 for (i = 0; i < 4; i++)
1441 x = from_x + check[i][0];
1442 y = from_y + check[i][1];
1444 if (IN_FIELD(x, y, max_fieldx, max_fieldy) && field[x][y] == old_element)
1445 FloodFillLevel(x, y, fill_element, field, max_fieldx, max_fieldy);
1451 void SetRandomAnimationValue(int x, int y)
1453 gfx.anim_random_frame = GfxRandom[x][y];
1456 inline int getGraphicAnimationFrame(int graphic, int sync_frame)
1458 /* animation synchronized with global frame counter, not move position */
1459 if (graphic_info[graphic].anim_global_sync || sync_frame < 0)
1460 sync_frame = FrameCounter;
1462 return getAnimationFrame(graphic_info[graphic].anim_frames,
1463 graphic_info[graphic].anim_delay,
1464 graphic_info[graphic].anim_mode,
1465 graphic_info[graphic].anim_start_frame,
1469 void getSizedGraphicSourceExt(int graphic, int frame, int tilesize_raw,
1470 Bitmap **bitmap, int *x, int *y,
1471 boolean get_backside)
1475 int width_mult, width_div;
1476 int height_mult, height_div;
1480 { 15, 16, 2, 3 }, /* 1 x 1 */
1481 { 7, 8, 2, 3 }, /* 2 x 2 */
1482 { 3, 4, 2, 3 }, /* 4 x 4 */
1483 { 1, 2, 2, 3 }, /* 8 x 8 */
1484 { 0, 1, 2, 3 }, /* 16 x 16 */
1485 { 0, 1, 0, 1 }, /* 32 x 32 */
1487 struct GraphicInfo *g = &graphic_info[graphic];
1488 Bitmap *src_bitmap = g->bitmap;
1489 int tilesize = MIN(MAX(1, tilesize_raw), TILESIZE);
1490 int offset_calc_pos = log_2(tilesize);
1491 int width_mult = offset_calc[offset_calc_pos].width_mult;
1492 int width_div = offset_calc[offset_calc_pos].width_div;
1493 int height_mult = offset_calc[offset_calc_pos].height_mult;
1494 int height_div = offset_calc[offset_calc_pos].height_div;
1495 int startx = src_bitmap->width * width_mult / width_div;
1496 int starty = src_bitmap->height * height_mult / height_div;
1498 int src_x = (g->src_x + (get_backside ? g->offset2_x : 0)) *
1499 tilesize / TILESIZE;
1500 int src_y = (g->src_y + (get_backside ? g->offset2_y : 0)) *
1501 tilesize / TILESIZE;
1503 int src_x = g->src_x * tilesize / TILESIZE;
1504 int src_y = g->src_y * tilesize / TILESIZE;
1506 int width = g->width * tilesize / TILESIZE;
1507 int height = g->height * tilesize / TILESIZE;
1508 int offset_x = g->offset_x * tilesize / TILESIZE;
1509 int offset_y = g->offset_y * tilesize / TILESIZE;
1511 if (g->offset_y == 0) /* frames are ordered horizontally */
1513 int max_width = g->anim_frames_per_line * width;
1514 int pos = (src_y / height) * max_width + src_x + frame * offset_x;
1516 src_x = pos % max_width;
1517 src_y = src_y % height + pos / max_width * height;
1519 else if (g->offset_x == 0) /* frames are ordered vertically */
1521 int max_height = g->anim_frames_per_line * height;
1522 int pos = (src_x / width) * max_height + src_y + frame * offset_y;
1524 src_x = src_x % width + pos / max_height * width;
1525 src_y = pos % max_height;
1527 else /* frames are ordered diagonally */
1529 src_x = src_x + frame * offset_x;
1530 src_y = src_y + frame * offset_y;
1533 *bitmap = src_bitmap;
1534 *x = startx + src_x;
1535 *y = starty + src_y;
1538 void getFixedGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
1539 int *x, int *y, boolean get_backside)
1541 getSizedGraphicSourceExt(graphic, frame, TILESIZE, bitmap, x, y,
1545 void getSizedGraphicSource(int graphic, int frame, int tilesize_raw,
1546 Bitmap **bitmap, int *x, int *y)
1548 getSizedGraphicSourceExt(graphic, frame, tilesize_raw, bitmap, x, y, FALSE);
1551 void getFixedGraphicSource(int graphic, int frame,
1552 Bitmap **bitmap, int *x, int *y)
1554 getSizedGraphicSourceExt(graphic, frame, TILESIZE, bitmap, x, y, FALSE);
1557 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
1560 getSizedGraphicSource(graphic, 0, MINI_TILESIZE, bitmap, x, y);
1562 struct GraphicInfo *g = &graphic_info[graphic];
1563 int mini_startx = 0;
1564 int mini_starty = g->bitmap->height * 2 / 3;
1566 *bitmap = g->bitmap;
1567 *x = mini_startx + g->src_x / 2;
1568 *y = mini_starty + g->src_y / 2;
1572 inline void getGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
1573 int *x, int *y, boolean get_backside)
1575 struct GraphicInfo *g = &graphic_info[graphic];
1576 int src_x = g->src_x + (get_backside ? g->offset2_x : 0);
1577 int src_y = g->src_y + (get_backside ? g->offset2_y : 0);
1580 if (TILESIZE_VAR != TILESIZE)
1581 return getSizedGraphicSourceExt(graphic, frame, TILESIZE_VAR, bitmap, x, y,
1585 *bitmap = g->bitmap;
1587 if (g->offset_y == 0) /* frames are ordered horizontally */
1589 int max_width = g->anim_frames_per_line * g->width;
1590 int pos = (src_y / g->height) * max_width + src_x + frame * g->offset_x;
1592 *x = pos % max_width;
1593 *y = src_y % g->height + pos / max_width * g->height;
1595 else if (g->offset_x == 0) /* frames are ordered vertically */
1597 int max_height = g->anim_frames_per_line * g->height;
1598 int pos = (src_x / g->width) * max_height + src_y + frame * g->offset_y;
1600 *x = src_x % g->width + pos / max_height * g->width;
1601 *y = pos % max_height;
1603 else /* frames are ordered diagonally */
1605 *x = src_x + frame * g->offset_x;
1606 *y = src_y + frame * g->offset_y;
1610 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
1612 getGraphicSourceExt(graphic, frame, bitmap, x, y, FALSE);
1615 void DrawGraphic(int x, int y, int graphic, int frame)
1618 if (!IN_SCR_FIELD(x, y))
1620 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
1621 printf("DrawGraphic(): This should never happen!\n");
1627 DrawGraphicExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR, graphic,
1630 DrawGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic, frame);
1632 MarkTileDirty(x, y);
1635 void DrawFixedGraphic(int x, int y, int graphic, int frame)
1638 if (!IN_SCR_FIELD(x, y))
1640 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
1641 printf("DrawGraphic(): This should never happen!\n");
1646 DrawFixedGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic,
1648 MarkTileDirty(x, y);
1651 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
1657 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1659 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX_VAR, TILEY_VAR, x, y);
1661 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
1665 void DrawFixedGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
1671 getFixedGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1672 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
1675 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
1678 if (!IN_SCR_FIELD(x, y))
1680 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
1681 printf("DrawGraphicThruMask(): This should never happen!\n");
1687 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR,
1690 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic,
1693 MarkTileDirty(x, y);
1696 void DrawFixedGraphicThruMask(int x, int y, int graphic, int frame)
1699 if (!IN_SCR_FIELD(x, y))
1701 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
1702 printf("DrawGraphicThruMask(): This should never happen!\n");
1707 DrawFixedGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
1709 MarkTileDirty(x, y);
1712 void DrawGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y, int graphic,
1718 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1720 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1721 dst_x - src_x, dst_y - src_y);
1723 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX_VAR, TILEY_VAR,
1726 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dst_x, dst_y);
1730 void DrawFixedGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y,
1731 int graphic, int frame)
1736 getFixedGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1738 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1739 dst_x - src_x, dst_y - src_y);
1740 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dst_x, dst_y);
1743 void DrawSizedGraphic(int x, int y, int graphic, int frame, int tilesize)
1745 DrawSizedGraphicExt(drawto, SX + x * tilesize, SY + y * tilesize, graphic,
1747 MarkTileDirty(x / tilesize, y / tilesize);
1750 void DrawSizedGraphicExt(DrawBuffer *d, int x, int y, int graphic, int frame,
1756 getSizedGraphicSource(graphic, frame, tilesize, &src_bitmap, &src_x, &src_y);
1757 BlitBitmap(src_bitmap, d, src_x, src_y, tilesize, tilesize, x, y);
1760 void DrawMiniGraphic(int x, int y, int graphic)
1762 DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
1763 MarkTileDirty(x / 2, y / 2);
1766 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
1771 getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1772 BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
1775 inline static void DrawGraphicShiftedNormal(int x, int y, int dx, int dy,
1776 int graphic, int frame,
1777 int cut_mode, int mask_mode)
1782 int width = TILEX, height = TILEY;
1785 if (dx || dy) /* shifted graphic */
1787 if (x < BX1) /* object enters playfield from the left */
1794 else if (x > BX2) /* object enters playfield from the right */
1800 else if (x==BX1 && dx < 0) /* object leaves playfield to the left */
1806 else if (x==BX2 && dx > 0) /* object leaves playfield to the right */
1808 else if (dx) /* general horizontal movement */
1809 MarkTileDirty(x + SIGN(dx), y);
1811 if (y < BY1) /* object enters playfield from the top */
1813 if (cut_mode==CUT_BELOW) /* object completely above top border */
1821 else if (y > BY2) /* object enters playfield from the bottom */
1827 else if (y==BY1 && dy < 0) /* object leaves playfield to the top */
1833 else if (dy > 0 && cut_mode == CUT_ABOVE)
1835 if (y == BY2) /* object completely above bottom border */
1841 MarkTileDirty(x, y + 1);
1842 } /* object leaves playfield to the bottom */
1843 else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
1845 else if (dy) /* general vertical movement */
1846 MarkTileDirty(x, y + SIGN(dy));
1850 if (!IN_SCR_FIELD(x, y))
1852 printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
1853 printf("DrawGraphicShifted(): This should never happen!\n");
1859 width = width * TILESIZE_VAR / TILESIZE;
1860 height = height * TILESIZE_VAR / TILESIZE;
1861 cx = cx * TILESIZE_VAR / TILESIZE;
1862 cy = cy * TILESIZE_VAR / TILESIZE;
1863 dx = dx * TILESIZE_VAR / TILESIZE;
1864 dy = dy * TILESIZE_VAR / TILESIZE;
1867 if (width > 0 && height > 0)
1869 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1875 dst_x = FX + x * TILEX_VAR + dx;
1876 dst_y = FY + y * TILEY_VAR + dy;
1878 dst_x = FX + x * TILEX + dx;
1879 dst_y = FY + y * TILEY + dy;
1882 if (mask_mode == USE_MASKING)
1884 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1885 dst_x - src_x, dst_y - src_y);
1886 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1890 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1893 MarkTileDirty(x, y);
1897 inline static void DrawGraphicShiftedDouble(int x, int y, int dx, int dy,
1898 int graphic, int frame,
1899 int cut_mode, int mask_mode)
1905 int width = TILEX_VAR, height = TILEY_VAR;
1907 int width = TILEX, height = TILEY;
1911 int x2 = x + SIGN(dx);
1912 int y2 = y + SIGN(dy);
1914 /* !!! DOES NOT WORK FOR SLOW MOVEMENT !!! */
1915 int sync_frame = GfxFrame[LEVELX(x)][LEVELY(y)];
1917 /* movement with two-tile animations must be sync'ed with movement position,
1918 not with current GfxFrame (which can be higher when using slow movement) */
1919 int anim_pos = (dx ? ABS(dx) : ABS(dy));
1920 int anim_frames = graphic_info[graphic].anim_frames;
1922 /* (we also need anim_delay here for movement animations with less frames) */
1923 int anim_delay = graphic_info[graphic].anim_delay;
1924 int sync_frame = anim_pos * anim_frames * anim_delay / TILESIZE;
1926 int sync_frame = anim_pos * anim_frames / TILESIZE;
1929 boolean draw_start_tile = (cut_mode != CUT_ABOVE); /* only for falling! */
1930 boolean draw_end_tile = (cut_mode != CUT_BELOW); /* only for falling! */
1932 /* re-calculate animation frame for two-tile movement animation */
1933 frame = getGraphicAnimationFrame(graphic, sync_frame);
1937 printf("::: %d, %d, %d => %d [%d]\n",
1938 anim_pos, anim_frames, anim_delay, sync_frame, graphic);
1940 printf("::: %d, %d => %d\n",
1941 anim_pos, anim_frames, sync_frame);
1946 printf("::: %d [%d, %d] [%d] [%d]\n", frame, sync_frame, dy,
1947 GfxFrame[LEVELX(x)][LEVELY(y)], mask_mode);
1950 /* check if movement start graphic inside screen area and should be drawn */
1951 if (draw_start_tile && IN_SCR_FIELD(x1, y1))
1953 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, TRUE);
1956 dst_x = FX + x1 * TILEX_VAR;
1957 dst_y = FY + y1 * TILEY_VAR;
1959 dst_x = FX + x1 * TILEX;
1960 dst_y = FY + y1 * TILEY;
1963 if (mask_mode == USE_MASKING)
1965 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1966 dst_x - src_x, dst_y - src_y);
1967 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1971 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1974 MarkTileDirty(x1, y1);
1977 /* check if movement end graphic inside screen area and should be drawn */
1978 if (draw_end_tile && IN_SCR_FIELD(x2, y2))
1980 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
1983 dst_x = FX + x2 * TILEX_VAR;
1984 dst_y = FY + y2 * TILEY_VAR;
1986 dst_x = FX + x2 * TILEX;
1987 dst_y = FY + y2 * TILEY;
1990 if (mask_mode == USE_MASKING)
1992 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1993 dst_x - src_x, dst_y - src_y);
1994 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1998 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
2001 MarkTileDirty(x2, y2);
2005 static void DrawGraphicShifted(int x, int y, int dx, int dy,
2006 int graphic, int frame,
2007 int cut_mode, int mask_mode)
2011 DrawGraphic(x, y, graphic, frame);
2016 if (graphic_info[graphic].double_movement) /* EM style movement images */
2017 DrawGraphicShiftedDouble(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
2019 DrawGraphicShiftedNormal(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
2022 void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
2023 int frame, int cut_mode)
2025 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, USE_MASKING);
2028 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
2029 int cut_mode, int mask_mode)
2031 int lx = LEVELX(x), ly = LEVELY(y);
2035 if (IN_LEV_FIELD(lx, ly))
2037 SetRandomAnimationValue(lx, ly);
2039 graphic = el_act_dir2img(element, GfxAction[lx][ly], GfxDir[lx][ly]);
2040 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
2042 /* do not use double (EM style) movement graphic when not moving */
2043 if (graphic_info[graphic].double_movement && !dx && !dy)
2045 graphic = el_act_dir2img(element, ACTION_DEFAULT, GfxDir[lx][ly]);
2046 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
2049 else /* border element */
2051 graphic = el2img(element);
2052 frame = getGraphicAnimationFrame(graphic, -1);
2055 if (element == EL_EXPANDABLE_WALL)
2057 boolean left_stopped = FALSE, right_stopped = FALSE;
2059 if (!IN_LEV_FIELD(lx - 1, ly) || IS_WALL(Feld[lx - 1][ly]))
2060 left_stopped = TRUE;
2061 if (!IN_LEV_FIELD(lx + 1, ly) || IS_WALL(Feld[lx + 1][ly]))
2062 right_stopped = TRUE;
2064 if (left_stopped && right_stopped)
2066 else if (left_stopped)
2068 graphic = IMG_EXPANDABLE_WALL_GROWING_RIGHT;
2069 frame = graphic_info[graphic].anim_frames - 1;
2071 else if (right_stopped)
2073 graphic = IMG_EXPANDABLE_WALL_GROWING_LEFT;
2074 frame = graphic_info[graphic].anim_frames - 1;
2079 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
2080 else if (mask_mode == USE_MASKING)
2081 DrawGraphicThruMask(x, y, graphic, frame);
2083 DrawGraphic(x, y, graphic, frame);
2086 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
2087 int cut_mode, int mask_mode)
2089 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
2090 DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
2091 cut_mode, mask_mode);
2094 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
2097 DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
2100 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
2103 DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
2106 void DrawLevelElementThruMask(int x, int y, int element)
2108 DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
2111 void DrawLevelFieldThruMask(int x, int y)
2113 DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
2116 /* !!! implementation of quicksand is totally broken !!! */
2117 #define IS_CRUMBLED_TILE(x, y, e) \
2118 (GFX_CRUMBLED(e) && (!IN_LEV_FIELD(x, y) || \
2119 !IS_MOVING(x, y) || \
2120 (e) == EL_QUICKSAND_EMPTYING || \
2121 (e) == EL_QUICKSAND_FAST_EMPTYING))
2123 static void DrawLevelFieldCrumbledInnerCorners(int x, int y, int dx, int dy,
2128 int width, height, cx, cy;
2129 int sx = SCREENX(x), sy = SCREENY(y);
2130 int crumbled_border_size = graphic_info[graphic].border_size;
2133 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
2135 for (i = 1; i < 4; i++)
2137 int dxx = (i & 1 ? dx : 0);
2138 int dyy = (i & 2 ? dy : 0);
2141 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
2144 /* check if neighbour field is of same crumble type */
2145 boolean same = (IS_CRUMBLED_TILE(xx, yy, element) &&
2146 graphic_info[graphic].class ==
2147 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class);
2149 /* return if check prevents inner corner */
2150 if (same == (dxx == dx && dyy == dy))
2154 /* if we reach this point, we have an inner corner */
2156 getGraphicSource(graphic, 1, &src_bitmap, &src_x, &src_y);
2159 width = crumbled_border_size * TILESIZE_VAR / TILESIZE;
2160 height = crumbled_border_size * TILESIZE_VAR / TILESIZE;
2161 cx = (dx > 0 ? TILEX - crumbled_border_size : 0) * TILESIZE_VAR / TILESIZE;
2162 cy = (dy > 0 ? TILEY - crumbled_border_size : 0) * TILESIZE_VAR / TILESIZE;
2164 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
2165 width, height, FX + sx * TILEX_VAR + cx, FY + sy * TILEY_VAR + cy);
2167 width = crumbled_border_size;
2168 height = crumbled_border_size;
2169 cx = (dx > 0 ? TILEX - crumbled_border_size : 0);
2170 cy = (dy > 0 ? TILEY - crumbled_border_size : 0);
2172 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
2173 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
2177 static void DrawLevelFieldCrumbledBorders(int x, int y, int graphic, int frame,
2182 int width, height, bx, by, cx, cy;
2183 int sx = SCREENX(x), sy = SCREENY(y);
2184 int crumbled_border_size = graphic_info[graphic].border_size;
2187 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
2189 /* draw simple, sloppy, non-corner-accurate crumbled border */
2192 width = (dir == 1 || dir == 2 ? crumbled_border_size : TILEX);
2193 height = (dir == 0 || dir == 3 ? crumbled_border_size : TILEY);
2194 cx = (dir == 2 ? TILEX - crumbled_border_size : 0);
2195 cy = (dir == 3 ? TILEY - crumbled_border_size : 0);
2197 if (dir == 1 || dir == 2) /* left or right crumbled border */
2199 width = crumbled_border_size;
2201 cx = (dir == 2 ? TILEX - crumbled_border_size : 0);
2204 else /* top or bottom crumbled border */
2207 height = crumbled_border_size;
2209 cy = (dir == 3 ? TILEY - crumbled_border_size : 0);
2214 BlitBitmap(src_bitmap, drawto_field,
2215 src_x + cx * TILESIZE_VAR / TILESIZE,
2216 src_y + cy * TILESIZE_VAR / TILESIZE,
2217 width * TILESIZE_VAR / TILESIZE,
2218 height * TILESIZE_VAR / TILESIZE,
2219 FX + sx * TILEX_VAR + cx * TILESIZE_VAR / TILESIZE,
2220 FY + sy * TILEY_VAR + cy * TILESIZE_VAR / TILESIZE);
2222 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
2223 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
2226 /* (remaining middle border part must be at least as big as corner part) */
2227 if (!(graphic_info[graphic].style & STYLE_ACCURATE_BORDERS) ||
2228 crumbled_border_size >= TILESIZE / 3)
2231 /* correct corners of crumbled border, if needed */
2234 for (i = -1; i <= 1; i+=2)
2236 int xx = x + (dir == 0 || dir == 3 ? i : 0);
2237 int yy = y + (dir == 1 || dir == 2 ? i : 0);
2238 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
2241 /* check if neighbour field is of same crumble type */
2242 if (IS_CRUMBLED_TILE(xx, yy, element) &&
2243 graphic_info[graphic].class ==
2244 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
2246 /* no crumbled corner, but continued crumbled border */
2248 int c1 = (dir == 2 || dir == 3 ? TILESIZE - crumbled_border_size : 0);
2249 int c2 = (i == 1 ? TILESIZE - crumbled_border_size : 0);
2250 int b1 = (i == 1 ? crumbled_border_size :
2251 TILESIZE - 2 * crumbled_border_size);
2253 width = crumbled_border_size;
2254 height = crumbled_border_size;
2256 if (dir == 1 || dir == 2)
2272 BlitBitmap(src_bitmap, drawto_field,
2273 src_x + bx * TILESIZE_VAR / TILESIZE,
2274 src_y + by * TILESIZE_VAR / TILESIZE,
2275 width * TILESIZE_VAR / TILESIZE,
2276 height * TILESIZE_VAR / TILESIZE,
2277 FX + sx * TILEX_VAR + cx * TILESIZE_VAR / TILESIZE,
2278 FY + sy * TILEY_VAR + cy * TILESIZE_VAR / TILESIZE);
2280 BlitBitmap(src_bitmap, drawto_field, src_x + bx, src_y + by,
2281 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
2286 if (dir == 1 || dir == 2) /* left or right crumbled border */
2288 for (i = -1; i <= 1; i+=2)
2292 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
2295 /* check if neighbour field is of same crumble type */
2296 if (IS_CRUMBLED_TILE(xx, yy, element) &&
2297 graphic_info[graphic].class ==
2298 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
2300 /* no crumbled corner, but continued crumbled border */
2302 width = crumbled_border_size;
2303 height = crumbled_border_size;
2304 cx = (dir == 2 ? TILEX - crumbled_border_size : 0);
2305 cy = (i == 1 ? TILEY - crumbled_border_size : 0);
2307 by = (i == 1 ? crumbled_border_size :
2308 TILEY - 2 * crumbled_border_size);
2310 BlitBitmap(src_bitmap, drawto_field, src_x + bx, src_y + by,
2311 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
2315 else /* top or bottom crumbled border */
2317 for (i = -1; i <= 1; i+=2)
2321 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
2324 /* check if neighbour field is of same crumble type */
2325 if (IS_CRUMBLED_TILE(xx, yy, element) &&
2326 graphic_info[graphic].class ==
2327 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
2329 /* no crumbled corner, but continued crumbled border */
2331 width = crumbled_border_size;
2332 height = crumbled_border_size;
2333 cx = (i == 1 ? TILEX - crumbled_border_size : 0);
2334 cy = (dir == 3 ? TILEY - crumbled_border_size : 0);
2335 bx = (i == 1 ? crumbled_border_size :
2336 TILEX - 2 * crumbled_border_size);
2339 BlitBitmap(src_bitmap, drawto_field, src_x + bx, src_y + by,
2340 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
2347 static void DrawLevelFieldCrumbledExt(int x, int y, int graphic, int frame)
2349 int sx = SCREENX(x), sy = SCREENY(y);
2352 static int xy[4][2] =
2360 if (!IN_LEV_FIELD(x, y))
2363 element = TILE_GFX_ELEMENT(x, y);
2365 /* crumble field itself */
2366 if (IS_CRUMBLED_TILE(x, y, element))
2368 if (!IN_SCR_FIELD(sx, sy))
2371 for (i = 0; i < 4; i++)
2373 int xx = x + xy[i][0];
2374 int yy = y + xy[i][1];
2376 element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
2379 /* check if neighbour field is of same crumble type */
2381 if (IS_CRUMBLED_TILE(xx, yy, element) &&
2382 graphic_info[graphic].class ==
2383 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
2386 if (IS_CRUMBLED_TILE(xx, yy, element))
2390 DrawLevelFieldCrumbledBorders(x, y, graphic, frame, i);
2393 if ((graphic_info[graphic].style & STYLE_INNER_CORNERS) &&
2394 graphic_info[graphic].anim_frames == 2)
2396 for (i = 0; i < 4; i++)
2398 int dx = (i & 1 ? +1 : -1);
2399 int dy = (i & 2 ? +1 : -1);
2401 DrawLevelFieldCrumbledInnerCorners(x, y, dx, dy, graphic);
2405 MarkTileDirty(sx, sy);
2407 else /* center field not crumbled -- crumble neighbour fields */
2409 for (i = 0; i < 4; i++)
2411 int xx = x + xy[i][0];
2412 int yy = y + xy[i][1];
2413 int sxx = sx + xy[i][0];
2414 int syy = sy + xy[i][1];
2416 if (!IN_LEV_FIELD(xx, yy) ||
2417 !IN_SCR_FIELD(sxx, syy))
2420 if (Feld[xx][yy] == EL_ELEMENT_SNAPPING)
2423 element = TILE_GFX_ELEMENT(xx, yy);
2425 if (!IS_CRUMBLED_TILE(xx, yy, element))
2428 graphic = el_act2crm(element, ACTION_DEFAULT);
2430 DrawLevelFieldCrumbledBorders(xx, yy, graphic, 0, 3 - i);
2432 MarkTileDirty(sxx, syy);
2437 void DrawLevelFieldCrumbled(int x, int y)
2441 if (!IN_LEV_FIELD(x, y))
2445 /* !!! CHECK THIS !!! */
2448 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
2449 GFX_CRUMBLED(GfxElement[x][y]))
2452 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
2453 GfxElement[x][y] != EL_UNDEFINED &&
2454 GFX_CRUMBLED(GfxElement[x][y]))
2456 DrawLevelFieldCrumbledDigging(x, y, GfxDir[x][y], GfxFrame[x][y]);
2463 graphic = el_act2crm(TILE_GFX_ELEMENT(x, y), ACTION_DEFAULT);
2465 graphic = el_act2crm(Feld[x][y], ACTION_DEFAULT);
2468 DrawLevelFieldCrumbledExt(x, y, graphic, 0);
2471 void DrawLevelFieldCrumbledDigging(int x, int y, int direction,
2474 int graphic1 = el_act_dir2img(GfxElement[x][y], ACTION_DIGGING, direction);
2475 int graphic2 = el_act_dir2crm(GfxElement[x][y], ACTION_DIGGING, direction);
2476 int frame1 = getGraphicAnimationFrame(graphic1, step_frame);
2477 int frame2 = getGraphicAnimationFrame(graphic2, step_frame);
2478 int sx = SCREENX(x), sy = SCREENY(y);
2480 DrawGraphic(sx, sy, graphic1, frame1);
2481 DrawLevelFieldCrumbledExt(x, y, graphic2, frame2);
2484 void DrawLevelFieldCrumbledNeighbours(int x, int y)
2486 int sx = SCREENX(x), sy = SCREENY(y);
2487 static int xy[4][2] =
2496 for (i = 0; i < 4; i++)
2498 int xx = x + xy[i][0];
2499 int yy = y + xy[i][1];
2500 int sxx = sx + xy[i][0];
2501 int syy = sy + xy[i][1];
2503 if (!IN_LEV_FIELD(xx, yy) ||
2504 !IN_SCR_FIELD(sxx, syy) ||
2505 !GFX_CRUMBLED(Feld[xx][yy]) ||
2509 DrawLevelField(xx, yy);
2513 static int getBorderElement(int x, int y)
2517 { EL_STEELWALL_TOPLEFT, EL_INVISIBLE_STEELWALL_TOPLEFT },
2518 { EL_STEELWALL_TOPRIGHT, EL_INVISIBLE_STEELWALL_TOPRIGHT },
2519 { EL_STEELWALL_BOTTOMLEFT, EL_INVISIBLE_STEELWALL_BOTTOMLEFT },
2520 { EL_STEELWALL_BOTTOMRIGHT, EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
2521 { EL_STEELWALL_VERTICAL, EL_INVISIBLE_STEELWALL_VERTICAL },
2522 { EL_STEELWALL_HORIZONTAL, EL_INVISIBLE_STEELWALL_HORIZONTAL },
2523 { EL_STEELWALL, EL_INVISIBLE_STEELWALL }
2525 int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
2526 int steel_position = (x == -1 && y == -1 ? 0 :
2527 x == lev_fieldx && y == -1 ? 1 :
2528 x == -1 && y == lev_fieldy ? 2 :
2529 x == lev_fieldx && y == lev_fieldy ? 3 :
2530 x == -1 || x == lev_fieldx ? 4 :
2531 y == -1 || y == lev_fieldy ? 5 : 6);
2533 return border[steel_position][steel_type];
2536 void DrawScreenElement(int x, int y, int element)
2538 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
2539 DrawLevelFieldCrumbled(LEVELX(x), LEVELY(y));
2542 void DrawLevelElement(int x, int y, int element)
2544 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
2545 DrawScreenElement(SCREENX(x), SCREENY(y), element);
2548 void DrawScreenField(int x, int y)
2550 int lx = LEVELX(x), ly = LEVELY(y);
2551 int element, content;
2553 if (!IN_LEV_FIELD(lx, ly))
2555 if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
2558 element = getBorderElement(lx, ly);
2560 DrawScreenElement(x, y, element);
2565 element = Feld[lx][ly];
2566 content = Store[lx][ly];
2568 if (IS_MOVING(lx, ly))
2570 int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
2571 boolean cut_mode = NO_CUTTING;
2573 if (element == EL_QUICKSAND_EMPTYING ||
2574 element == EL_QUICKSAND_FAST_EMPTYING ||
2575 element == EL_MAGIC_WALL_EMPTYING ||
2576 element == EL_BD_MAGIC_WALL_EMPTYING ||
2577 element == EL_DC_MAGIC_WALL_EMPTYING ||
2578 element == EL_AMOEBA_DROPPING)
2579 cut_mode = CUT_ABOVE;
2580 else if (element == EL_QUICKSAND_FILLING ||
2581 element == EL_QUICKSAND_FAST_FILLING ||
2582 element == EL_MAGIC_WALL_FILLING ||
2583 element == EL_BD_MAGIC_WALL_FILLING ||
2584 element == EL_DC_MAGIC_WALL_FILLING)
2585 cut_mode = CUT_BELOW;
2588 if (lx == 9 && ly == 1)
2589 printf("::: %s [%d] [%d, %d] [%d]\n",
2590 EL_NAME(TILE_GFX_ELEMENT(lx, ly)),
2591 el_act2crm(TILE_GFX_ELEMENT(lx, ly), ACTION_DEFAULT),
2592 element_info[EL_QUICKSAND_EMPTYING].graphic[ACTION_DEFAULT],
2593 element_info[EL_QUICKSAND_EMPTYING].crumbled[ACTION_DEFAULT],
2594 GFX_CRUMBLED(TILE_GFX_ELEMENT(lx, ly)));
2597 if (cut_mode == CUT_ABOVE)
2599 DrawScreenElement(x, y, element);
2601 DrawScreenElementShifted(x, y, 0, 0, element, NO_CUTTING);
2604 DrawScreenElement(x, y, EL_EMPTY);
2607 DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
2608 else if (cut_mode == NO_CUTTING)
2609 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
2612 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
2615 if (cut_mode == CUT_BELOW &&
2616 IN_LEV_FIELD(lx, ly + 1) && IN_SCR_FIELD(x, y + 1))
2617 DrawLevelElement(lx, ly + 1, element);
2621 if (content == EL_ACID)
2623 int dir = MovDir[lx][ly];
2624 int newlx = lx + (dir == MV_LEFT ? -1 : dir == MV_RIGHT ? +1 : 0);
2625 int newly = ly + (dir == MV_UP ? -1 : dir == MV_DOWN ? +1 : 0);
2627 DrawLevelElementThruMask(newlx, newly, EL_ACID);
2630 else if (IS_BLOCKED(lx, ly))
2635 boolean cut_mode = NO_CUTTING;
2636 int element_old, content_old;
2638 Blocked2Moving(lx, ly, &oldx, &oldy);
2641 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
2642 MovDir[oldx][oldy] == MV_RIGHT);
2644 element_old = Feld[oldx][oldy];
2645 content_old = Store[oldx][oldy];
2647 if (element_old == EL_QUICKSAND_EMPTYING ||
2648 element_old == EL_QUICKSAND_FAST_EMPTYING ||
2649 element_old == EL_MAGIC_WALL_EMPTYING ||
2650 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
2651 element_old == EL_DC_MAGIC_WALL_EMPTYING ||
2652 element_old == EL_AMOEBA_DROPPING)
2653 cut_mode = CUT_ABOVE;
2655 DrawScreenElement(x, y, EL_EMPTY);
2658 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
2660 else if (cut_mode == NO_CUTTING)
2661 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
2664 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
2667 else if (IS_DRAWABLE(element))
2668 DrawScreenElement(x, y, element);
2670 DrawScreenElement(x, y, EL_EMPTY);
2673 void DrawLevelField(int x, int y)
2675 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
2676 DrawScreenField(SCREENX(x), SCREENY(y));
2677 else if (IS_MOVING(x, y))
2681 Moving2Blocked(x, y, &newx, &newy);
2682 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
2683 DrawScreenField(SCREENX(newx), SCREENY(newy));
2685 else if (IS_BLOCKED(x, y))
2689 Blocked2Moving(x, y, &oldx, &oldy);
2690 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
2691 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
2695 void DrawMiniElement(int x, int y, int element)
2699 graphic = el2edimg(element);
2700 DrawMiniGraphic(x, y, graphic);
2703 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
2705 int x = sx + scroll_x, y = sy + scroll_y;
2707 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
2708 DrawMiniElement(sx, sy, EL_EMPTY);
2709 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
2710 DrawMiniElement(sx, sy, Feld[x][y]);
2712 DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
2715 void DrawEnvelopeBackgroundTiles(int graphic, int startx, int starty,
2716 int x, int y, int xsize, int ysize,
2717 int tile_width, int tile_height)
2721 int dst_x = startx + x * tile_width;
2722 int dst_y = starty + y * tile_height;
2723 int width = graphic_info[graphic].width;
2724 int height = graphic_info[graphic].height;
2725 int inner_width_raw = MAX(width - 2 * tile_width, tile_width);
2726 int inner_height_raw = MAX(height - 2 * tile_height, tile_height);
2727 int inner_width = inner_width_raw - (inner_width_raw % tile_width);
2728 int inner_height = inner_height_raw - (inner_height_raw % tile_height);
2729 int inner_sx = (width >= 3 * tile_width ? tile_width : 0);
2730 int inner_sy = (height >= 3 * tile_height ? tile_height : 0);
2731 boolean draw_masked = graphic_info[graphic].draw_masked;
2733 getFixedGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
2735 if (src_bitmap == NULL || width < tile_width || height < tile_height)
2737 ClearRectangle(drawto, dst_x, dst_y, tile_width, tile_height);
2741 src_x += (x == 0 ? 0 : x == xsize - 1 ? width - tile_width :
2742 inner_sx + (x - 1) * tile_width % inner_width);
2743 src_y += (y == 0 ? 0 : y == ysize - 1 ? height - tile_height :
2744 inner_sy + (y - 1) * tile_height % inner_height);
2748 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
2749 dst_x - src_x, dst_y - src_y);
2750 BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, tile_width, tile_height,
2754 BlitBitmap(src_bitmap, drawto, src_x, src_y, tile_width, tile_height,
2758 void DrawEnvelopeBackground(int graphic, int startx, int starty,
2759 int x, int y, int xsize, int ysize, int font_nr)
2761 int font_width = getFontWidth(font_nr);
2762 int font_height = getFontHeight(font_nr);
2764 DrawEnvelopeBackgroundTiles(graphic, startx, starty, x, y, xsize, ysize,
2765 font_width, font_height);
2768 void AnimateEnvelope(int envelope_nr, int anim_mode, int action)
2770 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2771 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
2772 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
2773 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2774 boolean no_delay = (tape.warp_forward);
2775 unsigned int anim_delay = 0;
2776 int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
2777 int anim_delay_value = (no_delay ? 0 : frame_delay_value);
2778 int font_nr = FONT_ENVELOPE_1 + envelope_nr;
2779 int font_width = getFontWidth(font_nr);
2780 int font_height = getFontHeight(font_nr);
2781 int max_xsize = level.envelope[envelope_nr].xsize;
2782 int max_ysize = level.envelope[envelope_nr].ysize;
2783 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
2784 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
2785 int xend = max_xsize;
2786 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
2787 int xstep = (xstart < xend ? 1 : 0);
2788 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
2791 for (x = xstart, y = ystart; x <= xend && y <= yend; x += xstep, y += ystep)
2793 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
2794 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
2795 int sx = SX + (SXSIZE - xsize * font_width) / 2;
2796 int sy = SY + (SYSIZE - ysize * font_height) / 2;
2799 SetDrawtoField(DRAW_BUFFERED);
2802 BlitScreenToBitmap(backbuffer);
2804 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
2807 SetDrawtoField(DRAW_BACKBUFFER);
2809 for (yy = 0; yy < ysize; yy++)
2810 for (xx = 0; xx < xsize; xx++)
2811 DrawEnvelopeBackground(graphic, sx, sy, xx, yy, xsize, ysize, font_nr);
2814 DrawTextBuffer(sx + font_width, sy + font_height,
2815 level.envelope[envelope_nr].text, font_nr, max_xsize,
2816 xsize - 2, ysize - 2, 0, mask_mode,
2817 level.envelope[envelope_nr].autowrap,
2818 level.envelope[envelope_nr].centered, FALSE);
2820 DrawTextToTextArea(sx + font_width, sy + font_height,
2821 level.envelope[envelope_nr].text, font_nr, max_xsize,
2822 xsize - 2, ysize - 2, mask_mode);
2825 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
2828 WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
2832 void ShowEnvelope(int envelope_nr)
2834 int element = EL_ENVELOPE_1 + envelope_nr;
2835 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2836 int sound_opening = element_info[element].sound[ACTION_OPENING];
2837 int sound_closing = element_info[element].sound[ACTION_CLOSING];
2838 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2839 boolean no_delay = (tape.warp_forward);
2840 int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
2841 int wait_delay_value = (no_delay ? 0 : normal_delay_value);
2842 int anim_mode = graphic_info[graphic].anim_mode;
2843 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
2844 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
2846 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
2848 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
2850 if (anim_mode == ANIM_DEFAULT)
2851 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_OPENING);
2853 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_OPENING);
2856 Delay(wait_delay_value);
2858 WaitForEventToContinue();
2860 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
2862 if (anim_mode != ANIM_NONE)
2863 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_CLOSING);
2865 if (anim_mode == ANIM_DEFAULT)
2866 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_CLOSING);
2868 game.envelope_active = FALSE;
2870 SetDrawtoField(DRAW_BUFFERED);
2872 redraw_mask |= REDRAW_FIELD;
2876 static void setRequestPosition(int *x, int *y, boolean add_border_size)
2878 int border_size = request.border_size;
2879 int sx_center = (request.x != -1 ? request.x : SX + SXSIZE / 2);
2880 int sy_center = (request.y != -1 ? request.y : SY + SYSIZE / 2);
2881 int sx = sx_center - request.width / 2;
2882 int sy = sy_center - request.height / 2;
2884 if (add_border_size)
2894 void DrawEnvelopeRequest(char *text)
2896 char *text_final = text;
2897 char *text_door_style = NULL;
2898 int graphic = IMG_BACKGROUND_REQUEST;
2899 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
2900 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
2901 int font_nr = FONT_REQUEST;
2902 int font_width = getFontWidth(font_nr);
2903 int font_height = getFontHeight(font_nr);
2904 int border_size = request.border_size;
2905 int line_spacing = request.line_spacing;
2906 int line_height = font_height + line_spacing;
2907 int text_width = request.width - 2 * border_size;
2908 int text_height = request.height - 2 * border_size;
2909 int line_length = text_width / font_width;
2910 int max_lines = text_height / line_height;
2911 int width = request.width;
2912 int height = request.height;
2913 int tile_size = request.step_offset;
2914 int x_steps = width / tile_size;
2915 int y_steps = height / tile_size;
2919 if (request.wrap_single_words)
2921 char *src_text_ptr, *dst_text_ptr;
2923 text_door_style = checked_malloc(2 * strlen(text) + 1);
2925 src_text_ptr = text;
2926 dst_text_ptr = text_door_style;
2928 while (*src_text_ptr)
2930 if (*src_text_ptr == ' ' ||
2931 *src_text_ptr == '?' ||
2932 *src_text_ptr == '!')
2933 *dst_text_ptr++ = '\n';
2935 if (*src_text_ptr != ' ')
2936 *dst_text_ptr++ = *src_text_ptr;
2941 *dst_text_ptr = '\0';
2943 text_final = text_door_style;
2946 setRequestPosition(&sx, &sy, FALSE);
2948 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
2950 for (y = 0; y < y_steps; y++)
2951 for (x = 0; x < x_steps; x++)
2952 DrawEnvelopeBackgroundTiles(graphic, sx, sy,
2953 x, y, x_steps, y_steps,
2954 tile_size, tile_size);
2956 DrawTextBuffer(sx + border_size, sy + border_size, text_final, font_nr,
2957 line_length, -1, max_lines, line_spacing, mask_mode,
2958 request.autowrap, request.centered, FALSE);
2960 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
2961 RedrawGadget(tool_gadget[i]);
2963 // store readily prepared envelope request for later use when animating
2964 BlitBitmap(backbuffer, bitmap_db_cross, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2968 BlitBitmap(bitmap_db_store, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2969 BlitBitmap(bitmap_db_cross, backbuffer, sx, sy, width, height, sx, sy);
2971 redraw_mask = REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
2976 BlitBitmap(bitmap_db_store, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2978 redraw_mask = REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
2984 if (text_door_style)
2985 free(text_door_style);
2990 void AnimateEnvelopeRequest(int anim_mode, int action)
2992 int graphic = IMG_BACKGROUND_REQUEST;
2993 boolean draw_masked = graphic_info[graphic].draw_masked;
2995 int delay_value_normal = request.step_delay;
2996 int delay_value_fast = delay_value_normal / 2;
2998 int delay_value_normal = GameFrameDelay;
2999 int delay_value_fast = FfwdFrameDelay;
3001 boolean ffwd_delay = (tape.playing && tape.fast_forward);
3002 boolean no_delay = (tape.warp_forward);
3003 int delay_value = (ffwd_delay ? delay_value_fast : delay_value_normal);
3004 int anim_delay_value = (no_delay ? 0 : delay_value + 500 * 0);
3005 unsigned int anim_delay = 0;
3007 int width = request.width;
3008 int height = request.height;
3009 int tile_size = request.step_offset;
3010 int max_xsize = width / tile_size;
3011 int max_ysize = height / tile_size;
3012 int max_xsize_inner = max_xsize - 2;
3013 int max_ysize_inner = max_ysize - 2;
3015 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize_inner : 0);
3016 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize_inner : 0);
3017 int xend = max_xsize_inner;
3018 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize_inner : 0);
3019 int xstep = (xstart < xend ? 1 : 0);
3020 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
3023 for (x = xstart, y = ystart; x <= xend && y <= yend; x += xstep, y += ystep)
3025 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
3026 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
3027 int sx_center = (request.x != -1 ? request.x : SX + SXSIZE / 2);
3028 int sy_center = (request.y != -1 ? request.y : SY + SYSIZE / 2);
3029 int src_x = sx_center - width / 2;
3030 int src_y = sy_center - height / 2;
3031 int dst_x = sx_center - xsize * tile_size / 2;
3032 int dst_y = sy_center - ysize * tile_size / 2;
3033 int xsize_size_left = (xsize - 1) * tile_size;
3034 int ysize_size_top = (ysize - 1) * tile_size;
3035 int max_xsize_pos = (max_xsize - 1) * tile_size;
3036 int max_ysize_pos = (max_ysize - 1) * tile_size;
3039 BlitBitmap(bitmap_db_store, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
3042 for (yy = 0; yy < 2; yy++)
3044 for (xx = 0; xx < 2; xx++)
3046 int src_xx = src_x + xx * max_xsize_pos;
3047 int src_yy = src_y + yy * max_ysize_pos;
3048 int dst_xx = dst_x + xx * xsize_size_left;
3049 int dst_yy = dst_y + yy * ysize_size_top;
3050 int xx_size = (xx ? tile_size : xsize_size_left);
3051 int yy_size = (yy ? tile_size : ysize_size_top);
3054 BlitBitmapMasked(bitmap_db_cross, backbuffer,
3055 src_xx, src_yy, xx_size, yy_size, dst_xx, dst_yy);
3057 BlitBitmap(bitmap_db_cross, backbuffer,
3058 src_xx, src_yy, xx_size, yy_size, dst_xx, dst_yy);
3062 BlitBitmap(bitmap_db_cross, backbuffer,
3064 xsize_size_left, ysize_size_top,
3066 BlitBitmap(bitmap_db_cross, backbuffer,
3067 src_x + max_xsize_pos, src_y,
3068 tile_size, ysize_size_top,
3069 dst_x + xsize_size_left, dst_y);
3070 BlitBitmap(bitmap_db_cross, backbuffer,
3071 src_x, src_y + max_ysize_pos,
3072 xsize_size_left, tile_size,
3073 dst_x, dst_y + ysize_size_top);
3074 BlitBitmap(bitmap_db_cross, backbuffer,
3075 src_x + max_xsize_pos, src_y + max_ysize_pos,
3076 tile_size, tile_size,
3077 dst_x + xsize_size_left, dst_y + ysize_size_top);
3081 redraw_mask = REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
3082 // redraw_mask |= REDRAW_ALL | REDRAW_FROM_BACKBUFFER;
3084 /* CHECK AGAIN (previous code reactivated) */
3085 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
3095 WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
3101 void AnimateEnvelopeRequest(char *text, int anim_mode, int action)
3104 int envelope_nr = 0;
3107 int graphic = IMG_BACKGROUND_REQUEST;
3109 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
3111 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
3112 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
3113 boolean ffwd_delay = (tape.playing && tape.fast_forward);
3114 boolean no_delay = (tape.warp_forward);
3115 unsigned int anim_delay = 0;
3116 int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
3117 int anim_delay_value = (no_delay ? 0 : frame_delay_value + 500 * 0);
3119 int max_word_len = maxWordLengthInString(text);
3120 int font_nr = (max_word_len > 7 ? FONT_TEXT_1 : FONT_TEXT_2);
3122 int font_nr = FONT_ENVELOPE_1 + envelope_nr;
3124 int font_width = getFontWidth(font_nr);
3125 int font_height = getFontHeight(font_nr);
3126 int line_spacing = 2 * 1;
3130 int max_xsize = DXSIZE / font_width;
3131 // int max_ysize = DYSIZE / font_height;
3132 int max_ysize = DYSIZE / (font_height + line_spacing);
3134 int max_xsize = 7; /* tools.c: MAX_REQUEST_LINE_FONT1_LEN == 7 */
3135 int max_ysize = 13; /* tools.c: MAX_REQUEST_LINES == 13 */
3139 int max_xsize = level.envelope[envelope_nr].xsize;
3140 int max_ysize = level.envelope[envelope_nr].ysize;
3142 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
3143 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
3144 int xend = max_xsize;
3145 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
3146 int xstep = (xstart < xend ? 1 : 0);
3147 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
3152 char *text_copy = getStringCopy(text);
3155 font_nr = FONT_TEXT_2;
3157 if (maxWordLengthInString(text) > 7) /* MAX_REQUEST_LINE_FONT1_LEN == 7 */
3159 max_xsize = 10; /* tools.c: MAX_REQUEST_LINE_FONT2_LEN == 10 */
3160 font_nr = FONT_TEXT_1;
3163 int max_word_len = 0;
3165 char *text_copy = getStringCopy(text);
3167 font_nr = FONT_TEXT_2;
3169 for (text_ptr = text; *text_ptr; text_ptr++)
3171 max_word_len = (*text_ptr != ' ' ? max_word_len + 1 : 0);
3173 if (max_word_len > 7) /* tools.c: MAX_REQUEST_LINE_FONT1_LEN == 7 */
3175 max_xsize = 10; /* tools.c: MAX_REQUEST_LINE_FONT2_LEN == 10 */
3176 font_nr = FONT_TEXT_1;
3185 for (text_ptr = text_copy; *text_ptr; text_ptr++)
3186 if (*text_ptr == ' ')
3191 dDX = SX + (SXSIZE - DXSIZE) / 2 - DX;
3192 dDY = SY + (SYSIZE - DYSIZE) / 2 - DY;
3194 dDX = SX + SXSIZE / 2 - max_xsize * font_width / 2 - DX;
3195 dDY = SY + SYSIZE / 2 - max_ysize * font_height / 2 - DY;
3198 for (x = xstart, y = ystart; x <= xend && y <= yend; x += xstep, y += ystep)
3200 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
3201 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
3202 int sx = SX + (SXSIZE - xsize * font_width) / 2;
3203 // int sy = SX + (SYSIZE - ysize * font_height) / 2;
3204 int sy = SY + (SYSIZE - ysize * (font_height + line_spacing)) / 2;
3208 BlitBitmap(bitmap_db_store, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
3210 SetDrawtoField(DRAW_BUFFERED);
3213 BlitScreenToBitmap(backbuffer);
3215 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
3218 SetDrawtoField(DRAW_BACKBUFFER);
3221 for (yy = 0; yy < ysize; yy++)
3222 for (xx = 0; xx < xsize; xx++)
3223 DrawEnvelopeBackgroundTiles(graphic, sx, sy, xx, yy, xsize, ysize,
3224 getFontWidth(font_nr),
3225 getFontHeight(font_nr) + line_spacing);
3230 DrawTextBuffer(sx + font_width, sy + font_height + 8,
3231 text_copy, font_nr, max_xsize,
3232 xsize - 2, ysize - 2, line_spacing, mask_mode,
3233 FALSE, TRUE, FALSE);
3235 DrawTextBuffer(sx + font_width, sy + font_height,
3236 level.envelope[envelope_nr].text, font_nr, max_xsize,
3237 xsize - 2, ysize - 2, 0, mask_mode,
3238 level.envelope[envelope_nr].autowrap,
3239 level.envelope[envelope_nr].centered, FALSE);
3243 DrawTextToTextArea(sx + font_width, sy + font_height,
3244 level.envelope[envelope_nr].text, font_nr, max_xsize,
3245 xsize - 2, ysize - 2, mask_mode);
3248 /* copy request gadgets to door backbuffer */
3251 if ((ysize - 2) > 13)
3252 BlitBitmap(bitmap_db_door, drawto,
3253 DOOR_GFX_PAGEX1 + (DXSIZE - (xsize - 2) * font_width) / 2,
3254 DOOR_GFX_PAGEY1 + 13 * font_height,
3255 (xsize - 2) * font_width,
3256 (ysize - 2 - 13) * font_height,
3258 sy + font_height * (1 + 13));
3260 if ((ysize - 2) > 13)
3261 BlitBitmap(bitmap_db_door, drawto,
3262 DOOR_GFX_PAGEX1 + (DXSIZE - (xsize - 2) * font_width) / 2,
3263 DOOR_GFX_PAGEY1 + 11 * (font_height + line_spacing * 0),
3264 (xsize - 2) * font_width,
3265 (ysize - 2 - 13) * (font_height + line_spacing),
3267 sy + (font_height + line_spacing) * (1 + 13));
3269 if ((ysize - 2) > 13)
3270 BlitBitmap(bitmap_db_door, drawto,
3271 DOOR_GFX_PAGEX1 + (DXSIZE - (xsize - 2) * font_width) / 2,
3272 DOOR_GFX_PAGEY1 + 13 * font_height,
3273 (xsize - 2) * font_width,
3274 (ysize - 2 - 13) * font_height,
3276 sy + font_height * (1 + 13));
3280 redraw_mask = REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
3281 // redraw_mask |= REDRAW_ALL | REDRAW_FROM_BACKBUFFER;
3283 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
3293 WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
3303 void ShowEnvelopeRequest(char *text, unsigned int req_state, int action)
3306 int last_game_status = game_status; /* save current game status */
3307 // int last_draw_background_mask = gfx.draw_background_mask;
3310 int graphic = IMG_BACKGROUND_REQUEST;
3311 int sound_opening = SND_REQUEST_OPENING;
3312 int sound_closing = SND_REQUEST_CLOSING;
3314 int envelope_nr = 0;
3315 int element = EL_ENVELOPE_1 + envelope_nr;
3316 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
3317 int sound_opening = element_info[element].sound[ACTION_OPENING];
3318 int sound_closing = element_info[element].sound[ACTION_CLOSING];
3321 boolean ffwd_delay = (tape.playing && tape.fast_forward);
3322 boolean no_delay = (tape.warp_forward);
3323 int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
3324 int wait_delay_value = (no_delay ? 0 : normal_delay_value);
3326 int anim_mode = graphic_info[graphic].anim_mode;
3327 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
3328 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
3330 char *text_copy = getStringCopy(text);
3333 for (text_ptr = text_copy; *text_ptr; text_ptr++)
3334 if (*text_ptr == ' ')
3339 if (game_status == GAME_MODE_PLAYING)
3342 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
3343 BlitScreenToBitmap_EM(backbuffer);
3344 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
3345 BlitScreenToBitmap_SP(backbuffer);
3347 BlitScreenToBitmap(backbuffer);
3349 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
3350 BlitScreenToBitmap_EM(backbuffer);
3351 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
3352 BlitScreenToBitmap_SP(backbuffer);
3355 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
3360 SetDrawtoField(DRAW_BACKBUFFER);
3362 // SetDrawBackgroundMask(REDRAW_NONE);
3364 if (action == ACTION_OPENING)
3366 BlitBitmap(backbuffer, bitmap_db_store, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
3369 if (req_state & REQ_ASK)
3371 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
3372 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
3374 else if (req_state & REQ_CONFIRM)
3376 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
3378 else if (req_state & REQ_PLAYER)
3380 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
3381 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
3382 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
3383 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
3388 DrawEnvelopeRequest(text);
3390 DrawEnvelopeRequest(text_copy);
3393 if (game_status != GAME_MODE_MAIN)
3397 /* force DOOR font inside door area */
3398 game_status = GAME_MODE_PSEUDO_DOOR;
3401 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
3403 if (action == ACTION_OPENING)
3405 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
3407 if (anim_mode == ANIM_DEFAULT)
3408 AnimateEnvelopeRequest(ANIM_DEFAULT, ACTION_OPENING);
3410 AnimateEnvelopeRequest(main_anim_mode, ACTION_OPENING);
3414 Delay(wait_delay_value);
3416 WaitForEventToContinue();
3421 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
3423 if (anim_mode != ANIM_NONE)
3424 AnimateEnvelopeRequest(main_anim_mode, ACTION_CLOSING);
3426 if (anim_mode == ANIM_DEFAULT)
3427 AnimateEnvelopeRequest(ANIM_DEFAULT, ACTION_CLOSING);
3430 game.envelope_active = FALSE;
3433 // game_status = last_game_status; /* restore current game status */
3436 /* !!! CHECK AGAIN (SEE BELOW) !!! */
3437 game_status = last_game_status; /* restore current game status */
3440 if (action == ACTION_CLOSING)
3442 if (game_status != GAME_MODE_MAIN)
3445 BlitBitmap(bitmap_db_store, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
3448 SetDrawtoField(DRAW_BUFFERED);
3451 // SetDrawBackgroundMask(last_draw_background_mask);
3454 redraw_mask = REDRAW_FIELD;
3455 // redraw_mask |= REDRAW_ALL;
3457 /* CHECK AGAIN (previous code reactivated) */
3458 redraw_mask |= REDRAW_FIELD;
3462 if (game_status == GAME_MODE_MAIN)
3468 /* (important: after "BackToFront()", but before "SetDrawtoField()") */
3469 game_status = last_game_status; /* restore current game status */
3473 if (action == ACTION_CLOSING &&
3474 game_status == GAME_MODE_PLAYING &&
3475 level.game_engine_type == GAME_ENGINE_TYPE_RND)
3476 SetDrawtoField(DRAW_BUFFERED);
3478 if (game_status == GAME_MODE_PLAYING &&
3479 level.game_engine_type == GAME_ENGINE_TYPE_RND)
3480 SetDrawtoField(DRAW_BUFFERED);
3492 void DrawPreviewElement(int dst_x, int dst_y, int element, int tilesize)
3496 int graphic = el2preimg(element);
3498 getSizedGraphicSource(graphic, 0, tilesize, &src_bitmap, &src_x, &src_y);
3499 BlitBitmap(src_bitmap, drawto, src_x, src_y, tilesize, tilesize, dst_x,dst_y);
3507 SetMainBackgroundImage(IMG_BACKGROUND_PLAYING);
3508 SetDrawBackgroundMask(REDRAW_FIELD);
3510 SetDrawBackgroundMask(REDRAW_NONE);
3515 for (x = BX1; x <= BX2; x++)
3516 for (y = BY1; y <= BY2; y++)
3517 DrawScreenField(x, y);
3519 redraw_mask |= REDRAW_FIELD;
3522 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
3526 for (x = 0; x < size_x; x++)
3527 for (y = 0; y < size_y; y++)
3528 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
3530 redraw_mask |= REDRAW_FIELD;
3533 static void DrawPreviewLevelPlayfieldExt(int from_x, int from_y)
3535 boolean show_level_border = (BorderElement != EL_EMPTY);
3536 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
3537 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
3538 int tile_size = preview.tile_size;
3539 int preview_width = preview.xsize * tile_size;
3540 int preview_height = preview.ysize * tile_size;
3541 int real_preview_xsize = MIN(level_xsize, preview.xsize);
3542 int real_preview_ysize = MIN(level_ysize, preview.ysize);
3543 int real_preview_width = real_preview_xsize * tile_size;
3544 int real_preview_height = real_preview_ysize * tile_size;
3545 int dst_x = SX + ALIGNED_XPOS(preview.x, preview_width, preview.align);
3546 int dst_y = SY + ALIGNED_YPOS(preview.y, preview_height, preview.valign);
3550 if (!IN_GFX_FIELD_FULL(dst_x, dst_y + preview_height - 1))
3555 dst_x += (preview_width - real_preview_width) / 2;
3556 dst_y += (preview_height - real_preview_height) / 2;
3558 DrawBackground(dst_x, dst_y, real_preview_width, real_preview_height);
3560 DrawBackground(dst_x, dst_y, preview_width, preview_height);
3562 dst_x += (preview_width - real_preview_width) / 2;
3563 dst_y += (preview_height - real_preview_height) / 2;
3566 for (x = 0; x < real_preview_xsize; x++)
3568 for (y = 0; y < real_preview_ysize; y++)
3570 int lx = from_x + x + (show_level_border ? -1 : 0);
3571 int ly = from_y + y + (show_level_border ? -1 : 0);
3572 int element = (IN_LEV_FIELD(lx, ly) ? level.field[lx][ly] :
3573 getBorderElement(lx, ly));
3575 DrawPreviewElement(dst_x + x * tile_size, dst_y + y * tile_size,
3576 element, tile_size);
3580 redraw_mask |= REDRAW_MICROLEVEL;
3583 #define MICROLABEL_EMPTY 0
3584 #define MICROLABEL_LEVEL_NAME 1
3585 #define MICROLABEL_LEVEL_AUTHOR_HEAD 2
3586 #define MICROLABEL_LEVEL_AUTHOR 3
3587 #define MICROLABEL_IMPORTED_FROM_HEAD 4
3588 #define MICROLABEL_IMPORTED_FROM 5
3589 #define MICROLABEL_IMPORTED_BY_HEAD 6
3590 #define MICROLABEL_IMPORTED_BY 7
3592 static int getMaxTextLength(struct TextPosInfo *pos, int font_nr)
3594 int max_text_width = SXSIZE;
3595 int font_width = getFontWidth(font_nr);
3597 if (pos->align == ALIGN_CENTER)
3598 max_text_width = (pos->x < SXSIZE / 2 ? pos->x * 2 : (SXSIZE - pos->x) * 2);
3599 else if (pos->align == ALIGN_RIGHT)
3600 max_text_width = pos->x;
3602 max_text_width = SXSIZE - pos->x;
3604 return max_text_width / font_width;
3607 static void DrawPreviewLevelLabelExt(int mode)
3609 struct TextPosInfo *pos = &menu.main.text.level_info_2;
3610 char label_text[MAX_OUTPUT_LINESIZE + 1];
3611 int max_len_label_text;
3613 int font_nr = pos->font;
3616 if (!IN_GFX_FIELD_FULL(pos->x, pos->y + getFontHeight(pos->font)))
3619 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
3620 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
3621 mode == MICROLABEL_IMPORTED_BY_HEAD)
3622 font_nr = pos->font_alt;
3624 int font_nr = FONT_TEXT_2;
3627 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
3628 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
3629 mode == MICROLABEL_IMPORTED_BY_HEAD)
3630 font_nr = FONT_TEXT_3;
3634 max_len_label_text = getMaxTextLength(pos, font_nr);
3636 max_len_label_text = SXSIZE / getFontWidth(font_nr);
3640 if (pos->size != -1)
3641 max_len_label_text = pos->size;
3644 for (i = 0; i < max_len_label_text; i++)
3645 label_text[i] = ' ';
3646 label_text[max_len_label_text] = '\0';
3648 if (strlen(label_text) > 0)
3651 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
3653 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
3654 int lypos = MICROLABEL2_YPOS;
3656 DrawText(lxpos, lypos, label_text, font_nr);
3661 (mode == MICROLABEL_LEVEL_NAME ? level.name :
3662 mode == MICROLABEL_LEVEL_AUTHOR_HEAD ? "created by" :
3663 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
3664 mode == MICROLABEL_IMPORTED_FROM_HEAD ? "imported from" :
3665 mode == MICROLABEL_IMPORTED_FROM ? leveldir_current->imported_from :
3666 mode == MICROLABEL_IMPORTED_BY_HEAD ? "imported by" :
3667 mode == MICROLABEL_IMPORTED_BY ? leveldir_current->imported_by :""),
3668 max_len_label_text);
3669 label_text[max_len_label_text] = '\0';
3671 if (strlen(label_text) > 0)
3674 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
3676 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
3677 int lypos = MICROLABEL2_YPOS;
3679 DrawText(lxpos, lypos, label_text, font_nr);
3683 redraw_mask |= REDRAW_MICROLEVEL;
3686 static void DrawPreviewLevelExt(boolean restart)
3688 static unsigned int scroll_delay = 0;
3689 static unsigned int label_delay = 0;
3690 static int from_x, from_y, scroll_direction;
3691 static int label_state, label_counter;
3692 unsigned int scroll_delay_value = preview.step_delay;
3693 boolean show_level_border = (BorderElement != EL_EMPTY);
3694 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
3695 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
3696 int last_game_status = game_status; /* save current game status */
3699 /* force PREVIEW font on preview level */
3700 game_status = GAME_MODE_PSEUDO_PREVIEW;
3708 if (preview.anim_mode == ANIM_CENTERED)
3710 if (level_xsize > preview.xsize)
3711 from_x = (level_xsize - preview.xsize) / 2;
3712 if (level_ysize > preview.ysize)
3713 from_y = (level_ysize - preview.ysize) / 2;
3716 from_x += preview.xoffset;
3717 from_y += preview.yoffset;
3719 scroll_direction = MV_RIGHT;
3723 DrawPreviewLevelPlayfieldExt(from_x, from_y);
3724 DrawPreviewLevelLabelExt(label_state);
3726 /* initialize delay counters */
3727 DelayReached(&scroll_delay, 0);
3728 DelayReached(&label_delay, 0);
3730 if (leveldir_current->name)
3732 struct TextPosInfo *pos = &menu.main.text.level_info_1;
3733 char label_text[MAX_OUTPUT_LINESIZE + 1];
3735 int font_nr = pos->font;
3737 int font_nr = FONT_TEXT_1;
3740 int max_len_label_text = getMaxTextLength(pos, font_nr);
3742 int max_len_label_text = SXSIZE / getFontWidth(font_nr);
3750 if (pos->size != -1)
3751 max_len_label_text = pos->size;
3754 strncpy(label_text, leveldir_current->name, max_len_label_text);
3755 label_text[max_len_label_text] = '\0';
3758 if (IN_GFX_FIELD_FULL(pos->x, pos->y + getFontHeight(pos->font)))
3759 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
3761 lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
3762 lypos = SY + MICROLABEL1_YPOS;
3764 DrawText(lxpos, lypos, label_text, font_nr);
3768 game_status = last_game_status; /* restore current game status */
3773 /* scroll preview level, if needed */
3774 if (preview.anim_mode != ANIM_NONE &&
3775 (level_xsize > preview.xsize || level_ysize > preview.ysize) &&
3776 DelayReached(&scroll_delay, scroll_delay_value))
3778 switch (scroll_direction)
3783 from_x -= preview.step_offset;
3784 from_x = (from_x < 0 ? 0 : from_x);
3787 scroll_direction = MV_UP;
3791 if (from_x < level_xsize - preview.xsize)
3793 from_x += preview.step_offset;
3794 from_x = (from_x > level_xsize - preview.xsize ?
3795 level_xsize - preview.xsize : from_x);
3798 scroll_direction = MV_DOWN;
3804 from_y -= preview.step_offset;
3805 from_y = (from_y < 0 ? 0 : from_y);
3808 scroll_direction = MV_RIGHT;
3812 if (from_y < level_ysize - preview.ysize)
3814 from_y += preview.step_offset;
3815 from_y = (from_y > level_ysize - preview.ysize ?
3816 level_ysize - preview.ysize : from_y);
3819 scroll_direction = MV_LEFT;
3826 DrawPreviewLevelPlayfieldExt(from_x, from_y);
3829 /* !!! THIS ALL SUCKS -- SHOULD BE CLEANLY REWRITTEN !!! */
3830 /* redraw micro level label, if needed */
3831 if (!strEqual(level.name, NAMELESS_LEVEL_NAME) &&
3832 !strEqual(level.author, ANONYMOUS_NAME) &&
3833 !strEqual(level.author, leveldir_current->name) &&
3834 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
3836 int max_label_counter = 23;
3838 if (leveldir_current->imported_from != NULL &&
3839 strlen(leveldir_current->imported_from) > 0)
3840 max_label_counter += 14;
3841 if (leveldir_current->imported_by != NULL &&
3842 strlen(leveldir_current->imported_by) > 0)
3843 max_label_counter += 14;
3845 label_counter = (label_counter + 1) % max_label_counter;
3846 label_state = (label_counter >= 0 && label_counter <= 7 ?
3847 MICROLABEL_LEVEL_NAME :
3848 label_counter >= 9 && label_counter <= 12 ?
3849 MICROLABEL_LEVEL_AUTHOR_HEAD :
3850 label_counter >= 14 && label_counter <= 21 ?
3851 MICROLABEL_LEVEL_AUTHOR :
3852 label_counter >= 23 && label_counter <= 26 ?
3853 MICROLABEL_IMPORTED_FROM_HEAD :
3854 label_counter >= 28 && label_counter <= 35 ?
3855 MICROLABEL_IMPORTED_FROM :
3856 label_counter >= 37 && label_counter <= 40 ?
3857 MICROLABEL_IMPORTED_BY_HEAD :
3858 label_counter >= 42 && label_counter <= 49 ?
3859 MICROLABEL_IMPORTED_BY : MICROLABEL_EMPTY);
3861 if (leveldir_current->imported_from == NULL &&
3862 (label_state == MICROLABEL_IMPORTED_FROM_HEAD ||
3863 label_state == MICROLABEL_IMPORTED_FROM))
3864 label_state = (label_state == MICROLABEL_IMPORTED_FROM_HEAD ?
3865 MICROLABEL_IMPORTED_BY_HEAD : MICROLABEL_IMPORTED_BY);
3867 DrawPreviewLevelLabelExt(label_state);
3870 game_status = last_game_status; /* restore current game status */
3873 void DrawPreviewLevelInitial()
3875 DrawPreviewLevelExt(TRUE);
3878 void DrawPreviewLevelAnimation()
3880 DrawPreviewLevelExt(FALSE);
3883 inline void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
3884 int graphic, int sync_frame, int mask_mode)
3886 int frame = getGraphicAnimationFrame(graphic, sync_frame);
3888 if (mask_mode == USE_MASKING)
3889 DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
3891 DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
3894 inline void DrawFixedGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
3895 int graphic, int sync_frame,
3898 int frame = getGraphicAnimationFrame(graphic, sync_frame);
3900 if (mask_mode == USE_MASKING)
3901 DrawFixedGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
3903 DrawFixedGraphicExt(dst_bitmap, x, y, graphic, frame);
3906 inline void DrawGraphicAnimation(int x, int y, int graphic)
3908 int lx = LEVELX(x), ly = LEVELY(y);
3910 if (!IN_SCR_FIELD(x, y))
3914 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR,
3915 graphic, GfxFrame[lx][ly], NO_MASKING);
3917 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
3918 graphic, GfxFrame[lx][ly], NO_MASKING);
3920 MarkTileDirty(x, y);
3923 inline void DrawFixedGraphicAnimation(int x, int y, int graphic)
3925 int lx = LEVELX(x), ly = LEVELY(y);
3927 if (!IN_SCR_FIELD(x, y))
3930 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
3931 graphic, GfxFrame[lx][ly], NO_MASKING);
3932 MarkTileDirty(x, y);
3935 void DrawLevelGraphicAnimation(int x, int y, int graphic)
3937 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
3940 void DrawLevelElementAnimation(int x, int y, int element)
3942 int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
3944 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
3947 inline void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
3949 int sx = SCREENX(x), sy = SCREENY(y);
3951 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
3954 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
3957 DrawGraphicAnimation(sx, sy, graphic);
3960 if (GFX_CRUMBLED(TILE_GFX_ELEMENT(x, y)))
3961 DrawLevelFieldCrumbled(x, y);
3963 if (GFX_CRUMBLED(Feld[x][y]))
3964 DrawLevelFieldCrumbled(x, y);
3968 void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
3970 int sx = SCREENX(x), sy = SCREENY(y);
3973 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
3976 graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
3978 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
3981 DrawGraphicAnimation(sx, sy, graphic);
3983 if (GFX_CRUMBLED(element))
3984 DrawLevelFieldCrumbled(x, y);
3987 static int getPlayerGraphic(struct PlayerInfo *player, int move_dir)
3989 if (player->use_murphy)
3991 /* this works only because currently only one player can be "murphy" ... */
3992 static int last_horizontal_dir = MV_LEFT;
3993 int graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir);
3995 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3996 last_horizontal_dir = move_dir;
3998 if (graphic == IMG_SP_MURPHY) /* undefined => use special graphic */
4000 int direction = (player->is_snapping ? move_dir : last_horizontal_dir);
4002 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
4008 return el_act_dir2img(player->artwork_element, player->GfxAction,move_dir);
4011 static boolean equalGraphics(int graphic1, int graphic2)
4013 struct GraphicInfo *g1 = &graphic_info[graphic1];
4014 struct GraphicInfo *g2 = &graphic_info[graphic2];
4016 return (g1->bitmap == g2->bitmap &&
4017 g1->src_x == g2->src_x &&
4018 g1->src_y == g2->src_y &&
4019 g1->anim_frames == g2->anim_frames &&
4020 g1->anim_delay == g2->anim_delay &&
4021 g1->anim_mode == g2->anim_mode);
4024 void DrawAllPlayers()
4028 for (i = 0; i < MAX_PLAYERS; i++)
4029 if (stored_player[i].active)
4030 DrawPlayer(&stored_player[i]);
4033 void DrawPlayerField(int x, int y)
4035 if (!IS_PLAYER(x, y))
4038 DrawPlayer(PLAYERINFO(x, y));
4041 #define DRAW_PLAYER_OVER_PUSHED_ELEMENT 1
4043 void DrawPlayer(struct PlayerInfo *player)
4045 int jx = player->jx;
4046 int jy = player->jy;
4047 int move_dir = player->MovDir;
4048 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? +1 : 0);
4049 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? +1 : 0);
4050 int last_jx = (player->is_moving ? jx - dx : jx);
4051 int last_jy = (player->is_moving ? jy - dy : jy);
4052 int next_jx = jx + dx;
4053 int next_jy = jy + dy;
4054 boolean player_is_moving = (player->MovPos ? TRUE : FALSE);
4055 boolean player_is_opaque = FALSE;
4056 int sx = SCREENX(jx), sy = SCREENY(jy);
4057 int sxx = 0, syy = 0;
4058 int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
4060 int action = ACTION_DEFAULT;
4061 int last_player_graphic = getPlayerGraphic(player, move_dir);
4062 int last_player_frame = player->Frame;
4065 /* GfxElement[][] is set to the element the player is digging or collecting;
4066 remove also for off-screen player if the player is not moving anymore */
4067 if (IN_LEV_FIELD(jx, jy) && !player_is_moving)
4068 GfxElement[jx][jy] = EL_UNDEFINED;
4070 if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
4074 if (!IN_LEV_FIELD(jx, jy))
4076 printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
4077 printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
4078 printf("DrawPlayerField(): This should never happen!\n");
4083 if (element == EL_EXPLOSION)
4086 action = (player->is_pushing ? ACTION_PUSHING :
4087 player->is_digging ? ACTION_DIGGING :
4088 player->is_collecting ? ACTION_COLLECTING :
4089 player->is_moving ? ACTION_MOVING :
4090 player->is_snapping ? ACTION_SNAPPING :
4091 player->is_dropping ? ACTION_DROPPING :
4092 player->is_waiting ? player->action_waiting : ACTION_DEFAULT);
4094 if (player->is_waiting)
4095 move_dir = player->dir_waiting;
4097 InitPlayerGfxAnimation(player, action, move_dir);
4099 /* ----------------------------------------------------------------------- */
4100 /* draw things in the field the player is leaving, if needed */
4101 /* ----------------------------------------------------------------------- */
4103 if (player->is_moving)
4105 if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
4107 DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
4109 if (last_element == EL_DYNAMITE_ACTIVE ||
4110 last_element == EL_EM_DYNAMITE_ACTIVE ||
4111 last_element == EL_SP_DISK_RED_ACTIVE)
4112 DrawDynamite(last_jx, last_jy);
4114 DrawLevelFieldThruMask(last_jx, last_jy);
4116 else if (last_element == EL_DYNAMITE_ACTIVE ||
4117 last_element == EL_EM_DYNAMITE_ACTIVE ||
4118 last_element == EL_SP_DISK_RED_ACTIVE)
4119 DrawDynamite(last_jx, last_jy);
4121 /* !!! this is not enough to prevent flickering of players which are
4122 moving next to each others without a free tile between them -- this
4123 can only be solved by drawing all players layer by layer (first the
4124 background, then the foreground etc.) !!! => TODO */
4125 else if (!IS_PLAYER(last_jx, last_jy))
4126 DrawLevelField(last_jx, last_jy);
4129 DrawLevelField(last_jx, last_jy);
4132 if (player->is_pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
4133 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
4136 if (!IN_SCR_FIELD(sx, sy))
4139 /* ----------------------------------------------------------------------- */
4140 /* draw things behind the player, if needed */
4141 /* ----------------------------------------------------------------------- */
4144 DrawLevelElement(jx, jy, Back[jx][jy]);
4145 else if (IS_ACTIVE_BOMB(element))
4146 DrawLevelElement(jx, jy, EL_EMPTY);
4149 if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
4151 int old_element = GfxElement[jx][jy];
4152 int old_graphic = el_act_dir2img(old_element, action, move_dir);
4153 int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
4155 if (GFX_CRUMBLED(old_element))
4156 DrawLevelFieldCrumbledDigging(jx, jy, move_dir, player->StepFrame);
4158 DrawGraphic(sx, sy, old_graphic, frame);
4160 if (graphic_info[old_graphic].anim_mode & ANIM_OPAQUE_PLAYER)
4161 player_is_opaque = TRUE;
4165 GfxElement[jx][jy] = EL_UNDEFINED;
4167 /* make sure that pushed elements are drawn with correct frame rate */
4169 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
4171 if (player->is_pushing && player->is_moving && !IS_ANIM_MODE_CE(graphic))
4172 GfxFrame[jx][jy] = player->StepFrame;
4174 if (player->is_pushing && player->is_moving)
4175 GfxFrame[jx][jy] = player->StepFrame;
4178 DrawLevelField(jx, jy);
4182 #if !DRAW_PLAYER_OVER_PUSHED_ELEMENT
4183 /* ----------------------------------------------------------------------- */
4184 /* draw player himself */
4185 /* ----------------------------------------------------------------------- */
4187 graphic = getPlayerGraphic(player, move_dir);
4189 /* in the case of changed player action or direction, prevent the current
4190 animation frame from being restarted for identical animations */
4191 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
4192 player->Frame = last_player_frame;
4194 frame = getGraphicAnimationFrame(graphic, player->Frame);
4198 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
4199 sxx = player->GfxPos;
4201 syy = player->GfxPos;
4204 if (!setup.soft_scrolling && ScreenMovPos)
4207 if (player_is_opaque)
4208 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
4210 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
4212 if (SHIELD_ON(player))
4214 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
4215 IMG_SHIELD_NORMAL_ACTIVE);
4216 int frame = getGraphicAnimationFrame(graphic, -1);
4218 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
4222 #if DRAW_PLAYER_OVER_PUSHED_ELEMENT
4225 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
4226 sxx = player->GfxPos;
4228 syy = player->GfxPos;
4232 /* ----------------------------------------------------------------------- */
4233 /* draw things the player is pushing, if needed */
4234 /* ----------------------------------------------------------------------- */
4237 printf("::: %d, %d [%d, %d] [%d]\n",
4238 player->is_pushing, player_is_moving, player->GfxAction,
4239 player->is_moving, player_is_moving);
4243 if (player->is_pushing && player->is_moving)
4245 int px = SCREENX(jx), py = SCREENY(jy);
4246 int pxx = (TILEX - ABS(sxx)) * dx;
4247 int pyy = (TILEY - ABS(syy)) * dy;
4248 int gfx_frame = GfxFrame[jx][jy];
4254 if (!IS_MOVING(jx, jy)) /* push movement already finished */
4256 element = Feld[next_jx][next_jy];
4257 gfx_frame = GfxFrame[next_jx][next_jy];
4260 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
4263 sync_frame = (IS_ANIM_MODE_CE(graphic) ? gfx_frame : player->StepFrame);
4264 frame = getGraphicAnimationFrame(graphic, sync_frame);
4266 frame = getGraphicAnimationFrame(graphic, player->StepFrame);
4269 /* draw background element under pushed element (like the Sokoban field) */
4271 if (game.use_masked_pushing && IS_MOVING(jx, jy))
4273 /* this allows transparent pushing animation over non-black background */
4276 DrawLevelElement(jx, jy, Back[jx][jy]);
4278 DrawLevelElement(jx, jy, EL_EMPTY);
4280 if (Back[next_jx][next_jy])
4281 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
4283 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
4285 else if (Back[next_jx][next_jy])
4286 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
4288 if (Back[next_jx][next_jy])
4289 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
4293 printf("::: %d, %d, %d, %d [%d] [%d, %d, %d] [%d] [%d, %d] [%d, %d]\n",
4294 jx, px, player->GfxPos, player->StepFrame,
4299 GfxFrame[jx][jy], GfxFrame[next_jx][next_jy]);
4303 /* do not draw (EM style) pushing animation when pushing is finished */
4304 /* (two-tile animations usually do not contain start and end frame) */
4305 if (graphic_info[graphic].double_movement && !IS_MOVING(jx, jy))
4306 DrawLevelElement(next_jx, next_jy, Feld[next_jx][next_jy]);
4308 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
4310 /* masked drawing is needed for EMC style (double) movement graphics */
4311 /* !!! (ONLY WHEN DRAWING PUSHED ELEMENT OVER THE PLAYER) !!! */
4312 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
4317 #if DRAW_PLAYER_OVER_PUSHED_ELEMENT
4318 /* ----------------------------------------------------------------------- */
4319 /* draw player himself */
4320 /* ----------------------------------------------------------------------- */
4322 graphic = getPlayerGraphic(player, move_dir);
4324 /* in the case of changed player action or direction, prevent the current
4325 animation frame from being restarted for identical animations */
4326 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
4327 player->Frame = last_player_frame;
4329 frame = getGraphicAnimationFrame(graphic, player->Frame);
4333 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
4334 sxx = player->GfxPos;
4336 syy = player->GfxPos;
4339 if (!setup.soft_scrolling && ScreenMovPos)
4342 if (player_is_opaque)
4343 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
4345 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
4347 if (SHIELD_ON(player))
4349 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
4350 IMG_SHIELD_NORMAL_ACTIVE);
4351 int frame = getGraphicAnimationFrame(graphic, -1);
4353 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
4357 /* ----------------------------------------------------------------------- */
4358 /* draw things in front of player (active dynamite or dynabombs) */
4359 /* ----------------------------------------------------------------------- */
4361 if (IS_ACTIVE_BOMB(element))
4363 graphic = el2img(element);
4364 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
4366 if (game.emulation == EMU_SUPAPLEX)
4367 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
4369 DrawGraphicThruMask(sx, sy, graphic, frame);
4372 if (player_is_moving && last_element == EL_EXPLOSION)
4374 int element = (GfxElement[last_jx][last_jy] != EL_UNDEFINED ?
4375 GfxElement[last_jx][last_jy] : EL_EMPTY);
4376 int graphic = el_act2img(element, ACTION_EXPLODING);
4377 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
4378 int phase = ExplodePhase[last_jx][last_jy] - 1;
4379 int frame = getGraphicAnimationFrame(graphic, phase - delay);
4382 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
4385 /* ----------------------------------------------------------------------- */
4386 /* draw elements the player is just walking/passing through/under */
4387 /* ----------------------------------------------------------------------- */
4389 if (player_is_moving)
4391 /* handle the field the player is leaving ... */
4392 if (IS_ACCESSIBLE_INSIDE(last_element))
4393 DrawLevelField(last_jx, last_jy);
4394 else if (IS_ACCESSIBLE_UNDER(last_element))
4395 DrawLevelFieldThruMask(last_jx, last_jy);
4398 /* do not redraw accessible elements if the player is just pushing them */
4399 if (!player_is_moving || !player->is_pushing)
4401 /* ... and the field the player is entering */
4402 if (IS_ACCESSIBLE_INSIDE(element))
4403 DrawLevelField(jx, jy);
4404 else if (IS_ACCESSIBLE_UNDER(element))
4405 DrawLevelFieldThruMask(jx, jy);
4408 MarkTileDirty(sx, sy);
4411 /* ------------------------------------------------------------------------- */
4413 void WaitForEventToContinue()
4415 boolean still_wait = TRUE;
4417 /* simulate releasing mouse button over last gadget, if still pressed */
4419 HandleGadgets(-1, -1, 0);
4421 button_status = MB_RELEASED;
4437 case EVENT_BUTTONPRESS:
4438 case EVENT_KEYPRESS:
4442 case EVENT_KEYRELEASE:
4443 ClearPlayerAction();
4447 HandleOtherEvents(&event);
4451 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
4458 /* don't eat all CPU time */
4463 #define MAX_REQUEST_LINES 13
4464 #define MAX_REQUEST_LINE_FONT1_LEN 7
4465 #define MAX_REQUEST_LINE_FONT2_LEN 10
4469 static int RequestHandleEvents(unsigned int req_state)
4471 int last_game_status = game_status; /* save current game status */
4475 button_status = MB_RELEASED;
4477 request_gadget_id = -1;
4490 case EVENT_BUTTONPRESS:
4491 case EVENT_BUTTONRELEASE:
4492 case EVENT_MOTIONNOTIFY:
4494 if (event.type == EVENT_MOTIONNOTIFY)
4496 if (!PointerInWindow(window))
4497 continue; /* window and pointer are on different screens */
4502 motion_status = TRUE;
4503 mx = ((MotionEvent *) &event)->x;
4504 my = ((MotionEvent *) &event)->y;
4508 motion_status = FALSE;
4509 mx = ((ButtonEvent *) &event)->x;
4510 my = ((ButtonEvent *) &event)->y;
4511 if (event.type == EVENT_BUTTONPRESS)
4512 button_status = ((ButtonEvent *) &event)->button;
4514 button_status = MB_RELEASED;
4517 /* this sets 'request_gadget_id' */
4518 HandleGadgets(mx, my, button_status);
4520 switch (request_gadget_id)
4522 case TOOL_CTRL_ID_YES:
4525 case TOOL_CTRL_ID_NO:
4528 case TOOL_CTRL_ID_CONFIRM:
4529 result = TRUE | FALSE;
4532 case TOOL_CTRL_ID_PLAYER_1:
4535 case TOOL_CTRL_ID_PLAYER_2:
4538 case TOOL_CTRL_ID_PLAYER_3:
4541 case TOOL_CTRL_ID_PLAYER_4:
4552 case EVENT_KEYPRESS:
4553 switch (GetEventKey((KeyEvent *)&event, TRUE))
4556 if (req_state & REQ_CONFIRM)
4565 #if defined(TARGET_SDL2)
4575 if (req_state & REQ_PLAYER)
4579 case EVENT_KEYRELEASE:
4580 ClearPlayerAction();
4584 HandleOtherEvents(&event);
4588 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
4590 int joy = AnyJoystick();
4592 if (joy & JOY_BUTTON_1)
4594 else if (joy & JOY_BUTTON_2)
4600 if (game_status == GAME_MODE_PLAYING && local_player->LevelSolved_GameEnd)
4602 HandleGameActions();
4608 if (!PendingEvent()) /* delay only if no pending events */
4613 game_status = GAME_MODE_PSEUDO_DOOR;
4619 game_status = last_game_status; /* restore current game status */
4627 if (!PendingEvent()) /* delay only if no pending events */
4630 /* don't eat all CPU time */
4640 static boolean RequestDoor(char *text, unsigned int req_state)
4642 unsigned int old_door_state;
4643 int last_game_status = game_status; /* save current game status */
4644 int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
4645 int font_nr = FONT_TEXT_2;
4650 if (maxWordLengthInString(text) > MAX_REQUEST_LINE_FONT1_LEN)
4652 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
4653 font_nr = FONT_TEXT_1;
4656 if (game_status == GAME_MODE_PLAYING)
4658 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
4659 BlitScreenToBitmap_EM(backbuffer);
4660 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
4661 BlitScreenToBitmap_SP(backbuffer);
4664 /* disable deactivated drawing when quick-loading level tape recording */
4665 if (tape.playing && tape.deactivate_display)
4666 TapeDeactivateDisplayOff(TRUE);
4668 SetMouseCursor(CURSOR_DEFAULT);
4670 #if defined(NETWORK_AVALIABLE)
4671 /* pause network game while waiting for request to answer */
4672 if (options.network &&
4673 game_status == GAME_MODE_PLAYING &&
4674 req_state & REQUEST_WAIT_FOR_INPUT)
4675 SendToServer_PausePlaying();
4678 old_door_state = GetDoorState();
4680 /* simulate releasing mouse button over last gadget, if still pressed */
4682 HandleGadgets(-1, -1, 0);
4686 /* draw released gadget before proceeding */
4689 if (old_door_state & DOOR_OPEN_1)
4691 CloseDoor(DOOR_CLOSE_1);
4693 /* save old door content */
4695 BlitBitmap(bitmap_db_door_1, bitmap_db_door_1,
4696 0 * DXSIZE, 0, DXSIZE, DYSIZE, 1 * DXSIZE, 0);
4698 BlitBitmap(bitmap_db_door, bitmap_db_door,
4699 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
4700 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
4704 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
4705 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
4707 /* clear door drawing field */
4708 DrawBackground(DX, DY, DXSIZE, DYSIZE);
4710 /* force DOOR font inside door area */
4711 game_status = GAME_MODE_PSEUDO_DOOR;
4713 /* write text for request */
4714 for (text_ptr = text, ty = 0; ty < MAX_REQUEST_LINES; ty++)
4716 char text_line[max_request_line_len + 1];
4722 for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
4724 tc = *(text_ptr + tx);
4725 // if (!tc || tc == ' ')
4726 if (!tc || tc == ' ' || tc == '?' || tc == '!')
4730 if ((tc == '?' || tc == '!') && tl == 0)
4740 strncpy(text_line, text_ptr, tl);
4743 DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
4744 DY + 8 + ty * (getFontHeight(font_nr) + 2),
4745 text_line, font_nr);
4747 text_ptr += tl + (tc == ' ' ? 1 : 0);
4748 // text_ptr += tl + (tc == ' ' || tc == '?' || tc == '!' ? 1 : 0);
4751 game_status = last_game_status; /* restore current game status */
4753 if (req_state & REQ_ASK)
4755 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
4756 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
4758 else if (req_state & REQ_CONFIRM)
4760 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
4762 else if (req_state & REQ_PLAYER)
4764 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
4765 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
4766 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
4767 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
4770 /* copy request gadgets to door backbuffer */
4772 BlitBitmap(drawto, bitmap_db_door_1, DX, DY, DXSIZE, DYSIZE, 0, 0);
4774 BlitBitmap(drawto, bitmap_db_door,
4775 DX, DY, DXSIZE, DYSIZE,
4776 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
4779 OpenDoor(DOOR_OPEN_1);
4781 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
4783 if (game_status == GAME_MODE_PLAYING)
4785 SetPanelBackground();
4786 SetDrawBackgroundMask(REDRAW_DOOR_1);
4790 SetDrawBackgroundMask(REDRAW_FIELD);
4796 if (game_status != GAME_MODE_MAIN)
4799 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
4801 // ---------- handle request buttons ----------
4802 result = RequestHandleEvents(req_state);
4804 if (game_status != GAME_MODE_MAIN)
4809 if (!(req_state & REQ_STAY_OPEN))
4811 CloseDoor(DOOR_CLOSE_1);
4813 if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
4814 (req_state & REQ_REOPEN))
4815 OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
4820 if (game_status == GAME_MODE_PLAYING)
4822 SetPanelBackground();
4823 SetDrawBackgroundMask(REDRAW_DOOR_1);
4827 SetDrawBackgroundMask(REDRAW_FIELD);
4830 #if defined(NETWORK_AVALIABLE)
4831 /* continue network game after request */
4832 if (options.network &&
4833 game_status == GAME_MODE_PLAYING &&
4834 req_state & REQUEST_WAIT_FOR_INPUT)
4835 SendToServer_ContinuePlaying();
4838 /* restore deactivated drawing when quick-loading level tape recording */
4839 if (tape.playing && tape.deactivate_display)
4840 TapeDeactivateDisplayOn();
4845 static boolean RequestEnvelope(char *text, unsigned int req_state)
4852 if (game_status == GAME_MODE_PLAYING)
4855 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
4856 BlitScreenToBitmap_EM(backbuffer);
4857 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
4858 BlitScreenToBitmap_SP(backbuffer);
4860 BlitScreenToBitmap(backbuffer);
4862 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
4863 BlitScreenToBitmap_EM(backbuffer);
4864 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
4865 BlitScreenToBitmap_SP(backbuffer);
4869 /* disable deactivated drawing when quick-loading level tape recording */
4870 if (tape.playing && tape.deactivate_display)
4871 TapeDeactivateDisplayOff(TRUE);
4873 SetMouseCursor(CURSOR_DEFAULT);
4875 #if defined(NETWORK_AVALIABLE)
4876 /* pause network game while waiting for request to answer */
4877 if (options.network &&
4878 game_status == GAME_MODE_PLAYING &&
4879 req_state & REQUEST_WAIT_FOR_INPUT)
4880 SendToServer_PausePlaying();
4883 /* simulate releasing mouse button over last gadget, if still pressed */
4885 HandleGadgets(-1, -1, 0);
4889 // (replace with setting corresponding request background)
4890 // SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
4891 // SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
4893 /* clear door drawing field */
4894 // DrawBackground(DX, DY, DXSIZE, DYSIZE);
4897 if (global.use_envelope_request)
4901 CreateToolButtons();
4907 if (req_state & REQ_ASK)
4909 MapGadgetExt(tool_gadget[TOOL_CTRL_ID_YES], FALSE);
4910 MapGadgetExt(tool_gadget[TOOL_CTRL_ID_NO], FALSE);
4912 else if (req_state & REQ_CONFIRM)
4914 MapGadgetExt(tool_gadget[TOOL_CTRL_ID_CONFIRM], FALSE);
4916 else if (req_state & REQ_PLAYER)
4918 MapGadgetExt(tool_gadget[TOOL_CTRL_ID_PLAYER_1], FALSE);
4919 MapGadgetExt(tool_gadget[TOOL_CTRL_ID_PLAYER_2], FALSE);
4920 MapGadgetExt(tool_gadget[TOOL_CTRL_ID_PLAYER_3], FALSE);
4921 MapGadgetExt(tool_gadget[TOOL_CTRL_ID_PLAYER_4], FALSE);
4924 if (req_state & REQ_ASK)
4926 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
4927 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
4929 else if (req_state & REQ_CONFIRM)
4931 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
4933 else if (req_state & REQ_PLAYER)
4935 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
4936 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
4937 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
4938 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
4943 ShowEnvelopeRequest(text, req_state, ACTION_OPENING);
4946 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4948 if ((req_state & REQ_ASK && (i == TOOL_CTRL_ID_YES ||
4949 i == TOOL_CTRL_ID_NO)) ||
4950 (req_state & REQ_CONFIRM && i == TOOL_CTRL_ID_CONFIRM) ||
4951 (req_state & REQ_PLAYER && (i == TOOL_CTRL_ID_PLAYER_1 &&
4952 i == TOOL_CTRL_ID_PLAYER_2 &&
4953 i == TOOL_CTRL_ID_PLAYER_3 &&
4954 i == TOOL_CTRL_ID_PLAYER_4)))
4956 int x = tool_gadget[i]->x + dDX;
4957 int y = tool_gadget[i]->y + dDY;
4959 ModifyGadget(tool_gadget[i], GDI_X, x, GDI_Y, y, GDI_END);
4964 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
4966 if (game_status == GAME_MODE_PLAYING)
4968 SetPanelBackground();
4969 SetDrawBackgroundMask(REDRAW_DOOR_1);
4973 SetDrawBackgroundMask(REDRAW_FIELD);
4980 if (game_status != GAME_MODE_MAIN)
4984 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
4986 // ---------- handle request buttons ----------
4987 result = RequestHandleEvents(req_state);
4989 if (game_status != GAME_MODE_MAIN)
4994 ShowEnvelopeRequest(text, req_state, ACTION_CLOSING);
4998 if (game_status == GAME_MODE_PLAYING)
5000 SetPanelBackground();
5001 SetDrawBackgroundMask(REDRAW_DOOR_1);
5005 SetDrawBackgroundMask(REDRAW_FIELD);
5008 #if defined(NETWORK_AVALIABLE)
5009 /* continue network game after request */
5010 if (options.network &&
5011 game_status == GAME_MODE_PLAYING &&
5012 req_state & REQUEST_WAIT_FOR_INPUT)
5013 SendToServer_ContinuePlaying();
5016 /* restore deactivated drawing when quick-loading level tape recording */
5017 if (tape.playing && tape.deactivate_display)
5018 TapeDeactivateDisplayOn();
5023 boolean Request(char *text, unsigned int req_state)
5025 if (global.use_envelope_request)
5026 return RequestEnvelope(text, req_state);
5028 return RequestDoor(text, req_state);
5031 #else // =====================================================================
5033 boolean Request(char *text, unsigned int req_state)
5035 int mx, my, ty, result = -1;
5036 unsigned int old_door_state;
5037 int last_game_status = game_status; /* save current game status */
5038 int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
5039 int font_nr = FONT_TEXT_2;
5041 int max_word_len = 0;
5047 global.use_envelope_request = 1;
5051 if (maxWordLengthInString(text) > MAX_REQUEST_LINE_FONT1_LEN)
5053 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
5054 font_nr = FONT_TEXT_1;
5057 for (text_ptr = text; *text_ptr; text_ptr++)
5059 max_word_len = (*text_ptr != ' ' ? max_word_len + 1 : 0);
5061 if (max_word_len > MAX_REQUEST_LINE_FONT1_LEN)
5063 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
5065 font_nr = FONT_TEXT_1;
5067 font_nr = FONT_LEVEL_NUMBER;
5075 if (game_status == GAME_MODE_PLAYING)
5077 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
5078 BlitScreenToBitmap_EM(backbuffer);
5079 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
5080 BlitScreenToBitmap_SP(backbuffer);
5083 /* disable deactivated drawing when quick-loading level tape recording */
5084 if (tape.playing && tape.deactivate_display)
5085 TapeDeactivateDisplayOff(TRUE);
5087 SetMouseCursor(CURSOR_DEFAULT);
5089 #if defined(NETWORK_AVALIABLE)
5090 /* pause network game while waiting for request to answer */
5091 if (options.network &&
5092 game_status == GAME_MODE_PLAYING &&
5093 req_state & REQUEST_WAIT_FOR_INPUT)
5094 SendToServer_PausePlaying();
5097 old_door_state = GetDoorState();
5099 /* simulate releasing mouse button over last gadget, if still pressed */
5101 HandleGadgets(-1, -1, 0);
5105 /* draw released gadget before proceeding */
5109 if (old_door_state & DOOR_OPEN_1 && !global.use_envelope_request)
5111 if (old_door_state & DOOR_OPEN_1)
5115 if (!global.use_envelope_request)
5116 CloseDoor(DOOR_CLOSE_1);
5118 CloseDoor(DOOR_CLOSE_1);
5121 /* save old door content */
5122 BlitBitmap(bitmap_db_door, bitmap_db_door,
5123 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
5124 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
5128 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
5131 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
5133 /* clear door drawing field */
5134 DrawBackground(DX, DY, DXSIZE, DYSIZE);
5136 /* force DOOR font inside door area */
5137 game_status = GAME_MODE_PSEUDO_DOOR;
5139 /* write text for request */
5140 for (text_ptr = text, ty = 0; ty < MAX_REQUEST_LINES; ty++)
5142 char text_line[max_request_line_len + 1];
5148 for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
5150 tc = *(text_ptr + tx);
5151 if (!tc || tc == ' ')
5162 strncpy(text_line, text_ptr, tl);
5165 DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
5166 DY + 8 + ty * (getFontHeight(font_nr) + 2),
5167 text_line, font_nr);
5169 text_ptr += tl + (tc == ' ' ? 1 : 0);
5172 game_status = last_game_status; /* restore current game status */
5175 if (global.use_envelope_request)
5179 CreateToolButtons();
5183 if (req_state & REQ_ASK)
5185 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
5186 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
5188 else if (req_state & REQ_CONFIRM)
5190 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
5192 else if (req_state & REQ_PLAYER)
5194 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
5195 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
5196 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
5197 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
5200 /* copy request gadgets to door backbuffer */
5201 BlitBitmap(drawto, bitmap_db_door,
5202 DX, DY, DXSIZE, DYSIZE,
5203 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
5206 if (global.use_envelope_request)
5208 ShowEnvelopeRequest(text, ACTION_OPENING);
5210 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
5212 if ((req_state & REQ_ASK && (i == TOOL_CTRL_ID_YES ||
5213 i == TOOL_CTRL_ID_NO)) ||
5214 (req_state & REQ_CONFIRM && i == TOOL_CTRL_ID_CONFIRM) ||
5215 (req_state & REQ_PLAYER && (i == TOOL_CTRL_ID_PLAYER_1 &&
5216 i == TOOL_CTRL_ID_PLAYER_2 &&
5217 i == TOOL_CTRL_ID_PLAYER_3 &&
5218 i == TOOL_CTRL_ID_PLAYER_4)))
5220 int x = tool_gadget[i]->x + dDX;
5221 int y = tool_gadget[i]->y + dDY;
5223 ModifyGadget(tool_gadget[i], GDI_X, x, GDI_Y, y, GDI_END);
5230 if (!global.use_envelope_request)
5231 OpenDoor(DOOR_OPEN_1);
5233 OpenDoor(DOOR_OPEN_1);
5236 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
5238 if (game_status == GAME_MODE_PLAYING)
5240 SetPanelBackground();
5241 SetDrawBackgroundMask(REDRAW_DOOR_1);
5245 SetDrawBackgroundMask(REDRAW_FIELD);
5252 if (game_status != GAME_MODE_MAIN && !global.use_envelope_request)
5255 if (game_status != GAME_MODE_MAIN)
5259 button_status = MB_RELEASED;
5261 request_gadget_id = -1;
5263 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
5275 case EVENT_BUTTONPRESS:
5276 case EVENT_BUTTONRELEASE:
5277 case EVENT_MOTIONNOTIFY:
5279 if (event.type == EVENT_MOTIONNOTIFY)
5281 if (!PointerInWindow(window))
5282 continue; /* window and pointer are on different screens */
5287 motion_status = TRUE;
5288 mx = ((MotionEvent *) &event)->x;
5289 my = ((MotionEvent *) &event)->y;
5293 motion_status = FALSE;
5294 mx = ((ButtonEvent *) &event)->x;
5295 my = ((ButtonEvent *) &event)->y;
5296 if (event.type == EVENT_BUTTONPRESS)
5297 button_status = ((ButtonEvent *) &event)->button;
5299 button_status = MB_RELEASED;
5302 /* this sets 'request_gadget_id' */
5303 HandleGadgets(mx, my, button_status);
5305 switch (request_gadget_id)
5307 case TOOL_CTRL_ID_YES:
5310 case TOOL_CTRL_ID_NO:
5313 case TOOL_CTRL_ID_CONFIRM:
5314 result = TRUE | FALSE;
5317 case TOOL_CTRL_ID_PLAYER_1:
5320 case TOOL_CTRL_ID_PLAYER_2:
5323 case TOOL_CTRL_ID_PLAYER_3:
5326 case TOOL_CTRL_ID_PLAYER_4:
5337 case EVENT_KEYPRESS:
5338 switch (GetEventKey((KeyEvent *)&event, TRUE))
5341 if (req_state & REQ_CONFIRM)
5350 #if defined(TARGET_SDL2)
5360 if (req_state & REQ_PLAYER)
5364 case EVENT_KEYRELEASE:
5365 ClearPlayerAction();
5369 HandleOtherEvents(&event);
5373 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
5375 int joy = AnyJoystick();
5377 if (joy & JOY_BUTTON_1)
5379 else if (joy & JOY_BUTTON_2)
5385 if (game_status == GAME_MODE_PLAYING && local_player->LevelSolved_GameEnd)
5387 HandleGameActions();
5393 if (!PendingEvent()) /* delay only if no pending events */
5398 game_status = GAME_MODE_PSEUDO_DOOR;
5404 game_status = last_game_status; /* restore current game status */
5412 if (!PendingEvent()) /* delay only if no pending events */
5415 /* don't eat all CPU time */
5422 if (game_status != GAME_MODE_MAIN)
5428 if (global.use_envelope_request)
5429 ShowEnvelopeRequest(text, ACTION_CLOSING);
5433 if (!(req_state & REQ_STAY_OPEN) && !global.use_envelope_request)
5435 if (!(req_state & REQ_STAY_OPEN))
5438 CloseDoor(DOOR_CLOSE_1);
5440 if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
5441 (req_state & REQ_REOPEN))
5442 OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
5447 if (game_status == GAME_MODE_PLAYING)
5449 SetPanelBackground();
5450 SetDrawBackgroundMask(REDRAW_DOOR_1);
5454 SetDrawBackgroundMask(REDRAW_FIELD);
5457 #if defined(NETWORK_AVALIABLE)
5458 /* continue network game after request */
5459 if (options.network &&
5460 game_status == GAME_MODE_PLAYING &&
5461 req_state & REQUEST_WAIT_FOR_INPUT)
5462 SendToServer_ContinuePlaying();
5465 /* restore deactivated drawing when quick-loading level tape recording */
5466 if (tape.playing && tape.deactivate_display)
5467 TapeDeactivateDisplayOn();
5474 static int compareDoorPartOrderInfo(const void *object1, const void *object2)
5476 const struct DoorPartOrderInfo *dpo1 = (struct DoorPartOrderInfo *)object1;
5477 const struct DoorPartOrderInfo *dpo2 = (struct DoorPartOrderInfo *)object2;
5480 if (dpo1->sort_priority != dpo2->sort_priority)
5481 compare_result = dpo1->sort_priority - dpo2->sort_priority;
5483 compare_result = dpo1->nr - dpo2->nr;
5485 return compare_result;
5488 void InitGraphicCompatibilityInfo_Doors()
5494 struct DoorInfo *door;
5498 { DOOR_1, IMG_DOOR_1_GFX_PART_1, IMG_DOOR_1_GFX_PART_8, &door_1 },
5499 { DOOR_2, IMG_DOOR_2_GFX_PART_1, IMG_DOOR_2_GFX_PART_8, &door_2 },
5501 { -1, -1, -1, NULL }
5503 struct Rect door_rect_list[] =
5505 { DX, DY, DXSIZE, DYSIZE },
5506 { VX, VY, VXSIZE, VYSIZE }
5510 for (i = 0; doors[i].door_token != -1; i++)
5512 int door_token = doors[i].door_token;
5513 int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
5514 int part_1 = doors[i].part_1;
5515 int part_8 = doors[i].part_8;
5516 int part_2 = part_1 + 1;
5517 int part_3 = part_1 + 2;
5518 struct DoorInfo *door = doors[i].door;
5519 struct Rect *door_rect = &door_rect_list[door_index];
5520 boolean door_gfx_redefined = FALSE;
5522 /* check if any door part graphic definitions have been redefined */
5524 for (j = 0; door_part_controls[j].door_token != -1; j++)
5526 struct DoorPartControlInfo *dpc = &door_part_controls[j];
5527 struct FileInfo *fi = getImageListEntryFromImageID(dpc->graphic);
5529 if (dpc->door_token == door_token && fi->redefined)
5530 door_gfx_redefined = TRUE;
5533 /* check for old-style door graphic/animation modifications */
5535 if (!door_gfx_redefined)
5537 if (door->anim_mode & ANIM_STATIC_PANEL)
5539 door->panel.step_xoffset = 0;
5540 door->panel.step_yoffset = 0;
5543 if (door->anim_mode & (ANIM_HORIZONTAL | ANIM_VERTICAL))
5545 struct GraphicInfo *g_part_1 = &graphic_info[part_1];
5546 struct GraphicInfo *g_part_2 = &graphic_info[part_2];
5547 int num_door_steps, num_panel_steps;
5549 /* remove door part graphics other than the two default wings */
5551 for (j = 0; door_part_controls[j].door_token != -1; j++)
5553 struct DoorPartControlInfo *dpc = &door_part_controls[j];
5554 struct GraphicInfo *g = &graphic_info[dpc->graphic];
5556 if (dpc->graphic >= part_3 &&
5557 dpc->graphic <= part_8)
5561 /* set graphics and screen positions of the default wings */
5563 g_part_1->width = door_rect->width;
5564 g_part_1->height = door_rect->height;
5565 g_part_2->width = door_rect->width;
5566 g_part_2->height = door_rect->height;
5567 g_part_2->src_x = door_rect->width;
5568 g_part_2->src_y = g_part_1->src_y;
5570 door->part_2.x = door->part_1.x;
5571 door->part_2.y = door->part_1.y;
5573 if (door->width != -1)
5575 g_part_1->width = door->width;
5576 g_part_2->width = door->width;
5578 // special treatment for graphics and screen position of right wing
5579 g_part_2->src_x += door_rect->width - door->width;
5580 door->part_2.x += door_rect->width - door->width;
5583 if (door->height != -1)
5585 g_part_1->height = door->height;
5586 g_part_2->height = door->height;
5588 // special treatment for graphics and screen position of bottom wing
5589 g_part_2->src_y += door_rect->height - door->height;
5590 door->part_2.y += door_rect->height - door->height;
5593 /* set animation delays for the default wings and panels */
5595 door->part_1.step_delay = door->step_delay;
5596 door->part_2.step_delay = door->step_delay;
5597 door->panel.step_delay = door->step_delay;
5599 /* set animation draw order for the default wings */
5601 door->part_1.sort_priority = 2; /* draw left wing over ... */
5602 door->part_2.sort_priority = 1; /* ... right wing */
5604 /* set animation draw offset for the default wings */
5606 if (door->anim_mode & ANIM_HORIZONTAL)
5608 door->part_1.step_xoffset = door->step_offset;
5609 door->part_1.step_yoffset = 0;
5610 door->part_2.step_xoffset = door->step_offset * -1;
5611 door->part_2.step_yoffset = 0;
5613 num_door_steps = g_part_1->width / door->step_offset;
5615 else // ANIM_VERTICAL
5617 door->part_1.step_xoffset = 0;
5618 door->part_1.step_yoffset = door->step_offset;
5619 door->part_2.step_xoffset = 0;
5620 door->part_2.step_yoffset = door->step_offset * -1;
5622 num_door_steps = g_part_1->height / door->step_offset;
5625 /* set animation draw offset for the default panels */
5627 if (door->step_offset > 1)
5629 num_panel_steps = 2 * door_rect->height / door->step_offset;
5630 door->panel.start_step = num_panel_steps - num_door_steps;
5634 num_panel_steps = door_rect->height / door->step_offset;
5635 door->panel.start_step = num_panel_steps - num_door_steps / 2;
5636 door->panel.step_delay *= 2;
5647 for (i = 0; door_part_controls[i].door_token != -1; i++)
5649 struct DoorPartControlInfo *dpc = &door_part_controls[i];
5650 struct DoorPartOrderInfo *dpo = &door_part_order[i];
5652 /* initialize "start_step_opening" and "start_step_closing", if needed */
5653 if (dpc->pos->start_step_opening == 0 &&
5654 dpc->pos->start_step_closing == 0)
5656 // dpc->pos->start_step_opening = dpc->pos->start_step;
5657 dpc->pos->start_step_closing = dpc->pos->start_step;
5660 /* fill structure for door part draw order (sorted below) */
5662 dpo->sort_priority = dpc->pos->sort_priority;
5665 struct DoorPartPosInfo *pos = dpc->pos;
5667 printf(":0: step_xoffset == %d, step_yoffset == %d\n",
5668 pos->step_xoffset, pos->step_yoffset);
5672 /* sort door part controls according to sort_priority and graphic number */
5673 qsort(door_part_order, MAX_DOOR_PARTS,
5674 sizeof(struct DoorPartOrderInfo), compareDoorPartOrderInfo);
5677 unsigned int OpenDoor(unsigned int door_state)
5679 if (door_state & DOOR_COPY_BACK)
5682 if (door_state & DOOR_OPEN_1)
5683 BlitBitmap(bitmap_db_door_1, bitmap_db_door_1,
5684 1 * DXSIZE, 0, DXSIZE, DYSIZE, 0 * DXSIZE, 0);
5686 if (door_state & DOOR_OPEN_2)
5687 BlitBitmap(bitmap_db_door_2, bitmap_db_door_2,
5688 1 * VXSIZE, 0, VXSIZE, VYSIZE, 0 * VXSIZE, 0);
5690 if (door_state & DOOR_OPEN_1)
5691 BlitBitmap(bitmap_db_door, bitmap_db_door,
5692 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
5693 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
5695 if (door_state & DOOR_OPEN_2)
5696 BlitBitmap(bitmap_db_door, bitmap_db_door,
5697 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY2, VXSIZE, VYSIZE,
5698 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
5701 door_state &= ~DOOR_COPY_BACK;
5704 return MoveDoor(door_state);
5707 unsigned int CloseDoor(unsigned int door_state)
5709 unsigned int old_door_state = GetDoorState();
5711 if (!(door_state & DOOR_NO_COPY_BACK))
5714 if (old_door_state & DOOR_OPEN_1)
5715 BlitBitmap(backbuffer, bitmap_db_door_1,
5716 DX, DY, DXSIZE, DYSIZE, 0, 0);
5718 if (old_door_state & DOOR_OPEN_2)
5719 BlitBitmap(backbuffer, bitmap_db_door_2,
5720 VX, VY, VXSIZE, VYSIZE, 0, 0);
5722 if (old_door_state & DOOR_OPEN_1)
5723 BlitBitmap(backbuffer, bitmap_db_door,
5724 DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
5726 if (old_door_state & DOOR_OPEN_2)
5727 BlitBitmap(backbuffer, bitmap_db_door,
5728 VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
5731 door_state &= ~DOOR_NO_COPY_BACK;
5734 return MoveDoor(door_state);
5737 unsigned int GetDoorState()
5739 return MoveDoor(DOOR_GET_STATE);
5742 unsigned int SetDoorState(unsigned int door_state)
5744 return MoveDoor(door_state | DOOR_SET_STATE);
5749 // ========== TEST 1 ===========================================================
5751 int euclid(int a, int b)
5753 return (b ? euclid(b, a % b) : a);
5756 unsigned int MoveDoor(unsigned int door_state)
5759 struct XY panel_pos_list[] =
5761 { DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 },
5762 { DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 },
5765 struct Rect door_rect_list[] =
5767 { DX, DY, DXSIZE, DYSIZE },
5768 { VX, VY, VXSIZE, VYSIZE }
5770 static int door1 = DOOR_OPEN_1;
5771 static int door2 = DOOR_CLOSE_2;
5772 unsigned int door_delay = 0;
5773 unsigned int door_delay_value;
5777 if (door_1.width < 0 || door_1.width > DXSIZE)
5778 door_1.width = DXSIZE;
5779 if (door_1.height < 0 || door_1.height > DYSIZE)
5780 door_1.height = DYSIZE;
5781 if (door_2.width < 0 || door_2.width > VXSIZE)
5782 door_2.width = VXSIZE;
5783 if (door_2.height < 0 || door_2.height > VYSIZE)
5784 door_2.height = VYSIZE;
5787 if (door_state == DOOR_GET_STATE)
5788 return (door1 | door2);
5790 if (door_state & DOOR_SET_STATE)
5792 if (door_state & DOOR_ACTION_1)
5793 door1 = door_state & DOOR_ACTION_1;
5794 if (door_state & DOOR_ACTION_2)
5795 door2 = door_state & DOOR_ACTION_2;
5797 return (door1 | door2);
5800 if (!(door_state & DOOR_FORCE_REDRAW))
5802 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
5803 door_state &= ~DOOR_OPEN_1;
5804 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
5805 door_state &= ~DOOR_CLOSE_1;
5806 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
5807 door_state &= ~DOOR_OPEN_2;
5808 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
5809 door_state &= ~DOOR_CLOSE_2;
5813 door_delay_value = (door_state & DOOR_ACTION_1 ? door_1.step_delay :
5816 if (setup.quick_doors)
5818 stepsize = 20; /* must be chosen to always draw last frame */
5819 door_delay_value = 0;
5823 if (global.autoplay_leveldir)
5825 door_state |= DOOR_NO_DELAY;
5826 door_state &= ~DOOR_CLOSE_ALL;
5830 if (game_status == GAME_MODE_EDITOR)
5831 door_state |= DOOR_NO_DELAY;
5834 if (door_state & DOOR_ACTION)
5836 boolean door_panel_drawn[NUM_DOORS];
5837 boolean panel_has_doors[NUM_DOORS];
5838 boolean door_part_skip[MAX_DOOR_PARTS];
5839 boolean door_part_done[MAX_DOOR_PARTS];
5840 boolean door_part_done_all;
5841 int num_steps[MAX_DOOR_PARTS];
5842 int max_move_delay = 0; // delay for complete animations of all doors
5843 int max_step_delay = 0; // delay (ms) between two animation frames
5844 int num_move_steps = 0; // number of animation steps for all doors
5845 int current_move_delay = 0;
5848 for (i = 0; i < NUM_DOORS; i++)
5849 panel_has_doors[i] = FALSE;
5851 for (i = 0; i < MAX_DOOR_PARTS; i++)
5853 struct DoorPartControlInfo *dpc = &door_part_controls[i];
5854 struct GraphicInfo *g = &graphic_info[dpc->graphic];
5855 int door_token = dpc->door_token;
5857 door_part_done[i] = FALSE;
5858 door_part_skip[i] = (!(door_state & door_token) ||
5863 for (i = 0; i < MAX_DOOR_PARTS; i++)
5865 struct DoorPartControlInfo *dpc = &door_part_controls[i];
5866 struct DoorPartPosInfo *pos = dpc->pos;
5867 int start_step = pos->start_step;
5869 printf("::: ---> %d: start_step == %d [%d]\n",
5870 i, start_step, door_part_done[i]);
5874 for (i = 0; i < MAX_DOOR_PARTS; i++)
5876 int nr = door_part_order[i].nr;
5877 struct DoorPartControlInfo *dpc = &door_part_controls[nr];
5878 struct DoorPartPosInfo *pos = dpc->pos;
5879 struct GraphicInfo *g = &graphic_info[dpc->graphic];
5880 int door_token = dpc->door_token;
5881 int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
5882 boolean is_panel = DOOR_PART_IS_PANEL(nr);
5883 int step_xoffset = ABS(pos->step_xoffset);
5884 int step_yoffset = ABS(pos->step_yoffset);
5885 int step_delay = pos->step_delay;
5886 int current_door_state = door_state & door_token;
5887 boolean door_opening = ((current_door_state & DOOR_OPEN) != 0);
5888 boolean door_closing = ((current_door_state & DOOR_CLOSE) != 0);
5889 boolean part_opening = (is_panel ? door_closing : door_opening);
5890 int start_step = (part_opening ? pos->start_step_opening :
5891 pos->start_step_closing);
5892 float move_xsize = (step_xoffset ? g->width : 0);
5893 float move_ysize = (step_yoffset ? g->height : 0);
5894 int move_xsteps = (step_xoffset ? ceil(move_xsize / step_xoffset) : 0);
5895 int move_ysteps = (step_yoffset ? ceil(move_ysize / step_yoffset) : 0);
5896 int move_steps = (move_xsteps && move_ysteps ?
5897 MIN(move_xsteps, move_ysteps) :
5898 move_xsteps ? move_xsteps : move_ysteps) - start_step;
5899 int move_delay = move_steps * step_delay;
5901 if (door_part_skip[nr])
5905 panel_has_doors[door_index] = TRUE;
5907 max_move_delay = MAX(max_move_delay, move_delay);
5908 max_step_delay = (max_step_delay == 0 ? step_delay :
5909 euclid(max_step_delay, step_delay));
5910 num_steps[nr] = move_steps;
5914 printf("::: %d: move_delay == %d, start_step == %d [%d]\n",
5915 i, move_delay, start_step, door_part_order[i].nr);
5917 if (DOOR_PART_IS_PANEL(i))
5918 printf("::: %d: move_delay == %d, start_step == %d\n",
5919 i, move_delay, start_step);
5924 num_move_steps = max_move_delay / max_step_delay;
5926 door_delay_value = max_step_delay;
5929 door_delay_value *= 10;
5933 printf("::: num_move_steps == %d, max_move_delay == %d, max_step_delay == %d\n", num_move_steps, max_move_delay, max_step_delay);
5936 for (k = 0; k < num_move_steps; k++)
5938 door_part_done_all = TRUE;
5940 for (i = 0; i < NUM_DOORS; i++)
5941 door_panel_drawn[i] = FALSE;
5943 for (i = 0; i < MAX_DOOR_PARTS; i++)
5945 int nr = door_part_order[i].nr;
5946 struct DoorPartControlInfo *dpc = &door_part_controls[nr];
5947 struct DoorPartPosInfo *pos = dpc->pos;
5948 struct GraphicInfo *g = &graphic_info[dpc->graphic];
5949 int door_token = dpc->door_token;
5950 int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
5951 boolean is_panel = DOOR_PART_IS_PANEL(nr);
5953 struct XY *panel_pos = &panel_pos_list[door_index];
5955 struct Rect *door_rect = &door_rect_list[door_index];
5956 Bitmap *bitmap_db_door = (door_token == DOOR_1 ? bitmap_db_door_1 :
5958 Bitmap *bitmap = (is_panel ? bitmap_db_door : g->bitmap);
5959 int current_door_state = door_state & door_token;
5960 boolean door_opening = ((current_door_state & DOOR_OPEN) != 0);
5961 boolean door_closing = !door_opening;
5962 boolean part_opening = (is_panel ? door_closing : door_opening);
5963 boolean part_closing = !part_opening;
5964 int start_step = (part_opening ? pos->start_step_opening :
5965 pos->start_step_closing);
5966 int step_delay = pos->step_delay;
5967 int step_factor = step_delay / max_step_delay;
5968 int k1 = (step_factor ? k / step_factor + 1 : k);
5969 int k2 = (part_opening ? k1 + start_step : num_steps[nr] - k1);
5970 int kk = (k2 < 0 ? 0 : k2);
5971 int src_x, src_y, src_xx, src_yy;
5972 int dst_x, dst_y, dst_xx, dst_yy;
5976 if (k == 0 && is_panel && door_token == DOOR_2)
5977 printf("::: %d, %d\n", g->width, g->height);
5981 if (DOOR_PART_IS_PANEL(nr))
5983 int start_step = pos->start_step;
5985 k2 = (door_closing ? k1 : num_steps[nr] - k1);// - start_step;
5986 kk = (k2 < 0 ? 0 : k2);
5992 if (nr != 16 && nr != 0)
6003 if (door_part_skip[nr])
6007 if (!(door_state & door_token))
6014 if (current_move_delay % step_delay)
6020 if (!door_panel_drawn[door_index])
6023 ClearRectangle(drawto, door_rect->x, door_rect->y,
6024 door_rect->width, door_rect->height);
6026 BlitBitmap(bitmap_db_door, drawto, panel_pos->x, panel_pos->y,
6027 door_rect->width, door_rect->height,
6028 door_rect->x, door_rect->y);
6031 door_panel_drawn[door_index] = TRUE;
6034 // draw opening or closing door parts
6036 if (pos->step_xoffset < 0) // door part on right side
6039 dst_xx = pos->x + ABS(kk * pos->step_xoffset);
6042 if (dst_xx + width > door_rect->width)
6043 width = door_rect->width - dst_xx;
6045 else // door part on left side
6048 dst_xx = pos->x - kk * pos->step_xoffset;
6052 src_xx = ABS(dst_xx);
6056 width = g->width - src_xx;
6058 // printf("::: k == %d [%d] \n", k, start_step);
6061 if (pos->step_yoffset < 0) // door part on bottom side
6064 dst_yy = pos->y + ABS(kk * pos->step_yoffset);
6067 if (dst_yy + height > door_rect->height)
6068 height = door_rect->height - dst_yy;
6070 else // door part on top side
6073 dst_yy = pos->y - kk * pos->step_yoffset;
6077 src_yy = ABS(dst_yy);
6081 height = g->height - src_yy;
6090 src_x = panel_pos->x + src_xx;
6091 src_y = panel_pos->y + src_yy;
6096 src_x = g->src_x + src_xx;
6097 src_y = g->src_y + src_yy;
6100 dst_x = door_rect->x + dst_xx;
6101 dst_y = door_rect->y + dst_yy;
6104 if (DOOR_PART_IS_PANEL(nr))
6106 printf("::: width == %d, height == %d [%d, %d] [%d, %d]\n",
6107 width, height, g->width, g->height, src_x, src_y);
6111 if (width >= 0 && width <= g->width &&
6112 height >= 0 && height <= g->height)
6114 if (is_panel || !pos->draw_masked)
6115 BlitBitmap(bitmap, drawto, src_x, src_y, width, height,
6118 BlitBitmapMasked(bitmap, drawto, src_x, src_y, width, height,
6123 if (DOOR_PART_IS_PANEL(nr))
6125 bitmap = bitmap_db_door;
6126 src_x = panel_pos->x + src_xx;
6127 src_y = panel_pos->y + src_yy;
6129 printf("::: width == %d, height == %d [%d, %d] [%d, %d]\n",
6130 width, height, g->width, g->height, src_x, src_y);
6132 if (width >= 0 && width <= g->width &&
6133 height >= 0 && height <= g->height)
6134 BlitBitmap(bitmap, drawto, src_x, src_y,
6140 redraw_mask |= REDRAW_DOOR_FROM_TOKEN(door_token);
6143 if ((part_opening && (width < 0 || height < 0)) ||
6144 (part_closing && (width >= g->width && height >= g->height)))
6145 door_part_done[nr] = TRUE;
6147 if ((door_opening && (width < 0 || height < 0)) ||
6148 (door_closing && (width >= g->width && height >= g->height)))
6149 door_part_done[nr] = TRUE;
6153 // continue door part animations, but not panel after door has closed
6154 if (!door_part_done[nr] &&
6155 !(is_panel && door_closing && panel_has_doors[door_index]))
6156 door_part_done_all = FALSE;
6158 // continue door part animations, but not panel after door has closed
6159 if (!door_part_done[nr] && !(is_panel && door_closing))
6160 door_part_done_all = FALSE;
6164 if (!door_part_done[nr])
6165 printf("::: k == %d, nr == %d\n", k, nr);
6169 if (!(door_state & DOOR_NO_DELAY))
6173 if (game_status == GAME_MODE_MAIN)
6176 WaitUntilDelayReached(&door_delay, door_delay_value);
6178 current_move_delay += max_step_delay;
6182 door_part_done_all = TRUE;
6184 for (i = 0; i < MAX_DOOR_PARTS; i++)
6185 if (!door_part_done[i] &&
6186 !(DOOR_PART_IS_PANEL(i) && door_closing))
6187 door_part_done_all = FALSE;
6190 if (door_part_done_all)
6196 if (door_state & DOOR_ACTION_1)
6197 door1 = door_state & DOOR_ACTION_1;
6198 if (door_state & DOOR_ACTION_2)
6199 door2 = door_state & DOOR_ACTION_2;
6202 printf("::: DOORS DONE %08x\n", door_state);
6204 printf("::: GO!\n");
6207 return (door1 | door2);
6212 // ========== OLD ==============================================================
6214 unsigned int MoveDoor(unsigned int door_state)
6216 static int door1 = DOOR_OPEN_1;
6217 static int door2 = DOOR_CLOSE_2;
6218 unsigned int door_delay = 0;
6219 unsigned int door_delay_value;
6223 if (door_1.width < 0 || door_1.width > DXSIZE)
6224 door_1.width = DXSIZE;
6225 if (door_1.height < 0 || door_1.height > DYSIZE)
6226 door_1.height = DYSIZE;
6227 if (door_2.width < 0 || door_2.width > VXSIZE)
6228 door_2.width = VXSIZE;
6229 if (door_2.height < 0 || door_2.height > VYSIZE)
6230 door_2.height = VYSIZE;
6233 if (door_state == DOOR_GET_STATE)
6234 return (door1 | door2);
6236 if (door_state & DOOR_SET_STATE)
6238 if (door_state & DOOR_ACTION_1)
6239 door1 = door_state & DOOR_ACTION_1;
6240 if (door_state & DOOR_ACTION_2)
6241 door2 = door_state & DOOR_ACTION_2;
6243 return (door1 | door2);
6246 if (!(door_state & DOOR_FORCE_REDRAW))
6248 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
6249 door_state &= ~DOOR_OPEN_1;
6250 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
6251 door_state &= ~DOOR_CLOSE_1;
6252 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
6253 door_state &= ~DOOR_OPEN_2;
6254 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
6255 door_state &= ~DOOR_CLOSE_2;
6258 door_delay_value = (door_state & DOOR_ACTION_1 ? door_1.step_delay :
6261 // door_delay_value *= 4; // !!! TEST ONLY !!!
6263 if (setup.quick_doors)
6265 stepsize = 20; /* must be chosen to always draw last frame */
6266 door_delay_value = 0;
6269 if (global.autoplay_leveldir)
6271 door_state |= DOOR_NO_DELAY;
6272 door_state &= ~DOOR_CLOSE_ALL;
6276 if (game_status == GAME_MODE_EDITOR)
6277 door_state |= DOOR_NO_DELAY;
6280 if (door_state & DOOR_ACTION)
6283 struct GraphicInfo *g1_left = &graphic_info[IMG_DOOR_1_WING_LEFT];
6284 struct GraphicInfo *g1_right = &graphic_info[IMG_DOOR_1_WING_RIGHT];
6285 struct GraphicInfo *g2_left = &graphic_info[IMG_DOOR_2_WING_LEFT];
6286 struct GraphicInfo *g2_right = &graphic_info[IMG_DOOR_2_WING_RIGHT];
6287 int door_1_left_width = g1_left->width;
6288 int door_1_left_height = g1_left->height;
6289 int door_1_right_width = g1_right->width;
6290 int door_1_right_height = g1_right->height;
6291 int door_2_left_width = g2_left->width;
6292 int door_2_left_height = g2_left->height;
6293 int door_2_right_width = g2_right->width;
6294 int door_2_right_height = g2_right->height;
6295 int door_1_width = MAX(door_1_left_width, door_1_right_width);
6296 int door_1_height = MAX(door_1_left_height, door_1_right_height);
6297 int door_2_width = MAX(door_2_left_width, door_2_right_width);
6298 int door_2_height = MAX(door_2_left_height, door_2_right_height);
6300 boolean handle_door_1 = (door_state & DOOR_ACTION_1);
6301 boolean handle_door_2 = (door_state & DOOR_ACTION_2);
6302 boolean door_1_done = (!handle_door_1);
6303 boolean door_2_done = (!handle_door_2);
6304 boolean door_1_vertical = (door_1.anim_mode & ANIM_VERTICAL);
6305 boolean door_2_vertical = (door_2.anim_mode & ANIM_VERTICAL);
6308 int door_size_1 = (door_1_vertical ? door_1_height : door_1_width);
6309 int door_size_2 = (door_2_vertical ? door_2_height : door_2_width);
6311 int door_size_1 = (door_1_vertical ? DYSIZE : DXSIZE);
6312 int door_size_2 = (door_2_vertical ? VYSIZE : VXSIZE);
6315 int door_size_1 = (door_1_vertical ? door_1.height : door_1.width);
6316 int door_size_2 = (door_2_vertical ? door_2.height : door_2.width);
6318 int max_door_size_1 = (door_1_vertical ? DYSIZE : DXSIZE);
6319 int max_door_size_2 = (door_2_vertical ? VYSIZE : VXSIZE);
6320 // int door_size = (handle_door_1 ? door_size_1 : door_size_2);
6321 int door_size = (handle_door_2 ? door_size_2 : door_size_1);
6322 int max_door_size = (handle_door_1 ? max_door_size_1 : max_door_size_2);
6323 int door_skip = max_door_size - door_size;
6324 int end = door_size;
6325 int start = ((door_state & DOOR_NO_DELAY) ? end : 0);
6328 if (!(door_state & DOOR_NO_DELAY) && !setup.quick_doors)
6330 /* opening door sound has priority over simultaneously closing door */
6331 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
6332 PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
6333 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
6334 PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
6337 for (k = start; k <= end && !(door_1_done && door_2_done); k += stepsize)
6341 Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
6342 GC gc = bitmap->stored_clip_gc;
6345 if (door_state & DOOR_ACTION_1 &&
6346 x * door_1.step_offset <= door_size_1)
6348 int a = MIN(x * door_1.step_offset, end);
6349 int p = (door_state & DOOR_OPEN_1 ? end - a : a);
6353 int i = p + door_skip;
6357 struct GraphicInfo *g_left = &graphic_info[IMG_DOOR_1_WING_LEFT];
6358 struct GraphicInfo *g_right = &graphic_info[IMG_DOOR_1_WING_RIGHT];
6359 Bitmap *bm_left = g_left->bitmap;
6360 Bitmap *bm_right = g_right->bitmap;
6361 GC gc_left = bm_left->stored_clip_gc;
6362 GC gc_right = bm_right->stored_clip_gc;
6365 int classic_dxsize = 100;
6366 int classic_dysize = 280;
6367 boolean classic_door_1_size = (DXSIZE == classic_dxsize &&
6368 DYSIZE == classic_dysize);
6370 if (door_1.anim_mode & ANIM_STATIC_PANEL)
6372 BlitBitmap(bitmap_db_door, drawto,
6373 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1,
6374 DXSIZE, DYSIZE, DX, DY);
6378 BlitBitmap(bitmap_db_door, drawto,
6379 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + p / 2,
6380 DXSIZE, DYSIZE - p / 2, DX, DY);
6383 // printf("::: p == %d\n", p);
6384 ClearRectangle(drawto, DX, DY + DYSIZE - p / 2, DXSIZE, p / 2);
6388 if (door_1.anim_mode & ANIM_HORIZONTAL && x <= DXSIZE)
6391 int src1_x = g_right->src_x;
6392 int src1_y = g_right->src_y;
6393 int src2_x = g_left->src_x + g_left->width - i;
6394 int src2_y = g_left->src_y;
6395 int dst1_x = DX + DXSIZE - i;
6400 int height = DYSIZE;
6402 SetClipOrigin(bm_right, gc_right, dst1_x - src1_x, dst1_y - src1_y);
6403 BlitBitmapMasked(bm_right, drawto, src1_x, src1_y, width, height,
6406 SetClipOrigin(bm_left, gc_left, dst2_x - src2_x, dst2_y - src2_y);
6407 BlitBitmapMasked(bm_left, drawto, src2_x, src2_y, width, height,
6410 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
6411 int src2_x = DXSIZE - i, src2_y = DOOR_GFX_PAGEY1;
6412 int dst1_x = DX + DXSIZE - i, dst1_y = DY;
6413 int dst2_x = DX, dst2_y = DY;
6414 int width = i, height = DYSIZE;
6416 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
6417 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
6420 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
6421 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
6425 else if (door_1.anim_mode & ANIM_VERTICAL && x <= DYSIZE)
6428 int src1_x = g_right->src_x;
6429 int src1_y = g_right->src_y;
6430 int src2_x = g_left->src_x;
6431 int src2_y = g_left->src_y + g_left->height - i;
6433 int dst1_y = DY + DYSIZE - i;
6439 SetClipOrigin(bm_right, gc_right, dst1_x - src1_x, dst1_y - src1_y);
6440 BlitBitmapMasked(bm_right, drawto, src1_x, src1_y, width, height,
6443 SetClipOrigin(bm_left, gc_left, dst2_x - src2_x, dst2_y - src2_y);
6444 BlitBitmapMasked(bm_left, drawto, src2_x, src2_y, width, height,
6447 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
6448 int src2_x = 0, src2_y = DOOR_GFX_PAGEY1 + DYSIZE - i;
6449 int dst1_x = DX, dst1_y = DY + DYSIZE - i;
6450 int dst2_x = DX, dst2_y = DY;
6451 int width = DXSIZE, height = i;
6453 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
6454 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
6457 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
6458 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
6462 else if (classic_door_1_size && x <= DXSIZE) /* ANIM_DEFAULT */
6464 int j = (door_1.anim_mode == ANIM_DEFAULT ? (DXSIZE - i) / 3 : 0);
6467 int src1_x = g_right->src_x;
6468 int src1_y = g_right->src_y;
6469 int src2_x = g_left->src_x + g_left->width - i;
6470 int src2_y = g_left->src_y;
6471 int dst1_x = DX + DXSIZE - i;
6476 int height1 = 63, height2 = DYSIZE / 2 - height1;
6477 int ypos1 = 0, ypos2 = height2;
6478 int ypos3 = DYSIZE / 2, ypos4 = DYSIZE - height2;
6480 SetClipOrigin(bm_right, gc_right,
6481 dst1_x - src1_x, dst1_y - src1_y + j);
6482 BlitBitmapMasked(bm_right, drawto,
6483 src1_x, src1_y + ypos1, width, height2,
6484 dst1_x, dst1_y + ypos1 + j);
6485 BlitBitmapMasked(bm_right, drawto,
6486 src1_x, src1_y + ypos3, width, height1,
6487 dst1_x, dst1_y + ypos3 + j);
6488 SetClipOrigin(bm_left, gc_left,
6489 dst2_x - src2_x, dst2_y - src2_y - j);
6490 BlitBitmapMasked(bm_left, drawto,
6491 src2_x, src2_y + ypos1 + j, width, height2 - j,
6492 dst2_x, dst2_y + ypos1);
6493 BlitBitmapMasked(bm_left, drawto,
6494 src2_x, src2_y + ypos3, width, height1,
6495 dst2_x, dst2_y + ypos3 - j);
6497 SetClipOrigin(bm_left, gc_left,
6498 dst2_x - src2_x, dst2_y - src2_y - j);
6499 BlitBitmapMasked(bm_left, drawto,
6500 src2_x, src2_y + ypos2, width, height1,
6501 dst2_x, dst2_y + ypos2 - j);
6502 BlitBitmapMasked(bm_left, drawto,
6503 src2_x, src2_y + ypos4, width, height2,
6504 dst2_x, dst2_y + ypos4 - j);
6505 SetClipOrigin(bm_right, gc_right,
6506 dst1_x - src1_x, dst1_y - src1_y + j);
6507 BlitBitmapMasked(bm_right, drawto,
6508 src1_x, src1_y + ypos2, width, height1,
6509 dst1_x, dst1_y + ypos2 + j);
6510 BlitBitmapMasked(bm_right, drawto,
6511 src1_x, src1_y + ypos4, width, height2 - j,
6512 dst1_x, dst1_y + ypos4 + j);
6515 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
6516 int src2_x = DXSIZE - i, src2_y = DOOR_GFX_PAGEY1;
6517 int dst1_x = DX + DXSIZE - i, dst1_y = DY;
6518 int dst2_x = DX, dst2_y = DY;
6519 int width = i, height = DYSIZE;
6520 int ypos1 = 63, ypos2 = 77, ypos3 = 140, ypos4 = 203;
6522 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y + j);
6523 BlitBitmapMasked(bitmap, drawto,
6524 src1_x, src1_y, width, ypos2,
6525 dst1_x, dst1_y + j);
6526 BlitBitmapMasked(bitmap, drawto,
6527 src1_x, src1_y + ypos3, width, ypos1,
6528 dst1_x, dst1_y + ypos3 + j);
6529 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y - j);
6530 BlitBitmapMasked(bitmap, drawto,
6531 src2_x, src2_y + j, width, ypos2 - j,
6533 BlitBitmapMasked(bitmap, drawto,
6534 src2_x, src2_y + ypos3, width, ypos1,
6535 dst2_x, dst2_y + ypos3 - j);
6537 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y - j);
6538 BlitBitmapMasked(bitmap, drawto,
6539 src2_x, src2_y + ypos2, width, ypos1,
6540 dst2_x, dst2_y + ypos2 - j);
6541 BlitBitmapMasked(bitmap, drawto,
6542 src2_x, src2_y + ypos4, width, ypos2,
6543 dst2_x, dst2_y + ypos4 - j);
6544 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y + j);
6545 BlitBitmapMasked(bitmap, drawto,
6546 src1_x, src1_y + ypos2, width, ypos1,
6547 dst1_x, dst1_y + ypos2 + j);
6548 BlitBitmapMasked(bitmap, drawto,
6549 src1_x, src1_y + ypos4, width, ypos2 - j,
6550 dst1_x, dst1_y + ypos4 + j);
6553 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
6554 BlitBitmapMasked(bitmap, drawto,
6555 DXSIZE, DOOR_GFX_PAGEY1, i, 77,
6556 DX + DXSIZE - i, DY + j);
6557 BlitBitmapMasked(bitmap, drawto,
6558 DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
6559 DX + DXSIZE - i, DY + 140 + j);
6560 SetClipOrigin(bitmap, gc, DX - DXSIZE + i,
6561 DY - (DOOR_GFX_PAGEY1 + j));
6562 BlitBitmapMasked(bitmap, drawto,
6563 DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
6565 BlitBitmapMasked(bitmap, drawto,
6566 DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
6569 BlitBitmapMasked(bitmap, drawto,
6570 DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
6572 BlitBitmapMasked(bitmap, drawto,
6573 DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
6575 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
6576 BlitBitmapMasked(bitmap, drawto,
6577 DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
6578 DX + DXSIZE - i, DY + 77 + j);
6579 BlitBitmapMasked(bitmap, drawto,
6580 DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
6581 DX + DXSIZE - i, DY + 203 + j);
6586 redraw_mask |= REDRAW_DOOR_1;
6587 door_1_done = (a == end);
6590 if (door_state & DOOR_ACTION_2 &&
6591 x * door_2.step_offset <= door_size_2)
6593 int a = MIN(x * door_2.step_offset, door_size);
6594 int p = (door_state & DOOR_OPEN_2 ? door_size - a : a);
6595 int i = p + door_skip;
6598 struct GraphicInfo *g_left = &graphic_info[IMG_DOOR_2_WING_LEFT];
6599 struct GraphicInfo *g_right = &graphic_info[IMG_DOOR_2_WING_RIGHT];
6600 Bitmap *bm_left = g_left->bitmap;
6601 Bitmap *bm_right = g_right->bitmap;
6602 GC gc_left = bm_left->stored_clip_gc;
6603 GC gc_right = bm_right->stored_clip_gc;
6606 int classic_vxsize = 100;
6607 int classic_vysize = 100;
6608 boolean classic_door_2_size = (VXSIZE == classic_vxsize &&
6609 VYSIZE == classic_vysize);
6611 if (door_2.anim_mode & ANIM_STATIC_PANEL)
6613 BlitBitmap(bitmap_db_door, drawto,
6614 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2,
6615 VXSIZE, VYSIZE, VX, VY);
6617 else if (x <= VYSIZE)
6619 BlitBitmap(bitmap_db_door, drawto,
6620 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + p / 2,
6621 VXSIZE, VYSIZE - p / 2, VX, VY);
6623 ClearRectangle(drawto, VX, VY + VYSIZE - p / 2, VXSIZE, p / 2);
6626 if (door_2.anim_mode & ANIM_HORIZONTAL && x <= VXSIZE)
6629 int src1_x = g_right->src_x;
6630 int src1_y = g_right->src_y;
6631 int src2_x = g_left->src_x + g_left->width - i;
6632 int src2_y = g_left->src_y;
6633 int dst1_x = VX + VXSIZE - i;
6638 int height = VYSIZE;
6640 SetClipOrigin(bm_right, gc_right, dst1_x - src1_x, dst1_y - src1_y);
6641 BlitBitmapMasked(bm_right, drawto, src1_x, src1_y, width, height,
6644 SetClipOrigin(bm_left, gc_left, dst2_x - src2_x, dst2_y - src2_y);
6645 BlitBitmapMasked(bm_left, drawto, src2_x, src2_y, width, height,
6648 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
6649 int src2_x = VXSIZE - i, src2_y = DOOR_GFX_PAGEY2;
6650 int dst1_x = VX + VXSIZE - i, dst1_y = VY;
6651 int dst2_x = VX, dst2_y = VY;
6652 int width = i, height = VYSIZE;
6654 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
6655 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
6658 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
6659 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
6663 else if (door_2.anim_mode & ANIM_VERTICAL && x <= VYSIZE)
6666 int src1_x = g_right->src_x;
6667 int src1_y = g_right->src_y;
6668 int src2_x = g_left->src_x;
6669 int src2_y = g_left->src_y + g_left->height - i;
6671 int dst1_y = VY + VYSIZE - i;
6677 SetClipOrigin(bm_right, gc_right, dst1_x - src1_x, dst1_y - src1_y);
6678 BlitBitmapMasked(bm_right, drawto, src1_x, src1_y, width, height,
6681 SetClipOrigin(bm_left, gc_left, dst2_x - src2_x, dst2_y - src2_y);
6682 BlitBitmapMasked(bm_left, drawto, src2_x, src2_y, width, height,
6685 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
6686 int src2_x = 0, src2_y = DOOR_GFX_PAGEY2 + VYSIZE - i;
6687 int dst1_x = VX, dst1_y = VY + VYSIZE - i;
6688 int dst2_x = VX, dst2_y = VY;
6689 int width = VXSIZE, height = i;
6691 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
6692 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
6695 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
6696 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
6700 else if (classic_door_2_size && x <= VXSIZE) /* ANIM_DEFAULT */
6702 int j = (door_2.anim_mode == ANIM_DEFAULT ? (VXSIZE - i) / 3 : 0);
6705 int src1_x = g_right->src_x;
6706 int src1_y = g_right->src_y;
6707 int src2_x = g_left->src_x + g_left->width - i;
6708 int src2_y = g_left->src_y;
6709 int dst1_x = VX + VXSIZE - i;
6714 int height = VYSIZE / 2;
6715 int ypos1 = 0, ypos2 = VYSIZE / 2;
6717 SetClipOrigin(bm_right, gc_right,
6718 dst1_x - src1_x, dst1_y - src1_y + j);
6719 BlitBitmapMasked(bm_right, drawto,
6720 src1_x, src1_y + ypos1, width, height,
6721 dst1_x, dst1_y + ypos1 + j);
6722 SetClipOrigin(bm_left, gc_left,
6723 dst2_x - src2_x, dst2_y - src2_y - j);
6724 BlitBitmapMasked(bm_left, drawto,
6725 src2_x, src2_y + ypos1 + j, width, height - j,
6726 dst2_x, dst2_y + ypos1);
6728 SetClipOrigin(bm_left, gc_left,
6729 dst2_x - src2_x, dst2_y - src2_y - j);
6730 BlitBitmapMasked(bm_left, drawto,
6731 src2_x, src2_y + ypos2, width, height,
6732 dst2_x, dst2_y + ypos2 - j);
6733 SetClipOrigin(bm_right, gc_right,
6734 dst1_x - src1_x, dst1_y - src1_y + j);
6735 BlitBitmapMasked(bm_right, drawto,
6736 src1_x, src1_y + ypos2, width, height - j,
6737 dst1_x, dst1_y + ypos2 + j);
6739 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
6740 int src2_x = VXSIZE - i, src2_y = DOOR_GFX_PAGEY2;
6741 int dst1_x = VX + VXSIZE - i, dst1_y = VY;
6742 int dst2_x = VX, dst2_y = VY;
6743 int width = i, height = VYSIZE;
6744 int ypos = VYSIZE / 2;
6746 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y + j);
6747 BlitBitmapMasked(bitmap, drawto,
6748 src1_x, src1_y, width, ypos,
6749 dst1_x, dst1_y + j);
6750 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src1_y - j);
6751 BlitBitmapMasked(bitmap, drawto,
6752 src2_x, src2_y + j, width, ypos - j,
6755 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src1_y - j);
6756 BlitBitmapMasked(bitmap, drawto,
6757 src2_x, src2_y + ypos, width, ypos,
6758 dst2_x, dst2_y + ypos - j);
6759 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y + j);
6760 BlitBitmapMasked(bitmap, drawto,
6761 src1_x, src1_y + ypos, width, ypos - j,
6762 dst1_x, dst1_y + ypos + j);
6765 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
6766 BlitBitmapMasked(bitmap, drawto,
6767 VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
6768 VX + VXSIZE - i, VY + j);
6769 SetClipOrigin(bitmap, gc,
6770 VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
6771 BlitBitmapMasked(bitmap, drawto,
6772 VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
6775 BlitBitmapMasked(bitmap, drawto,
6776 VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
6777 i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
6778 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
6779 BlitBitmapMasked(bitmap, drawto,
6780 VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
6782 VX + VXSIZE - i, VY + VYSIZE / 2 + j);
6787 redraw_mask |= REDRAW_DOOR_2;
6788 door_2_done = (a == VXSIZE);
6791 if (!(door_state & DOOR_NO_DELAY))
6795 if (game_status == GAME_MODE_MAIN)
6798 WaitUntilDelayReached(&door_delay, door_delay_value);
6803 if (door_state & DOOR_ACTION_1)
6804 door1 = door_state & DOOR_ACTION_1;
6805 if (door_state & DOOR_ACTION_2)
6806 door2 = door_state & DOOR_ACTION_2;
6808 return (door1 | door2);
6813 void DrawSpecialEditorDoor()
6816 struct GraphicInfo *gfx1 = &graphic_info[IMG_DOOR_2_TOP_BORDER_CORRECTION];
6817 int top_border_width = gfx1->width;
6818 int top_border_height = gfx1->height;
6819 int outer_border = viewport.door_2[GAME_MODE_EDITOR].border_size;
6820 int ex = EX - outer_border;
6821 int ey = EY - outer_border;
6822 int vy = VY - outer_border;
6823 int exsize = EXSIZE + 2 * outer_border;
6825 CloseDoor(DOOR_CLOSE_2);
6827 /* draw bigger level editor toolbox window */
6828 BlitBitmap(gfx1->bitmap, drawto, gfx1->src_x, gfx1->src_y,
6829 top_border_width, top_border_height, ex, ey - top_border_height);
6830 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto, ex, vy,
6831 exsize, EYSIZE - VYSIZE + outer_border, ex, ey);
6833 /* draw bigger level editor toolbox window */
6834 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
6835 DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
6837 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
6838 EX - 6, VY - 4, EXSIZE + 12, EYSIZE - VYSIZE + 4,
6842 redraw_mask |= REDRAW_ALL;
6845 void UndrawSpecialEditorDoor()
6848 struct GraphicInfo *gfx1 = &graphic_info[IMG_DOOR_2_TOP_BORDER_CORRECTION];
6849 int top_border_width = gfx1->width;
6850 int top_border_height = gfx1->height;
6851 int outer_border = viewport.door_2[GAME_MODE_EDITOR].border_size;
6852 int ex = EX - outer_border;
6853 int ey = EY - outer_border;
6854 int ey_top = ey - top_border_height;
6855 int exsize = EXSIZE + 2 * outer_border;
6856 int eysize = EYSIZE + 2 * outer_border;
6858 /* draw normal tape recorder window */
6859 if (graphic_info[IMG_GLOBAL_BORDER].bitmap)
6861 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
6862 ex, ey_top, top_border_width, top_border_height,
6864 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
6865 ex, ey, exsize, eysize, ex, ey);
6869 // if screen background is set to "[NONE]", clear editor toolbox window
6870 ClearRectangle(drawto, ex, ey_top, top_border_width, top_border_height);
6871 ClearRectangle(drawto, ex, ey, exsize, eysize);
6874 /* draw normal tape recorder window */
6875 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
6876 EX - 6, EY - 12, EXSIZE + 12, EYSIZE - VYSIZE + 12,
6880 redraw_mask |= REDRAW_ALL;
6884 /* ---------- new tool button stuff ---------------------------------------- */
6891 struct TextPosInfo *pos;
6894 } toolbutton_info[NUM_TOOL_BUTTONS] =
6897 IMG_REQUEST_BUTTON_GFX_YES, &request.button.yes,
6898 TOOL_CTRL_ID_YES, "yes"
6901 IMG_REQUEST_BUTTON_GFX_NO, &request.button.no,
6902 TOOL_CTRL_ID_NO, "no"
6905 IMG_REQUEST_BUTTON_GFX_CONFIRM, &request.button.confirm,
6906 TOOL_CTRL_ID_CONFIRM, "confirm"
6909 IMG_REQUEST_BUTTON_GFX_PLAYER_1, &request.button.player_1,
6910 TOOL_CTRL_ID_PLAYER_1, "player 1"
6913 IMG_REQUEST_BUTTON_GFX_PLAYER_2, &request.button.player_2,
6914 TOOL_CTRL_ID_PLAYER_2, "player 2"
6917 IMG_REQUEST_BUTTON_GFX_PLAYER_3, &request.button.player_3,
6918 TOOL_CTRL_ID_PLAYER_3, "player 3"
6921 IMG_REQUEST_BUTTON_GFX_PLAYER_4, &request.button.player_4,
6922 TOOL_CTRL_ID_PLAYER_4, "player 4"
6926 void CreateToolButtons()
6930 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
6932 struct GraphicInfo *gfx = &graphic_info[toolbutton_info[i].graphic];
6933 struct TextPosInfo *pos = toolbutton_info[i].pos;
6934 struct GadgetInfo *gi;
6935 Bitmap *deco_bitmap = None;
6936 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
6937 unsigned int event_mask = GD_EVENT_RELEASED;
6940 int gd_x = gfx->src_x;
6941 int gd_y = gfx->src_y;
6942 int gd_xp = gfx->src_x + gfx->pressed_xoffset;
6943 int gd_yp = gfx->src_y + gfx->pressed_yoffset;
6946 if (global.use_envelope_request)
6947 setRequestPosition(&dx, &dy, TRUE);
6949 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
6951 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
6953 getSizedGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr), 0,
6954 pos->size, &deco_bitmap, &deco_x, &deco_y);
6955 deco_xpos = (gfx->width - pos->size) / 2;
6956 deco_ypos = (gfx->height - pos->size) / 2;
6959 gi = CreateGadget(GDI_CUSTOM_ID, id,
6960 GDI_INFO_TEXT, toolbutton_info[i].infotext,
6961 GDI_X, dx + GDI_ACTIVE_POS(pos->x),
6962 GDI_Y, dy + GDI_ACTIVE_POS(pos->y),
6963 GDI_WIDTH, gfx->width,
6964 GDI_HEIGHT, gfx->height,
6965 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
6966 GDI_STATE, GD_BUTTON_UNPRESSED,
6967 GDI_DESIGN_UNPRESSED, gfx->bitmap, gd_x, gd_y,
6968 GDI_DESIGN_PRESSED, gfx->bitmap, gd_xp, gd_yp,
6969 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
6970 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
6971 GDI_DECORATION_SIZE, pos->size, pos->size,
6972 GDI_DECORATION_SHIFTING, 1, 1,
6973 GDI_DIRECT_DRAW, FALSE,
6974 GDI_EVENT_MASK, event_mask,
6975 GDI_CALLBACK_ACTION, HandleToolButtons,
6979 Error(ERR_EXIT, "cannot create gadget");
6981 tool_gadget[id] = gi;
6987 /* graphic position values for tool buttons */
6988 #define TOOL_BUTTON_YES_XPOS 2
6989 #define TOOL_BUTTON_YES_YPOS 250
6990 #define TOOL_BUTTON_YES_GFX_YPOS 0
6991 #define TOOL_BUTTON_YES_XSIZE 46
6992 #define TOOL_BUTTON_YES_YSIZE 28
6993 #define TOOL_BUTTON_NO_XPOS 52
6994 #define TOOL_BUTTON_NO_YPOS TOOL_BUTTON_YES_YPOS
6995 #define TOOL_BUTTON_NO_GFX_YPOS TOOL_BUTTON_YES_GFX_YPOS
6996 #define TOOL_BUTTON_NO_XSIZE TOOL_BUTTON_YES_XSIZE
6997 #define TOOL_BUTTON_NO_YSIZE TOOL_BUTTON_YES_YSIZE
6998 #define TOOL_BUTTON_CONFIRM_XPOS TOOL_BUTTON_YES_XPOS
6999 #define TOOL_BUTTON_CONFIRM_YPOS TOOL_BUTTON_YES_YPOS
7000 #define TOOL_BUTTON_CONFIRM_GFX_YPOS 30
7001 #define TOOL_BUTTON_CONFIRM_XSIZE 96
7002 #define TOOL_BUTTON_CONFIRM_YSIZE TOOL_BUTTON_YES_YSIZE
7003 #define TOOL_BUTTON_PLAYER_XSIZE 30
7004 #define TOOL_BUTTON_PLAYER_YSIZE 30
7005 #define TOOL_BUTTON_PLAYER_GFX_XPOS 5
7006 #define TOOL_BUTTON_PLAYER_GFX_YPOS 185
7007 #define TOOL_BUTTON_PLAYER_XPOS (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
7008 #define TOOL_BUTTON_PLAYER_YPOS (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
7009 #define TOOL_BUTTON_PLAYER1_XPOS (TOOL_BUTTON_PLAYER_XPOS \
7010 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
7011 #define TOOL_BUTTON_PLAYER2_XPOS (TOOL_BUTTON_PLAYER_XPOS \
7012 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
7013 #define TOOL_BUTTON_PLAYER3_XPOS (TOOL_BUTTON_PLAYER_XPOS \
7014 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
7015 #define TOOL_BUTTON_PLAYER4_XPOS (TOOL_BUTTON_PLAYER_XPOS \
7016 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
7017 #define TOOL_BUTTON_PLAYER1_YPOS (TOOL_BUTTON_PLAYER_YPOS \
7018 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
7019 #define TOOL_BUTTON_PLAYER2_YPOS (TOOL_BUTTON_PLAYER_YPOS \
7020 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
7021 #define TOOL_BUTTON_PLAYER3_YPOS (TOOL_BUTTON_PLAYER_YPOS \
7022 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
7023 #define TOOL_BUTTON_PLAYER4_YPOS (TOOL_BUTTON_PLAYER_YPOS \
7024 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
7033 } toolbutton_info[NUM_TOOL_BUTTONS] =
7036 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_GFX_YPOS,
7037 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_YPOS,
7038 TOOL_BUTTON_YES_XSIZE, TOOL_BUTTON_YES_YSIZE,
7043 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_GFX_YPOS,
7044 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_YPOS,
7045 TOOL_BUTTON_NO_XSIZE, TOOL_BUTTON_NO_YSIZE,
7050 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_GFX_YPOS,
7051 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_YPOS,
7052 TOOL_BUTTON_CONFIRM_XSIZE, TOOL_BUTTON_CONFIRM_YSIZE,
7053 TOOL_CTRL_ID_CONFIRM,
7057 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
7058 TOOL_BUTTON_PLAYER1_XPOS, TOOL_BUTTON_PLAYER1_YPOS,
7059 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
7060 TOOL_CTRL_ID_PLAYER_1,
7064 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
7065 TOOL_BUTTON_PLAYER2_XPOS, TOOL_BUTTON_PLAYER2_YPOS,
7066 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
7067 TOOL_CTRL_ID_PLAYER_2,
7071 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
7072 TOOL_BUTTON_PLAYER3_XPOS, TOOL_BUTTON_PLAYER3_YPOS,
7073 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
7074 TOOL_CTRL_ID_PLAYER_3,
7078 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
7079 TOOL_BUTTON_PLAYER4_XPOS, TOOL_BUTTON_PLAYER4_YPOS,
7080 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
7081 TOOL_CTRL_ID_PLAYER_4,
7086 void CreateToolButtons()
7090 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
7092 Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
7093 Bitmap *deco_bitmap = None;
7094 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
7095 struct GadgetInfo *gi;
7096 unsigned int event_mask;
7097 int gd_xoffset, gd_yoffset;
7098 int gd_x1, gd_x2, gd_y;
7101 event_mask = GD_EVENT_RELEASED;
7103 gd_xoffset = toolbutton_info[i].xpos;
7104 gd_yoffset = toolbutton_info[i].ypos;
7105 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
7106 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
7107 gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
7109 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
7111 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
7113 getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr),
7114 &deco_bitmap, &deco_x, &deco_y);
7115 deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
7116 deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
7119 gi = CreateGadget(GDI_CUSTOM_ID, id,
7120 GDI_INFO_TEXT, toolbutton_info[i].infotext,
7121 GDI_X, DX + GDI_ACTIVE_POS(toolbutton_info[i].x),
7122 GDI_Y, DY + GDI_ACTIVE_POS(toolbutton_info[i].y),
7123 GDI_WIDTH, toolbutton_info[i].width,
7124 GDI_HEIGHT, toolbutton_info[i].height,
7125 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
7126 GDI_STATE, GD_BUTTON_UNPRESSED,
7127 GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
7128 GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
7129 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
7130 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
7131 GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
7132 GDI_DECORATION_SHIFTING, 1, 1,
7133 GDI_DIRECT_DRAW, FALSE,
7134 GDI_EVENT_MASK, event_mask,
7135 GDI_CALLBACK_ACTION, HandleToolButtons,
7139 Error(ERR_EXIT, "cannot create gadget");
7141 tool_gadget[id] = gi;
7147 void FreeToolButtons()
7151 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
7152 FreeGadget(tool_gadget[i]);
7155 static void UnmapToolButtons()
7159 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
7160 UnmapGadget(tool_gadget[i]);
7163 static void HandleToolButtons(struct GadgetInfo *gi)
7165 request_gadget_id = gi->custom_id;
7168 static struct Mapping_EM_to_RND_object
7171 boolean is_rnd_to_em_mapping; /* unique mapping EM <-> RND */
7172 boolean is_backside; /* backside of moving element */
7178 em_object_mapping_list[] =
7181 Xblank, TRUE, FALSE,
7185 Yacid_splash_eB, FALSE, FALSE,
7186 EL_ACID_SPLASH_RIGHT, -1, -1
7189 Yacid_splash_wB, FALSE, FALSE,
7190 EL_ACID_SPLASH_LEFT, -1, -1
7193 #ifdef EM_ENGINE_BAD_ROLL
7195 Xstone_force_e, FALSE, FALSE,
7196 EL_ROCK, -1, MV_BIT_RIGHT
7199 Xstone_force_w, FALSE, FALSE,
7200 EL_ROCK, -1, MV_BIT_LEFT
7203 Xnut_force_e, FALSE, FALSE,
7204 EL_NUT, -1, MV_BIT_RIGHT
7207 Xnut_force_w, FALSE, FALSE,
7208 EL_NUT, -1, MV_BIT_LEFT
7211 Xspring_force_e, FALSE, FALSE,
7212 EL_SPRING, -1, MV_BIT_RIGHT
7215 Xspring_force_w, FALSE, FALSE,
7216 EL_SPRING, -1, MV_BIT_LEFT
7219 Xemerald_force_e, FALSE, FALSE,
7220 EL_EMERALD, -1, MV_BIT_RIGHT
7223 Xemerald_force_w, FALSE, FALSE,
7224 EL_EMERALD, -1, MV_BIT_LEFT
7227 Xdiamond_force_e, FALSE, FALSE,
7228 EL_DIAMOND, -1, MV_BIT_RIGHT
7231 Xdiamond_force_w, FALSE, FALSE,
7232 EL_DIAMOND, -1, MV_BIT_LEFT
7235 Xbomb_force_e, FALSE, FALSE,
7236 EL_BOMB, -1, MV_BIT_RIGHT
7239 Xbomb_force_w, FALSE, FALSE,
7240 EL_BOMB, -1, MV_BIT_LEFT
7242 #endif /* EM_ENGINE_BAD_ROLL */
7245 Xstone, TRUE, FALSE,
7249 Xstone_pause, FALSE, FALSE,
7253 Xstone_fall, FALSE, FALSE,
7257 Ystone_s, FALSE, FALSE,
7258 EL_ROCK, ACTION_FALLING, -1
7261 Ystone_sB, FALSE, TRUE,
7262 EL_ROCK, ACTION_FALLING, -1
7265 Ystone_e, FALSE, FALSE,
7266 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
7269 Ystone_eB, FALSE, TRUE,
7270 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
7273 Ystone_w, FALSE, FALSE,
7274 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
7277 Ystone_wB, FALSE, TRUE,
7278 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
7285 Xnut_pause, FALSE, FALSE,
7289 Xnut_fall, FALSE, FALSE,
7293 Ynut_s, FALSE, FALSE,
7294 EL_NUT, ACTION_FALLING, -1
7297 Ynut_sB, FALSE, TRUE,
7298 EL_NUT, ACTION_FALLING, -1
7301 Ynut_e, FALSE, FALSE,
7302 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
7305 Ynut_eB, FALSE, TRUE,
7306 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
7309 Ynut_w, FALSE, FALSE,
7310 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
7313 Ynut_wB, FALSE, TRUE,
7314 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
7317 Xbug_n, TRUE, FALSE,
7321 Xbug_e, TRUE, FALSE,
7322 EL_BUG_RIGHT, -1, -1
7325 Xbug_s, TRUE, FALSE,
7329 Xbug_w, TRUE, FALSE,
7333 Xbug_gon, FALSE, FALSE,
7337 Xbug_goe, FALSE, FALSE,
7338 EL_BUG_RIGHT, -1, -1
7341 Xbug_gos, FALSE, FALSE,
7345 Xbug_gow, FALSE, FALSE,
7349 Ybug_n, FALSE, FALSE,
7350 EL_BUG, ACTION_MOVING, MV_BIT_UP
7353 Ybug_nB, FALSE, TRUE,
7354 EL_BUG, ACTION_MOVING, MV_BIT_UP
7357 Ybug_e, FALSE, FALSE,
7358 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
7361 Ybug_eB, FALSE, TRUE,
7362 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
7365 Ybug_s, FALSE, FALSE,
7366 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
7369 Ybug_sB, FALSE, TRUE,
7370 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
7373 Ybug_w, FALSE, FALSE,
7374 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
7377 Ybug_wB, FALSE, TRUE,
7378 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
7381 Ybug_w_n, FALSE, FALSE,
7382 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
7385 Ybug_n_e, FALSE, FALSE,
7386 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
7389 Ybug_e_s, FALSE, FALSE,
7390 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
7393 Ybug_s_w, FALSE, FALSE,
7394 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
7397 Ybug_e_n, FALSE, FALSE,
7398 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
7401 Ybug_s_e, FALSE, FALSE,
7402 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
7405 Ybug_w_s, FALSE, FALSE,
7406 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
7409 Ybug_n_w, FALSE, FALSE,
7410 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
7413 Ybug_stone, FALSE, FALSE,
7414 EL_BUG, ACTION_SMASHED_BY_ROCK, -1
7417 Ybug_spring, FALSE, FALSE,
7418 EL_BUG, ACTION_SMASHED_BY_SPRING, -1
7421 Xtank_n, TRUE, FALSE,
7422 EL_SPACESHIP_UP, -1, -1
7425 Xtank_e, TRUE, FALSE,
7426 EL_SPACESHIP_RIGHT, -1, -1
7429 Xtank_s, TRUE, FALSE,
7430 EL_SPACESHIP_DOWN, -1, -1
7433 Xtank_w, TRUE, FALSE,
7434 EL_SPACESHIP_LEFT, -1, -1
7437 Xtank_gon, FALSE, FALSE,
7438 EL_SPACESHIP_UP, -1, -1
7441 Xtank_goe, FALSE, FALSE,
7442 EL_SPACESHIP_RIGHT, -1, -1
7445 Xtank_gos, FALSE, FALSE,
7446 EL_SPACESHIP_DOWN, -1, -1
7449 Xtank_gow, FALSE, FALSE,
7450 EL_SPACESHIP_LEFT, -1, -1
7453 Ytank_n, FALSE, FALSE,
7454 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
7457 Ytank_nB, FALSE, TRUE,
7458 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
7461 Ytank_e, FALSE, FALSE,
7462 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
7465 Ytank_eB, FALSE, TRUE,
7466 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
7469 Ytank_s, FALSE, FALSE,
7470 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
7473 Ytank_sB, FALSE, TRUE,
7474 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
7477 Ytank_w, FALSE, FALSE,
7478 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
7481 Ytank_wB, FALSE, TRUE,
7482 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
7485 Ytank_w_n, FALSE, FALSE,
7486 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
7489 Ytank_n_e, FALSE, FALSE,
7490 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
7493 Ytank_e_s, FALSE, FALSE,
7494 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
7497 Ytank_s_w, FALSE, FALSE,
7498 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
7501 Ytank_e_n, FALSE, FALSE,
7502 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
7505 Ytank_s_e, FALSE, FALSE,
7506 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
7509 Ytank_w_s, FALSE, FALSE,
7510 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
7513 Ytank_n_w, FALSE, FALSE,
7514 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
7517 Ytank_stone, FALSE, FALSE,
7518 EL_SPACESHIP, ACTION_SMASHED_BY_ROCK, -1
7521 Ytank_spring, FALSE, FALSE,
7522 EL_SPACESHIP, ACTION_SMASHED_BY_SPRING, -1
7525 Xandroid, TRUE, FALSE,
7526 EL_EMC_ANDROID, ACTION_ACTIVE, -1
7529 Xandroid_1_n, FALSE, FALSE,
7530 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
7533 Xandroid_2_n, FALSE, FALSE,
7534 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
7537 Xandroid_1_e, FALSE, FALSE,
7538 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
7541 Xandroid_2_e, FALSE, FALSE,
7542 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
7545 Xandroid_1_w, FALSE, FALSE,
7546 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
7549 Xandroid_2_w, FALSE, FALSE,
7550 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
7553 Xandroid_1_s, FALSE, FALSE,
7554 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
7557 Xandroid_2_s, FALSE, FALSE,
7558 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
7561 Yandroid_n, FALSE, FALSE,
7562 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
7565 Yandroid_nB, FALSE, TRUE,
7566 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
7569 Yandroid_ne, FALSE, FALSE,
7570 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPRIGHT
7573 Yandroid_neB, FALSE, TRUE,
7574 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPRIGHT
7577 Yandroid_e, FALSE, FALSE,
7578 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
7581 Yandroid_eB, FALSE, TRUE,
7582 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
7585 Yandroid_se, FALSE, FALSE,
7586 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNRIGHT
7589 Yandroid_seB, FALSE, TRUE,
7590 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNRIGHT
7593 Yandroid_s, FALSE, FALSE,
7594 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
7597 Yandroid_sB, FALSE, TRUE,
7598 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
7601 Yandroid_sw, FALSE, FALSE,
7602 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNLEFT
7605 Yandroid_swB, FALSE, TRUE,
7606 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNLEFT
7609 Yandroid_w, FALSE, FALSE,
7610 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
7613 Yandroid_wB, FALSE, TRUE,
7614 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
7617 Yandroid_nw, FALSE, FALSE,
7618 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPLEFT
7621 Yandroid_nwB, FALSE, TRUE,
7622 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPLEFT
7625 Xspring, TRUE, FALSE,
7629 Xspring_pause, FALSE, FALSE,
7633 Xspring_e, FALSE, FALSE,
7637 Xspring_w, FALSE, FALSE,
7641 Xspring_fall, FALSE, FALSE,
7645 Yspring_s, FALSE, FALSE,
7646 EL_SPRING, ACTION_FALLING, -1
7649 Yspring_sB, FALSE, TRUE,
7650 EL_SPRING, ACTION_FALLING, -1
7653 Yspring_e, FALSE, FALSE,
7654 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
7657 Yspring_eB, FALSE, TRUE,
7658 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
7661 Yspring_w, FALSE, FALSE,
7662 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
7665 Yspring_wB, FALSE, TRUE,
7666 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
7669 Yspring_kill_e, FALSE, FALSE,
7670 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
7673 Yspring_kill_eB, FALSE, TRUE,
7674 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
7677 Yspring_kill_w, FALSE, FALSE,
7678 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
7681 Yspring_kill_wB, FALSE, TRUE,
7682 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
7685 Xeater_n, TRUE, FALSE,
7686 EL_YAMYAM_UP, -1, -1
7689 Xeater_e, TRUE, FALSE,
7690 EL_YAMYAM_RIGHT, -1, -1
7693 Xeater_w, TRUE, FALSE,
7694 EL_YAMYAM_LEFT, -1, -1
7697 Xeater_s, TRUE, FALSE,
7698 EL_YAMYAM_DOWN, -1, -1
7701 Yeater_n, FALSE, FALSE,
7702 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
7705 Yeater_nB, FALSE, TRUE,
7706 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
7709 Yeater_e, FALSE, FALSE,
7710 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
7713 Yeater_eB, FALSE, TRUE,
7714 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
7717 Yeater_s, FALSE, FALSE,
7718 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
7721 Yeater_sB, FALSE, TRUE,
7722 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
7725 Yeater_w, FALSE, FALSE,
7726 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
7729 Yeater_wB, FALSE, TRUE,
7730 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
7733 Yeater_stone, FALSE, FALSE,
7734 EL_YAMYAM, ACTION_SMASHED_BY_ROCK, -1
7737 Yeater_spring, FALSE, FALSE,
7738 EL_YAMYAM, ACTION_SMASHED_BY_SPRING, -1
7741 Xalien, TRUE, FALSE,
7745 Xalien_pause, FALSE, FALSE,
7749 Yalien_n, FALSE, FALSE,
7750 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
7753 Yalien_nB, FALSE, TRUE,
7754 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
7757 Yalien_e, FALSE, FALSE,
7758 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
7761 Yalien_eB, FALSE, TRUE,
7762 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
7765 Yalien_s, FALSE, FALSE,
7766 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
7769 Yalien_sB, FALSE, TRUE,
7770 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
7773 Yalien_w, FALSE, FALSE,
7774 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
7777 Yalien_wB, FALSE, TRUE,
7778 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
7781 Yalien_stone, FALSE, FALSE,
7782 EL_ROBOT, ACTION_SMASHED_BY_ROCK, -1
7785 Yalien_spring, FALSE, FALSE,
7786 EL_ROBOT, ACTION_SMASHED_BY_SPRING, -1
7789 Xemerald, TRUE, FALSE,
7793 Xemerald_pause, FALSE, FALSE,
7797 Xemerald_fall, FALSE, FALSE,
7801 Xemerald_shine, FALSE, FALSE,
7802 EL_EMERALD, ACTION_TWINKLING, -1
7805 Yemerald_s, FALSE, FALSE,
7806 EL_EMERALD, ACTION_FALLING, -1
7809 Yemerald_sB, FALSE, TRUE,
7810 EL_EMERALD, ACTION_FALLING, -1
7813 Yemerald_e, FALSE, FALSE,
7814 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
7817 Yemerald_eB, FALSE, TRUE,
7818 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
7821 Yemerald_w, FALSE, FALSE,
7822 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
7825 Yemerald_wB, FALSE, TRUE,
7826 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
7829 Yemerald_eat, FALSE, FALSE,
7830 EL_EMERALD, ACTION_COLLECTING, -1
7833 Yemerald_stone, FALSE, FALSE,
7834 EL_NUT, ACTION_BREAKING, -1
7837 Xdiamond, TRUE, FALSE,
7841 Xdiamond_pause, FALSE, FALSE,
7845 Xdiamond_fall, FALSE, FALSE,
7849 Xdiamond_shine, FALSE, FALSE,
7850 EL_DIAMOND, ACTION_TWINKLING, -1
7853 Ydiamond_s, FALSE, FALSE,
7854 EL_DIAMOND, ACTION_FALLING, -1
7857 Ydiamond_sB, FALSE, TRUE,
7858 EL_DIAMOND, ACTION_FALLING, -1
7861 Ydiamond_e, FALSE, FALSE,
7862 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
7865 Ydiamond_eB, FALSE, TRUE,
7866 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
7869 Ydiamond_w, FALSE, FALSE,
7870 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
7873 Ydiamond_wB, FALSE, TRUE,
7874 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
7877 Ydiamond_eat, FALSE, FALSE,
7878 EL_DIAMOND, ACTION_COLLECTING, -1
7881 Ydiamond_stone, FALSE, FALSE,
7882 EL_DIAMOND, ACTION_SMASHED_BY_ROCK, -1
7885 Xdrip_fall, TRUE, FALSE,
7886 EL_AMOEBA_DROP, -1, -1
7889 Xdrip_stretch, FALSE, FALSE,
7890 EL_AMOEBA_DROP, ACTION_FALLING, -1
7893 Xdrip_stretchB, FALSE, TRUE,
7894 EL_AMOEBA_DROP, ACTION_FALLING, -1
7897 Xdrip_eat, FALSE, FALSE,
7898 EL_AMOEBA_DROP, ACTION_GROWING, -1
7901 Ydrip_s1, FALSE, FALSE,
7902 EL_AMOEBA_DROP, ACTION_FALLING, -1
7905 Ydrip_s1B, FALSE, TRUE,
7906 EL_AMOEBA_DROP, ACTION_FALLING, -1
7909 Ydrip_s2, FALSE, FALSE,
7910 EL_AMOEBA_DROP, ACTION_FALLING, -1
7913 Ydrip_s2B, FALSE, TRUE,
7914 EL_AMOEBA_DROP, ACTION_FALLING, -1
7921 Xbomb_pause, FALSE, FALSE,
7925 Xbomb_fall, FALSE, FALSE,
7929 Ybomb_s, FALSE, FALSE,
7930 EL_BOMB, ACTION_FALLING, -1
7933 Ybomb_sB, FALSE, TRUE,
7934 EL_BOMB, ACTION_FALLING, -1
7937 Ybomb_e, FALSE, FALSE,
7938 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
7941 Ybomb_eB, FALSE, TRUE,
7942 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
7945 Ybomb_w, FALSE, FALSE,
7946 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
7949 Ybomb_wB, FALSE, TRUE,
7950 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
7953 Ybomb_eat, FALSE, FALSE,
7954 EL_BOMB, ACTION_ACTIVATING, -1
7957 Xballoon, TRUE, FALSE,
7961 Yballoon_n, FALSE, FALSE,
7962 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
7965 Yballoon_nB, FALSE, TRUE,
7966 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
7969 Yballoon_e, FALSE, FALSE,
7970 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
7973 Yballoon_eB, FALSE, TRUE,
7974 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
7977 Yballoon_s, FALSE, FALSE,
7978 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
7981 Yballoon_sB, FALSE, TRUE,
7982 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
7985 Yballoon_w, FALSE, FALSE,
7986 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
7989 Yballoon_wB, FALSE, TRUE,
7990 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
7993 Xgrass, TRUE, FALSE,
7994 EL_EMC_GRASS, -1, -1
7997 Ygrass_nB, FALSE, FALSE,
7998 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_UP
8001 Ygrass_eB, FALSE, FALSE,
8002 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_RIGHT
8005 Ygrass_sB, FALSE, FALSE,
8006 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_DOWN
8009 Ygrass_wB, FALSE, FALSE,
8010 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_LEFT
8017 Ydirt_nB, FALSE, FALSE,
8018 EL_SAND, ACTION_DIGGING, MV_BIT_UP
8021 Ydirt_eB, FALSE, FALSE,
8022 EL_SAND, ACTION_DIGGING, MV_BIT_RIGHT
8025 Ydirt_sB, FALSE, FALSE,
8026 EL_SAND, ACTION_DIGGING, MV_BIT_DOWN
8029 Ydirt_wB, FALSE, FALSE,
8030 EL_SAND, ACTION_DIGGING, MV_BIT_LEFT
8033 Xacid_ne, TRUE, FALSE,
8034 EL_ACID_POOL_TOPRIGHT, -1, -1
8037 Xacid_se, TRUE, FALSE,
8038 EL_ACID_POOL_BOTTOMRIGHT, -1, -1
8041 Xacid_s, TRUE, FALSE,
8042 EL_ACID_POOL_BOTTOM, -1, -1
8045 Xacid_sw, TRUE, FALSE,
8046 EL_ACID_POOL_BOTTOMLEFT, -1, -1
8049 Xacid_nw, TRUE, FALSE,
8050 EL_ACID_POOL_TOPLEFT, -1, -1
8053 Xacid_1, TRUE, FALSE,
8057 Xacid_2, FALSE, FALSE,
8061 Xacid_3, FALSE, FALSE,
8065 Xacid_4, FALSE, FALSE,
8069 Xacid_5, FALSE, FALSE,
8073 Xacid_6, FALSE, FALSE,
8077 Xacid_7, FALSE, FALSE,
8081 Xacid_8, FALSE, FALSE,
8085 Xball_1, TRUE, FALSE,
8086 EL_EMC_MAGIC_BALL, -1, -1
8089 Xball_1B, FALSE, FALSE,
8090 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
8093 Xball_2, FALSE, FALSE,
8094 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
8097 Xball_2B, FALSE, FALSE,
8098 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
8101 Yball_eat, FALSE, FALSE,
8102 EL_EMC_MAGIC_BALL, ACTION_DROPPING, -1
8105 Ykey_1_eat, FALSE, FALSE,
8106 EL_EM_KEY_1, ACTION_COLLECTING, -1
8109 Ykey_2_eat, FALSE, FALSE,
8110 EL_EM_KEY_2, ACTION_COLLECTING, -1
8113 Ykey_3_eat, FALSE, FALSE,
8114 EL_EM_KEY_3, ACTION_COLLECTING, -1
8117 Ykey_4_eat, FALSE, FALSE,
8118 EL_EM_KEY_4, ACTION_COLLECTING, -1
8121 Ykey_5_eat, FALSE, FALSE,
8122 EL_EMC_KEY_5, ACTION_COLLECTING, -1
8125 Ykey_6_eat, FALSE, FALSE,
8126 EL_EMC_KEY_6, ACTION_COLLECTING, -1
8129 Ykey_7_eat, FALSE, FALSE,
8130 EL_EMC_KEY_7, ACTION_COLLECTING, -1
8133 Ykey_8_eat, FALSE, FALSE,
8134 EL_EMC_KEY_8, ACTION_COLLECTING, -1
8137 Ylenses_eat, FALSE, FALSE,
8138 EL_EMC_LENSES, ACTION_COLLECTING, -1
8141 Ymagnify_eat, FALSE, FALSE,
8142 EL_EMC_MAGNIFIER, ACTION_COLLECTING, -1
8145 Ygrass_eat, FALSE, FALSE,
8146 EL_EMC_GRASS, ACTION_SNAPPING, -1
8149 Ydirt_eat, FALSE, FALSE,
8150 EL_SAND, ACTION_SNAPPING, -1
8153 Xgrow_ns, TRUE, FALSE,
8154 EL_EXPANDABLE_WALL_VERTICAL, -1, -1
8157 Ygrow_ns_eat, FALSE, FALSE,
8158 EL_EXPANDABLE_WALL_VERTICAL, ACTION_GROWING, -1
8161 Xgrow_ew, TRUE, FALSE,
8162 EL_EXPANDABLE_WALL_HORIZONTAL, -1, -1
8165 Ygrow_ew_eat, FALSE, FALSE,
8166 EL_EXPANDABLE_WALL_HORIZONTAL, ACTION_GROWING, -1
8169 Xwonderwall, TRUE, FALSE,
8170 EL_MAGIC_WALL, -1, -1
8173 XwonderwallB, FALSE, FALSE,
8174 EL_MAGIC_WALL, ACTION_ACTIVE, -1
8177 Xamoeba_1, TRUE, FALSE,
8178 EL_AMOEBA_DRY, ACTION_OTHER, -1
8181 Xamoeba_2, FALSE, FALSE,
8182 EL_AMOEBA_DRY, ACTION_OTHER, -1
8185 Xamoeba_3, FALSE, FALSE,
8186 EL_AMOEBA_DRY, ACTION_OTHER, -1
8189 Xamoeba_4, FALSE, FALSE,
8190 EL_AMOEBA_DRY, ACTION_OTHER, -1
8193 Xamoeba_5, TRUE, FALSE,
8194 EL_AMOEBA_WET, ACTION_OTHER, -1
8197 Xamoeba_6, FALSE, FALSE,
8198 EL_AMOEBA_WET, ACTION_OTHER, -1
8201 Xamoeba_7, FALSE, FALSE,
8202 EL_AMOEBA_WET, ACTION_OTHER, -1
8205 Xamoeba_8, FALSE, FALSE,
8206 EL_AMOEBA_WET, ACTION_OTHER, -1
8209 Xdoor_1, TRUE, FALSE,
8210 EL_EM_GATE_1, -1, -1
8213 Xdoor_2, TRUE, FALSE,
8214 EL_EM_GATE_2, -1, -1
8217 Xdoor_3, TRUE, FALSE,
8218 EL_EM_GATE_3, -1, -1
8221 Xdoor_4, TRUE, FALSE,
8222 EL_EM_GATE_4, -1, -1
8225 Xdoor_5, TRUE, FALSE,
8226 EL_EMC_GATE_5, -1, -1
8229 Xdoor_6, TRUE, FALSE,
8230 EL_EMC_GATE_6, -1, -1
8233 Xdoor_7, TRUE, FALSE,
8234 EL_EMC_GATE_7, -1, -1
8237 Xdoor_8, TRUE, FALSE,
8238 EL_EMC_GATE_8, -1, -1
8241 Xkey_1, TRUE, FALSE,
8245 Xkey_2, TRUE, FALSE,
8249 Xkey_3, TRUE, FALSE,
8253 Xkey_4, TRUE, FALSE,
8257 Xkey_5, TRUE, FALSE,
8258 EL_EMC_KEY_5, -1, -1
8261 Xkey_6, TRUE, FALSE,
8262 EL_EMC_KEY_6, -1, -1
8265 Xkey_7, TRUE, FALSE,
8266 EL_EMC_KEY_7, -1, -1
8269 Xkey_8, TRUE, FALSE,
8270 EL_EMC_KEY_8, -1, -1
8273 Xwind_n, TRUE, FALSE,
8274 EL_BALLOON_SWITCH_UP, -1, -1
8277 Xwind_e, TRUE, FALSE,
8278 EL_BALLOON_SWITCH_RIGHT, -1, -1
8281 Xwind_s, TRUE, FALSE,
8282 EL_BALLOON_SWITCH_DOWN, -1, -1
8285 Xwind_w, TRUE, FALSE,
8286 EL_BALLOON_SWITCH_LEFT, -1, -1
8289 Xwind_nesw, TRUE, FALSE,
8290 EL_BALLOON_SWITCH_ANY, -1, -1
8293 Xwind_stop, TRUE, FALSE,
8294 EL_BALLOON_SWITCH_NONE, -1, -1
8298 EL_EM_EXIT_CLOSED, -1, -1
8301 Xexit_1, TRUE, FALSE,
8302 EL_EM_EXIT_OPEN, -1, -1
8305 Xexit_2, FALSE, FALSE,
8306 EL_EM_EXIT_OPEN, -1, -1
8309 Xexit_3, FALSE, FALSE,
8310 EL_EM_EXIT_OPEN, -1, -1
8313 Xdynamite, TRUE, FALSE,
8314 EL_EM_DYNAMITE, -1, -1
8317 Ydynamite_eat, FALSE, FALSE,
8318 EL_EM_DYNAMITE, ACTION_COLLECTING, -1
8321 Xdynamite_1, TRUE, FALSE,
8322 EL_EM_DYNAMITE_ACTIVE, -1, -1
8325 Xdynamite_2, FALSE, FALSE,
8326 EL_EM_DYNAMITE_ACTIVE, -1, -1
8329 Xdynamite_3, FALSE, FALSE,
8330 EL_EM_DYNAMITE_ACTIVE, -1, -1
8333 Xdynamite_4, FALSE, FALSE,
8334 EL_EM_DYNAMITE_ACTIVE, -1, -1
8337 Xbumper, TRUE, FALSE,
8338 EL_EMC_SPRING_BUMPER, -1, -1
8341 XbumperB, FALSE, FALSE,
8342 EL_EMC_SPRING_BUMPER, ACTION_ACTIVE, -1
8345 Xwheel, TRUE, FALSE,
8346 EL_ROBOT_WHEEL, -1, -1
8349 XwheelB, FALSE, FALSE,
8350 EL_ROBOT_WHEEL, ACTION_ACTIVE, -1
8353 Xswitch, TRUE, FALSE,
8354 EL_EMC_MAGIC_BALL_SWITCH, -1, -1
8357 XswitchB, FALSE, FALSE,
8358 EL_EMC_MAGIC_BALL_SWITCH, ACTION_ACTIVE, -1
8362 EL_QUICKSAND_EMPTY, -1, -1
8365 Xsand_stone, TRUE, FALSE,
8366 EL_QUICKSAND_FULL, -1, -1
8369 Xsand_stonein_1, FALSE, TRUE,
8370 EL_ROCK, ACTION_FILLING, -1
8373 Xsand_stonein_2, FALSE, TRUE,
8374 EL_ROCK, ACTION_FILLING, -1
8377 Xsand_stonein_3, FALSE, TRUE,
8378 EL_ROCK, ACTION_FILLING, -1
8381 Xsand_stonein_4, FALSE, TRUE,
8382 EL_ROCK, ACTION_FILLING, -1
8386 Xsand_stonesand_1, FALSE, FALSE,
8387 EL_QUICKSAND_EMPTYING, -1, -1
8390 Xsand_stonesand_2, FALSE, FALSE,
8391 EL_QUICKSAND_EMPTYING, -1, -1
8394 Xsand_stonesand_3, FALSE, FALSE,
8395 EL_QUICKSAND_EMPTYING, -1, -1
8398 Xsand_stonesand_4, FALSE, FALSE,
8399 EL_QUICKSAND_EMPTYING, -1, -1
8402 Xsand_stonesand_quickout_1, FALSE, FALSE,
8403 EL_QUICKSAND_EMPTYING, -1, -1
8406 Xsand_stonesand_quickout_2, FALSE, FALSE,
8407 EL_QUICKSAND_EMPTYING, -1, -1
8411 Xsand_stonesand_1, FALSE, FALSE,
8412 EL_QUICKSAND_FULL, -1, -1
8415 Xsand_stonesand_2, FALSE, FALSE,
8416 EL_QUICKSAND_FULL, -1, -1
8419 Xsand_stonesand_3, FALSE, FALSE,
8420 EL_QUICKSAND_FULL, -1, -1
8423 Xsand_stonesand_4, FALSE, FALSE,
8424 EL_QUICKSAND_FULL, -1, -1
8428 Xsand_stoneout_1, FALSE, FALSE,
8429 EL_ROCK, ACTION_EMPTYING, -1
8432 Xsand_stoneout_2, FALSE, FALSE,
8433 EL_ROCK, ACTION_EMPTYING, -1
8437 Xsand_sandstone_1, FALSE, FALSE,
8438 EL_QUICKSAND_FILLING, -1, -1
8441 Xsand_sandstone_2, FALSE, FALSE,
8442 EL_QUICKSAND_FILLING, -1, -1
8445 Xsand_sandstone_3, FALSE, FALSE,
8446 EL_QUICKSAND_FILLING, -1, -1
8449 Xsand_sandstone_4, FALSE, FALSE,
8450 EL_QUICKSAND_FILLING, -1, -1
8454 Xsand_sandstone_1, FALSE, FALSE,
8455 EL_QUICKSAND_FULL, -1, -1
8458 Xsand_sandstone_2, FALSE, FALSE,
8459 EL_QUICKSAND_FULL, -1, -1
8462 Xsand_sandstone_3, FALSE, FALSE,
8463 EL_QUICKSAND_FULL, -1, -1
8466 Xsand_sandstone_4, FALSE, FALSE,
8467 EL_QUICKSAND_FULL, -1, -1
8471 Xplant, TRUE, FALSE,
8472 EL_EMC_PLANT, -1, -1
8475 Yplant, FALSE, FALSE,
8476 EL_EMC_PLANT, -1, -1
8479 Xlenses, TRUE, FALSE,
8480 EL_EMC_LENSES, -1, -1
8483 Xmagnify, TRUE, FALSE,
8484 EL_EMC_MAGNIFIER, -1, -1
8487 Xdripper, TRUE, FALSE,
8488 EL_EMC_DRIPPER, -1, -1
8491 XdripperB, FALSE, FALSE,
8492 EL_EMC_DRIPPER, ACTION_ACTIVE, -1
8495 Xfake_blank, TRUE, FALSE,
8496 EL_INVISIBLE_WALL, -1, -1
8499 Xfake_blankB, FALSE, FALSE,
8500 EL_INVISIBLE_WALL, ACTION_ACTIVE, -1
8503 Xfake_grass, TRUE, FALSE,
8504 EL_EMC_FAKE_GRASS, -1, -1
8507 Xfake_grassB, FALSE, FALSE,
8508 EL_EMC_FAKE_GRASS, ACTION_ACTIVE, -1
8511 Xfake_door_1, TRUE, FALSE,
8512 EL_EM_GATE_1_GRAY, -1, -1
8515 Xfake_door_2, TRUE, FALSE,
8516 EL_EM_GATE_2_GRAY, -1, -1
8519 Xfake_door_3, TRUE, FALSE,
8520 EL_EM_GATE_3_GRAY, -1, -1
8523 Xfake_door_4, TRUE, FALSE,
8524 EL_EM_GATE_4_GRAY, -1, -1
8527 Xfake_door_5, TRUE, FALSE,
8528 EL_EMC_GATE_5_GRAY, -1, -1
8531 Xfake_door_6, TRUE, FALSE,
8532 EL_EMC_GATE_6_GRAY, -1, -1
8535 Xfake_door_7, TRUE, FALSE,
8536 EL_EMC_GATE_7_GRAY, -1, -1
8539 Xfake_door_8, TRUE, FALSE,
8540 EL_EMC_GATE_8_GRAY, -1, -1
8543 Xfake_acid_1, TRUE, FALSE,
8544 EL_EMC_FAKE_ACID, -1, -1
8547 Xfake_acid_2, FALSE, FALSE,
8548 EL_EMC_FAKE_ACID, -1, -1
8551 Xfake_acid_3, FALSE, FALSE,
8552 EL_EMC_FAKE_ACID, -1, -1
8555 Xfake_acid_4, FALSE, FALSE,
8556 EL_EMC_FAKE_ACID, -1, -1
8559 Xfake_acid_5, FALSE, FALSE,
8560 EL_EMC_FAKE_ACID, -1, -1
8563 Xfake_acid_6, FALSE, FALSE,
8564 EL_EMC_FAKE_ACID, -1, -1
8567 Xfake_acid_7, FALSE, FALSE,
8568 EL_EMC_FAKE_ACID, -1, -1
8571 Xfake_acid_8, FALSE, FALSE,
8572 EL_EMC_FAKE_ACID, -1, -1
8575 Xsteel_1, TRUE, FALSE,
8576 EL_STEELWALL, -1, -1
8579 Xsteel_2, TRUE, FALSE,
8580 EL_EMC_STEELWALL_2, -1, -1
8583 Xsteel_3, TRUE, FALSE,
8584 EL_EMC_STEELWALL_3, -1, -1
8587 Xsteel_4, TRUE, FALSE,
8588 EL_EMC_STEELWALL_4, -1, -1
8591 Xwall_1, TRUE, FALSE,
8595 Xwall_2, TRUE, FALSE,
8596 EL_EMC_WALL_14, -1, -1
8599 Xwall_3, TRUE, FALSE,
8600 EL_EMC_WALL_15, -1, -1
8603 Xwall_4, TRUE, FALSE,
8604 EL_EMC_WALL_16, -1, -1
8607 Xround_wall_1, TRUE, FALSE,
8608 EL_WALL_SLIPPERY, -1, -1
8611 Xround_wall_2, TRUE, FALSE,
8612 EL_EMC_WALL_SLIPPERY_2, -1, -1
8615 Xround_wall_3, TRUE, FALSE,
8616 EL_EMC_WALL_SLIPPERY_3, -1, -1
8619 Xround_wall_4, TRUE, FALSE,
8620 EL_EMC_WALL_SLIPPERY_4, -1, -1
8623 Xdecor_1, TRUE, FALSE,
8624 EL_EMC_WALL_8, -1, -1
8627 Xdecor_2, TRUE, FALSE,
8628 EL_EMC_WALL_6, -1, -1
8631 Xdecor_3, TRUE, FALSE,
8632 EL_EMC_WALL_4, -1, -1
8635 Xdecor_4, TRUE, FALSE,
8636 EL_EMC_WALL_7, -1, -1
8639 Xdecor_5, TRUE, FALSE,
8640 EL_EMC_WALL_5, -1, -1
8643 Xdecor_6, TRUE, FALSE,
8644 EL_EMC_WALL_9, -1, -1
8647 Xdecor_7, TRUE, FALSE,
8648 EL_EMC_WALL_10, -1, -1
8651 Xdecor_8, TRUE, FALSE,
8652 EL_EMC_WALL_1, -1, -1
8655 Xdecor_9, TRUE, FALSE,
8656 EL_EMC_WALL_2, -1, -1
8659 Xdecor_10, TRUE, FALSE,
8660 EL_EMC_WALL_3, -1, -1
8663 Xdecor_11, TRUE, FALSE,
8664 EL_EMC_WALL_11, -1, -1
8667 Xdecor_12, TRUE, FALSE,
8668 EL_EMC_WALL_12, -1, -1
8671 Xalpha_0, TRUE, FALSE,
8672 EL_CHAR('0'), -1, -1
8675 Xalpha_1, TRUE, FALSE,
8676 EL_CHAR('1'), -1, -1
8679 Xalpha_2, TRUE, FALSE,
8680 EL_CHAR('2'), -1, -1
8683 Xalpha_3, TRUE, FALSE,
8684 EL_CHAR('3'), -1, -1
8687 Xalpha_4, TRUE, FALSE,
8688 EL_CHAR('4'), -1, -1
8691 Xalpha_5, TRUE, FALSE,
8692 EL_CHAR('5'), -1, -1
8695 Xalpha_6, TRUE, FALSE,
8696 EL_CHAR('6'), -1, -1
8699 Xalpha_7, TRUE, FALSE,
8700 EL_CHAR('7'), -1, -1
8703 Xalpha_8, TRUE, FALSE,
8704 EL_CHAR('8'), -1, -1
8707 Xalpha_9, TRUE, FALSE,
8708 EL_CHAR('9'), -1, -1
8711 Xalpha_excla, TRUE, FALSE,
8712 EL_CHAR('!'), -1, -1
8715 Xalpha_quote, TRUE, FALSE,
8716 EL_CHAR('"'), -1, -1
8719 Xalpha_comma, TRUE, FALSE,
8720 EL_CHAR(','), -1, -1
8723 Xalpha_minus, TRUE, FALSE,
8724 EL_CHAR('-'), -1, -1
8727 Xalpha_perio, TRUE, FALSE,
8728 EL_CHAR('.'), -1, -1
8731 Xalpha_colon, TRUE, FALSE,
8732 EL_CHAR(':'), -1, -1
8735 Xalpha_quest, TRUE, FALSE,
8736 EL_CHAR('?'), -1, -1
8739 Xalpha_a, TRUE, FALSE,
8740 EL_CHAR('A'), -1, -1
8743 Xalpha_b, TRUE, FALSE,
8744 EL_CHAR('B'), -1, -1
8747 Xalpha_c, TRUE, FALSE,
8748 EL_CHAR('C'), -1, -1
8751 Xalpha_d, TRUE, FALSE,
8752 EL_CHAR('D'), -1, -1
8755 Xalpha_e, TRUE, FALSE,
8756 EL_CHAR('E'), -1, -1
8759 Xalpha_f, TRUE, FALSE,
8760 EL_CHAR('F'), -1, -1
8763 Xalpha_g, TRUE, FALSE,
8764 EL_CHAR('G'), -1, -1
8767 Xalpha_h, TRUE, FALSE,
8768 EL_CHAR('H'), -1, -1
8771 Xalpha_i, TRUE, FALSE,
8772 EL_CHAR('I'), -1, -1
8775 Xalpha_j, TRUE, FALSE,
8776 EL_CHAR('J'), -1, -1
8779 Xalpha_k, TRUE, FALSE,
8780 EL_CHAR('K'), -1, -1
8783 Xalpha_l, TRUE, FALSE,
8784 EL_CHAR('L'), -1, -1
8787 Xalpha_m, TRUE, FALSE,
8788 EL_CHAR('M'), -1, -1
8791 Xalpha_n, TRUE, FALSE,
8792 EL_CHAR('N'), -1, -1
8795 Xalpha_o, TRUE, FALSE,
8796 EL_CHAR('O'), -1, -1
8799 Xalpha_p, TRUE, FALSE,
8800 EL_CHAR('P'), -1, -1
8803 Xalpha_q, TRUE, FALSE,
8804 EL_CHAR('Q'), -1, -1
8807 Xalpha_r, TRUE, FALSE,
8808 EL_CHAR('R'), -1, -1
8811 Xalpha_s, TRUE, FALSE,
8812 EL_CHAR('S'), -1, -1
8815 Xalpha_t, TRUE, FALSE,
8816 EL_CHAR('T'), -1, -1
8819 Xalpha_u, TRUE, FALSE,
8820 EL_CHAR('U'), -1, -1
8823 Xalpha_v, TRUE, FALSE,
8824 EL_CHAR('V'), -1, -1
8827 Xalpha_w, TRUE, FALSE,
8828 EL_CHAR('W'), -1, -1
8831 Xalpha_x, TRUE, FALSE,
8832 EL_CHAR('X'), -1, -1
8835 Xalpha_y, TRUE, FALSE,
8836 EL_CHAR('Y'), -1, -1
8839 Xalpha_z, TRUE, FALSE,
8840 EL_CHAR('Z'), -1, -1
8843 Xalpha_arrow_e, TRUE, FALSE,
8844 EL_CHAR('>'), -1, -1
8847 Xalpha_arrow_w, TRUE, FALSE,
8848 EL_CHAR('<'), -1, -1
8851 Xalpha_copyr, TRUE, FALSE,
8852 EL_CHAR('©'), -1, -1
8856 Xboom_bug, FALSE, FALSE,
8857 EL_BUG, ACTION_EXPLODING, -1
8860 Xboom_bomb, FALSE, FALSE,
8861 EL_BOMB, ACTION_EXPLODING, -1
8864 Xboom_android, FALSE, FALSE,
8865 EL_EMC_ANDROID, ACTION_OTHER, -1
8868 Xboom_1, FALSE, FALSE,
8869 EL_DEFAULT, ACTION_EXPLODING, -1
8872 Xboom_2, FALSE, FALSE,
8873 EL_DEFAULT, ACTION_EXPLODING, -1
8876 Znormal, FALSE, FALSE,
8880 Zdynamite, FALSE, FALSE,
8884 Zplayer, FALSE, FALSE,
8888 ZBORDER, FALSE, FALSE,
8898 static struct Mapping_EM_to_RND_player
8907 em_player_mapping_list[] =
8911 EL_PLAYER_1, ACTION_MOVING, MV_BIT_UP,
8915 EL_PLAYER_1, ACTION_MOVING, MV_BIT_RIGHT,
8919 EL_PLAYER_1, ACTION_MOVING, MV_BIT_DOWN,
8923 EL_PLAYER_1, ACTION_MOVING, MV_BIT_LEFT,
8927 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_UP,
8931 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_RIGHT,
8935 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_DOWN,
8939 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_LEFT,
8943 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_UP,
8947 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_RIGHT,
8951 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_DOWN,
8955 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_LEFT,
8959 EL_PLAYER_2, ACTION_MOVING, MV_BIT_UP,
8963 EL_PLAYER_2, ACTION_MOVING, MV_BIT_RIGHT,
8967 EL_PLAYER_2, ACTION_MOVING, MV_BIT_DOWN,
8971 EL_PLAYER_2, ACTION_MOVING, MV_BIT_LEFT,
8975 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_UP,
8979 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_RIGHT,
8983 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_DOWN,
8987 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_LEFT,
8991 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_UP,
8995 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_RIGHT,
8999 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_DOWN,
9003 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_LEFT,
9007 EL_PLAYER_1, ACTION_DEFAULT, -1,
9011 EL_PLAYER_2, ACTION_DEFAULT, -1,
9015 EL_PLAYER_3, ACTION_MOVING, MV_BIT_UP,
9019 EL_PLAYER_3, ACTION_MOVING, MV_BIT_RIGHT,
9023 EL_PLAYER_3, ACTION_MOVING, MV_BIT_DOWN,
9027 EL_PLAYER_3, ACTION_MOVING, MV_BIT_LEFT,
9031 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_UP,
9035 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_RIGHT,
9039 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_DOWN,
9043 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_LEFT,
9047 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_UP,
9051 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_RIGHT,
9055 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_DOWN,
9059 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_LEFT,
9063 EL_PLAYER_4, ACTION_MOVING, MV_BIT_UP,
9067 EL_PLAYER_4, ACTION_MOVING, MV_BIT_RIGHT,
9071 EL_PLAYER_4, ACTION_MOVING, MV_BIT_DOWN,
9075 EL_PLAYER_4, ACTION_MOVING, MV_BIT_LEFT,
9079 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_UP,
9083 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_RIGHT,
9087 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_DOWN,
9091 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_LEFT,
9095 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_UP,
9099 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_RIGHT,
9103 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_DOWN,
9107 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_LEFT,
9111 EL_PLAYER_3, ACTION_DEFAULT, -1,
9115 EL_PLAYER_4, ACTION_DEFAULT, -1,
9124 int map_element_RND_to_EM(int element_rnd)
9126 static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
9127 static boolean mapping_initialized = FALSE;
9129 if (!mapping_initialized)
9133 /* return "Xalpha_quest" for all undefined elements in mapping array */
9134 for (i = 0; i < NUM_FILE_ELEMENTS; i++)
9135 mapping_RND_to_EM[i] = Xalpha_quest;
9137 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
9138 if (em_object_mapping_list[i].is_rnd_to_em_mapping)
9139 mapping_RND_to_EM[em_object_mapping_list[i].element_rnd] =
9140 em_object_mapping_list[i].element_em;
9142 mapping_initialized = TRUE;
9145 if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
9146 return mapping_RND_to_EM[element_rnd];
9148 Error(ERR_WARN, "invalid RND level element %d", element_rnd);
9153 int map_element_EM_to_RND(int element_em)
9155 static unsigned short mapping_EM_to_RND[TILE_MAX];
9156 static boolean mapping_initialized = FALSE;
9158 if (!mapping_initialized)
9162 /* return "EL_UNKNOWN" for all undefined elements in mapping array */
9163 for (i = 0; i < TILE_MAX; i++)
9164 mapping_EM_to_RND[i] = EL_UNKNOWN;
9166 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
9167 mapping_EM_to_RND[em_object_mapping_list[i].element_em] =
9168 em_object_mapping_list[i].element_rnd;
9170 mapping_initialized = TRUE;
9173 if (element_em >= 0 && element_em < TILE_MAX)
9174 return mapping_EM_to_RND[element_em];
9176 Error(ERR_WARN, "invalid EM level element %d", element_em);
9181 void map_android_clone_elements_RND_to_EM(struct LevelInfo *level)
9183 struct LevelInfo_EM *level_em = level->native_em_level;
9184 struct LEVEL *lev = level_em->lev;
9187 for (i = 0; i < TILE_MAX; i++)
9188 lev->android_array[i] = Xblank;
9190 for (i = 0; i < level->num_android_clone_elements; i++)
9192 int element_rnd = level->android_clone_element[i];
9193 int element_em = map_element_RND_to_EM(element_rnd);
9195 for (j = 0; em_object_mapping_list[j].element_em != -1; j++)
9196 if (em_object_mapping_list[j].element_rnd == element_rnd)
9197 lev->android_array[em_object_mapping_list[j].element_em] = element_em;
9201 void map_android_clone_elements_EM_to_RND(struct LevelInfo *level)
9203 struct LevelInfo_EM *level_em = level->native_em_level;
9204 struct LEVEL *lev = level_em->lev;
9207 level->num_android_clone_elements = 0;
9209 for (i = 0; i < TILE_MAX; i++)
9211 int element_em = lev->android_array[i];
9213 boolean element_found = FALSE;
9215 if (element_em == Xblank)
9218 element_rnd = map_element_EM_to_RND(element_em);
9220 for (j = 0; j < level->num_android_clone_elements; j++)
9221 if (level->android_clone_element[j] == element_rnd)
9222 element_found = TRUE;
9226 level->android_clone_element[level->num_android_clone_elements++] =
9229 if (level->num_android_clone_elements == MAX_ANDROID_ELEMENTS)
9234 if (level->num_android_clone_elements == 0)
9236 level->num_android_clone_elements = 1;
9237 level->android_clone_element[0] = EL_EMPTY;
9241 int map_direction_RND_to_EM(int direction)
9243 return (direction == MV_UP ? 0 :
9244 direction == MV_RIGHT ? 1 :
9245 direction == MV_DOWN ? 2 :
9246 direction == MV_LEFT ? 3 :
9250 int map_direction_EM_to_RND(int direction)
9252 return (direction == 0 ? MV_UP :
9253 direction == 1 ? MV_RIGHT :
9254 direction == 2 ? MV_DOWN :
9255 direction == 3 ? MV_LEFT :
9259 int map_element_RND_to_SP(int element_rnd)
9261 int element_sp = 0x20; /* map unknown elements to yellow "hardware" */
9263 if (element_rnd >= EL_SP_START &&
9264 element_rnd <= EL_SP_END)
9265 element_sp = element_rnd - EL_SP_START;
9266 else if (element_rnd == EL_EMPTY_SPACE)
9268 else if (element_rnd == EL_INVISIBLE_WALL)
9274 int map_element_SP_to_RND(int element_sp)
9276 int element_rnd = EL_UNKNOWN;
9278 if (element_sp >= 0x00 &&
9280 element_rnd = EL_SP_START + element_sp;
9281 else if (element_sp == 0x28)
9282 element_rnd = EL_INVISIBLE_WALL;
9287 int map_action_SP_to_RND(int action_sp)
9291 case actActive: return ACTION_ACTIVE;
9292 case actImpact: return ACTION_IMPACT;
9293 case actExploding: return ACTION_EXPLODING;
9294 case actDigging: return ACTION_DIGGING;
9295 case actSnapping: return ACTION_SNAPPING;
9296 case actCollecting: return ACTION_COLLECTING;
9297 case actPassing: return ACTION_PASSING;
9298 case actPushing: return ACTION_PUSHING;
9299 case actDropping: return ACTION_DROPPING;
9301 default: return ACTION_DEFAULT;
9305 int get_next_element(int element)
9309 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
9310 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
9311 case EL_QUICKSAND_FAST_FILLING: return EL_QUICKSAND_FAST_FULL;
9312 case EL_QUICKSAND_FAST_EMPTYING: return EL_QUICKSAND_FAST_EMPTY;
9313 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
9314 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
9315 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
9316 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
9317 case EL_DC_MAGIC_WALL_FILLING: return EL_DC_MAGIC_WALL_FULL;
9318 case EL_DC_MAGIC_WALL_EMPTYING: return EL_DC_MAGIC_WALL_ACTIVE;
9319 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
9321 default: return element;
9326 int el_act_dir2img(int element, int action, int direction)
9328 element = GFX_ELEMENT(element);
9330 if (direction == MV_NONE)
9331 return element_info[element].graphic[action];
9333 direction = MV_DIR_TO_BIT(direction);
9335 return element_info[element].direction_graphic[action][direction];
9338 int el_act_dir2img(int element, int action, int direction)
9340 element = GFX_ELEMENT(element);
9341 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
9343 /* direction_graphic[][] == graphic[] for undefined direction graphics */
9344 return element_info[element].direction_graphic[action][direction];
9349 static int el_act_dir2crm(int element, int action, int direction)
9351 element = GFX_ELEMENT(element);
9353 if (direction == MV_NONE)
9354 return element_info[element].crumbled[action];
9356 direction = MV_DIR_TO_BIT(direction);
9358 return element_info[element].direction_crumbled[action][direction];
9361 static int el_act_dir2crm(int element, int action, int direction)
9363 element = GFX_ELEMENT(element);
9364 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
9366 /* direction_graphic[][] == graphic[] for undefined direction graphics */
9367 return element_info[element].direction_crumbled[action][direction];
9371 int el_act2img(int element, int action)
9373 element = GFX_ELEMENT(element);
9375 return element_info[element].graphic[action];
9378 int el_act2crm(int element, int action)
9380 element = GFX_ELEMENT(element);
9382 return element_info[element].crumbled[action];
9385 int el_dir2img(int element, int direction)
9387 element = GFX_ELEMENT(element);
9389 return el_act_dir2img(element, ACTION_DEFAULT, direction);
9392 int el2baseimg(int element)
9394 return element_info[element].graphic[ACTION_DEFAULT];
9397 int el2img(int element)
9399 element = GFX_ELEMENT(element);
9401 return element_info[element].graphic[ACTION_DEFAULT];
9404 int el2edimg(int element)
9406 element = GFX_ELEMENT(element);
9408 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
9411 int el2preimg(int element)
9413 element = GFX_ELEMENT(element);
9415 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
9418 int el2panelimg(int element)
9420 element = GFX_ELEMENT(element);
9422 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PANEL];
9425 int font2baseimg(int font_nr)
9427 return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
9430 int getBeltNrFromBeltElement(int element)
9432 return (element < EL_CONVEYOR_BELT_2_LEFT ? 0 :
9433 element < EL_CONVEYOR_BELT_3_LEFT ? 1 :
9434 element < EL_CONVEYOR_BELT_4_LEFT ? 2 : 3);
9437 int getBeltNrFromBeltActiveElement(int element)
9439 return (element < EL_CONVEYOR_BELT_2_LEFT_ACTIVE ? 0 :
9440 element < EL_CONVEYOR_BELT_3_LEFT_ACTIVE ? 1 :
9441 element < EL_CONVEYOR_BELT_4_LEFT_ACTIVE ? 2 : 3);
9444 int getBeltNrFromBeltSwitchElement(int element)
9446 return (element < EL_CONVEYOR_BELT_2_SWITCH_LEFT ? 0 :
9447 element < EL_CONVEYOR_BELT_3_SWITCH_LEFT ? 1 :
9448 element < EL_CONVEYOR_BELT_4_SWITCH_LEFT ? 2 : 3);
9451 int getBeltDirNrFromBeltElement(int element)
9453 static int belt_base_element[4] =
9455 EL_CONVEYOR_BELT_1_LEFT,
9456 EL_CONVEYOR_BELT_2_LEFT,
9457 EL_CONVEYOR_BELT_3_LEFT,
9458 EL_CONVEYOR_BELT_4_LEFT
9461 int belt_nr = getBeltNrFromBeltElement(element);
9462 int belt_dir_nr = element - belt_base_element[belt_nr];
9464 return (belt_dir_nr % 3);
9467 int getBeltDirNrFromBeltSwitchElement(int element)
9469 static int belt_base_element[4] =
9471 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
9472 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
9473 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
9474 EL_CONVEYOR_BELT_4_SWITCH_LEFT
9477 int belt_nr = getBeltNrFromBeltSwitchElement(element);
9478 int belt_dir_nr = element - belt_base_element[belt_nr];
9480 return (belt_dir_nr % 3);
9483 int getBeltDirFromBeltElement(int element)
9485 static int belt_move_dir[3] =
9492 int belt_dir_nr = getBeltDirNrFromBeltElement(element);
9494 return belt_move_dir[belt_dir_nr];
9497 int getBeltDirFromBeltSwitchElement(int element)
9499 static int belt_move_dir[3] =
9506 int belt_dir_nr = getBeltDirNrFromBeltSwitchElement(element);
9508 return belt_move_dir[belt_dir_nr];
9511 int getBeltElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
9513 static int belt_base_element[4] =
9515 EL_CONVEYOR_BELT_1_LEFT,
9516 EL_CONVEYOR_BELT_2_LEFT,
9517 EL_CONVEYOR_BELT_3_LEFT,
9518 EL_CONVEYOR_BELT_4_LEFT
9521 return belt_base_element[belt_nr] + belt_dir_nr;
9524 int getBeltElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
9526 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
9528 return getBeltElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
9531 int getBeltSwitchElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
9533 static int belt_base_element[4] =
9535 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
9536 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
9537 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
9538 EL_CONVEYOR_BELT_4_SWITCH_LEFT
9541 return belt_base_element[belt_nr] + belt_dir_nr;
9544 int getBeltSwitchElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
9546 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
9548 return getBeltSwitchElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
9552 boolean getTeamMode_EM()
9554 return game.team_mode;
9557 int getNumActivePlayers_EM()
9560 int num_players = 0;
9564 return (setup.team_mode ? MAX_PLAYERS : 1);
9566 for (i = 0; i < MAX_PLAYERS; i++)
9567 if (tape.player_participates[i])
9570 return (num_players > 1 ? MAX_PLAYERS : 1);
9574 int num_players = 0;
9577 /* when recording game, activate all connected players */
9581 for (i = 0; i < MAX_PLAYERS; i++)
9582 if (tape.player_participates[i])
9590 int getGameFrameDelay_EM(int native_em_game_frame_delay)
9592 int game_frame_delay_value;
9594 game_frame_delay_value =
9595 (tape.playing && tape.fast_forward ? FfwdFrameDelay :
9596 GameFrameDelay == GAME_FRAME_DELAY ? native_em_game_frame_delay :
9599 if (tape.playing && tape.warp_forward && !tape.pausing)
9600 game_frame_delay_value = 0;
9602 return game_frame_delay_value;
9605 unsigned int InitRND(int seed)
9607 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
9608 return InitEngineRandom_EM(seed);
9609 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
9610 return InitEngineRandom_SP(seed);
9612 return InitEngineRandom_RND(seed);
9616 static struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
9617 static struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
9620 inline static int get_effective_element_EM(int tile, int frame_em)
9622 int element = object_mapping[tile].element_rnd;
9623 int action = object_mapping[tile].action;
9624 boolean is_backside = object_mapping[tile].is_backside;
9625 boolean action_removing = (action == ACTION_DIGGING ||
9626 action == ACTION_SNAPPING ||
9627 action == ACTION_COLLECTING);
9633 case Yacid_splash_eB:
9634 case Yacid_splash_wB:
9635 return (frame_em > 5 ? EL_EMPTY : element);
9639 case Ydiamond_stone:
9640 // if (!game.use_native_emc_graphics_engine)
9648 else /* frame_em == 7 */
9652 case Yacid_splash_eB:
9653 case Yacid_splash_wB:
9656 case Yemerald_stone:
9659 case Ydiamond_stone:
9663 case Xdrip_stretchB:
9682 case Xsand_stonein_1:
9683 case Xsand_stonein_2:
9684 case Xsand_stonein_3:
9685 case Xsand_stonein_4:
9689 return (is_backside || action_removing ? EL_EMPTY : element);
9694 inline static boolean check_linear_animation_EM(int tile)
9698 case Xsand_stonesand_1:
9699 case Xsand_stonesand_quickout_1:
9700 case Xsand_sandstone_1:
9701 case Xsand_stonein_1:
9702 case Xsand_stoneout_1:
9722 case Yacid_splash_eB:
9723 case Yacid_splash_wB:
9724 case Yemerald_stone:
9732 inline static void set_crumbled_graphics_EM(struct GraphicInfo_EM *g_em,
9733 boolean has_crumbled_graphics,
9734 int crumbled, int sync_frame)
9736 /* if element can be crumbled, but certain action graphics are just empty
9737 space (like instantly snapping sand to empty space in 1 frame), do not
9738 treat these empty space graphics as crumbled graphics in EMC engine */
9739 if (crumbled == IMG_EMPTY_SPACE)
9740 has_crumbled_graphics = FALSE;
9742 if (has_crumbled_graphics)
9744 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
9745 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
9746 g_crumbled->anim_delay,
9747 g_crumbled->anim_mode,
9748 g_crumbled->anim_start_frame,
9751 getGraphicSource(crumbled, frame_crumbled, &g_em->crumbled_bitmap,
9752 &g_em->crumbled_src_x, &g_em->crumbled_src_y);
9754 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
9756 g_em->has_crumbled_graphics = TRUE;
9760 g_em->crumbled_bitmap = NULL;
9761 g_em->crumbled_src_x = 0;
9762 g_em->crumbled_src_y = 0;
9763 g_em->crumbled_border_size = 0;
9765 g_em->has_crumbled_graphics = FALSE;
9769 void ResetGfxAnimation_EM(int x, int y, int tile)
9774 void SetGfxAnimation_EM(struct GraphicInfo_EM *g_em,
9775 int tile, int frame_em, int x, int y)
9777 int action = object_mapping[tile].action;
9779 int direction = object_mapping[tile].direction;
9780 int effective_element = get_effective_element_EM(tile, frame_em);
9781 int graphic = (direction == MV_NONE ?
9782 el_act2img(effective_element, action) :
9783 el_act_dir2img(effective_element, action, direction));
9784 struct GraphicInfo *g = &graphic_info[graphic];
9787 boolean action_removing = (action == ACTION_DIGGING ||
9788 action == ACTION_SNAPPING ||
9789 action == ACTION_COLLECTING);
9790 boolean action_moving = (action == ACTION_FALLING ||
9791 action == ACTION_MOVING ||
9792 action == ACTION_PUSHING ||
9793 action == ACTION_EATING ||
9794 action == ACTION_FILLING ||
9795 action == ACTION_EMPTYING);
9796 boolean action_falling = (action == ACTION_FALLING ||
9797 action == ACTION_FILLING ||
9798 action == ACTION_EMPTYING);
9800 /* special case: graphic uses "2nd movement tile" and has defined
9801 7 frames for movement animation (or less) => use default graphic
9802 for last (8th) frame which ends the movement animation */
9803 if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
9805 action = ACTION_DEFAULT; /* (keep action_* unchanged for now) */
9806 graphic = (direction == MV_NONE ?
9807 el_act2img(effective_element, action) :
9808 el_act_dir2img(effective_element, action, direction));
9810 g = &graphic_info[graphic];
9814 if (tile == Xsand_stonesand_1 ||
9815 tile == Xsand_stonesand_2 ||
9816 tile == Xsand_stonesand_3 ||
9817 tile == Xsand_stonesand_4)
9818 printf("::: 1: quicksand frame %d [%d]\n", GfxFrame[x][y], tile);
9822 if ((action_removing || check_linear_animation_EM(tile)) && frame_em == 0)
9826 // printf("::: resetting... [%d]\n", tile);
9829 if (action_removing || check_linear_animation_EM(tile))
9831 GfxFrame[x][y] = frame_em;
9833 // printf("::: resetting... [%d]\n", tile);
9836 else if (action_moving)
9838 boolean is_backside = object_mapping[tile].is_backside;
9842 int direction = object_mapping[tile].direction;
9843 int move_dir = (action_falling ? MV_DOWN : direction);
9848 /* !!! TEST !!! NEW !!! DOES NOT WORK RIGHT YET !!! */
9849 if (g->double_movement && frame_em == 0)
9853 // printf("::: resetting... [%d]\n", tile);
9857 if (move_dir == MV_LEFT)
9858 GfxFrame[x - 1][y] = GfxFrame[x][y];
9859 else if (move_dir == MV_RIGHT)
9860 GfxFrame[x + 1][y] = GfxFrame[x][y];
9861 else if (move_dir == MV_UP)
9862 GfxFrame[x][y - 1] = GfxFrame[x][y];
9863 else if (move_dir == MV_DOWN)
9864 GfxFrame[x][y + 1] = GfxFrame[x][y];
9871 /* special case: animation for Xsand_stonesand_quickout_1/2 twice as fast */
9872 if (tile == Xsand_stonesand_quickout_1 ||
9873 tile == Xsand_stonesand_quickout_2)
9878 if (tile == Xsand_stonesand_1 ||
9879 tile == Xsand_stonesand_2 ||
9880 tile == Xsand_stonesand_3 ||
9881 tile == Xsand_stonesand_4)
9882 printf("::: 2: quicksand frame %d [%d]\n", GfxFrame[x][y], tile);
9886 if (graphic_info[graphic].anim_global_sync)
9887 sync_frame = FrameCounter;
9888 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
9889 sync_frame = GfxFrame[x][y];
9891 sync_frame = 0; /* playfield border (pseudo steel) */
9893 SetRandomAnimationValue(x, y);
9895 int frame = getAnimationFrame(g->anim_frames,
9898 g->anim_start_frame,
9901 g_em->unique_identifier =
9902 (graphic << 16) | ((frame % 8) << 12) | (g_em->width << 6) | g_em->height;
9906 void getGraphicSourceObjectExt_EM(struct GraphicInfo_EM *g_em,
9907 int tile, int frame_em, int x, int y)
9909 int action = object_mapping[tile].action;
9910 int direction = object_mapping[tile].direction;
9911 boolean is_backside = object_mapping[tile].is_backside;
9912 int effective_element = get_effective_element_EM(tile, frame_em);
9914 int effective_action = action;
9916 int effective_action = (frame_em < 7 ? action : ACTION_DEFAULT);
9918 int graphic = (direction == MV_NONE ?
9919 el_act2img(effective_element, effective_action) :
9920 el_act_dir2img(effective_element, effective_action,
9922 int crumbled = (direction == MV_NONE ?
9923 el_act2crm(effective_element, effective_action) :
9924 el_act_dir2crm(effective_element, effective_action,
9926 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
9927 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
9928 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
9929 struct GraphicInfo *g = &graphic_info[graphic];
9931 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
9935 /* special case: graphic uses "2nd movement tile" and has defined
9936 7 frames for movement animation (or less) => use default graphic
9937 for last (8th) frame which ends the movement animation */
9938 if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
9940 effective_action = ACTION_DEFAULT;
9941 graphic = (direction == MV_NONE ?
9942 el_act2img(effective_element, effective_action) :
9943 el_act_dir2img(effective_element, effective_action,
9945 crumbled = (direction == MV_NONE ?
9946 el_act2crm(effective_element, effective_action) :
9947 el_act_dir2crm(effective_element, effective_action,
9950 g = &graphic_info[graphic];
9960 if (frame_em == 0) /* reset animation frame for certain elements */
9962 if (check_linear_animation_EM(tile))
9967 if (graphic_info[graphic].anim_global_sync)
9968 sync_frame = FrameCounter;
9969 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
9970 sync_frame = GfxFrame[x][y];
9972 sync_frame = 0; /* playfield border (pseudo steel) */
9974 SetRandomAnimationValue(x, y);
9979 int xxx_sync_frame = (i == Xdrip_stretch ? 7 :
9980 i == Xdrip_stretchB ? 7 :
9981 i == Ydrip_s2 ? j + 8 :
9982 i == Ydrip_s2B ? j + 8 :
9991 i == Xfake_acid_1 ? 0 :
9992 i == Xfake_acid_2 ? 10 :
9993 i == Xfake_acid_3 ? 20 :
9994 i == Xfake_acid_4 ? 30 :
9995 i == Xfake_acid_5 ? 40 :
9996 i == Xfake_acid_6 ? 50 :
9997 i == Xfake_acid_7 ? 60 :
9998 i == Xfake_acid_8 ? 70 :
10000 i == Xball_2B ? j + 8 :
10001 i == Yball_eat ? j + 1 :
10002 i == Ykey_1_eat ? j + 1 :
10003 i == Ykey_2_eat ? j + 1 :
10004 i == Ykey_3_eat ? j + 1 :
10005 i == Ykey_4_eat ? j + 1 :
10006 i == Ykey_5_eat ? j + 1 :
10007 i == Ykey_6_eat ? j + 1 :
10008 i == Ykey_7_eat ? j + 1 :
10009 i == Ykey_8_eat ? j + 1 :
10010 i == Ylenses_eat ? j + 1 :
10011 i == Ymagnify_eat ? j + 1 :
10012 i == Ygrass_eat ? j + 1 :
10013 i == Ydirt_eat ? j + 1 :
10014 i == Xamoeba_1 ? 0 :
10015 i == Xamoeba_2 ? 1 :
10016 i == Xamoeba_3 ? 2 :
10017 i == Xamoeba_4 ? 3 :
10018 i == Xamoeba_5 ? 0 :
10019 i == Xamoeba_6 ? 1 :
10020 i == Xamoeba_7 ? 2 :
10021 i == Xamoeba_8 ? 3 :
10022 i == Xexit_2 ? j + 8 :
10023 i == Xexit_3 ? j + 16 :
10024 i == Xdynamite_1 ? 0 :
10025 i == Xdynamite_2 ? 8 :
10026 i == Xdynamite_3 ? 16 :
10027 i == Xdynamite_4 ? 24 :
10028 i == Xsand_stonein_1 ? j + 1 :
10029 i == Xsand_stonein_2 ? j + 9 :
10030 i == Xsand_stonein_3 ? j + 17 :
10031 i == Xsand_stonein_4 ? j + 25 :
10032 i == Xsand_stoneout_1 && j == 0 ? 0 :
10033 i == Xsand_stoneout_1 && j == 1 ? 0 :
10034 i == Xsand_stoneout_1 && j == 2 ? 1 :
10035 i == Xsand_stoneout_1 && j == 3 ? 2 :
10036 i == Xsand_stoneout_1 && j == 4 ? 2 :
10037 i == Xsand_stoneout_1 && j == 5 ? 3 :
10038 i == Xsand_stoneout_1 && j == 6 ? 4 :
10039 i == Xsand_stoneout_1 && j == 7 ? 4 :
10040 i == Xsand_stoneout_2 && j == 0 ? 5 :
10041 i == Xsand_stoneout_2 && j == 1 ? 6 :
10042 i == Xsand_stoneout_2 && j == 2 ? 7 :
10043 i == Xsand_stoneout_2 && j == 3 ? 8 :
10044 i == Xsand_stoneout_2 && j == 4 ? 9 :
10045 i == Xsand_stoneout_2 && j == 5 ? 11 :
10046 i == Xsand_stoneout_2 && j == 6 ? 13 :
10047 i == Xsand_stoneout_2 && j == 7 ? 15 :
10048 i == Xboom_bug && j == 1 ? 2 :
10049 i == Xboom_bug && j == 2 ? 2 :
10050 i == Xboom_bug && j == 3 ? 4 :
10051 i == Xboom_bug && j == 4 ? 4 :
10052 i == Xboom_bug && j == 5 ? 2 :
10053 i == Xboom_bug && j == 6 ? 2 :
10054 i == Xboom_bug && j == 7 ? 0 :
10055 i == Xboom_bomb && j == 1 ? 2 :
10056 i == Xboom_bomb && j == 2 ? 2 :
10057 i == Xboom_bomb && j == 3 ? 4 :
10058 i == Xboom_bomb && j == 4 ? 4 :
10059 i == Xboom_bomb && j == 5 ? 2 :
10060 i == Xboom_bomb && j == 6 ? 2 :
10061 i == Xboom_bomb && j == 7 ? 0 :
10062 i == Xboom_android && j == 7 ? 6 :
10063 i == Xboom_1 && j == 1 ? 2 :
10064 i == Xboom_1 && j == 2 ? 2 :
10065 i == Xboom_1 && j == 3 ? 4 :
10066 i == Xboom_1 && j == 4 ? 4 :
10067 i == Xboom_1 && j == 5 ? 6 :
10068 i == Xboom_1 && j == 6 ? 6 :
10069 i == Xboom_1 && j == 7 ? 8 :
10070 i == Xboom_2 && j == 0 ? 8 :
10071 i == Xboom_2 && j == 1 ? 8 :
10072 i == Xboom_2 && j == 2 ? 10 :
10073 i == Xboom_2 && j == 3 ? 10 :
10074 i == Xboom_2 && j == 4 ? 10 :
10075 i == Xboom_2 && j == 5 ? 12 :
10076 i == Xboom_2 && j == 6 ? 12 :
10077 i == Xboom_2 && j == 7 ? 12 :
10079 special_animation && j == 4 ? 3 :
10080 effective_action != action ? 0 :
10086 int xxx_effective_action;
10087 int xxx_has_action_graphics;
10090 int element = object_mapping[i].element_rnd;
10091 int action = object_mapping[i].action;
10092 int direction = object_mapping[i].direction;
10093 boolean is_backside = object_mapping[i].is_backside;
10095 boolean action_removing = (action == ACTION_DIGGING ||
10096 action == ACTION_SNAPPING ||
10097 action == ACTION_COLLECTING);
10099 boolean action_exploding = ((action == ACTION_EXPLODING ||
10100 action == ACTION_SMASHED_BY_ROCK ||
10101 action == ACTION_SMASHED_BY_SPRING) &&
10102 element != EL_DIAMOND);
10103 boolean action_active = (action == ACTION_ACTIVE);
10104 boolean action_other = (action == ACTION_OTHER);
10108 int effective_element = get_effective_element_EM(i, j);
10110 int effective_element = (j > 5 && i == Yacid_splash_eB ? EL_EMPTY :
10111 j > 5 && i == Yacid_splash_wB ? EL_EMPTY :
10113 i == Xdrip_stretch ? element :
10114 i == Xdrip_stretchB ? element :
10115 i == Ydrip_s1 ? element :
10116 i == Ydrip_s1B ? element :
10117 i == Xball_1B ? element :
10118 i == Xball_2 ? element :
10119 i == Xball_2B ? element :
10120 i == Yball_eat ? element :
10121 i == Ykey_1_eat ? element :
10122 i == Ykey_2_eat ? element :
10123 i == Ykey_3_eat ? element :
10124 i == Ykey_4_eat ? element :
10125 i == Ykey_5_eat ? element :
10126 i == Ykey_6_eat ? element :
10127 i == Ykey_7_eat ? element :
10128 i == Ykey_8_eat ? element :
10129 i == Ylenses_eat ? element :
10130 i == Ymagnify_eat ? element :
10131 i == Ygrass_eat ? element :
10132 i == Ydirt_eat ? element :
10133 i == Yemerald_stone ? EL_EMERALD :
10134 i == Ydiamond_stone ? EL_ROCK :
10135 i == Xsand_stonein_1 ? element :
10136 i == Xsand_stonein_2 ? element :
10137 i == Xsand_stonein_3 ? element :
10138 i == Xsand_stonein_4 ? element :
10139 is_backside ? EL_EMPTY :
10140 action_removing ? EL_EMPTY :
10143 int effective_action = (j < 7 ? action :
10144 i == Xdrip_stretch ? action :
10145 i == Xdrip_stretchB ? action :
10146 i == Ydrip_s1 ? action :
10147 i == Ydrip_s1B ? action :
10148 i == Xball_1B ? action :
10149 i == Xball_2 ? action :
10150 i == Xball_2B ? action :
10151 i == Yball_eat ? action :
10152 i == Ykey_1_eat ? action :
10153 i == Ykey_2_eat ? action :
10154 i == Ykey_3_eat ? action :
10155 i == Ykey_4_eat ? action :
10156 i == Ykey_5_eat ? action :
10157 i == Ykey_6_eat ? action :
10158 i == Ykey_7_eat ? action :
10159 i == Ykey_8_eat ? action :
10160 i == Ylenses_eat ? action :
10161 i == Ymagnify_eat ? action :
10162 i == Ygrass_eat ? action :
10163 i == Ydirt_eat ? action :
10164 i == Xsand_stonein_1 ? action :
10165 i == Xsand_stonein_2 ? action :
10166 i == Xsand_stonein_3 ? action :
10167 i == Xsand_stonein_4 ? action :
10168 i == Xsand_stoneout_1 ? action :
10169 i == Xsand_stoneout_2 ? action :
10170 i == Xboom_android ? ACTION_EXPLODING :
10171 action_exploding ? ACTION_EXPLODING :
10172 action_active ? action :
10173 action_other ? action :
10175 int graphic = (el_act_dir2img(effective_element, effective_action,
10177 int crumbled = (el_act_dir2crm(effective_element, effective_action,
10179 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
10180 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
10181 boolean has_action_graphics = (graphic != base_graphic);
10182 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
10183 struct GraphicInfo *g = &graphic_info[graphic];
10185 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
10187 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
10188 Bitmap *src_bitmap;
10190 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
10191 boolean special_animation = (action != ACTION_DEFAULT &&
10192 g->anim_frames == 3 &&
10193 g->anim_delay == 2 &&
10194 g->anim_mode & ANIM_LINEAR);
10195 xxx_sync_frame = (i == Xdrip_stretch ? 7 :
10196 i == Xdrip_stretchB ? 7 :
10197 i == Ydrip_s2 ? j + 8 :
10198 i == Ydrip_s2B ? j + 8 :
10200 i == Xacid_2 ? 10 :
10201 i == Xacid_3 ? 20 :
10202 i == Xacid_4 ? 30 :
10203 i == Xacid_5 ? 40 :
10204 i == Xacid_6 ? 50 :
10205 i == Xacid_7 ? 60 :
10206 i == Xacid_8 ? 70 :
10207 i == Xfake_acid_1 ? 0 :
10208 i == Xfake_acid_2 ? 10 :
10209 i == Xfake_acid_3 ? 20 :
10210 i == Xfake_acid_4 ? 30 :
10211 i == Xfake_acid_5 ? 40 :
10212 i == Xfake_acid_6 ? 50 :
10213 i == Xfake_acid_7 ? 60 :
10214 i == Xfake_acid_8 ? 70 :
10216 i == Xball_2B ? j + 8 :
10217 i == Yball_eat ? j + 1 :
10218 i == Ykey_1_eat ? j + 1 :
10219 i == Ykey_2_eat ? j + 1 :
10220 i == Ykey_3_eat ? j + 1 :
10221 i == Ykey_4_eat ? j + 1 :
10222 i == Ykey_5_eat ? j + 1 :
10223 i == Ykey_6_eat ? j + 1 :
10224 i == Ykey_7_eat ? j + 1 :
10225 i == Ykey_8_eat ? j + 1 :
10226 i == Ylenses_eat ? j + 1 :
10227 i == Ymagnify_eat ? j + 1 :
10228 i == Ygrass_eat ? j + 1 :
10229 i == Ydirt_eat ? j + 1 :
10230 i == Xamoeba_1 ? 0 :
10231 i == Xamoeba_2 ? 1 :
10232 i == Xamoeba_3 ? 2 :
10233 i == Xamoeba_4 ? 3 :
10234 i == Xamoeba_5 ? 0 :
10235 i == Xamoeba_6 ? 1 :
10236 i == Xamoeba_7 ? 2 :
10237 i == Xamoeba_8 ? 3 :
10238 i == Xexit_2 ? j + 8 :
10239 i == Xexit_3 ? j + 16 :
10240 i == Xdynamite_1 ? 0 :
10241 i == Xdynamite_2 ? 8 :
10242 i == Xdynamite_3 ? 16 :
10243 i == Xdynamite_4 ? 24 :
10244 i == Xsand_stonein_1 ? j + 1 :
10245 i == Xsand_stonein_2 ? j + 9 :
10246 i == Xsand_stonein_3 ? j + 17 :
10247 i == Xsand_stonein_4 ? j + 25 :
10248 i == Xsand_stoneout_1 && j == 0 ? 0 :
10249 i == Xsand_stoneout_1 && j == 1 ? 0 :
10250 i == Xsand_stoneout_1 && j == 2 ? 1 :
10251 i == Xsand_stoneout_1 && j == 3 ? 2 :
10252 i == Xsand_stoneout_1 && j == 4 ? 2 :
10253 i == Xsand_stoneout_1 && j == 5 ? 3 :
10254 i == Xsand_stoneout_1 && j == 6 ? 4 :
10255 i == Xsand_stoneout_1 && j == 7 ? 4 :
10256 i == Xsand_stoneout_2 && j == 0 ? 5 :
10257 i == Xsand_stoneout_2 && j == 1 ? 6 :
10258 i == Xsand_stoneout_2 && j == 2 ? 7 :
10259 i == Xsand_stoneout_2 && j == 3 ? 8 :
10260 i == Xsand_stoneout_2 && j == 4 ? 9 :
10261 i == Xsand_stoneout_2 && j == 5 ? 11 :
10262 i == Xsand_stoneout_2 && j == 6 ? 13 :
10263 i == Xsand_stoneout_2 && j == 7 ? 15 :
10264 i == Xboom_bug && j == 1 ? 2 :
10265 i == Xboom_bug && j == 2 ? 2 :
10266 i == Xboom_bug && j == 3 ? 4 :
10267 i == Xboom_bug && j == 4 ? 4 :
10268 i == Xboom_bug && j == 5 ? 2 :
10269 i == Xboom_bug && j == 6 ? 2 :
10270 i == Xboom_bug && j == 7 ? 0 :
10271 i == Xboom_bomb && j == 1 ? 2 :
10272 i == Xboom_bomb && j == 2 ? 2 :
10273 i == Xboom_bomb && j == 3 ? 4 :
10274 i == Xboom_bomb && j == 4 ? 4 :
10275 i == Xboom_bomb && j == 5 ? 2 :
10276 i == Xboom_bomb && j == 6 ? 2 :
10277 i == Xboom_bomb && j == 7 ? 0 :
10278 i == Xboom_android && j == 7 ? 6 :
10279 i == Xboom_1 && j == 1 ? 2 :
10280 i == Xboom_1 && j == 2 ? 2 :
10281 i == Xboom_1 && j == 3 ? 4 :
10282 i == Xboom_1 && j == 4 ? 4 :
10283 i == Xboom_1 && j == 5 ? 6 :
10284 i == Xboom_1 && j == 6 ? 6 :
10285 i == Xboom_1 && j == 7 ? 8 :
10286 i == Xboom_2 && j == 0 ? 8 :
10287 i == Xboom_2 && j == 1 ? 8 :
10288 i == Xboom_2 && j == 2 ? 10 :
10289 i == Xboom_2 && j == 3 ? 10 :
10290 i == Xboom_2 && j == 4 ? 10 :
10291 i == Xboom_2 && j == 5 ? 12 :
10292 i == Xboom_2 && j == 6 ? 12 :
10293 i == Xboom_2 && j == 7 ? 12 :
10294 special_animation && j == 4 ? 3 :
10295 effective_action != action ? 0 :
10298 xxx_effective_action = effective_action;
10299 xxx_has_action_graphics = has_action_graphics;
10304 int frame = getAnimationFrame(g->anim_frames,
10307 g->anim_start_frame,
10321 int old_src_x = g_em->src_x;
10322 int old_src_y = g_em->src_y;
10326 getGraphicSourceExt(graphic, frame, &g_em->bitmap, &g_em->src_x, &g_em->src_y,
10327 g->double_movement && is_backside);
10329 getGraphicSourceExt(graphic, frame, &g_em->bitmap,
10330 &g_em->src_x, &g_em->src_y, FALSE);
10335 if (tile == Ydiamond_stone)
10336 printf("::: stone smashing diamond... %d: %d, %d, %d, %d, %d -> %d [%d, %d, %d, %d, %d, %d] [%d]\n",
10341 g->anim_start_frame,
10344 g_em->src_x, g_em->src_y,
10345 g_em->src_offset_x, g_em->src_offset_y,
10346 g_em->dst_offset_x, g_em->dst_offset_y,
10358 if (graphic == IMG_BUG_MOVING_RIGHT)
10359 printf("::: %d, %d, %d: %d, %d [%d, %d -> %d, %d]\n", graphic, x, y,
10360 g->double_movement, is_backside,
10361 old_src_x, old_src_y, g_em->src_x, g_em->src_y);
10369 g_em->src_offset_x = 0;
10370 g_em->src_offset_y = 0;
10371 g_em->dst_offset_x = 0;
10372 g_em->dst_offset_y = 0;
10373 g_em->width = TILEX;
10374 g_em->height = TILEY;
10376 g_em->preserve_background = FALSE;
10379 /* (updating the "crumbled" graphic definitions is probably not really needed,
10380 as animations for crumbled graphics can't be longer than one EMC cycle) */
10382 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
10387 g_em->crumbled_bitmap = NULL;
10388 g_em->crumbled_src_x = 0;
10389 g_em->crumbled_src_y = 0;
10391 g_em->has_crumbled_graphics = FALSE;
10393 if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
10395 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
10396 g_crumbled->anim_delay,
10397 g_crumbled->anim_mode,
10398 g_crumbled->anim_start_frame,
10401 getGraphicSource(crumbled, frame_crumbled, &g_em->crumbled_bitmap,
10402 &g_em->crumbled_src_x, &g_em->crumbled_src_y);
10404 g_em->has_crumbled_graphics = TRUE;
10410 int effective_action = xxx_effective_action;
10411 int has_action_graphics = xxx_has_action_graphics;
10413 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
10414 effective_action == ACTION_MOVING ||
10415 effective_action == ACTION_PUSHING ||
10416 effective_action == ACTION_EATING)) ||
10417 (!has_action_graphics && (effective_action == ACTION_FILLING ||
10418 effective_action == ACTION_EMPTYING)))
10421 (effective_action == ACTION_FALLING ||
10422 effective_action == ACTION_FILLING ||
10423 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
10424 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
10425 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
10426 int num_steps = (i == Ydrip_s1 ? 16 :
10427 i == Ydrip_s1B ? 16 :
10428 i == Ydrip_s2 ? 16 :
10429 i == Ydrip_s2B ? 16 :
10430 i == Xsand_stonein_1 ? 32 :
10431 i == Xsand_stonein_2 ? 32 :
10432 i == Xsand_stonein_3 ? 32 :
10433 i == Xsand_stonein_4 ? 32 :
10434 i == Xsand_stoneout_1 ? 16 :
10435 i == Xsand_stoneout_2 ? 16 : 8);
10436 int cx = ABS(dx) * (TILEX / num_steps);
10437 int cy = ABS(dy) * (TILEY / num_steps);
10438 int step_frame = (i == Ydrip_s2 ? j + 8 :
10439 i == Ydrip_s2B ? j + 8 :
10440 i == Xsand_stonein_2 ? j + 8 :
10441 i == Xsand_stonein_3 ? j + 16 :
10442 i == Xsand_stonein_4 ? j + 24 :
10443 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
10444 int step = (is_backside ? step_frame : num_steps - step_frame);
10446 if (is_backside) /* tile where movement starts */
10448 if (dx < 0 || dy < 0)
10450 g_em->src_offset_x = cx * step;
10451 g_em->src_offset_y = cy * step;
10455 g_em->dst_offset_x = cx * step;
10456 g_em->dst_offset_y = cy * step;
10459 else /* tile where movement ends */
10461 if (dx < 0 || dy < 0)
10463 g_em->dst_offset_x = cx * step;
10464 g_em->dst_offset_y = cy * step;
10468 g_em->src_offset_x = cx * step;
10469 g_em->src_offset_y = cy * step;
10473 g_em->width = TILEX - cx * step;
10474 g_em->height = TILEY - cy * step;
10477 /* create unique graphic identifier to decide if tile must be redrawn */
10478 /* bit 31 - 16 (16 bit): EM style graphic
10479 bit 15 - 12 ( 4 bit): EM style frame
10480 bit 11 - 6 ( 6 bit): graphic width
10481 bit 5 - 0 ( 6 bit): graphic height */
10482 g_em->unique_identifier =
10483 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
10489 void getGraphicSourcePlayerExt_EM(struct GraphicInfo_EM *g_em,
10490 int player_nr, int anim, int frame_em)
10492 int element = player_mapping[player_nr][anim].element_rnd;
10493 int action = player_mapping[player_nr][anim].action;
10494 int direction = player_mapping[player_nr][anim].direction;
10495 int graphic = (direction == MV_NONE ?
10496 el_act2img(element, action) :
10497 el_act_dir2img(element, action, direction));
10498 struct GraphicInfo *g = &graphic_info[graphic];
10501 InitPlayerGfxAnimation(&stored_player[player_nr], action, direction);
10503 stored_player[player_nr].StepFrame = frame_em;
10505 sync_frame = stored_player[player_nr].Frame;
10507 int frame = getAnimationFrame(g->anim_frames,
10510 g->anim_start_frame,
10513 getGraphicSourceExt(graphic, frame, &g_em->bitmap,
10514 &g_em->src_x, &g_em->src_y, FALSE);
10517 printf("::: %d: %d, %d [%d]\n",
10519 stored_player[player_nr].Frame,
10520 stored_player[player_nr].StepFrame,
10525 void InitGraphicInfo_EM(void)
10528 struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
10529 struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
10534 int num_em_gfx_errors = 0;
10536 if (graphic_info_em_object[0][0].bitmap == NULL)
10538 /* EM graphics not yet initialized in em_open_all() */
10543 printf("::: [4 errors can be ignored (1 x 'bomb', 3 x 'em_dynamite']\n");
10546 /* always start with reliable default values */
10547 for (i = 0; i < TILE_MAX; i++)
10549 object_mapping[i].element_rnd = EL_UNKNOWN;
10550 object_mapping[i].is_backside = FALSE;
10551 object_mapping[i].action = ACTION_DEFAULT;
10552 object_mapping[i].direction = MV_NONE;
10555 /* always start with reliable default values */
10556 for (p = 0; p < MAX_PLAYERS; p++)
10558 for (i = 0; i < SPR_MAX; i++)
10560 player_mapping[p][i].element_rnd = EL_UNKNOWN;
10561 player_mapping[p][i].action = ACTION_DEFAULT;
10562 player_mapping[p][i].direction = MV_NONE;
10566 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
10568 int e = em_object_mapping_list[i].element_em;
10570 object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd;
10571 object_mapping[e].is_backside = em_object_mapping_list[i].is_backside;
10573 if (em_object_mapping_list[i].action != -1)
10574 object_mapping[e].action = em_object_mapping_list[i].action;
10576 if (em_object_mapping_list[i].direction != -1)
10577 object_mapping[e].direction =
10578 MV_DIR_FROM_BIT(em_object_mapping_list[i].direction);
10581 for (i = 0; em_player_mapping_list[i].action_em != -1; i++)
10583 int a = em_player_mapping_list[i].action_em;
10584 int p = em_player_mapping_list[i].player_nr;
10586 player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd;
10588 if (em_player_mapping_list[i].action != -1)
10589 player_mapping[p][a].action = em_player_mapping_list[i].action;
10591 if (em_player_mapping_list[i].direction != -1)
10592 player_mapping[p][a].direction =
10593 MV_DIR_FROM_BIT(em_player_mapping_list[i].direction);
10596 for (i = 0; i < TILE_MAX; i++)
10598 int element = object_mapping[i].element_rnd;
10599 int action = object_mapping[i].action;
10600 int direction = object_mapping[i].direction;
10601 boolean is_backside = object_mapping[i].is_backside;
10603 boolean action_removing = (action == ACTION_DIGGING ||
10604 action == ACTION_SNAPPING ||
10605 action == ACTION_COLLECTING);
10607 boolean action_exploding = ((action == ACTION_EXPLODING ||
10608 action == ACTION_SMASHED_BY_ROCK ||
10609 action == ACTION_SMASHED_BY_SPRING) &&
10610 element != EL_DIAMOND);
10611 boolean action_active = (action == ACTION_ACTIVE);
10612 boolean action_other = (action == ACTION_OTHER);
10614 for (j = 0; j < 8; j++)
10617 int effective_element = get_effective_element_EM(i, j);
10619 int effective_element = (j > 5 && i == Yacid_splash_eB ? EL_EMPTY :
10620 j > 5 && i == Yacid_splash_wB ? EL_EMPTY :
10622 i == Xdrip_stretch ? element :
10623 i == Xdrip_stretchB ? element :
10624 i == Ydrip_s1 ? element :
10625 i == Ydrip_s1B ? element :
10626 i == Xball_1B ? element :
10627 i == Xball_2 ? element :
10628 i == Xball_2B ? element :
10629 i == Yball_eat ? element :
10630 i == Ykey_1_eat ? element :
10631 i == Ykey_2_eat ? element :
10632 i == Ykey_3_eat ? element :
10633 i == Ykey_4_eat ? element :
10634 i == Ykey_5_eat ? element :
10635 i == Ykey_6_eat ? element :
10636 i == Ykey_7_eat ? element :
10637 i == Ykey_8_eat ? element :
10638 i == Ylenses_eat ? element :
10639 i == Ymagnify_eat ? element :
10640 i == Ygrass_eat ? element :
10641 i == Ydirt_eat ? element :
10642 i == Yemerald_stone ? EL_EMERALD :
10643 i == Ydiamond_stone ? EL_ROCK :
10644 i == Xsand_stonein_1 ? element :
10645 i == Xsand_stonein_2 ? element :
10646 i == Xsand_stonein_3 ? element :
10647 i == Xsand_stonein_4 ? element :
10648 is_backside ? EL_EMPTY :
10649 action_removing ? EL_EMPTY :
10652 int effective_action = (j < 7 ? action :
10653 i == Xdrip_stretch ? action :
10654 i == Xdrip_stretchB ? action :
10655 i == Ydrip_s1 ? action :
10656 i == Ydrip_s1B ? action :
10657 i == Xball_1B ? action :
10658 i == Xball_2 ? action :
10659 i == Xball_2B ? action :
10660 i == Yball_eat ? action :
10661 i == Ykey_1_eat ? action :
10662 i == Ykey_2_eat ? action :
10663 i == Ykey_3_eat ? action :
10664 i == Ykey_4_eat ? action :
10665 i == Ykey_5_eat ? action :
10666 i == Ykey_6_eat ? action :
10667 i == Ykey_7_eat ? action :
10668 i == Ykey_8_eat ? action :
10669 i == Ylenses_eat ? action :
10670 i == Ymagnify_eat ? action :
10671 i == Ygrass_eat ? action :
10672 i == Ydirt_eat ? action :
10673 i == Xsand_stonein_1 ? action :
10674 i == Xsand_stonein_2 ? action :
10675 i == Xsand_stonein_3 ? action :
10676 i == Xsand_stonein_4 ? action :
10677 i == Xsand_stoneout_1 ? action :
10678 i == Xsand_stoneout_2 ? action :
10679 i == Xboom_android ? ACTION_EXPLODING :
10680 action_exploding ? ACTION_EXPLODING :
10681 action_active ? action :
10682 action_other ? action :
10684 int graphic = (el_act_dir2img(effective_element, effective_action,
10686 int crumbled = (el_act_dir2crm(effective_element, effective_action,
10688 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
10689 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
10690 boolean has_action_graphics = (graphic != base_graphic);
10691 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
10692 struct GraphicInfo *g = &graphic_info[graphic];
10694 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
10696 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
10697 Bitmap *src_bitmap;
10699 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
10700 boolean special_animation = (action != ACTION_DEFAULT &&
10701 g->anim_frames == 3 &&
10702 g->anim_delay == 2 &&
10703 g->anim_mode & ANIM_LINEAR);
10704 int sync_frame = (i == Xdrip_stretch ? 7 :
10705 i == Xdrip_stretchB ? 7 :
10706 i == Ydrip_s2 ? j + 8 :
10707 i == Ydrip_s2B ? j + 8 :
10709 i == Xacid_2 ? 10 :
10710 i == Xacid_3 ? 20 :
10711 i == Xacid_4 ? 30 :
10712 i == Xacid_5 ? 40 :
10713 i == Xacid_6 ? 50 :
10714 i == Xacid_7 ? 60 :
10715 i == Xacid_8 ? 70 :
10716 i == Xfake_acid_1 ? 0 :
10717 i == Xfake_acid_2 ? 10 :
10718 i == Xfake_acid_3 ? 20 :
10719 i == Xfake_acid_4 ? 30 :
10720 i == Xfake_acid_5 ? 40 :
10721 i == Xfake_acid_6 ? 50 :
10722 i == Xfake_acid_7 ? 60 :
10723 i == Xfake_acid_8 ? 70 :
10725 i == Xball_2B ? j + 8 :
10726 i == Yball_eat ? j + 1 :
10727 i == Ykey_1_eat ? j + 1 :
10728 i == Ykey_2_eat ? j + 1 :
10729 i == Ykey_3_eat ? j + 1 :
10730 i == Ykey_4_eat ? j + 1 :
10731 i == Ykey_5_eat ? j + 1 :
10732 i == Ykey_6_eat ? j + 1 :
10733 i == Ykey_7_eat ? j + 1 :
10734 i == Ykey_8_eat ? j + 1 :
10735 i == Ylenses_eat ? j + 1 :
10736 i == Ymagnify_eat ? j + 1 :
10737 i == Ygrass_eat ? j + 1 :
10738 i == Ydirt_eat ? j + 1 :
10739 i == Xamoeba_1 ? 0 :
10740 i == Xamoeba_2 ? 1 :
10741 i == Xamoeba_3 ? 2 :
10742 i == Xamoeba_4 ? 3 :
10743 i == Xamoeba_5 ? 0 :
10744 i == Xamoeba_6 ? 1 :
10745 i == Xamoeba_7 ? 2 :
10746 i == Xamoeba_8 ? 3 :
10747 i == Xexit_2 ? j + 8 :
10748 i == Xexit_3 ? j + 16 :
10749 i == Xdynamite_1 ? 0 :
10750 i == Xdynamite_2 ? 8 :
10751 i == Xdynamite_3 ? 16 :
10752 i == Xdynamite_4 ? 24 :
10753 i == Xsand_stonein_1 ? j + 1 :
10754 i == Xsand_stonein_2 ? j + 9 :
10755 i == Xsand_stonein_3 ? j + 17 :
10756 i == Xsand_stonein_4 ? j + 25 :
10757 i == Xsand_stoneout_1 && j == 0 ? 0 :
10758 i == Xsand_stoneout_1 && j == 1 ? 0 :
10759 i == Xsand_stoneout_1 && j == 2 ? 1 :
10760 i == Xsand_stoneout_1 && j == 3 ? 2 :
10761 i == Xsand_stoneout_1 && j == 4 ? 2 :
10762 i == Xsand_stoneout_1 && j == 5 ? 3 :
10763 i == Xsand_stoneout_1 && j == 6 ? 4 :
10764 i == Xsand_stoneout_1 && j == 7 ? 4 :
10765 i == Xsand_stoneout_2 && j == 0 ? 5 :
10766 i == Xsand_stoneout_2 && j == 1 ? 6 :
10767 i == Xsand_stoneout_2 && j == 2 ? 7 :
10768 i == Xsand_stoneout_2 && j == 3 ? 8 :
10769 i == Xsand_stoneout_2 && j == 4 ? 9 :
10770 i == Xsand_stoneout_2 && j == 5 ? 11 :
10771 i == Xsand_stoneout_2 && j == 6 ? 13 :
10772 i == Xsand_stoneout_2 && j == 7 ? 15 :
10773 i == Xboom_bug && j == 1 ? 2 :
10774 i == Xboom_bug && j == 2 ? 2 :
10775 i == Xboom_bug && j == 3 ? 4 :
10776 i == Xboom_bug && j == 4 ? 4 :
10777 i == Xboom_bug && j == 5 ? 2 :
10778 i == Xboom_bug && j == 6 ? 2 :
10779 i == Xboom_bug && j == 7 ? 0 :
10780 i == Xboom_bomb && j == 1 ? 2 :
10781 i == Xboom_bomb && j == 2 ? 2 :
10782 i == Xboom_bomb && j == 3 ? 4 :
10783 i == Xboom_bomb && j == 4 ? 4 :
10784 i == Xboom_bomb && j == 5 ? 2 :
10785 i == Xboom_bomb && j == 6 ? 2 :
10786 i == Xboom_bomb && j == 7 ? 0 :
10787 i == Xboom_android && j == 7 ? 6 :
10788 i == Xboom_1 && j == 1 ? 2 :
10789 i == Xboom_1 && j == 2 ? 2 :
10790 i == Xboom_1 && j == 3 ? 4 :
10791 i == Xboom_1 && j == 4 ? 4 :
10792 i == Xboom_1 && j == 5 ? 6 :
10793 i == Xboom_1 && j == 6 ? 6 :
10794 i == Xboom_1 && j == 7 ? 8 :
10795 i == Xboom_2 && j == 0 ? 8 :
10796 i == Xboom_2 && j == 1 ? 8 :
10797 i == Xboom_2 && j == 2 ? 10 :
10798 i == Xboom_2 && j == 3 ? 10 :
10799 i == Xboom_2 && j == 4 ? 10 :
10800 i == Xboom_2 && j == 5 ? 12 :
10801 i == Xboom_2 && j == 6 ? 12 :
10802 i == Xboom_2 && j == 7 ? 12 :
10803 special_animation && j == 4 ? 3 :
10804 effective_action != action ? 0 :
10808 Bitmap *debug_bitmap = g_em->bitmap;
10809 int debug_src_x = g_em->src_x;
10810 int debug_src_y = g_em->src_y;
10813 int frame = getAnimationFrame(g->anim_frames,
10816 g->anim_start_frame,
10819 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y,
10820 g->double_movement && is_backside);
10822 g_em->bitmap = src_bitmap;
10823 g_em->src_x = src_x;
10824 g_em->src_y = src_y;
10825 g_em->src_offset_x = 0;
10826 g_em->src_offset_y = 0;
10827 g_em->dst_offset_x = 0;
10828 g_em->dst_offset_y = 0;
10829 g_em->width = TILEX;
10830 g_em->height = TILEY;
10832 g_em->preserve_background = FALSE;
10835 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
10840 g_em->crumbled_bitmap = NULL;
10841 g_em->crumbled_src_x = 0;
10842 g_em->crumbled_src_y = 0;
10843 g_em->crumbled_border_size = 0;
10845 g_em->has_crumbled_graphics = FALSE;
10848 if (has_crumbled_graphics && crumbled == IMG_EMPTY_SPACE)
10849 printf("::: empty crumbled: %d [%s], %d, %d\n",
10850 effective_element, element_info[effective_element].token_name,
10851 effective_action, direction);
10854 /* if element can be crumbled, but certain action graphics are just empty
10855 space (like instantly snapping sand to empty space in 1 frame), do not
10856 treat these empty space graphics as crumbled graphics in EMC engine */
10857 if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
10859 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
10860 g_crumbled->anim_delay,
10861 g_crumbled->anim_mode,
10862 g_crumbled->anim_start_frame,
10865 getGraphicSource(crumbled, frame_crumbled, &src_bitmap, &src_x, &src_y);
10867 g_em->has_crumbled_graphics = TRUE;
10868 g_em->crumbled_bitmap = src_bitmap;
10869 g_em->crumbled_src_x = src_x;
10870 g_em->crumbled_src_y = src_y;
10871 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
10875 if (g_em == &graphic_info_em_object[207][0])
10876 printf("... %d, %d [%d, %d, %d, %d] [%d, %d, %d, %d, %d, %d => %d]\n",
10877 graphic_info_em_object[207][0].crumbled_src_x,
10878 graphic_info_em_object[207][0].crumbled_src_y,
10880 crumbled, frame, src_x, src_y,
10885 g->anim_start_frame,
10887 gfx.anim_random_frame,
10892 printf("::: EMC tile %d is crumbled\n", i);
10898 if (element == EL_ROCK &&
10899 effective_action == ACTION_FILLING)
10900 printf("::: has_action_graphics == %d\n", has_action_graphics);
10903 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
10904 effective_action == ACTION_MOVING ||
10905 effective_action == ACTION_PUSHING ||
10906 effective_action == ACTION_EATING)) ||
10907 (!has_action_graphics && (effective_action == ACTION_FILLING ||
10908 effective_action == ACTION_EMPTYING)))
10911 (effective_action == ACTION_FALLING ||
10912 effective_action == ACTION_FILLING ||
10913 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
10914 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
10915 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
10916 int num_steps = (i == Ydrip_s1 ? 16 :
10917 i == Ydrip_s1B ? 16 :
10918 i == Ydrip_s2 ? 16 :
10919 i == Ydrip_s2B ? 16 :
10920 i == Xsand_stonein_1 ? 32 :
10921 i == Xsand_stonein_2 ? 32 :
10922 i == Xsand_stonein_3 ? 32 :
10923 i == Xsand_stonein_4 ? 32 :
10924 i == Xsand_stoneout_1 ? 16 :
10925 i == Xsand_stoneout_2 ? 16 : 8);
10926 int cx = ABS(dx) * (TILEX / num_steps);
10927 int cy = ABS(dy) * (TILEY / num_steps);
10928 int step_frame = (i == Ydrip_s2 ? j + 8 :
10929 i == Ydrip_s2B ? j + 8 :
10930 i == Xsand_stonein_2 ? j + 8 :
10931 i == Xsand_stonein_3 ? j + 16 :
10932 i == Xsand_stonein_4 ? j + 24 :
10933 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
10934 int step = (is_backside ? step_frame : num_steps - step_frame);
10936 if (is_backside) /* tile where movement starts */
10938 if (dx < 0 || dy < 0)
10940 g_em->src_offset_x = cx * step;
10941 g_em->src_offset_y = cy * step;
10945 g_em->dst_offset_x = cx * step;
10946 g_em->dst_offset_y = cy * step;
10949 else /* tile where movement ends */
10951 if (dx < 0 || dy < 0)
10953 g_em->dst_offset_x = cx * step;
10954 g_em->dst_offset_y = cy * step;
10958 g_em->src_offset_x = cx * step;
10959 g_em->src_offset_y = cy * step;
10963 g_em->width = TILEX - cx * step;
10964 g_em->height = TILEY - cy * step;
10967 /* create unique graphic identifier to decide if tile must be redrawn */
10968 /* bit 31 - 16 (16 bit): EM style graphic
10969 bit 15 - 12 ( 4 bit): EM style frame
10970 bit 11 - 6 ( 6 bit): graphic width
10971 bit 5 - 0 ( 6 bit): graphic height */
10972 g_em->unique_identifier =
10973 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
10977 /* skip check for EMC elements not contained in original EMC artwork */
10978 if (element == EL_EMC_FAKE_ACID)
10981 if (g_em->bitmap != debug_bitmap ||
10982 g_em->src_x != debug_src_x ||
10983 g_em->src_y != debug_src_y ||
10984 g_em->src_offset_x != 0 ||
10985 g_em->src_offset_y != 0 ||
10986 g_em->dst_offset_x != 0 ||
10987 g_em->dst_offset_y != 0 ||
10988 g_em->width != TILEX ||
10989 g_em->height != TILEY)
10991 static int last_i = -1;
10999 printf("::: EMC GFX ERROR for element %d -> %d ('%s', '%s', %d)",
11000 i, element, element_info[element].token_name,
11001 element_action_info[effective_action].suffix, direction);
11003 if (element != effective_element)
11004 printf(" [%d ('%s')]",
11006 element_info[effective_element].token_name);
11010 if (g_em->bitmap != debug_bitmap)
11011 printf(" %d (%d): different bitmap! (0x%08x != 0x%08x)\n",
11012 j, is_backside, (int)(g_em->bitmap), (int)(debug_bitmap));
11014 if (g_em->src_x != debug_src_x ||
11015 g_em->src_y != debug_src_y)
11016 printf(" frame %d (%c): %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
11017 j, (is_backside ? 'B' : 'F'),
11018 g_em->src_x, g_em->src_y,
11019 g_em->src_x / 32, g_em->src_y / 32,
11020 debug_src_x, debug_src_y,
11021 debug_src_x / 32, debug_src_y / 32);
11023 if (g_em->src_offset_x != 0 ||
11024 g_em->src_offset_y != 0 ||
11025 g_em->dst_offset_x != 0 ||
11026 g_em->dst_offset_y != 0)
11027 printf(" %d (%d): offsets %d,%d and %d,%d should be all 0\n",
11029 g_em->src_offset_x, g_em->src_offset_y,
11030 g_em->dst_offset_x, g_em->dst_offset_y);
11032 if (g_em->width != TILEX ||
11033 g_em->height != TILEY)
11034 printf(" %d (%d): size %d,%d should be %d,%d\n",
11036 g_em->width, g_em->height, TILEX, TILEY);
11038 num_em_gfx_errors++;
11045 for (i = 0; i < TILE_MAX; i++)
11047 for (j = 0; j < 8; j++)
11049 int element = object_mapping[i].element_rnd;
11050 int action = object_mapping[i].action;
11051 int direction = object_mapping[i].direction;
11052 boolean is_backside = object_mapping[i].is_backside;
11053 int graphic_action = el_act_dir2img(element, action, direction);
11054 int graphic_default = el_act_dir2img(element, ACTION_DEFAULT, direction);
11056 if ((action == ACTION_SMASHED_BY_ROCK ||
11057 action == ACTION_SMASHED_BY_SPRING ||
11058 action == ACTION_EATING) &&
11059 graphic_action == graphic_default)
11061 int e = (action == ACTION_SMASHED_BY_ROCK ? Ystone_s :
11062 action == ACTION_SMASHED_BY_SPRING ? Yspring_s :
11063 direction == MV_LEFT ? (is_backside? Yspring_wB: Yspring_w) :
11064 direction == MV_RIGHT ? (is_backside? Yspring_eB: Yspring_e) :
11067 /* no separate animation for "smashed by rock" -- use rock instead */
11068 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
11069 struct GraphicInfo_EM *g_xx = &graphic_info_em_object[e][7 - j];
11071 g_em->bitmap = g_xx->bitmap;
11072 g_em->src_x = g_xx->src_x;
11073 g_em->src_y = g_xx->src_y;
11074 g_em->src_offset_x = g_xx->src_offset_x;
11075 g_em->src_offset_y = g_xx->src_offset_y;
11076 g_em->dst_offset_x = g_xx->dst_offset_x;
11077 g_em->dst_offset_y = g_xx->dst_offset_y;
11078 g_em->width = g_xx->width;
11079 g_em->height = g_xx->height;
11080 g_em->unique_identifier = g_xx->unique_identifier;
11083 g_em->preserve_background = TRUE;
11088 for (p = 0; p < MAX_PLAYERS; p++)
11090 for (i = 0; i < SPR_MAX; i++)
11092 int element = player_mapping[p][i].element_rnd;
11093 int action = player_mapping[p][i].action;
11094 int direction = player_mapping[p][i].direction;
11096 for (j = 0; j < 8; j++)
11098 int effective_element = element;
11099 int effective_action = action;
11100 int graphic = (direction == MV_NONE ?
11101 el_act2img(effective_element, effective_action) :
11102 el_act_dir2img(effective_element, effective_action,
11104 struct GraphicInfo *g = &graphic_info[graphic];
11105 struct GraphicInfo_EM *g_em = &graphic_info_em_player[p][i][7 - j];
11106 Bitmap *src_bitmap;
11108 int sync_frame = j;
11111 Bitmap *debug_bitmap = g_em->bitmap;
11112 int debug_src_x = g_em->src_x;
11113 int debug_src_y = g_em->src_y;
11116 int frame = getAnimationFrame(g->anim_frames,
11119 g->anim_start_frame,
11122 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
11124 g_em->bitmap = src_bitmap;
11125 g_em->src_x = src_x;
11126 g_em->src_y = src_y;
11127 g_em->src_offset_x = 0;
11128 g_em->src_offset_y = 0;
11129 g_em->dst_offset_x = 0;
11130 g_em->dst_offset_y = 0;
11131 g_em->width = TILEX;
11132 g_em->height = TILEY;
11136 /* skip check for EMC elements not contained in original EMC artwork */
11137 if (element == EL_PLAYER_3 ||
11138 element == EL_PLAYER_4)
11141 if (g_em->bitmap != debug_bitmap ||
11142 g_em->src_x != debug_src_x ||
11143 g_em->src_y != debug_src_y)
11145 static int last_i = -1;
11153 printf("::: EMC GFX ERROR for p/a %d/%d -> %d ('%s', '%s', %d)",
11154 p, i, element, element_info[element].token_name,
11155 element_action_info[effective_action].suffix, direction);
11157 if (element != effective_element)
11158 printf(" [%d ('%s')]",
11160 element_info[effective_element].token_name);
11164 if (g_em->bitmap != debug_bitmap)
11165 printf(" %d: different bitmap! (0x%08x != 0x%08x)\n",
11166 j, (int)(g_em->bitmap), (int)(debug_bitmap));
11168 if (g_em->src_x != debug_src_x ||
11169 g_em->src_y != debug_src_y)
11170 printf(" frame %d: %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
11172 g_em->src_x, g_em->src_y,
11173 g_em->src_x / 32, g_em->src_y / 32,
11174 debug_src_x, debug_src_y,
11175 debug_src_x / 32, debug_src_y / 32);
11177 num_em_gfx_errors++;
11187 printf("::: [%d errors found]\n", num_em_gfx_errors);
11193 void CheckSingleStepMode_EM(byte action[MAX_PLAYERS], int frame,
11194 boolean any_player_moving,
11195 boolean player_is_dropping)
11197 if (tape.single_step && tape.recording && !tape.pausing)
11200 boolean active_players = FALSE;
11203 for (i = 0; i < MAX_PLAYERS; i++)
11204 if (action[i] != JOY_NO_ACTION)
11205 active_players = TRUE;
11209 if (frame == 0 && !player_is_dropping)
11210 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
11214 void CheckSingleStepMode_SP(boolean murphy_is_waiting,
11215 boolean murphy_is_dropping)
11218 printf("::: waiting: %d, dropping: %d\n",
11219 murphy_is_waiting, murphy_is_dropping);
11222 if (tape.single_step && tape.recording && !tape.pausing)
11224 // if (murphy_is_waiting || murphy_is_dropping)
11225 if (murphy_is_waiting)
11228 printf("::: murphy is waiting -> pause mode\n");
11231 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
11236 void getGraphicSource_SP(struct GraphicInfo_SP *g_sp,
11237 int graphic, int sync_frame, int x, int y)
11239 int frame = getGraphicAnimationFrame(graphic, sync_frame);
11241 getGraphicSource(graphic, frame, &g_sp->bitmap, &g_sp->src_x, &g_sp->src_y);
11244 boolean isNextAnimationFrame_SP(int graphic, int sync_frame)
11246 return (IS_NEXT_FRAME(sync_frame, graphic));
11249 int getGraphicInfo_Delay(int graphic)
11251 return graphic_info[graphic].anim_delay;
11254 void PlayMenuSoundExt(int sound)
11256 if (sound == SND_UNDEFINED)
11259 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
11260 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
11263 if (IS_LOOP_SOUND(sound))
11264 PlaySoundLoop(sound);
11269 void PlayMenuSound()
11271 PlayMenuSoundExt(menu.sound[game_status]);
11274 void PlayMenuSoundStereo(int sound, int stereo_position)
11276 if (sound == SND_UNDEFINED)
11279 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
11280 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
11283 if (IS_LOOP_SOUND(sound))
11284 PlaySoundExt(sound, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_LOOP);
11286 PlaySoundStereo(sound, stereo_position);
11289 void PlayMenuSoundIfLoopExt(int sound)
11291 if (sound == SND_UNDEFINED)
11294 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
11295 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
11298 if (IS_LOOP_SOUND(sound))
11299 PlaySoundLoop(sound);
11302 void PlayMenuSoundIfLoop()
11304 PlayMenuSoundIfLoopExt(menu.sound[game_status]);
11307 void PlayMenuMusicExt(int music)
11309 if (music == MUS_UNDEFINED)
11312 if (!setup.sound_music)
11318 void PlayMenuMusic()
11320 PlayMenuMusicExt(menu.music[game_status]);
11323 void PlaySoundActivating()
11326 PlaySound(SND_MENU_ITEM_ACTIVATING);
11330 void PlaySoundSelecting()
11333 PlaySound(SND_MENU_ITEM_SELECTING);
11337 void ToggleFullscreenOrChangeWindowScalingIfNeeded()
11339 boolean change_fullscreen = (setup.fullscreen !=
11340 video.fullscreen_enabled);
11341 boolean change_fullscreen_mode = (video.fullscreen_enabled &&
11342 !strEqual(setup.fullscreen_mode,
11343 video.fullscreen_mode_current));
11344 boolean change_window_scaling_percent = (!video.fullscreen_enabled &&
11345 setup.window_scaling_percent !=
11346 video.window_scaling_percent);
11348 if (change_window_scaling_percent && video.fullscreen_enabled)
11351 if (!change_window_scaling_percent && !video.fullscreen_available)
11354 #if defined(TARGET_SDL2)
11355 if (change_window_scaling_percent)
11357 SDLSetWindowScaling(setup.window_scaling_percent);
11361 else if (change_fullscreen)
11363 SDLSetWindowFullscreen(setup.fullscreen);
11365 /* set setup value according to successfully changed fullscreen mode */
11366 setup.fullscreen = video.fullscreen_enabled;
11372 if (change_fullscreen ||
11373 change_fullscreen_mode ||
11374 change_window_scaling_percent)
11376 Bitmap *tmp_backbuffer = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
11378 /* save backbuffer content which gets lost when toggling fullscreen mode */
11379 BlitBitmap(backbuffer, tmp_backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
11381 if (change_fullscreen_mode)
11383 /* keep fullscreen, but change fullscreen mode (screen resolution) */
11384 video.fullscreen_enabled = FALSE; /* force new fullscreen mode */
11387 if (change_window_scaling_percent)
11389 /* keep window mode, but change window scaling */
11390 video.fullscreen_enabled = TRUE; /* force new window scaling */
11393 /* toggle fullscreen */
11394 ChangeVideoModeIfNeeded(setup.fullscreen);
11396 /* set setup value according to successfully changed fullscreen mode */
11397 setup.fullscreen = video.fullscreen_enabled;
11399 /* restore backbuffer content from temporary backbuffer backup bitmap */
11400 BlitBitmap(tmp_backbuffer, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
11402 FreeBitmap(tmp_backbuffer);
11405 /* update visible window/screen */
11406 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
11408 redraw_mask = REDRAW_ALL;
11413 void ChangeViewportPropertiesIfNeeded()
11416 int *door_1_x = &DX;
11417 int *door_1_y = &DY;
11418 int *door_2_x = (game_status == GAME_MODE_EDITOR ? &EX : &VX);
11419 int *door_2_y = (game_status == GAME_MODE_EDITOR ? &EY : &VY);
11422 int gfx_game_mode = game_status;
11424 int gfx_game_mode = (game_status == GAME_MODE_PLAYING ||
11425 game_status == GAME_MODE_EDITOR ? game_status :
11428 int gfx_game_mode2 = (game_status == GAME_MODE_EDITOR ? GAME_MODE_DEFAULT :
11430 struct RectWithBorder *vp_playfield = &viewport.playfield[gfx_game_mode];
11431 struct RectWithBorder *vp_door_1 = &viewport.door_1[gfx_game_mode];
11432 struct RectWithBorder *vp_door_2 = &viewport.door_2[gfx_game_mode2];
11433 struct RectWithBorder *vp_door_3 = &viewport.door_2[GAME_MODE_EDITOR];
11434 int border_size = vp_playfield->border_size;
11435 int new_sx = vp_playfield->x + border_size;
11436 int new_sy = vp_playfield->y + border_size;
11437 int new_sxsize = vp_playfield->width - 2 * border_size;
11438 int new_sysize = vp_playfield->height - 2 * border_size;
11439 int new_real_sx = vp_playfield->x;
11440 int new_real_sy = vp_playfield->y;
11441 int new_full_sxsize = vp_playfield->width;
11442 int new_full_sysize = vp_playfield->height;
11443 int new_dx = vp_door_1->x;
11444 int new_dy = vp_door_1->y;
11445 int new_dxsize = vp_door_1->width;
11446 int new_dysize = vp_door_1->height;
11447 int new_vx = vp_door_2->x;
11448 int new_vy = vp_door_2->y;
11449 int new_vxsize = vp_door_2->width;
11450 int new_vysize = vp_door_2->height;
11451 int new_ex = vp_door_3->x;
11452 int new_ey = vp_door_3->y;
11453 int new_exsize = vp_door_3->width;
11454 int new_eysize = vp_door_3->height;
11456 int new_tilesize_var = TILESIZE / (setup.small_game_graphics ? 2 : 1);
11457 int tilesize = (gfx_game_mode == GAME_MODE_PLAYING ? new_tilesize_var :
11458 gfx_game_mode == GAME_MODE_EDITOR ? MINI_TILESIZE : TILESIZE);
11459 int new_scr_fieldx = new_sxsize / tilesize;
11460 int new_scr_fieldy = new_sysize / tilesize;
11461 int new_scr_fieldx_buffers = new_sxsize / new_tilesize_var;
11462 int new_scr_fieldy_buffers = new_sysize / new_tilesize_var;
11464 int new_scr_fieldx = (vp_playfield->width - 2 * border_size) / TILESIZE;
11465 int new_scr_fieldy = (vp_playfield->height - 2 * border_size) / TILESIZE;
11467 boolean init_gfx_buffers = FALSE;
11468 boolean init_video_buffer = FALSE;
11469 boolean init_gadgets_and_toons = FALSE;
11472 /* !!! TEST ONLY !!! */
11473 // InitGfxBuffers();
11477 if (viewport.window.width != WIN_XSIZE ||
11478 viewport.window.height != WIN_YSIZE)
11480 WIN_XSIZE = viewport.window.width;
11481 WIN_YSIZE = viewport.window.height;
11484 init_video_buffer = TRUE;
11485 init_gfx_buffers = TRUE;
11487 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
11491 SetDrawDeactivationMask(REDRAW_NONE);
11492 SetDrawBackgroundMask(REDRAW_FIELD);
11494 // RedrawBackground();
11498 // printf("::: video: init_video_buffer, init_gfx_buffers\n");
11501 if (new_scr_fieldx != SCR_FIELDX ||
11502 new_scr_fieldy != SCR_FIELDY)
11504 /* this always toggles between MAIN and GAME when using small tile size */
11506 SCR_FIELDX = new_scr_fieldx;
11507 SCR_FIELDY = new_scr_fieldy;
11509 // printf("::: new_scr_fieldx != SCR_FIELDX ...\n");
11513 if (new_tilesize_var != TILESIZE_VAR &&
11514 gfx_game_mode == GAME_MODE_PLAYING)
11516 /* doing this outside GAME_MODE_PLAYING would give wrong playfield size */
11518 TILESIZE_VAR = new_tilesize_var;
11520 init_gfx_buffers = TRUE;
11522 // printf("::: tilesize: init_gfx_buffers\n");
11526 if (new_sx != SX ||
11534 new_sxsize != SXSIZE ||
11535 new_sysize != SYSIZE ||
11536 new_dxsize != DXSIZE ||
11537 new_dysize != DYSIZE ||
11538 new_vxsize != VXSIZE ||
11539 new_vysize != VYSIZE ||
11540 new_exsize != EXSIZE ||
11541 new_eysize != EYSIZE ||
11542 new_real_sx != REAL_SX ||
11543 new_real_sy != REAL_SY ||
11544 new_full_sxsize != FULL_SXSIZE ||
11545 new_full_sysize != FULL_SYSIZE ||
11546 new_tilesize_var != TILESIZE_VAR
11549 vp_door_1->x != *door_1_x ||
11550 vp_door_1->y != *door_1_y ||
11551 vp_door_2->x != *door_2_x ||
11552 vp_door_2->y != *door_2_y
11557 // changing tile size invalidates scroll values of engine snapshots
11558 if (new_tilesize_var != TILESIZE_VAR)
11560 // printf("::: new_tilesize_var != TILESIZE_VAR\n");
11562 FreeEngineSnapshot();
11574 SXSIZE = new_sxsize;
11575 SYSIZE = new_sysize;
11576 DXSIZE = new_dxsize;
11577 DYSIZE = new_dysize;
11578 VXSIZE = new_vxsize;
11579 VYSIZE = new_vysize;
11580 EXSIZE = new_exsize;
11581 EYSIZE = new_eysize;
11582 REAL_SX = new_real_sx;
11583 REAL_SY = new_real_sy;
11584 FULL_SXSIZE = new_full_sxsize;
11585 FULL_SYSIZE = new_full_sysize;
11586 TILESIZE_VAR = new_tilesize_var;
11589 printf("::: %d, %d, %d [%d]\n",
11590 SCR_FIELDX, SCR_FIELDY, TILESIZE_VAR,
11591 setup.small_game_graphics);
11595 *door_1_x = vp_door_1->x;
11596 *door_1_y = vp_door_1->y;
11597 *door_2_x = vp_door_2->x;
11598 *door_2_y = vp_door_2->y;
11602 init_gfx_buffers = TRUE;
11604 // printf("::: viewports: init_gfx_buffers\n");
11610 if (gfx_game_mode == GAME_MODE_MAIN)
11614 init_gadgets_and_toons = TRUE;
11616 // printf("::: viewports: init_gadgets_and_toons\n");
11624 if (init_gfx_buffers)
11626 // printf("::: init_gfx_buffers\n");
11628 SCR_FIELDX = new_scr_fieldx_buffers;
11629 SCR_FIELDY = new_scr_fieldy_buffers;
11633 SCR_FIELDX = new_scr_fieldx;
11634 SCR_FIELDY = new_scr_fieldy;
11637 if (init_video_buffer)
11639 // printf("::: init_video_buffer\n");
11641 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
11643 SetDrawDeactivationMask(REDRAW_NONE);
11644 SetDrawBackgroundMask(REDRAW_FIELD);
11647 if (init_gadgets_and_toons)
11649 // printf("::: init_gadgets_and_toons\n");
11656 printf("::: %d, %d / %d, %d [%d]\n", VX, VY, EX, EY, game_status);