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 MAX_PARTS_PER_DOOR 8
45 #define MAX_DOOR_PARTS (NUM_DOORS * MAX_PARTS_PER_DOOR)
48 struct DoorPartOrderInfo
54 static struct DoorPartOrderInfo door_part_order[MAX_DOOR_PARTS];
56 struct DoorPartControlInfo
60 struct DoorPartPosInfo *pos;
63 static struct DoorPartControlInfo door_part_controls[] =
67 IMG_DOOR_1_GFX_PART_1,
72 IMG_DOOR_1_GFX_PART_2,
77 IMG_DOOR_1_GFX_PART_3,
82 IMG_DOOR_1_GFX_PART_4,
87 IMG_DOOR_1_GFX_PART_5,
92 IMG_DOOR_1_GFX_PART_6,
97 IMG_DOOR_1_GFX_PART_7,
102 IMG_DOOR_1_GFX_PART_8,
107 IMG_DOOR_2_GFX_PART_1,
112 IMG_DOOR_2_GFX_PART_2,
117 IMG_DOOR_2_GFX_PART_3,
122 IMG_DOOR_2_GFX_PART_4,
127 IMG_DOOR_2_GFX_PART_5,
132 IMG_DOOR_2_GFX_PART_6,
137 IMG_DOOR_2_GFX_PART_7,
142 IMG_DOOR_2_GFX_PART_8,
154 /* forward declaration for internal use */
155 static void UnmapToolButtons();
156 static void HandleToolButtons(struct GadgetInfo *);
157 static int el_act_dir2crm(int, int, int);
158 static int el_act2crm(int, int);
160 static struct GadgetInfo *tool_gadget[NUM_TOOL_BUTTONS];
161 static int request_gadget_id = -1;
163 static char *print_if_not_empty(int element)
165 static char *s = NULL;
166 char *token_name = element_info[element].token_name;
171 s = checked_malloc(strlen(token_name) + 10 + 1);
173 if (element != EL_EMPTY)
174 sprintf(s, "%d\t['%s']", element, token_name);
176 sprintf(s, "%d", element);
181 void DumpTile(int x, int y)
186 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
192 printf_line("-", 79);
193 printf("Field Info: SCREEN(%d, %d), LEVEL(%d, %d)\n", sx, sy, x, y);
194 printf_line("-", 79);
196 if (!IN_LEV_FIELD(x, y))
198 printf("(not in level field)\n");
204 printf(" Feld: %d\t['%s']\n", Feld[x][y],
205 element_info[Feld[x][y]].token_name);
206 printf(" Back: %s\n", print_if_not_empty(Back[x][y]));
207 printf(" Store: %s\n", print_if_not_empty(Store[x][y]));
208 printf(" Store2: %s\n", print_if_not_empty(Store2[x][y]));
209 printf(" StorePlayer: %s\n", print_if_not_empty(StorePlayer[x][y]));
210 printf(" MovPos: %d\n", MovPos[x][y]);
211 printf(" MovDir: %d\n", MovDir[x][y]);
212 printf(" MovDelay: %d\n", MovDelay[x][y]);
213 printf(" ChangeDelay: %d\n", ChangeDelay[x][y]);
214 printf(" CustomValue: %d\n", CustomValue[x][y]);
215 printf(" GfxElement: %d\n", GfxElement[x][y]);
216 printf(" GfxAction: %d\n", GfxAction[x][y]);
217 printf(" GfxFrame: %d\n", GfxFrame[x][y]);
221 void SetDrawtoField(int mode)
223 if (mode == DRAW_BUFFERED && setup.soft_scrolling)
231 BX2 = SCR_FIELDX + 1;
232 BY2 = SCR_FIELDY + 1;
251 BX2 = SCR_FIELDX + 1;
252 BY2 = SCR_FIELDY + 1;
267 drawto_field = fieldbuffer;
269 else /* DRAW_BACKBUFFER */
275 BX2 = SCR_FIELDX - 1;
276 BY2 = SCR_FIELDY - 1;
280 drawto_field = backbuffer;
284 void RedrawPlayfield(boolean force_redraw, int x, int y, int width, int height)
286 if (game_status == GAME_MODE_PLAYING &&
287 level.game_engine_type == GAME_ENGINE_TYPE_EM)
289 /* currently there is no partial redraw -- always redraw whole playfield */
290 RedrawPlayfield_EM(TRUE);
292 /* blit playfield from scroll buffer to normal back buffer for fading in */
293 BlitScreenToBitmap_EM(backbuffer);
295 else if (game_status == GAME_MODE_PLAYING &&
296 level.game_engine_type == GAME_ENGINE_TYPE_SP)
298 /* currently there is no partial redraw -- always redraw whole playfield */
299 RedrawPlayfield_SP(TRUE);
301 /* blit playfield from scroll buffer to normal back buffer for fading in */
302 BlitScreenToBitmap_SP(backbuffer);
304 else if (game_status == GAME_MODE_PLAYING &&
305 !game.envelope_active)
311 width = gfx.sxsize + 2 * TILEX;
312 height = gfx.sysize + 2 * TILEY;
318 int x1 = (x - SX) / TILEX, y1 = (y - SY) / TILEY;
319 int x2 = (x - SX + width) / TILEX, y2 = (y - SY + height) / TILEY;
321 for (xx = BX1; xx <= BX2; xx++)
322 for (yy = BY1; yy <= BY2; yy++)
323 if (xx >= x1 && xx <= x2 && yy >= y1 && yy <= y2)
324 DrawScreenField(xx, yy);
328 if (setup.soft_scrolling)
330 int fx = FX, fy = FY;
332 fx += (ScreenMovDir & (MV_LEFT|MV_RIGHT) ? ScreenGfxPos : 0);
333 fy += (ScreenMovDir & (MV_UP|MV_DOWN) ? ScreenGfxPos : 0);
335 BlitBitmap(fieldbuffer, backbuffer, fx,fy, SXSIZE,SYSIZE, SX,SY);
347 BlitBitmap(drawto, window, x, y, width, height, x, y);
350 void DrawMaskedBorder_Rect(int x, int y, int width, int height)
352 Bitmap *bitmap = graphic_info[IMG_GLOBAL_BORDER].bitmap;
354 SetClipOrigin(bitmap, bitmap->stored_clip_gc, 0, 0);
355 BlitBitmapMasked(bitmap, backbuffer, x, y, width, height, x, y);
358 void DrawMaskedBorder_FIELD()
360 if (global.border_status >= GAME_MODE_TITLE &&
361 global.border_status <= GAME_MODE_PLAYING &&
362 border.draw_masked[global.border_status])
363 DrawMaskedBorder_Rect(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
366 void DrawMaskedBorder_DOOR_1()
368 if (border.draw_masked[GFX_SPECIAL_ARG_DOOR] &&
369 (global.border_status != GAME_MODE_EDITOR ||
370 border.draw_masked[GFX_SPECIAL_ARG_EDITOR]))
371 DrawMaskedBorder_Rect(DX, DY, DXSIZE, DYSIZE);
374 void DrawMaskedBorder_DOOR_2()
376 if (border.draw_masked[GFX_SPECIAL_ARG_DOOR] &&
377 global.border_status != GAME_MODE_EDITOR)
378 DrawMaskedBorder_Rect(VX, VY, VXSIZE, VYSIZE);
381 void DrawMaskedBorder_DOOR_3()
383 /* currently not available */
386 void DrawMaskedBorder_ALL()
388 DrawMaskedBorder_FIELD();
389 DrawMaskedBorder_DOOR_1();
390 DrawMaskedBorder_DOOR_2();
391 DrawMaskedBorder_DOOR_3();
394 void DrawMaskedBorder(int redraw_mask)
396 /* never draw masked screen borders on borderless screens */
397 if (effectiveGameStatus() == GAME_MODE_LOADING ||
398 effectiveGameStatus() == GAME_MODE_TITLE)
401 /* never draw masked screen borders when displaying request outside door */
402 if (effectiveGameStatus() == GAME_MODE_PSEUDO_DOOR &&
403 global.use_envelope_request)
406 if (redraw_mask & REDRAW_ALL)
407 DrawMaskedBorder_ALL();
410 if (redraw_mask & REDRAW_FIELD)
411 DrawMaskedBorder_FIELD();
412 if (redraw_mask & REDRAW_DOOR_1)
413 DrawMaskedBorder_DOOR_1();
414 if (redraw_mask & REDRAW_DOOR_2)
415 DrawMaskedBorder_DOOR_2();
416 if (redraw_mask & REDRAW_DOOR_3)
417 DrawMaskedBorder_DOOR_3();
421 void BlitScreenToBitmap(Bitmap *target_bitmap)
423 DrawBuffer *buffer = (drawto_field == window ? backbuffer : drawto_field);
424 int fx = FX, fy = FY;
427 int dx = (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
428 int dy = (ScreenMovDir & (MV_UP | MV_DOWN) ? ScreenGfxPos : 0);
429 int dx_var = dx * TILESIZE_VAR / TILESIZE;
430 int dy_var = dy * TILESIZE_VAR / TILESIZE;
433 // fx += dx * TILESIZE_VAR / TILESIZE;
434 // fy += dy * TILESIZE_VAR / TILESIZE;
436 fx += (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
437 fy += (ScreenMovDir & (MV_UP | MV_DOWN) ? ScreenGfxPos : 0);
440 ffx = (scroll_x - SBX_Left) * TILEX_VAR + dx_var;
441 ffy = (scroll_y - SBY_Upper) * TILEY_VAR + dy_var;
443 if (EVEN(SCR_FIELDX))
445 if (ffx < SBX_Right * TILEX_VAR + TILEX_VAR / 2 + TILEX_VAR)
446 fx += dx_var - MIN(ffx, TILEX_VAR / 2) + TILEX_VAR;
448 fx += (dx_var > 0 ? TILEX_VAR : 0);
455 if (EVEN(SCR_FIELDY))
457 if (ffy < SBY_Lower * TILEY_VAR + TILEY_VAR / 2 + TILEY_VAR)
458 fy += dy_var - MIN(ffy, TILEY_VAR / 2) + TILEY_VAR;
460 fy += (dy_var > 0 ? TILEY_VAR : 0);
468 printf("::: (%d, %d) [(%d / %d, %d / %d)] => %d, %d\n",
471 SBY_Upper, SBY_Lower,
475 if (border.draw_masked[GAME_MODE_PLAYING])
477 if (buffer != backbuffer)
479 /* copy playfield buffer to backbuffer to add masked border */
480 BlitBitmap(buffer, backbuffer, fx, fy, SXSIZE, SYSIZE, SX, SY);
481 DrawMaskedBorder(REDRAW_FIELD);
484 BlitBitmap(backbuffer, target_bitmap,
485 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
490 BlitBitmap(buffer, target_bitmap, fx, fy, SXSIZE, SYSIZE, SX, SY);
497 DrawBuffer *buffer = (drawto_field == window ? backbuffer : drawto_field);
500 printf("::: TILES TO REFRESH: %d\n", redraw_tiles);
501 for (x = 0; x < SCR_FIELDX; x++)
502 for (y = 0 ; y < SCR_FIELDY; y++)
503 if (redraw[redraw_x1 + x][redraw_y1 + y])
504 printf("::: - %d, %d [%s]\n",
505 LEVELX(x), LEVELY(y),
506 EL_NAME(Feld[LEVELX(x)][LEVELY(y)]));
509 if (redraw_mask & REDRAW_TILES && redraw_tiles > REDRAWTILES_THRESHOLD)
510 redraw_mask |= REDRAW_FIELD;
513 // never redraw single tiles, always redraw the whole field
514 // (redrawing single tiles up to a certain threshold was faster on old,
515 // now legacy graphics, but slows things down on modern graphics now)
516 // UPDATE: this is now globally defined by value of REDRAWTILES_THRESHOLD
517 if (redraw_mask & REDRAW_TILES)
518 redraw_mask |= REDRAW_FIELD;
522 /* !!! TEST ONLY !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */
523 /* (force full redraw) */
524 if (game_status == GAME_MODE_PLAYING)
525 redraw_mask |= REDRAW_FIELD;
528 if (redraw_mask & REDRAW_FIELD)
529 redraw_mask &= ~REDRAW_TILES;
531 if (redraw_mask == REDRAW_NONE)
536 if (redraw_mask & REDRAW_ALL)
537 printf("[REDRAW_ALL]");
538 if (redraw_mask & REDRAW_FIELD)
539 printf("[REDRAW_FIELD]");
540 if (redraw_mask & REDRAW_TILES)
541 printf("[REDRAW_TILES]");
542 if (redraw_mask & REDRAW_DOOR_1)
543 printf("[REDRAW_DOOR_1]");
544 if (redraw_mask & REDRAW_DOOR_2)
545 printf("[REDRAW_DOOR_2]");
546 if (redraw_mask & REDRAW_FROM_BACKBUFFER)
547 printf("[REDRAW_FROM_BACKBUFFER]");
548 printf(" [%d]\n", FrameCounter);
551 if (redraw_mask & REDRAW_TILES &&
552 game_status == GAME_MODE_PLAYING &&
553 border.draw_masked[GAME_MODE_PLAYING])
554 redraw_mask |= REDRAW_FIELD;
556 if (global.fps_slowdown && game_status == GAME_MODE_PLAYING)
558 static boolean last_frame_skipped = FALSE;
559 boolean skip_even_when_not_scrolling = TRUE;
560 boolean just_scrolling = (ScreenMovDir != 0);
561 boolean verbose = FALSE;
563 if (global.fps_slowdown_factor > 1 &&
564 (FrameCounter % global.fps_slowdown_factor) &&
565 (just_scrolling || skip_even_when_not_scrolling))
567 redraw_mask &= ~REDRAW_MAIN;
569 last_frame_skipped = TRUE;
572 printf("FRAME SKIPPED\n");
576 if (last_frame_skipped)
577 redraw_mask |= REDRAW_FIELD;
579 last_frame_skipped = FALSE;
582 printf("frame not skipped\n");
586 /* synchronize X11 graphics at this point; if we would synchronize the
587 display immediately after the buffer switching (after the XFlush),
588 this could mean that we have to wait for the graphics to complete,
589 although we could go on doing calculations for the next frame */
593 /* never draw masked border to backbuffer when using playfield buffer */
594 if (game_status != GAME_MODE_PLAYING ||
595 redraw_mask & REDRAW_FROM_BACKBUFFER ||
596 buffer == backbuffer)
597 DrawMaskedBorder(redraw_mask);
599 DrawMaskedBorder(redraw_mask & REDRAW_DOORS);
601 if (redraw_mask & REDRAW_ALL)
603 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
605 redraw_mask = REDRAW_NONE;
608 if (redraw_mask & REDRAW_FIELD)
611 printf("::: REDRAW_FIELD\n");
614 if (game_status != GAME_MODE_PLAYING ||
615 redraw_mask & REDRAW_FROM_BACKBUFFER)
617 BlitBitmap(backbuffer, window,
618 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE, REAL_SX, REAL_SY);
623 BlitScreenToBitmap(window);
625 int fx = FX, fy = FY;
628 int dx = (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
629 int dy = (ScreenMovDir & (MV_UP | MV_DOWN) ? ScreenGfxPos : 0);
630 int dx_var = dx * TILESIZE_VAR / TILESIZE;
631 int dy_var = dy * TILESIZE_VAR / TILESIZE;
634 // fx += dx * TILESIZE_VAR / TILESIZE;
635 // fy += dy * TILESIZE_VAR / TILESIZE;
637 fx += (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
638 fy += (ScreenMovDir & (MV_UP | MV_DOWN) ? ScreenGfxPos : 0);
641 /* !!! THIS WORKS !!! */
643 printf("::: %d, %d\n", scroll_x, scroll_y);
645 ffx = (scroll_x - SBX_Left) * TILEX_VAR + dx_var;
646 ffy = (scroll_y - SBY_Upper) * TILEY_VAR + dy_var;
648 if (EVEN(SCR_FIELDX))
650 if (ffx < SBX_Right * TILEX_VAR + TILEX_VAR / 2 + TILEX_VAR)
651 fx += dx_var - MIN(ffx, TILEX_VAR / 2) + TILEX_VAR;
653 fx += (dx > 0 ? TILEX_VAR : 0);
660 if (EVEN(SCR_FIELDY))
662 if (ffy < SBY_Lower * TILEY_VAR + TILEY_VAR / 2 + TILEY_VAR)
663 fy += dy_var - MIN(ffy, TILEY_VAR / 2) + TILEY_VAR;
665 fy += (dy > 0 ? TILEY_VAR : 0);
672 if (border.draw_masked[GAME_MODE_PLAYING])
674 if (buffer != backbuffer)
676 /* copy playfield buffer to backbuffer to add masked border */
677 BlitBitmap(buffer, backbuffer, fx, fy, SXSIZE, SYSIZE, SX, SY);
678 DrawMaskedBorder(REDRAW_FIELD);
681 BlitBitmap(backbuffer, window,
682 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
687 BlitBitmap(buffer, window, fx, fy, SXSIZE, SYSIZE, SX, SY);
693 printf("redrawing all (ScreenGfxPos == %d) because %s\n",
695 (setup.soft_scrolling ?
696 "setup.soft_scrolling" :
697 ABS(ScreenGfxPos) + ScrollStepSize == TILEX ?
698 "ABS(ScreenGfxPos) + ScrollStepSize == TILEX" :
699 ABS(ScreenGfxPos) == ScrollStepSize ?
700 "ABS(ScreenGfxPos) == ScrollStepSize" :
701 "redraw_tiles > REDRAWTILES_THRESHOLD"));
706 redraw_mask &= ~REDRAW_MAIN;
709 if (redraw_mask & REDRAW_DOORS)
711 if (redraw_mask & REDRAW_DOOR_1)
712 BlitBitmap(backbuffer, window, DX, DY, DXSIZE, DYSIZE, DX, DY);
714 if (redraw_mask & REDRAW_DOOR_2)
715 BlitBitmap(backbuffer, window, VX, VY, VXSIZE, VYSIZE, VX, VY);
717 if (redraw_mask & REDRAW_DOOR_3)
718 BlitBitmap(backbuffer, window, EX, EY, EXSIZE, EYSIZE, EX, EY);
720 redraw_mask &= ~REDRAW_DOORS;
723 if (redraw_mask & REDRAW_MICROLEVEL)
725 BlitBitmap(backbuffer, window, SX, SY + 10 * TILEY, SXSIZE, 7 * TILEY,
726 SX, SY + 10 * TILEY);
728 redraw_mask &= ~REDRAW_MICROLEVEL;
731 if (redraw_mask & REDRAW_TILES)
734 printf("::: REDRAW_TILES\n");
740 InitGfxClipRegion(TRUE, SX, SY, SXSIZE, SYSIZE);
743 int sx = SX; // - (EVEN(SCR_FIELDX) ? TILEX_VAR / 2 : 0);
744 int sy = SY; // + (EVEN(SCR_FIELDY) ? TILEY_VAR / 2 : 0);
747 int dx_var = dx * TILESIZE_VAR / TILESIZE;
748 int dy_var = dy * TILESIZE_VAR / TILESIZE;
750 int fx = FX, fy = FY;
752 int scr_fieldx = SCR_FIELDX + (EVEN(SCR_FIELDX) ? 2 : 0);
753 int scr_fieldy = SCR_FIELDY + (EVEN(SCR_FIELDY) ? 2 : 0);
755 ffx = (scroll_x - SBX_Left) * TILEX_VAR + dx_var;
756 ffy = (scroll_y - SBY_Upper) * TILEY_VAR + dy_var;
758 if (EVEN(SCR_FIELDX))
760 if (ffx < SBX_Right * TILEX_VAR + TILEX_VAR / 2 + TILEX_VAR)
762 fx += dx_var - MIN(ffx, TILEX_VAR / 2) + TILEX_VAR;
771 fx += (dx_var > 0 ? TILEX_VAR : 0);
775 if (EVEN(SCR_FIELDY))
777 if (ffy < SBY_Lower * TILEY_VAR + TILEY_VAR / 2 + TILEY_VAR)
779 fy += dy_var - MIN(ffy, TILEY_VAR / 2) + TILEY_VAR;
788 fy += (dy_var > 0 ? TILEY_VAR : 0);
793 printf("::: %d, %d, %d, %d\n", sx, sy, SCR_FIELDX, SCR_FIELDY);
796 for (x = 0; x < scr_fieldx; x++)
797 for (y = 0 ; y < scr_fieldy; y++)
798 if (redraw[redraw_x1 + x][redraw_y1 + y])
799 BlitBitmap(buffer, window,
800 FX + x * TILEX_VAR, FY + y * TILEY_VAR,
801 TILEX_VAR, TILEY_VAR,
802 sx + x * TILEX_VAR, sy + y * TILEY_VAR);
805 InitGfxClipRegion(FALSE, -1, -1, -1, -1);
807 for (x = 0; x < SCR_FIELDX; x++)
808 for (y = 0 ; y < SCR_FIELDY; y++)
809 if (redraw[redraw_x1 + x][redraw_y1 + y])
810 BlitBitmap(buffer, window,
811 FX + x * TILEX_VAR, FY + y * TILEY_VAR,
812 TILEX_VAR, TILEY_VAR,
813 SX + x * TILEX_VAR, SY + y * TILEY_VAR);
817 for (x = 0; x < SCR_FIELDX; x++)
818 for (y = 0 ; y < SCR_FIELDY; y++)
819 if (redraw[redraw_x1 + x][redraw_y1 + y])
820 BlitBitmap(buffer, window,
821 FX + x * TILEX, FY + y * TILEY, TILEX, TILEY,
822 SX + x * TILEX, SY + y * TILEY);
826 if (redraw_mask & REDRAW_FPS) /* display frames per second */
831 sprintf(info1, " (only every %d. frame)", global.fps_slowdown_factor);
832 if (!global.fps_slowdown)
835 sprintf(text, "%04.1f fps%s", global.frames_per_second, info1);
837 DrawTextExt(window, SX + SXSIZE + SX, 0, text, FONT_TEXT_2, BLIT_OPAQUE);
839 DrawTextExt(window, SX, SY, text, FONT_TEXT_2, BLIT_OPAQUE);
845 for (x = 0; x < MAX_BUF_XSIZE; x++)
846 for (y = 0; y < MAX_BUF_YSIZE; y++)
849 redraw_mask = REDRAW_NONE;
852 static void FadeCrossSaveBackbuffer()
854 BlitBitmap(backbuffer, bitmap_db_cross, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
857 static void FadeExt(int fade_mask, int fade_mode, int fade_type)
859 static int fade_type_skip = FADE_TYPE_NONE;
860 void (*draw_border_function)(void) = NULL;
861 Bitmap *bitmap = (fade_mode & FADE_TYPE_TRANSFORM ? bitmap_db_cross : NULL);
862 int x, y, width, height;
863 int fade_delay, post_delay;
865 if (fade_type == FADE_TYPE_FADE_OUT)
867 if (fade_type_skip != FADE_TYPE_NONE)
870 printf("::: skipping %d ... [%d] (X)\n", fade_mode, fade_type_skip);
873 /* skip all fade operations until specified fade operation */
874 if (fade_type & fade_type_skip)
875 fade_type_skip = FADE_TYPE_NONE;
880 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
882 FadeCrossSaveBackbuffer();
888 redraw_mask |= fade_mask;
890 if (fade_type == FADE_TYPE_SKIP)
893 printf("::: will skip %d ... [%d]\n", fade_mode, fade_type_skip);
896 fade_type_skip = fade_mode;
902 printf("::: !!! FADING %d ... [%d] [%d]\n", fade_mode, fade_type,
907 fade_delay = fading.fade_delay;
908 post_delay = (fade_mode == FADE_MODE_FADE_OUT ? fading.post_delay : 0);
911 if (fade_type_skip != FADE_TYPE_NONE)
914 printf("::: skipping %d ... [%d]\n", fade_mode, fade_type_skip);
917 /* skip all fade operations until specified fade operation */
918 if (fade_type & fade_type_skip)
919 fade_type_skip = FADE_TYPE_NONE;
929 if (global.autoplay_leveldir)
931 // fading.fade_mode = FADE_MODE_NONE;
938 if (fading.fade_mode == FADE_MODE_NONE)
946 /* !!! what about fade_mask == REDRAW_FIELD | REDRAW_ALL ??? !!! */
949 printf("::: NOW FADING %d ... [%d]\n", fade_mode, fade_type);
953 if (fade_mask == REDRAW_NONE)
954 fade_mask = REDRAW_FIELD;
957 // if (fade_mask & REDRAW_FIELD)
958 if (fade_mask == REDRAW_FIELD)
963 height = FULL_SYSIZE;
966 fade_delay = fading.fade_delay;
967 post_delay = (fade_mode == FADE_MODE_FADE_OUT ? fading.post_delay : 0);
970 if (border.draw_masked_when_fading)
971 draw_border_function = DrawMaskedBorder_FIELD; /* update when fading */
973 DrawMaskedBorder_FIELD(); /* draw once */
975 else /* REDRAW_ALL */
983 fade_delay = fading.fade_delay;
984 post_delay = (fade_mode == FADE_MODE_FADE_OUT ? fading.post_delay : 0);
989 if (!setup.fade_screens ||
991 fading.fade_mode == FADE_MODE_NONE)
993 if (!setup.fade_screens || fade_delay == 0)
996 if (fade_mode == FADE_MODE_FADE_OUT)
1000 if (fade_mode == FADE_MODE_FADE_OUT &&
1001 fading.fade_mode != FADE_MODE_NONE)
1002 ClearRectangle(backbuffer, x, y, width, height);
1006 BlitBitmap(backbuffer, window, x, y, width, height, x, y);
1007 redraw_mask = REDRAW_NONE;
1015 FadeRectangle(bitmap, x, y, width, height, fade_mode, fade_delay, post_delay,
1016 draw_border_function);
1018 redraw_mask &= ~fade_mask;
1021 void FadeIn(int fade_mask)
1023 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
1024 FadeExt(fade_mask, fading.fade_mode, FADE_TYPE_FADE_IN);
1026 FadeExt(fade_mask, FADE_MODE_FADE_IN, FADE_TYPE_FADE_IN);
1029 void FadeOut(int fade_mask)
1031 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
1032 FadeExt(fade_mask, fading.fade_mode, FADE_TYPE_FADE_OUT);
1034 FadeExt(fade_mask, FADE_MODE_FADE_OUT, FADE_TYPE_FADE_OUT);
1036 global.border_status = game_status;
1039 static void FadeSetLeaveNext(struct TitleFadingInfo fading_leave, boolean set)
1041 static struct TitleFadingInfo fading_leave_stored;
1044 fading_leave_stored = fading_leave;
1046 fading = fading_leave_stored;
1049 void FadeSetEnterMenu()
1051 fading = menu.enter_menu;
1054 printf("::: storing enter_menu\n");
1057 FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
1060 void FadeSetLeaveMenu()
1062 fading = menu.leave_menu;
1065 printf("::: storing leave_menu\n");
1068 FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
1071 void FadeSetEnterScreen()
1073 fading = menu.enter_screen[game_status];
1076 printf("::: storing leave_screen[%d]\n", game_status);
1079 FadeSetLeaveNext(menu.leave_screen[game_status], TRUE); /* store */
1082 void FadeSetNextScreen()
1084 fading = menu.next_screen;
1087 printf("::: storing next_screen\n");
1090 // (do not overwrite fade mode set by FadeSetEnterScreen)
1091 // FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
1094 void FadeSetLeaveScreen()
1097 printf("::: recalling last stored value\n");
1100 FadeSetLeaveNext(menu.leave_screen[game_status], FALSE); /* recall */
1103 void FadeSetFromType(int type)
1105 if (type & TYPE_ENTER_SCREEN)
1106 FadeSetEnterScreen();
1107 else if (type & TYPE_ENTER)
1109 else if (type & TYPE_LEAVE)
1113 void FadeSetDisabled()
1115 static struct TitleFadingInfo fading_none = { FADE_MODE_NONE, -1, -1, -1 };
1117 fading = fading_none;
1120 void FadeSkipNextFadeIn()
1122 FadeExt(0, FADE_MODE_SKIP_FADE_IN, FADE_TYPE_SKIP);
1125 void FadeSkipNextFadeOut()
1127 FadeExt(0, FADE_MODE_SKIP_FADE_OUT, FADE_TYPE_SKIP);
1130 void SetWindowBackgroundImageIfDefined(int graphic)
1132 if (graphic_info[graphic].bitmap)
1133 SetWindowBackgroundBitmap(graphic_info[graphic].bitmap);
1136 void SetMainBackgroundImageIfDefined(int graphic)
1138 if (graphic_info[graphic].bitmap)
1139 SetMainBackgroundBitmap(graphic_info[graphic].bitmap);
1142 void SetDoorBackgroundImageIfDefined(int graphic)
1144 if (graphic_info[graphic].bitmap)
1145 SetDoorBackgroundBitmap(graphic_info[graphic].bitmap);
1148 void SetWindowBackgroundImage(int graphic)
1150 SetWindowBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
1151 graphic_info[graphic].bitmap ?
1152 graphic_info[graphic].bitmap :
1153 graphic_info[IMG_BACKGROUND].bitmap);
1156 void SetMainBackgroundImage(int graphic)
1158 SetMainBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
1159 graphic_info[graphic].bitmap ?
1160 graphic_info[graphic].bitmap :
1161 graphic_info[IMG_BACKGROUND].bitmap);
1164 void SetDoorBackgroundImage(int graphic)
1166 SetDoorBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
1167 graphic_info[graphic].bitmap ?
1168 graphic_info[graphic].bitmap :
1169 graphic_info[IMG_BACKGROUND].bitmap);
1172 void SetPanelBackground()
1175 struct GraphicInfo *gfx = &graphic_info[IMG_BACKGROUND_PANEL];
1178 BlitBitmapTiled(gfx->bitmap, bitmap_db_panel, gfx->src_x, gfx->src_y,
1179 gfx->width, gfx->height, 0, 0, DXSIZE, DYSIZE);
1181 /* (ClearRectangle() only needed if panel bitmap is smaller than panel) */
1182 ClearRectangle(bitmap_db_panel, DX, DY, DXSIZE, DYSIZE);
1183 BlitBitmap(gfx->bitmap, bitmap_db_panel, gfx->src_x, gfx->src_y,
1184 MIN(gfx->width, DXSIZE), MIN(gfx->height, DYSIZE), 0, 0);
1187 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, bitmap_db_panel,
1188 DOOR_GFX_PAGEX5, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE, 0, 0);
1191 SetDoorBackgroundBitmap(bitmap_db_panel);
1194 void DrawBackground(int x, int y, int width, int height)
1196 /* !!! "drawto" might still point to playfield buffer here (see below) !!! */
1197 /* (when entering hall of fame after playing) */
1199 ClearRectangleOnBackground(drawto, x, y, width, height);
1201 ClearRectangleOnBackground(backbuffer, x, y, width, height);
1207 if (IN_GFX_FIELD_FULL(x, y))
1208 redraw_mask |= REDRAW_FIELD;
1209 else if (IN_GFX_DOOR_1(x, y))
1210 redraw_mask |= REDRAW_DOOR_1;
1211 else if (IN_GFX_DOOR_2(x, y))
1212 redraw_mask |= REDRAW_DOOR_2;
1213 else if (IN_GFX_DOOR_3(x, y))
1214 redraw_mask |= REDRAW_DOOR_3;
1216 /* (this only works for the current arrangement of playfield and panels) */
1218 redraw_mask |= REDRAW_FIELD;
1219 else if (y < gfx.vy)
1220 redraw_mask |= REDRAW_DOOR_1;
1222 redraw_mask |= REDRAW_DOOR_2;
1226 /* (this is just wrong (when drawing to one of the two door panel areas)) */
1227 redraw_mask |= REDRAW_FIELD;
1231 void DrawBackgroundForFont(int x, int y, int width, int height, int font_nr)
1233 struct FontBitmapInfo *font = getFontBitmapInfo(font_nr);
1235 if (font->bitmap == NULL)
1238 DrawBackground(x, y, width, height);
1241 void DrawBackgroundForGraphic(int x, int y, int width, int height, int graphic)
1243 struct GraphicInfo *g = &graphic_info[graphic];
1245 if (g->bitmap == NULL)
1248 DrawBackground(x, y, width, height);
1253 /* !!! "drawto" might still point to playfield buffer here (see above) !!! */
1254 /* (when entering hall of fame after playing) */
1255 DrawBackground(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
1257 /* !!! maybe this should be done before clearing the background !!! */
1258 if (setup.soft_scrolling && game_status == GAME_MODE_PLAYING)
1260 ClearRectangle(fieldbuffer, 0, 0, FXSIZE, FYSIZE);
1261 SetDrawtoField(DRAW_BUFFERED);
1264 SetDrawtoField(DRAW_BACKBUFFER);
1267 void MarkTileDirty(int x, int y)
1269 int xx = redraw_x1 + x;
1270 int yy = redraw_y1 + y;
1272 if (!redraw[xx][yy])
1275 redraw[xx][yy] = TRUE;
1276 redraw_mask |= REDRAW_TILES;
1279 void SetBorderElement()
1283 BorderElement = EL_EMPTY;
1285 for (y = 0; y < lev_fieldy && BorderElement == EL_EMPTY; y++)
1287 for (x = 0; x < lev_fieldx; x++)
1289 if (!IS_INDESTRUCTIBLE(Feld[x][y]))
1290 BorderElement = EL_STEELWALL;
1292 if (y != 0 && y != lev_fieldy - 1 && x != lev_fieldx - 1)
1298 void FloodFillLevel(int from_x, int from_y, int fill_element,
1299 short field[MAX_LEV_FIELDX][MAX_LEV_FIELDY],
1300 int max_fieldx, int max_fieldy)
1304 static int check[4][2] = { { -1, 0 }, { 0, -1 }, { 1, 0 }, { 0, 1 } };
1305 static int safety = 0;
1307 /* check if starting field still has the desired content */
1308 if (field[from_x][from_y] == fill_element)
1313 if (safety > max_fieldx * max_fieldy)
1314 Error(ERR_EXIT, "Something went wrong in 'FloodFill()'. Please debug.");
1316 old_element = field[from_x][from_y];
1317 field[from_x][from_y] = fill_element;
1319 for (i = 0; i < 4; i++)
1321 x = from_x + check[i][0];
1322 y = from_y + check[i][1];
1324 if (IN_FIELD(x, y, max_fieldx, max_fieldy) && field[x][y] == old_element)
1325 FloodFillLevel(x, y, fill_element, field, max_fieldx, max_fieldy);
1331 void SetRandomAnimationValue(int x, int y)
1333 gfx.anim_random_frame = GfxRandom[x][y];
1336 inline int getGraphicAnimationFrame(int graphic, int sync_frame)
1338 /* animation synchronized with global frame counter, not move position */
1339 if (graphic_info[graphic].anim_global_sync || sync_frame < 0)
1340 sync_frame = FrameCounter;
1342 return getAnimationFrame(graphic_info[graphic].anim_frames,
1343 graphic_info[graphic].anim_delay,
1344 graphic_info[graphic].anim_mode,
1345 graphic_info[graphic].anim_start_frame,
1349 void getSizedGraphicSourceExt(int graphic, int frame, int tilesize_raw,
1350 Bitmap **bitmap, int *x, int *y,
1351 boolean get_backside)
1355 int width_mult, width_div;
1356 int height_mult, height_div;
1360 { 15, 16, 2, 3 }, /* 1 x 1 */
1361 { 7, 8, 2, 3 }, /* 2 x 2 */
1362 { 3, 4, 2, 3 }, /* 4 x 4 */
1363 { 1, 2, 2, 3 }, /* 8 x 8 */
1364 { 0, 1, 2, 3 }, /* 16 x 16 */
1365 { 0, 1, 0, 1 }, /* 32 x 32 */
1367 struct GraphicInfo *g = &graphic_info[graphic];
1368 Bitmap *src_bitmap = g->bitmap;
1369 int tilesize = MIN(MAX(1, tilesize_raw), TILESIZE);
1370 int offset_calc_pos = log_2(tilesize);
1371 int width_mult = offset_calc[offset_calc_pos].width_mult;
1372 int width_div = offset_calc[offset_calc_pos].width_div;
1373 int height_mult = offset_calc[offset_calc_pos].height_mult;
1374 int height_div = offset_calc[offset_calc_pos].height_div;
1375 int startx = src_bitmap->width * width_mult / width_div;
1376 int starty = src_bitmap->height * height_mult / height_div;
1378 int src_x = (g->src_x + (get_backside ? g->offset2_x : 0)) *
1379 tilesize / TILESIZE;
1380 int src_y = (g->src_y + (get_backside ? g->offset2_y : 0)) *
1381 tilesize / TILESIZE;
1383 int src_x = g->src_x * tilesize / TILESIZE;
1384 int src_y = g->src_y * tilesize / TILESIZE;
1386 int width = g->width * tilesize / TILESIZE;
1387 int height = g->height * tilesize / TILESIZE;
1388 int offset_x = g->offset_x * tilesize / TILESIZE;
1389 int offset_y = g->offset_y * tilesize / TILESIZE;
1391 if (g->offset_y == 0) /* frames are ordered horizontally */
1393 int max_width = g->anim_frames_per_line * width;
1394 int pos = (src_y / height) * max_width + src_x + frame * offset_x;
1396 src_x = pos % max_width;
1397 src_y = src_y % height + pos / max_width * height;
1399 else if (g->offset_x == 0) /* frames are ordered vertically */
1401 int max_height = g->anim_frames_per_line * height;
1402 int pos = (src_x / width) * max_height + src_y + frame * offset_y;
1404 src_x = src_x % width + pos / max_height * width;
1405 src_y = pos % max_height;
1407 else /* frames are ordered diagonally */
1409 src_x = src_x + frame * offset_x;
1410 src_y = src_y + frame * offset_y;
1413 *bitmap = src_bitmap;
1414 *x = startx + src_x;
1415 *y = starty + src_y;
1418 void getFixedGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
1419 int *x, int *y, boolean get_backside)
1421 getSizedGraphicSourceExt(graphic, frame, TILESIZE, bitmap, x, y,
1425 void getSizedGraphicSource(int graphic, int frame, int tilesize_raw,
1426 Bitmap **bitmap, int *x, int *y)
1428 getSizedGraphicSourceExt(graphic, frame, tilesize_raw, bitmap, x, y, FALSE);
1431 void getFixedGraphicSource(int graphic, int frame,
1432 Bitmap **bitmap, int *x, int *y)
1434 getSizedGraphicSourceExt(graphic, frame, TILESIZE, bitmap, x, y, FALSE);
1437 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
1440 getSizedGraphicSource(graphic, 0, MINI_TILESIZE, bitmap, x, y);
1442 struct GraphicInfo *g = &graphic_info[graphic];
1443 int mini_startx = 0;
1444 int mini_starty = g->bitmap->height * 2 / 3;
1446 *bitmap = g->bitmap;
1447 *x = mini_startx + g->src_x / 2;
1448 *y = mini_starty + g->src_y / 2;
1452 inline void getGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
1453 int *x, int *y, boolean get_backside)
1455 struct GraphicInfo *g = &graphic_info[graphic];
1456 int src_x = g->src_x + (get_backside ? g->offset2_x : 0);
1457 int src_y = g->src_y + (get_backside ? g->offset2_y : 0);
1460 if (TILESIZE_VAR != TILESIZE)
1461 return getSizedGraphicSourceExt(graphic, frame, TILESIZE_VAR, bitmap, x, y,
1465 *bitmap = g->bitmap;
1467 if (g->offset_y == 0) /* frames are ordered horizontally */
1469 int max_width = g->anim_frames_per_line * g->width;
1470 int pos = (src_y / g->height) * max_width + src_x + frame * g->offset_x;
1472 *x = pos % max_width;
1473 *y = src_y % g->height + pos / max_width * g->height;
1475 else if (g->offset_x == 0) /* frames are ordered vertically */
1477 int max_height = g->anim_frames_per_line * g->height;
1478 int pos = (src_x / g->width) * max_height + src_y + frame * g->offset_y;
1480 *x = src_x % g->width + pos / max_height * g->width;
1481 *y = pos % max_height;
1483 else /* frames are ordered diagonally */
1485 *x = src_x + frame * g->offset_x;
1486 *y = src_y + frame * g->offset_y;
1490 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
1492 getGraphicSourceExt(graphic, frame, bitmap, x, y, FALSE);
1495 void DrawGraphic(int x, int y, int graphic, int frame)
1498 if (!IN_SCR_FIELD(x, y))
1500 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
1501 printf("DrawGraphic(): This should never happen!\n");
1507 DrawGraphicExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR, graphic,
1510 DrawGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic, frame);
1512 MarkTileDirty(x, y);
1515 void DrawFixedGraphic(int x, int y, int graphic, int frame)
1518 if (!IN_SCR_FIELD(x, y))
1520 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
1521 printf("DrawGraphic(): This should never happen!\n");
1526 DrawFixedGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic,
1528 MarkTileDirty(x, y);
1531 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
1537 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1539 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX_VAR, TILEY_VAR, x, y);
1541 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
1545 void DrawFixedGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
1551 getFixedGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1552 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
1555 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
1558 if (!IN_SCR_FIELD(x, y))
1560 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
1561 printf("DrawGraphicThruMask(): This should never happen!\n");
1567 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR,
1570 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic,
1573 MarkTileDirty(x, y);
1576 void DrawFixedGraphicThruMask(int x, int y, int graphic, int frame)
1579 if (!IN_SCR_FIELD(x, y))
1581 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
1582 printf("DrawGraphicThruMask(): This should never happen!\n");
1587 DrawFixedGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
1589 MarkTileDirty(x, y);
1592 void DrawGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y, int graphic,
1598 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1600 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1601 dst_x - src_x, dst_y - src_y);
1603 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX_VAR, TILEY_VAR,
1606 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dst_x, dst_y);
1610 void DrawFixedGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y,
1611 int graphic, int frame)
1616 getFixedGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1618 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1619 dst_x - src_x, dst_y - src_y);
1620 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dst_x, dst_y);
1623 void DrawSizedGraphic(int x, int y, int graphic, int frame, int tilesize)
1625 DrawSizedGraphicExt(drawto, SX + x * tilesize, SY + y * tilesize, graphic,
1627 MarkTileDirty(x / tilesize, y / tilesize);
1630 void DrawSizedGraphicExt(DrawBuffer *d, int x, int y, int graphic, int frame,
1636 getSizedGraphicSource(graphic, frame, tilesize, &src_bitmap, &src_x, &src_y);
1637 BlitBitmap(src_bitmap, d, src_x, src_y, tilesize, tilesize, x, y);
1640 void DrawMiniGraphic(int x, int y, int graphic)
1642 DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
1643 MarkTileDirty(x / 2, y / 2);
1646 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
1651 getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1652 BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
1655 inline static void DrawGraphicShiftedNormal(int x, int y, int dx, int dy,
1656 int graphic, int frame,
1657 int cut_mode, int mask_mode)
1662 int width = TILEX, height = TILEY;
1665 if (dx || dy) /* shifted graphic */
1667 if (x < BX1) /* object enters playfield from the left */
1674 else if (x > BX2) /* object enters playfield from the right */
1680 else if (x==BX1 && dx < 0) /* object leaves playfield to the left */
1686 else if (x==BX2 && dx > 0) /* object leaves playfield to the right */
1688 else if (dx) /* general horizontal movement */
1689 MarkTileDirty(x + SIGN(dx), y);
1691 if (y < BY1) /* object enters playfield from the top */
1693 if (cut_mode==CUT_BELOW) /* object completely above top border */
1701 else if (y > BY2) /* object enters playfield from the bottom */
1707 else if (y==BY1 && dy < 0) /* object leaves playfield to the top */
1713 else if (dy > 0 && cut_mode == CUT_ABOVE)
1715 if (y == BY2) /* object completely above bottom border */
1721 MarkTileDirty(x, y + 1);
1722 } /* object leaves playfield to the bottom */
1723 else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
1725 else if (dy) /* general vertical movement */
1726 MarkTileDirty(x, y + SIGN(dy));
1730 if (!IN_SCR_FIELD(x, y))
1732 printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
1733 printf("DrawGraphicShifted(): This should never happen!\n");
1739 width = width * TILESIZE_VAR / TILESIZE;
1740 height = height * TILESIZE_VAR / TILESIZE;
1741 cx = cx * TILESIZE_VAR / TILESIZE;
1742 cy = cy * TILESIZE_VAR / TILESIZE;
1743 dx = dx * TILESIZE_VAR / TILESIZE;
1744 dy = dy * TILESIZE_VAR / TILESIZE;
1747 if (width > 0 && height > 0)
1749 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1755 dst_x = FX + x * TILEX_VAR + dx;
1756 dst_y = FY + y * TILEY_VAR + dy;
1758 dst_x = FX + x * TILEX + dx;
1759 dst_y = FY + y * TILEY + dy;
1762 if (mask_mode == USE_MASKING)
1764 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1765 dst_x - src_x, dst_y - src_y);
1766 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1770 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1773 MarkTileDirty(x, y);
1777 inline static void DrawGraphicShiftedDouble(int x, int y, int dx, int dy,
1778 int graphic, int frame,
1779 int cut_mode, int mask_mode)
1785 int width = TILEX_VAR, height = TILEY_VAR;
1787 int width = TILEX, height = TILEY;
1791 int x2 = x + SIGN(dx);
1792 int y2 = y + SIGN(dy);
1794 /* !!! DOES NOT WORK FOR SLOW MOVEMENT !!! */
1795 int sync_frame = GfxFrame[LEVELX(x)][LEVELY(y)];
1797 /* movement with two-tile animations must be sync'ed with movement position,
1798 not with current GfxFrame (which can be higher when using slow movement) */
1799 int anim_pos = (dx ? ABS(dx) : ABS(dy));
1800 int anim_frames = graphic_info[graphic].anim_frames;
1802 /* (we also need anim_delay here for movement animations with less frames) */
1803 int anim_delay = graphic_info[graphic].anim_delay;
1804 int sync_frame = anim_pos * anim_frames * anim_delay / TILESIZE;
1806 int sync_frame = anim_pos * anim_frames / TILESIZE;
1809 boolean draw_start_tile = (cut_mode != CUT_ABOVE); /* only for falling! */
1810 boolean draw_end_tile = (cut_mode != CUT_BELOW); /* only for falling! */
1812 /* re-calculate animation frame for two-tile movement animation */
1813 frame = getGraphicAnimationFrame(graphic, sync_frame);
1817 printf("::: %d, %d, %d => %d [%d]\n",
1818 anim_pos, anim_frames, anim_delay, sync_frame, graphic);
1820 printf("::: %d, %d => %d\n",
1821 anim_pos, anim_frames, sync_frame);
1826 printf("::: %d [%d, %d] [%d] [%d]\n", frame, sync_frame, dy,
1827 GfxFrame[LEVELX(x)][LEVELY(y)], mask_mode);
1830 /* check if movement start graphic inside screen area and should be drawn */
1831 if (draw_start_tile && IN_SCR_FIELD(x1, y1))
1833 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, TRUE);
1836 dst_x = FX + x1 * TILEX_VAR;
1837 dst_y = FY + y1 * TILEY_VAR;
1839 dst_x = FX + x1 * TILEX;
1840 dst_y = FY + y1 * TILEY;
1843 if (mask_mode == USE_MASKING)
1845 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1846 dst_x - src_x, dst_y - src_y);
1847 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1851 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1854 MarkTileDirty(x1, y1);
1857 /* check if movement end graphic inside screen area and should be drawn */
1858 if (draw_end_tile && IN_SCR_FIELD(x2, y2))
1860 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
1863 dst_x = FX + x2 * TILEX_VAR;
1864 dst_y = FY + y2 * TILEY_VAR;
1866 dst_x = FX + x2 * TILEX;
1867 dst_y = FY + y2 * TILEY;
1870 if (mask_mode == USE_MASKING)
1872 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1873 dst_x - src_x, dst_y - src_y);
1874 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1878 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1881 MarkTileDirty(x2, y2);
1885 static void DrawGraphicShifted(int x, int y, int dx, int dy,
1886 int graphic, int frame,
1887 int cut_mode, int mask_mode)
1891 DrawGraphic(x, y, graphic, frame);
1896 if (graphic_info[graphic].double_movement) /* EM style movement images */
1897 DrawGraphicShiftedDouble(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1899 DrawGraphicShiftedNormal(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1902 void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
1903 int frame, int cut_mode)
1905 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, USE_MASKING);
1908 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
1909 int cut_mode, int mask_mode)
1911 int lx = LEVELX(x), ly = LEVELY(y);
1915 if (IN_LEV_FIELD(lx, ly))
1917 SetRandomAnimationValue(lx, ly);
1919 graphic = el_act_dir2img(element, GfxAction[lx][ly], GfxDir[lx][ly]);
1920 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1922 /* do not use double (EM style) movement graphic when not moving */
1923 if (graphic_info[graphic].double_movement && !dx && !dy)
1925 graphic = el_act_dir2img(element, ACTION_DEFAULT, GfxDir[lx][ly]);
1926 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1929 else /* border element */
1931 graphic = el2img(element);
1932 frame = getGraphicAnimationFrame(graphic, -1);
1935 if (element == EL_EXPANDABLE_WALL)
1937 boolean left_stopped = FALSE, right_stopped = FALSE;
1939 if (!IN_LEV_FIELD(lx - 1, ly) || IS_WALL(Feld[lx - 1][ly]))
1940 left_stopped = TRUE;
1941 if (!IN_LEV_FIELD(lx + 1, ly) || IS_WALL(Feld[lx + 1][ly]))
1942 right_stopped = TRUE;
1944 if (left_stopped && right_stopped)
1946 else if (left_stopped)
1948 graphic = IMG_EXPANDABLE_WALL_GROWING_RIGHT;
1949 frame = graphic_info[graphic].anim_frames - 1;
1951 else if (right_stopped)
1953 graphic = IMG_EXPANDABLE_WALL_GROWING_LEFT;
1954 frame = graphic_info[graphic].anim_frames - 1;
1959 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
1960 else if (mask_mode == USE_MASKING)
1961 DrawGraphicThruMask(x, y, graphic, frame);
1963 DrawGraphic(x, y, graphic, frame);
1966 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
1967 int cut_mode, int mask_mode)
1969 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1970 DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
1971 cut_mode, mask_mode);
1974 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
1977 DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1980 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
1983 DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1986 void DrawLevelElementThruMask(int x, int y, int element)
1988 DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1991 void DrawLevelFieldThruMask(int x, int y)
1993 DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
1996 /* !!! implementation of quicksand is totally broken !!! */
1997 #define IS_CRUMBLED_TILE(x, y, e) \
1998 (GFX_CRUMBLED(e) && (!IN_LEV_FIELD(x, y) || \
1999 !IS_MOVING(x, y) || \
2000 (e) == EL_QUICKSAND_EMPTYING || \
2001 (e) == EL_QUICKSAND_FAST_EMPTYING))
2003 static void DrawLevelFieldCrumbledInnerCorners(int x, int y, int dx, int dy,
2008 int width, height, cx, cy;
2009 int sx = SCREENX(x), sy = SCREENY(y);
2010 int crumbled_border_size = graphic_info[graphic].border_size;
2013 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
2015 for (i = 1; i < 4; i++)
2017 int dxx = (i & 1 ? dx : 0);
2018 int dyy = (i & 2 ? dy : 0);
2021 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
2024 /* check if neighbour field is of same crumble type */
2025 boolean same = (IS_CRUMBLED_TILE(xx, yy, element) &&
2026 graphic_info[graphic].class ==
2027 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class);
2029 /* return if check prevents inner corner */
2030 if (same == (dxx == dx && dyy == dy))
2034 /* if we reach this point, we have an inner corner */
2036 getGraphicSource(graphic, 1, &src_bitmap, &src_x, &src_y);
2039 width = crumbled_border_size * TILESIZE_VAR / TILESIZE;
2040 height = crumbled_border_size * TILESIZE_VAR / TILESIZE;
2041 cx = (dx > 0 ? TILEX - crumbled_border_size : 0) * TILESIZE_VAR / TILESIZE;
2042 cy = (dy > 0 ? TILEY - crumbled_border_size : 0) * TILESIZE_VAR / TILESIZE;
2044 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
2045 width, height, FX + sx * TILEX_VAR + cx, FY + sy * TILEY_VAR + cy);
2047 width = crumbled_border_size;
2048 height = crumbled_border_size;
2049 cx = (dx > 0 ? TILEX - crumbled_border_size : 0);
2050 cy = (dy > 0 ? TILEY - crumbled_border_size : 0);
2052 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
2053 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
2057 static void DrawLevelFieldCrumbledBorders(int x, int y, int graphic, int frame,
2062 int width, height, bx, by, cx, cy;
2063 int sx = SCREENX(x), sy = SCREENY(y);
2064 int crumbled_border_size = graphic_info[graphic].border_size;
2067 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
2069 /* draw simple, sloppy, non-corner-accurate crumbled border */
2072 width = (dir == 1 || dir == 2 ? crumbled_border_size : TILEX);
2073 height = (dir == 0 || dir == 3 ? crumbled_border_size : TILEY);
2074 cx = (dir == 2 ? TILEX - crumbled_border_size : 0);
2075 cy = (dir == 3 ? TILEY - crumbled_border_size : 0);
2077 if (dir == 1 || dir == 2) /* left or right crumbled border */
2079 width = crumbled_border_size;
2081 cx = (dir == 2 ? TILEX - crumbled_border_size : 0);
2084 else /* top or bottom crumbled border */
2087 height = crumbled_border_size;
2089 cy = (dir == 3 ? TILEY - crumbled_border_size : 0);
2094 BlitBitmap(src_bitmap, drawto_field,
2095 src_x + cx * TILESIZE_VAR / TILESIZE,
2096 src_y + cy * TILESIZE_VAR / TILESIZE,
2097 width * TILESIZE_VAR / TILESIZE,
2098 height * TILESIZE_VAR / TILESIZE,
2099 FX + sx * TILEX_VAR + cx * TILESIZE_VAR / TILESIZE,
2100 FY + sy * TILEY_VAR + cy * TILESIZE_VAR / TILESIZE);
2102 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
2103 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
2106 /* (remaining middle border part must be at least as big as corner part) */
2107 if (!(graphic_info[graphic].style & STYLE_ACCURATE_BORDERS) ||
2108 crumbled_border_size >= TILESIZE / 3)
2111 /* correct corners of crumbled border, if needed */
2114 for (i = -1; i <= 1; i+=2)
2116 int xx = x + (dir == 0 || dir == 3 ? i : 0);
2117 int yy = y + (dir == 1 || dir == 2 ? i : 0);
2118 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
2121 /* check if neighbour field is of same crumble type */
2122 if (IS_CRUMBLED_TILE(xx, yy, element) &&
2123 graphic_info[graphic].class ==
2124 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
2126 /* no crumbled corner, but continued crumbled border */
2128 int c1 = (dir == 2 || dir == 3 ? TILESIZE - crumbled_border_size : 0);
2129 int c2 = (i == 1 ? TILESIZE - crumbled_border_size : 0);
2130 int b1 = (i == 1 ? crumbled_border_size :
2131 TILESIZE - 2 * crumbled_border_size);
2133 width = crumbled_border_size;
2134 height = crumbled_border_size;
2136 if (dir == 1 || dir == 2)
2152 BlitBitmap(src_bitmap, drawto_field,
2153 src_x + bx * TILESIZE_VAR / TILESIZE,
2154 src_y + by * TILESIZE_VAR / TILESIZE,
2155 width * TILESIZE_VAR / TILESIZE,
2156 height * TILESIZE_VAR / TILESIZE,
2157 FX + sx * TILEX_VAR + cx * TILESIZE_VAR / TILESIZE,
2158 FY + sy * TILEY_VAR + cy * TILESIZE_VAR / TILESIZE);
2160 BlitBitmap(src_bitmap, drawto_field, src_x + bx, src_y + by,
2161 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
2166 if (dir == 1 || dir == 2) /* left or right crumbled border */
2168 for (i = -1; i <= 1; i+=2)
2172 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
2175 /* check if neighbour field is of same crumble type */
2176 if (IS_CRUMBLED_TILE(xx, yy, element) &&
2177 graphic_info[graphic].class ==
2178 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
2180 /* no crumbled corner, but continued crumbled border */
2182 width = crumbled_border_size;
2183 height = crumbled_border_size;
2184 cx = (dir == 2 ? TILEX - crumbled_border_size : 0);
2185 cy = (i == 1 ? TILEY - crumbled_border_size : 0);
2187 by = (i == 1 ? crumbled_border_size :
2188 TILEY - 2 * crumbled_border_size);
2190 BlitBitmap(src_bitmap, drawto_field, src_x + bx, src_y + by,
2191 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
2195 else /* top or bottom crumbled border */
2197 for (i = -1; i <= 1; i+=2)
2201 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
2204 /* check if neighbour field is of same crumble type */
2205 if (IS_CRUMBLED_TILE(xx, yy, element) &&
2206 graphic_info[graphic].class ==
2207 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
2209 /* no crumbled corner, but continued crumbled border */
2211 width = crumbled_border_size;
2212 height = crumbled_border_size;
2213 cx = (i == 1 ? TILEX - crumbled_border_size : 0);
2214 cy = (dir == 3 ? TILEY - crumbled_border_size : 0);
2215 bx = (i == 1 ? crumbled_border_size :
2216 TILEX - 2 * crumbled_border_size);
2219 BlitBitmap(src_bitmap, drawto_field, src_x + bx, src_y + by,
2220 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
2227 static void DrawLevelFieldCrumbledExt(int x, int y, int graphic, int frame)
2229 int sx = SCREENX(x), sy = SCREENY(y);
2232 static int xy[4][2] =
2240 if (!IN_LEV_FIELD(x, y))
2243 element = TILE_GFX_ELEMENT(x, y);
2245 /* crumble field itself */
2246 if (IS_CRUMBLED_TILE(x, y, element))
2248 if (!IN_SCR_FIELD(sx, sy))
2251 for (i = 0; i < 4; i++)
2253 int xx = x + xy[i][0];
2254 int yy = y + xy[i][1];
2256 element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
2259 /* check if neighbour field is of same crumble type */
2261 if (IS_CRUMBLED_TILE(xx, yy, element) &&
2262 graphic_info[graphic].class ==
2263 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
2266 if (IS_CRUMBLED_TILE(xx, yy, element))
2270 DrawLevelFieldCrumbledBorders(x, y, graphic, frame, i);
2273 if ((graphic_info[graphic].style & STYLE_INNER_CORNERS) &&
2274 graphic_info[graphic].anim_frames == 2)
2276 for (i = 0; i < 4; i++)
2278 int dx = (i & 1 ? +1 : -1);
2279 int dy = (i & 2 ? +1 : -1);
2281 DrawLevelFieldCrumbledInnerCorners(x, y, dx, dy, graphic);
2285 MarkTileDirty(sx, sy);
2287 else /* center field not crumbled -- crumble neighbour fields */
2289 for (i = 0; i < 4; i++)
2291 int xx = x + xy[i][0];
2292 int yy = y + xy[i][1];
2293 int sxx = sx + xy[i][0];
2294 int syy = sy + xy[i][1];
2296 if (!IN_LEV_FIELD(xx, yy) ||
2297 !IN_SCR_FIELD(sxx, syy))
2300 if (Feld[xx][yy] == EL_ELEMENT_SNAPPING)
2303 element = TILE_GFX_ELEMENT(xx, yy);
2305 if (!IS_CRUMBLED_TILE(xx, yy, element))
2308 graphic = el_act2crm(element, ACTION_DEFAULT);
2310 DrawLevelFieldCrumbledBorders(xx, yy, graphic, 0, 3 - i);
2312 MarkTileDirty(sxx, syy);
2317 void DrawLevelFieldCrumbled(int x, int y)
2321 if (!IN_LEV_FIELD(x, y))
2325 /* !!! CHECK THIS !!! */
2328 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
2329 GFX_CRUMBLED(GfxElement[x][y]))
2332 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
2333 GfxElement[x][y] != EL_UNDEFINED &&
2334 GFX_CRUMBLED(GfxElement[x][y]))
2336 DrawLevelFieldCrumbledDigging(x, y, GfxDir[x][y], GfxFrame[x][y]);
2343 graphic = el_act2crm(TILE_GFX_ELEMENT(x, y), ACTION_DEFAULT);
2345 graphic = el_act2crm(Feld[x][y], ACTION_DEFAULT);
2348 DrawLevelFieldCrumbledExt(x, y, graphic, 0);
2351 void DrawLevelFieldCrumbledDigging(int x, int y, int direction,
2354 int graphic1 = el_act_dir2img(GfxElement[x][y], ACTION_DIGGING, direction);
2355 int graphic2 = el_act_dir2crm(GfxElement[x][y], ACTION_DIGGING, direction);
2356 int frame1 = getGraphicAnimationFrame(graphic1, step_frame);
2357 int frame2 = getGraphicAnimationFrame(graphic2, step_frame);
2358 int sx = SCREENX(x), sy = SCREENY(y);
2360 DrawGraphic(sx, sy, graphic1, frame1);
2361 DrawLevelFieldCrumbledExt(x, y, graphic2, frame2);
2364 void DrawLevelFieldCrumbledNeighbours(int x, int y)
2366 int sx = SCREENX(x), sy = SCREENY(y);
2367 static int xy[4][2] =
2376 for (i = 0; i < 4; i++)
2378 int xx = x + xy[i][0];
2379 int yy = y + xy[i][1];
2380 int sxx = sx + xy[i][0];
2381 int syy = sy + xy[i][1];
2383 if (!IN_LEV_FIELD(xx, yy) ||
2384 !IN_SCR_FIELD(sxx, syy) ||
2385 !GFX_CRUMBLED(Feld[xx][yy]) ||
2389 DrawLevelField(xx, yy);
2393 static int getBorderElement(int x, int y)
2397 { EL_STEELWALL_TOPLEFT, EL_INVISIBLE_STEELWALL_TOPLEFT },
2398 { EL_STEELWALL_TOPRIGHT, EL_INVISIBLE_STEELWALL_TOPRIGHT },
2399 { EL_STEELWALL_BOTTOMLEFT, EL_INVISIBLE_STEELWALL_BOTTOMLEFT },
2400 { EL_STEELWALL_BOTTOMRIGHT, EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
2401 { EL_STEELWALL_VERTICAL, EL_INVISIBLE_STEELWALL_VERTICAL },
2402 { EL_STEELWALL_HORIZONTAL, EL_INVISIBLE_STEELWALL_HORIZONTAL },
2403 { EL_STEELWALL, EL_INVISIBLE_STEELWALL }
2405 int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
2406 int steel_position = (x == -1 && y == -1 ? 0 :
2407 x == lev_fieldx && y == -1 ? 1 :
2408 x == -1 && y == lev_fieldy ? 2 :
2409 x == lev_fieldx && y == lev_fieldy ? 3 :
2410 x == -1 || x == lev_fieldx ? 4 :
2411 y == -1 || y == lev_fieldy ? 5 : 6);
2413 return border[steel_position][steel_type];
2416 void DrawScreenElement(int x, int y, int element)
2418 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
2419 DrawLevelFieldCrumbled(LEVELX(x), LEVELY(y));
2422 void DrawLevelElement(int x, int y, int element)
2424 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
2425 DrawScreenElement(SCREENX(x), SCREENY(y), element);
2428 void DrawScreenField(int x, int y)
2430 int lx = LEVELX(x), ly = LEVELY(y);
2431 int element, content;
2433 if (!IN_LEV_FIELD(lx, ly))
2435 if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
2438 element = getBorderElement(lx, ly);
2440 DrawScreenElement(x, y, element);
2445 element = Feld[lx][ly];
2446 content = Store[lx][ly];
2448 if (IS_MOVING(lx, ly))
2450 int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
2451 boolean cut_mode = NO_CUTTING;
2453 if (element == EL_QUICKSAND_EMPTYING ||
2454 element == EL_QUICKSAND_FAST_EMPTYING ||
2455 element == EL_MAGIC_WALL_EMPTYING ||
2456 element == EL_BD_MAGIC_WALL_EMPTYING ||
2457 element == EL_DC_MAGIC_WALL_EMPTYING ||
2458 element == EL_AMOEBA_DROPPING)
2459 cut_mode = CUT_ABOVE;
2460 else if (element == EL_QUICKSAND_FILLING ||
2461 element == EL_QUICKSAND_FAST_FILLING ||
2462 element == EL_MAGIC_WALL_FILLING ||
2463 element == EL_BD_MAGIC_WALL_FILLING ||
2464 element == EL_DC_MAGIC_WALL_FILLING)
2465 cut_mode = CUT_BELOW;
2468 if (lx == 9 && ly == 1)
2469 printf("::: %s [%d] [%d, %d] [%d]\n",
2470 EL_NAME(TILE_GFX_ELEMENT(lx, ly)),
2471 el_act2crm(TILE_GFX_ELEMENT(lx, ly), ACTION_DEFAULT),
2472 element_info[EL_QUICKSAND_EMPTYING].graphic[ACTION_DEFAULT],
2473 element_info[EL_QUICKSAND_EMPTYING].crumbled[ACTION_DEFAULT],
2474 GFX_CRUMBLED(TILE_GFX_ELEMENT(lx, ly)));
2477 if (cut_mode == CUT_ABOVE)
2479 DrawScreenElement(x, y, element);
2481 DrawScreenElementShifted(x, y, 0, 0, element, NO_CUTTING);
2484 DrawScreenElement(x, y, EL_EMPTY);
2487 DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
2488 else if (cut_mode == NO_CUTTING)
2489 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
2492 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
2495 if (cut_mode == CUT_BELOW &&
2496 IN_LEV_FIELD(lx, ly + 1) && IN_SCR_FIELD(x, y + 1))
2497 DrawLevelElement(lx, ly + 1, element);
2501 if (content == EL_ACID)
2503 int dir = MovDir[lx][ly];
2504 int newlx = lx + (dir == MV_LEFT ? -1 : dir == MV_RIGHT ? +1 : 0);
2505 int newly = ly + (dir == MV_UP ? -1 : dir == MV_DOWN ? +1 : 0);
2507 DrawLevelElementThruMask(newlx, newly, EL_ACID);
2510 else if (IS_BLOCKED(lx, ly))
2515 boolean cut_mode = NO_CUTTING;
2516 int element_old, content_old;
2518 Blocked2Moving(lx, ly, &oldx, &oldy);
2521 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
2522 MovDir[oldx][oldy] == MV_RIGHT);
2524 element_old = Feld[oldx][oldy];
2525 content_old = Store[oldx][oldy];
2527 if (element_old == EL_QUICKSAND_EMPTYING ||
2528 element_old == EL_QUICKSAND_FAST_EMPTYING ||
2529 element_old == EL_MAGIC_WALL_EMPTYING ||
2530 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
2531 element_old == EL_DC_MAGIC_WALL_EMPTYING ||
2532 element_old == EL_AMOEBA_DROPPING)
2533 cut_mode = CUT_ABOVE;
2535 DrawScreenElement(x, y, EL_EMPTY);
2538 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
2540 else if (cut_mode == NO_CUTTING)
2541 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
2544 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
2547 else if (IS_DRAWABLE(element))
2548 DrawScreenElement(x, y, element);
2550 DrawScreenElement(x, y, EL_EMPTY);
2553 void DrawLevelField(int x, int y)
2555 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
2556 DrawScreenField(SCREENX(x), SCREENY(y));
2557 else if (IS_MOVING(x, y))
2561 Moving2Blocked(x, y, &newx, &newy);
2562 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
2563 DrawScreenField(SCREENX(newx), SCREENY(newy));
2565 else if (IS_BLOCKED(x, y))
2569 Blocked2Moving(x, y, &oldx, &oldy);
2570 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
2571 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
2575 void DrawMiniElement(int x, int y, int element)
2579 graphic = el2edimg(element);
2580 DrawMiniGraphic(x, y, graphic);
2583 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
2585 int x = sx + scroll_x, y = sy + scroll_y;
2587 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
2588 DrawMiniElement(sx, sy, EL_EMPTY);
2589 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
2590 DrawMiniElement(sx, sy, Feld[x][y]);
2592 DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
2595 void DrawEnvelopeBackgroundTiles(int graphic, int startx, int starty,
2596 int x, int y, int xsize, int ysize,
2597 int tile_width, int tile_height)
2601 int dst_x = startx + x * tile_width;
2602 int dst_y = starty + y * tile_height;
2603 int width = graphic_info[graphic].width;
2604 int height = graphic_info[graphic].height;
2605 int inner_width_raw = MAX(width - 2 * tile_width, tile_width);
2606 int inner_height_raw = MAX(height - 2 * tile_height, tile_height);
2607 int inner_width = inner_width_raw - (inner_width_raw % tile_width);
2608 int inner_height = inner_height_raw - (inner_height_raw % tile_height);
2609 int inner_sx = (width >= 3 * tile_width ? tile_width : 0);
2610 int inner_sy = (height >= 3 * tile_height ? tile_height : 0);
2611 boolean draw_masked = graphic_info[graphic].draw_masked;
2613 getFixedGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
2615 if (src_bitmap == NULL || width < tile_width || height < tile_height)
2617 ClearRectangle(drawto, dst_x, dst_y, tile_width, tile_height);
2621 src_x += (x == 0 ? 0 : x == xsize - 1 ? width - tile_width :
2622 inner_sx + (x - 1) * tile_width % inner_width);
2623 src_y += (y == 0 ? 0 : y == ysize - 1 ? height - tile_height :
2624 inner_sy + (y - 1) * tile_height % inner_height);
2628 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
2629 dst_x - src_x, dst_y - src_y);
2630 BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, tile_width, tile_height,
2634 BlitBitmap(src_bitmap, drawto, src_x, src_y, tile_width, tile_height,
2638 void DrawEnvelopeBackground(int graphic, int startx, int starty,
2639 int x, int y, int xsize, int ysize, int font_nr)
2641 int font_width = getFontWidth(font_nr);
2642 int font_height = getFontHeight(font_nr);
2644 DrawEnvelopeBackgroundTiles(graphic, startx, starty, x, y, xsize, ysize,
2645 font_width, font_height);
2648 void AnimateEnvelope(int envelope_nr, int anim_mode, int action)
2650 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2651 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
2652 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
2653 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2654 boolean no_delay = (tape.warp_forward);
2655 unsigned int anim_delay = 0;
2656 int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
2657 int anim_delay_value = (no_delay ? 0 : frame_delay_value);
2658 int font_nr = FONT_ENVELOPE_1 + envelope_nr;
2659 int font_width = getFontWidth(font_nr);
2660 int font_height = getFontHeight(font_nr);
2661 int max_xsize = level.envelope[envelope_nr].xsize;
2662 int max_ysize = level.envelope[envelope_nr].ysize;
2663 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
2664 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
2665 int xend = max_xsize;
2666 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
2667 int xstep = (xstart < xend ? 1 : 0);
2668 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
2671 for (x = xstart, y = ystart; x <= xend && y <= yend; x += xstep, y += ystep)
2673 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
2674 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
2675 int sx = SX + (SXSIZE - xsize * font_width) / 2;
2676 int sy = SY + (SYSIZE - ysize * font_height) / 2;
2679 SetDrawtoField(DRAW_BUFFERED);
2682 BlitScreenToBitmap(backbuffer);
2684 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
2687 SetDrawtoField(DRAW_BACKBUFFER);
2689 for (yy = 0; yy < ysize; yy++)
2690 for (xx = 0; xx < xsize; xx++)
2691 DrawEnvelopeBackground(graphic, sx, sy, xx, yy, xsize, ysize, font_nr);
2694 DrawTextBuffer(sx + font_width, sy + font_height,
2695 level.envelope[envelope_nr].text, font_nr, max_xsize,
2696 xsize - 2, ysize - 2, 0, mask_mode,
2697 level.envelope[envelope_nr].autowrap,
2698 level.envelope[envelope_nr].centered, FALSE);
2700 DrawTextToTextArea(sx + font_width, sy + font_height,
2701 level.envelope[envelope_nr].text, font_nr, max_xsize,
2702 xsize - 2, ysize - 2, mask_mode);
2705 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
2708 WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
2712 void ShowEnvelope(int envelope_nr)
2714 int element = EL_ENVELOPE_1 + envelope_nr;
2715 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2716 int sound_opening = element_info[element].sound[ACTION_OPENING];
2717 int sound_closing = element_info[element].sound[ACTION_CLOSING];
2718 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2719 boolean no_delay = (tape.warp_forward);
2720 int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
2721 int wait_delay_value = (no_delay ? 0 : normal_delay_value);
2722 int anim_mode = graphic_info[graphic].anim_mode;
2723 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
2724 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
2726 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
2728 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
2730 if (anim_mode == ANIM_DEFAULT)
2731 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_OPENING);
2733 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_OPENING);
2736 Delay(wait_delay_value);
2738 WaitForEventToContinue();
2740 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
2742 if (anim_mode != ANIM_NONE)
2743 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_CLOSING);
2745 if (anim_mode == ANIM_DEFAULT)
2746 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_CLOSING);
2748 game.envelope_active = FALSE;
2750 SetDrawtoField(DRAW_BUFFERED);
2752 redraw_mask |= REDRAW_FIELD;
2756 static void setRequestPosition(int *x, int *y, boolean add_border_size)
2758 int border_size = request.border_size;
2759 int sx_center = (request.x != -1 ? request.x : SX + SXSIZE / 2);
2760 int sy_center = (request.y != -1 ? request.y : SY + SYSIZE / 2);
2761 int sx = sx_center - request.width / 2;
2762 int sy = sy_center - request.height / 2;
2764 if (add_border_size)
2774 void DrawEnvelopeRequest(char *text)
2776 char *text_final = text;
2777 char *text_door_style = NULL;
2778 int graphic = IMG_BACKGROUND_REQUEST;
2779 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
2780 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
2781 int font_nr = FONT_REQUEST;
2782 int font_width = getFontWidth(font_nr);
2783 int font_height = getFontHeight(font_nr);
2784 int border_size = request.border_size;
2785 int line_spacing = request.line_spacing;
2786 int line_height = font_height + line_spacing;
2787 int text_width = request.width - 2 * border_size;
2788 int text_height = request.height - 2 * border_size;
2789 int line_length = text_width / font_width;
2790 int max_lines = text_height / line_height;
2791 int width = request.width;
2792 int height = request.height;
2793 int tile_size = request.step_offset;
2794 int x_steps = width / tile_size;
2795 int y_steps = height / tile_size;
2799 if (request.wrap_single_words)
2801 char *src_text_ptr, *dst_text_ptr;
2803 text_door_style = checked_malloc(2 * strlen(text) + 1);
2805 src_text_ptr = text;
2806 dst_text_ptr = text_door_style;
2808 while (*src_text_ptr)
2810 if (*src_text_ptr == ' ' ||
2811 *src_text_ptr == '?' ||
2812 *src_text_ptr == '!')
2813 *dst_text_ptr++ = '\n';
2815 if (*src_text_ptr != ' ')
2816 *dst_text_ptr++ = *src_text_ptr;
2821 *dst_text_ptr = '\0';
2823 text_final = text_door_style;
2826 setRequestPosition(&sx, &sy, FALSE);
2828 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
2830 for (y = 0; y < y_steps; y++)
2831 for (x = 0; x < x_steps; x++)
2832 DrawEnvelopeBackgroundTiles(graphic, sx, sy,
2833 x, y, x_steps, y_steps,
2834 tile_size, tile_size);
2836 DrawTextBuffer(sx + border_size, sy + border_size, text_final, font_nr,
2837 line_length, -1, max_lines, line_spacing, mask_mode,
2838 request.autowrap, request.centered, FALSE);
2840 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
2841 RedrawGadget(tool_gadget[i]);
2843 // store readily prepared envelope request for later use when animating
2844 BlitBitmap(backbuffer, bitmap_db_cross, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2848 BlitBitmap(bitmap_db_store, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2849 BlitBitmap(bitmap_db_cross, backbuffer, sx, sy, width, height, sx, sy);
2851 redraw_mask = REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
2856 BlitBitmap(bitmap_db_store, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2858 redraw_mask = REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
2864 if (text_door_style)
2865 free(text_door_style);
2870 void AnimateEnvelopeRequest(int anim_mode, int action)
2872 int graphic = IMG_BACKGROUND_REQUEST;
2873 boolean draw_masked = graphic_info[graphic].draw_masked;
2875 int delay_value_normal = request.step_delay;
2876 int delay_value_fast = delay_value_normal / 2;
2878 int delay_value_normal = GameFrameDelay;
2879 int delay_value_fast = FfwdFrameDelay;
2881 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2882 boolean no_delay = (tape.warp_forward);
2883 int delay_value = (ffwd_delay ? delay_value_fast : delay_value_normal);
2884 int anim_delay_value = (no_delay ? 0 : delay_value + 500 * 0);
2885 unsigned int anim_delay = 0;
2887 int width = request.width;
2888 int height = request.height;
2889 int tile_size = request.step_offset;
2890 int max_xsize = width / tile_size;
2891 int max_ysize = height / tile_size;
2892 int max_xsize_inner = max_xsize - 2;
2893 int max_ysize_inner = max_ysize - 2;
2895 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize_inner : 0);
2896 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize_inner : 0);
2897 int xend = max_xsize_inner;
2898 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize_inner : 0);
2899 int xstep = (xstart < xend ? 1 : 0);
2900 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
2903 for (x = xstart, y = ystart; x <= xend && y <= yend; x += xstep, y += ystep)
2905 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
2906 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
2907 int sx_center = (request.x != -1 ? request.x : SX + SXSIZE / 2);
2908 int sy_center = (request.y != -1 ? request.y : SY + SYSIZE / 2);
2909 int src_x = sx_center - width / 2;
2910 int src_y = sy_center - height / 2;
2911 int dst_x = sx_center - xsize * tile_size / 2;
2912 int dst_y = sy_center - ysize * tile_size / 2;
2913 int xsize_size_left = (xsize - 1) * tile_size;
2914 int ysize_size_top = (ysize - 1) * tile_size;
2915 int max_xsize_pos = (max_xsize - 1) * tile_size;
2916 int max_ysize_pos = (max_ysize - 1) * tile_size;
2919 BlitBitmap(bitmap_db_store, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2922 for (yy = 0; yy < 2; yy++)
2924 for (xx = 0; xx < 2; xx++)
2926 int src_xx = src_x + xx * max_xsize_pos;
2927 int src_yy = src_y + yy * max_ysize_pos;
2928 int dst_xx = dst_x + xx * xsize_size_left;
2929 int dst_yy = dst_y + yy * ysize_size_top;
2930 int xx_size = (xx ? tile_size : xsize_size_left);
2931 int yy_size = (yy ? tile_size : ysize_size_top);
2934 BlitBitmapMasked(bitmap_db_cross, backbuffer,
2935 src_xx, src_yy, xx_size, yy_size, dst_xx, dst_yy);
2937 BlitBitmap(bitmap_db_cross, backbuffer,
2938 src_xx, src_yy, xx_size, yy_size, dst_xx, dst_yy);
2942 BlitBitmap(bitmap_db_cross, backbuffer,
2944 xsize_size_left, ysize_size_top,
2946 BlitBitmap(bitmap_db_cross, backbuffer,
2947 src_x + max_xsize_pos, src_y,
2948 tile_size, ysize_size_top,
2949 dst_x + xsize_size_left, dst_y);
2950 BlitBitmap(bitmap_db_cross, backbuffer,
2951 src_x, src_y + max_ysize_pos,
2952 xsize_size_left, tile_size,
2953 dst_x, dst_y + ysize_size_top);
2954 BlitBitmap(bitmap_db_cross, backbuffer,
2955 src_x + max_xsize_pos, src_y + max_ysize_pos,
2956 tile_size, tile_size,
2957 dst_x + xsize_size_left, dst_y + ysize_size_top);
2961 redraw_mask = REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
2962 // redraw_mask |= REDRAW_ALL | REDRAW_FROM_BACKBUFFER;
2964 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
2974 WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
2980 void AnimateEnvelopeRequest(char *text, int anim_mode, int action)
2983 int envelope_nr = 0;
2986 int graphic = IMG_BACKGROUND_REQUEST;
2988 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2990 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
2991 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
2992 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2993 boolean no_delay = (tape.warp_forward);
2994 unsigned int anim_delay = 0;
2995 int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
2996 int anim_delay_value = (no_delay ? 0 : frame_delay_value + 500 * 0);
2998 int max_word_len = maxWordLengthInString(text);
2999 int font_nr = (max_word_len > 7 ? FONT_TEXT_1 : FONT_TEXT_2);
3001 int font_nr = FONT_ENVELOPE_1 + envelope_nr;
3003 int font_width = getFontWidth(font_nr);
3004 int font_height = getFontHeight(font_nr);
3005 int line_spacing = 2 * 1;
3009 int max_xsize = DXSIZE / font_width;
3010 // int max_ysize = DYSIZE / font_height;
3011 int max_ysize = DYSIZE / (font_height + line_spacing);
3013 int max_xsize = 7; /* tools.c: MAX_REQUEST_LINE_FONT1_LEN == 7 */
3014 int max_ysize = 13; /* tools.c: MAX_REQUEST_LINES == 13 */
3018 int max_xsize = level.envelope[envelope_nr].xsize;
3019 int max_ysize = level.envelope[envelope_nr].ysize;
3021 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
3022 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
3023 int xend = max_xsize;
3024 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
3025 int xstep = (xstart < xend ? 1 : 0);
3026 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
3031 char *text_copy = getStringCopy(text);
3034 font_nr = FONT_TEXT_2;
3036 if (maxWordLengthInString(text) > 7) /* MAX_REQUEST_LINE_FONT1_LEN == 7 */
3038 max_xsize = 10; /* tools.c: MAX_REQUEST_LINE_FONT2_LEN == 10 */
3039 font_nr = FONT_TEXT_1;
3042 int max_word_len = 0;
3044 char *text_copy = getStringCopy(text);
3046 font_nr = FONT_TEXT_2;
3048 for (text_ptr = text; *text_ptr; text_ptr++)
3050 max_word_len = (*text_ptr != ' ' ? max_word_len + 1 : 0);
3052 if (max_word_len > 7) /* tools.c: MAX_REQUEST_LINE_FONT1_LEN == 7 */
3054 max_xsize = 10; /* tools.c: MAX_REQUEST_LINE_FONT2_LEN == 10 */
3055 font_nr = FONT_TEXT_1;
3064 for (text_ptr = text_copy; *text_ptr; text_ptr++)
3065 if (*text_ptr == ' ')
3070 dDX = SX + (SXSIZE - DXSIZE) / 2 - DX;
3071 dDY = SY + (SYSIZE - DYSIZE) / 2 - DY;
3073 dDX = SX + SXSIZE / 2 - max_xsize * font_width / 2 - DX;
3074 dDY = SY + SYSIZE / 2 - max_ysize * font_height / 2 - DY;
3077 for (x = xstart, y = ystart; x <= xend && y <= yend; x += xstep, y += ystep)
3079 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
3080 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
3081 int sx = SX + (SXSIZE - xsize * font_width) / 2;
3082 // int sy = SX + (SYSIZE - ysize * font_height) / 2;
3083 int sy = SY + (SYSIZE - ysize * (font_height + line_spacing)) / 2;
3087 BlitBitmap(bitmap_db_store, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
3089 SetDrawtoField(DRAW_BUFFERED);
3092 BlitScreenToBitmap(backbuffer);
3094 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
3097 SetDrawtoField(DRAW_BACKBUFFER);
3100 for (yy = 0; yy < ysize; yy++)
3101 for (xx = 0; xx < xsize; xx++)
3102 DrawEnvelopeBackgroundTiles(graphic, sx, sy, xx, yy, xsize, ysize,
3103 getFontWidth(font_nr),
3104 getFontHeight(font_nr) + line_spacing);
3109 DrawTextBuffer(sx + font_width, sy + font_height + 8,
3110 text_copy, font_nr, max_xsize,
3111 xsize - 2, ysize - 2, line_spacing, mask_mode,
3112 FALSE, TRUE, FALSE);
3114 DrawTextBuffer(sx + font_width, sy + font_height,
3115 level.envelope[envelope_nr].text, font_nr, max_xsize,
3116 xsize - 2, ysize - 2, 0, mask_mode,
3117 level.envelope[envelope_nr].autowrap,
3118 level.envelope[envelope_nr].centered, FALSE);
3122 DrawTextToTextArea(sx + font_width, sy + font_height,
3123 level.envelope[envelope_nr].text, font_nr, max_xsize,
3124 xsize - 2, ysize - 2, mask_mode);
3127 /* copy request gadgets to door backbuffer */
3130 if ((ysize - 2) > 13)
3131 BlitBitmap(bitmap_db_door, drawto,
3132 DOOR_GFX_PAGEX1 + (DXSIZE - (xsize - 2) * font_width) / 2,
3133 DOOR_GFX_PAGEY1 + 13 * font_height,
3134 (xsize - 2) * font_width,
3135 (ysize - 2 - 13) * font_height,
3137 sy + font_height * (1 + 13));
3139 if ((ysize - 2) > 13)
3140 BlitBitmap(bitmap_db_door, drawto,
3141 DOOR_GFX_PAGEX1 + (DXSIZE - (xsize - 2) * font_width) / 2,
3142 DOOR_GFX_PAGEY1 + 11 * (font_height + line_spacing * 0),
3143 (xsize - 2) * font_width,
3144 (ysize - 2 - 13) * (font_height + line_spacing),
3146 sy + (font_height + line_spacing) * (1 + 13));
3148 if ((ysize - 2) > 13)
3149 BlitBitmap(bitmap_db_door, drawto,
3150 DOOR_GFX_PAGEX1 + (DXSIZE - (xsize - 2) * font_width) / 2,
3151 DOOR_GFX_PAGEY1 + 13 * font_height,
3152 (xsize - 2) * font_width,
3153 (ysize - 2 - 13) * font_height,
3155 sy + font_height * (1 + 13));
3159 redraw_mask = REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
3160 // redraw_mask |= REDRAW_ALL | REDRAW_FROM_BACKBUFFER;
3162 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
3172 WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
3182 void ShowEnvelopeRequest(char *text, unsigned int req_state, int action)
3185 int last_game_status = game_status; /* save current game status */
3186 // int last_draw_background_mask = gfx.draw_background_mask;
3189 int graphic = IMG_BACKGROUND_REQUEST;
3190 int sound_opening = SND_REQUEST_OPENING;
3191 int sound_closing = SND_REQUEST_CLOSING;
3193 int envelope_nr = 0;
3194 int element = EL_ENVELOPE_1 + envelope_nr;
3195 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
3196 int sound_opening = element_info[element].sound[ACTION_OPENING];
3197 int sound_closing = element_info[element].sound[ACTION_CLOSING];
3200 boolean ffwd_delay = (tape.playing && tape.fast_forward);
3201 boolean no_delay = (tape.warp_forward);
3202 int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
3203 int wait_delay_value = (no_delay ? 0 : normal_delay_value);
3205 int anim_mode = graphic_info[graphic].anim_mode;
3206 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
3207 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
3209 char *text_copy = getStringCopy(text);
3212 for (text_ptr = text_copy; *text_ptr; text_ptr++)
3213 if (*text_ptr == ' ')
3218 if (game_status == GAME_MODE_PLAYING)
3220 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
3221 BlitScreenToBitmap_EM(backbuffer);
3222 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
3223 BlitScreenToBitmap_SP(backbuffer);
3226 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
3230 SetDrawtoField(DRAW_BACKBUFFER);
3232 // SetDrawBackgroundMask(REDRAW_NONE);
3234 if (action == ACTION_OPENING)
3236 BlitBitmap(backbuffer, bitmap_db_store, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
3239 if (req_state & REQ_ASK)
3241 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
3242 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
3244 else if (req_state & REQ_CONFIRM)
3246 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
3248 else if (req_state & REQ_PLAYER)
3250 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
3251 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
3252 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
3253 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
3258 DrawEnvelopeRequest(text);
3260 DrawEnvelopeRequest(text_copy);
3263 if (game_status != GAME_MODE_MAIN)
3267 /* force DOOR font inside door area */
3268 game_status = GAME_MODE_PSEUDO_DOOR;
3271 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
3273 if (action == ACTION_OPENING)
3275 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
3277 if (anim_mode == ANIM_DEFAULT)
3278 AnimateEnvelopeRequest(ANIM_DEFAULT, ACTION_OPENING);
3280 AnimateEnvelopeRequest(main_anim_mode, ACTION_OPENING);
3284 Delay(wait_delay_value);
3286 WaitForEventToContinue();
3291 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
3293 if (anim_mode != ANIM_NONE)
3294 AnimateEnvelopeRequest(main_anim_mode, ACTION_CLOSING);
3296 if (anim_mode == ANIM_DEFAULT)
3297 AnimateEnvelopeRequest(ANIM_DEFAULT, ACTION_CLOSING);
3300 game.envelope_active = FALSE;
3303 // game_status = last_game_status; /* restore current game status */
3305 if (action == ACTION_CLOSING)
3307 if (game_status != GAME_MODE_MAIN)
3310 BlitBitmap(bitmap_db_store, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
3313 SetDrawtoField(DRAW_BUFFERED);
3316 // SetDrawBackgroundMask(last_draw_background_mask);
3319 redraw_mask = REDRAW_FIELD;
3320 // redraw_mask |= REDRAW_ALL;
3322 redraw_mask |= REDRAW_FIELD;
3326 if (game_status == GAME_MODE_MAIN)
3331 /* (important: after "BackToFront()", but before "SetDrawtoField()") */
3332 game_status = last_game_status; /* restore current game status */
3335 if (action == ACTION_CLOSING &&
3336 game_status == GAME_MODE_PLAYING &&
3337 level.game_engine_type == GAME_ENGINE_TYPE_RND)
3338 SetDrawtoField(DRAW_BUFFERED);
3340 if (game_status == GAME_MODE_PLAYING &&
3341 level.game_engine_type == GAME_ENGINE_TYPE_RND)
3342 SetDrawtoField(DRAW_BUFFERED);
3354 void DrawPreviewElement(int dst_x, int dst_y, int element, int tilesize)
3358 int graphic = el2preimg(element);
3360 getSizedGraphicSource(graphic, 0, tilesize, &src_bitmap, &src_x, &src_y);
3361 BlitBitmap(src_bitmap, drawto, src_x, src_y, tilesize, tilesize, dst_x,dst_y);
3369 SetMainBackgroundImage(IMG_BACKGROUND_PLAYING);
3370 SetDrawBackgroundMask(REDRAW_FIELD);
3372 SetDrawBackgroundMask(REDRAW_NONE);
3377 for (x = BX1; x <= BX2; x++)
3378 for (y = BY1; y <= BY2; y++)
3379 DrawScreenField(x, y);
3381 redraw_mask |= REDRAW_FIELD;
3384 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
3388 for (x = 0; x < size_x; x++)
3389 for (y = 0; y < size_y; y++)
3390 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
3392 redraw_mask |= REDRAW_FIELD;
3395 static void DrawPreviewLevelPlayfieldExt(int from_x, int from_y)
3397 boolean show_level_border = (BorderElement != EL_EMPTY);
3398 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
3399 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
3400 int tile_size = preview.tile_size;
3401 int preview_width = preview.xsize * tile_size;
3402 int preview_height = preview.ysize * tile_size;
3403 int real_preview_xsize = MIN(level_xsize, preview.xsize);
3404 int real_preview_ysize = MIN(level_ysize, preview.ysize);
3405 int dst_x = SX + ALIGNED_XPOS(preview.x, preview_width, preview.align);
3406 int dst_y = SY + ALIGNED_YPOS(preview.y, preview_height, preview.valign);
3409 DrawBackground(dst_x, dst_y, preview_width, preview_height);
3411 dst_x += (preview_width - real_preview_xsize * tile_size) / 2;
3412 dst_y += (preview_height - real_preview_ysize * tile_size) / 2;
3414 for (x = 0; x < real_preview_xsize; x++)
3416 for (y = 0; y < real_preview_ysize; y++)
3418 int lx = from_x + x + (show_level_border ? -1 : 0);
3419 int ly = from_y + y + (show_level_border ? -1 : 0);
3420 int element = (IN_LEV_FIELD(lx, ly) ? level.field[lx][ly] :
3421 getBorderElement(lx, ly));
3423 DrawPreviewElement(dst_x + x * tile_size, dst_y + y * tile_size,
3424 element, tile_size);
3428 redraw_mask |= REDRAW_MICROLEVEL;
3431 #define MICROLABEL_EMPTY 0
3432 #define MICROLABEL_LEVEL_NAME 1
3433 #define MICROLABEL_LEVEL_AUTHOR_HEAD 2
3434 #define MICROLABEL_LEVEL_AUTHOR 3
3435 #define MICROLABEL_IMPORTED_FROM_HEAD 4
3436 #define MICROLABEL_IMPORTED_FROM 5
3437 #define MICROLABEL_IMPORTED_BY_HEAD 6
3438 #define MICROLABEL_IMPORTED_BY 7
3440 static int getMaxTextLength(struct TextPosInfo *pos, int font_nr)
3442 int max_text_width = SXSIZE;
3443 int font_width = getFontWidth(font_nr);
3445 if (pos->align == ALIGN_CENTER)
3446 max_text_width = (pos->x < SXSIZE / 2 ? pos->x * 2 : (SXSIZE - pos->x) * 2);
3447 else if (pos->align == ALIGN_RIGHT)
3448 max_text_width = pos->x;
3450 max_text_width = SXSIZE - pos->x;
3452 return max_text_width / font_width;
3455 static void DrawPreviewLevelLabelExt(int mode)
3457 struct TextPosInfo *pos = &menu.main.text.level_info_2;
3458 char label_text[MAX_OUTPUT_LINESIZE + 1];
3459 int max_len_label_text;
3461 int font_nr = pos->font;
3464 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
3465 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
3466 mode == MICROLABEL_IMPORTED_BY_HEAD)
3467 font_nr = pos->font_alt;
3469 int font_nr = FONT_TEXT_2;
3472 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
3473 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
3474 mode == MICROLABEL_IMPORTED_BY_HEAD)
3475 font_nr = FONT_TEXT_3;
3479 max_len_label_text = getMaxTextLength(pos, font_nr);
3481 max_len_label_text = SXSIZE / getFontWidth(font_nr);
3485 if (pos->size != -1)
3486 max_len_label_text = pos->size;
3489 for (i = 0; i < max_len_label_text; i++)
3490 label_text[i] = ' ';
3491 label_text[max_len_label_text] = '\0';
3493 if (strlen(label_text) > 0)
3496 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
3498 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
3499 int lypos = MICROLABEL2_YPOS;
3501 DrawText(lxpos, lypos, label_text, font_nr);
3506 (mode == MICROLABEL_LEVEL_NAME ? level.name :
3507 mode == MICROLABEL_LEVEL_AUTHOR_HEAD ? "created by" :
3508 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
3509 mode == MICROLABEL_IMPORTED_FROM_HEAD ? "imported from" :
3510 mode == MICROLABEL_IMPORTED_FROM ? leveldir_current->imported_from :
3511 mode == MICROLABEL_IMPORTED_BY_HEAD ? "imported by" :
3512 mode == MICROLABEL_IMPORTED_BY ? leveldir_current->imported_by :""),
3513 max_len_label_text);
3514 label_text[max_len_label_text] = '\0';
3516 if (strlen(label_text) > 0)
3519 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
3521 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
3522 int lypos = MICROLABEL2_YPOS;
3524 DrawText(lxpos, lypos, label_text, font_nr);
3528 redraw_mask |= REDRAW_MICROLEVEL;
3531 static void DrawPreviewLevelExt(boolean restart)
3533 static unsigned int scroll_delay = 0;
3534 static unsigned int label_delay = 0;
3535 static int from_x, from_y, scroll_direction;
3536 static int label_state, label_counter;
3537 unsigned int scroll_delay_value = preview.step_delay;
3538 boolean show_level_border = (BorderElement != EL_EMPTY);
3539 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
3540 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
3541 int last_game_status = game_status; /* save current game status */
3544 /* force PREVIEW font on preview level */
3545 game_status = GAME_MODE_PSEUDO_PREVIEW;
3553 if (preview.anim_mode == ANIM_CENTERED)
3555 if (level_xsize > preview.xsize)
3556 from_x = (level_xsize - preview.xsize) / 2;
3557 if (level_ysize > preview.ysize)
3558 from_y = (level_ysize - preview.ysize) / 2;
3561 from_x += preview.xoffset;
3562 from_y += preview.yoffset;
3564 scroll_direction = MV_RIGHT;
3568 DrawPreviewLevelPlayfieldExt(from_x, from_y);
3569 DrawPreviewLevelLabelExt(label_state);
3571 /* initialize delay counters */
3572 DelayReached(&scroll_delay, 0);
3573 DelayReached(&label_delay, 0);
3575 if (leveldir_current->name)
3577 struct TextPosInfo *pos = &menu.main.text.level_info_1;
3578 char label_text[MAX_OUTPUT_LINESIZE + 1];
3580 int font_nr = pos->font;
3582 int font_nr = FONT_TEXT_1;
3585 int max_len_label_text = getMaxTextLength(pos, font_nr);
3587 int max_len_label_text = SXSIZE / getFontWidth(font_nr);
3595 if (pos->size != -1)
3596 max_len_label_text = pos->size;
3599 strncpy(label_text, leveldir_current->name, max_len_label_text);
3600 label_text[max_len_label_text] = '\0';
3603 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
3605 lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
3606 lypos = SY + MICROLABEL1_YPOS;
3608 DrawText(lxpos, lypos, label_text, font_nr);
3612 game_status = last_game_status; /* restore current game status */
3617 /* scroll preview level, if needed */
3618 if (preview.anim_mode != ANIM_NONE &&
3619 (level_xsize > preview.xsize || level_ysize > preview.ysize) &&
3620 DelayReached(&scroll_delay, scroll_delay_value))
3622 switch (scroll_direction)
3627 from_x -= preview.step_offset;
3628 from_x = (from_x < 0 ? 0 : from_x);
3631 scroll_direction = MV_UP;
3635 if (from_x < level_xsize - preview.xsize)
3637 from_x += preview.step_offset;
3638 from_x = (from_x > level_xsize - preview.xsize ?
3639 level_xsize - preview.xsize : from_x);
3642 scroll_direction = MV_DOWN;
3648 from_y -= preview.step_offset;
3649 from_y = (from_y < 0 ? 0 : from_y);
3652 scroll_direction = MV_RIGHT;
3656 if (from_y < level_ysize - preview.ysize)
3658 from_y += preview.step_offset;
3659 from_y = (from_y > level_ysize - preview.ysize ?
3660 level_ysize - preview.ysize : from_y);
3663 scroll_direction = MV_LEFT;
3670 DrawPreviewLevelPlayfieldExt(from_x, from_y);
3673 /* !!! THIS ALL SUCKS -- SHOULD BE CLEANLY REWRITTEN !!! */
3674 /* redraw micro level label, if needed */
3675 if (!strEqual(level.name, NAMELESS_LEVEL_NAME) &&
3676 !strEqual(level.author, ANONYMOUS_NAME) &&
3677 !strEqual(level.author, leveldir_current->name) &&
3678 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
3680 int max_label_counter = 23;
3682 if (leveldir_current->imported_from != NULL &&
3683 strlen(leveldir_current->imported_from) > 0)
3684 max_label_counter += 14;
3685 if (leveldir_current->imported_by != NULL &&
3686 strlen(leveldir_current->imported_by) > 0)
3687 max_label_counter += 14;
3689 label_counter = (label_counter + 1) % max_label_counter;
3690 label_state = (label_counter >= 0 && label_counter <= 7 ?
3691 MICROLABEL_LEVEL_NAME :
3692 label_counter >= 9 && label_counter <= 12 ?
3693 MICROLABEL_LEVEL_AUTHOR_HEAD :
3694 label_counter >= 14 && label_counter <= 21 ?
3695 MICROLABEL_LEVEL_AUTHOR :
3696 label_counter >= 23 && label_counter <= 26 ?
3697 MICROLABEL_IMPORTED_FROM_HEAD :
3698 label_counter >= 28 && label_counter <= 35 ?
3699 MICROLABEL_IMPORTED_FROM :
3700 label_counter >= 37 && label_counter <= 40 ?
3701 MICROLABEL_IMPORTED_BY_HEAD :
3702 label_counter >= 42 && label_counter <= 49 ?
3703 MICROLABEL_IMPORTED_BY : MICROLABEL_EMPTY);
3705 if (leveldir_current->imported_from == NULL &&
3706 (label_state == MICROLABEL_IMPORTED_FROM_HEAD ||
3707 label_state == MICROLABEL_IMPORTED_FROM))
3708 label_state = (label_state == MICROLABEL_IMPORTED_FROM_HEAD ?
3709 MICROLABEL_IMPORTED_BY_HEAD : MICROLABEL_IMPORTED_BY);
3711 DrawPreviewLevelLabelExt(label_state);
3714 game_status = last_game_status; /* restore current game status */
3717 void DrawPreviewLevelInitial()
3719 DrawPreviewLevelExt(TRUE);
3722 void DrawPreviewLevelAnimation()
3724 DrawPreviewLevelExt(FALSE);
3727 inline void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
3728 int graphic, int sync_frame, int mask_mode)
3730 int frame = getGraphicAnimationFrame(graphic, sync_frame);
3732 if (mask_mode == USE_MASKING)
3733 DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
3735 DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
3738 inline void DrawFixedGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
3739 int graphic, int sync_frame,
3742 int frame = getGraphicAnimationFrame(graphic, sync_frame);
3744 if (mask_mode == USE_MASKING)
3745 DrawFixedGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
3747 DrawFixedGraphicExt(dst_bitmap, x, y, graphic, frame);
3750 inline void DrawGraphicAnimation(int x, int y, int graphic)
3752 int lx = LEVELX(x), ly = LEVELY(y);
3754 if (!IN_SCR_FIELD(x, y))
3758 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR,
3759 graphic, GfxFrame[lx][ly], NO_MASKING);
3761 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
3762 graphic, GfxFrame[lx][ly], NO_MASKING);
3764 MarkTileDirty(x, y);
3767 inline void DrawFixedGraphicAnimation(int x, int y, int graphic)
3769 int lx = LEVELX(x), ly = LEVELY(y);
3771 if (!IN_SCR_FIELD(x, y))
3774 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
3775 graphic, GfxFrame[lx][ly], NO_MASKING);
3776 MarkTileDirty(x, y);
3779 void DrawLevelGraphicAnimation(int x, int y, int graphic)
3781 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
3784 void DrawLevelElementAnimation(int x, int y, int element)
3786 int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
3788 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
3791 inline void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
3793 int sx = SCREENX(x), sy = SCREENY(y);
3795 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
3798 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
3801 DrawGraphicAnimation(sx, sy, graphic);
3804 if (GFX_CRUMBLED(TILE_GFX_ELEMENT(x, y)))
3805 DrawLevelFieldCrumbled(x, y);
3807 if (GFX_CRUMBLED(Feld[x][y]))
3808 DrawLevelFieldCrumbled(x, y);
3812 void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
3814 int sx = SCREENX(x), sy = SCREENY(y);
3817 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
3820 graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
3822 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
3825 DrawGraphicAnimation(sx, sy, graphic);
3827 if (GFX_CRUMBLED(element))
3828 DrawLevelFieldCrumbled(x, y);
3831 static int getPlayerGraphic(struct PlayerInfo *player, int move_dir)
3833 if (player->use_murphy)
3835 /* this works only because currently only one player can be "murphy" ... */
3836 static int last_horizontal_dir = MV_LEFT;
3837 int graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir);
3839 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3840 last_horizontal_dir = move_dir;
3842 if (graphic == IMG_SP_MURPHY) /* undefined => use special graphic */
3844 int direction = (player->is_snapping ? move_dir : last_horizontal_dir);
3846 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
3852 return el_act_dir2img(player->artwork_element, player->GfxAction,move_dir);
3855 static boolean equalGraphics(int graphic1, int graphic2)
3857 struct GraphicInfo *g1 = &graphic_info[graphic1];
3858 struct GraphicInfo *g2 = &graphic_info[graphic2];
3860 return (g1->bitmap == g2->bitmap &&
3861 g1->src_x == g2->src_x &&
3862 g1->src_y == g2->src_y &&
3863 g1->anim_frames == g2->anim_frames &&
3864 g1->anim_delay == g2->anim_delay &&
3865 g1->anim_mode == g2->anim_mode);
3868 void DrawAllPlayers()
3872 for (i = 0; i < MAX_PLAYERS; i++)
3873 if (stored_player[i].active)
3874 DrawPlayer(&stored_player[i]);
3877 void DrawPlayerField(int x, int y)
3879 if (!IS_PLAYER(x, y))
3882 DrawPlayer(PLAYERINFO(x, y));
3885 #define DRAW_PLAYER_OVER_PUSHED_ELEMENT 1
3887 void DrawPlayer(struct PlayerInfo *player)
3889 int jx = player->jx;
3890 int jy = player->jy;
3891 int move_dir = player->MovDir;
3892 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? +1 : 0);
3893 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? +1 : 0);
3894 int last_jx = (player->is_moving ? jx - dx : jx);
3895 int last_jy = (player->is_moving ? jy - dy : jy);
3896 int next_jx = jx + dx;
3897 int next_jy = jy + dy;
3898 boolean player_is_moving = (player->MovPos ? TRUE : FALSE);
3899 boolean player_is_opaque = FALSE;
3900 int sx = SCREENX(jx), sy = SCREENY(jy);
3901 int sxx = 0, syy = 0;
3902 int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
3904 int action = ACTION_DEFAULT;
3905 int last_player_graphic = getPlayerGraphic(player, move_dir);
3906 int last_player_frame = player->Frame;
3909 /* GfxElement[][] is set to the element the player is digging or collecting;
3910 remove also for off-screen player if the player is not moving anymore */
3911 if (IN_LEV_FIELD(jx, jy) && !player_is_moving)
3912 GfxElement[jx][jy] = EL_UNDEFINED;
3914 if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
3918 if (!IN_LEV_FIELD(jx, jy))
3920 printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
3921 printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
3922 printf("DrawPlayerField(): This should never happen!\n");
3927 if (element == EL_EXPLOSION)
3930 action = (player->is_pushing ? ACTION_PUSHING :
3931 player->is_digging ? ACTION_DIGGING :
3932 player->is_collecting ? ACTION_COLLECTING :
3933 player->is_moving ? ACTION_MOVING :
3934 player->is_snapping ? ACTION_SNAPPING :
3935 player->is_dropping ? ACTION_DROPPING :
3936 player->is_waiting ? player->action_waiting : ACTION_DEFAULT);
3938 if (player->is_waiting)
3939 move_dir = player->dir_waiting;
3941 InitPlayerGfxAnimation(player, action, move_dir);
3943 /* ----------------------------------------------------------------------- */
3944 /* draw things in the field the player is leaving, if needed */
3945 /* ----------------------------------------------------------------------- */
3947 if (player->is_moving)
3949 if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
3951 DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
3953 if (last_element == EL_DYNAMITE_ACTIVE ||
3954 last_element == EL_EM_DYNAMITE_ACTIVE ||
3955 last_element == EL_SP_DISK_RED_ACTIVE)
3956 DrawDynamite(last_jx, last_jy);
3958 DrawLevelFieldThruMask(last_jx, last_jy);
3960 else if (last_element == EL_DYNAMITE_ACTIVE ||
3961 last_element == EL_EM_DYNAMITE_ACTIVE ||
3962 last_element == EL_SP_DISK_RED_ACTIVE)
3963 DrawDynamite(last_jx, last_jy);
3965 /* !!! this is not enough to prevent flickering of players which are
3966 moving next to each others without a free tile between them -- this
3967 can only be solved by drawing all players layer by layer (first the
3968 background, then the foreground etc.) !!! => TODO */
3969 else if (!IS_PLAYER(last_jx, last_jy))
3970 DrawLevelField(last_jx, last_jy);
3973 DrawLevelField(last_jx, last_jy);
3976 if (player->is_pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
3977 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
3980 if (!IN_SCR_FIELD(sx, sy))
3983 /* ----------------------------------------------------------------------- */
3984 /* draw things behind the player, if needed */
3985 /* ----------------------------------------------------------------------- */
3988 DrawLevelElement(jx, jy, Back[jx][jy]);
3989 else if (IS_ACTIVE_BOMB(element))
3990 DrawLevelElement(jx, jy, EL_EMPTY);
3993 if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
3995 int old_element = GfxElement[jx][jy];
3996 int old_graphic = el_act_dir2img(old_element, action, move_dir);
3997 int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
3999 if (GFX_CRUMBLED(old_element))
4000 DrawLevelFieldCrumbledDigging(jx, jy, move_dir, player->StepFrame);
4002 DrawGraphic(sx, sy, old_graphic, frame);
4004 if (graphic_info[old_graphic].anim_mode & ANIM_OPAQUE_PLAYER)
4005 player_is_opaque = TRUE;
4009 GfxElement[jx][jy] = EL_UNDEFINED;
4011 /* make sure that pushed elements are drawn with correct frame rate */
4013 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
4015 if (player->is_pushing && player->is_moving && !IS_ANIM_MODE_CE(graphic))
4016 GfxFrame[jx][jy] = player->StepFrame;
4018 if (player->is_pushing && player->is_moving)
4019 GfxFrame[jx][jy] = player->StepFrame;
4022 DrawLevelField(jx, jy);
4026 #if !DRAW_PLAYER_OVER_PUSHED_ELEMENT
4027 /* ----------------------------------------------------------------------- */
4028 /* draw player himself */
4029 /* ----------------------------------------------------------------------- */
4031 graphic = getPlayerGraphic(player, move_dir);
4033 /* in the case of changed player action or direction, prevent the current
4034 animation frame from being restarted for identical animations */
4035 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
4036 player->Frame = last_player_frame;
4038 frame = getGraphicAnimationFrame(graphic, player->Frame);
4042 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
4043 sxx = player->GfxPos;
4045 syy = player->GfxPos;
4048 if (!setup.soft_scrolling && ScreenMovPos)
4051 if (player_is_opaque)
4052 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
4054 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
4056 if (SHIELD_ON(player))
4058 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
4059 IMG_SHIELD_NORMAL_ACTIVE);
4060 int frame = getGraphicAnimationFrame(graphic, -1);
4062 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
4066 #if DRAW_PLAYER_OVER_PUSHED_ELEMENT
4069 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
4070 sxx = player->GfxPos;
4072 syy = player->GfxPos;
4076 /* ----------------------------------------------------------------------- */
4077 /* draw things the player is pushing, if needed */
4078 /* ----------------------------------------------------------------------- */
4081 printf("::: %d, %d [%d, %d] [%d]\n",
4082 player->is_pushing, player_is_moving, player->GfxAction,
4083 player->is_moving, player_is_moving);
4087 if (player->is_pushing && player->is_moving)
4089 int px = SCREENX(jx), py = SCREENY(jy);
4090 int pxx = (TILEX - ABS(sxx)) * dx;
4091 int pyy = (TILEY - ABS(syy)) * dy;
4092 int gfx_frame = GfxFrame[jx][jy];
4098 if (!IS_MOVING(jx, jy)) /* push movement already finished */
4100 element = Feld[next_jx][next_jy];
4101 gfx_frame = GfxFrame[next_jx][next_jy];
4104 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
4107 sync_frame = (IS_ANIM_MODE_CE(graphic) ? gfx_frame : player->StepFrame);
4108 frame = getGraphicAnimationFrame(graphic, sync_frame);
4110 frame = getGraphicAnimationFrame(graphic, player->StepFrame);
4113 /* draw background element under pushed element (like the Sokoban field) */
4115 if (game.use_masked_pushing && IS_MOVING(jx, jy))
4117 /* this allows transparent pushing animation over non-black background */
4120 DrawLevelElement(jx, jy, Back[jx][jy]);
4122 DrawLevelElement(jx, jy, EL_EMPTY);
4124 if (Back[next_jx][next_jy])
4125 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
4127 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
4129 else if (Back[next_jx][next_jy])
4130 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
4132 if (Back[next_jx][next_jy])
4133 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
4137 printf("::: %d, %d, %d, %d [%d] [%d, %d, %d] [%d] [%d, %d] [%d, %d]\n",
4138 jx, px, player->GfxPos, player->StepFrame,
4143 GfxFrame[jx][jy], GfxFrame[next_jx][next_jy]);
4147 /* do not draw (EM style) pushing animation when pushing is finished */
4148 /* (two-tile animations usually do not contain start and end frame) */
4149 if (graphic_info[graphic].double_movement && !IS_MOVING(jx, jy))
4150 DrawLevelElement(next_jx, next_jy, Feld[next_jx][next_jy]);
4152 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
4154 /* masked drawing is needed for EMC style (double) movement graphics */
4155 /* !!! (ONLY WHEN DRAWING PUSHED ELEMENT OVER THE PLAYER) !!! */
4156 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
4161 #if DRAW_PLAYER_OVER_PUSHED_ELEMENT
4162 /* ----------------------------------------------------------------------- */
4163 /* draw player himself */
4164 /* ----------------------------------------------------------------------- */
4166 graphic = getPlayerGraphic(player, move_dir);
4168 /* in the case of changed player action or direction, prevent the current
4169 animation frame from being restarted for identical animations */
4170 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
4171 player->Frame = last_player_frame;
4173 frame = getGraphicAnimationFrame(graphic, player->Frame);
4177 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
4178 sxx = player->GfxPos;
4180 syy = player->GfxPos;
4183 if (!setup.soft_scrolling && ScreenMovPos)
4186 if (player_is_opaque)
4187 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
4189 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
4191 if (SHIELD_ON(player))
4193 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
4194 IMG_SHIELD_NORMAL_ACTIVE);
4195 int frame = getGraphicAnimationFrame(graphic, -1);
4197 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
4201 /* ----------------------------------------------------------------------- */
4202 /* draw things in front of player (active dynamite or dynabombs) */
4203 /* ----------------------------------------------------------------------- */
4205 if (IS_ACTIVE_BOMB(element))
4207 graphic = el2img(element);
4208 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
4210 if (game.emulation == EMU_SUPAPLEX)
4211 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
4213 DrawGraphicThruMask(sx, sy, graphic, frame);
4216 if (player_is_moving && last_element == EL_EXPLOSION)
4218 int element = (GfxElement[last_jx][last_jy] != EL_UNDEFINED ?
4219 GfxElement[last_jx][last_jy] : EL_EMPTY);
4220 int graphic = el_act2img(element, ACTION_EXPLODING);
4221 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
4222 int phase = ExplodePhase[last_jx][last_jy] - 1;
4223 int frame = getGraphicAnimationFrame(graphic, phase - delay);
4226 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
4229 /* ----------------------------------------------------------------------- */
4230 /* draw elements the player is just walking/passing through/under */
4231 /* ----------------------------------------------------------------------- */
4233 if (player_is_moving)
4235 /* handle the field the player is leaving ... */
4236 if (IS_ACCESSIBLE_INSIDE(last_element))
4237 DrawLevelField(last_jx, last_jy);
4238 else if (IS_ACCESSIBLE_UNDER(last_element))
4239 DrawLevelFieldThruMask(last_jx, last_jy);
4242 /* do not redraw accessible elements if the player is just pushing them */
4243 if (!player_is_moving || !player->is_pushing)
4245 /* ... and the field the player is entering */
4246 if (IS_ACCESSIBLE_INSIDE(element))
4247 DrawLevelField(jx, jy);
4248 else if (IS_ACCESSIBLE_UNDER(element))
4249 DrawLevelFieldThruMask(jx, jy);
4252 MarkTileDirty(sx, sy);
4255 /* ------------------------------------------------------------------------- */
4257 void WaitForEventToContinue()
4259 boolean still_wait = TRUE;
4261 /* simulate releasing mouse button over last gadget, if still pressed */
4263 HandleGadgets(-1, -1, 0);
4265 button_status = MB_RELEASED;
4281 case EVENT_BUTTONPRESS:
4282 case EVENT_KEYPRESS:
4286 case EVENT_KEYRELEASE:
4287 ClearPlayerAction();
4291 HandleOtherEvents(&event);
4295 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
4302 /* don't eat all CPU time */
4307 #define MAX_REQUEST_LINES 13
4308 #define MAX_REQUEST_LINE_FONT1_LEN 7
4309 #define MAX_REQUEST_LINE_FONT2_LEN 10
4313 static int RequestHandleEvents(unsigned int req_state)
4315 int last_game_status = game_status; /* save current game status */
4319 button_status = MB_RELEASED;
4321 request_gadget_id = -1;
4334 case EVENT_BUTTONPRESS:
4335 case EVENT_BUTTONRELEASE:
4336 case EVENT_MOTIONNOTIFY:
4338 if (event.type == EVENT_MOTIONNOTIFY)
4340 if (!PointerInWindow(window))
4341 continue; /* window and pointer are on different screens */
4346 motion_status = TRUE;
4347 mx = ((MotionEvent *) &event)->x;
4348 my = ((MotionEvent *) &event)->y;
4352 motion_status = FALSE;
4353 mx = ((ButtonEvent *) &event)->x;
4354 my = ((ButtonEvent *) &event)->y;
4355 if (event.type == EVENT_BUTTONPRESS)
4356 button_status = ((ButtonEvent *) &event)->button;
4358 button_status = MB_RELEASED;
4361 /* this sets 'request_gadget_id' */
4362 HandleGadgets(mx, my, button_status);
4364 switch (request_gadget_id)
4366 case TOOL_CTRL_ID_YES:
4369 case TOOL_CTRL_ID_NO:
4372 case TOOL_CTRL_ID_CONFIRM:
4373 result = TRUE | FALSE;
4376 case TOOL_CTRL_ID_PLAYER_1:
4379 case TOOL_CTRL_ID_PLAYER_2:
4382 case TOOL_CTRL_ID_PLAYER_3:
4385 case TOOL_CTRL_ID_PLAYER_4:
4396 case EVENT_KEYPRESS:
4397 switch (GetEventKey((KeyEvent *)&event, TRUE))
4400 if (req_state & REQ_CONFIRM)
4409 #if defined(TARGET_SDL2)
4419 if (req_state & REQ_PLAYER)
4423 case EVENT_KEYRELEASE:
4424 ClearPlayerAction();
4428 HandleOtherEvents(&event);
4432 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
4434 int joy = AnyJoystick();
4436 if (joy & JOY_BUTTON_1)
4438 else if (joy & JOY_BUTTON_2)
4444 if (game_status == GAME_MODE_PLAYING && local_player->LevelSolved_GameEnd)
4446 HandleGameActions();
4452 if (!PendingEvent()) /* delay only if no pending events */
4457 game_status = GAME_MODE_PSEUDO_DOOR;
4463 game_status = last_game_status; /* restore current game status */
4471 if (!PendingEvent()) /* delay only if no pending events */
4474 /* don't eat all CPU time */
4484 static boolean RequestDoor(char *text, unsigned int req_state)
4486 unsigned int old_door_state;
4487 int last_game_status = game_status; /* save current game status */
4488 int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
4489 int font_nr = FONT_TEXT_2;
4494 if (maxWordLengthInString(text) > MAX_REQUEST_LINE_FONT1_LEN)
4496 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
4497 font_nr = FONT_TEXT_1;
4500 if (game_status == GAME_MODE_PLAYING)
4502 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
4503 BlitScreenToBitmap_EM(backbuffer);
4504 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
4505 BlitScreenToBitmap_SP(backbuffer);
4508 /* disable deactivated drawing when quick-loading level tape recording */
4509 if (tape.playing && tape.deactivate_display)
4510 TapeDeactivateDisplayOff(TRUE);
4512 SetMouseCursor(CURSOR_DEFAULT);
4514 #if defined(NETWORK_AVALIABLE)
4515 /* pause network game while waiting for request to answer */
4516 if (options.network &&
4517 game_status == GAME_MODE_PLAYING &&
4518 req_state & REQUEST_WAIT_FOR_INPUT)
4519 SendToServer_PausePlaying();
4522 old_door_state = GetDoorState();
4524 /* simulate releasing mouse button over last gadget, if still pressed */
4526 HandleGadgets(-1, -1, 0);
4530 /* draw released gadget before proceeding */
4533 if (old_door_state & DOOR_OPEN_1)
4535 CloseDoor(DOOR_CLOSE_1);
4537 /* save old door content */
4538 BlitBitmap(bitmap_db_door, bitmap_db_door,
4539 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
4540 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
4543 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
4544 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
4546 /* clear door drawing field */
4547 DrawBackground(DX, DY, DXSIZE, DYSIZE);
4549 /* force DOOR font inside door area */
4550 game_status = GAME_MODE_PSEUDO_DOOR;
4552 /* write text for request */
4553 for (text_ptr = text, ty = 0; ty < MAX_REQUEST_LINES; ty++)
4555 char text_line[max_request_line_len + 1];
4561 for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
4563 tc = *(text_ptr + tx);
4564 // if (!tc || tc == ' ')
4565 if (!tc || tc == ' ' || tc == '?' || tc == '!')
4569 if ((tc == '?' || tc == '!') && tl == 0)
4579 strncpy(text_line, text_ptr, tl);
4582 DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
4583 DY + 8 + ty * (getFontHeight(font_nr) + 2),
4584 text_line, font_nr);
4586 text_ptr += tl + (tc == ' ' ? 1 : 0);
4587 // text_ptr += tl + (tc == ' ' || tc == '?' || tc == '!' ? 1 : 0);
4590 game_status = last_game_status; /* restore current game status */
4592 if (req_state & REQ_ASK)
4594 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
4595 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
4597 else if (req_state & REQ_CONFIRM)
4599 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
4601 else if (req_state & REQ_PLAYER)
4603 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
4604 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
4605 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
4606 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
4609 /* copy request gadgets to door backbuffer */
4610 BlitBitmap(drawto, bitmap_db_door,
4611 DX, DY, DXSIZE, DYSIZE,
4612 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
4614 OpenDoor(DOOR_OPEN_1);
4616 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
4618 if (game_status == GAME_MODE_PLAYING)
4620 SetPanelBackground();
4621 SetDrawBackgroundMask(REDRAW_DOOR_1);
4625 SetDrawBackgroundMask(REDRAW_FIELD);
4631 if (game_status != GAME_MODE_MAIN)
4634 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
4636 // ---------- handle request buttons ----------
4637 result = RequestHandleEvents(req_state);
4639 if (game_status != GAME_MODE_MAIN)
4644 if (!(req_state & REQ_STAY_OPEN))
4646 CloseDoor(DOOR_CLOSE_1);
4648 if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
4649 (req_state & REQ_REOPEN))
4650 OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
4655 if (game_status == GAME_MODE_PLAYING)
4657 SetPanelBackground();
4658 SetDrawBackgroundMask(REDRAW_DOOR_1);
4662 SetDrawBackgroundMask(REDRAW_FIELD);
4665 #if defined(NETWORK_AVALIABLE)
4666 /* continue network game after request */
4667 if (options.network &&
4668 game_status == GAME_MODE_PLAYING &&
4669 req_state & REQUEST_WAIT_FOR_INPUT)
4670 SendToServer_ContinuePlaying();
4673 /* restore deactivated drawing when quick-loading level tape recording */
4674 if (tape.playing && tape.deactivate_display)
4675 TapeDeactivateDisplayOn();
4680 static boolean RequestEnvelope(char *text, unsigned int req_state)
4687 if (game_status == GAME_MODE_PLAYING)
4689 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
4690 BlitScreenToBitmap_EM(backbuffer);
4691 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
4692 BlitScreenToBitmap_SP(backbuffer);
4695 /* disable deactivated drawing when quick-loading level tape recording */
4696 if (tape.playing && tape.deactivate_display)
4697 TapeDeactivateDisplayOff(TRUE);
4699 SetMouseCursor(CURSOR_DEFAULT);
4701 #if defined(NETWORK_AVALIABLE)
4702 /* pause network game while waiting for request to answer */
4703 if (options.network &&
4704 game_status == GAME_MODE_PLAYING &&
4705 req_state & REQUEST_WAIT_FOR_INPUT)
4706 SendToServer_PausePlaying();
4709 /* simulate releasing mouse button over last gadget, if still pressed */
4711 HandleGadgets(-1, -1, 0);
4715 // (replace with setting corresponding request background)
4716 // SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
4717 // SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
4719 /* clear door drawing field */
4720 // DrawBackground(DX, DY, DXSIZE, DYSIZE);
4723 if (global.use_envelope_request)
4727 CreateToolButtons();
4733 if (req_state & REQ_ASK)
4735 MapGadgetExt(tool_gadget[TOOL_CTRL_ID_YES], FALSE);
4736 MapGadgetExt(tool_gadget[TOOL_CTRL_ID_NO], FALSE);
4738 else if (req_state & REQ_CONFIRM)
4740 MapGadgetExt(tool_gadget[TOOL_CTRL_ID_CONFIRM], FALSE);
4742 else if (req_state & REQ_PLAYER)
4744 MapGadgetExt(tool_gadget[TOOL_CTRL_ID_PLAYER_1], FALSE);
4745 MapGadgetExt(tool_gadget[TOOL_CTRL_ID_PLAYER_2], FALSE);
4746 MapGadgetExt(tool_gadget[TOOL_CTRL_ID_PLAYER_3], FALSE);
4747 MapGadgetExt(tool_gadget[TOOL_CTRL_ID_PLAYER_4], FALSE);
4750 if (req_state & REQ_ASK)
4752 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
4753 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
4755 else if (req_state & REQ_CONFIRM)
4757 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
4759 else if (req_state & REQ_PLAYER)
4761 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
4762 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
4763 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
4764 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
4769 ShowEnvelopeRequest(text, req_state, ACTION_OPENING);
4772 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4774 if ((req_state & REQ_ASK && (i == TOOL_CTRL_ID_YES ||
4775 i == TOOL_CTRL_ID_NO)) ||
4776 (req_state & REQ_CONFIRM && i == TOOL_CTRL_ID_CONFIRM) ||
4777 (req_state & REQ_PLAYER && (i == TOOL_CTRL_ID_PLAYER_1 &&
4778 i == TOOL_CTRL_ID_PLAYER_2 &&
4779 i == TOOL_CTRL_ID_PLAYER_3 &&
4780 i == TOOL_CTRL_ID_PLAYER_4)))
4782 int x = tool_gadget[i]->x + dDX;
4783 int y = tool_gadget[i]->y + dDY;
4785 ModifyGadget(tool_gadget[i], GDI_X, x, GDI_Y, y, GDI_END);
4790 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
4792 if (game_status == GAME_MODE_PLAYING)
4794 SetPanelBackground();
4795 SetDrawBackgroundMask(REDRAW_DOOR_1);
4799 SetDrawBackgroundMask(REDRAW_FIELD);
4806 if (game_status != GAME_MODE_MAIN)
4810 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
4812 // ---------- handle request buttons ----------
4813 result = RequestHandleEvents(req_state);
4815 if (game_status != GAME_MODE_MAIN)
4820 ShowEnvelopeRequest(text, req_state, ACTION_CLOSING);
4824 if (game_status == GAME_MODE_PLAYING)
4826 SetPanelBackground();
4827 SetDrawBackgroundMask(REDRAW_DOOR_1);
4831 SetDrawBackgroundMask(REDRAW_FIELD);
4834 #if defined(NETWORK_AVALIABLE)
4835 /* continue network game after request */
4836 if (options.network &&
4837 game_status == GAME_MODE_PLAYING &&
4838 req_state & REQUEST_WAIT_FOR_INPUT)
4839 SendToServer_ContinuePlaying();
4842 /* restore deactivated drawing when quick-loading level tape recording */
4843 if (tape.playing && tape.deactivate_display)
4844 TapeDeactivateDisplayOn();
4849 boolean Request(char *text, unsigned int req_state)
4851 if (global.use_envelope_request)
4852 return RequestEnvelope(text, req_state);
4854 return RequestDoor(text, req_state);
4857 #else // =====================================================================
4859 boolean Request(char *text, unsigned int req_state)
4861 int mx, my, ty, result = -1;
4862 unsigned int old_door_state;
4863 int last_game_status = game_status; /* save current game status */
4864 int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
4865 int font_nr = FONT_TEXT_2;
4867 int max_word_len = 0;
4873 global.use_envelope_request = 1;
4877 if (maxWordLengthInString(text) > MAX_REQUEST_LINE_FONT1_LEN)
4879 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
4880 font_nr = FONT_TEXT_1;
4883 for (text_ptr = text; *text_ptr; text_ptr++)
4885 max_word_len = (*text_ptr != ' ' ? max_word_len + 1 : 0);
4887 if (max_word_len > MAX_REQUEST_LINE_FONT1_LEN)
4889 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
4891 font_nr = FONT_TEXT_1;
4893 font_nr = FONT_LEVEL_NUMBER;
4901 if (game_status == GAME_MODE_PLAYING)
4903 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
4904 BlitScreenToBitmap_EM(backbuffer);
4905 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
4906 BlitScreenToBitmap_SP(backbuffer);
4909 /* disable deactivated drawing when quick-loading level tape recording */
4910 if (tape.playing && tape.deactivate_display)
4911 TapeDeactivateDisplayOff(TRUE);
4913 SetMouseCursor(CURSOR_DEFAULT);
4915 #if defined(NETWORK_AVALIABLE)
4916 /* pause network game while waiting for request to answer */
4917 if (options.network &&
4918 game_status == GAME_MODE_PLAYING &&
4919 req_state & REQUEST_WAIT_FOR_INPUT)
4920 SendToServer_PausePlaying();
4923 old_door_state = GetDoorState();
4925 /* simulate releasing mouse button over last gadget, if still pressed */
4927 HandleGadgets(-1, -1, 0);
4931 /* draw released gadget before proceeding */
4935 if (old_door_state & DOOR_OPEN_1 && !global.use_envelope_request)
4937 if (old_door_state & DOOR_OPEN_1)
4941 if (!global.use_envelope_request)
4942 CloseDoor(DOOR_CLOSE_1);
4944 CloseDoor(DOOR_CLOSE_1);
4947 /* save old door content */
4948 BlitBitmap(bitmap_db_door, bitmap_db_door,
4949 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
4950 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
4954 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
4957 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
4959 /* clear door drawing field */
4960 DrawBackground(DX, DY, DXSIZE, DYSIZE);
4962 /* force DOOR font inside door area */
4963 game_status = GAME_MODE_PSEUDO_DOOR;
4965 /* write text for request */
4966 for (text_ptr = text, ty = 0; ty < MAX_REQUEST_LINES; ty++)
4968 char text_line[max_request_line_len + 1];
4974 for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
4976 tc = *(text_ptr + tx);
4977 if (!tc || tc == ' ')
4988 strncpy(text_line, text_ptr, tl);
4991 DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
4992 DY + 8 + ty * (getFontHeight(font_nr) + 2),
4993 text_line, font_nr);
4995 text_ptr += tl + (tc == ' ' ? 1 : 0);
4998 game_status = last_game_status; /* restore current game status */
5001 if (global.use_envelope_request)
5005 CreateToolButtons();
5009 if (req_state & REQ_ASK)
5011 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
5012 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
5014 else if (req_state & REQ_CONFIRM)
5016 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
5018 else if (req_state & REQ_PLAYER)
5020 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
5021 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
5022 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
5023 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
5026 /* copy request gadgets to door backbuffer */
5027 BlitBitmap(drawto, bitmap_db_door,
5028 DX, DY, DXSIZE, DYSIZE,
5029 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
5032 if (global.use_envelope_request)
5034 ShowEnvelopeRequest(text, ACTION_OPENING);
5036 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
5038 if ((req_state & REQ_ASK && (i == TOOL_CTRL_ID_YES ||
5039 i == TOOL_CTRL_ID_NO)) ||
5040 (req_state & REQ_CONFIRM && i == TOOL_CTRL_ID_CONFIRM) ||
5041 (req_state & REQ_PLAYER && (i == TOOL_CTRL_ID_PLAYER_1 &&
5042 i == TOOL_CTRL_ID_PLAYER_2 &&
5043 i == TOOL_CTRL_ID_PLAYER_3 &&
5044 i == TOOL_CTRL_ID_PLAYER_4)))
5046 int x = tool_gadget[i]->x + dDX;
5047 int y = tool_gadget[i]->y + dDY;
5049 ModifyGadget(tool_gadget[i], GDI_X, x, GDI_Y, y, GDI_END);
5056 if (!global.use_envelope_request)
5057 OpenDoor(DOOR_OPEN_1);
5059 OpenDoor(DOOR_OPEN_1);
5062 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
5064 if (game_status == GAME_MODE_PLAYING)
5066 SetPanelBackground();
5067 SetDrawBackgroundMask(REDRAW_DOOR_1);
5071 SetDrawBackgroundMask(REDRAW_FIELD);
5078 if (game_status != GAME_MODE_MAIN && !global.use_envelope_request)
5081 if (game_status != GAME_MODE_MAIN)
5085 button_status = MB_RELEASED;
5087 request_gadget_id = -1;
5089 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
5101 case EVENT_BUTTONPRESS:
5102 case EVENT_BUTTONRELEASE:
5103 case EVENT_MOTIONNOTIFY:
5105 if (event.type == EVENT_MOTIONNOTIFY)
5107 if (!PointerInWindow(window))
5108 continue; /* window and pointer are on different screens */
5113 motion_status = TRUE;
5114 mx = ((MotionEvent *) &event)->x;
5115 my = ((MotionEvent *) &event)->y;
5119 motion_status = FALSE;
5120 mx = ((ButtonEvent *) &event)->x;
5121 my = ((ButtonEvent *) &event)->y;
5122 if (event.type == EVENT_BUTTONPRESS)
5123 button_status = ((ButtonEvent *) &event)->button;
5125 button_status = MB_RELEASED;
5128 /* this sets 'request_gadget_id' */
5129 HandleGadgets(mx, my, button_status);
5131 switch (request_gadget_id)
5133 case TOOL_CTRL_ID_YES:
5136 case TOOL_CTRL_ID_NO:
5139 case TOOL_CTRL_ID_CONFIRM:
5140 result = TRUE | FALSE;
5143 case TOOL_CTRL_ID_PLAYER_1:
5146 case TOOL_CTRL_ID_PLAYER_2:
5149 case TOOL_CTRL_ID_PLAYER_3:
5152 case TOOL_CTRL_ID_PLAYER_4:
5163 case EVENT_KEYPRESS:
5164 switch (GetEventKey((KeyEvent *)&event, TRUE))
5167 if (req_state & REQ_CONFIRM)
5176 #if defined(TARGET_SDL2)
5186 if (req_state & REQ_PLAYER)
5190 case EVENT_KEYRELEASE:
5191 ClearPlayerAction();
5195 HandleOtherEvents(&event);
5199 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
5201 int joy = AnyJoystick();
5203 if (joy & JOY_BUTTON_1)
5205 else if (joy & JOY_BUTTON_2)
5211 if (game_status == GAME_MODE_PLAYING && local_player->LevelSolved_GameEnd)
5213 HandleGameActions();
5219 if (!PendingEvent()) /* delay only if no pending events */
5224 game_status = GAME_MODE_PSEUDO_DOOR;
5230 game_status = last_game_status; /* restore current game status */
5238 if (!PendingEvent()) /* delay only if no pending events */
5241 /* don't eat all CPU time */
5248 if (game_status != GAME_MODE_MAIN)
5254 if (global.use_envelope_request)
5255 ShowEnvelopeRequest(text, ACTION_CLOSING);
5259 if (!(req_state & REQ_STAY_OPEN) && !global.use_envelope_request)
5261 if (!(req_state & REQ_STAY_OPEN))
5264 CloseDoor(DOOR_CLOSE_1);
5266 if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
5267 (req_state & REQ_REOPEN))
5268 OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
5273 if (game_status == GAME_MODE_PLAYING)
5275 SetPanelBackground();
5276 SetDrawBackgroundMask(REDRAW_DOOR_1);
5280 SetDrawBackgroundMask(REDRAW_FIELD);
5283 #if defined(NETWORK_AVALIABLE)
5284 /* continue network game after request */
5285 if (options.network &&
5286 game_status == GAME_MODE_PLAYING &&
5287 req_state & REQUEST_WAIT_FOR_INPUT)
5288 SendToServer_ContinuePlaying();
5291 /* restore deactivated drawing when quick-loading level tape recording */
5292 if (tape.playing && tape.deactivate_display)
5293 TapeDeactivateDisplayOn();
5300 static int compareDoorPartOrderInfo(const void *object1, const void *object2)
5302 const struct DoorPartOrderInfo *dpo1 = (struct DoorPartOrderInfo *)object1;
5303 const struct DoorPartOrderInfo *dpo2 = (struct DoorPartOrderInfo *)object2;
5306 if (dpo1->sort_priority != dpo2->sort_priority)
5307 compare_result = dpo1->sort_priority - dpo2->sort_priority;
5309 compare_result = dpo1->nr - dpo2->nr;
5311 return compare_result;
5318 for (i = 0; door_part_controls[i].door_nr != -1; i++)
5320 struct DoorPartControlInfo *dpc = &door_part_controls[i];
5321 struct DoorPartOrderInfo *dpo = &door_part_order[i];
5323 /* fill structure for door part draw order */
5325 dpo->sort_priority = dpc->pos->sort_priority;
5328 struct DoorPartPosInfo *pos = dpc->pos;
5330 printf(":0: step_xoffset == %d, step_yoffset == %d\n",
5331 pos->step_xoffset, pos->step_yoffset);
5335 /* sort door part controls according to sort_priority and graphic number */
5336 qsort(door_part_order, MAX_DOOR_PARTS,
5337 sizeof(struct DoorPartOrderInfo), compareDoorPartOrderInfo);
5340 unsigned int OpenDoor(unsigned int door_state)
5342 if (door_state & DOOR_COPY_BACK)
5344 if (door_state & DOOR_OPEN_1)
5345 BlitBitmap(bitmap_db_door, bitmap_db_door,
5346 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
5347 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
5349 if (door_state & DOOR_OPEN_2)
5350 BlitBitmap(bitmap_db_door, bitmap_db_door,
5351 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY2, VXSIZE, VYSIZE,
5352 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
5354 door_state &= ~DOOR_COPY_BACK;
5357 return MoveDoor(door_state);
5360 unsigned int CloseDoor(unsigned int door_state)
5362 unsigned int old_door_state = GetDoorState();
5364 if (!(door_state & DOOR_NO_COPY_BACK))
5366 if (old_door_state & DOOR_OPEN_1)
5367 BlitBitmap(backbuffer, bitmap_db_door,
5368 DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
5370 if (old_door_state & DOOR_OPEN_2)
5371 BlitBitmap(backbuffer, bitmap_db_door,
5372 VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
5374 door_state &= ~DOOR_NO_COPY_BACK;
5377 return MoveDoor(door_state);
5380 unsigned int GetDoorState()
5382 return MoveDoor(DOOR_GET_STATE);
5385 unsigned int SetDoorState(unsigned int door_state)
5387 return MoveDoor(door_state | DOOR_SET_STATE);
5392 // ========== TEST 1 ===========================================================
5394 int euclid(int a, int b)
5396 return (b ? euclid(b, a % b) : a);
5399 unsigned int MoveDoor(unsigned int door_state)
5401 struct XY panel_pos_list[] =
5403 { DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 },
5404 { DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 },
5406 struct Rect door_rect_list[] =
5408 { DX, DY, DXSIZE, DYSIZE },
5409 { VX, VY, VXSIZE, VYSIZE }
5411 static int door1 = DOOR_OPEN_1;
5412 static int door2 = DOOR_CLOSE_2;
5413 unsigned int door_delay = 0;
5414 unsigned int door_delay_value;
5418 if (door_1.width < 0 || door_1.width > DXSIZE)
5419 door_1.width = DXSIZE;
5420 if (door_1.height < 0 || door_1.height > DYSIZE)
5421 door_1.height = DYSIZE;
5422 if (door_2.width < 0 || door_2.width > VXSIZE)
5423 door_2.width = VXSIZE;
5424 if (door_2.height < 0 || door_2.height > VYSIZE)
5425 door_2.height = VYSIZE;
5428 if (door_state == DOOR_GET_STATE)
5429 return (door1 | door2);
5431 if (door_state & DOOR_SET_STATE)
5433 if (door_state & DOOR_ACTION_1)
5434 door1 = door_state & DOOR_ACTION_1;
5435 if (door_state & DOOR_ACTION_2)
5436 door2 = door_state & DOOR_ACTION_2;
5438 return (door1 | door2);
5441 if (!(door_state & DOOR_FORCE_REDRAW))
5443 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
5444 door_state &= ~DOOR_OPEN_1;
5445 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
5446 door_state &= ~DOOR_CLOSE_1;
5447 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
5448 door_state &= ~DOOR_OPEN_2;
5449 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
5450 door_state &= ~DOOR_CLOSE_2;
5454 door_delay_value = (door_state & DOOR_ACTION_1 ? door_1.step_delay :
5457 if (setup.quick_doors)
5459 stepsize = 20; /* must be chosen to always draw last frame */
5460 door_delay_value = 0;
5464 if (global.autoplay_leveldir)
5466 door_state |= DOOR_NO_DELAY;
5467 door_state &= ~DOOR_CLOSE_ALL;
5471 if (game_status == GAME_MODE_EDITOR)
5472 door_state |= DOOR_NO_DELAY;
5475 if (door_state & DOOR_ACTION)
5477 boolean door_panel_drawn[NUM_DOORS];
5478 boolean door_part_done[MAX_DOOR_PARTS];
5479 boolean door_part_done_all;
5480 int num_steps[MAX_DOOR_PARTS];
5481 int max_move_delay = 0; // delay for complete animations of all doors
5482 int max_step_delay = 0; // delay (ms) between two animation frames
5483 int num_move_steps = 0; // number of animation steps for all doors
5484 int current_move_delay = 0;
5487 for (i = 0; i < MAX_DOOR_PARTS; i++)
5489 int nr = door_part_order[i].nr;
5490 struct DoorPartControlInfo *dpc = &door_part_controls[nr];
5491 struct GraphicInfo *g = &graphic_info[dpc->graphic];
5492 int door_token = dpc->door_nr;
5494 door_part_done[nr] = (!(door_state & door_token) ||
5498 for (i = 0; i < MAX_DOOR_PARTS; i++)
5500 struct DoorPartControlInfo *dpc = &door_part_controls[i];
5501 struct GraphicInfo *g = &graphic_info[dpc->graphic];
5502 struct DoorPartPosInfo *pos = dpc->pos;
5503 int step_xoffset = ABS(pos->step_xoffset);
5504 int step_yoffset = ABS(pos->step_yoffset);
5505 int step_delay = pos->step_delay;
5506 float move_xsize = (step_xoffset ? g->width : 0);
5507 float move_ysize = (step_yoffset ? g->height : 0);
5508 int move_xsteps = (step_xoffset ? ceil(move_xsize / step_xoffset) : 0);
5509 int move_ysteps = (step_yoffset ? ceil(move_ysize / step_yoffset) : 0);
5510 int move_steps = (move_xsteps && move_ysteps ?
5511 MIN(move_xsteps, move_ysteps) :
5512 move_xsteps ? move_xsteps : move_ysteps);
5513 int move_delay = move_steps * step_delay;
5515 max_move_delay = MAX(max_move_delay, move_delay);
5516 max_step_delay = (max_step_delay == 0 ? step_delay :
5517 euclid(max_step_delay, step_delay));
5518 num_steps[i] = (move_xsteps && move_ysteps ?
5519 MIN(move_xsteps, move_ysteps) :
5520 move_xsteps ? move_xsteps : move_ysteps);
5523 num_move_steps = max_move_delay / max_step_delay;
5525 door_delay_value = max_step_delay;
5528 door_delay_value *= 10;
5531 for (k = 0; k < num_move_steps; k++)
5533 for (i = 0; i < NUM_DOORS; i++)
5534 door_panel_drawn[i] = FALSE;
5536 for (i = 0; i < MAX_DOOR_PARTS; i++)
5538 int nr = door_part_order[i].nr;
5539 struct DoorPartControlInfo *dpc = &door_part_controls[nr];
5540 int door_token = dpc->door_nr;
5541 int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
5542 struct GraphicInfo *g = &graphic_info[dpc->graphic];
5543 struct DoorPartPosInfo *pos = dpc->pos;
5544 struct XY *panel_pos = &panel_pos_list[door_index];
5545 struct Rect *door_rect = &door_rect_list[door_index];
5546 int current_door_state = door_state & door_token;
5547 boolean door_opening = ((current_door_state & DOOR_OPEN) != 0);
5548 boolean door_closing = ((current_door_state & DOOR_CLOSE) != 0);
5549 int step_delay = pos->step_delay;
5550 int step_factor = step_delay / max_step_delay;
5551 int k1 = (step_factor ? k / step_factor + 1 : k);
5552 int kk = (door_opening ? k1 : num_steps[nr] - k1);
5563 if (door_part_done[nr])
5566 if (!(door_state & door_token))
5572 if (current_move_delay % step_delay)
5577 if (!door_panel_drawn[door_index])
5579 BlitBitmap(bitmap_db_door, drawto, panel_pos->x, panel_pos->y,
5580 door_rect->width, door_rect->height,
5581 door_rect->x, door_rect->y);
5583 door_panel_drawn[door_index] = TRUE;
5586 // draw opening or closing door parts
5588 if (pos->step_xoffset < 0) // door part on right side
5591 dst_xx = pos->x + ABS(kk * pos->step_xoffset);
5594 if (dst_xx + width > door_rect->width)
5595 width = door_rect->width - dst_xx;
5597 else // door part on left side
5600 dst_xx = pos->x - kk * pos->step_xoffset;
5604 src_xx = ABS(dst_xx);
5608 width = g->width - src_xx;
5611 if (pos->step_yoffset < 0) // door part on bottom side
5614 dst_yy = pos->y + ABS(kk * pos->step_yoffset);
5617 if (dst_yy + height > door_rect->height)
5618 height = door_rect->height - dst_yy;
5620 else // door part on top side
5623 dst_yy = pos->y - kk * pos->step_yoffset;
5627 src_yy = ABS(dst_yy);
5631 height = g->height - src_yy;
5634 if (width >= 0 && width <= g->width &&
5635 height >= 0 && height <= g->height)
5636 BlitBitmapMasked(g->bitmap, drawto,
5637 g->src_x + src_xx, g->src_y + src_yy, width, height,
5638 door_rect->x + dst_xx, door_rect->y + dst_yy);
5640 redraw_mask |= REDRAW_DOOR_FROM_TOKEN(door_token);
5642 if ((door_opening && (width < 0 || height < 0)) ||
5643 (door_closing && (width >= g->width && height >= g->height)))
5644 door_part_done[nr] = TRUE;
5647 if (!(door_state & DOOR_NO_DELAY))
5651 if (game_status == GAME_MODE_MAIN)
5654 WaitUntilDelayReached(&door_delay, door_delay_value);
5656 current_move_delay += max_step_delay;
5659 door_part_done_all = TRUE;
5661 for (i = 0; i < MAX_DOOR_PARTS; i++)
5662 if (!door_part_done[i])
5663 door_part_done_all = FALSE;
5665 if (door_part_done_all)
5670 if (door_state & DOOR_ACTION_1)
5671 door1 = door_state & DOOR_ACTION_1;
5672 if (door_state & DOOR_ACTION_2)
5673 door2 = door_state & DOOR_ACTION_2;
5675 return (door1 | door2);
5680 // ========== OLD ==============================================================
5682 unsigned int MoveDoor(unsigned int door_state)
5684 static int door1 = DOOR_OPEN_1;
5685 static int door2 = DOOR_CLOSE_2;
5686 unsigned int door_delay = 0;
5687 unsigned int door_delay_value;
5691 if (door_1.width < 0 || door_1.width > DXSIZE)
5692 door_1.width = DXSIZE;
5693 if (door_1.height < 0 || door_1.height > DYSIZE)
5694 door_1.height = DYSIZE;
5695 if (door_2.width < 0 || door_2.width > VXSIZE)
5696 door_2.width = VXSIZE;
5697 if (door_2.height < 0 || door_2.height > VYSIZE)
5698 door_2.height = VYSIZE;
5701 if (door_state == DOOR_GET_STATE)
5702 return (door1 | door2);
5704 if (door_state & DOOR_SET_STATE)
5706 if (door_state & DOOR_ACTION_1)
5707 door1 = door_state & DOOR_ACTION_1;
5708 if (door_state & DOOR_ACTION_2)
5709 door2 = door_state & DOOR_ACTION_2;
5711 return (door1 | door2);
5714 if (!(door_state & DOOR_FORCE_REDRAW))
5716 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
5717 door_state &= ~DOOR_OPEN_1;
5718 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
5719 door_state &= ~DOOR_CLOSE_1;
5720 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
5721 door_state &= ~DOOR_OPEN_2;
5722 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
5723 door_state &= ~DOOR_CLOSE_2;
5726 door_delay_value = (door_state & DOOR_ACTION_1 ? door_1.step_delay :
5729 // door_delay_value *= 4; // !!! TEST ONLY !!!
5731 if (setup.quick_doors)
5733 stepsize = 20; /* must be chosen to always draw last frame */
5734 door_delay_value = 0;
5737 if (global.autoplay_leveldir)
5739 door_state |= DOOR_NO_DELAY;
5740 door_state &= ~DOOR_CLOSE_ALL;
5744 if (game_status == GAME_MODE_EDITOR)
5745 door_state |= DOOR_NO_DELAY;
5748 if (door_state & DOOR_ACTION)
5751 struct GraphicInfo *g1_left = &graphic_info[IMG_DOOR_1_WING_LEFT];
5752 struct GraphicInfo *g1_right = &graphic_info[IMG_DOOR_1_WING_RIGHT];
5753 struct GraphicInfo *g2_left = &graphic_info[IMG_DOOR_2_WING_LEFT];
5754 struct GraphicInfo *g2_right = &graphic_info[IMG_DOOR_2_WING_RIGHT];
5755 int door_1_left_width = g1_left->width;
5756 int door_1_left_height = g1_left->height;
5757 int door_1_right_width = g1_right->width;
5758 int door_1_right_height = g1_right->height;
5759 int door_2_left_width = g2_left->width;
5760 int door_2_left_height = g2_left->height;
5761 int door_2_right_width = g2_right->width;
5762 int door_2_right_height = g2_right->height;
5763 int door_1_width = MAX(door_1_left_width, door_1_right_width);
5764 int door_1_height = MAX(door_1_left_height, door_1_right_height);
5765 int door_2_width = MAX(door_2_left_width, door_2_right_width);
5766 int door_2_height = MAX(door_2_left_height, door_2_right_height);
5768 boolean handle_door_1 = (door_state & DOOR_ACTION_1);
5769 boolean handle_door_2 = (door_state & DOOR_ACTION_2);
5770 boolean door_1_done = (!handle_door_1);
5771 boolean door_2_done = (!handle_door_2);
5772 boolean door_1_vertical = (door_1.anim_mode & ANIM_VERTICAL);
5773 boolean door_2_vertical = (door_2.anim_mode & ANIM_VERTICAL);
5776 int door_size_1 = (door_1_vertical ? door_1_height : door_1_width);
5777 int door_size_2 = (door_2_vertical ? door_2_height : door_2_width);
5779 int door_size_1 = (door_1_vertical ? DYSIZE : DXSIZE);
5780 int door_size_2 = (door_2_vertical ? VYSIZE : VXSIZE);
5783 int door_size_1 = (door_1_vertical ? door_1.height : door_1.width);
5784 int door_size_2 = (door_2_vertical ? door_2.height : door_2.width);
5786 int max_door_size_1 = (door_1_vertical ? DYSIZE : DXSIZE);
5787 int max_door_size_2 = (door_2_vertical ? VYSIZE : VXSIZE);
5788 // int door_size = (handle_door_1 ? door_size_1 : door_size_2);
5789 int door_size = (handle_door_2 ? door_size_2 : door_size_1);
5790 int max_door_size = (handle_door_1 ? max_door_size_1 : max_door_size_2);
5791 int door_skip = max_door_size - door_size;
5792 int end = door_size;
5793 int start = ((door_state & DOOR_NO_DELAY) ? end : 0);
5796 if (!(door_state & DOOR_NO_DELAY) && !setup.quick_doors)
5798 /* opening door sound has priority over simultaneously closing door */
5799 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
5800 PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
5801 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
5802 PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
5805 for (k = start; k <= end && !(door_1_done && door_2_done); k += stepsize)
5809 Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
5810 GC gc = bitmap->stored_clip_gc;
5813 if (door_state & DOOR_ACTION_1 &&
5814 x * door_1.step_offset <= door_size_1)
5816 int a = MIN(x * door_1.step_offset, end);
5817 int p = (door_state & DOOR_OPEN_1 ? end - a : a);
5821 int i = p + door_skip;
5825 struct GraphicInfo *g_left = &graphic_info[IMG_DOOR_1_WING_LEFT];
5826 struct GraphicInfo *g_right = &graphic_info[IMG_DOOR_1_WING_RIGHT];
5827 Bitmap *bm_left = g_left->bitmap;
5828 Bitmap *bm_right = g_right->bitmap;
5829 GC gc_left = bm_left->stored_clip_gc;
5830 GC gc_right = bm_right->stored_clip_gc;
5833 int classic_dxsize = 100;
5834 int classic_dysize = 280;
5835 boolean classic_door_1_size = (DXSIZE == classic_dxsize &&
5836 DYSIZE == classic_dysize);
5838 if (door_1.anim_mode & ANIM_STATIC_PANEL)
5840 BlitBitmap(bitmap_db_door, drawto,
5841 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1,
5842 DXSIZE, DYSIZE, DX, DY);
5846 BlitBitmap(bitmap_db_door, drawto,
5847 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + p / 2,
5848 DXSIZE, DYSIZE - p / 2, DX, DY);
5851 // printf("::: p == %d\n", p);
5852 ClearRectangle(drawto, DX, DY + DYSIZE - p / 2, DXSIZE, p / 2);
5856 if (door_1.anim_mode & ANIM_HORIZONTAL && x <= DXSIZE)
5859 int src1_x = g_right->src_x;
5860 int src1_y = g_right->src_y;
5861 int src2_x = g_left->src_x + g_left->width - i;
5862 int src2_y = g_left->src_y;
5863 int dst1_x = DX + DXSIZE - i;
5868 int height = DYSIZE;
5870 SetClipOrigin(bm_right, gc_right, dst1_x - src1_x, dst1_y - src1_y);
5871 BlitBitmapMasked(bm_right, drawto, src1_x, src1_y, width, height,
5874 SetClipOrigin(bm_left, gc_left, dst2_x - src2_x, dst2_y - src2_y);
5875 BlitBitmapMasked(bm_left, drawto, src2_x, src2_y, width, height,
5878 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
5879 int src2_x = DXSIZE - i, src2_y = DOOR_GFX_PAGEY1;
5880 int dst1_x = DX + DXSIZE - i, dst1_y = DY;
5881 int dst2_x = DX, dst2_y = DY;
5882 int width = i, height = DYSIZE;
5884 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
5885 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
5888 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
5889 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
5893 else if (door_1.anim_mode & ANIM_VERTICAL && x <= DYSIZE)
5896 int src1_x = g_right->src_x;
5897 int src1_y = g_right->src_y;
5898 int src2_x = g_left->src_x;
5899 int src2_y = g_left->src_y + g_left->height - i;
5901 int dst1_y = DY + DYSIZE - i;
5907 SetClipOrigin(bm_right, gc_right, dst1_x - src1_x, dst1_y - src1_y);
5908 BlitBitmapMasked(bm_right, drawto, src1_x, src1_y, width, height,
5911 SetClipOrigin(bm_left, gc_left, dst2_x - src2_x, dst2_y - src2_y);
5912 BlitBitmapMasked(bm_left, drawto, src2_x, src2_y, width, height,
5915 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
5916 int src2_x = 0, src2_y = DOOR_GFX_PAGEY1 + DYSIZE - i;
5917 int dst1_x = DX, dst1_y = DY + DYSIZE - i;
5918 int dst2_x = DX, dst2_y = DY;
5919 int width = DXSIZE, height = i;
5921 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
5922 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
5925 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
5926 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
5930 else if (classic_door_1_size && x <= DXSIZE) /* ANIM_DEFAULT */
5932 int j = (door_1.anim_mode == ANIM_DEFAULT ? (DXSIZE - i) / 3 : 0);
5935 int src1_x = g_right->src_x;
5936 int src1_y = g_right->src_y;
5937 int src2_x = g_left->src_x + g_left->width - i;
5938 int src2_y = g_left->src_y;
5939 int dst1_x = DX + DXSIZE - i;
5944 int height1 = 63, height2 = DYSIZE / 2 - height1;
5945 int ypos1 = 0, ypos2 = height2;
5946 int ypos3 = DYSIZE / 2, ypos4 = DYSIZE - height2;
5948 SetClipOrigin(bm_right, gc_right,
5949 dst1_x - src1_x, dst1_y - src1_y + j);
5950 BlitBitmapMasked(bm_right, drawto,
5951 src1_x, src1_y + ypos1, width, height2,
5952 dst1_x, dst1_y + ypos1 + j);
5953 BlitBitmapMasked(bm_right, drawto,
5954 src1_x, src1_y + ypos3, width, height1,
5955 dst1_x, dst1_y + ypos3 + j);
5956 SetClipOrigin(bm_left, gc_left,
5957 dst2_x - src2_x, dst2_y - src2_y - j);
5958 BlitBitmapMasked(bm_left, drawto,
5959 src2_x, src2_y + ypos1 + j, width, height2 - j,
5960 dst2_x, dst2_y + ypos1);
5961 BlitBitmapMasked(bm_left, drawto,
5962 src2_x, src2_y + ypos3, width, height1,
5963 dst2_x, dst2_y + ypos3 - j);
5965 SetClipOrigin(bm_left, gc_left,
5966 dst2_x - src2_x, dst2_y - src2_y - j);
5967 BlitBitmapMasked(bm_left, drawto,
5968 src2_x, src2_y + ypos2, width, height1,
5969 dst2_x, dst2_y + ypos2 - j);
5970 BlitBitmapMasked(bm_left, drawto,
5971 src2_x, src2_y + ypos4, width, height2,
5972 dst2_x, dst2_y + ypos4 - j);
5973 SetClipOrigin(bm_right, gc_right,
5974 dst1_x - src1_x, dst1_y - src1_y + j);
5975 BlitBitmapMasked(bm_right, drawto,
5976 src1_x, src1_y + ypos2, width, height1,
5977 dst1_x, dst1_y + ypos2 + j);
5978 BlitBitmapMasked(bm_right, drawto,
5979 src1_x, src1_y + ypos4, width, height2 - j,
5980 dst1_x, dst1_y + ypos4 + j);
5983 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
5984 int src2_x = DXSIZE - i, src2_y = DOOR_GFX_PAGEY1;
5985 int dst1_x = DX + DXSIZE - i, dst1_y = DY;
5986 int dst2_x = DX, dst2_y = DY;
5987 int width = i, height = DYSIZE;
5988 int ypos1 = 63, ypos2 = 77, ypos3 = 140, ypos4 = 203;
5990 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y + j);
5991 BlitBitmapMasked(bitmap, drawto,
5992 src1_x, src1_y, width, ypos2,
5993 dst1_x, dst1_y + j);
5994 BlitBitmapMasked(bitmap, drawto,
5995 src1_x, src1_y + ypos3, width, ypos1,
5996 dst1_x, dst1_y + ypos3 + j);
5997 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y - j);
5998 BlitBitmapMasked(bitmap, drawto,
5999 src2_x, src2_y + j, width, ypos2 - j,
6001 BlitBitmapMasked(bitmap, drawto,
6002 src2_x, src2_y + ypos3, width, ypos1,
6003 dst2_x, dst2_y + ypos3 - j);
6005 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y - j);
6006 BlitBitmapMasked(bitmap, drawto,
6007 src2_x, src2_y + ypos2, width, ypos1,
6008 dst2_x, dst2_y + ypos2 - j);
6009 BlitBitmapMasked(bitmap, drawto,
6010 src2_x, src2_y + ypos4, width, ypos2,
6011 dst2_x, dst2_y + ypos4 - j);
6012 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y + j);
6013 BlitBitmapMasked(bitmap, drawto,
6014 src1_x, src1_y + ypos2, width, ypos1,
6015 dst1_x, dst1_y + ypos2 + j);
6016 BlitBitmapMasked(bitmap, drawto,
6017 src1_x, src1_y + ypos4, width, ypos2 - j,
6018 dst1_x, dst1_y + ypos4 + j);
6021 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
6022 BlitBitmapMasked(bitmap, drawto,
6023 DXSIZE, DOOR_GFX_PAGEY1, i, 77,
6024 DX + DXSIZE - i, DY + j);
6025 BlitBitmapMasked(bitmap, drawto,
6026 DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
6027 DX + DXSIZE - i, DY + 140 + j);
6028 SetClipOrigin(bitmap, gc, DX - DXSIZE + i,
6029 DY - (DOOR_GFX_PAGEY1 + j));
6030 BlitBitmapMasked(bitmap, drawto,
6031 DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
6033 BlitBitmapMasked(bitmap, drawto,
6034 DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
6037 BlitBitmapMasked(bitmap, drawto,
6038 DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
6040 BlitBitmapMasked(bitmap, drawto,
6041 DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
6043 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
6044 BlitBitmapMasked(bitmap, drawto,
6045 DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
6046 DX + DXSIZE - i, DY + 77 + j);
6047 BlitBitmapMasked(bitmap, drawto,
6048 DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
6049 DX + DXSIZE - i, DY + 203 + j);
6054 redraw_mask |= REDRAW_DOOR_1;
6055 door_1_done = (a == end);
6058 if (door_state & DOOR_ACTION_2 &&
6059 x * door_2.step_offset <= door_size_2)
6061 int a = MIN(x * door_2.step_offset, door_size);
6062 int p = (door_state & DOOR_OPEN_2 ? door_size - a : a);
6063 int i = p + door_skip;
6066 struct GraphicInfo *g_left = &graphic_info[IMG_DOOR_2_WING_LEFT];
6067 struct GraphicInfo *g_right = &graphic_info[IMG_DOOR_2_WING_RIGHT];
6068 Bitmap *bm_left = g_left->bitmap;
6069 Bitmap *bm_right = g_right->bitmap;
6070 GC gc_left = bm_left->stored_clip_gc;
6071 GC gc_right = bm_right->stored_clip_gc;
6074 int classic_vxsize = 100;
6075 int classic_vysize = 100;
6076 boolean classic_door_2_size = (VXSIZE == classic_vxsize &&
6077 VYSIZE == classic_vysize);
6079 if (door_2.anim_mode & ANIM_STATIC_PANEL)
6081 BlitBitmap(bitmap_db_door, drawto,
6082 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2,
6083 VXSIZE, VYSIZE, VX, VY);
6085 else if (x <= VYSIZE)
6087 BlitBitmap(bitmap_db_door, drawto,
6088 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + p / 2,
6089 VXSIZE, VYSIZE - p / 2, VX, VY);
6091 ClearRectangle(drawto, VX, VY + VYSIZE - p / 2, VXSIZE, p / 2);
6094 if (door_2.anim_mode & ANIM_HORIZONTAL && x <= VXSIZE)
6097 int src1_x = g_right->src_x;
6098 int src1_y = g_right->src_y;
6099 int src2_x = g_left->src_x + g_left->width - i;
6100 int src2_y = g_left->src_y;
6101 int dst1_x = VX + VXSIZE - i;
6106 int height = VYSIZE;
6108 SetClipOrigin(bm_right, gc_right, dst1_x - src1_x, dst1_y - src1_y);
6109 BlitBitmapMasked(bm_right, drawto, src1_x, src1_y, width, height,
6112 SetClipOrigin(bm_left, gc_left, dst2_x - src2_x, dst2_y - src2_y);
6113 BlitBitmapMasked(bm_left, drawto, src2_x, src2_y, width, height,
6116 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
6117 int src2_x = VXSIZE - i, src2_y = DOOR_GFX_PAGEY2;
6118 int dst1_x = VX + VXSIZE - i, dst1_y = VY;
6119 int dst2_x = VX, dst2_y = VY;
6120 int width = i, height = VYSIZE;
6122 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
6123 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
6126 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
6127 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
6131 else if (door_2.anim_mode & ANIM_VERTICAL && x <= VYSIZE)
6134 int src1_x = g_right->src_x;
6135 int src1_y = g_right->src_y;
6136 int src2_x = g_left->src_x;
6137 int src2_y = g_left->src_y + g_left->height - i;
6139 int dst1_y = VY + VYSIZE - i;
6145 SetClipOrigin(bm_right, gc_right, dst1_x - src1_x, dst1_y - src1_y);
6146 BlitBitmapMasked(bm_right, drawto, src1_x, src1_y, width, height,
6149 SetClipOrigin(bm_left, gc_left, dst2_x - src2_x, dst2_y - src2_y);
6150 BlitBitmapMasked(bm_left, drawto, src2_x, src2_y, width, height,
6153 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
6154 int src2_x = 0, src2_y = DOOR_GFX_PAGEY2 + VYSIZE - i;
6155 int dst1_x = VX, dst1_y = VY + VYSIZE - i;
6156 int dst2_x = VX, dst2_y = VY;
6157 int width = VXSIZE, height = i;
6159 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
6160 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
6163 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
6164 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
6168 else if (classic_door_2_size && x <= VXSIZE) /* ANIM_DEFAULT */
6170 int j = (door_2.anim_mode == ANIM_DEFAULT ? (VXSIZE - i) / 3 : 0);
6173 int src1_x = g_right->src_x;
6174 int src1_y = g_right->src_y;
6175 int src2_x = g_left->src_x + g_left->width - i;
6176 int src2_y = g_left->src_y;
6177 int dst1_x = VX + VXSIZE - i;
6182 int height = VYSIZE / 2;
6183 int ypos1 = 0, ypos2 = VYSIZE / 2;
6185 SetClipOrigin(bm_right, gc_right,
6186 dst1_x - src1_x, dst1_y - src1_y + j);
6187 BlitBitmapMasked(bm_right, drawto,
6188 src1_x, src1_y + ypos1, width, height,
6189 dst1_x, dst1_y + ypos1 + j);
6190 SetClipOrigin(bm_left, gc_left,
6191 dst2_x - src2_x, dst2_y - src2_y - j);
6192 BlitBitmapMasked(bm_left, drawto,
6193 src2_x, src2_y + ypos1 + j, width, height - j,
6194 dst2_x, dst2_y + ypos1);
6196 SetClipOrigin(bm_left, gc_left,
6197 dst2_x - src2_x, dst2_y - src2_y - j);
6198 BlitBitmapMasked(bm_left, drawto,
6199 src2_x, src2_y + ypos2, width, height,
6200 dst2_x, dst2_y + ypos2 - j);
6201 SetClipOrigin(bm_right, gc_right,
6202 dst1_x - src1_x, dst1_y - src1_y + j);
6203 BlitBitmapMasked(bm_right, drawto,
6204 src1_x, src1_y + ypos2, width, height - j,
6205 dst1_x, dst1_y + ypos2 + j);
6207 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
6208 int src2_x = VXSIZE - i, src2_y = DOOR_GFX_PAGEY2;
6209 int dst1_x = VX + VXSIZE - i, dst1_y = VY;
6210 int dst2_x = VX, dst2_y = VY;
6211 int width = i, height = VYSIZE;
6212 int ypos = VYSIZE / 2;
6214 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y + j);
6215 BlitBitmapMasked(bitmap, drawto,
6216 src1_x, src1_y, width, ypos,
6217 dst1_x, dst1_y + j);
6218 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src1_y - j);
6219 BlitBitmapMasked(bitmap, drawto,
6220 src2_x, src2_y + j, width, ypos - j,
6223 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src1_y - j);
6224 BlitBitmapMasked(bitmap, drawto,
6225 src2_x, src2_y + ypos, width, ypos,
6226 dst2_x, dst2_y + ypos - j);
6227 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y + j);
6228 BlitBitmapMasked(bitmap, drawto,
6229 src1_x, src1_y + ypos, width, ypos - j,
6230 dst1_x, dst1_y + ypos + j);
6233 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
6234 BlitBitmapMasked(bitmap, drawto,
6235 VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
6236 VX + VXSIZE - i, VY + j);
6237 SetClipOrigin(bitmap, gc,
6238 VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
6239 BlitBitmapMasked(bitmap, drawto,
6240 VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
6243 BlitBitmapMasked(bitmap, drawto,
6244 VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
6245 i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
6246 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
6247 BlitBitmapMasked(bitmap, drawto,
6248 VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
6250 VX + VXSIZE - i, VY + VYSIZE / 2 + j);
6255 redraw_mask |= REDRAW_DOOR_2;
6256 door_2_done = (a == VXSIZE);
6259 if (!(door_state & DOOR_NO_DELAY))
6263 if (game_status == GAME_MODE_MAIN)
6266 WaitUntilDelayReached(&door_delay, door_delay_value);
6271 if (door_state & DOOR_ACTION_1)
6272 door1 = door_state & DOOR_ACTION_1;
6273 if (door_state & DOOR_ACTION_2)
6274 door2 = door_state & DOOR_ACTION_2;
6276 return (door1 | door2);
6281 void DrawSpecialEditorDoor()
6284 struct GraphicInfo *gfx1 = &graphic_info[IMG_DOOR_2_TOP_BORDER_CORRECTION];
6285 int top_border_width = gfx1->width;
6286 int top_border_height = gfx1->height;
6287 int outer_border = viewport.door_2[GAME_MODE_EDITOR].border_size;
6288 int ex = EX - outer_border;
6289 int ey = EY - outer_border;
6290 int vy = VY - outer_border;
6291 int exsize = EXSIZE + 2 * outer_border;
6293 CloseDoor(DOOR_CLOSE_2);
6295 /* draw bigger level editor toolbox window */
6296 BlitBitmap(gfx1->bitmap, drawto, gfx1->src_x, gfx1->src_y,
6297 top_border_width, top_border_height, ex, ey - top_border_height);
6298 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto, ex, vy,
6299 exsize, EYSIZE - VYSIZE + outer_border, ex, ey);
6301 /* draw bigger level editor toolbox window */
6302 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
6303 DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
6305 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
6306 EX - 6, VY - 4, EXSIZE + 12, EYSIZE - VYSIZE + 4,
6310 redraw_mask |= REDRAW_ALL;
6313 void UndrawSpecialEditorDoor()
6316 struct GraphicInfo *gfx1 = &graphic_info[IMG_DOOR_2_TOP_BORDER_CORRECTION];
6317 int top_border_width = gfx1->width;
6318 int top_border_height = gfx1->height;
6319 int outer_border = viewport.door_2[GAME_MODE_EDITOR].border_size;
6320 int ex = EX - outer_border;
6321 int ey = EY - outer_border;
6322 int ey_top = ey - top_border_height;
6323 int exsize = EXSIZE + 2 * outer_border;
6324 int eysize = EYSIZE + 2 * outer_border;
6326 /* draw normal tape recorder window */
6327 if (graphic_info[IMG_GLOBAL_BORDER].bitmap)
6329 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
6330 ex, ey_top, top_border_width, top_border_height,
6332 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
6333 ex, ey, exsize, eysize, ex, ey);
6337 // if screen background is set to "[NONE]", clear editor toolbox window
6338 ClearRectangle(drawto, ex, ey_top, top_border_width, top_border_height);
6339 ClearRectangle(drawto, ex, ey, exsize, eysize);
6342 /* draw normal tape recorder window */
6343 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
6344 EX - 6, EY - 12, EXSIZE + 12, EYSIZE - VYSIZE + 12,
6348 redraw_mask |= REDRAW_ALL;
6352 /* ---------- new tool button stuff ---------------------------------------- */
6359 struct TextPosInfo *pos;
6362 } toolbutton_info[NUM_TOOL_BUTTONS] =
6365 IMG_REQUEST_BUTTON_GFX_YES, &request.button.yes,
6366 TOOL_CTRL_ID_YES, "yes"
6369 IMG_REQUEST_BUTTON_GFX_NO, &request.button.no,
6370 TOOL_CTRL_ID_NO, "no"
6373 IMG_REQUEST_BUTTON_GFX_CONFIRM, &request.button.confirm,
6374 TOOL_CTRL_ID_CONFIRM, "confirm"
6377 IMG_REQUEST_BUTTON_GFX_PLAYER_1, &request.button.player_1,
6378 TOOL_CTRL_ID_PLAYER_1, "player 1"
6381 IMG_REQUEST_BUTTON_GFX_PLAYER_2, &request.button.player_2,
6382 TOOL_CTRL_ID_PLAYER_2, "player 2"
6385 IMG_REQUEST_BUTTON_GFX_PLAYER_3, &request.button.player_3,
6386 TOOL_CTRL_ID_PLAYER_3, "player 3"
6389 IMG_REQUEST_BUTTON_GFX_PLAYER_4, &request.button.player_4,
6390 TOOL_CTRL_ID_PLAYER_4, "player 4"
6394 void CreateToolButtons()
6398 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
6400 struct GraphicInfo *gfx = &graphic_info[toolbutton_info[i].graphic];
6401 struct TextPosInfo *pos = toolbutton_info[i].pos;
6402 struct GadgetInfo *gi;
6403 Bitmap *deco_bitmap = None;
6404 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
6405 unsigned int event_mask = GD_EVENT_RELEASED;
6408 int gd_x = gfx->src_x;
6409 int gd_y = gfx->src_y;
6410 int gd_xp = gfx->src_x + gfx->pressed_xoffset;
6411 int gd_yp = gfx->src_y + gfx->pressed_yoffset;
6414 if (global.use_envelope_request)
6415 setRequestPosition(&dx, &dy, TRUE);
6417 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
6419 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
6421 getSizedGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr), 0,
6422 pos->size, &deco_bitmap, &deco_x, &deco_y);
6423 deco_xpos = (gfx->width - pos->size) / 2;
6424 deco_ypos = (gfx->height - pos->size) / 2;
6427 gi = CreateGadget(GDI_CUSTOM_ID, id,
6428 GDI_INFO_TEXT, toolbutton_info[i].infotext,
6431 GDI_WIDTH, gfx->width,
6432 GDI_HEIGHT, gfx->height,
6433 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
6434 GDI_STATE, GD_BUTTON_UNPRESSED,
6435 GDI_DESIGN_UNPRESSED, gfx->bitmap, gd_x, gd_y,
6436 GDI_DESIGN_PRESSED, gfx->bitmap, gd_xp, gd_yp,
6437 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
6438 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
6439 GDI_DECORATION_SIZE, pos->size, pos->size,
6440 GDI_DECORATION_SHIFTING, 1, 1,
6441 GDI_DIRECT_DRAW, FALSE,
6442 GDI_EVENT_MASK, event_mask,
6443 GDI_CALLBACK_ACTION, HandleToolButtons,
6447 Error(ERR_EXIT, "cannot create gadget");
6449 tool_gadget[id] = gi;
6455 /* graphic position values for tool buttons */
6456 #define TOOL_BUTTON_YES_XPOS 2
6457 #define TOOL_BUTTON_YES_YPOS 250
6458 #define TOOL_BUTTON_YES_GFX_YPOS 0
6459 #define TOOL_BUTTON_YES_XSIZE 46
6460 #define TOOL_BUTTON_YES_YSIZE 28
6461 #define TOOL_BUTTON_NO_XPOS 52
6462 #define TOOL_BUTTON_NO_YPOS TOOL_BUTTON_YES_YPOS
6463 #define TOOL_BUTTON_NO_GFX_YPOS TOOL_BUTTON_YES_GFX_YPOS
6464 #define TOOL_BUTTON_NO_XSIZE TOOL_BUTTON_YES_XSIZE
6465 #define TOOL_BUTTON_NO_YSIZE TOOL_BUTTON_YES_YSIZE
6466 #define TOOL_BUTTON_CONFIRM_XPOS TOOL_BUTTON_YES_XPOS
6467 #define TOOL_BUTTON_CONFIRM_YPOS TOOL_BUTTON_YES_YPOS
6468 #define TOOL_BUTTON_CONFIRM_GFX_YPOS 30
6469 #define TOOL_BUTTON_CONFIRM_XSIZE 96
6470 #define TOOL_BUTTON_CONFIRM_YSIZE TOOL_BUTTON_YES_YSIZE
6471 #define TOOL_BUTTON_PLAYER_XSIZE 30
6472 #define TOOL_BUTTON_PLAYER_YSIZE 30
6473 #define TOOL_BUTTON_PLAYER_GFX_XPOS 5
6474 #define TOOL_BUTTON_PLAYER_GFX_YPOS 185
6475 #define TOOL_BUTTON_PLAYER_XPOS (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
6476 #define TOOL_BUTTON_PLAYER_YPOS (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
6477 #define TOOL_BUTTON_PLAYER1_XPOS (TOOL_BUTTON_PLAYER_XPOS \
6478 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
6479 #define TOOL_BUTTON_PLAYER2_XPOS (TOOL_BUTTON_PLAYER_XPOS \
6480 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
6481 #define TOOL_BUTTON_PLAYER3_XPOS (TOOL_BUTTON_PLAYER_XPOS \
6482 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
6483 #define TOOL_BUTTON_PLAYER4_XPOS (TOOL_BUTTON_PLAYER_XPOS \
6484 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
6485 #define TOOL_BUTTON_PLAYER1_YPOS (TOOL_BUTTON_PLAYER_YPOS \
6486 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
6487 #define TOOL_BUTTON_PLAYER2_YPOS (TOOL_BUTTON_PLAYER_YPOS \
6488 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
6489 #define TOOL_BUTTON_PLAYER3_YPOS (TOOL_BUTTON_PLAYER_YPOS \
6490 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
6491 #define TOOL_BUTTON_PLAYER4_YPOS (TOOL_BUTTON_PLAYER_YPOS \
6492 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
6501 } toolbutton_info[NUM_TOOL_BUTTONS] =
6504 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_GFX_YPOS,
6505 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_YPOS,
6506 TOOL_BUTTON_YES_XSIZE, TOOL_BUTTON_YES_YSIZE,
6511 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_GFX_YPOS,
6512 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_YPOS,
6513 TOOL_BUTTON_NO_XSIZE, TOOL_BUTTON_NO_YSIZE,
6518 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_GFX_YPOS,
6519 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_YPOS,
6520 TOOL_BUTTON_CONFIRM_XSIZE, TOOL_BUTTON_CONFIRM_YSIZE,
6521 TOOL_CTRL_ID_CONFIRM,
6525 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
6526 TOOL_BUTTON_PLAYER1_XPOS, TOOL_BUTTON_PLAYER1_YPOS,
6527 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
6528 TOOL_CTRL_ID_PLAYER_1,
6532 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
6533 TOOL_BUTTON_PLAYER2_XPOS, TOOL_BUTTON_PLAYER2_YPOS,
6534 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
6535 TOOL_CTRL_ID_PLAYER_2,
6539 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
6540 TOOL_BUTTON_PLAYER3_XPOS, TOOL_BUTTON_PLAYER3_YPOS,
6541 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
6542 TOOL_CTRL_ID_PLAYER_3,
6546 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
6547 TOOL_BUTTON_PLAYER4_XPOS, TOOL_BUTTON_PLAYER4_YPOS,
6548 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
6549 TOOL_CTRL_ID_PLAYER_4,
6554 void CreateToolButtons()
6558 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
6560 Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
6561 Bitmap *deco_bitmap = None;
6562 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
6563 struct GadgetInfo *gi;
6564 unsigned int event_mask;
6565 int gd_xoffset, gd_yoffset;
6566 int gd_x1, gd_x2, gd_y;
6569 event_mask = GD_EVENT_RELEASED;
6571 gd_xoffset = toolbutton_info[i].xpos;
6572 gd_yoffset = toolbutton_info[i].ypos;
6573 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
6574 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
6575 gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
6577 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
6579 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
6581 getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr),
6582 &deco_bitmap, &deco_x, &deco_y);
6583 deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
6584 deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
6587 gi = CreateGadget(GDI_CUSTOM_ID, id,
6588 GDI_INFO_TEXT, toolbutton_info[i].infotext,
6589 GDI_X, DX + toolbutton_info[i].x,
6590 GDI_Y, DY + toolbutton_info[i].y,
6591 GDI_WIDTH, toolbutton_info[i].width,
6592 GDI_HEIGHT, toolbutton_info[i].height,
6593 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
6594 GDI_STATE, GD_BUTTON_UNPRESSED,
6595 GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
6596 GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
6597 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
6598 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
6599 GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
6600 GDI_DECORATION_SHIFTING, 1, 1,
6601 GDI_DIRECT_DRAW, FALSE,
6602 GDI_EVENT_MASK, event_mask,
6603 GDI_CALLBACK_ACTION, HandleToolButtons,
6607 Error(ERR_EXIT, "cannot create gadget");
6609 tool_gadget[id] = gi;
6615 void FreeToolButtons()
6619 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
6620 FreeGadget(tool_gadget[i]);
6623 static void UnmapToolButtons()
6627 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
6628 UnmapGadget(tool_gadget[i]);
6631 static void HandleToolButtons(struct GadgetInfo *gi)
6633 request_gadget_id = gi->custom_id;
6636 static struct Mapping_EM_to_RND_object
6639 boolean is_rnd_to_em_mapping; /* unique mapping EM <-> RND */
6640 boolean is_backside; /* backside of moving element */
6646 em_object_mapping_list[] =
6649 Xblank, TRUE, FALSE,
6653 Yacid_splash_eB, FALSE, FALSE,
6654 EL_ACID_SPLASH_RIGHT, -1, -1
6657 Yacid_splash_wB, FALSE, FALSE,
6658 EL_ACID_SPLASH_LEFT, -1, -1
6661 #ifdef EM_ENGINE_BAD_ROLL
6663 Xstone_force_e, FALSE, FALSE,
6664 EL_ROCK, -1, MV_BIT_RIGHT
6667 Xstone_force_w, FALSE, FALSE,
6668 EL_ROCK, -1, MV_BIT_LEFT
6671 Xnut_force_e, FALSE, FALSE,
6672 EL_NUT, -1, MV_BIT_RIGHT
6675 Xnut_force_w, FALSE, FALSE,
6676 EL_NUT, -1, MV_BIT_LEFT
6679 Xspring_force_e, FALSE, FALSE,
6680 EL_SPRING, -1, MV_BIT_RIGHT
6683 Xspring_force_w, FALSE, FALSE,
6684 EL_SPRING, -1, MV_BIT_LEFT
6687 Xemerald_force_e, FALSE, FALSE,
6688 EL_EMERALD, -1, MV_BIT_RIGHT
6691 Xemerald_force_w, FALSE, FALSE,
6692 EL_EMERALD, -1, MV_BIT_LEFT
6695 Xdiamond_force_e, FALSE, FALSE,
6696 EL_DIAMOND, -1, MV_BIT_RIGHT
6699 Xdiamond_force_w, FALSE, FALSE,
6700 EL_DIAMOND, -1, MV_BIT_LEFT
6703 Xbomb_force_e, FALSE, FALSE,
6704 EL_BOMB, -1, MV_BIT_RIGHT
6707 Xbomb_force_w, FALSE, FALSE,
6708 EL_BOMB, -1, MV_BIT_LEFT
6710 #endif /* EM_ENGINE_BAD_ROLL */
6713 Xstone, TRUE, FALSE,
6717 Xstone_pause, FALSE, FALSE,
6721 Xstone_fall, FALSE, FALSE,
6725 Ystone_s, FALSE, FALSE,
6726 EL_ROCK, ACTION_FALLING, -1
6729 Ystone_sB, FALSE, TRUE,
6730 EL_ROCK, ACTION_FALLING, -1
6733 Ystone_e, FALSE, FALSE,
6734 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
6737 Ystone_eB, FALSE, TRUE,
6738 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
6741 Ystone_w, FALSE, FALSE,
6742 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
6745 Ystone_wB, FALSE, TRUE,
6746 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
6753 Xnut_pause, FALSE, FALSE,
6757 Xnut_fall, FALSE, FALSE,
6761 Ynut_s, FALSE, FALSE,
6762 EL_NUT, ACTION_FALLING, -1
6765 Ynut_sB, FALSE, TRUE,
6766 EL_NUT, ACTION_FALLING, -1
6769 Ynut_e, FALSE, FALSE,
6770 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
6773 Ynut_eB, FALSE, TRUE,
6774 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
6777 Ynut_w, FALSE, FALSE,
6778 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
6781 Ynut_wB, FALSE, TRUE,
6782 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
6785 Xbug_n, TRUE, FALSE,
6789 Xbug_e, TRUE, FALSE,
6790 EL_BUG_RIGHT, -1, -1
6793 Xbug_s, TRUE, FALSE,
6797 Xbug_w, TRUE, FALSE,
6801 Xbug_gon, FALSE, FALSE,
6805 Xbug_goe, FALSE, FALSE,
6806 EL_BUG_RIGHT, -1, -1
6809 Xbug_gos, FALSE, FALSE,
6813 Xbug_gow, FALSE, FALSE,
6817 Ybug_n, FALSE, FALSE,
6818 EL_BUG, ACTION_MOVING, MV_BIT_UP
6821 Ybug_nB, FALSE, TRUE,
6822 EL_BUG, ACTION_MOVING, MV_BIT_UP
6825 Ybug_e, FALSE, FALSE,
6826 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
6829 Ybug_eB, FALSE, TRUE,
6830 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
6833 Ybug_s, FALSE, FALSE,
6834 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
6837 Ybug_sB, FALSE, TRUE,
6838 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
6841 Ybug_w, FALSE, FALSE,
6842 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
6845 Ybug_wB, FALSE, TRUE,
6846 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
6849 Ybug_w_n, FALSE, FALSE,
6850 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
6853 Ybug_n_e, FALSE, FALSE,
6854 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
6857 Ybug_e_s, FALSE, FALSE,
6858 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
6861 Ybug_s_w, FALSE, FALSE,
6862 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
6865 Ybug_e_n, FALSE, FALSE,
6866 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
6869 Ybug_s_e, FALSE, FALSE,
6870 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
6873 Ybug_w_s, FALSE, FALSE,
6874 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
6877 Ybug_n_w, FALSE, FALSE,
6878 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
6881 Ybug_stone, FALSE, FALSE,
6882 EL_BUG, ACTION_SMASHED_BY_ROCK, -1
6885 Ybug_spring, FALSE, FALSE,
6886 EL_BUG, ACTION_SMASHED_BY_SPRING, -1
6889 Xtank_n, TRUE, FALSE,
6890 EL_SPACESHIP_UP, -1, -1
6893 Xtank_e, TRUE, FALSE,
6894 EL_SPACESHIP_RIGHT, -1, -1
6897 Xtank_s, TRUE, FALSE,
6898 EL_SPACESHIP_DOWN, -1, -1
6901 Xtank_w, TRUE, FALSE,
6902 EL_SPACESHIP_LEFT, -1, -1
6905 Xtank_gon, FALSE, FALSE,
6906 EL_SPACESHIP_UP, -1, -1
6909 Xtank_goe, FALSE, FALSE,
6910 EL_SPACESHIP_RIGHT, -1, -1
6913 Xtank_gos, FALSE, FALSE,
6914 EL_SPACESHIP_DOWN, -1, -1
6917 Xtank_gow, FALSE, FALSE,
6918 EL_SPACESHIP_LEFT, -1, -1
6921 Ytank_n, FALSE, FALSE,
6922 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
6925 Ytank_nB, FALSE, TRUE,
6926 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
6929 Ytank_e, FALSE, FALSE,
6930 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
6933 Ytank_eB, FALSE, TRUE,
6934 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
6937 Ytank_s, FALSE, FALSE,
6938 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
6941 Ytank_sB, FALSE, TRUE,
6942 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
6945 Ytank_w, FALSE, FALSE,
6946 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
6949 Ytank_wB, FALSE, TRUE,
6950 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
6953 Ytank_w_n, FALSE, FALSE,
6954 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
6957 Ytank_n_e, FALSE, FALSE,
6958 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
6961 Ytank_e_s, FALSE, FALSE,
6962 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
6965 Ytank_s_w, FALSE, FALSE,
6966 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
6969 Ytank_e_n, FALSE, FALSE,
6970 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
6973 Ytank_s_e, FALSE, FALSE,
6974 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
6977 Ytank_w_s, FALSE, FALSE,
6978 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
6981 Ytank_n_w, FALSE, FALSE,
6982 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
6985 Ytank_stone, FALSE, FALSE,
6986 EL_SPACESHIP, ACTION_SMASHED_BY_ROCK, -1
6989 Ytank_spring, FALSE, FALSE,
6990 EL_SPACESHIP, ACTION_SMASHED_BY_SPRING, -1
6993 Xandroid, TRUE, FALSE,
6994 EL_EMC_ANDROID, ACTION_ACTIVE, -1
6997 Xandroid_1_n, FALSE, FALSE,
6998 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
7001 Xandroid_2_n, FALSE, FALSE,
7002 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
7005 Xandroid_1_e, FALSE, FALSE,
7006 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
7009 Xandroid_2_e, FALSE, FALSE,
7010 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
7013 Xandroid_1_w, FALSE, FALSE,
7014 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
7017 Xandroid_2_w, FALSE, FALSE,
7018 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
7021 Xandroid_1_s, FALSE, FALSE,
7022 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
7025 Xandroid_2_s, FALSE, FALSE,
7026 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
7029 Yandroid_n, FALSE, FALSE,
7030 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
7033 Yandroid_nB, FALSE, TRUE,
7034 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
7037 Yandroid_ne, FALSE, FALSE,
7038 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPRIGHT
7041 Yandroid_neB, FALSE, TRUE,
7042 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPRIGHT
7045 Yandroid_e, FALSE, FALSE,
7046 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
7049 Yandroid_eB, FALSE, TRUE,
7050 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
7053 Yandroid_se, FALSE, FALSE,
7054 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNRIGHT
7057 Yandroid_seB, FALSE, TRUE,
7058 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNRIGHT
7061 Yandroid_s, FALSE, FALSE,
7062 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
7065 Yandroid_sB, FALSE, TRUE,
7066 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
7069 Yandroid_sw, FALSE, FALSE,
7070 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNLEFT
7073 Yandroid_swB, FALSE, TRUE,
7074 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNLEFT
7077 Yandroid_w, FALSE, FALSE,
7078 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
7081 Yandroid_wB, FALSE, TRUE,
7082 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
7085 Yandroid_nw, FALSE, FALSE,
7086 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPLEFT
7089 Yandroid_nwB, FALSE, TRUE,
7090 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPLEFT
7093 Xspring, TRUE, FALSE,
7097 Xspring_pause, FALSE, FALSE,
7101 Xspring_e, FALSE, FALSE,
7105 Xspring_w, FALSE, FALSE,
7109 Xspring_fall, FALSE, FALSE,
7113 Yspring_s, FALSE, FALSE,
7114 EL_SPRING, ACTION_FALLING, -1
7117 Yspring_sB, FALSE, TRUE,
7118 EL_SPRING, ACTION_FALLING, -1
7121 Yspring_e, FALSE, FALSE,
7122 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
7125 Yspring_eB, FALSE, TRUE,
7126 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
7129 Yspring_w, FALSE, FALSE,
7130 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
7133 Yspring_wB, FALSE, TRUE,
7134 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
7137 Yspring_kill_e, FALSE, FALSE,
7138 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
7141 Yspring_kill_eB, FALSE, TRUE,
7142 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
7145 Yspring_kill_w, FALSE, FALSE,
7146 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
7149 Yspring_kill_wB, FALSE, TRUE,
7150 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
7153 Xeater_n, TRUE, FALSE,
7154 EL_YAMYAM_UP, -1, -1
7157 Xeater_e, TRUE, FALSE,
7158 EL_YAMYAM_RIGHT, -1, -1
7161 Xeater_w, TRUE, FALSE,
7162 EL_YAMYAM_LEFT, -1, -1
7165 Xeater_s, TRUE, FALSE,
7166 EL_YAMYAM_DOWN, -1, -1
7169 Yeater_n, FALSE, FALSE,
7170 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
7173 Yeater_nB, FALSE, TRUE,
7174 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
7177 Yeater_e, FALSE, FALSE,
7178 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
7181 Yeater_eB, FALSE, TRUE,
7182 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
7185 Yeater_s, FALSE, FALSE,
7186 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
7189 Yeater_sB, FALSE, TRUE,
7190 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
7193 Yeater_w, FALSE, FALSE,
7194 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
7197 Yeater_wB, FALSE, TRUE,
7198 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
7201 Yeater_stone, FALSE, FALSE,
7202 EL_YAMYAM, ACTION_SMASHED_BY_ROCK, -1
7205 Yeater_spring, FALSE, FALSE,
7206 EL_YAMYAM, ACTION_SMASHED_BY_SPRING, -1
7209 Xalien, TRUE, FALSE,
7213 Xalien_pause, FALSE, FALSE,
7217 Yalien_n, FALSE, FALSE,
7218 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
7221 Yalien_nB, FALSE, TRUE,
7222 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
7225 Yalien_e, FALSE, FALSE,
7226 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
7229 Yalien_eB, FALSE, TRUE,
7230 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
7233 Yalien_s, FALSE, FALSE,
7234 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
7237 Yalien_sB, FALSE, TRUE,
7238 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
7241 Yalien_w, FALSE, FALSE,
7242 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
7245 Yalien_wB, FALSE, TRUE,
7246 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
7249 Yalien_stone, FALSE, FALSE,
7250 EL_ROBOT, ACTION_SMASHED_BY_ROCK, -1
7253 Yalien_spring, FALSE, FALSE,
7254 EL_ROBOT, ACTION_SMASHED_BY_SPRING, -1
7257 Xemerald, TRUE, FALSE,
7261 Xemerald_pause, FALSE, FALSE,
7265 Xemerald_fall, FALSE, FALSE,
7269 Xemerald_shine, FALSE, FALSE,
7270 EL_EMERALD, ACTION_TWINKLING, -1
7273 Yemerald_s, FALSE, FALSE,
7274 EL_EMERALD, ACTION_FALLING, -1
7277 Yemerald_sB, FALSE, TRUE,
7278 EL_EMERALD, ACTION_FALLING, -1
7281 Yemerald_e, FALSE, FALSE,
7282 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
7285 Yemerald_eB, FALSE, TRUE,
7286 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
7289 Yemerald_w, FALSE, FALSE,
7290 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
7293 Yemerald_wB, FALSE, TRUE,
7294 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
7297 Yemerald_eat, FALSE, FALSE,
7298 EL_EMERALD, ACTION_COLLECTING, -1
7301 Yemerald_stone, FALSE, FALSE,
7302 EL_NUT, ACTION_BREAKING, -1
7305 Xdiamond, TRUE, FALSE,
7309 Xdiamond_pause, FALSE, FALSE,
7313 Xdiamond_fall, FALSE, FALSE,
7317 Xdiamond_shine, FALSE, FALSE,
7318 EL_DIAMOND, ACTION_TWINKLING, -1
7321 Ydiamond_s, FALSE, FALSE,
7322 EL_DIAMOND, ACTION_FALLING, -1
7325 Ydiamond_sB, FALSE, TRUE,
7326 EL_DIAMOND, ACTION_FALLING, -1
7329 Ydiamond_e, FALSE, FALSE,
7330 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
7333 Ydiamond_eB, FALSE, TRUE,
7334 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
7337 Ydiamond_w, FALSE, FALSE,
7338 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
7341 Ydiamond_wB, FALSE, TRUE,
7342 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
7345 Ydiamond_eat, FALSE, FALSE,
7346 EL_DIAMOND, ACTION_COLLECTING, -1
7349 Ydiamond_stone, FALSE, FALSE,
7350 EL_DIAMOND, ACTION_SMASHED_BY_ROCK, -1
7353 Xdrip_fall, TRUE, FALSE,
7354 EL_AMOEBA_DROP, -1, -1
7357 Xdrip_stretch, FALSE, FALSE,
7358 EL_AMOEBA_DROP, ACTION_FALLING, -1
7361 Xdrip_stretchB, FALSE, TRUE,
7362 EL_AMOEBA_DROP, ACTION_FALLING, -1
7365 Xdrip_eat, FALSE, FALSE,
7366 EL_AMOEBA_DROP, ACTION_GROWING, -1
7369 Ydrip_s1, FALSE, FALSE,
7370 EL_AMOEBA_DROP, ACTION_FALLING, -1
7373 Ydrip_s1B, FALSE, TRUE,
7374 EL_AMOEBA_DROP, ACTION_FALLING, -1
7377 Ydrip_s2, FALSE, FALSE,
7378 EL_AMOEBA_DROP, ACTION_FALLING, -1
7381 Ydrip_s2B, FALSE, TRUE,
7382 EL_AMOEBA_DROP, ACTION_FALLING, -1
7389 Xbomb_pause, FALSE, FALSE,
7393 Xbomb_fall, FALSE, FALSE,
7397 Ybomb_s, FALSE, FALSE,
7398 EL_BOMB, ACTION_FALLING, -1
7401 Ybomb_sB, FALSE, TRUE,
7402 EL_BOMB, ACTION_FALLING, -1
7405 Ybomb_e, FALSE, FALSE,
7406 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
7409 Ybomb_eB, FALSE, TRUE,
7410 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
7413 Ybomb_w, FALSE, FALSE,
7414 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
7417 Ybomb_wB, FALSE, TRUE,
7418 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
7421 Ybomb_eat, FALSE, FALSE,
7422 EL_BOMB, ACTION_ACTIVATING, -1
7425 Xballoon, TRUE, FALSE,
7429 Yballoon_n, FALSE, FALSE,
7430 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
7433 Yballoon_nB, FALSE, TRUE,
7434 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
7437 Yballoon_e, FALSE, FALSE,
7438 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
7441 Yballoon_eB, FALSE, TRUE,
7442 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
7445 Yballoon_s, FALSE, FALSE,
7446 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
7449 Yballoon_sB, FALSE, TRUE,
7450 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
7453 Yballoon_w, FALSE, FALSE,
7454 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
7457 Yballoon_wB, FALSE, TRUE,
7458 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
7461 Xgrass, TRUE, FALSE,
7462 EL_EMC_GRASS, -1, -1
7465 Ygrass_nB, FALSE, FALSE,
7466 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_UP
7469 Ygrass_eB, FALSE, FALSE,
7470 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_RIGHT
7473 Ygrass_sB, FALSE, FALSE,
7474 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_DOWN
7477 Ygrass_wB, FALSE, FALSE,
7478 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_LEFT
7485 Ydirt_nB, FALSE, FALSE,
7486 EL_SAND, ACTION_DIGGING, MV_BIT_UP
7489 Ydirt_eB, FALSE, FALSE,
7490 EL_SAND, ACTION_DIGGING, MV_BIT_RIGHT
7493 Ydirt_sB, FALSE, FALSE,
7494 EL_SAND, ACTION_DIGGING, MV_BIT_DOWN
7497 Ydirt_wB, FALSE, FALSE,
7498 EL_SAND, ACTION_DIGGING, MV_BIT_LEFT
7501 Xacid_ne, TRUE, FALSE,
7502 EL_ACID_POOL_TOPRIGHT, -1, -1
7505 Xacid_se, TRUE, FALSE,
7506 EL_ACID_POOL_BOTTOMRIGHT, -1, -1
7509 Xacid_s, TRUE, FALSE,
7510 EL_ACID_POOL_BOTTOM, -1, -1
7513 Xacid_sw, TRUE, FALSE,
7514 EL_ACID_POOL_BOTTOMLEFT, -1, -1
7517 Xacid_nw, TRUE, FALSE,
7518 EL_ACID_POOL_TOPLEFT, -1, -1
7521 Xacid_1, TRUE, FALSE,
7525 Xacid_2, FALSE, FALSE,
7529 Xacid_3, FALSE, FALSE,
7533 Xacid_4, FALSE, FALSE,
7537 Xacid_5, FALSE, FALSE,
7541 Xacid_6, FALSE, FALSE,
7545 Xacid_7, FALSE, FALSE,
7549 Xacid_8, FALSE, FALSE,
7553 Xball_1, TRUE, FALSE,
7554 EL_EMC_MAGIC_BALL, -1, -1
7557 Xball_1B, FALSE, FALSE,
7558 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
7561 Xball_2, FALSE, FALSE,
7562 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
7565 Xball_2B, FALSE, FALSE,
7566 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
7569 Yball_eat, FALSE, FALSE,
7570 EL_EMC_MAGIC_BALL, ACTION_DROPPING, -1
7573 Ykey_1_eat, FALSE, FALSE,
7574 EL_EM_KEY_1, ACTION_COLLECTING, -1
7577 Ykey_2_eat, FALSE, FALSE,
7578 EL_EM_KEY_2, ACTION_COLLECTING, -1
7581 Ykey_3_eat, FALSE, FALSE,
7582 EL_EM_KEY_3, ACTION_COLLECTING, -1
7585 Ykey_4_eat, FALSE, FALSE,
7586 EL_EM_KEY_4, ACTION_COLLECTING, -1
7589 Ykey_5_eat, FALSE, FALSE,
7590 EL_EMC_KEY_5, ACTION_COLLECTING, -1
7593 Ykey_6_eat, FALSE, FALSE,
7594 EL_EMC_KEY_6, ACTION_COLLECTING, -1
7597 Ykey_7_eat, FALSE, FALSE,
7598 EL_EMC_KEY_7, ACTION_COLLECTING, -1
7601 Ykey_8_eat, FALSE, FALSE,
7602 EL_EMC_KEY_8, ACTION_COLLECTING, -1
7605 Ylenses_eat, FALSE, FALSE,
7606 EL_EMC_LENSES, ACTION_COLLECTING, -1
7609 Ymagnify_eat, FALSE, FALSE,
7610 EL_EMC_MAGNIFIER, ACTION_COLLECTING, -1
7613 Ygrass_eat, FALSE, FALSE,
7614 EL_EMC_GRASS, ACTION_SNAPPING, -1
7617 Ydirt_eat, FALSE, FALSE,
7618 EL_SAND, ACTION_SNAPPING, -1
7621 Xgrow_ns, TRUE, FALSE,
7622 EL_EXPANDABLE_WALL_VERTICAL, -1, -1
7625 Ygrow_ns_eat, FALSE, FALSE,
7626 EL_EXPANDABLE_WALL_VERTICAL, ACTION_GROWING, -1
7629 Xgrow_ew, TRUE, FALSE,
7630 EL_EXPANDABLE_WALL_HORIZONTAL, -1, -1
7633 Ygrow_ew_eat, FALSE, FALSE,
7634 EL_EXPANDABLE_WALL_HORIZONTAL, ACTION_GROWING, -1
7637 Xwonderwall, TRUE, FALSE,
7638 EL_MAGIC_WALL, -1, -1
7641 XwonderwallB, FALSE, FALSE,
7642 EL_MAGIC_WALL, ACTION_ACTIVE, -1
7645 Xamoeba_1, TRUE, FALSE,
7646 EL_AMOEBA_DRY, ACTION_OTHER, -1
7649 Xamoeba_2, FALSE, FALSE,
7650 EL_AMOEBA_DRY, ACTION_OTHER, -1
7653 Xamoeba_3, FALSE, FALSE,
7654 EL_AMOEBA_DRY, ACTION_OTHER, -1
7657 Xamoeba_4, FALSE, FALSE,
7658 EL_AMOEBA_DRY, ACTION_OTHER, -1
7661 Xamoeba_5, TRUE, FALSE,
7662 EL_AMOEBA_WET, ACTION_OTHER, -1
7665 Xamoeba_6, FALSE, FALSE,
7666 EL_AMOEBA_WET, ACTION_OTHER, -1
7669 Xamoeba_7, FALSE, FALSE,
7670 EL_AMOEBA_WET, ACTION_OTHER, -1
7673 Xamoeba_8, FALSE, FALSE,
7674 EL_AMOEBA_WET, ACTION_OTHER, -1
7677 Xdoor_1, TRUE, FALSE,
7678 EL_EM_GATE_1, -1, -1
7681 Xdoor_2, TRUE, FALSE,
7682 EL_EM_GATE_2, -1, -1
7685 Xdoor_3, TRUE, FALSE,
7686 EL_EM_GATE_3, -1, -1
7689 Xdoor_4, TRUE, FALSE,
7690 EL_EM_GATE_4, -1, -1
7693 Xdoor_5, TRUE, FALSE,
7694 EL_EMC_GATE_5, -1, -1
7697 Xdoor_6, TRUE, FALSE,
7698 EL_EMC_GATE_6, -1, -1
7701 Xdoor_7, TRUE, FALSE,
7702 EL_EMC_GATE_7, -1, -1
7705 Xdoor_8, TRUE, FALSE,
7706 EL_EMC_GATE_8, -1, -1
7709 Xkey_1, TRUE, FALSE,
7713 Xkey_2, TRUE, FALSE,
7717 Xkey_3, TRUE, FALSE,
7721 Xkey_4, TRUE, FALSE,
7725 Xkey_5, TRUE, FALSE,
7726 EL_EMC_KEY_5, -1, -1
7729 Xkey_6, TRUE, FALSE,
7730 EL_EMC_KEY_6, -1, -1
7733 Xkey_7, TRUE, FALSE,
7734 EL_EMC_KEY_7, -1, -1
7737 Xkey_8, TRUE, FALSE,
7738 EL_EMC_KEY_8, -1, -1
7741 Xwind_n, TRUE, FALSE,
7742 EL_BALLOON_SWITCH_UP, -1, -1
7745 Xwind_e, TRUE, FALSE,
7746 EL_BALLOON_SWITCH_RIGHT, -1, -1
7749 Xwind_s, TRUE, FALSE,
7750 EL_BALLOON_SWITCH_DOWN, -1, -1
7753 Xwind_w, TRUE, FALSE,
7754 EL_BALLOON_SWITCH_LEFT, -1, -1
7757 Xwind_nesw, TRUE, FALSE,
7758 EL_BALLOON_SWITCH_ANY, -1, -1
7761 Xwind_stop, TRUE, FALSE,
7762 EL_BALLOON_SWITCH_NONE, -1, -1
7766 EL_EM_EXIT_CLOSED, -1, -1
7769 Xexit_1, TRUE, FALSE,
7770 EL_EM_EXIT_OPEN, -1, -1
7773 Xexit_2, FALSE, FALSE,
7774 EL_EM_EXIT_OPEN, -1, -1
7777 Xexit_3, FALSE, FALSE,
7778 EL_EM_EXIT_OPEN, -1, -1
7781 Xdynamite, TRUE, FALSE,
7782 EL_EM_DYNAMITE, -1, -1
7785 Ydynamite_eat, FALSE, FALSE,
7786 EL_EM_DYNAMITE, ACTION_COLLECTING, -1
7789 Xdynamite_1, TRUE, FALSE,
7790 EL_EM_DYNAMITE_ACTIVE, -1, -1
7793 Xdynamite_2, FALSE, FALSE,
7794 EL_EM_DYNAMITE_ACTIVE, -1, -1
7797 Xdynamite_3, FALSE, FALSE,
7798 EL_EM_DYNAMITE_ACTIVE, -1, -1
7801 Xdynamite_4, FALSE, FALSE,
7802 EL_EM_DYNAMITE_ACTIVE, -1, -1
7805 Xbumper, TRUE, FALSE,
7806 EL_EMC_SPRING_BUMPER, -1, -1
7809 XbumperB, FALSE, FALSE,
7810 EL_EMC_SPRING_BUMPER, ACTION_ACTIVE, -1
7813 Xwheel, TRUE, FALSE,
7814 EL_ROBOT_WHEEL, -1, -1
7817 XwheelB, FALSE, FALSE,
7818 EL_ROBOT_WHEEL, ACTION_ACTIVE, -1
7821 Xswitch, TRUE, FALSE,
7822 EL_EMC_MAGIC_BALL_SWITCH, -1, -1
7825 XswitchB, FALSE, FALSE,
7826 EL_EMC_MAGIC_BALL_SWITCH, ACTION_ACTIVE, -1
7830 EL_QUICKSAND_EMPTY, -1, -1
7833 Xsand_stone, TRUE, FALSE,
7834 EL_QUICKSAND_FULL, -1, -1
7837 Xsand_stonein_1, FALSE, TRUE,
7838 EL_ROCK, ACTION_FILLING, -1
7841 Xsand_stonein_2, FALSE, TRUE,
7842 EL_ROCK, ACTION_FILLING, -1
7845 Xsand_stonein_3, FALSE, TRUE,
7846 EL_ROCK, ACTION_FILLING, -1
7849 Xsand_stonein_4, FALSE, TRUE,
7850 EL_ROCK, ACTION_FILLING, -1
7854 Xsand_stonesand_1, FALSE, FALSE,
7855 EL_QUICKSAND_EMPTYING, -1, -1
7858 Xsand_stonesand_2, FALSE, FALSE,
7859 EL_QUICKSAND_EMPTYING, -1, -1
7862 Xsand_stonesand_3, FALSE, FALSE,
7863 EL_QUICKSAND_EMPTYING, -1, -1
7866 Xsand_stonesand_4, FALSE, FALSE,
7867 EL_QUICKSAND_EMPTYING, -1, -1
7870 Xsand_stonesand_quickout_1, FALSE, FALSE,
7871 EL_QUICKSAND_EMPTYING, -1, -1
7874 Xsand_stonesand_quickout_2, FALSE, FALSE,
7875 EL_QUICKSAND_EMPTYING, -1, -1
7879 Xsand_stonesand_1, FALSE, FALSE,
7880 EL_QUICKSAND_FULL, -1, -1
7883 Xsand_stonesand_2, FALSE, FALSE,
7884 EL_QUICKSAND_FULL, -1, -1
7887 Xsand_stonesand_3, FALSE, FALSE,
7888 EL_QUICKSAND_FULL, -1, -1
7891 Xsand_stonesand_4, FALSE, FALSE,
7892 EL_QUICKSAND_FULL, -1, -1
7896 Xsand_stoneout_1, FALSE, FALSE,
7897 EL_ROCK, ACTION_EMPTYING, -1
7900 Xsand_stoneout_2, FALSE, FALSE,
7901 EL_ROCK, ACTION_EMPTYING, -1
7905 Xsand_sandstone_1, FALSE, FALSE,
7906 EL_QUICKSAND_FILLING, -1, -1
7909 Xsand_sandstone_2, FALSE, FALSE,
7910 EL_QUICKSAND_FILLING, -1, -1
7913 Xsand_sandstone_3, FALSE, FALSE,
7914 EL_QUICKSAND_FILLING, -1, -1
7917 Xsand_sandstone_4, FALSE, FALSE,
7918 EL_QUICKSAND_FILLING, -1, -1
7922 Xsand_sandstone_1, FALSE, FALSE,
7923 EL_QUICKSAND_FULL, -1, -1
7926 Xsand_sandstone_2, FALSE, FALSE,
7927 EL_QUICKSAND_FULL, -1, -1
7930 Xsand_sandstone_3, FALSE, FALSE,
7931 EL_QUICKSAND_FULL, -1, -1
7934 Xsand_sandstone_4, FALSE, FALSE,
7935 EL_QUICKSAND_FULL, -1, -1
7939 Xplant, TRUE, FALSE,
7940 EL_EMC_PLANT, -1, -1
7943 Yplant, FALSE, FALSE,
7944 EL_EMC_PLANT, -1, -1
7947 Xlenses, TRUE, FALSE,
7948 EL_EMC_LENSES, -1, -1
7951 Xmagnify, TRUE, FALSE,
7952 EL_EMC_MAGNIFIER, -1, -1
7955 Xdripper, TRUE, FALSE,
7956 EL_EMC_DRIPPER, -1, -1
7959 XdripperB, FALSE, FALSE,
7960 EL_EMC_DRIPPER, ACTION_ACTIVE, -1
7963 Xfake_blank, TRUE, FALSE,
7964 EL_INVISIBLE_WALL, -1, -1
7967 Xfake_blankB, FALSE, FALSE,
7968 EL_INVISIBLE_WALL, ACTION_ACTIVE, -1
7971 Xfake_grass, TRUE, FALSE,
7972 EL_EMC_FAKE_GRASS, -1, -1
7975 Xfake_grassB, FALSE, FALSE,
7976 EL_EMC_FAKE_GRASS, ACTION_ACTIVE, -1
7979 Xfake_door_1, TRUE, FALSE,
7980 EL_EM_GATE_1_GRAY, -1, -1
7983 Xfake_door_2, TRUE, FALSE,
7984 EL_EM_GATE_2_GRAY, -1, -1
7987 Xfake_door_3, TRUE, FALSE,
7988 EL_EM_GATE_3_GRAY, -1, -1
7991 Xfake_door_4, TRUE, FALSE,
7992 EL_EM_GATE_4_GRAY, -1, -1
7995 Xfake_door_5, TRUE, FALSE,
7996 EL_EMC_GATE_5_GRAY, -1, -1
7999 Xfake_door_6, TRUE, FALSE,
8000 EL_EMC_GATE_6_GRAY, -1, -1
8003 Xfake_door_7, TRUE, FALSE,
8004 EL_EMC_GATE_7_GRAY, -1, -1
8007 Xfake_door_8, TRUE, FALSE,
8008 EL_EMC_GATE_8_GRAY, -1, -1
8011 Xfake_acid_1, TRUE, FALSE,
8012 EL_EMC_FAKE_ACID, -1, -1
8015 Xfake_acid_2, FALSE, FALSE,
8016 EL_EMC_FAKE_ACID, -1, -1
8019 Xfake_acid_3, FALSE, FALSE,
8020 EL_EMC_FAKE_ACID, -1, -1
8023 Xfake_acid_4, FALSE, FALSE,
8024 EL_EMC_FAKE_ACID, -1, -1
8027 Xfake_acid_5, FALSE, FALSE,
8028 EL_EMC_FAKE_ACID, -1, -1
8031 Xfake_acid_6, FALSE, FALSE,
8032 EL_EMC_FAKE_ACID, -1, -1
8035 Xfake_acid_7, FALSE, FALSE,
8036 EL_EMC_FAKE_ACID, -1, -1
8039 Xfake_acid_8, FALSE, FALSE,
8040 EL_EMC_FAKE_ACID, -1, -1
8043 Xsteel_1, TRUE, FALSE,
8044 EL_STEELWALL, -1, -1
8047 Xsteel_2, TRUE, FALSE,
8048 EL_EMC_STEELWALL_2, -1, -1
8051 Xsteel_3, TRUE, FALSE,
8052 EL_EMC_STEELWALL_3, -1, -1
8055 Xsteel_4, TRUE, FALSE,
8056 EL_EMC_STEELWALL_4, -1, -1
8059 Xwall_1, TRUE, FALSE,
8063 Xwall_2, TRUE, FALSE,
8064 EL_EMC_WALL_14, -1, -1
8067 Xwall_3, TRUE, FALSE,
8068 EL_EMC_WALL_15, -1, -1
8071 Xwall_4, TRUE, FALSE,
8072 EL_EMC_WALL_16, -1, -1
8075 Xround_wall_1, TRUE, FALSE,
8076 EL_WALL_SLIPPERY, -1, -1
8079 Xround_wall_2, TRUE, FALSE,
8080 EL_EMC_WALL_SLIPPERY_2, -1, -1
8083 Xround_wall_3, TRUE, FALSE,
8084 EL_EMC_WALL_SLIPPERY_3, -1, -1
8087 Xround_wall_4, TRUE, FALSE,
8088 EL_EMC_WALL_SLIPPERY_4, -1, -1
8091 Xdecor_1, TRUE, FALSE,
8092 EL_EMC_WALL_8, -1, -1
8095 Xdecor_2, TRUE, FALSE,
8096 EL_EMC_WALL_6, -1, -1
8099 Xdecor_3, TRUE, FALSE,
8100 EL_EMC_WALL_4, -1, -1
8103 Xdecor_4, TRUE, FALSE,
8104 EL_EMC_WALL_7, -1, -1
8107 Xdecor_5, TRUE, FALSE,
8108 EL_EMC_WALL_5, -1, -1
8111 Xdecor_6, TRUE, FALSE,
8112 EL_EMC_WALL_9, -1, -1
8115 Xdecor_7, TRUE, FALSE,
8116 EL_EMC_WALL_10, -1, -1
8119 Xdecor_8, TRUE, FALSE,
8120 EL_EMC_WALL_1, -1, -1
8123 Xdecor_9, TRUE, FALSE,
8124 EL_EMC_WALL_2, -1, -1
8127 Xdecor_10, TRUE, FALSE,
8128 EL_EMC_WALL_3, -1, -1
8131 Xdecor_11, TRUE, FALSE,
8132 EL_EMC_WALL_11, -1, -1
8135 Xdecor_12, TRUE, FALSE,
8136 EL_EMC_WALL_12, -1, -1
8139 Xalpha_0, TRUE, FALSE,
8140 EL_CHAR('0'), -1, -1
8143 Xalpha_1, TRUE, FALSE,
8144 EL_CHAR('1'), -1, -1
8147 Xalpha_2, TRUE, FALSE,
8148 EL_CHAR('2'), -1, -1
8151 Xalpha_3, TRUE, FALSE,
8152 EL_CHAR('3'), -1, -1
8155 Xalpha_4, TRUE, FALSE,
8156 EL_CHAR('4'), -1, -1
8159 Xalpha_5, TRUE, FALSE,
8160 EL_CHAR('5'), -1, -1
8163 Xalpha_6, TRUE, FALSE,
8164 EL_CHAR('6'), -1, -1
8167 Xalpha_7, TRUE, FALSE,
8168 EL_CHAR('7'), -1, -1
8171 Xalpha_8, TRUE, FALSE,
8172 EL_CHAR('8'), -1, -1
8175 Xalpha_9, TRUE, FALSE,
8176 EL_CHAR('9'), -1, -1
8179 Xalpha_excla, TRUE, FALSE,
8180 EL_CHAR('!'), -1, -1
8183 Xalpha_quote, TRUE, FALSE,
8184 EL_CHAR('"'), -1, -1
8187 Xalpha_comma, TRUE, FALSE,
8188 EL_CHAR(','), -1, -1
8191 Xalpha_minus, TRUE, FALSE,
8192 EL_CHAR('-'), -1, -1
8195 Xalpha_perio, TRUE, FALSE,
8196 EL_CHAR('.'), -1, -1
8199 Xalpha_colon, TRUE, FALSE,
8200 EL_CHAR(':'), -1, -1
8203 Xalpha_quest, TRUE, FALSE,
8204 EL_CHAR('?'), -1, -1
8207 Xalpha_a, TRUE, FALSE,
8208 EL_CHAR('A'), -1, -1
8211 Xalpha_b, TRUE, FALSE,
8212 EL_CHAR('B'), -1, -1
8215 Xalpha_c, TRUE, FALSE,
8216 EL_CHAR('C'), -1, -1
8219 Xalpha_d, TRUE, FALSE,
8220 EL_CHAR('D'), -1, -1
8223 Xalpha_e, TRUE, FALSE,
8224 EL_CHAR('E'), -1, -1
8227 Xalpha_f, TRUE, FALSE,
8228 EL_CHAR('F'), -1, -1
8231 Xalpha_g, TRUE, FALSE,
8232 EL_CHAR('G'), -1, -1
8235 Xalpha_h, TRUE, FALSE,
8236 EL_CHAR('H'), -1, -1
8239 Xalpha_i, TRUE, FALSE,
8240 EL_CHAR('I'), -1, -1
8243 Xalpha_j, TRUE, FALSE,
8244 EL_CHAR('J'), -1, -1
8247 Xalpha_k, TRUE, FALSE,
8248 EL_CHAR('K'), -1, -1
8251 Xalpha_l, TRUE, FALSE,
8252 EL_CHAR('L'), -1, -1
8255 Xalpha_m, TRUE, FALSE,
8256 EL_CHAR('M'), -1, -1
8259 Xalpha_n, TRUE, FALSE,
8260 EL_CHAR('N'), -1, -1
8263 Xalpha_o, TRUE, FALSE,
8264 EL_CHAR('O'), -1, -1
8267 Xalpha_p, TRUE, FALSE,
8268 EL_CHAR('P'), -1, -1
8271 Xalpha_q, TRUE, FALSE,
8272 EL_CHAR('Q'), -1, -1
8275 Xalpha_r, TRUE, FALSE,
8276 EL_CHAR('R'), -1, -1
8279 Xalpha_s, TRUE, FALSE,
8280 EL_CHAR('S'), -1, -1
8283 Xalpha_t, TRUE, FALSE,
8284 EL_CHAR('T'), -1, -1
8287 Xalpha_u, TRUE, FALSE,
8288 EL_CHAR('U'), -1, -1
8291 Xalpha_v, TRUE, FALSE,
8292 EL_CHAR('V'), -1, -1
8295 Xalpha_w, TRUE, FALSE,
8296 EL_CHAR('W'), -1, -1
8299 Xalpha_x, TRUE, FALSE,
8300 EL_CHAR('X'), -1, -1
8303 Xalpha_y, TRUE, FALSE,
8304 EL_CHAR('Y'), -1, -1
8307 Xalpha_z, TRUE, FALSE,
8308 EL_CHAR('Z'), -1, -1
8311 Xalpha_arrow_e, TRUE, FALSE,
8312 EL_CHAR('>'), -1, -1
8315 Xalpha_arrow_w, TRUE, FALSE,
8316 EL_CHAR('<'), -1, -1
8319 Xalpha_copyr, TRUE, FALSE,
8320 EL_CHAR('©'), -1, -1
8324 Xboom_bug, FALSE, FALSE,
8325 EL_BUG, ACTION_EXPLODING, -1
8328 Xboom_bomb, FALSE, FALSE,
8329 EL_BOMB, ACTION_EXPLODING, -1
8332 Xboom_android, FALSE, FALSE,
8333 EL_EMC_ANDROID, ACTION_OTHER, -1
8336 Xboom_1, FALSE, FALSE,
8337 EL_DEFAULT, ACTION_EXPLODING, -1
8340 Xboom_2, FALSE, FALSE,
8341 EL_DEFAULT, ACTION_EXPLODING, -1
8344 Znormal, FALSE, FALSE,
8348 Zdynamite, FALSE, FALSE,
8352 Zplayer, FALSE, FALSE,
8356 ZBORDER, FALSE, FALSE,
8366 static struct Mapping_EM_to_RND_player
8375 em_player_mapping_list[] =
8379 EL_PLAYER_1, ACTION_MOVING, MV_BIT_UP,
8383 EL_PLAYER_1, ACTION_MOVING, MV_BIT_RIGHT,
8387 EL_PLAYER_1, ACTION_MOVING, MV_BIT_DOWN,
8391 EL_PLAYER_1, ACTION_MOVING, MV_BIT_LEFT,
8395 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_UP,
8399 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_RIGHT,
8403 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_DOWN,
8407 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_LEFT,
8411 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_UP,
8415 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_RIGHT,
8419 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_DOWN,
8423 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_LEFT,
8427 EL_PLAYER_2, ACTION_MOVING, MV_BIT_UP,
8431 EL_PLAYER_2, ACTION_MOVING, MV_BIT_RIGHT,
8435 EL_PLAYER_2, ACTION_MOVING, MV_BIT_DOWN,
8439 EL_PLAYER_2, ACTION_MOVING, MV_BIT_LEFT,
8443 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_UP,
8447 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_RIGHT,
8451 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_DOWN,
8455 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_LEFT,
8459 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_UP,
8463 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_RIGHT,
8467 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_DOWN,
8471 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_LEFT,
8475 EL_PLAYER_1, ACTION_DEFAULT, -1,
8479 EL_PLAYER_2, ACTION_DEFAULT, -1,
8483 EL_PLAYER_3, ACTION_MOVING, MV_BIT_UP,
8487 EL_PLAYER_3, ACTION_MOVING, MV_BIT_RIGHT,
8491 EL_PLAYER_3, ACTION_MOVING, MV_BIT_DOWN,
8495 EL_PLAYER_3, ACTION_MOVING, MV_BIT_LEFT,
8499 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_UP,
8503 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_RIGHT,
8507 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_DOWN,
8511 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_LEFT,
8515 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_UP,
8519 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_RIGHT,
8523 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_DOWN,
8527 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_LEFT,
8531 EL_PLAYER_4, ACTION_MOVING, MV_BIT_UP,
8535 EL_PLAYER_4, ACTION_MOVING, MV_BIT_RIGHT,
8539 EL_PLAYER_4, ACTION_MOVING, MV_BIT_DOWN,
8543 EL_PLAYER_4, ACTION_MOVING, MV_BIT_LEFT,
8547 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_UP,
8551 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_RIGHT,
8555 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_DOWN,
8559 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_LEFT,
8563 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_UP,
8567 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_RIGHT,
8571 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_DOWN,
8575 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_LEFT,
8579 EL_PLAYER_3, ACTION_DEFAULT, -1,
8583 EL_PLAYER_4, ACTION_DEFAULT, -1,
8592 int map_element_RND_to_EM(int element_rnd)
8594 static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
8595 static boolean mapping_initialized = FALSE;
8597 if (!mapping_initialized)
8601 /* return "Xalpha_quest" for all undefined elements in mapping array */
8602 for (i = 0; i < NUM_FILE_ELEMENTS; i++)
8603 mapping_RND_to_EM[i] = Xalpha_quest;
8605 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
8606 if (em_object_mapping_list[i].is_rnd_to_em_mapping)
8607 mapping_RND_to_EM[em_object_mapping_list[i].element_rnd] =
8608 em_object_mapping_list[i].element_em;
8610 mapping_initialized = TRUE;
8613 if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
8614 return mapping_RND_to_EM[element_rnd];
8616 Error(ERR_WARN, "invalid RND level element %d", element_rnd);
8621 int map_element_EM_to_RND(int element_em)
8623 static unsigned short mapping_EM_to_RND[TILE_MAX];
8624 static boolean mapping_initialized = FALSE;
8626 if (!mapping_initialized)
8630 /* return "EL_UNKNOWN" for all undefined elements in mapping array */
8631 for (i = 0; i < TILE_MAX; i++)
8632 mapping_EM_to_RND[i] = EL_UNKNOWN;
8634 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
8635 mapping_EM_to_RND[em_object_mapping_list[i].element_em] =
8636 em_object_mapping_list[i].element_rnd;
8638 mapping_initialized = TRUE;
8641 if (element_em >= 0 && element_em < TILE_MAX)
8642 return mapping_EM_to_RND[element_em];
8644 Error(ERR_WARN, "invalid EM level element %d", element_em);
8649 void map_android_clone_elements_RND_to_EM(struct LevelInfo *level)
8651 struct LevelInfo_EM *level_em = level->native_em_level;
8652 struct LEVEL *lev = level_em->lev;
8655 for (i = 0; i < TILE_MAX; i++)
8656 lev->android_array[i] = Xblank;
8658 for (i = 0; i < level->num_android_clone_elements; i++)
8660 int element_rnd = level->android_clone_element[i];
8661 int element_em = map_element_RND_to_EM(element_rnd);
8663 for (j = 0; em_object_mapping_list[j].element_em != -1; j++)
8664 if (em_object_mapping_list[j].element_rnd == element_rnd)
8665 lev->android_array[em_object_mapping_list[j].element_em] = element_em;
8669 void map_android_clone_elements_EM_to_RND(struct LevelInfo *level)
8671 struct LevelInfo_EM *level_em = level->native_em_level;
8672 struct LEVEL *lev = level_em->lev;
8675 level->num_android_clone_elements = 0;
8677 for (i = 0; i < TILE_MAX; i++)
8679 int element_em = lev->android_array[i];
8681 boolean element_found = FALSE;
8683 if (element_em == Xblank)
8686 element_rnd = map_element_EM_to_RND(element_em);
8688 for (j = 0; j < level->num_android_clone_elements; j++)
8689 if (level->android_clone_element[j] == element_rnd)
8690 element_found = TRUE;
8694 level->android_clone_element[level->num_android_clone_elements++] =
8697 if (level->num_android_clone_elements == MAX_ANDROID_ELEMENTS)
8702 if (level->num_android_clone_elements == 0)
8704 level->num_android_clone_elements = 1;
8705 level->android_clone_element[0] = EL_EMPTY;
8709 int map_direction_RND_to_EM(int direction)
8711 return (direction == MV_UP ? 0 :
8712 direction == MV_RIGHT ? 1 :
8713 direction == MV_DOWN ? 2 :
8714 direction == MV_LEFT ? 3 :
8718 int map_direction_EM_to_RND(int direction)
8720 return (direction == 0 ? MV_UP :
8721 direction == 1 ? MV_RIGHT :
8722 direction == 2 ? MV_DOWN :
8723 direction == 3 ? MV_LEFT :
8727 int map_element_RND_to_SP(int element_rnd)
8729 int element_sp = 0x20; /* map unknown elements to yellow "hardware" */
8731 if (element_rnd >= EL_SP_START &&
8732 element_rnd <= EL_SP_END)
8733 element_sp = element_rnd - EL_SP_START;
8734 else if (element_rnd == EL_EMPTY_SPACE)
8736 else if (element_rnd == EL_INVISIBLE_WALL)
8742 int map_element_SP_to_RND(int element_sp)
8744 int element_rnd = EL_UNKNOWN;
8746 if (element_sp >= 0x00 &&
8748 element_rnd = EL_SP_START + element_sp;
8749 else if (element_sp == 0x28)
8750 element_rnd = EL_INVISIBLE_WALL;
8755 int map_action_SP_to_RND(int action_sp)
8759 case actActive: return ACTION_ACTIVE;
8760 case actImpact: return ACTION_IMPACT;
8761 case actExploding: return ACTION_EXPLODING;
8762 case actDigging: return ACTION_DIGGING;
8763 case actSnapping: return ACTION_SNAPPING;
8764 case actCollecting: return ACTION_COLLECTING;
8765 case actPassing: return ACTION_PASSING;
8766 case actPushing: return ACTION_PUSHING;
8767 case actDropping: return ACTION_DROPPING;
8769 default: return ACTION_DEFAULT;
8773 int get_next_element(int element)
8777 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
8778 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
8779 case EL_QUICKSAND_FAST_FILLING: return EL_QUICKSAND_FAST_FULL;
8780 case EL_QUICKSAND_FAST_EMPTYING: return EL_QUICKSAND_FAST_EMPTY;
8781 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
8782 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
8783 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
8784 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
8785 case EL_DC_MAGIC_WALL_FILLING: return EL_DC_MAGIC_WALL_FULL;
8786 case EL_DC_MAGIC_WALL_EMPTYING: return EL_DC_MAGIC_WALL_ACTIVE;
8787 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
8789 default: return element;
8794 int el_act_dir2img(int element, int action, int direction)
8796 element = GFX_ELEMENT(element);
8798 if (direction == MV_NONE)
8799 return element_info[element].graphic[action];
8801 direction = MV_DIR_TO_BIT(direction);
8803 return element_info[element].direction_graphic[action][direction];
8806 int el_act_dir2img(int element, int action, int direction)
8808 element = GFX_ELEMENT(element);
8809 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
8811 /* direction_graphic[][] == graphic[] for undefined direction graphics */
8812 return element_info[element].direction_graphic[action][direction];
8817 static int el_act_dir2crm(int element, int action, int direction)
8819 element = GFX_ELEMENT(element);
8821 if (direction == MV_NONE)
8822 return element_info[element].crumbled[action];
8824 direction = MV_DIR_TO_BIT(direction);
8826 return element_info[element].direction_crumbled[action][direction];
8829 static int el_act_dir2crm(int element, int action, int direction)
8831 element = GFX_ELEMENT(element);
8832 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
8834 /* direction_graphic[][] == graphic[] for undefined direction graphics */
8835 return element_info[element].direction_crumbled[action][direction];
8839 int el_act2img(int element, int action)
8841 element = GFX_ELEMENT(element);
8843 return element_info[element].graphic[action];
8846 int el_act2crm(int element, int action)
8848 element = GFX_ELEMENT(element);
8850 return element_info[element].crumbled[action];
8853 int el_dir2img(int element, int direction)
8855 element = GFX_ELEMENT(element);
8857 return el_act_dir2img(element, ACTION_DEFAULT, direction);
8860 int el2baseimg(int element)
8862 return element_info[element].graphic[ACTION_DEFAULT];
8865 int el2img(int element)
8867 element = GFX_ELEMENT(element);
8869 return element_info[element].graphic[ACTION_DEFAULT];
8872 int el2edimg(int element)
8874 element = GFX_ELEMENT(element);
8876 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
8879 int el2preimg(int element)
8881 element = GFX_ELEMENT(element);
8883 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
8886 int el2panelimg(int element)
8888 element = GFX_ELEMENT(element);
8890 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PANEL];
8893 int font2baseimg(int font_nr)
8895 return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
8898 int getBeltNrFromBeltElement(int element)
8900 return (element < EL_CONVEYOR_BELT_2_LEFT ? 0 :
8901 element < EL_CONVEYOR_BELT_3_LEFT ? 1 :
8902 element < EL_CONVEYOR_BELT_4_LEFT ? 2 : 3);
8905 int getBeltNrFromBeltActiveElement(int element)
8907 return (element < EL_CONVEYOR_BELT_2_LEFT_ACTIVE ? 0 :
8908 element < EL_CONVEYOR_BELT_3_LEFT_ACTIVE ? 1 :
8909 element < EL_CONVEYOR_BELT_4_LEFT_ACTIVE ? 2 : 3);
8912 int getBeltNrFromBeltSwitchElement(int element)
8914 return (element < EL_CONVEYOR_BELT_2_SWITCH_LEFT ? 0 :
8915 element < EL_CONVEYOR_BELT_3_SWITCH_LEFT ? 1 :
8916 element < EL_CONVEYOR_BELT_4_SWITCH_LEFT ? 2 : 3);
8919 int getBeltDirNrFromBeltElement(int element)
8921 static int belt_base_element[4] =
8923 EL_CONVEYOR_BELT_1_LEFT,
8924 EL_CONVEYOR_BELT_2_LEFT,
8925 EL_CONVEYOR_BELT_3_LEFT,
8926 EL_CONVEYOR_BELT_4_LEFT
8929 int belt_nr = getBeltNrFromBeltElement(element);
8930 int belt_dir_nr = element - belt_base_element[belt_nr];
8932 return (belt_dir_nr % 3);
8935 int getBeltDirNrFromBeltSwitchElement(int element)
8937 static int belt_base_element[4] =
8939 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
8940 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
8941 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
8942 EL_CONVEYOR_BELT_4_SWITCH_LEFT
8945 int belt_nr = getBeltNrFromBeltSwitchElement(element);
8946 int belt_dir_nr = element - belt_base_element[belt_nr];
8948 return (belt_dir_nr % 3);
8951 int getBeltDirFromBeltElement(int element)
8953 static int belt_move_dir[3] =
8960 int belt_dir_nr = getBeltDirNrFromBeltElement(element);
8962 return belt_move_dir[belt_dir_nr];
8965 int getBeltDirFromBeltSwitchElement(int element)
8967 static int belt_move_dir[3] =
8974 int belt_dir_nr = getBeltDirNrFromBeltSwitchElement(element);
8976 return belt_move_dir[belt_dir_nr];
8979 int getBeltElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
8981 static int belt_base_element[4] =
8983 EL_CONVEYOR_BELT_1_LEFT,
8984 EL_CONVEYOR_BELT_2_LEFT,
8985 EL_CONVEYOR_BELT_3_LEFT,
8986 EL_CONVEYOR_BELT_4_LEFT
8989 return belt_base_element[belt_nr] + belt_dir_nr;
8992 int getBeltElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
8994 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
8996 return getBeltElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
8999 int getBeltSwitchElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
9001 static int belt_base_element[4] =
9003 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
9004 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
9005 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
9006 EL_CONVEYOR_BELT_4_SWITCH_LEFT
9009 return belt_base_element[belt_nr] + belt_dir_nr;
9012 int getBeltSwitchElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
9014 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
9016 return getBeltSwitchElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
9020 boolean getTeamMode_EM()
9022 return game.team_mode;
9025 int getNumActivePlayers_EM()
9028 int num_players = 0;
9032 return (setup.team_mode ? MAX_PLAYERS : 1);
9034 for (i = 0; i < MAX_PLAYERS; i++)
9035 if (tape.player_participates[i])
9038 return (num_players > 1 ? MAX_PLAYERS : 1);
9042 int num_players = 0;
9045 /* when recording game, activate all connected players */
9049 for (i = 0; i < MAX_PLAYERS; i++)
9050 if (tape.player_participates[i])
9058 int getGameFrameDelay_EM(int native_em_game_frame_delay)
9060 int game_frame_delay_value;
9062 game_frame_delay_value =
9063 (tape.playing && tape.fast_forward ? FfwdFrameDelay :
9064 GameFrameDelay == GAME_FRAME_DELAY ? native_em_game_frame_delay :
9067 if (tape.playing && tape.warp_forward && !tape.pausing)
9068 game_frame_delay_value = 0;
9070 return game_frame_delay_value;
9073 unsigned int InitRND(int seed)
9075 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
9076 return InitEngineRandom_EM(seed);
9077 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
9078 return InitEngineRandom_SP(seed);
9080 return InitEngineRandom_RND(seed);
9084 static struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
9085 static struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
9088 inline static int get_effective_element_EM(int tile, int frame_em)
9090 int element = object_mapping[tile].element_rnd;
9091 int action = object_mapping[tile].action;
9092 boolean is_backside = object_mapping[tile].is_backside;
9093 boolean action_removing = (action == ACTION_DIGGING ||
9094 action == ACTION_SNAPPING ||
9095 action == ACTION_COLLECTING);
9101 case Yacid_splash_eB:
9102 case Yacid_splash_wB:
9103 return (frame_em > 5 ? EL_EMPTY : element);
9107 case Ydiamond_stone:
9108 // if (!game.use_native_emc_graphics_engine)
9116 else /* frame_em == 7 */
9120 case Yacid_splash_eB:
9121 case Yacid_splash_wB:
9124 case Yemerald_stone:
9127 case Ydiamond_stone:
9131 case Xdrip_stretchB:
9150 case Xsand_stonein_1:
9151 case Xsand_stonein_2:
9152 case Xsand_stonein_3:
9153 case Xsand_stonein_4:
9157 return (is_backside || action_removing ? EL_EMPTY : element);
9162 inline static boolean check_linear_animation_EM(int tile)
9166 case Xsand_stonesand_1:
9167 case Xsand_stonesand_quickout_1:
9168 case Xsand_sandstone_1:
9169 case Xsand_stonein_1:
9170 case Xsand_stoneout_1:
9190 case Yacid_splash_eB:
9191 case Yacid_splash_wB:
9192 case Yemerald_stone:
9200 inline static void set_crumbled_graphics_EM(struct GraphicInfo_EM *g_em,
9201 boolean has_crumbled_graphics,
9202 int crumbled, int sync_frame)
9204 /* if element can be crumbled, but certain action graphics are just empty
9205 space (like instantly snapping sand to empty space in 1 frame), do not
9206 treat these empty space graphics as crumbled graphics in EMC engine */
9207 if (crumbled == IMG_EMPTY_SPACE)
9208 has_crumbled_graphics = FALSE;
9210 if (has_crumbled_graphics)
9212 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
9213 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
9214 g_crumbled->anim_delay,
9215 g_crumbled->anim_mode,
9216 g_crumbled->anim_start_frame,
9219 getGraphicSource(crumbled, frame_crumbled, &g_em->crumbled_bitmap,
9220 &g_em->crumbled_src_x, &g_em->crumbled_src_y);
9222 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
9224 g_em->has_crumbled_graphics = TRUE;
9228 g_em->crumbled_bitmap = NULL;
9229 g_em->crumbled_src_x = 0;
9230 g_em->crumbled_src_y = 0;
9231 g_em->crumbled_border_size = 0;
9233 g_em->has_crumbled_graphics = FALSE;
9237 void ResetGfxAnimation_EM(int x, int y, int tile)
9242 void SetGfxAnimation_EM(struct GraphicInfo_EM *g_em,
9243 int tile, int frame_em, int x, int y)
9245 int action = object_mapping[tile].action;
9247 int direction = object_mapping[tile].direction;
9248 int effective_element = get_effective_element_EM(tile, frame_em);
9249 int graphic = (direction == MV_NONE ?
9250 el_act2img(effective_element, action) :
9251 el_act_dir2img(effective_element, action, direction));
9252 struct GraphicInfo *g = &graphic_info[graphic];
9255 boolean action_removing = (action == ACTION_DIGGING ||
9256 action == ACTION_SNAPPING ||
9257 action == ACTION_COLLECTING);
9258 boolean action_moving = (action == ACTION_FALLING ||
9259 action == ACTION_MOVING ||
9260 action == ACTION_PUSHING ||
9261 action == ACTION_EATING ||
9262 action == ACTION_FILLING ||
9263 action == ACTION_EMPTYING);
9264 boolean action_falling = (action == ACTION_FALLING ||
9265 action == ACTION_FILLING ||
9266 action == ACTION_EMPTYING);
9268 /* special case: graphic uses "2nd movement tile" and has defined
9269 7 frames for movement animation (or less) => use default graphic
9270 for last (8th) frame which ends the movement animation */
9271 if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
9273 action = ACTION_DEFAULT; /* (keep action_* unchanged for now) */
9274 graphic = (direction == MV_NONE ?
9275 el_act2img(effective_element, action) :
9276 el_act_dir2img(effective_element, action, direction));
9278 g = &graphic_info[graphic];
9282 if (tile == Xsand_stonesand_1 ||
9283 tile == Xsand_stonesand_2 ||
9284 tile == Xsand_stonesand_3 ||
9285 tile == Xsand_stonesand_4)
9286 printf("::: 1: quicksand frame %d [%d]\n", GfxFrame[x][y], tile);
9290 if ((action_removing || check_linear_animation_EM(tile)) && frame_em == 0)
9294 // printf("::: resetting... [%d]\n", tile);
9297 if (action_removing || check_linear_animation_EM(tile))
9299 GfxFrame[x][y] = frame_em;
9301 // printf("::: resetting... [%d]\n", tile);
9304 else if (action_moving)
9306 boolean is_backside = object_mapping[tile].is_backside;
9310 int direction = object_mapping[tile].direction;
9311 int move_dir = (action_falling ? MV_DOWN : direction);
9316 /* !!! TEST !!! NEW !!! DOES NOT WORK RIGHT YET !!! */
9317 if (g->double_movement && frame_em == 0)
9321 // printf("::: resetting... [%d]\n", tile);
9325 if (move_dir == MV_LEFT)
9326 GfxFrame[x - 1][y] = GfxFrame[x][y];
9327 else if (move_dir == MV_RIGHT)
9328 GfxFrame[x + 1][y] = GfxFrame[x][y];
9329 else if (move_dir == MV_UP)
9330 GfxFrame[x][y - 1] = GfxFrame[x][y];
9331 else if (move_dir == MV_DOWN)
9332 GfxFrame[x][y + 1] = GfxFrame[x][y];
9339 /* special case: animation for Xsand_stonesand_quickout_1/2 twice as fast */
9340 if (tile == Xsand_stonesand_quickout_1 ||
9341 tile == Xsand_stonesand_quickout_2)
9346 if (tile == Xsand_stonesand_1 ||
9347 tile == Xsand_stonesand_2 ||
9348 tile == Xsand_stonesand_3 ||
9349 tile == Xsand_stonesand_4)
9350 printf("::: 2: quicksand frame %d [%d]\n", GfxFrame[x][y], tile);
9354 if (graphic_info[graphic].anim_global_sync)
9355 sync_frame = FrameCounter;
9356 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
9357 sync_frame = GfxFrame[x][y];
9359 sync_frame = 0; /* playfield border (pseudo steel) */
9361 SetRandomAnimationValue(x, y);
9363 int frame = getAnimationFrame(g->anim_frames,
9366 g->anim_start_frame,
9369 g_em->unique_identifier =
9370 (graphic << 16) | ((frame % 8) << 12) | (g_em->width << 6) | g_em->height;
9374 void getGraphicSourceObjectExt_EM(struct GraphicInfo_EM *g_em,
9375 int tile, int frame_em, int x, int y)
9377 int action = object_mapping[tile].action;
9378 int direction = object_mapping[tile].direction;
9379 boolean is_backside = object_mapping[tile].is_backside;
9380 int effective_element = get_effective_element_EM(tile, frame_em);
9382 int effective_action = action;
9384 int effective_action = (frame_em < 7 ? action : ACTION_DEFAULT);
9386 int graphic = (direction == MV_NONE ?
9387 el_act2img(effective_element, effective_action) :
9388 el_act_dir2img(effective_element, effective_action,
9390 int crumbled = (direction == MV_NONE ?
9391 el_act2crm(effective_element, effective_action) :
9392 el_act_dir2crm(effective_element, effective_action,
9394 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
9395 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
9396 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
9397 struct GraphicInfo *g = &graphic_info[graphic];
9399 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
9403 /* special case: graphic uses "2nd movement tile" and has defined
9404 7 frames for movement animation (or less) => use default graphic
9405 for last (8th) frame which ends the movement animation */
9406 if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
9408 effective_action = ACTION_DEFAULT;
9409 graphic = (direction == MV_NONE ?
9410 el_act2img(effective_element, effective_action) :
9411 el_act_dir2img(effective_element, effective_action,
9413 crumbled = (direction == MV_NONE ?
9414 el_act2crm(effective_element, effective_action) :
9415 el_act_dir2crm(effective_element, effective_action,
9418 g = &graphic_info[graphic];
9428 if (frame_em == 0) /* reset animation frame for certain elements */
9430 if (check_linear_animation_EM(tile))
9435 if (graphic_info[graphic].anim_global_sync)
9436 sync_frame = FrameCounter;
9437 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
9438 sync_frame = GfxFrame[x][y];
9440 sync_frame = 0; /* playfield border (pseudo steel) */
9442 SetRandomAnimationValue(x, y);
9447 int xxx_sync_frame = (i == Xdrip_stretch ? 7 :
9448 i == Xdrip_stretchB ? 7 :
9449 i == Ydrip_s2 ? j + 8 :
9450 i == Ydrip_s2B ? j + 8 :
9459 i == Xfake_acid_1 ? 0 :
9460 i == Xfake_acid_2 ? 10 :
9461 i == Xfake_acid_3 ? 20 :
9462 i == Xfake_acid_4 ? 30 :
9463 i == Xfake_acid_5 ? 40 :
9464 i == Xfake_acid_6 ? 50 :
9465 i == Xfake_acid_7 ? 60 :
9466 i == Xfake_acid_8 ? 70 :
9468 i == Xball_2B ? j + 8 :
9469 i == Yball_eat ? j + 1 :
9470 i == Ykey_1_eat ? j + 1 :
9471 i == Ykey_2_eat ? j + 1 :
9472 i == Ykey_3_eat ? j + 1 :
9473 i == Ykey_4_eat ? j + 1 :
9474 i == Ykey_5_eat ? j + 1 :
9475 i == Ykey_6_eat ? j + 1 :
9476 i == Ykey_7_eat ? j + 1 :
9477 i == Ykey_8_eat ? j + 1 :
9478 i == Ylenses_eat ? j + 1 :
9479 i == Ymagnify_eat ? j + 1 :
9480 i == Ygrass_eat ? j + 1 :
9481 i == Ydirt_eat ? j + 1 :
9482 i == Xamoeba_1 ? 0 :
9483 i == Xamoeba_2 ? 1 :
9484 i == Xamoeba_3 ? 2 :
9485 i == Xamoeba_4 ? 3 :
9486 i == Xamoeba_5 ? 0 :
9487 i == Xamoeba_6 ? 1 :
9488 i == Xamoeba_7 ? 2 :
9489 i == Xamoeba_8 ? 3 :
9490 i == Xexit_2 ? j + 8 :
9491 i == Xexit_3 ? j + 16 :
9492 i == Xdynamite_1 ? 0 :
9493 i == Xdynamite_2 ? 8 :
9494 i == Xdynamite_3 ? 16 :
9495 i == Xdynamite_4 ? 24 :
9496 i == Xsand_stonein_1 ? j + 1 :
9497 i == Xsand_stonein_2 ? j + 9 :
9498 i == Xsand_stonein_3 ? j + 17 :
9499 i == Xsand_stonein_4 ? j + 25 :
9500 i == Xsand_stoneout_1 && j == 0 ? 0 :
9501 i == Xsand_stoneout_1 && j == 1 ? 0 :
9502 i == Xsand_stoneout_1 && j == 2 ? 1 :
9503 i == Xsand_stoneout_1 && j == 3 ? 2 :
9504 i == Xsand_stoneout_1 && j == 4 ? 2 :
9505 i == Xsand_stoneout_1 && j == 5 ? 3 :
9506 i == Xsand_stoneout_1 && j == 6 ? 4 :
9507 i == Xsand_stoneout_1 && j == 7 ? 4 :
9508 i == Xsand_stoneout_2 && j == 0 ? 5 :
9509 i == Xsand_stoneout_2 && j == 1 ? 6 :
9510 i == Xsand_stoneout_2 && j == 2 ? 7 :
9511 i == Xsand_stoneout_2 && j == 3 ? 8 :
9512 i == Xsand_stoneout_2 && j == 4 ? 9 :
9513 i == Xsand_stoneout_2 && j == 5 ? 11 :
9514 i == Xsand_stoneout_2 && j == 6 ? 13 :
9515 i == Xsand_stoneout_2 && j == 7 ? 15 :
9516 i == Xboom_bug && j == 1 ? 2 :
9517 i == Xboom_bug && j == 2 ? 2 :
9518 i == Xboom_bug && j == 3 ? 4 :
9519 i == Xboom_bug && j == 4 ? 4 :
9520 i == Xboom_bug && j == 5 ? 2 :
9521 i == Xboom_bug && j == 6 ? 2 :
9522 i == Xboom_bug && j == 7 ? 0 :
9523 i == Xboom_bomb && j == 1 ? 2 :
9524 i == Xboom_bomb && j == 2 ? 2 :
9525 i == Xboom_bomb && j == 3 ? 4 :
9526 i == Xboom_bomb && j == 4 ? 4 :
9527 i == Xboom_bomb && j == 5 ? 2 :
9528 i == Xboom_bomb && j == 6 ? 2 :
9529 i == Xboom_bomb && j == 7 ? 0 :
9530 i == Xboom_android && j == 7 ? 6 :
9531 i == Xboom_1 && j == 1 ? 2 :
9532 i == Xboom_1 && j == 2 ? 2 :
9533 i == Xboom_1 && j == 3 ? 4 :
9534 i == Xboom_1 && j == 4 ? 4 :
9535 i == Xboom_1 && j == 5 ? 6 :
9536 i == Xboom_1 && j == 6 ? 6 :
9537 i == Xboom_1 && j == 7 ? 8 :
9538 i == Xboom_2 && j == 0 ? 8 :
9539 i == Xboom_2 && j == 1 ? 8 :
9540 i == Xboom_2 && j == 2 ? 10 :
9541 i == Xboom_2 && j == 3 ? 10 :
9542 i == Xboom_2 && j == 4 ? 10 :
9543 i == Xboom_2 && j == 5 ? 12 :
9544 i == Xboom_2 && j == 6 ? 12 :
9545 i == Xboom_2 && j == 7 ? 12 :
9547 special_animation && j == 4 ? 3 :
9548 effective_action != action ? 0 :
9554 int xxx_effective_action;
9555 int xxx_has_action_graphics;
9558 int element = object_mapping[i].element_rnd;
9559 int action = object_mapping[i].action;
9560 int direction = object_mapping[i].direction;
9561 boolean is_backside = object_mapping[i].is_backside;
9563 boolean action_removing = (action == ACTION_DIGGING ||
9564 action == ACTION_SNAPPING ||
9565 action == ACTION_COLLECTING);
9567 boolean action_exploding = ((action == ACTION_EXPLODING ||
9568 action == ACTION_SMASHED_BY_ROCK ||
9569 action == ACTION_SMASHED_BY_SPRING) &&
9570 element != EL_DIAMOND);
9571 boolean action_active = (action == ACTION_ACTIVE);
9572 boolean action_other = (action == ACTION_OTHER);
9576 int effective_element = get_effective_element_EM(i, j);
9578 int effective_element = (j > 5 && i == Yacid_splash_eB ? EL_EMPTY :
9579 j > 5 && i == Yacid_splash_wB ? EL_EMPTY :
9581 i == Xdrip_stretch ? element :
9582 i == Xdrip_stretchB ? element :
9583 i == Ydrip_s1 ? element :
9584 i == Ydrip_s1B ? element :
9585 i == Xball_1B ? element :
9586 i == Xball_2 ? element :
9587 i == Xball_2B ? element :
9588 i == Yball_eat ? element :
9589 i == Ykey_1_eat ? element :
9590 i == Ykey_2_eat ? element :
9591 i == Ykey_3_eat ? element :
9592 i == Ykey_4_eat ? element :
9593 i == Ykey_5_eat ? element :
9594 i == Ykey_6_eat ? element :
9595 i == Ykey_7_eat ? element :
9596 i == Ykey_8_eat ? element :
9597 i == Ylenses_eat ? element :
9598 i == Ymagnify_eat ? element :
9599 i == Ygrass_eat ? element :
9600 i == Ydirt_eat ? element :
9601 i == Yemerald_stone ? EL_EMERALD :
9602 i == Ydiamond_stone ? EL_ROCK :
9603 i == Xsand_stonein_1 ? element :
9604 i == Xsand_stonein_2 ? element :
9605 i == Xsand_stonein_3 ? element :
9606 i == Xsand_stonein_4 ? element :
9607 is_backside ? EL_EMPTY :
9608 action_removing ? EL_EMPTY :
9611 int effective_action = (j < 7 ? action :
9612 i == Xdrip_stretch ? action :
9613 i == Xdrip_stretchB ? action :
9614 i == Ydrip_s1 ? action :
9615 i == Ydrip_s1B ? action :
9616 i == Xball_1B ? action :
9617 i == Xball_2 ? action :
9618 i == Xball_2B ? action :
9619 i == Yball_eat ? action :
9620 i == Ykey_1_eat ? action :
9621 i == Ykey_2_eat ? action :
9622 i == Ykey_3_eat ? action :
9623 i == Ykey_4_eat ? action :
9624 i == Ykey_5_eat ? action :
9625 i == Ykey_6_eat ? action :
9626 i == Ykey_7_eat ? action :
9627 i == Ykey_8_eat ? action :
9628 i == Ylenses_eat ? action :
9629 i == Ymagnify_eat ? action :
9630 i == Ygrass_eat ? action :
9631 i == Ydirt_eat ? action :
9632 i == Xsand_stonein_1 ? action :
9633 i == Xsand_stonein_2 ? action :
9634 i == Xsand_stonein_3 ? action :
9635 i == Xsand_stonein_4 ? action :
9636 i == Xsand_stoneout_1 ? action :
9637 i == Xsand_stoneout_2 ? action :
9638 i == Xboom_android ? ACTION_EXPLODING :
9639 action_exploding ? ACTION_EXPLODING :
9640 action_active ? action :
9641 action_other ? action :
9643 int graphic = (el_act_dir2img(effective_element, effective_action,
9645 int crumbled = (el_act_dir2crm(effective_element, effective_action,
9647 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
9648 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
9649 boolean has_action_graphics = (graphic != base_graphic);
9650 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
9651 struct GraphicInfo *g = &graphic_info[graphic];
9653 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
9655 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
9658 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
9659 boolean special_animation = (action != ACTION_DEFAULT &&
9660 g->anim_frames == 3 &&
9661 g->anim_delay == 2 &&
9662 g->anim_mode & ANIM_LINEAR);
9663 xxx_sync_frame = (i == Xdrip_stretch ? 7 :
9664 i == Xdrip_stretchB ? 7 :
9665 i == Ydrip_s2 ? j + 8 :
9666 i == Ydrip_s2B ? j + 8 :
9675 i == Xfake_acid_1 ? 0 :
9676 i == Xfake_acid_2 ? 10 :
9677 i == Xfake_acid_3 ? 20 :
9678 i == Xfake_acid_4 ? 30 :
9679 i == Xfake_acid_5 ? 40 :
9680 i == Xfake_acid_6 ? 50 :
9681 i == Xfake_acid_7 ? 60 :
9682 i == Xfake_acid_8 ? 70 :
9684 i == Xball_2B ? j + 8 :
9685 i == Yball_eat ? j + 1 :
9686 i == Ykey_1_eat ? j + 1 :
9687 i == Ykey_2_eat ? j + 1 :
9688 i == Ykey_3_eat ? j + 1 :
9689 i == Ykey_4_eat ? j + 1 :
9690 i == Ykey_5_eat ? j + 1 :
9691 i == Ykey_6_eat ? j + 1 :
9692 i == Ykey_7_eat ? j + 1 :
9693 i == Ykey_8_eat ? j + 1 :
9694 i == Ylenses_eat ? j + 1 :
9695 i == Ymagnify_eat ? j + 1 :
9696 i == Ygrass_eat ? j + 1 :
9697 i == Ydirt_eat ? j + 1 :
9698 i == Xamoeba_1 ? 0 :
9699 i == Xamoeba_2 ? 1 :
9700 i == Xamoeba_3 ? 2 :
9701 i == Xamoeba_4 ? 3 :
9702 i == Xamoeba_5 ? 0 :
9703 i == Xamoeba_6 ? 1 :
9704 i == Xamoeba_7 ? 2 :
9705 i == Xamoeba_8 ? 3 :
9706 i == Xexit_2 ? j + 8 :
9707 i == Xexit_3 ? j + 16 :
9708 i == Xdynamite_1 ? 0 :
9709 i == Xdynamite_2 ? 8 :
9710 i == Xdynamite_3 ? 16 :
9711 i == Xdynamite_4 ? 24 :
9712 i == Xsand_stonein_1 ? j + 1 :
9713 i == Xsand_stonein_2 ? j + 9 :
9714 i == Xsand_stonein_3 ? j + 17 :
9715 i == Xsand_stonein_4 ? j + 25 :
9716 i == Xsand_stoneout_1 && j == 0 ? 0 :
9717 i == Xsand_stoneout_1 && j == 1 ? 0 :
9718 i == Xsand_stoneout_1 && j == 2 ? 1 :
9719 i == Xsand_stoneout_1 && j == 3 ? 2 :
9720 i == Xsand_stoneout_1 && j == 4 ? 2 :
9721 i == Xsand_stoneout_1 && j == 5 ? 3 :
9722 i == Xsand_stoneout_1 && j == 6 ? 4 :
9723 i == Xsand_stoneout_1 && j == 7 ? 4 :
9724 i == Xsand_stoneout_2 && j == 0 ? 5 :
9725 i == Xsand_stoneout_2 && j == 1 ? 6 :
9726 i == Xsand_stoneout_2 && j == 2 ? 7 :
9727 i == Xsand_stoneout_2 && j == 3 ? 8 :
9728 i == Xsand_stoneout_2 && j == 4 ? 9 :
9729 i == Xsand_stoneout_2 && j == 5 ? 11 :
9730 i == Xsand_stoneout_2 && j == 6 ? 13 :
9731 i == Xsand_stoneout_2 && j == 7 ? 15 :
9732 i == Xboom_bug && j == 1 ? 2 :
9733 i == Xboom_bug && j == 2 ? 2 :
9734 i == Xboom_bug && j == 3 ? 4 :
9735 i == Xboom_bug && j == 4 ? 4 :
9736 i == Xboom_bug && j == 5 ? 2 :
9737 i == Xboom_bug && j == 6 ? 2 :
9738 i == Xboom_bug && j == 7 ? 0 :
9739 i == Xboom_bomb && j == 1 ? 2 :
9740 i == Xboom_bomb && j == 2 ? 2 :
9741 i == Xboom_bomb && j == 3 ? 4 :
9742 i == Xboom_bomb && j == 4 ? 4 :
9743 i == Xboom_bomb && j == 5 ? 2 :
9744 i == Xboom_bomb && j == 6 ? 2 :
9745 i == Xboom_bomb && j == 7 ? 0 :
9746 i == Xboom_android && j == 7 ? 6 :
9747 i == Xboom_1 && j == 1 ? 2 :
9748 i == Xboom_1 && j == 2 ? 2 :
9749 i == Xboom_1 && j == 3 ? 4 :
9750 i == Xboom_1 && j == 4 ? 4 :
9751 i == Xboom_1 && j == 5 ? 6 :
9752 i == Xboom_1 && j == 6 ? 6 :
9753 i == Xboom_1 && j == 7 ? 8 :
9754 i == Xboom_2 && j == 0 ? 8 :
9755 i == Xboom_2 && j == 1 ? 8 :
9756 i == Xboom_2 && j == 2 ? 10 :
9757 i == Xboom_2 && j == 3 ? 10 :
9758 i == Xboom_2 && j == 4 ? 10 :
9759 i == Xboom_2 && j == 5 ? 12 :
9760 i == Xboom_2 && j == 6 ? 12 :
9761 i == Xboom_2 && j == 7 ? 12 :
9762 special_animation && j == 4 ? 3 :
9763 effective_action != action ? 0 :
9766 xxx_effective_action = effective_action;
9767 xxx_has_action_graphics = has_action_graphics;
9772 int frame = getAnimationFrame(g->anim_frames,
9775 g->anim_start_frame,
9789 int old_src_x = g_em->src_x;
9790 int old_src_y = g_em->src_y;
9794 getGraphicSourceExt(graphic, frame, &g_em->bitmap, &g_em->src_x, &g_em->src_y,
9795 g->double_movement && is_backside);
9797 getGraphicSourceExt(graphic, frame, &g_em->bitmap,
9798 &g_em->src_x, &g_em->src_y, FALSE);
9803 if (tile == Ydiamond_stone)
9804 printf("::: stone smashing diamond... %d: %d, %d, %d, %d, %d -> %d [%d, %d, %d, %d, %d, %d] [%d]\n",
9809 g->anim_start_frame,
9812 g_em->src_x, g_em->src_y,
9813 g_em->src_offset_x, g_em->src_offset_y,
9814 g_em->dst_offset_x, g_em->dst_offset_y,
9826 if (graphic == IMG_BUG_MOVING_RIGHT)
9827 printf("::: %d, %d, %d: %d, %d [%d, %d -> %d, %d]\n", graphic, x, y,
9828 g->double_movement, is_backside,
9829 old_src_x, old_src_y, g_em->src_x, g_em->src_y);
9837 g_em->src_offset_x = 0;
9838 g_em->src_offset_y = 0;
9839 g_em->dst_offset_x = 0;
9840 g_em->dst_offset_y = 0;
9841 g_em->width = TILEX;
9842 g_em->height = TILEY;
9844 g_em->preserve_background = FALSE;
9847 /* (updating the "crumbled" graphic definitions is probably not really needed,
9848 as animations for crumbled graphics can't be longer than one EMC cycle) */
9850 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
9855 g_em->crumbled_bitmap = NULL;
9856 g_em->crumbled_src_x = 0;
9857 g_em->crumbled_src_y = 0;
9859 g_em->has_crumbled_graphics = FALSE;
9861 if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
9863 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
9864 g_crumbled->anim_delay,
9865 g_crumbled->anim_mode,
9866 g_crumbled->anim_start_frame,
9869 getGraphicSource(crumbled, frame_crumbled, &g_em->crumbled_bitmap,
9870 &g_em->crumbled_src_x, &g_em->crumbled_src_y);
9872 g_em->has_crumbled_graphics = TRUE;
9878 int effective_action = xxx_effective_action;
9879 int has_action_graphics = xxx_has_action_graphics;
9881 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
9882 effective_action == ACTION_MOVING ||
9883 effective_action == ACTION_PUSHING ||
9884 effective_action == ACTION_EATING)) ||
9885 (!has_action_graphics && (effective_action == ACTION_FILLING ||
9886 effective_action == ACTION_EMPTYING)))
9889 (effective_action == ACTION_FALLING ||
9890 effective_action == ACTION_FILLING ||
9891 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
9892 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
9893 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
9894 int num_steps = (i == Ydrip_s1 ? 16 :
9895 i == Ydrip_s1B ? 16 :
9896 i == Ydrip_s2 ? 16 :
9897 i == Ydrip_s2B ? 16 :
9898 i == Xsand_stonein_1 ? 32 :
9899 i == Xsand_stonein_2 ? 32 :
9900 i == Xsand_stonein_3 ? 32 :
9901 i == Xsand_stonein_4 ? 32 :
9902 i == Xsand_stoneout_1 ? 16 :
9903 i == Xsand_stoneout_2 ? 16 : 8);
9904 int cx = ABS(dx) * (TILEX / num_steps);
9905 int cy = ABS(dy) * (TILEY / num_steps);
9906 int step_frame = (i == Ydrip_s2 ? j + 8 :
9907 i == Ydrip_s2B ? j + 8 :
9908 i == Xsand_stonein_2 ? j + 8 :
9909 i == Xsand_stonein_3 ? j + 16 :
9910 i == Xsand_stonein_4 ? j + 24 :
9911 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
9912 int step = (is_backside ? step_frame : num_steps - step_frame);
9914 if (is_backside) /* tile where movement starts */
9916 if (dx < 0 || dy < 0)
9918 g_em->src_offset_x = cx * step;
9919 g_em->src_offset_y = cy * step;
9923 g_em->dst_offset_x = cx * step;
9924 g_em->dst_offset_y = cy * step;
9927 else /* tile where movement ends */
9929 if (dx < 0 || dy < 0)
9931 g_em->dst_offset_x = cx * step;
9932 g_em->dst_offset_y = cy * step;
9936 g_em->src_offset_x = cx * step;
9937 g_em->src_offset_y = cy * step;
9941 g_em->width = TILEX - cx * step;
9942 g_em->height = TILEY - cy * step;
9945 /* create unique graphic identifier to decide if tile must be redrawn */
9946 /* bit 31 - 16 (16 bit): EM style graphic
9947 bit 15 - 12 ( 4 bit): EM style frame
9948 bit 11 - 6 ( 6 bit): graphic width
9949 bit 5 - 0 ( 6 bit): graphic height */
9950 g_em->unique_identifier =
9951 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
9957 void getGraphicSourcePlayerExt_EM(struct GraphicInfo_EM *g_em,
9958 int player_nr, int anim, int frame_em)
9960 int element = player_mapping[player_nr][anim].element_rnd;
9961 int action = player_mapping[player_nr][anim].action;
9962 int direction = player_mapping[player_nr][anim].direction;
9963 int graphic = (direction == MV_NONE ?
9964 el_act2img(element, action) :
9965 el_act_dir2img(element, action, direction));
9966 struct GraphicInfo *g = &graphic_info[graphic];
9969 InitPlayerGfxAnimation(&stored_player[player_nr], action, direction);
9971 stored_player[player_nr].StepFrame = frame_em;
9973 sync_frame = stored_player[player_nr].Frame;
9975 int frame = getAnimationFrame(g->anim_frames,
9978 g->anim_start_frame,
9981 getGraphicSourceExt(graphic, frame, &g_em->bitmap,
9982 &g_em->src_x, &g_em->src_y, FALSE);
9985 printf("::: %d: %d, %d [%d]\n",
9987 stored_player[player_nr].Frame,
9988 stored_player[player_nr].StepFrame,
9993 void InitGraphicInfo_EM(void)
9996 struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
9997 struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
10002 int num_em_gfx_errors = 0;
10004 if (graphic_info_em_object[0][0].bitmap == NULL)
10006 /* EM graphics not yet initialized in em_open_all() */
10011 printf("::: [4 errors can be ignored (1 x 'bomb', 3 x 'em_dynamite']\n");
10014 /* always start with reliable default values */
10015 for (i = 0; i < TILE_MAX; i++)
10017 object_mapping[i].element_rnd = EL_UNKNOWN;
10018 object_mapping[i].is_backside = FALSE;
10019 object_mapping[i].action = ACTION_DEFAULT;
10020 object_mapping[i].direction = MV_NONE;
10023 /* always start with reliable default values */
10024 for (p = 0; p < MAX_PLAYERS; p++)
10026 for (i = 0; i < SPR_MAX; i++)
10028 player_mapping[p][i].element_rnd = EL_UNKNOWN;
10029 player_mapping[p][i].action = ACTION_DEFAULT;
10030 player_mapping[p][i].direction = MV_NONE;
10034 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
10036 int e = em_object_mapping_list[i].element_em;
10038 object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd;
10039 object_mapping[e].is_backside = em_object_mapping_list[i].is_backside;
10041 if (em_object_mapping_list[i].action != -1)
10042 object_mapping[e].action = em_object_mapping_list[i].action;
10044 if (em_object_mapping_list[i].direction != -1)
10045 object_mapping[e].direction =
10046 MV_DIR_FROM_BIT(em_object_mapping_list[i].direction);
10049 for (i = 0; em_player_mapping_list[i].action_em != -1; i++)
10051 int a = em_player_mapping_list[i].action_em;
10052 int p = em_player_mapping_list[i].player_nr;
10054 player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd;
10056 if (em_player_mapping_list[i].action != -1)
10057 player_mapping[p][a].action = em_player_mapping_list[i].action;
10059 if (em_player_mapping_list[i].direction != -1)
10060 player_mapping[p][a].direction =
10061 MV_DIR_FROM_BIT(em_player_mapping_list[i].direction);
10064 for (i = 0; i < TILE_MAX; i++)
10066 int element = object_mapping[i].element_rnd;
10067 int action = object_mapping[i].action;
10068 int direction = object_mapping[i].direction;
10069 boolean is_backside = object_mapping[i].is_backside;
10071 boolean action_removing = (action == ACTION_DIGGING ||
10072 action == ACTION_SNAPPING ||
10073 action == ACTION_COLLECTING);
10075 boolean action_exploding = ((action == ACTION_EXPLODING ||
10076 action == ACTION_SMASHED_BY_ROCK ||
10077 action == ACTION_SMASHED_BY_SPRING) &&
10078 element != EL_DIAMOND);
10079 boolean action_active = (action == ACTION_ACTIVE);
10080 boolean action_other = (action == ACTION_OTHER);
10082 for (j = 0; j < 8; j++)
10085 int effective_element = get_effective_element_EM(i, j);
10087 int effective_element = (j > 5 && i == Yacid_splash_eB ? EL_EMPTY :
10088 j > 5 && i == Yacid_splash_wB ? EL_EMPTY :
10090 i == Xdrip_stretch ? element :
10091 i == Xdrip_stretchB ? element :
10092 i == Ydrip_s1 ? element :
10093 i == Ydrip_s1B ? element :
10094 i == Xball_1B ? element :
10095 i == Xball_2 ? element :
10096 i == Xball_2B ? element :
10097 i == Yball_eat ? element :
10098 i == Ykey_1_eat ? element :
10099 i == Ykey_2_eat ? element :
10100 i == Ykey_3_eat ? element :
10101 i == Ykey_4_eat ? element :
10102 i == Ykey_5_eat ? element :
10103 i == Ykey_6_eat ? element :
10104 i == Ykey_7_eat ? element :
10105 i == Ykey_8_eat ? element :
10106 i == Ylenses_eat ? element :
10107 i == Ymagnify_eat ? element :
10108 i == Ygrass_eat ? element :
10109 i == Ydirt_eat ? element :
10110 i == Yemerald_stone ? EL_EMERALD :
10111 i == Ydiamond_stone ? EL_ROCK :
10112 i == Xsand_stonein_1 ? element :
10113 i == Xsand_stonein_2 ? element :
10114 i == Xsand_stonein_3 ? element :
10115 i == Xsand_stonein_4 ? element :
10116 is_backside ? EL_EMPTY :
10117 action_removing ? EL_EMPTY :
10120 int effective_action = (j < 7 ? action :
10121 i == Xdrip_stretch ? action :
10122 i == Xdrip_stretchB ? action :
10123 i == Ydrip_s1 ? action :
10124 i == Ydrip_s1B ? action :
10125 i == Xball_1B ? action :
10126 i == Xball_2 ? action :
10127 i == Xball_2B ? action :
10128 i == Yball_eat ? action :
10129 i == Ykey_1_eat ? action :
10130 i == Ykey_2_eat ? action :
10131 i == Ykey_3_eat ? action :
10132 i == Ykey_4_eat ? action :
10133 i == Ykey_5_eat ? action :
10134 i == Ykey_6_eat ? action :
10135 i == Ykey_7_eat ? action :
10136 i == Ykey_8_eat ? action :
10137 i == Ylenses_eat ? action :
10138 i == Ymagnify_eat ? action :
10139 i == Ygrass_eat ? action :
10140 i == Ydirt_eat ? action :
10141 i == Xsand_stonein_1 ? action :
10142 i == Xsand_stonein_2 ? action :
10143 i == Xsand_stonein_3 ? action :
10144 i == Xsand_stonein_4 ? action :
10145 i == Xsand_stoneout_1 ? action :
10146 i == Xsand_stoneout_2 ? action :
10147 i == Xboom_android ? ACTION_EXPLODING :
10148 action_exploding ? ACTION_EXPLODING :
10149 action_active ? action :
10150 action_other ? action :
10152 int graphic = (el_act_dir2img(effective_element, effective_action,
10154 int crumbled = (el_act_dir2crm(effective_element, effective_action,
10156 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
10157 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
10158 boolean has_action_graphics = (graphic != base_graphic);
10159 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
10160 struct GraphicInfo *g = &graphic_info[graphic];
10162 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
10164 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
10165 Bitmap *src_bitmap;
10167 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
10168 boolean special_animation = (action != ACTION_DEFAULT &&
10169 g->anim_frames == 3 &&
10170 g->anim_delay == 2 &&
10171 g->anim_mode & ANIM_LINEAR);
10172 int sync_frame = (i == Xdrip_stretch ? 7 :
10173 i == Xdrip_stretchB ? 7 :
10174 i == Ydrip_s2 ? j + 8 :
10175 i == Ydrip_s2B ? j + 8 :
10177 i == Xacid_2 ? 10 :
10178 i == Xacid_3 ? 20 :
10179 i == Xacid_4 ? 30 :
10180 i == Xacid_5 ? 40 :
10181 i == Xacid_6 ? 50 :
10182 i == Xacid_7 ? 60 :
10183 i == Xacid_8 ? 70 :
10184 i == Xfake_acid_1 ? 0 :
10185 i == Xfake_acid_2 ? 10 :
10186 i == Xfake_acid_3 ? 20 :
10187 i == Xfake_acid_4 ? 30 :
10188 i == Xfake_acid_5 ? 40 :
10189 i == Xfake_acid_6 ? 50 :
10190 i == Xfake_acid_7 ? 60 :
10191 i == Xfake_acid_8 ? 70 :
10193 i == Xball_2B ? j + 8 :
10194 i == Yball_eat ? j + 1 :
10195 i == Ykey_1_eat ? j + 1 :
10196 i == Ykey_2_eat ? j + 1 :
10197 i == Ykey_3_eat ? j + 1 :
10198 i == Ykey_4_eat ? j + 1 :
10199 i == Ykey_5_eat ? j + 1 :
10200 i == Ykey_6_eat ? j + 1 :
10201 i == Ykey_7_eat ? j + 1 :
10202 i == Ykey_8_eat ? j + 1 :
10203 i == Ylenses_eat ? j + 1 :
10204 i == Ymagnify_eat ? j + 1 :
10205 i == Ygrass_eat ? j + 1 :
10206 i == Ydirt_eat ? j + 1 :
10207 i == Xamoeba_1 ? 0 :
10208 i == Xamoeba_2 ? 1 :
10209 i == Xamoeba_3 ? 2 :
10210 i == Xamoeba_4 ? 3 :
10211 i == Xamoeba_5 ? 0 :
10212 i == Xamoeba_6 ? 1 :
10213 i == Xamoeba_7 ? 2 :
10214 i == Xamoeba_8 ? 3 :
10215 i == Xexit_2 ? j + 8 :
10216 i == Xexit_3 ? j + 16 :
10217 i == Xdynamite_1 ? 0 :
10218 i == Xdynamite_2 ? 8 :
10219 i == Xdynamite_3 ? 16 :
10220 i == Xdynamite_4 ? 24 :
10221 i == Xsand_stonein_1 ? j + 1 :
10222 i == Xsand_stonein_2 ? j + 9 :
10223 i == Xsand_stonein_3 ? j + 17 :
10224 i == Xsand_stonein_4 ? j + 25 :
10225 i == Xsand_stoneout_1 && j == 0 ? 0 :
10226 i == Xsand_stoneout_1 && j == 1 ? 0 :
10227 i == Xsand_stoneout_1 && j == 2 ? 1 :
10228 i == Xsand_stoneout_1 && j == 3 ? 2 :
10229 i == Xsand_stoneout_1 && j == 4 ? 2 :
10230 i == Xsand_stoneout_1 && j == 5 ? 3 :
10231 i == Xsand_stoneout_1 && j == 6 ? 4 :
10232 i == Xsand_stoneout_1 && j == 7 ? 4 :
10233 i == Xsand_stoneout_2 && j == 0 ? 5 :
10234 i == Xsand_stoneout_2 && j == 1 ? 6 :
10235 i == Xsand_stoneout_2 && j == 2 ? 7 :
10236 i == Xsand_stoneout_2 && j == 3 ? 8 :
10237 i == Xsand_stoneout_2 && j == 4 ? 9 :
10238 i == Xsand_stoneout_2 && j == 5 ? 11 :
10239 i == Xsand_stoneout_2 && j == 6 ? 13 :
10240 i == Xsand_stoneout_2 && j == 7 ? 15 :
10241 i == Xboom_bug && j == 1 ? 2 :
10242 i == Xboom_bug && j == 2 ? 2 :
10243 i == Xboom_bug && j == 3 ? 4 :
10244 i == Xboom_bug && j == 4 ? 4 :
10245 i == Xboom_bug && j == 5 ? 2 :
10246 i == Xboom_bug && j == 6 ? 2 :
10247 i == Xboom_bug && j == 7 ? 0 :
10248 i == Xboom_bomb && j == 1 ? 2 :
10249 i == Xboom_bomb && j == 2 ? 2 :
10250 i == Xboom_bomb && j == 3 ? 4 :
10251 i == Xboom_bomb && j == 4 ? 4 :
10252 i == Xboom_bomb && j == 5 ? 2 :
10253 i == Xboom_bomb && j == 6 ? 2 :
10254 i == Xboom_bomb && j == 7 ? 0 :
10255 i == Xboom_android && j == 7 ? 6 :
10256 i == Xboom_1 && j == 1 ? 2 :
10257 i == Xboom_1 && j == 2 ? 2 :
10258 i == Xboom_1 && j == 3 ? 4 :
10259 i == Xboom_1 && j == 4 ? 4 :
10260 i == Xboom_1 && j == 5 ? 6 :
10261 i == Xboom_1 && j == 6 ? 6 :
10262 i == Xboom_1 && j == 7 ? 8 :
10263 i == Xboom_2 && j == 0 ? 8 :
10264 i == Xboom_2 && j == 1 ? 8 :
10265 i == Xboom_2 && j == 2 ? 10 :
10266 i == Xboom_2 && j == 3 ? 10 :
10267 i == Xboom_2 && j == 4 ? 10 :
10268 i == Xboom_2 && j == 5 ? 12 :
10269 i == Xboom_2 && j == 6 ? 12 :
10270 i == Xboom_2 && j == 7 ? 12 :
10271 special_animation && j == 4 ? 3 :
10272 effective_action != action ? 0 :
10276 Bitmap *debug_bitmap = g_em->bitmap;
10277 int debug_src_x = g_em->src_x;
10278 int debug_src_y = g_em->src_y;
10281 int frame = getAnimationFrame(g->anim_frames,
10284 g->anim_start_frame,
10287 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y,
10288 g->double_movement && is_backside);
10290 g_em->bitmap = src_bitmap;
10291 g_em->src_x = src_x;
10292 g_em->src_y = src_y;
10293 g_em->src_offset_x = 0;
10294 g_em->src_offset_y = 0;
10295 g_em->dst_offset_x = 0;
10296 g_em->dst_offset_y = 0;
10297 g_em->width = TILEX;
10298 g_em->height = TILEY;
10300 g_em->preserve_background = FALSE;
10303 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
10308 g_em->crumbled_bitmap = NULL;
10309 g_em->crumbled_src_x = 0;
10310 g_em->crumbled_src_y = 0;
10311 g_em->crumbled_border_size = 0;
10313 g_em->has_crumbled_graphics = FALSE;
10316 if (has_crumbled_graphics && crumbled == IMG_EMPTY_SPACE)
10317 printf("::: empty crumbled: %d [%s], %d, %d\n",
10318 effective_element, element_info[effective_element].token_name,
10319 effective_action, direction);
10322 /* if element can be crumbled, but certain action graphics are just empty
10323 space (like instantly snapping sand to empty space in 1 frame), do not
10324 treat these empty space graphics as crumbled graphics in EMC engine */
10325 if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
10327 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
10328 g_crumbled->anim_delay,
10329 g_crumbled->anim_mode,
10330 g_crumbled->anim_start_frame,
10333 getGraphicSource(crumbled, frame_crumbled, &src_bitmap, &src_x, &src_y);
10335 g_em->has_crumbled_graphics = TRUE;
10336 g_em->crumbled_bitmap = src_bitmap;
10337 g_em->crumbled_src_x = src_x;
10338 g_em->crumbled_src_y = src_y;
10339 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
10343 if (g_em == &graphic_info_em_object[207][0])
10344 printf("... %d, %d [%d, %d, %d, %d] [%d, %d, %d, %d, %d, %d => %d]\n",
10345 graphic_info_em_object[207][0].crumbled_src_x,
10346 graphic_info_em_object[207][0].crumbled_src_y,
10348 crumbled, frame, src_x, src_y,
10353 g->anim_start_frame,
10355 gfx.anim_random_frame,
10360 printf("::: EMC tile %d is crumbled\n", i);
10366 if (element == EL_ROCK &&
10367 effective_action == ACTION_FILLING)
10368 printf("::: has_action_graphics == %d\n", has_action_graphics);
10371 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
10372 effective_action == ACTION_MOVING ||
10373 effective_action == ACTION_PUSHING ||
10374 effective_action == ACTION_EATING)) ||
10375 (!has_action_graphics && (effective_action == ACTION_FILLING ||
10376 effective_action == ACTION_EMPTYING)))
10379 (effective_action == ACTION_FALLING ||
10380 effective_action == ACTION_FILLING ||
10381 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
10382 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
10383 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
10384 int num_steps = (i == Ydrip_s1 ? 16 :
10385 i == Ydrip_s1B ? 16 :
10386 i == Ydrip_s2 ? 16 :
10387 i == Ydrip_s2B ? 16 :
10388 i == Xsand_stonein_1 ? 32 :
10389 i == Xsand_stonein_2 ? 32 :
10390 i == Xsand_stonein_3 ? 32 :
10391 i == Xsand_stonein_4 ? 32 :
10392 i == Xsand_stoneout_1 ? 16 :
10393 i == Xsand_stoneout_2 ? 16 : 8);
10394 int cx = ABS(dx) * (TILEX / num_steps);
10395 int cy = ABS(dy) * (TILEY / num_steps);
10396 int step_frame = (i == Ydrip_s2 ? j + 8 :
10397 i == Ydrip_s2B ? j + 8 :
10398 i == Xsand_stonein_2 ? j + 8 :
10399 i == Xsand_stonein_3 ? j + 16 :
10400 i == Xsand_stonein_4 ? j + 24 :
10401 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
10402 int step = (is_backside ? step_frame : num_steps - step_frame);
10404 if (is_backside) /* tile where movement starts */
10406 if (dx < 0 || dy < 0)
10408 g_em->src_offset_x = cx * step;
10409 g_em->src_offset_y = cy * step;
10413 g_em->dst_offset_x = cx * step;
10414 g_em->dst_offset_y = cy * step;
10417 else /* tile where movement ends */
10419 if (dx < 0 || dy < 0)
10421 g_em->dst_offset_x = cx * step;
10422 g_em->dst_offset_y = cy * step;
10426 g_em->src_offset_x = cx * step;
10427 g_em->src_offset_y = cy * step;
10431 g_em->width = TILEX - cx * step;
10432 g_em->height = TILEY - cy * step;
10435 /* create unique graphic identifier to decide if tile must be redrawn */
10436 /* bit 31 - 16 (16 bit): EM style graphic
10437 bit 15 - 12 ( 4 bit): EM style frame
10438 bit 11 - 6 ( 6 bit): graphic width
10439 bit 5 - 0 ( 6 bit): graphic height */
10440 g_em->unique_identifier =
10441 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
10445 /* skip check for EMC elements not contained in original EMC artwork */
10446 if (element == EL_EMC_FAKE_ACID)
10449 if (g_em->bitmap != debug_bitmap ||
10450 g_em->src_x != debug_src_x ||
10451 g_em->src_y != debug_src_y ||
10452 g_em->src_offset_x != 0 ||
10453 g_em->src_offset_y != 0 ||
10454 g_em->dst_offset_x != 0 ||
10455 g_em->dst_offset_y != 0 ||
10456 g_em->width != TILEX ||
10457 g_em->height != TILEY)
10459 static int last_i = -1;
10467 printf("::: EMC GFX ERROR for element %d -> %d ('%s', '%s', %d)",
10468 i, element, element_info[element].token_name,
10469 element_action_info[effective_action].suffix, direction);
10471 if (element != effective_element)
10472 printf(" [%d ('%s')]",
10474 element_info[effective_element].token_name);
10478 if (g_em->bitmap != debug_bitmap)
10479 printf(" %d (%d): different bitmap! (0x%08x != 0x%08x)\n",
10480 j, is_backside, (int)(g_em->bitmap), (int)(debug_bitmap));
10482 if (g_em->src_x != debug_src_x ||
10483 g_em->src_y != debug_src_y)
10484 printf(" frame %d (%c): %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
10485 j, (is_backside ? 'B' : 'F'),
10486 g_em->src_x, g_em->src_y,
10487 g_em->src_x / 32, g_em->src_y / 32,
10488 debug_src_x, debug_src_y,
10489 debug_src_x / 32, debug_src_y / 32);
10491 if (g_em->src_offset_x != 0 ||
10492 g_em->src_offset_y != 0 ||
10493 g_em->dst_offset_x != 0 ||
10494 g_em->dst_offset_y != 0)
10495 printf(" %d (%d): offsets %d,%d and %d,%d should be all 0\n",
10497 g_em->src_offset_x, g_em->src_offset_y,
10498 g_em->dst_offset_x, g_em->dst_offset_y);
10500 if (g_em->width != TILEX ||
10501 g_em->height != TILEY)
10502 printf(" %d (%d): size %d,%d should be %d,%d\n",
10504 g_em->width, g_em->height, TILEX, TILEY);
10506 num_em_gfx_errors++;
10513 for (i = 0; i < TILE_MAX; i++)
10515 for (j = 0; j < 8; j++)
10517 int element = object_mapping[i].element_rnd;
10518 int action = object_mapping[i].action;
10519 int direction = object_mapping[i].direction;
10520 boolean is_backside = object_mapping[i].is_backside;
10521 int graphic_action = el_act_dir2img(element, action, direction);
10522 int graphic_default = el_act_dir2img(element, ACTION_DEFAULT, direction);
10524 if ((action == ACTION_SMASHED_BY_ROCK ||
10525 action == ACTION_SMASHED_BY_SPRING ||
10526 action == ACTION_EATING) &&
10527 graphic_action == graphic_default)
10529 int e = (action == ACTION_SMASHED_BY_ROCK ? Ystone_s :
10530 action == ACTION_SMASHED_BY_SPRING ? Yspring_s :
10531 direction == MV_LEFT ? (is_backside? Yspring_wB: Yspring_w) :
10532 direction == MV_RIGHT ? (is_backside? Yspring_eB: Yspring_e) :
10535 /* no separate animation for "smashed by rock" -- use rock instead */
10536 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
10537 struct GraphicInfo_EM *g_xx = &graphic_info_em_object[e][7 - j];
10539 g_em->bitmap = g_xx->bitmap;
10540 g_em->src_x = g_xx->src_x;
10541 g_em->src_y = g_xx->src_y;
10542 g_em->src_offset_x = g_xx->src_offset_x;
10543 g_em->src_offset_y = g_xx->src_offset_y;
10544 g_em->dst_offset_x = g_xx->dst_offset_x;
10545 g_em->dst_offset_y = g_xx->dst_offset_y;
10546 g_em->width = g_xx->width;
10547 g_em->height = g_xx->height;
10548 g_em->unique_identifier = g_xx->unique_identifier;
10551 g_em->preserve_background = TRUE;
10556 for (p = 0; p < MAX_PLAYERS; p++)
10558 for (i = 0; i < SPR_MAX; i++)
10560 int element = player_mapping[p][i].element_rnd;
10561 int action = player_mapping[p][i].action;
10562 int direction = player_mapping[p][i].direction;
10564 for (j = 0; j < 8; j++)
10566 int effective_element = element;
10567 int effective_action = action;
10568 int graphic = (direction == MV_NONE ?
10569 el_act2img(effective_element, effective_action) :
10570 el_act_dir2img(effective_element, effective_action,
10572 struct GraphicInfo *g = &graphic_info[graphic];
10573 struct GraphicInfo_EM *g_em = &graphic_info_em_player[p][i][7 - j];
10574 Bitmap *src_bitmap;
10576 int sync_frame = j;
10579 Bitmap *debug_bitmap = g_em->bitmap;
10580 int debug_src_x = g_em->src_x;
10581 int debug_src_y = g_em->src_y;
10584 int frame = getAnimationFrame(g->anim_frames,
10587 g->anim_start_frame,
10590 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
10592 g_em->bitmap = src_bitmap;
10593 g_em->src_x = src_x;
10594 g_em->src_y = src_y;
10595 g_em->src_offset_x = 0;
10596 g_em->src_offset_y = 0;
10597 g_em->dst_offset_x = 0;
10598 g_em->dst_offset_y = 0;
10599 g_em->width = TILEX;
10600 g_em->height = TILEY;
10604 /* skip check for EMC elements not contained in original EMC artwork */
10605 if (element == EL_PLAYER_3 ||
10606 element == EL_PLAYER_4)
10609 if (g_em->bitmap != debug_bitmap ||
10610 g_em->src_x != debug_src_x ||
10611 g_em->src_y != debug_src_y)
10613 static int last_i = -1;
10621 printf("::: EMC GFX ERROR for p/a %d/%d -> %d ('%s', '%s', %d)",
10622 p, i, element, element_info[element].token_name,
10623 element_action_info[effective_action].suffix, direction);
10625 if (element != effective_element)
10626 printf(" [%d ('%s')]",
10628 element_info[effective_element].token_name);
10632 if (g_em->bitmap != debug_bitmap)
10633 printf(" %d: different bitmap! (0x%08x != 0x%08x)\n",
10634 j, (int)(g_em->bitmap), (int)(debug_bitmap));
10636 if (g_em->src_x != debug_src_x ||
10637 g_em->src_y != debug_src_y)
10638 printf(" frame %d: %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
10640 g_em->src_x, g_em->src_y,
10641 g_em->src_x / 32, g_em->src_y / 32,
10642 debug_src_x, debug_src_y,
10643 debug_src_x / 32, debug_src_y / 32);
10645 num_em_gfx_errors++;
10655 printf("::: [%d errors found]\n", num_em_gfx_errors);
10661 void CheckSingleStepMode_EM(byte action[MAX_PLAYERS], int frame,
10662 boolean any_player_moving,
10663 boolean player_is_dropping)
10665 if (tape.single_step && tape.recording && !tape.pausing)
10668 boolean active_players = FALSE;
10671 for (i = 0; i < MAX_PLAYERS; i++)
10672 if (action[i] != JOY_NO_ACTION)
10673 active_players = TRUE;
10677 if (frame == 0 && !player_is_dropping)
10678 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
10682 void CheckSingleStepMode_SP(boolean murphy_is_waiting,
10683 boolean murphy_is_dropping)
10686 printf("::: waiting: %d, dropping: %d\n",
10687 murphy_is_waiting, murphy_is_dropping);
10690 if (tape.single_step && tape.recording && !tape.pausing)
10692 // if (murphy_is_waiting || murphy_is_dropping)
10693 if (murphy_is_waiting)
10696 printf("::: murphy is waiting -> pause mode\n");
10699 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
10704 void getGraphicSource_SP(struct GraphicInfo_SP *g_sp,
10705 int graphic, int sync_frame, int x, int y)
10707 int frame = getGraphicAnimationFrame(graphic, sync_frame);
10709 getGraphicSource(graphic, frame, &g_sp->bitmap, &g_sp->src_x, &g_sp->src_y);
10712 boolean isNextAnimationFrame_SP(int graphic, int sync_frame)
10714 return (IS_NEXT_FRAME(sync_frame, graphic));
10717 int getGraphicInfo_Delay(int graphic)
10719 return graphic_info[graphic].anim_delay;
10722 void PlayMenuSoundExt(int sound)
10724 if (sound == SND_UNDEFINED)
10727 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
10728 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
10731 if (IS_LOOP_SOUND(sound))
10732 PlaySoundLoop(sound);
10737 void PlayMenuSound()
10739 PlayMenuSoundExt(menu.sound[game_status]);
10742 void PlayMenuSoundStereo(int sound, int stereo_position)
10744 if (sound == SND_UNDEFINED)
10747 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
10748 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
10751 if (IS_LOOP_SOUND(sound))
10752 PlaySoundExt(sound, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_LOOP);
10754 PlaySoundStereo(sound, stereo_position);
10757 void PlayMenuSoundIfLoopExt(int sound)
10759 if (sound == SND_UNDEFINED)
10762 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
10763 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
10766 if (IS_LOOP_SOUND(sound))
10767 PlaySoundLoop(sound);
10770 void PlayMenuSoundIfLoop()
10772 PlayMenuSoundIfLoopExt(menu.sound[game_status]);
10775 void PlayMenuMusicExt(int music)
10777 if (music == MUS_UNDEFINED)
10780 if (!setup.sound_music)
10786 void PlayMenuMusic()
10788 PlayMenuMusicExt(menu.music[game_status]);
10791 void PlaySoundActivating()
10794 PlaySound(SND_MENU_ITEM_ACTIVATING);
10798 void PlaySoundSelecting()
10801 PlaySound(SND_MENU_ITEM_SELECTING);
10805 void ToggleFullscreenOrChangeWindowScalingIfNeeded()
10807 boolean change_fullscreen = (setup.fullscreen !=
10808 video.fullscreen_enabled);
10809 boolean change_fullscreen_mode = (video.fullscreen_enabled &&
10810 !strEqual(setup.fullscreen_mode,
10811 video.fullscreen_mode_current));
10812 boolean change_window_scaling_percent = (!video.fullscreen_enabled &&
10813 setup.window_scaling_percent !=
10814 video.window_scaling_percent);
10816 if (change_window_scaling_percent && video.fullscreen_enabled)
10819 if (!change_window_scaling_percent && !video.fullscreen_available)
10822 #if defined(TARGET_SDL2)
10823 if (change_window_scaling_percent)
10825 SDLSetWindowScaling(setup.window_scaling_percent);
10829 else if (change_fullscreen)
10831 SDLSetWindowFullscreen(setup.fullscreen);
10833 /* set setup value according to successfully changed fullscreen mode */
10834 setup.fullscreen = video.fullscreen_enabled;
10840 if (change_fullscreen ||
10841 change_fullscreen_mode ||
10842 change_window_scaling_percent)
10844 Bitmap *tmp_backbuffer = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
10846 /* save backbuffer content which gets lost when toggling fullscreen mode */
10847 BlitBitmap(backbuffer, tmp_backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
10849 if (change_fullscreen_mode)
10851 /* keep fullscreen, but change fullscreen mode (screen resolution) */
10852 video.fullscreen_enabled = FALSE; /* force new fullscreen mode */
10855 if (change_window_scaling_percent)
10857 /* keep window mode, but change window scaling */
10858 video.fullscreen_enabled = TRUE; /* force new window scaling */
10861 /* toggle fullscreen */
10862 ChangeVideoModeIfNeeded(setup.fullscreen);
10864 /* set setup value according to successfully changed fullscreen mode */
10865 setup.fullscreen = video.fullscreen_enabled;
10867 /* restore backbuffer content from temporary backbuffer backup bitmap */
10868 BlitBitmap(tmp_backbuffer, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
10870 FreeBitmap(tmp_backbuffer);
10873 /* update visible window/screen */
10874 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
10876 redraw_mask = REDRAW_ALL;
10881 void ChangeViewportPropertiesIfNeeded()
10884 int *door_1_x = &DX;
10885 int *door_1_y = &DY;
10886 int *door_2_x = (game_status == GAME_MODE_EDITOR ? &EX : &VX);
10887 int *door_2_y = (game_status == GAME_MODE_EDITOR ? &EY : &VY);
10889 int gfx_game_mode = (game_status == GAME_MODE_PLAYING ||
10890 game_status == GAME_MODE_EDITOR ? game_status :
10892 int gfx_game_mode2 = (game_status == GAME_MODE_EDITOR ? GAME_MODE_DEFAULT :
10894 struct RectWithBorder *vp_playfield = &viewport.playfield[gfx_game_mode];
10895 struct RectWithBorder *vp_door_1 = &viewport.door_1[gfx_game_mode];
10896 struct RectWithBorder *vp_door_2 = &viewport.door_2[gfx_game_mode2];
10897 struct RectWithBorder *vp_door_3 = &viewport.door_2[GAME_MODE_EDITOR];
10898 int border_size = vp_playfield->border_size;
10899 int new_sx = vp_playfield->x + border_size;
10900 int new_sy = vp_playfield->y + border_size;
10901 int new_sxsize = vp_playfield->width - 2 * border_size;
10902 int new_sysize = vp_playfield->height - 2 * border_size;
10903 int new_real_sx = vp_playfield->x;
10904 int new_real_sy = vp_playfield->y;
10905 int new_full_sxsize = vp_playfield->width;
10906 int new_full_sysize = vp_playfield->height;
10907 int new_dx = vp_door_1->x;
10908 int new_dy = vp_door_1->y;
10909 int new_dxsize = vp_door_1->width;
10910 int new_dysize = vp_door_1->height;
10911 int new_vx = vp_door_2->x;
10912 int new_vy = vp_door_2->y;
10913 int new_vxsize = vp_door_2->width;
10914 int new_vysize = vp_door_2->height;
10915 int new_ex = vp_door_3->x;
10916 int new_ey = vp_door_3->y;
10917 int new_exsize = vp_door_3->width;
10918 int new_eysize = vp_door_3->height;
10920 int new_tilesize_var = TILESIZE / (setup.small_game_graphics ? 2 : 1);
10921 int tilesize = (gfx_game_mode == GAME_MODE_PLAYING ? new_tilesize_var :
10922 gfx_game_mode == GAME_MODE_EDITOR ? MINI_TILESIZE : TILESIZE);
10923 int new_scr_fieldx = new_sxsize / tilesize;
10924 int new_scr_fieldy = new_sysize / tilesize;
10925 int new_scr_fieldx_buffers = new_sxsize / new_tilesize_var;
10926 int new_scr_fieldy_buffers = new_sysize / new_tilesize_var;
10928 int new_scr_fieldx = (vp_playfield->width - 2 * border_size) / TILESIZE;
10929 int new_scr_fieldy = (vp_playfield->height - 2 * border_size) / TILESIZE;
10931 boolean init_gfx_buffers = FALSE;
10932 boolean init_video_buffer = FALSE;
10933 boolean init_gadgets_and_toons = FALSE;
10936 /* !!! TEST ONLY !!! */
10937 // InitGfxBuffers();
10941 if (viewport.window.width != WIN_XSIZE ||
10942 viewport.window.height != WIN_YSIZE)
10944 WIN_XSIZE = viewport.window.width;
10945 WIN_YSIZE = viewport.window.height;
10948 init_video_buffer = TRUE;
10949 init_gfx_buffers = TRUE;
10951 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
10955 SetDrawDeactivationMask(REDRAW_NONE);
10956 SetDrawBackgroundMask(REDRAW_FIELD);
10958 // RedrawBackground();
10962 // printf("::: video: init_video_buffer, init_gfx_buffers\n");
10965 if (new_scr_fieldx != SCR_FIELDX ||
10966 new_scr_fieldy != SCR_FIELDY)
10968 /* this always toggles between MAIN and GAME when using small tile size */
10970 SCR_FIELDX = new_scr_fieldx;
10971 SCR_FIELDY = new_scr_fieldy;
10973 // printf("::: new_scr_fieldx != SCR_FIELDX ...\n");
10977 if (new_tilesize_var != TILESIZE_VAR &&
10978 gfx_game_mode == GAME_MODE_PLAYING)
10980 /* doing this outside GAME_MODE_PLAYING would give wrong playfield size */
10982 TILESIZE_VAR = new_tilesize_var;
10984 init_gfx_buffers = TRUE;
10986 // printf("::: tilesize: init_gfx_buffers\n");
10990 if (new_sx != SX ||
10998 new_sxsize != SXSIZE ||
10999 new_sysize != SYSIZE ||
11000 new_dxsize != DXSIZE ||
11001 new_dysize != DYSIZE ||
11002 new_vxsize != VXSIZE ||
11003 new_vysize != VYSIZE ||
11004 new_exsize != EXSIZE ||
11005 new_eysize != EYSIZE ||
11006 new_real_sx != REAL_SX ||
11007 new_real_sy != REAL_SY ||
11008 new_full_sxsize != FULL_SXSIZE ||
11009 new_full_sysize != FULL_SYSIZE ||
11010 new_tilesize_var != TILESIZE_VAR
11013 vp_door_1->x != *door_1_x ||
11014 vp_door_1->y != *door_1_y ||
11015 vp_door_2->x != *door_2_x ||
11016 vp_door_2->y != *door_2_y
11028 SXSIZE = new_sxsize;
11029 SYSIZE = new_sysize;
11030 DXSIZE = new_dxsize;
11031 DYSIZE = new_dysize;
11032 VXSIZE = new_vxsize;
11033 VYSIZE = new_vysize;
11034 EXSIZE = new_exsize;
11035 EYSIZE = new_eysize;
11036 REAL_SX = new_real_sx;
11037 REAL_SY = new_real_sy;
11038 FULL_SXSIZE = new_full_sxsize;
11039 FULL_SYSIZE = new_full_sysize;
11040 TILESIZE_VAR = new_tilesize_var;
11043 printf("::: %d, %d, %d [%d]\n",
11044 SCR_FIELDX, SCR_FIELDY, TILESIZE_VAR,
11045 setup.small_game_graphics);
11049 *door_1_x = vp_door_1->x;
11050 *door_1_y = vp_door_1->y;
11051 *door_2_x = vp_door_2->x;
11052 *door_2_y = vp_door_2->y;
11056 init_gfx_buffers = TRUE;
11058 // printf("::: viewports: init_gfx_buffers\n");
11063 if (gfx_game_mode == GAME_MODE_MAIN)
11066 init_gadgets_and_toons = TRUE;
11068 // printf("::: viewports: init_gadgets_and_toons\n");
11076 if (init_gfx_buffers)
11078 // printf("::: init_gfx_buffers\n");
11080 SCR_FIELDX = new_scr_fieldx_buffers;
11081 SCR_FIELDY = new_scr_fieldy_buffers;
11085 SCR_FIELDX = new_scr_fieldx;
11086 SCR_FIELDY = new_scr_fieldy;
11089 if (init_video_buffer)
11091 // printf("::: init_video_buffer\n");
11093 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
11095 SetDrawDeactivationMask(REDRAW_NONE);
11096 SetDrawBackgroundMask(REDRAW_FIELD);
11099 if (init_gadgets_and_toons)
11101 // printf("::: init_gadgets_and_toons\n");
11108 printf("::: %d, %d / %d, %d [%d]\n", VX, VY, EX, EY, game_status);