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;
5414 unsigned int door_delay = 0;
5415 unsigned int door_delay_value;
5423 if (door_1.width < 0 || door_1.width > DXSIZE)
5424 door_1.width = DXSIZE;
5425 if (door_1.height < 0 || door_1.height > DYSIZE)
5426 door_1.height = DYSIZE;
5427 if (door_2.width < 0 || door_2.width > VXSIZE)
5428 door_2.width = VXSIZE;
5429 if (door_2.height < 0 || door_2.height > VYSIZE)
5430 door_2.height = VYSIZE;
5433 if (door_state == DOOR_GET_STATE)
5434 return (door1 | door2);
5436 if (door_state & DOOR_SET_STATE)
5438 if (door_state & DOOR_ACTION_1)
5439 door1 = door_state & DOOR_ACTION_1;
5440 if (door_state & DOOR_ACTION_2)
5441 door2 = door_state & DOOR_ACTION_2;
5443 return (door1 | door2);
5446 if (!(door_state & DOOR_FORCE_REDRAW))
5448 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
5449 door_state &= ~DOOR_OPEN_1;
5450 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
5451 door_state &= ~DOOR_CLOSE_1;
5452 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
5453 door_state &= ~DOOR_OPEN_2;
5454 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
5455 door_state &= ~DOOR_CLOSE_2;
5459 door_delay_value = (door_state & DOOR_ACTION_1 ? door_1.step_delay :
5462 if (setup.quick_doors)
5464 stepsize = 20; /* must be chosen to always draw last frame */
5465 door_delay_value = 0;
5469 if (global.autoplay_leveldir)
5471 door_state |= DOOR_NO_DELAY;
5472 door_state &= ~DOOR_CLOSE_ALL;
5476 if (game_status == GAME_MODE_EDITOR)
5477 door_state |= DOOR_NO_DELAY;
5480 if (door_state & DOOR_ACTION)
5482 boolean door_panel_drawn[NUM_DOORS];
5483 boolean door_part_done[MAX_DOOR_PARTS];
5484 boolean door_part_done_all;
5485 int num_xsteps[MAX_DOOR_PARTS];
5486 int num_ysteps[MAX_DOOR_PARTS];
5487 int max_move_delay = 0; // delay for complete animations of all doors
5488 int max_step_delay = 0; // delay (ms) between two animation frames
5489 int num_move_steps = 0; // number of animation steps for all doors
5490 int current_move_delay = 0;
5493 for (i = 0; i < MAX_DOOR_PARTS; i++)
5495 int nr = door_part_order[i].nr;
5496 struct DoorPartControlInfo *dpc = &door_part_controls[nr];
5497 struct GraphicInfo *g = &graphic_info[dpc->graphic];
5498 int door_token = dpc->door_nr;
5500 door_part_done[nr] = (!(door_state & door_token) ||
5504 for (i = 0; i < MAX_DOOR_PARTS; i++)
5506 struct DoorPartControlInfo *dpc = &door_part_controls[i];
5507 struct GraphicInfo *g = &graphic_info[dpc->graphic];
5508 struct DoorPartPosInfo *pos = dpc->pos;
5509 int step_xoffset = ABS(pos->step_xoffset);
5510 int step_yoffset = ABS(pos->step_yoffset);
5511 int step_delay = pos->step_delay;
5512 float move_xsize = (step_xoffset ? g->width : 0);
5513 float move_ysize = (step_yoffset ? g->height : 0);
5515 int move_size = (move_xsize && move_ysize ?
5516 MIN(move_xsize, move_ysize) :
5517 move_xsize ? move_xsize : move_ysize);
5519 int move_xsteps = (step_xoffset ? ceil(move_xsize / step_xoffset) : 0);
5520 int move_ysteps = (step_yoffset ? ceil(move_ysize / step_yoffset) : 0);
5522 int move_xdelay = move_xsteps * step_delay;
5523 int move_ydelay = move_ysteps * step_delay;
5524 int move_delay = (move_xdelay && move_ydelay ?
5525 MIN(move_xdelay, move_ydelay) :
5526 move_xdelay ? move_xdelay : move_ydelay);
5528 int move_steps = (move_xsteps && move_ysteps ?
5529 MIN(move_xsteps, move_ysteps) :
5530 move_xsteps ? move_xsteps : move_ysteps);
5531 int move_delay = move_steps * step_delay;
5532 // int move_delay = MAX(move_xsize, move_ysize) * step_delay;
5534 max_move_delay = MAX(max_move_delay, move_delay);
5535 max_step_delay = (max_step_delay == 0 ? step_delay :
5536 euclid(max_step_delay, step_delay));
5538 num_xsteps[i] = move_xsteps;
5539 num_ysteps[i] = move_ysteps;
5542 num_move_steps = max_move_delay / max_step_delay;
5544 door_delay_value = max_step_delay;
5547 door_delay_value *= 10;
5551 printf("::: max_move_delay == %d, max_step_delay == %d, num_move_steps == %d\n",
5552 max_move_delay, max_step_delay, num_move_steps);
5556 for (i = 0; i < MAX_DOOR_PARTS; i++)
5557 printf("::: door_part_done[%d] == %d\n", i, door_part_done[i]);
5561 for (k = 0; k < num_move_steps; k++)
5563 for (i = 0; i < NUM_DOORS; i++)
5564 door_panel_drawn[i] = FALSE;
5566 for (i = 0; i < MAX_DOOR_PARTS; i++)
5568 int nr = door_part_order[i].nr;
5569 struct DoorPartControlInfo *dpc = &door_part_controls[nr];
5570 int door_token = dpc->door_nr;
5571 int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
5572 struct GraphicInfo *g = &graphic_info[dpc->graphic];
5573 struct DoorPartPosInfo *pos = dpc->pos;
5574 struct XY *panel_pos = &panel_pos_list[door_index];
5575 struct Rect *door_rect = &door_rect_list[door_index];
5576 int step_delay = pos->step_delay;
5583 if (nr != 0 && nr != 8)
5587 if (door_part_done[nr])
5590 if (!(door_state & door_token))
5596 if (current_move_delay % step_delay)
5599 if (!door_panel_drawn[door_index])
5601 BlitBitmap(bitmap_db_door, drawto, panel_pos->x, panel_pos->y,
5602 door_rect->width, door_rect->height,
5603 door_rect->x, door_rect->y);
5605 door_panel_drawn[door_index] = TRUE;
5608 if ((door_state & door_token) & DOOR_OPEN)
5610 int step_factor = step_delay / max_step_delay;
5611 int kx = k / step_factor + 1;
5612 int ky = k / step_factor + 1;
5616 printf("::: kx == %d, ky == %d\n", kx, ky);
5619 if (pos->step_xoffset < 0)
5622 dst_xx = pos->x + ABS(kx * pos->step_xoffset);
5625 if (dst_xx + width > door_rect->width)
5626 width = door_rect->width - dst_xx;
5631 dst_xx = pos->x - kx * pos->step_xoffset;
5635 src_xx = ABS(dst_xx);
5639 width = g->width - src_xx;
5642 if (pos->step_yoffset < 0)
5645 dst_yy = pos->y + ABS(ky * pos->step_yoffset);
5648 if (dst_yy + height > door_rect->height)
5649 height = door_rect->height - dst_yy;
5654 dst_yy = pos->y - ky * pos->step_yoffset;
5658 src_yy = ABS(dst_yy);
5662 height = g->height - src_yy;
5666 if (width < 0 || height < 0)
5667 door_part_done[nr] = TRUE;
5672 int step_factor = step_delay / max_step_delay;
5673 int num_steps = (num_xsteps[nr] && num_ysteps[nr] ?
5674 MIN(num_xsteps[nr], num_ysteps[nr]) :
5675 num_xsteps[nr] ? num_xsteps[nr] :
5678 int kx = num_steps - k / step_factor - 1;
5679 int ky = num_steps - k / step_factor - 1;
5681 int kx = num_xsteps[nr] - k;
5682 int ky = num_ysteps[nr] - k;
5693 printf("::: kx == %d, ky == %d\n", kx, ky);
5698 printf("::: step_xoffset == %d, step_yoffset == %d\n",
5699 pos->step_xoffset, pos->step_yoffset);
5702 if (pos->step_xoffset < 0)
5705 dst_xx = pos->x + ABS(kx * pos->step_xoffset);
5708 if (dst_xx + width > door_rect->width)
5709 width = door_rect->width - dst_xx;
5714 dst_xx = pos->x - kx * pos->step_xoffset;
5718 src_xx = ABS(dst_xx);
5722 width = g->width - src_xx;
5725 if (pos->step_yoffset < 0)
5728 dst_yy = pos->y + ABS(ky * pos->step_yoffset);
5731 if (dst_yy + height > door_rect->height)
5732 height = door_rect->height - dst_yy;
5737 dst_yy = pos->y - ky * pos->step_yoffset;
5741 src_yy = ABS(dst_yy);
5745 height = g->height - src_yy;
5749 printf("::: src_xx, src_yy ; dst_xx, dst_yy ; width, height == %d, %d ; %d, %d ; %d, %d\n", src_xx, src_yy, dst_xx, dst_yy, width, height);
5753 if ((pos->step_xoffset != 0 && width >= g->width) ||
5754 (pos->step_yoffset != 0 && height >= g->height))
5755 door_part_done[nr] = TRUE;
5762 door_part_done[nr] = TRUE;
5764 BlitBitmapMasked(g->bitmap, drawto, g->src_x, g->src_y,
5765 g->width, g->height,
5766 door_rect->x + pos->x, door_rect->y + pos->y);
5768 redraw_mask |= REDRAW_DOOR_FROM_TOKEN(door_token);
5770 src_xx = (num_xsteps[nr] - k) * pos->step_xoffset;
5771 src_yy = (num_ysteps[nr] - k) * pos->step_yoffset;
5774 width = g->width - src_xx;
5775 height = g->height - src_yy;
5777 // if (width < ABS(pos->step_xoffset)
5782 src_xx = g->width - k * pos->step_xoffset;
5783 src_yy = g->height - k * pos->step_yoffset;
5787 if (width < 0 || height < 0)
5788 door_part_done[nr] = TRUE;
5793 if (door_part_done[nr])
5802 if (width >= 0 && width <= g->width &&
5803 height >= 0 && height <= g->height)
5804 BlitBitmapMasked(g->bitmap, drawto,
5805 g->src_x + src_xx, g->src_y + src_yy, width, height,
5806 door_rect->x + dst_xx, door_rect->y + dst_yy);
5808 // printf("::: %d: width == %d, height == %d\n", nr, width, height);
5810 redraw_mask |= REDRAW_DOOR_FROM_TOKEN(door_token);
5813 if ((((door_state & door_token) & DOOR_OPEN) &&
5814 (width < 0 || height < 0)) ||
5815 (((door_state & door_token) & DOOR_CLOSE) &&
5816 (width >= g->width && height >= g->height)))
5817 door_part_done[nr] = TRUE;
5819 if ((((door_state & door_token) & DOOR_OPEN) &&
5820 (width < 0 || height < 0)) ||
5821 (((door_state & door_token) & DOOR_CLOSE) &&
5822 ((pos->step_xoffset != 0 && width >= g->width) ||
5823 (pos->step_yoffset != 0 && height >= g->height))))
5824 door_part_done[nr] = TRUE;
5828 if (!(door_state & DOOR_NO_DELAY))
5832 if (game_status == GAME_MODE_MAIN)
5835 WaitUntilDelayReached(&door_delay, door_delay_value);
5837 current_move_delay += max_step_delay;
5840 door_part_done_all = TRUE;
5842 for (i = 0; i < MAX_DOOR_PARTS; i++)
5843 if (!door_part_done[i])
5844 door_part_done_all = FALSE;
5846 if (door_part_done_all)
5851 // redraw_mask |= REDRAW_ALL;
5853 if (door_state & DOOR_ACTION_1)
5854 door1 = door_state & DOOR_ACTION_1;
5855 if (door_state & DOOR_ACTION_2)
5856 door2 = door_state & DOOR_ACTION_2;
5858 return (door1 | door2);
5863 // ========== OLD ==============================================================
5865 unsigned int MoveDoor(unsigned int door_state)
5867 static int door1 = DOOR_OPEN_1;
5868 static int door2 = DOOR_CLOSE_2;
5869 unsigned int door_delay = 0;
5870 unsigned int door_delay_value;
5874 if (door_1.width < 0 || door_1.width > DXSIZE)
5875 door_1.width = DXSIZE;
5876 if (door_1.height < 0 || door_1.height > DYSIZE)
5877 door_1.height = DYSIZE;
5878 if (door_2.width < 0 || door_2.width > VXSIZE)
5879 door_2.width = VXSIZE;
5880 if (door_2.height < 0 || door_2.height > VYSIZE)
5881 door_2.height = VYSIZE;
5884 if (door_state == DOOR_GET_STATE)
5885 return (door1 | door2);
5887 if (door_state & DOOR_SET_STATE)
5889 if (door_state & DOOR_ACTION_1)
5890 door1 = door_state & DOOR_ACTION_1;
5891 if (door_state & DOOR_ACTION_2)
5892 door2 = door_state & DOOR_ACTION_2;
5894 return (door1 | door2);
5897 if (!(door_state & DOOR_FORCE_REDRAW))
5899 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
5900 door_state &= ~DOOR_OPEN_1;
5901 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
5902 door_state &= ~DOOR_CLOSE_1;
5903 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
5904 door_state &= ~DOOR_OPEN_2;
5905 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
5906 door_state &= ~DOOR_CLOSE_2;
5909 door_delay_value = (door_state & DOOR_ACTION_1 ? door_1.step_delay :
5912 // door_delay_value *= 4; // !!! TEST ONLY !!!
5914 if (setup.quick_doors)
5916 stepsize = 20; /* must be chosen to always draw last frame */
5917 door_delay_value = 0;
5920 if (global.autoplay_leveldir)
5922 door_state |= DOOR_NO_DELAY;
5923 door_state &= ~DOOR_CLOSE_ALL;
5927 if (game_status == GAME_MODE_EDITOR)
5928 door_state |= DOOR_NO_DELAY;
5931 if (door_state & DOOR_ACTION)
5934 struct GraphicInfo *g1_left = &graphic_info[IMG_DOOR_1_WING_LEFT];
5935 struct GraphicInfo *g1_right = &graphic_info[IMG_DOOR_1_WING_RIGHT];
5936 struct GraphicInfo *g2_left = &graphic_info[IMG_DOOR_2_WING_LEFT];
5937 struct GraphicInfo *g2_right = &graphic_info[IMG_DOOR_2_WING_RIGHT];
5938 int door_1_left_width = g1_left->width;
5939 int door_1_left_height = g1_left->height;
5940 int door_1_right_width = g1_right->width;
5941 int door_1_right_height = g1_right->height;
5942 int door_2_left_width = g2_left->width;
5943 int door_2_left_height = g2_left->height;
5944 int door_2_right_width = g2_right->width;
5945 int door_2_right_height = g2_right->height;
5946 int door_1_width = MAX(door_1_left_width, door_1_right_width);
5947 int door_1_height = MAX(door_1_left_height, door_1_right_height);
5948 int door_2_width = MAX(door_2_left_width, door_2_right_width);
5949 int door_2_height = MAX(door_2_left_height, door_2_right_height);
5951 boolean handle_door_1 = (door_state & DOOR_ACTION_1);
5952 boolean handle_door_2 = (door_state & DOOR_ACTION_2);
5953 boolean door_1_done = (!handle_door_1);
5954 boolean door_2_done = (!handle_door_2);
5955 boolean door_1_vertical = (door_1.anim_mode & ANIM_VERTICAL);
5956 boolean door_2_vertical = (door_2.anim_mode & ANIM_VERTICAL);
5959 int door_size_1 = (door_1_vertical ? door_1_height : door_1_width);
5960 int door_size_2 = (door_2_vertical ? door_2_height : door_2_width);
5962 int door_size_1 = (door_1_vertical ? DYSIZE : DXSIZE);
5963 int door_size_2 = (door_2_vertical ? VYSIZE : VXSIZE);
5966 int door_size_1 = (door_1_vertical ? door_1.height : door_1.width);
5967 int door_size_2 = (door_2_vertical ? door_2.height : door_2.width);
5969 int max_door_size_1 = (door_1_vertical ? DYSIZE : DXSIZE);
5970 int max_door_size_2 = (door_2_vertical ? VYSIZE : VXSIZE);
5971 // int door_size = (handle_door_1 ? door_size_1 : door_size_2);
5972 int door_size = (handle_door_2 ? door_size_2 : door_size_1);
5973 int max_door_size = (handle_door_1 ? max_door_size_1 : max_door_size_2);
5974 int door_skip = max_door_size - door_size;
5975 int end = door_size;
5976 int start = ((door_state & DOOR_NO_DELAY) ? end : 0);
5979 if (!(door_state & DOOR_NO_DELAY) && !setup.quick_doors)
5981 /* opening door sound has priority over simultaneously closing door */
5982 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
5983 PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
5984 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
5985 PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
5988 for (k = start; k <= end && !(door_1_done && door_2_done); k += stepsize)
5992 Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
5993 GC gc = bitmap->stored_clip_gc;
5996 if (door_state & DOOR_ACTION_1 &&
5997 x * door_1.step_offset <= door_size_1)
5999 int a = MIN(x * door_1.step_offset, end);
6000 int p = (door_state & DOOR_OPEN_1 ? end - a : a);
6004 int i = p + door_skip;
6008 struct GraphicInfo *g_left = &graphic_info[IMG_DOOR_1_WING_LEFT];
6009 struct GraphicInfo *g_right = &graphic_info[IMG_DOOR_1_WING_RIGHT];
6010 Bitmap *bm_left = g_left->bitmap;
6011 Bitmap *bm_right = g_right->bitmap;
6012 GC gc_left = bm_left->stored_clip_gc;
6013 GC gc_right = bm_right->stored_clip_gc;
6016 int classic_dxsize = 100;
6017 int classic_dysize = 280;
6018 boolean classic_door_1_size = (DXSIZE == classic_dxsize &&
6019 DYSIZE == classic_dysize);
6021 if (door_1.anim_mode & ANIM_STATIC_PANEL)
6023 BlitBitmap(bitmap_db_door, drawto,
6024 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1,
6025 DXSIZE, DYSIZE, DX, DY);
6029 BlitBitmap(bitmap_db_door, drawto,
6030 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + p / 2,
6031 DXSIZE, DYSIZE - p / 2, DX, DY);
6034 // printf("::: p == %d\n", p);
6035 ClearRectangle(drawto, DX, DY + DYSIZE - p / 2, DXSIZE, p / 2);
6039 if (door_1.anim_mode & ANIM_HORIZONTAL && x <= DXSIZE)
6042 int src1_x = g_right->src_x;
6043 int src1_y = g_right->src_y;
6044 int src2_x = g_left->src_x + g_left->width - i;
6045 int src2_y = g_left->src_y;
6046 int dst1_x = DX + DXSIZE - i;
6051 int height = DYSIZE;
6053 SetClipOrigin(bm_right, gc_right, dst1_x - src1_x, dst1_y - src1_y);
6054 BlitBitmapMasked(bm_right, drawto, src1_x, src1_y, width, height,
6057 SetClipOrigin(bm_left, gc_left, dst2_x - src2_x, dst2_y - src2_y);
6058 BlitBitmapMasked(bm_left, drawto, src2_x, src2_y, width, height,
6061 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
6062 int src2_x = DXSIZE - i, src2_y = DOOR_GFX_PAGEY1;
6063 int dst1_x = DX + DXSIZE - i, dst1_y = DY;
6064 int dst2_x = DX, dst2_y = DY;
6065 int width = i, height = DYSIZE;
6067 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
6068 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
6071 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
6072 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
6076 else if (door_1.anim_mode & ANIM_VERTICAL && x <= DYSIZE)
6079 int src1_x = g_right->src_x;
6080 int src1_y = g_right->src_y;
6081 int src2_x = g_left->src_x;
6082 int src2_y = g_left->src_y + g_left->height - i;
6084 int dst1_y = DY + DYSIZE - i;
6090 SetClipOrigin(bm_right, gc_right, dst1_x - src1_x, dst1_y - src1_y);
6091 BlitBitmapMasked(bm_right, drawto, src1_x, src1_y, width, height,
6094 SetClipOrigin(bm_left, gc_left, dst2_x - src2_x, dst2_y - src2_y);
6095 BlitBitmapMasked(bm_left, drawto, src2_x, src2_y, width, height,
6098 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
6099 int src2_x = 0, src2_y = DOOR_GFX_PAGEY1 + DYSIZE - i;
6100 int dst1_x = DX, dst1_y = DY + DYSIZE - i;
6101 int dst2_x = DX, dst2_y = DY;
6102 int width = DXSIZE, height = i;
6104 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
6105 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
6108 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
6109 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
6113 else if (classic_door_1_size && x <= DXSIZE) /* ANIM_DEFAULT */
6115 int j = (door_1.anim_mode == ANIM_DEFAULT ? (DXSIZE - i) / 3 : 0);
6118 int src1_x = g_right->src_x;
6119 int src1_y = g_right->src_y;
6120 int src2_x = g_left->src_x + g_left->width - i;
6121 int src2_y = g_left->src_y;
6122 int dst1_x = DX + DXSIZE - i;
6127 int height1 = 63, height2 = DYSIZE / 2 - height1;
6128 int ypos1 = 0, ypos2 = height2;
6129 int ypos3 = DYSIZE / 2, ypos4 = DYSIZE - height2;
6131 SetClipOrigin(bm_right, gc_right,
6132 dst1_x - src1_x, dst1_y - src1_y + j);
6133 BlitBitmapMasked(bm_right, drawto,
6134 src1_x, src1_y + ypos1, width, height2,
6135 dst1_x, dst1_y + ypos1 + j);
6136 BlitBitmapMasked(bm_right, drawto,
6137 src1_x, src1_y + ypos3, width, height1,
6138 dst1_x, dst1_y + ypos3 + j);
6139 SetClipOrigin(bm_left, gc_left,
6140 dst2_x - src2_x, dst2_y - src2_y - j);
6141 BlitBitmapMasked(bm_left, drawto,
6142 src2_x, src2_y + ypos1 + j, width, height2 - j,
6143 dst2_x, dst2_y + ypos1);
6144 BlitBitmapMasked(bm_left, drawto,
6145 src2_x, src2_y + ypos3, width, height1,
6146 dst2_x, dst2_y + ypos3 - j);
6148 SetClipOrigin(bm_left, gc_left,
6149 dst2_x - src2_x, dst2_y - src2_y - j);
6150 BlitBitmapMasked(bm_left, drawto,
6151 src2_x, src2_y + ypos2, width, height1,
6152 dst2_x, dst2_y + ypos2 - j);
6153 BlitBitmapMasked(bm_left, drawto,
6154 src2_x, src2_y + ypos4, width, height2,
6155 dst2_x, dst2_y + ypos4 - j);
6156 SetClipOrigin(bm_right, gc_right,
6157 dst1_x - src1_x, dst1_y - src1_y + j);
6158 BlitBitmapMasked(bm_right, drawto,
6159 src1_x, src1_y + ypos2, width, height1,
6160 dst1_x, dst1_y + ypos2 + j);
6161 BlitBitmapMasked(bm_right, drawto,
6162 src1_x, src1_y + ypos4, width, height2 - j,
6163 dst1_x, dst1_y + ypos4 + j);
6166 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
6167 int src2_x = DXSIZE - i, src2_y = DOOR_GFX_PAGEY1;
6168 int dst1_x = DX + DXSIZE - i, dst1_y = DY;
6169 int dst2_x = DX, dst2_y = DY;
6170 int width = i, height = DYSIZE;
6171 int ypos1 = 63, ypos2 = 77, ypos3 = 140, ypos4 = 203;
6173 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y + j);
6174 BlitBitmapMasked(bitmap, drawto,
6175 src1_x, src1_y, width, ypos2,
6176 dst1_x, dst1_y + j);
6177 BlitBitmapMasked(bitmap, drawto,
6178 src1_x, src1_y + ypos3, width, ypos1,
6179 dst1_x, dst1_y + ypos3 + j);
6180 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y - j);
6181 BlitBitmapMasked(bitmap, drawto,
6182 src2_x, src2_y + j, width, ypos2 - j,
6184 BlitBitmapMasked(bitmap, drawto,
6185 src2_x, src2_y + ypos3, width, ypos1,
6186 dst2_x, dst2_y + ypos3 - j);
6188 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y - j);
6189 BlitBitmapMasked(bitmap, drawto,
6190 src2_x, src2_y + ypos2, width, ypos1,
6191 dst2_x, dst2_y + ypos2 - j);
6192 BlitBitmapMasked(bitmap, drawto,
6193 src2_x, src2_y + ypos4, width, ypos2,
6194 dst2_x, dst2_y + ypos4 - j);
6195 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y + j);
6196 BlitBitmapMasked(bitmap, drawto,
6197 src1_x, src1_y + ypos2, width, ypos1,
6198 dst1_x, dst1_y + ypos2 + j);
6199 BlitBitmapMasked(bitmap, drawto,
6200 src1_x, src1_y + ypos4, width, ypos2 - j,
6201 dst1_x, dst1_y + ypos4 + j);
6204 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
6205 BlitBitmapMasked(bitmap, drawto,
6206 DXSIZE, DOOR_GFX_PAGEY1, i, 77,
6207 DX + DXSIZE - i, DY + j);
6208 BlitBitmapMasked(bitmap, drawto,
6209 DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
6210 DX + DXSIZE - i, DY + 140 + j);
6211 SetClipOrigin(bitmap, gc, DX - DXSIZE + i,
6212 DY - (DOOR_GFX_PAGEY1 + j));
6213 BlitBitmapMasked(bitmap, drawto,
6214 DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
6216 BlitBitmapMasked(bitmap, drawto,
6217 DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
6220 BlitBitmapMasked(bitmap, drawto,
6221 DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
6223 BlitBitmapMasked(bitmap, drawto,
6224 DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
6226 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
6227 BlitBitmapMasked(bitmap, drawto,
6228 DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
6229 DX + DXSIZE - i, DY + 77 + j);
6230 BlitBitmapMasked(bitmap, drawto,
6231 DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
6232 DX + DXSIZE - i, DY + 203 + j);
6237 redraw_mask |= REDRAW_DOOR_1;
6238 door_1_done = (a == end);
6241 if (door_state & DOOR_ACTION_2 &&
6242 x * door_2.step_offset <= door_size_2)
6244 int a = MIN(x * door_2.step_offset, door_size);
6245 int p = (door_state & DOOR_OPEN_2 ? door_size - a : a);
6246 int i = p + door_skip;
6249 struct GraphicInfo *g_left = &graphic_info[IMG_DOOR_2_WING_LEFT];
6250 struct GraphicInfo *g_right = &graphic_info[IMG_DOOR_2_WING_RIGHT];
6251 Bitmap *bm_left = g_left->bitmap;
6252 Bitmap *bm_right = g_right->bitmap;
6253 GC gc_left = bm_left->stored_clip_gc;
6254 GC gc_right = bm_right->stored_clip_gc;
6257 int classic_vxsize = 100;
6258 int classic_vysize = 100;
6259 boolean classic_door_2_size = (VXSIZE == classic_vxsize &&
6260 VYSIZE == classic_vysize);
6262 if (door_2.anim_mode & ANIM_STATIC_PANEL)
6264 BlitBitmap(bitmap_db_door, drawto,
6265 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2,
6266 VXSIZE, VYSIZE, VX, VY);
6268 else if (x <= VYSIZE)
6270 BlitBitmap(bitmap_db_door, drawto,
6271 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + p / 2,
6272 VXSIZE, VYSIZE - p / 2, VX, VY);
6274 ClearRectangle(drawto, VX, VY + VYSIZE - p / 2, VXSIZE, p / 2);
6277 if (door_2.anim_mode & ANIM_HORIZONTAL && x <= VXSIZE)
6280 int src1_x = g_right->src_x;
6281 int src1_y = g_right->src_y;
6282 int src2_x = g_left->src_x + g_left->width - i;
6283 int src2_y = g_left->src_y;
6284 int dst1_x = VX + VXSIZE - i;
6289 int height = VYSIZE;
6291 SetClipOrigin(bm_right, gc_right, dst1_x - src1_x, dst1_y - src1_y);
6292 BlitBitmapMasked(bm_right, drawto, src1_x, src1_y, width, height,
6295 SetClipOrigin(bm_left, gc_left, dst2_x - src2_x, dst2_y - src2_y);
6296 BlitBitmapMasked(bm_left, drawto, src2_x, src2_y, width, height,
6299 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
6300 int src2_x = VXSIZE - i, src2_y = DOOR_GFX_PAGEY2;
6301 int dst1_x = VX + VXSIZE - i, dst1_y = VY;
6302 int dst2_x = VX, dst2_y = VY;
6303 int width = i, height = VYSIZE;
6305 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
6306 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
6309 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
6310 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
6314 else if (door_2.anim_mode & ANIM_VERTICAL && x <= VYSIZE)
6317 int src1_x = g_right->src_x;
6318 int src1_y = g_right->src_y;
6319 int src2_x = g_left->src_x;
6320 int src2_y = g_left->src_y + g_left->height - i;
6322 int dst1_y = VY + VYSIZE - i;
6328 SetClipOrigin(bm_right, gc_right, dst1_x - src1_x, dst1_y - src1_y);
6329 BlitBitmapMasked(bm_right, drawto, src1_x, src1_y, width, height,
6332 SetClipOrigin(bm_left, gc_left, dst2_x - src2_x, dst2_y - src2_y);
6333 BlitBitmapMasked(bm_left, drawto, src2_x, src2_y, width, height,
6336 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
6337 int src2_x = 0, src2_y = DOOR_GFX_PAGEY2 + VYSIZE - i;
6338 int dst1_x = VX, dst1_y = VY + VYSIZE - i;
6339 int dst2_x = VX, dst2_y = VY;
6340 int width = VXSIZE, height = i;
6342 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
6343 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
6346 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
6347 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
6351 else if (classic_door_2_size && x <= VXSIZE) /* ANIM_DEFAULT */
6353 int j = (door_2.anim_mode == ANIM_DEFAULT ? (VXSIZE - i) / 3 : 0);
6356 int src1_x = g_right->src_x;
6357 int src1_y = g_right->src_y;
6358 int src2_x = g_left->src_x + g_left->width - i;
6359 int src2_y = g_left->src_y;
6360 int dst1_x = VX + VXSIZE - i;
6365 int height = VYSIZE / 2;
6366 int ypos1 = 0, ypos2 = VYSIZE / 2;
6368 SetClipOrigin(bm_right, gc_right,
6369 dst1_x - src1_x, dst1_y - src1_y + j);
6370 BlitBitmapMasked(bm_right, drawto,
6371 src1_x, src1_y + ypos1, width, height,
6372 dst1_x, dst1_y + ypos1 + j);
6373 SetClipOrigin(bm_left, gc_left,
6374 dst2_x - src2_x, dst2_y - src2_y - j);
6375 BlitBitmapMasked(bm_left, drawto,
6376 src2_x, src2_y + ypos1 + j, width, height - j,
6377 dst2_x, dst2_y + ypos1);
6379 SetClipOrigin(bm_left, gc_left,
6380 dst2_x - src2_x, dst2_y - src2_y - j);
6381 BlitBitmapMasked(bm_left, drawto,
6382 src2_x, src2_y + ypos2, width, height,
6383 dst2_x, dst2_y + ypos2 - j);
6384 SetClipOrigin(bm_right, gc_right,
6385 dst1_x - src1_x, dst1_y - src1_y + j);
6386 BlitBitmapMasked(bm_right, drawto,
6387 src1_x, src1_y + ypos2, width, height - j,
6388 dst1_x, dst1_y + ypos2 + j);
6390 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
6391 int src2_x = VXSIZE - i, src2_y = DOOR_GFX_PAGEY2;
6392 int dst1_x = VX + VXSIZE - i, dst1_y = VY;
6393 int dst2_x = VX, dst2_y = VY;
6394 int width = i, height = VYSIZE;
6395 int ypos = VYSIZE / 2;
6397 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y + j);
6398 BlitBitmapMasked(bitmap, drawto,
6399 src1_x, src1_y, width, ypos,
6400 dst1_x, dst1_y + j);
6401 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src1_y - j);
6402 BlitBitmapMasked(bitmap, drawto,
6403 src2_x, src2_y + j, width, ypos - j,
6406 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src1_y - j);
6407 BlitBitmapMasked(bitmap, drawto,
6408 src2_x, src2_y + ypos, width, ypos,
6409 dst2_x, dst2_y + ypos - j);
6410 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y + j);
6411 BlitBitmapMasked(bitmap, drawto,
6412 src1_x, src1_y + ypos, width, ypos - j,
6413 dst1_x, dst1_y + ypos + j);
6416 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
6417 BlitBitmapMasked(bitmap, drawto,
6418 VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
6419 VX + VXSIZE - i, VY + j);
6420 SetClipOrigin(bitmap, gc,
6421 VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
6422 BlitBitmapMasked(bitmap, drawto,
6423 VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
6426 BlitBitmapMasked(bitmap, drawto,
6427 VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
6428 i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
6429 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
6430 BlitBitmapMasked(bitmap, drawto,
6431 VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
6433 VX + VXSIZE - i, VY + VYSIZE / 2 + j);
6438 redraw_mask |= REDRAW_DOOR_2;
6439 door_2_done = (a == VXSIZE);
6442 if (!(door_state & DOOR_NO_DELAY))
6446 if (game_status == GAME_MODE_MAIN)
6449 WaitUntilDelayReached(&door_delay, door_delay_value);
6454 if (door_state & DOOR_ACTION_1)
6455 door1 = door_state & DOOR_ACTION_1;
6456 if (door_state & DOOR_ACTION_2)
6457 door2 = door_state & DOOR_ACTION_2;
6459 return (door1 | door2);
6464 void DrawSpecialEditorDoor()
6467 struct GraphicInfo *gfx1 = &graphic_info[IMG_DOOR_2_TOP_BORDER_CORRECTION];
6468 int top_border_width = gfx1->width;
6469 int top_border_height = gfx1->height;
6470 int outer_border = viewport.door_2[GAME_MODE_EDITOR].border_size;
6471 int ex = EX - outer_border;
6472 int ey = EY - outer_border;
6473 int vy = VY - outer_border;
6474 int exsize = EXSIZE + 2 * outer_border;
6476 CloseDoor(DOOR_CLOSE_2);
6478 /* draw bigger level editor toolbox window */
6479 BlitBitmap(gfx1->bitmap, drawto, gfx1->src_x, gfx1->src_y,
6480 top_border_width, top_border_height, ex, ey - top_border_height);
6481 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto, ex, vy,
6482 exsize, EYSIZE - VYSIZE + outer_border, ex, ey);
6484 /* draw bigger level editor toolbox window */
6485 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
6486 DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
6488 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
6489 EX - 6, VY - 4, EXSIZE + 12, EYSIZE - VYSIZE + 4,
6493 redraw_mask |= REDRAW_ALL;
6496 void UndrawSpecialEditorDoor()
6499 struct GraphicInfo *gfx1 = &graphic_info[IMG_DOOR_2_TOP_BORDER_CORRECTION];
6500 int top_border_width = gfx1->width;
6501 int top_border_height = gfx1->height;
6502 int outer_border = viewport.door_2[GAME_MODE_EDITOR].border_size;
6503 int ex = EX - outer_border;
6504 int ey = EY - outer_border;
6505 int ey_top = ey - top_border_height;
6506 int exsize = EXSIZE + 2 * outer_border;
6507 int eysize = EYSIZE + 2 * outer_border;
6509 /* draw normal tape recorder window */
6510 if (graphic_info[IMG_GLOBAL_BORDER].bitmap)
6512 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
6513 ex, ey_top, top_border_width, top_border_height,
6515 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
6516 ex, ey, exsize, eysize, ex, ey);
6520 // if screen background is set to "[NONE]", clear editor toolbox window
6521 ClearRectangle(drawto, ex, ey_top, top_border_width, top_border_height);
6522 ClearRectangle(drawto, ex, ey, exsize, eysize);
6525 /* draw normal tape recorder window */
6526 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
6527 EX - 6, EY - 12, EXSIZE + 12, EYSIZE - VYSIZE + 12,
6531 redraw_mask |= REDRAW_ALL;
6535 /* ---------- new tool button stuff ---------------------------------------- */
6542 struct TextPosInfo *pos;
6545 } toolbutton_info[NUM_TOOL_BUTTONS] =
6548 IMG_REQUEST_BUTTON_GFX_YES, &request.button.yes,
6549 TOOL_CTRL_ID_YES, "yes"
6552 IMG_REQUEST_BUTTON_GFX_NO, &request.button.no,
6553 TOOL_CTRL_ID_NO, "no"
6556 IMG_REQUEST_BUTTON_GFX_CONFIRM, &request.button.confirm,
6557 TOOL_CTRL_ID_CONFIRM, "confirm"
6560 IMG_REQUEST_BUTTON_GFX_PLAYER_1, &request.button.player_1,
6561 TOOL_CTRL_ID_PLAYER_1, "player 1"
6564 IMG_REQUEST_BUTTON_GFX_PLAYER_2, &request.button.player_2,
6565 TOOL_CTRL_ID_PLAYER_2, "player 2"
6568 IMG_REQUEST_BUTTON_GFX_PLAYER_3, &request.button.player_3,
6569 TOOL_CTRL_ID_PLAYER_3, "player 3"
6572 IMG_REQUEST_BUTTON_GFX_PLAYER_4, &request.button.player_4,
6573 TOOL_CTRL_ID_PLAYER_4, "player 4"
6577 void CreateToolButtons()
6581 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
6583 struct GraphicInfo *gfx = &graphic_info[toolbutton_info[i].graphic];
6584 struct TextPosInfo *pos = toolbutton_info[i].pos;
6585 struct GadgetInfo *gi;
6586 Bitmap *deco_bitmap = None;
6587 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
6588 unsigned int event_mask = GD_EVENT_RELEASED;
6591 int gd_x = gfx->src_x;
6592 int gd_y = gfx->src_y;
6593 int gd_xp = gfx->src_x + gfx->pressed_xoffset;
6594 int gd_yp = gfx->src_y + gfx->pressed_yoffset;
6597 if (global.use_envelope_request)
6598 setRequestPosition(&dx, &dy, TRUE);
6600 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
6602 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
6604 getSizedGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr), 0,
6605 pos->size, &deco_bitmap, &deco_x, &deco_y);
6606 deco_xpos = (gfx->width - pos->size) / 2;
6607 deco_ypos = (gfx->height - pos->size) / 2;
6610 gi = CreateGadget(GDI_CUSTOM_ID, id,
6611 GDI_INFO_TEXT, toolbutton_info[i].infotext,
6614 GDI_WIDTH, gfx->width,
6615 GDI_HEIGHT, gfx->height,
6616 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
6617 GDI_STATE, GD_BUTTON_UNPRESSED,
6618 GDI_DESIGN_UNPRESSED, gfx->bitmap, gd_x, gd_y,
6619 GDI_DESIGN_PRESSED, gfx->bitmap, gd_xp, gd_yp,
6620 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
6621 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
6622 GDI_DECORATION_SIZE, pos->size, pos->size,
6623 GDI_DECORATION_SHIFTING, 1, 1,
6624 GDI_DIRECT_DRAW, FALSE,
6625 GDI_EVENT_MASK, event_mask,
6626 GDI_CALLBACK_ACTION, HandleToolButtons,
6630 Error(ERR_EXIT, "cannot create gadget");
6632 tool_gadget[id] = gi;
6638 /* graphic position values for tool buttons */
6639 #define TOOL_BUTTON_YES_XPOS 2
6640 #define TOOL_BUTTON_YES_YPOS 250
6641 #define TOOL_BUTTON_YES_GFX_YPOS 0
6642 #define TOOL_BUTTON_YES_XSIZE 46
6643 #define TOOL_BUTTON_YES_YSIZE 28
6644 #define TOOL_BUTTON_NO_XPOS 52
6645 #define TOOL_BUTTON_NO_YPOS TOOL_BUTTON_YES_YPOS
6646 #define TOOL_BUTTON_NO_GFX_YPOS TOOL_BUTTON_YES_GFX_YPOS
6647 #define TOOL_BUTTON_NO_XSIZE TOOL_BUTTON_YES_XSIZE
6648 #define TOOL_BUTTON_NO_YSIZE TOOL_BUTTON_YES_YSIZE
6649 #define TOOL_BUTTON_CONFIRM_XPOS TOOL_BUTTON_YES_XPOS
6650 #define TOOL_BUTTON_CONFIRM_YPOS TOOL_BUTTON_YES_YPOS
6651 #define TOOL_BUTTON_CONFIRM_GFX_YPOS 30
6652 #define TOOL_BUTTON_CONFIRM_XSIZE 96
6653 #define TOOL_BUTTON_CONFIRM_YSIZE TOOL_BUTTON_YES_YSIZE
6654 #define TOOL_BUTTON_PLAYER_XSIZE 30
6655 #define TOOL_BUTTON_PLAYER_YSIZE 30
6656 #define TOOL_BUTTON_PLAYER_GFX_XPOS 5
6657 #define TOOL_BUTTON_PLAYER_GFX_YPOS 185
6658 #define TOOL_BUTTON_PLAYER_XPOS (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
6659 #define TOOL_BUTTON_PLAYER_YPOS (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
6660 #define TOOL_BUTTON_PLAYER1_XPOS (TOOL_BUTTON_PLAYER_XPOS \
6661 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
6662 #define TOOL_BUTTON_PLAYER2_XPOS (TOOL_BUTTON_PLAYER_XPOS \
6663 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
6664 #define TOOL_BUTTON_PLAYER3_XPOS (TOOL_BUTTON_PLAYER_XPOS \
6665 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
6666 #define TOOL_BUTTON_PLAYER4_XPOS (TOOL_BUTTON_PLAYER_XPOS \
6667 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
6668 #define TOOL_BUTTON_PLAYER1_YPOS (TOOL_BUTTON_PLAYER_YPOS \
6669 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
6670 #define TOOL_BUTTON_PLAYER2_YPOS (TOOL_BUTTON_PLAYER_YPOS \
6671 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
6672 #define TOOL_BUTTON_PLAYER3_YPOS (TOOL_BUTTON_PLAYER_YPOS \
6673 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
6674 #define TOOL_BUTTON_PLAYER4_YPOS (TOOL_BUTTON_PLAYER_YPOS \
6675 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
6684 } toolbutton_info[NUM_TOOL_BUTTONS] =
6687 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_GFX_YPOS,
6688 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_YPOS,
6689 TOOL_BUTTON_YES_XSIZE, TOOL_BUTTON_YES_YSIZE,
6694 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_GFX_YPOS,
6695 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_YPOS,
6696 TOOL_BUTTON_NO_XSIZE, TOOL_BUTTON_NO_YSIZE,
6701 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_GFX_YPOS,
6702 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_YPOS,
6703 TOOL_BUTTON_CONFIRM_XSIZE, TOOL_BUTTON_CONFIRM_YSIZE,
6704 TOOL_CTRL_ID_CONFIRM,
6708 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
6709 TOOL_BUTTON_PLAYER1_XPOS, TOOL_BUTTON_PLAYER1_YPOS,
6710 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
6711 TOOL_CTRL_ID_PLAYER_1,
6715 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
6716 TOOL_BUTTON_PLAYER2_XPOS, TOOL_BUTTON_PLAYER2_YPOS,
6717 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
6718 TOOL_CTRL_ID_PLAYER_2,
6722 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
6723 TOOL_BUTTON_PLAYER3_XPOS, TOOL_BUTTON_PLAYER3_YPOS,
6724 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
6725 TOOL_CTRL_ID_PLAYER_3,
6729 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
6730 TOOL_BUTTON_PLAYER4_XPOS, TOOL_BUTTON_PLAYER4_YPOS,
6731 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
6732 TOOL_CTRL_ID_PLAYER_4,
6737 void CreateToolButtons()
6741 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
6743 Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
6744 Bitmap *deco_bitmap = None;
6745 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
6746 struct GadgetInfo *gi;
6747 unsigned int event_mask;
6748 int gd_xoffset, gd_yoffset;
6749 int gd_x1, gd_x2, gd_y;
6752 event_mask = GD_EVENT_RELEASED;
6754 gd_xoffset = toolbutton_info[i].xpos;
6755 gd_yoffset = toolbutton_info[i].ypos;
6756 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
6757 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
6758 gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
6760 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
6762 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
6764 getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr),
6765 &deco_bitmap, &deco_x, &deco_y);
6766 deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
6767 deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
6770 gi = CreateGadget(GDI_CUSTOM_ID, id,
6771 GDI_INFO_TEXT, toolbutton_info[i].infotext,
6772 GDI_X, DX + toolbutton_info[i].x,
6773 GDI_Y, DY + toolbutton_info[i].y,
6774 GDI_WIDTH, toolbutton_info[i].width,
6775 GDI_HEIGHT, toolbutton_info[i].height,
6776 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
6777 GDI_STATE, GD_BUTTON_UNPRESSED,
6778 GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
6779 GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
6780 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
6781 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
6782 GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
6783 GDI_DECORATION_SHIFTING, 1, 1,
6784 GDI_DIRECT_DRAW, FALSE,
6785 GDI_EVENT_MASK, event_mask,
6786 GDI_CALLBACK_ACTION, HandleToolButtons,
6790 Error(ERR_EXIT, "cannot create gadget");
6792 tool_gadget[id] = gi;
6798 void FreeToolButtons()
6802 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
6803 FreeGadget(tool_gadget[i]);
6806 static void UnmapToolButtons()
6810 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
6811 UnmapGadget(tool_gadget[i]);
6814 static void HandleToolButtons(struct GadgetInfo *gi)
6816 request_gadget_id = gi->custom_id;
6819 static struct Mapping_EM_to_RND_object
6822 boolean is_rnd_to_em_mapping; /* unique mapping EM <-> RND */
6823 boolean is_backside; /* backside of moving element */
6829 em_object_mapping_list[] =
6832 Xblank, TRUE, FALSE,
6836 Yacid_splash_eB, FALSE, FALSE,
6837 EL_ACID_SPLASH_RIGHT, -1, -1
6840 Yacid_splash_wB, FALSE, FALSE,
6841 EL_ACID_SPLASH_LEFT, -1, -1
6844 #ifdef EM_ENGINE_BAD_ROLL
6846 Xstone_force_e, FALSE, FALSE,
6847 EL_ROCK, -1, MV_BIT_RIGHT
6850 Xstone_force_w, FALSE, FALSE,
6851 EL_ROCK, -1, MV_BIT_LEFT
6854 Xnut_force_e, FALSE, FALSE,
6855 EL_NUT, -1, MV_BIT_RIGHT
6858 Xnut_force_w, FALSE, FALSE,
6859 EL_NUT, -1, MV_BIT_LEFT
6862 Xspring_force_e, FALSE, FALSE,
6863 EL_SPRING, -1, MV_BIT_RIGHT
6866 Xspring_force_w, FALSE, FALSE,
6867 EL_SPRING, -1, MV_BIT_LEFT
6870 Xemerald_force_e, FALSE, FALSE,
6871 EL_EMERALD, -1, MV_BIT_RIGHT
6874 Xemerald_force_w, FALSE, FALSE,
6875 EL_EMERALD, -1, MV_BIT_LEFT
6878 Xdiamond_force_e, FALSE, FALSE,
6879 EL_DIAMOND, -1, MV_BIT_RIGHT
6882 Xdiamond_force_w, FALSE, FALSE,
6883 EL_DIAMOND, -1, MV_BIT_LEFT
6886 Xbomb_force_e, FALSE, FALSE,
6887 EL_BOMB, -1, MV_BIT_RIGHT
6890 Xbomb_force_w, FALSE, FALSE,
6891 EL_BOMB, -1, MV_BIT_LEFT
6893 #endif /* EM_ENGINE_BAD_ROLL */
6896 Xstone, TRUE, FALSE,
6900 Xstone_pause, FALSE, FALSE,
6904 Xstone_fall, FALSE, FALSE,
6908 Ystone_s, FALSE, FALSE,
6909 EL_ROCK, ACTION_FALLING, -1
6912 Ystone_sB, FALSE, TRUE,
6913 EL_ROCK, ACTION_FALLING, -1
6916 Ystone_e, FALSE, FALSE,
6917 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
6920 Ystone_eB, FALSE, TRUE,
6921 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
6924 Ystone_w, FALSE, FALSE,
6925 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
6928 Ystone_wB, FALSE, TRUE,
6929 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
6936 Xnut_pause, FALSE, FALSE,
6940 Xnut_fall, FALSE, FALSE,
6944 Ynut_s, FALSE, FALSE,
6945 EL_NUT, ACTION_FALLING, -1
6948 Ynut_sB, FALSE, TRUE,
6949 EL_NUT, ACTION_FALLING, -1
6952 Ynut_e, FALSE, FALSE,
6953 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
6956 Ynut_eB, FALSE, TRUE,
6957 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
6960 Ynut_w, FALSE, FALSE,
6961 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
6964 Ynut_wB, FALSE, TRUE,
6965 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
6968 Xbug_n, TRUE, FALSE,
6972 Xbug_e, TRUE, FALSE,
6973 EL_BUG_RIGHT, -1, -1
6976 Xbug_s, TRUE, FALSE,
6980 Xbug_w, TRUE, FALSE,
6984 Xbug_gon, FALSE, FALSE,
6988 Xbug_goe, FALSE, FALSE,
6989 EL_BUG_RIGHT, -1, -1
6992 Xbug_gos, FALSE, FALSE,
6996 Xbug_gow, FALSE, FALSE,
7000 Ybug_n, FALSE, FALSE,
7001 EL_BUG, ACTION_MOVING, MV_BIT_UP
7004 Ybug_nB, FALSE, TRUE,
7005 EL_BUG, ACTION_MOVING, MV_BIT_UP
7008 Ybug_e, FALSE, FALSE,
7009 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
7012 Ybug_eB, FALSE, TRUE,
7013 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
7016 Ybug_s, FALSE, FALSE,
7017 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
7020 Ybug_sB, FALSE, TRUE,
7021 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
7024 Ybug_w, FALSE, FALSE,
7025 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
7028 Ybug_wB, FALSE, TRUE,
7029 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
7032 Ybug_w_n, FALSE, FALSE,
7033 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
7036 Ybug_n_e, FALSE, FALSE,
7037 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
7040 Ybug_e_s, FALSE, FALSE,
7041 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
7044 Ybug_s_w, FALSE, FALSE,
7045 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
7048 Ybug_e_n, FALSE, FALSE,
7049 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
7052 Ybug_s_e, FALSE, FALSE,
7053 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
7056 Ybug_w_s, FALSE, FALSE,
7057 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
7060 Ybug_n_w, FALSE, FALSE,
7061 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
7064 Ybug_stone, FALSE, FALSE,
7065 EL_BUG, ACTION_SMASHED_BY_ROCK, -1
7068 Ybug_spring, FALSE, FALSE,
7069 EL_BUG, ACTION_SMASHED_BY_SPRING, -1
7072 Xtank_n, TRUE, FALSE,
7073 EL_SPACESHIP_UP, -1, -1
7076 Xtank_e, TRUE, FALSE,
7077 EL_SPACESHIP_RIGHT, -1, -1
7080 Xtank_s, TRUE, FALSE,
7081 EL_SPACESHIP_DOWN, -1, -1
7084 Xtank_w, TRUE, FALSE,
7085 EL_SPACESHIP_LEFT, -1, -1
7088 Xtank_gon, FALSE, FALSE,
7089 EL_SPACESHIP_UP, -1, -1
7092 Xtank_goe, FALSE, FALSE,
7093 EL_SPACESHIP_RIGHT, -1, -1
7096 Xtank_gos, FALSE, FALSE,
7097 EL_SPACESHIP_DOWN, -1, -1
7100 Xtank_gow, FALSE, FALSE,
7101 EL_SPACESHIP_LEFT, -1, -1
7104 Ytank_n, FALSE, FALSE,
7105 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
7108 Ytank_nB, FALSE, TRUE,
7109 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
7112 Ytank_e, FALSE, FALSE,
7113 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
7116 Ytank_eB, FALSE, TRUE,
7117 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
7120 Ytank_s, FALSE, FALSE,
7121 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
7124 Ytank_sB, FALSE, TRUE,
7125 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
7128 Ytank_w, FALSE, FALSE,
7129 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
7132 Ytank_wB, FALSE, TRUE,
7133 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
7136 Ytank_w_n, FALSE, FALSE,
7137 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
7140 Ytank_n_e, FALSE, FALSE,
7141 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
7144 Ytank_e_s, FALSE, FALSE,
7145 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
7148 Ytank_s_w, FALSE, FALSE,
7149 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
7152 Ytank_e_n, FALSE, FALSE,
7153 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
7156 Ytank_s_e, FALSE, FALSE,
7157 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
7160 Ytank_w_s, FALSE, FALSE,
7161 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
7164 Ytank_n_w, FALSE, FALSE,
7165 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
7168 Ytank_stone, FALSE, FALSE,
7169 EL_SPACESHIP, ACTION_SMASHED_BY_ROCK, -1
7172 Ytank_spring, FALSE, FALSE,
7173 EL_SPACESHIP, ACTION_SMASHED_BY_SPRING, -1
7176 Xandroid, TRUE, FALSE,
7177 EL_EMC_ANDROID, ACTION_ACTIVE, -1
7180 Xandroid_1_n, FALSE, FALSE,
7181 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
7184 Xandroid_2_n, FALSE, FALSE,
7185 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
7188 Xandroid_1_e, FALSE, FALSE,
7189 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
7192 Xandroid_2_e, FALSE, FALSE,
7193 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
7196 Xandroid_1_w, FALSE, FALSE,
7197 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
7200 Xandroid_2_w, FALSE, FALSE,
7201 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
7204 Xandroid_1_s, FALSE, FALSE,
7205 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
7208 Xandroid_2_s, FALSE, FALSE,
7209 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
7212 Yandroid_n, FALSE, FALSE,
7213 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
7216 Yandroid_nB, FALSE, TRUE,
7217 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
7220 Yandroid_ne, FALSE, FALSE,
7221 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPRIGHT
7224 Yandroid_neB, FALSE, TRUE,
7225 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPRIGHT
7228 Yandroid_e, FALSE, FALSE,
7229 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
7232 Yandroid_eB, FALSE, TRUE,
7233 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
7236 Yandroid_se, FALSE, FALSE,
7237 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNRIGHT
7240 Yandroid_seB, FALSE, TRUE,
7241 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNRIGHT
7244 Yandroid_s, FALSE, FALSE,
7245 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
7248 Yandroid_sB, FALSE, TRUE,
7249 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
7252 Yandroid_sw, FALSE, FALSE,
7253 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNLEFT
7256 Yandroid_swB, FALSE, TRUE,
7257 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNLEFT
7260 Yandroid_w, FALSE, FALSE,
7261 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
7264 Yandroid_wB, FALSE, TRUE,
7265 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
7268 Yandroid_nw, FALSE, FALSE,
7269 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPLEFT
7272 Yandroid_nwB, FALSE, TRUE,
7273 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPLEFT
7276 Xspring, TRUE, FALSE,
7280 Xspring_pause, FALSE, FALSE,
7284 Xspring_e, FALSE, FALSE,
7288 Xspring_w, FALSE, FALSE,
7292 Xspring_fall, FALSE, FALSE,
7296 Yspring_s, FALSE, FALSE,
7297 EL_SPRING, ACTION_FALLING, -1
7300 Yspring_sB, FALSE, TRUE,
7301 EL_SPRING, ACTION_FALLING, -1
7304 Yspring_e, FALSE, FALSE,
7305 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
7308 Yspring_eB, FALSE, TRUE,
7309 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
7312 Yspring_w, FALSE, FALSE,
7313 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
7316 Yspring_wB, FALSE, TRUE,
7317 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
7320 Yspring_kill_e, FALSE, FALSE,
7321 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
7324 Yspring_kill_eB, FALSE, TRUE,
7325 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
7328 Yspring_kill_w, FALSE, FALSE,
7329 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
7332 Yspring_kill_wB, FALSE, TRUE,
7333 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
7336 Xeater_n, TRUE, FALSE,
7337 EL_YAMYAM_UP, -1, -1
7340 Xeater_e, TRUE, FALSE,
7341 EL_YAMYAM_RIGHT, -1, -1
7344 Xeater_w, TRUE, FALSE,
7345 EL_YAMYAM_LEFT, -1, -1
7348 Xeater_s, TRUE, FALSE,
7349 EL_YAMYAM_DOWN, -1, -1
7352 Yeater_n, FALSE, FALSE,
7353 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
7356 Yeater_nB, FALSE, TRUE,
7357 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
7360 Yeater_e, FALSE, FALSE,
7361 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
7364 Yeater_eB, FALSE, TRUE,
7365 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
7368 Yeater_s, FALSE, FALSE,
7369 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
7372 Yeater_sB, FALSE, TRUE,
7373 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
7376 Yeater_w, FALSE, FALSE,
7377 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
7380 Yeater_wB, FALSE, TRUE,
7381 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
7384 Yeater_stone, FALSE, FALSE,
7385 EL_YAMYAM, ACTION_SMASHED_BY_ROCK, -1
7388 Yeater_spring, FALSE, FALSE,
7389 EL_YAMYAM, ACTION_SMASHED_BY_SPRING, -1
7392 Xalien, TRUE, FALSE,
7396 Xalien_pause, FALSE, FALSE,
7400 Yalien_n, FALSE, FALSE,
7401 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
7404 Yalien_nB, FALSE, TRUE,
7405 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
7408 Yalien_e, FALSE, FALSE,
7409 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
7412 Yalien_eB, FALSE, TRUE,
7413 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
7416 Yalien_s, FALSE, FALSE,
7417 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
7420 Yalien_sB, FALSE, TRUE,
7421 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
7424 Yalien_w, FALSE, FALSE,
7425 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
7428 Yalien_wB, FALSE, TRUE,
7429 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
7432 Yalien_stone, FALSE, FALSE,
7433 EL_ROBOT, ACTION_SMASHED_BY_ROCK, -1
7436 Yalien_spring, FALSE, FALSE,
7437 EL_ROBOT, ACTION_SMASHED_BY_SPRING, -1
7440 Xemerald, TRUE, FALSE,
7444 Xemerald_pause, FALSE, FALSE,
7448 Xemerald_fall, FALSE, FALSE,
7452 Xemerald_shine, FALSE, FALSE,
7453 EL_EMERALD, ACTION_TWINKLING, -1
7456 Yemerald_s, FALSE, FALSE,
7457 EL_EMERALD, ACTION_FALLING, -1
7460 Yemerald_sB, FALSE, TRUE,
7461 EL_EMERALD, ACTION_FALLING, -1
7464 Yemerald_e, FALSE, FALSE,
7465 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
7468 Yemerald_eB, FALSE, TRUE,
7469 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
7472 Yemerald_w, FALSE, FALSE,
7473 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
7476 Yemerald_wB, FALSE, TRUE,
7477 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
7480 Yemerald_eat, FALSE, FALSE,
7481 EL_EMERALD, ACTION_COLLECTING, -1
7484 Yemerald_stone, FALSE, FALSE,
7485 EL_NUT, ACTION_BREAKING, -1
7488 Xdiamond, TRUE, FALSE,
7492 Xdiamond_pause, FALSE, FALSE,
7496 Xdiamond_fall, FALSE, FALSE,
7500 Xdiamond_shine, FALSE, FALSE,
7501 EL_DIAMOND, ACTION_TWINKLING, -1
7504 Ydiamond_s, FALSE, FALSE,
7505 EL_DIAMOND, ACTION_FALLING, -1
7508 Ydiamond_sB, FALSE, TRUE,
7509 EL_DIAMOND, ACTION_FALLING, -1
7512 Ydiamond_e, FALSE, FALSE,
7513 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
7516 Ydiamond_eB, FALSE, TRUE,
7517 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
7520 Ydiamond_w, FALSE, FALSE,
7521 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
7524 Ydiamond_wB, FALSE, TRUE,
7525 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
7528 Ydiamond_eat, FALSE, FALSE,
7529 EL_DIAMOND, ACTION_COLLECTING, -1
7532 Ydiamond_stone, FALSE, FALSE,
7533 EL_DIAMOND, ACTION_SMASHED_BY_ROCK, -1
7536 Xdrip_fall, TRUE, FALSE,
7537 EL_AMOEBA_DROP, -1, -1
7540 Xdrip_stretch, FALSE, FALSE,
7541 EL_AMOEBA_DROP, ACTION_FALLING, -1
7544 Xdrip_stretchB, FALSE, TRUE,
7545 EL_AMOEBA_DROP, ACTION_FALLING, -1
7548 Xdrip_eat, FALSE, FALSE,
7549 EL_AMOEBA_DROP, ACTION_GROWING, -1
7552 Ydrip_s1, FALSE, FALSE,
7553 EL_AMOEBA_DROP, ACTION_FALLING, -1
7556 Ydrip_s1B, FALSE, TRUE,
7557 EL_AMOEBA_DROP, ACTION_FALLING, -1
7560 Ydrip_s2, FALSE, FALSE,
7561 EL_AMOEBA_DROP, ACTION_FALLING, -1
7564 Ydrip_s2B, FALSE, TRUE,
7565 EL_AMOEBA_DROP, ACTION_FALLING, -1
7572 Xbomb_pause, FALSE, FALSE,
7576 Xbomb_fall, FALSE, FALSE,
7580 Ybomb_s, FALSE, FALSE,
7581 EL_BOMB, ACTION_FALLING, -1
7584 Ybomb_sB, FALSE, TRUE,
7585 EL_BOMB, ACTION_FALLING, -1
7588 Ybomb_e, FALSE, FALSE,
7589 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
7592 Ybomb_eB, FALSE, TRUE,
7593 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
7596 Ybomb_w, FALSE, FALSE,
7597 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
7600 Ybomb_wB, FALSE, TRUE,
7601 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
7604 Ybomb_eat, FALSE, FALSE,
7605 EL_BOMB, ACTION_ACTIVATING, -1
7608 Xballoon, TRUE, FALSE,
7612 Yballoon_n, FALSE, FALSE,
7613 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
7616 Yballoon_nB, FALSE, TRUE,
7617 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
7620 Yballoon_e, FALSE, FALSE,
7621 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
7624 Yballoon_eB, FALSE, TRUE,
7625 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
7628 Yballoon_s, FALSE, FALSE,
7629 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
7632 Yballoon_sB, FALSE, TRUE,
7633 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
7636 Yballoon_w, FALSE, FALSE,
7637 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
7640 Yballoon_wB, FALSE, TRUE,
7641 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
7644 Xgrass, TRUE, FALSE,
7645 EL_EMC_GRASS, -1, -1
7648 Ygrass_nB, FALSE, FALSE,
7649 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_UP
7652 Ygrass_eB, FALSE, FALSE,
7653 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_RIGHT
7656 Ygrass_sB, FALSE, FALSE,
7657 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_DOWN
7660 Ygrass_wB, FALSE, FALSE,
7661 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_LEFT
7668 Ydirt_nB, FALSE, FALSE,
7669 EL_SAND, ACTION_DIGGING, MV_BIT_UP
7672 Ydirt_eB, FALSE, FALSE,
7673 EL_SAND, ACTION_DIGGING, MV_BIT_RIGHT
7676 Ydirt_sB, FALSE, FALSE,
7677 EL_SAND, ACTION_DIGGING, MV_BIT_DOWN
7680 Ydirt_wB, FALSE, FALSE,
7681 EL_SAND, ACTION_DIGGING, MV_BIT_LEFT
7684 Xacid_ne, TRUE, FALSE,
7685 EL_ACID_POOL_TOPRIGHT, -1, -1
7688 Xacid_se, TRUE, FALSE,
7689 EL_ACID_POOL_BOTTOMRIGHT, -1, -1
7692 Xacid_s, TRUE, FALSE,
7693 EL_ACID_POOL_BOTTOM, -1, -1
7696 Xacid_sw, TRUE, FALSE,
7697 EL_ACID_POOL_BOTTOMLEFT, -1, -1
7700 Xacid_nw, TRUE, FALSE,
7701 EL_ACID_POOL_TOPLEFT, -1, -1
7704 Xacid_1, TRUE, FALSE,
7708 Xacid_2, FALSE, FALSE,
7712 Xacid_3, FALSE, FALSE,
7716 Xacid_4, FALSE, FALSE,
7720 Xacid_5, FALSE, FALSE,
7724 Xacid_6, FALSE, FALSE,
7728 Xacid_7, FALSE, FALSE,
7732 Xacid_8, FALSE, FALSE,
7736 Xball_1, TRUE, FALSE,
7737 EL_EMC_MAGIC_BALL, -1, -1
7740 Xball_1B, FALSE, FALSE,
7741 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
7744 Xball_2, FALSE, FALSE,
7745 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
7748 Xball_2B, FALSE, FALSE,
7749 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
7752 Yball_eat, FALSE, FALSE,
7753 EL_EMC_MAGIC_BALL, ACTION_DROPPING, -1
7756 Ykey_1_eat, FALSE, FALSE,
7757 EL_EM_KEY_1, ACTION_COLLECTING, -1
7760 Ykey_2_eat, FALSE, FALSE,
7761 EL_EM_KEY_2, ACTION_COLLECTING, -1
7764 Ykey_3_eat, FALSE, FALSE,
7765 EL_EM_KEY_3, ACTION_COLLECTING, -1
7768 Ykey_4_eat, FALSE, FALSE,
7769 EL_EM_KEY_4, ACTION_COLLECTING, -1
7772 Ykey_5_eat, FALSE, FALSE,
7773 EL_EMC_KEY_5, ACTION_COLLECTING, -1
7776 Ykey_6_eat, FALSE, FALSE,
7777 EL_EMC_KEY_6, ACTION_COLLECTING, -1
7780 Ykey_7_eat, FALSE, FALSE,
7781 EL_EMC_KEY_7, ACTION_COLLECTING, -1
7784 Ykey_8_eat, FALSE, FALSE,
7785 EL_EMC_KEY_8, ACTION_COLLECTING, -1
7788 Ylenses_eat, FALSE, FALSE,
7789 EL_EMC_LENSES, ACTION_COLLECTING, -1
7792 Ymagnify_eat, FALSE, FALSE,
7793 EL_EMC_MAGNIFIER, ACTION_COLLECTING, -1
7796 Ygrass_eat, FALSE, FALSE,
7797 EL_EMC_GRASS, ACTION_SNAPPING, -1
7800 Ydirt_eat, FALSE, FALSE,
7801 EL_SAND, ACTION_SNAPPING, -1
7804 Xgrow_ns, TRUE, FALSE,
7805 EL_EXPANDABLE_WALL_VERTICAL, -1, -1
7808 Ygrow_ns_eat, FALSE, FALSE,
7809 EL_EXPANDABLE_WALL_VERTICAL, ACTION_GROWING, -1
7812 Xgrow_ew, TRUE, FALSE,
7813 EL_EXPANDABLE_WALL_HORIZONTAL, -1, -1
7816 Ygrow_ew_eat, FALSE, FALSE,
7817 EL_EXPANDABLE_WALL_HORIZONTAL, ACTION_GROWING, -1
7820 Xwonderwall, TRUE, FALSE,
7821 EL_MAGIC_WALL, -1, -1
7824 XwonderwallB, FALSE, FALSE,
7825 EL_MAGIC_WALL, ACTION_ACTIVE, -1
7828 Xamoeba_1, TRUE, FALSE,
7829 EL_AMOEBA_DRY, ACTION_OTHER, -1
7832 Xamoeba_2, FALSE, FALSE,
7833 EL_AMOEBA_DRY, ACTION_OTHER, -1
7836 Xamoeba_3, FALSE, FALSE,
7837 EL_AMOEBA_DRY, ACTION_OTHER, -1
7840 Xamoeba_4, FALSE, FALSE,
7841 EL_AMOEBA_DRY, ACTION_OTHER, -1
7844 Xamoeba_5, TRUE, FALSE,
7845 EL_AMOEBA_WET, ACTION_OTHER, -1
7848 Xamoeba_6, FALSE, FALSE,
7849 EL_AMOEBA_WET, ACTION_OTHER, -1
7852 Xamoeba_7, FALSE, FALSE,
7853 EL_AMOEBA_WET, ACTION_OTHER, -1
7856 Xamoeba_8, FALSE, FALSE,
7857 EL_AMOEBA_WET, ACTION_OTHER, -1
7860 Xdoor_1, TRUE, FALSE,
7861 EL_EM_GATE_1, -1, -1
7864 Xdoor_2, TRUE, FALSE,
7865 EL_EM_GATE_2, -1, -1
7868 Xdoor_3, TRUE, FALSE,
7869 EL_EM_GATE_3, -1, -1
7872 Xdoor_4, TRUE, FALSE,
7873 EL_EM_GATE_4, -1, -1
7876 Xdoor_5, TRUE, FALSE,
7877 EL_EMC_GATE_5, -1, -1
7880 Xdoor_6, TRUE, FALSE,
7881 EL_EMC_GATE_6, -1, -1
7884 Xdoor_7, TRUE, FALSE,
7885 EL_EMC_GATE_7, -1, -1
7888 Xdoor_8, TRUE, FALSE,
7889 EL_EMC_GATE_8, -1, -1
7892 Xkey_1, TRUE, FALSE,
7896 Xkey_2, TRUE, FALSE,
7900 Xkey_3, TRUE, FALSE,
7904 Xkey_4, TRUE, FALSE,
7908 Xkey_5, TRUE, FALSE,
7909 EL_EMC_KEY_5, -1, -1
7912 Xkey_6, TRUE, FALSE,
7913 EL_EMC_KEY_6, -1, -1
7916 Xkey_7, TRUE, FALSE,
7917 EL_EMC_KEY_7, -1, -1
7920 Xkey_8, TRUE, FALSE,
7921 EL_EMC_KEY_8, -1, -1
7924 Xwind_n, TRUE, FALSE,
7925 EL_BALLOON_SWITCH_UP, -1, -1
7928 Xwind_e, TRUE, FALSE,
7929 EL_BALLOON_SWITCH_RIGHT, -1, -1
7932 Xwind_s, TRUE, FALSE,
7933 EL_BALLOON_SWITCH_DOWN, -1, -1
7936 Xwind_w, TRUE, FALSE,
7937 EL_BALLOON_SWITCH_LEFT, -1, -1
7940 Xwind_nesw, TRUE, FALSE,
7941 EL_BALLOON_SWITCH_ANY, -1, -1
7944 Xwind_stop, TRUE, FALSE,
7945 EL_BALLOON_SWITCH_NONE, -1, -1
7949 EL_EM_EXIT_CLOSED, -1, -1
7952 Xexit_1, TRUE, FALSE,
7953 EL_EM_EXIT_OPEN, -1, -1
7956 Xexit_2, FALSE, FALSE,
7957 EL_EM_EXIT_OPEN, -1, -1
7960 Xexit_3, FALSE, FALSE,
7961 EL_EM_EXIT_OPEN, -1, -1
7964 Xdynamite, TRUE, FALSE,
7965 EL_EM_DYNAMITE, -1, -1
7968 Ydynamite_eat, FALSE, FALSE,
7969 EL_EM_DYNAMITE, ACTION_COLLECTING, -1
7972 Xdynamite_1, TRUE, FALSE,
7973 EL_EM_DYNAMITE_ACTIVE, -1, -1
7976 Xdynamite_2, FALSE, FALSE,
7977 EL_EM_DYNAMITE_ACTIVE, -1, -1
7980 Xdynamite_3, FALSE, FALSE,
7981 EL_EM_DYNAMITE_ACTIVE, -1, -1
7984 Xdynamite_4, FALSE, FALSE,
7985 EL_EM_DYNAMITE_ACTIVE, -1, -1
7988 Xbumper, TRUE, FALSE,
7989 EL_EMC_SPRING_BUMPER, -1, -1
7992 XbumperB, FALSE, FALSE,
7993 EL_EMC_SPRING_BUMPER, ACTION_ACTIVE, -1
7996 Xwheel, TRUE, FALSE,
7997 EL_ROBOT_WHEEL, -1, -1
8000 XwheelB, FALSE, FALSE,
8001 EL_ROBOT_WHEEL, ACTION_ACTIVE, -1
8004 Xswitch, TRUE, FALSE,
8005 EL_EMC_MAGIC_BALL_SWITCH, -1, -1
8008 XswitchB, FALSE, FALSE,
8009 EL_EMC_MAGIC_BALL_SWITCH, ACTION_ACTIVE, -1
8013 EL_QUICKSAND_EMPTY, -1, -1
8016 Xsand_stone, TRUE, FALSE,
8017 EL_QUICKSAND_FULL, -1, -1
8020 Xsand_stonein_1, FALSE, TRUE,
8021 EL_ROCK, ACTION_FILLING, -1
8024 Xsand_stonein_2, FALSE, TRUE,
8025 EL_ROCK, ACTION_FILLING, -1
8028 Xsand_stonein_3, FALSE, TRUE,
8029 EL_ROCK, ACTION_FILLING, -1
8032 Xsand_stonein_4, FALSE, TRUE,
8033 EL_ROCK, ACTION_FILLING, -1
8037 Xsand_stonesand_1, FALSE, FALSE,
8038 EL_QUICKSAND_EMPTYING, -1, -1
8041 Xsand_stonesand_2, FALSE, FALSE,
8042 EL_QUICKSAND_EMPTYING, -1, -1
8045 Xsand_stonesand_3, FALSE, FALSE,
8046 EL_QUICKSAND_EMPTYING, -1, -1
8049 Xsand_stonesand_4, FALSE, FALSE,
8050 EL_QUICKSAND_EMPTYING, -1, -1
8053 Xsand_stonesand_quickout_1, FALSE, FALSE,
8054 EL_QUICKSAND_EMPTYING, -1, -1
8057 Xsand_stonesand_quickout_2, FALSE, FALSE,
8058 EL_QUICKSAND_EMPTYING, -1, -1
8062 Xsand_stonesand_1, FALSE, FALSE,
8063 EL_QUICKSAND_FULL, -1, -1
8066 Xsand_stonesand_2, FALSE, FALSE,
8067 EL_QUICKSAND_FULL, -1, -1
8070 Xsand_stonesand_3, FALSE, FALSE,
8071 EL_QUICKSAND_FULL, -1, -1
8074 Xsand_stonesand_4, FALSE, FALSE,
8075 EL_QUICKSAND_FULL, -1, -1
8079 Xsand_stoneout_1, FALSE, FALSE,
8080 EL_ROCK, ACTION_EMPTYING, -1
8083 Xsand_stoneout_2, FALSE, FALSE,
8084 EL_ROCK, ACTION_EMPTYING, -1
8088 Xsand_sandstone_1, FALSE, FALSE,
8089 EL_QUICKSAND_FILLING, -1, -1
8092 Xsand_sandstone_2, FALSE, FALSE,
8093 EL_QUICKSAND_FILLING, -1, -1
8096 Xsand_sandstone_3, FALSE, FALSE,
8097 EL_QUICKSAND_FILLING, -1, -1
8100 Xsand_sandstone_4, FALSE, FALSE,
8101 EL_QUICKSAND_FILLING, -1, -1
8105 Xsand_sandstone_1, FALSE, FALSE,
8106 EL_QUICKSAND_FULL, -1, -1
8109 Xsand_sandstone_2, FALSE, FALSE,
8110 EL_QUICKSAND_FULL, -1, -1
8113 Xsand_sandstone_3, FALSE, FALSE,
8114 EL_QUICKSAND_FULL, -1, -1
8117 Xsand_sandstone_4, FALSE, FALSE,
8118 EL_QUICKSAND_FULL, -1, -1
8122 Xplant, TRUE, FALSE,
8123 EL_EMC_PLANT, -1, -1
8126 Yplant, FALSE, FALSE,
8127 EL_EMC_PLANT, -1, -1
8130 Xlenses, TRUE, FALSE,
8131 EL_EMC_LENSES, -1, -1
8134 Xmagnify, TRUE, FALSE,
8135 EL_EMC_MAGNIFIER, -1, -1
8138 Xdripper, TRUE, FALSE,
8139 EL_EMC_DRIPPER, -1, -1
8142 XdripperB, FALSE, FALSE,
8143 EL_EMC_DRIPPER, ACTION_ACTIVE, -1
8146 Xfake_blank, TRUE, FALSE,
8147 EL_INVISIBLE_WALL, -1, -1
8150 Xfake_blankB, FALSE, FALSE,
8151 EL_INVISIBLE_WALL, ACTION_ACTIVE, -1
8154 Xfake_grass, TRUE, FALSE,
8155 EL_EMC_FAKE_GRASS, -1, -1
8158 Xfake_grassB, FALSE, FALSE,
8159 EL_EMC_FAKE_GRASS, ACTION_ACTIVE, -1
8162 Xfake_door_1, TRUE, FALSE,
8163 EL_EM_GATE_1_GRAY, -1, -1
8166 Xfake_door_2, TRUE, FALSE,
8167 EL_EM_GATE_2_GRAY, -1, -1
8170 Xfake_door_3, TRUE, FALSE,
8171 EL_EM_GATE_3_GRAY, -1, -1
8174 Xfake_door_4, TRUE, FALSE,
8175 EL_EM_GATE_4_GRAY, -1, -1
8178 Xfake_door_5, TRUE, FALSE,
8179 EL_EMC_GATE_5_GRAY, -1, -1
8182 Xfake_door_6, TRUE, FALSE,
8183 EL_EMC_GATE_6_GRAY, -1, -1
8186 Xfake_door_7, TRUE, FALSE,
8187 EL_EMC_GATE_7_GRAY, -1, -1
8190 Xfake_door_8, TRUE, FALSE,
8191 EL_EMC_GATE_8_GRAY, -1, -1
8194 Xfake_acid_1, TRUE, FALSE,
8195 EL_EMC_FAKE_ACID, -1, -1
8198 Xfake_acid_2, FALSE, FALSE,
8199 EL_EMC_FAKE_ACID, -1, -1
8202 Xfake_acid_3, FALSE, FALSE,
8203 EL_EMC_FAKE_ACID, -1, -1
8206 Xfake_acid_4, FALSE, FALSE,
8207 EL_EMC_FAKE_ACID, -1, -1
8210 Xfake_acid_5, FALSE, FALSE,
8211 EL_EMC_FAKE_ACID, -1, -1
8214 Xfake_acid_6, FALSE, FALSE,
8215 EL_EMC_FAKE_ACID, -1, -1
8218 Xfake_acid_7, FALSE, FALSE,
8219 EL_EMC_FAKE_ACID, -1, -1
8222 Xfake_acid_8, FALSE, FALSE,
8223 EL_EMC_FAKE_ACID, -1, -1
8226 Xsteel_1, TRUE, FALSE,
8227 EL_STEELWALL, -1, -1
8230 Xsteel_2, TRUE, FALSE,
8231 EL_EMC_STEELWALL_2, -1, -1
8234 Xsteel_3, TRUE, FALSE,
8235 EL_EMC_STEELWALL_3, -1, -1
8238 Xsteel_4, TRUE, FALSE,
8239 EL_EMC_STEELWALL_4, -1, -1
8242 Xwall_1, TRUE, FALSE,
8246 Xwall_2, TRUE, FALSE,
8247 EL_EMC_WALL_14, -1, -1
8250 Xwall_3, TRUE, FALSE,
8251 EL_EMC_WALL_15, -1, -1
8254 Xwall_4, TRUE, FALSE,
8255 EL_EMC_WALL_16, -1, -1
8258 Xround_wall_1, TRUE, FALSE,
8259 EL_WALL_SLIPPERY, -1, -1
8262 Xround_wall_2, TRUE, FALSE,
8263 EL_EMC_WALL_SLIPPERY_2, -1, -1
8266 Xround_wall_3, TRUE, FALSE,
8267 EL_EMC_WALL_SLIPPERY_3, -1, -1
8270 Xround_wall_4, TRUE, FALSE,
8271 EL_EMC_WALL_SLIPPERY_4, -1, -1
8274 Xdecor_1, TRUE, FALSE,
8275 EL_EMC_WALL_8, -1, -1
8278 Xdecor_2, TRUE, FALSE,
8279 EL_EMC_WALL_6, -1, -1
8282 Xdecor_3, TRUE, FALSE,
8283 EL_EMC_WALL_4, -1, -1
8286 Xdecor_4, TRUE, FALSE,
8287 EL_EMC_WALL_7, -1, -1
8290 Xdecor_5, TRUE, FALSE,
8291 EL_EMC_WALL_5, -1, -1
8294 Xdecor_6, TRUE, FALSE,
8295 EL_EMC_WALL_9, -1, -1
8298 Xdecor_7, TRUE, FALSE,
8299 EL_EMC_WALL_10, -1, -1
8302 Xdecor_8, TRUE, FALSE,
8303 EL_EMC_WALL_1, -1, -1
8306 Xdecor_9, TRUE, FALSE,
8307 EL_EMC_WALL_2, -1, -1
8310 Xdecor_10, TRUE, FALSE,
8311 EL_EMC_WALL_3, -1, -1
8314 Xdecor_11, TRUE, FALSE,
8315 EL_EMC_WALL_11, -1, -1
8318 Xdecor_12, TRUE, FALSE,
8319 EL_EMC_WALL_12, -1, -1
8322 Xalpha_0, TRUE, FALSE,
8323 EL_CHAR('0'), -1, -1
8326 Xalpha_1, TRUE, FALSE,
8327 EL_CHAR('1'), -1, -1
8330 Xalpha_2, TRUE, FALSE,
8331 EL_CHAR('2'), -1, -1
8334 Xalpha_3, TRUE, FALSE,
8335 EL_CHAR('3'), -1, -1
8338 Xalpha_4, TRUE, FALSE,
8339 EL_CHAR('4'), -1, -1
8342 Xalpha_5, TRUE, FALSE,
8343 EL_CHAR('5'), -1, -1
8346 Xalpha_6, TRUE, FALSE,
8347 EL_CHAR('6'), -1, -1
8350 Xalpha_7, TRUE, FALSE,
8351 EL_CHAR('7'), -1, -1
8354 Xalpha_8, TRUE, FALSE,
8355 EL_CHAR('8'), -1, -1
8358 Xalpha_9, TRUE, FALSE,
8359 EL_CHAR('9'), -1, -1
8362 Xalpha_excla, TRUE, FALSE,
8363 EL_CHAR('!'), -1, -1
8366 Xalpha_quote, TRUE, FALSE,
8367 EL_CHAR('"'), -1, -1
8370 Xalpha_comma, TRUE, FALSE,
8371 EL_CHAR(','), -1, -1
8374 Xalpha_minus, TRUE, FALSE,
8375 EL_CHAR('-'), -1, -1
8378 Xalpha_perio, TRUE, FALSE,
8379 EL_CHAR('.'), -1, -1
8382 Xalpha_colon, TRUE, FALSE,
8383 EL_CHAR(':'), -1, -1
8386 Xalpha_quest, TRUE, FALSE,
8387 EL_CHAR('?'), -1, -1
8390 Xalpha_a, TRUE, FALSE,
8391 EL_CHAR('A'), -1, -1
8394 Xalpha_b, TRUE, FALSE,
8395 EL_CHAR('B'), -1, -1
8398 Xalpha_c, TRUE, FALSE,
8399 EL_CHAR('C'), -1, -1
8402 Xalpha_d, TRUE, FALSE,
8403 EL_CHAR('D'), -1, -1
8406 Xalpha_e, TRUE, FALSE,
8407 EL_CHAR('E'), -1, -1
8410 Xalpha_f, TRUE, FALSE,
8411 EL_CHAR('F'), -1, -1
8414 Xalpha_g, TRUE, FALSE,
8415 EL_CHAR('G'), -1, -1
8418 Xalpha_h, TRUE, FALSE,
8419 EL_CHAR('H'), -1, -1
8422 Xalpha_i, TRUE, FALSE,
8423 EL_CHAR('I'), -1, -1
8426 Xalpha_j, TRUE, FALSE,
8427 EL_CHAR('J'), -1, -1
8430 Xalpha_k, TRUE, FALSE,
8431 EL_CHAR('K'), -1, -1
8434 Xalpha_l, TRUE, FALSE,
8435 EL_CHAR('L'), -1, -1
8438 Xalpha_m, TRUE, FALSE,
8439 EL_CHAR('M'), -1, -1
8442 Xalpha_n, TRUE, FALSE,
8443 EL_CHAR('N'), -1, -1
8446 Xalpha_o, TRUE, FALSE,
8447 EL_CHAR('O'), -1, -1
8450 Xalpha_p, TRUE, FALSE,
8451 EL_CHAR('P'), -1, -1
8454 Xalpha_q, TRUE, FALSE,
8455 EL_CHAR('Q'), -1, -1
8458 Xalpha_r, TRUE, FALSE,
8459 EL_CHAR('R'), -1, -1
8462 Xalpha_s, TRUE, FALSE,
8463 EL_CHAR('S'), -1, -1
8466 Xalpha_t, TRUE, FALSE,
8467 EL_CHAR('T'), -1, -1
8470 Xalpha_u, TRUE, FALSE,
8471 EL_CHAR('U'), -1, -1
8474 Xalpha_v, TRUE, FALSE,
8475 EL_CHAR('V'), -1, -1
8478 Xalpha_w, TRUE, FALSE,
8479 EL_CHAR('W'), -1, -1
8482 Xalpha_x, TRUE, FALSE,
8483 EL_CHAR('X'), -1, -1
8486 Xalpha_y, TRUE, FALSE,
8487 EL_CHAR('Y'), -1, -1
8490 Xalpha_z, TRUE, FALSE,
8491 EL_CHAR('Z'), -1, -1
8494 Xalpha_arrow_e, TRUE, FALSE,
8495 EL_CHAR('>'), -1, -1
8498 Xalpha_arrow_w, TRUE, FALSE,
8499 EL_CHAR('<'), -1, -1
8502 Xalpha_copyr, TRUE, FALSE,
8503 EL_CHAR('©'), -1, -1
8507 Xboom_bug, FALSE, FALSE,
8508 EL_BUG, ACTION_EXPLODING, -1
8511 Xboom_bomb, FALSE, FALSE,
8512 EL_BOMB, ACTION_EXPLODING, -1
8515 Xboom_android, FALSE, FALSE,
8516 EL_EMC_ANDROID, ACTION_OTHER, -1
8519 Xboom_1, FALSE, FALSE,
8520 EL_DEFAULT, ACTION_EXPLODING, -1
8523 Xboom_2, FALSE, FALSE,
8524 EL_DEFAULT, ACTION_EXPLODING, -1
8527 Znormal, FALSE, FALSE,
8531 Zdynamite, FALSE, FALSE,
8535 Zplayer, FALSE, FALSE,
8539 ZBORDER, FALSE, FALSE,
8549 static struct Mapping_EM_to_RND_player
8558 em_player_mapping_list[] =
8562 EL_PLAYER_1, ACTION_MOVING, MV_BIT_UP,
8566 EL_PLAYER_1, ACTION_MOVING, MV_BIT_RIGHT,
8570 EL_PLAYER_1, ACTION_MOVING, MV_BIT_DOWN,
8574 EL_PLAYER_1, ACTION_MOVING, MV_BIT_LEFT,
8578 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_UP,
8582 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_RIGHT,
8586 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_DOWN,
8590 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_LEFT,
8594 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_UP,
8598 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_RIGHT,
8602 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_DOWN,
8606 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_LEFT,
8610 EL_PLAYER_2, ACTION_MOVING, MV_BIT_UP,
8614 EL_PLAYER_2, ACTION_MOVING, MV_BIT_RIGHT,
8618 EL_PLAYER_2, ACTION_MOVING, MV_BIT_DOWN,
8622 EL_PLAYER_2, ACTION_MOVING, MV_BIT_LEFT,
8626 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_UP,
8630 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_RIGHT,
8634 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_DOWN,
8638 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_LEFT,
8642 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_UP,
8646 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_RIGHT,
8650 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_DOWN,
8654 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_LEFT,
8658 EL_PLAYER_1, ACTION_DEFAULT, -1,
8662 EL_PLAYER_2, ACTION_DEFAULT, -1,
8666 EL_PLAYER_3, ACTION_MOVING, MV_BIT_UP,
8670 EL_PLAYER_3, ACTION_MOVING, MV_BIT_RIGHT,
8674 EL_PLAYER_3, ACTION_MOVING, MV_BIT_DOWN,
8678 EL_PLAYER_3, ACTION_MOVING, MV_BIT_LEFT,
8682 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_UP,
8686 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_RIGHT,
8690 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_DOWN,
8694 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_LEFT,
8698 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_UP,
8702 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_RIGHT,
8706 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_DOWN,
8710 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_LEFT,
8714 EL_PLAYER_4, ACTION_MOVING, MV_BIT_UP,
8718 EL_PLAYER_4, ACTION_MOVING, MV_BIT_RIGHT,
8722 EL_PLAYER_4, ACTION_MOVING, MV_BIT_DOWN,
8726 EL_PLAYER_4, ACTION_MOVING, MV_BIT_LEFT,
8730 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_UP,
8734 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_RIGHT,
8738 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_DOWN,
8742 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_LEFT,
8746 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_UP,
8750 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_RIGHT,
8754 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_DOWN,
8758 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_LEFT,
8762 EL_PLAYER_3, ACTION_DEFAULT, -1,
8766 EL_PLAYER_4, ACTION_DEFAULT, -1,
8775 int map_element_RND_to_EM(int element_rnd)
8777 static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
8778 static boolean mapping_initialized = FALSE;
8780 if (!mapping_initialized)
8784 /* return "Xalpha_quest" for all undefined elements in mapping array */
8785 for (i = 0; i < NUM_FILE_ELEMENTS; i++)
8786 mapping_RND_to_EM[i] = Xalpha_quest;
8788 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
8789 if (em_object_mapping_list[i].is_rnd_to_em_mapping)
8790 mapping_RND_to_EM[em_object_mapping_list[i].element_rnd] =
8791 em_object_mapping_list[i].element_em;
8793 mapping_initialized = TRUE;
8796 if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
8797 return mapping_RND_to_EM[element_rnd];
8799 Error(ERR_WARN, "invalid RND level element %d", element_rnd);
8804 int map_element_EM_to_RND(int element_em)
8806 static unsigned short mapping_EM_to_RND[TILE_MAX];
8807 static boolean mapping_initialized = FALSE;
8809 if (!mapping_initialized)
8813 /* return "EL_UNKNOWN" for all undefined elements in mapping array */
8814 for (i = 0; i < TILE_MAX; i++)
8815 mapping_EM_to_RND[i] = EL_UNKNOWN;
8817 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
8818 mapping_EM_to_RND[em_object_mapping_list[i].element_em] =
8819 em_object_mapping_list[i].element_rnd;
8821 mapping_initialized = TRUE;
8824 if (element_em >= 0 && element_em < TILE_MAX)
8825 return mapping_EM_to_RND[element_em];
8827 Error(ERR_WARN, "invalid EM level element %d", element_em);
8832 void map_android_clone_elements_RND_to_EM(struct LevelInfo *level)
8834 struct LevelInfo_EM *level_em = level->native_em_level;
8835 struct LEVEL *lev = level_em->lev;
8838 for (i = 0; i < TILE_MAX; i++)
8839 lev->android_array[i] = Xblank;
8841 for (i = 0; i < level->num_android_clone_elements; i++)
8843 int element_rnd = level->android_clone_element[i];
8844 int element_em = map_element_RND_to_EM(element_rnd);
8846 for (j = 0; em_object_mapping_list[j].element_em != -1; j++)
8847 if (em_object_mapping_list[j].element_rnd == element_rnd)
8848 lev->android_array[em_object_mapping_list[j].element_em] = element_em;
8852 void map_android_clone_elements_EM_to_RND(struct LevelInfo *level)
8854 struct LevelInfo_EM *level_em = level->native_em_level;
8855 struct LEVEL *lev = level_em->lev;
8858 level->num_android_clone_elements = 0;
8860 for (i = 0; i < TILE_MAX; i++)
8862 int element_em = lev->android_array[i];
8864 boolean element_found = FALSE;
8866 if (element_em == Xblank)
8869 element_rnd = map_element_EM_to_RND(element_em);
8871 for (j = 0; j < level->num_android_clone_elements; j++)
8872 if (level->android_clone_element[j] == element_rnd)
8873 element_found = TRUE;
8877 level->android_clone_element[level->num_android_clone_elements++] =
8880 if (level->num_android_clone_elements == MAX_ANDROID_ELEMENTS)
8885 if (level->num_android_clone_elements == 0)
8887 level->num_android_clone_elements = 1;
8888 level->android_clone_element[0] = EL_EMPTY;
8892 int map_direction_RND_to_EM(int direction)
8894 return (direction == MV_UP ? 0 :
8895 direction == MV_RIGHT ? 1 :
8896 direction == MV_DOWN ? 2 :
8897 direction == MV_LEFT ? 3 :
8901 int map_direction_EM_to_RND(int direction)
8903 return (direction == 0 ? MV_UP :
8904 direction == 1 ? MV_RIGHT :
8905 direction == 2 ? MV_DOWN :
8906 direction == 3 ? MV_LEFT :
8910 int map_element_RND_to_SP(int element_rnd)
8912 int element_sp = 0x20; /* map unknown elements to yellow "hardware" */
8914 if (element_rnd >= EL_SP_START &&
8915 element_rnd <= EL_SP_END)
8916 element_sp = element_rnd - EL_SP_START;
8917 else if (element_rnd == EL_EMPTY_SPACE)
8919 else if (element_rnd == EL_INVISIBLE_WALL)
8925 int map_element_SP_to_RND(int element_sp)
8927 int element_rnd = EL_UNKNOWN;
8929 if (element_sp >= 0x00 &&
8931 element_rnd = EL_SP_START + element_sp;
8932 else if (element_sp == 0x28)
8933 element_rnd = EL_INVISIBLE_WALL;
8938 int map_action_SP_to_RND(int action_sp)
8942 case actActive: return ACTION_ACTIVE;
8943 case actImpact: return ACTION_IMPACT;
8944 case actExploding: return ACTION_EXPLODING;
8945 case actDigging: return ACTION_DIGGING;
8946 case actSnapping: return ACTION_SNAPPING;
8947 case actCollecting: return ACTION_COLLECTING;
8948 case actPassing: return ACTION_PASSING;
8949 case actPushing: return ACTION_PUSHING;
8950 case actDropping: return ACTION_DROPPING;
8952 default: return ACTION_DEFAULT;
8956 int get_next_element(int element)
8960 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
8961 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
8962 case EL_QUICKSAND_FAST_FILLING: return EL_QUICKSAND_FAST_FULL;
8963 case EL_QUICKSAND_FAST_EMPTYING: return EL_QUICKSAND_FAST_EMPTY;
8964 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
8965 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
8966 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
8967 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
8968 case EL_DC_MAGIC_WALL_FILLING: return EL_DC_MAGIC_WALL_FULL;
8969 case EL_DC_MAGIC_WALL_EMPTYING: return EL_DC_MAGIC_WALL_ACTIVE;
8970 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
8972 default: return element;
8977 int el_act_dir2img(int element, int action, int direction)
8979 element = GFX_ELEMENT(element);
8981 if (direction == MV_NONE)
8982 return element_info[element].graphic[action];
8984 direction = MV_DIR_TO_BIT(direction);
8986 return element_info[element].direction_graphic[action][direction];
8989 int el_act_dir2img(int element, int action, int direction)
8991 element = GFX_ELEMENT(element);
8992 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
8994 /* direction_graphic[][] == graphic[] for undefined direction graphics */
8995 return element_info[element].direction_graphic[action][direction];
9000 static int el_act_dir2crm(int element, int action, int direction)
9002 element = GFX_ELEMENT(element);
9004 if (direction == MV_NONE)
9005 return element_info[element].crumbled[action];
9007 direction = MV_DIR_TO_BIT(direction);
9009 return element_info[element].direction_crumbled[action][direction];
9012 static int el_act_dir2crm(int element, int action, int direction)
9014 element = GFX_ELEMENT(element);
9015 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
9017 /* direction_graphic[][] == graphic[] for undefined direction graphics */
9018 return element_info[element].direction_crumbled[action][direction];
9022 int el_act2img(int element, int action)
9024 element = GFX_ELEMENT(element);
9026 return element_info[element].graphic[action];
9029 int el_act2crm(int element, int action)
9031 element = GFX_ELEMENT(element);
9033 return element_info[element].crumbled[action];
9036 int el_dir2img(int element, int direction)
9038 element = GFX_ELEMENT(element);
9040 return el_act_dir2img(element, ACTION_DEFAULT, direction);
9043 int el2baseimg(int element)
9045 return element_info[element].graphic[ACTION_DEFAULT];
9048 int el2img(int element)
9050 element = GFX_ELEMENT(element);
9052 return element_info[element].graphic[ACTION_DEFAULT];
9055 int el2edimg(int element)
9057 element = GFX_ELEMENT(element);
9059 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
9062 int el2preimg(int element)
9064 element = GFX_ELEMENT(element);
9066 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
9069 int el2panelimg(int element)
9071 element = GFX_ELEMENT(element);
9073 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PANEL];
9076 int font2baseimg(int font_nr)
9078 return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
9081 int getBeltNrFromBeltElement(int element)
9083 return (element < EL_CONVEYOR_BELT_2_LEFT ? 0 :
9084 element < EL_CONVEYOR_BELT_3_LEFT ? 1 :
9085 element < EL_CONVEYOR_BELT_4_LEFT ? 2 : 3);
9088 int getBeltNrFromBeltActiveElement(int element)
9090 return (element < EL_CONVEYOR_BELT_2_LEFT_ACTIVE ? 0 :
9091 element < EL_CONVEYOR_BELT_3_LEFT_ACTIVE ? 1 :
9092 element < EL_CONVEYOR_BELT_4_LEFT_ACTIVE ? 2 : 3);
9095 int getBeltNrFromBeltSwitchElement(int element)
9097 return (element < EL_CONVEYOR_BELT_2_SWITCH_LEFT ? 0 :
9098 element < EL_CONVEYOR_BELT_3_SWITCH_LEFT ? 1 :
9099 element < EL_CONVEYOR_BELT_4_SWITCH_LEFT ? 2 : 3);
9102 int getBeltDirNrFromBeltElement(int element)
9104 static int belt_base_element[4] =
9106 EL_CONVEYOR_BELT_1_LEFT,
9107 EL_CONVEYOR_BELT_2_LEFT,
9108 EL_CONVEYOR_BELT_3_LEFT,
9109 EL_CONVEYOR_BELT_4_LEFT
9112 int belt_nr = getBeltNrFromBeltElement(element);
9113 int belt_dir_nr = element - belt_base_element[belt_nr];
9115 return (belt_dir_nr % 3);
9118 int getBeltDirNrFromBeltSwitchElement(int element)
9120 static int belt_base_element[4] =
9122 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
9123 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
9124 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
9125 EL_CONVEYOR_BELT_4_SWITCH_LEFT
9128 int belt_nr = getBeltNrFromBeltSwitchElement(element);
9129 int belt_dir_nr = element - belt_base_element[belt_nr];
9131 return (belt_dir_nr % 3);
9134 int getBeltDirFromBeltElement(int element)
9136 static int belt_move_dir[3] =
9143 int belt_dir_nr = getBeltDirNrFromBeltElement(element);
9145 return belt_move_dir[belt_dir_nr];
9148 int getBeltDirFromBeltSwitchElement(int element)
9150 static int belt_move_dir[3] =
9157 int belt_dir_nr = getBeltDirNrFromBeltSwitchElement(element);
9159 return belt_move_dir[belt_dir_nr];
9162 int getBeltElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
9164 static int belt_base_element[4] =
9166 EL_CONVEYOR_BELT_1_LEFT,
9167 EL_CONVEYOR_BELT_2_LEFT,
9168 EL_CONVEYOR_BELT_3_LEFT,
9169 EL_CONVEYOR_BELT_4_LEFT
9172 return belt_base_element[belt_nr] + belt_dir_nr;
9175 int getBeltElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
9177 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
9179 return getBeltElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
9182 int getBeltSwitchElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
9184 static int belt_base_element[4] =
9186 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
9187 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
9188 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
9189 EL_CONVEYOR_BELT_4_SWITCH_LEFT
9192 return belt_base_element[belt_nr] + belt_dir_nr;
9195 int getBeltSwitchElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
9197 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
9199 return getBeltSwitchElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
9203 boolean getTeamMode_EM()
9205 return game.team_mode;
9208 int getNumActivePlayers_EM()
9211 int num_players = 0;
9215 return (setup.team_mode ? MAX_PLAYERS : 1);
9217 for (i = 0; i < MAX_PLAYERS; i++)
9218 if (tape.player_participates[i])
9221 return (num_players > 1 ? MAX_PLAYERS : 1);
9225 int num_players = 0;
9228 /* when recording game, activate all connected players */
9232 for (i = 0; i < MAX_PLAYERS; i++)
9233 if (tape.player_participates[i])
9241 int getGameFrameDelay_EM(int native_em_game_frame_delay)
9243 int game_frame_delay_value;
9245 game_frame_delay_value =
9246 (tape.playing && tape.fast_forward ? FfwdFrameDelay :
9247 GameFrameDelay == GAME_FRAME_DELAY ? native_em_game_frame_delay :
9250 if (tape.playing && tape.warp_forward && !tape.pausing)
9251 game_frame_delay_value = 0;
9253 return game_frame_delay_value;
9256 unsigned int InitRND(int seed)
9258 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
9259 return InitEngineRandom_EM(seed);
9260 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
9261 return InitEngineRandom_SP(seed);
9263 return InitEngineRandom_RND(seed);
9267 static struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
9268 static struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
9271 inline static int get_effective_element_EM(int tile, int frame_em)
9273 int element = object_mapping[tile].element_rnd;
9274 int action = object_mapping[tile].action;
9275 boolean is_backside = object_mapping[tile].is_backside;
9276 boolean action_removing = (action == ACTION_DIGGING ||
9277 action == ACTION_SNAPPING ||
9278 action == ACTION_COLLECTING);
9284 case Yacid_splash_eB:
9285 case Yacid_splash_wB:
9286 return (frame_em > 5 ? EL_EMPTY : element);
9290 case Ydiamond_stone:
9291 // if (!game.use_native_emc_graphics_engine)
9299 else /* frame_em == 7 */
9303 case Yacid_splash_eB:
9304 case Yacid_splash_wB:
9307 case Yemerald_stone:
9310 case Ydiamond_stone:
9314 case Xdrip_stretchB:
9333 case Xsand_stonein_1:
9334 case Xsand_stonein_2:
9335 case Xsand_stonein_3:
9336 case Xsand_stonein_4:
9340 return (is_backside || action_removing ? EL_EMPTY : element);
9345 inline static boolean check_linear_animation_EM(int tile)
9349 case Xsand_stonesand_1:
9350 case Xsand_stonesand_quickout_1:
9351 case Xsand_sandstone_1:
9352 case Xsand_stonein_1:
9353 case Xsand_stoneout_1:
9373 case Yacid_splash_eB:
9374 case Yacid_splash_wB:
9375 case Yemerald_stone:
9383 inline static void set_crumbled_graphics_EM(struct GraphicInfo_EM *g_em,
9384 boolean has_crumbled_graphics,
9385 int crumbled, int sync_frame)
9387 /* if element can be crumbled, but certain action graphics are just empty
9388 space (like instantly snapping sand to empty space in 1 frame), do not
9389 treat these empty space graphics as crumbled graphics in EMC engine */
9390 if (crumbled == IMG_EMPTY_SPACE)
9391 has_crumbled_graphics = FALSE;
9393 if (has_crumbled_graphics)
9395 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
9396 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
9397 g_crumbled->anim_delay,
9398 g_crumbled->anim_mode,
9399 g_crumbled->anim_start_frame,
9402 getGraphicSource(crumbled, frame_crumbled, &g_em->crumbled_bitmap,
9403 &g_em->crumbled_src_x, &g_em->crumbled_src_y);
9405 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
9407 g_em->has_crumbled_graphics = TRUE;
9411 g_em->crumbled_bitmap = NULL;
9412 g_em->crumbled_src_x = 0;
9413 g_em->crumbled_src_y = 0;
9414 g_em->crumbled_border_size = 0;
9416 g_em->has_crumbled_graphics = FALSE;
9420 void ResetGfxAnimation_EM(int x, int y, int tile)
9425 void SetGfxAnimation_EM(struct GraphicInfo_EM *g_em,
9426 int tile, int frame_em, int x, int y)
9428 int action = object_mapping[tile].action;
9430 int direction = object_mapping[tile].direction;
9431 int effective_element = get_effective_element_EM(tile, frame_em);
9432 int graphic = (direction == MV_NONE ?
9433 el_act2img(effective_element, action) :
9434 el_act_dir2img(effective_element, action, direction));
9435 struct GraphicInfo *g = &graphic_info[graphic];
9438 boolean action_removing = (action == ACTION_DIGGING ||
9439 action == ACTION_SNAPPING ||
9440 action == ACTION_COLLECTING);
9441 boolean action_moving = (action == ACTION_FALLING ||
9442 action == ACTION_MOVING ||
9443 action == ACTION_PUSHING ||
9444 action == ACTION_EATING ||
9445 action == ACTION_FILLING ||
9446 action == ACTION_EMPTYING);
9447 boolean action_falling = (action == ACTION_FALLING ||
9448 action == ACTION_FILLING ||
9449 action == ACTION_EMPTYING);
9451 /* special case: graphic uses "2nd movement tile" and has defined
9452 7 frames for movement animation (or less) => use default graphic
9453 for last (8th) frame which ends the movement animation */
9454 if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
9456 action = ACTION_DEFAULT; /* (keep action_* unchanged for now) */
9457 graphic = (direction == MV_NONE ?
9458 el_act2img(effective_element, action) :
9459 el_act_dir2img(effective_element, action, direction));
9461 g = &graphic_info[graphic];
9465 if (tile == Xsand_stonesand_1 ||
9466 tile == Xsand_stonesand_2 ||
9467 tile == Xsand_stonesand_3 ||
9468 tile == Xsand_stonesand_4)
9469 printf("::: 1: quicksand frame %d [%d]\n", GfxFrame[x][y], tile);
9473 if ((action_removing || check_linear_animation_EM(tile)) && frame_em == 0)
9477 // printf("::: resetting... [%d]\n", tile);
9480 if (action_removing || check_linear_animation_EM(tile))
9482 GfxFrame[x][y] = frame_em;
9484 // printf("::: resetting... [%d]\n", tile);
9487 else if (action_moving)
9489 boolean is_backside = object_mapping[tile].is_backside;
9493 int direction = object_mapping[tile].direction;
9494 int move_dir = (action_falling ? MV_DOWN : direction);
9499 /* !!! TEST !!! NEW !!! DOES NOT WORK RIGHT YET !!! */
9500 if (g->double_movement && frame_em == 0)
9504 // printf("::: resetting... [%d]\n", tile);
9508 if (move_dir == MV_LEFT)
9509 GfxFrame[x - 1][y] = GfxFrame[x][y];
9510 else if (move_dir == MV_RIGHT)
9511 GfxFrame[x + 1][y] = GfxFrame[x][y];
9512 else if (move_dir == MV_UP)
9513 GfxFrame[x][y - 1] = GfxFrame[x][y];
9514 else if (move_dir == MV_DOWN)
9515 GfxFrame[x][y + 1] = GfxFrame[x][y];
9522 /* special case: animation for Xsand_stonesand_quickout_1/2 twice as fast */
9523 if (tile == Xsand_stonesand_quickout_1 ||
9524 tile == Xsand_stonesand_quickout_2)
9529 if (tile == Xsand_stonesand_1 ||
9530 tile == Xsand_stonesand_2 ||
9531 tile == Xsand_stonesand_3 ||
9532 tile == Xsand_stonesand_4)
9533 printf("::: 2: quicksand frame %d [%d]\n", GfxFrame[x][y], tile);
9537 if (graphic_info[graphic].anim_global_sync)
9538 sync_frame = FrameCounter;
9539 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
9540 sync_frame = GfxFrame[x][y];
9542 sync_frame = 0; /* playfield border (pseudo steel) */
9544 SetRandomAnimationValue(x, y);
9546 int frame = getAnimationFrame(g->anim_frames,
9549 g->anim_start_frame,
9552 g_em->unique_identifier =
9553 (graphic << 16) | ((frame % 8) << 12) | (g_em->width << 6) | g_em->height;
9557 void getGraphicSourceObjectExt_EM(struct GraphicInfo_EM *g_em,
9558 int tile, int frame_em, int x, int y)
9560 int action = object_mapping[tile].action;
9561 int direction = object_mapping[tile].direction;
9562 boolean is_backside = object_mapping[tile].is_backside;
9563 int effective_element = get_effective_element_EM(tile, frame_em);
9565 int effective_action = action;
9567 int effective_action = (frame_em < 7 ? action : ACTION_DEFAULT);
9569 int graphic = (direction == MV_NONE ?
9570 el_act2img(effective_element, effective_action) :
9571 el_act_dir2img(effective_element, effective_action,
9573 int crumbled = (direction == MV_NONE ?
9574 el_act2crm(effective_element, effective_action) :
9575 el_act_dir2crm(effective_element, effective_action,
9577 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
9578 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
9579 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
9580 struct GraphicInfo *g = &graphic_info[graphic];
9582 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
9586 /* special case: graphic uses "2nd movement tile" and has defined
9587 7 frames for movement animation (or less) => use default graphic
9588 for last (8th) frame which ends the movement animation */
9589 if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
9591 effective_action = ACTION_DEFAULT;
9592 graphic = (direction == MV_NONE ?
9593 el_act2img(effective_element, effective_action) :
9594 el_act_dir2img(effective_element, effective_action,
9596 crumbled = (direction == MV_NONE ?
9597 el_act2crm(effective_element, effective_action) :
9598 el_act_dir2crm(effective_element, effective_action,
9601 g = &graphic_info[graphic];
9611 if (frame_em == 0) /* reset animation frame for certain elements */
9613 if (check_linear_animation_EM(tile))
9618 if (graphic_info[graphic].anim_global_sync)
9619 sync_frame = FrameCounter;
9620 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
9621 sync_frame = GfxFrame[x][y];
9623 sync_frame = 0; /* playfield border (pseudo steel) */
9625 SetRandomAnimationValue(x, y);
9630 int xxx_sync_frame = (i == Xdrip_stretch ? 7 :
9631 i == Xdrip_stretchB ? 7 :
9632 i == Ydrip_s2 ? j + 8 :
9633 i == Ydrip_s2B ? j + 8 :
9642 i == Xfake_acid_1 ? 0 :
9643 i == Xfake_acid_2 ? 10 :
9644 i == Xfake_acid_3 ? 20 :
9645 i == Xfake_acid_4 ? 30 :
9646 i == Xfake_acid_5 ? 40 :
9647 i == Xfake_acid_6 ? 50 :
9648 i == Xfake_acid_7 ? 60 :
9649 i == Xfake_acid_8 ? 70 :
9651 i == Xball_2B ? j + 8 :
9652 i == Yball_eat ? j + 1 :
9653 i == Ykey_1_eat ? j + 1 :
9654 i == Ykey_2_eat ? j + 1 :
9655 i == Ykey_3_eat ? j + 1 :
9656 i == Ykey_4_eat ? j + 1 :
9657 i == Ykey_5_eat ? j + 1 :
9658 i == Ykey_6_eat ? j + 1 :
9659 i == Ykey_7_eat ? j + 1 :
9660 i == Ykey_8_eat ? j + 1 :
9661 i == Ylenses_eat ? j + 1 :
9662 i == Ymagnify_eat ? j + 1 :
9663 i == Ygrass_eat ? j + 1 :
9664 i == Ydirt_eat ? j + 1 :
9665 i == Xamoeba_1 ? 0 :
9666 i == Xamoeba_2 ? 1 :
9667 i == Xamoeba_3 ? 2 :
9668 i == Xamoeba_4 ? 3 :
9669 i == Xamoeba_5 ? 0 :
9670 i == Xamoeba_6 ? 1 :
9671 i == Xamoeba_7 ? 2 :
9672 i == Xamoeba_8 ? 3 :
9673 i == Xexit_2 ? j + 8 :
9674 i == Xexit_3 ? j + 16 :
9675 i == Xdynamite_1 ? 0 :
9676 i == Xdynamite_2 ? 8 :
9677 i == Xdynamite_3 ? 16 :
9678 i == Xdynamite_4 ? 24 :
9679 i == Xsand_stonein_1 ? j + 1 :
9680 i == Xsand_stonein_2 ? j + 9 :
9681 i == Xsand_stonein_3 ? j + 17 :
9682 i == Xsand_stonein_4 ? j + 25 :
9683 i == Xsand_stoneout_1 && j == 0 ? 0 :
9684 i == Xsand_stoneout_1 && j == 1 ? 0 :
9685 i == Xsand_stoneout_1 && j == 2 ? 1 :
9686 i == Xsand_stoneout_1 && j == 3 ? 2 :
9687 i == Xsand_stoneout_1 && j == 4 ? 2 :
9688 i == Xsand_stoneout_1 && j == 5 ? 3 :
9689 i == Xsand_stoneout_1 && j == 6 ? 4 :
9690 i == Xsand_stoneout_1 && j == 7 ? 4 :
9691 i == Xsand_stoneout_2 && j == 0 ? 5 :
9692 i == Xsand_stoneout_2 && j == 1 ? 6 :
9693 i == Xsand_stoneout_2 && j == 2 ? 7 :
9694 i == Xsand_stoneout_2 && j == 3 ? 8 :
9695 i == Xsand_stoneout_2 && j == 4 ? 9 :
9696 i == Xsand_stoneout_2 && j == 5 ? 11 :
9697 i == Xsand_stoneout_2 && j == 6 ? 13 :
9698 i == Xsand_stoneout_2 && j == 7 ? 15 :
9699 i == Xboom_bug && j == 1 ? 2 :
9700 i == Xboom_bug && j == 2 ? 2 :
9701 i == Xboom_bug && j == 3 ? 4 :
9702 i == Xboom_bug && j == 4 ? 4 :
9703 i == Xboom_bug && j == 5 ? 2 :
9704 i == Xboom_bug && j == 6 ? 2 :
9705 i == Xboom_bug && j == 7 ? 0 :
9706 i == Xboom_bomb && j == 1 ? 2 :
9707 i == Xboom_bomb && j == 2 ? 2 :
9708 i == Xboom_bomb && j == 3 ? 4 :
9709 i == Xboom_bomb && j == 4 ? 4 :
9710 i == Xboom_bomb && j == 5 ? 2 :
9711 i == Xboom_bomb && j == 6 ? 2 :
9712 i == Xboom_bomb && j == 7 ? 0 :
9713 i == Xboom_android && j == 7 ? 6 :
9714 i == Xboom_1 && j == 1 ? 2 :
9715 i == Xboom_1 && j == 2 ? 2 :
9716 i == Xboom_1 && j == 3 ? 4 :
9717 i == Xboom_1 && j == 4 ? 4 :
9718 i == Xboom_1 && j == 5 ? 6 :
9719 i == Xboom_1 && j == 6 ? 6 :
9720 i == Xboom_1 && j == 7 ? 8 :
9721 i == Xboom_2 && j == 0 ? 8 :
9722 i == Xboom_2 && j == 1 ? 8 :
9723 i == Xboom_2 && j == 2 ? 10 :
9724 i == Xboom_2 && j == 3 ? 10 :
9725 i == Xboom_2 && j == 4 ? 10 :
9726 i == Xboom_2 && j == 5 ? 12 :
9727 i == Xboom_2 && j == 6 ? 12 :
9728 i == Xboom_2 && j == 7 ? 12 :
9730 special_animation && j == 4 ? 3 :
9731 effective_action != action ? 0 :
9737 int xxx_effective_action;
9738 int xxx_has_action_graphics;
9741 int element = object_mapping[i].element_rnd;
9742 int action = object_mapping[i].action;
9743 int direction = object_mapping[i].direction;
9744 boolean is_backside = object_mapping[i].is_backside;
9746 boolean action_removing = (action == ACTION_DIGGING ||
9747 action == ACTION_SNAPPING ||
9748 action == ACTION_COLLECTING);
9750 boolean action_exploding = ((action == ACTION_EXPLODING ||
9751 action == ACTION_SMASHED_BY_ROCK ||
9752 action == ACTION_SMASHED_BY_SPRING) &&
9753 element != EL_DIAMOND);
9754 boolean action_active = (action == ACTION_ACTIVE);
9755 boolean action_other = (action == ACTION_OTHER);
9759 int effective_element = get_effective_element_EM(i, j);
9761 int effective_element = (j > 5 && i == Yacid_splash_eB ? EL_EMPTY :
9762 j > 5 && i == Yacid_splash_wB ? EL_EMPTY :
9764 i == Xdrip_stretch ? element :
9765 i == Xdrip_stretchB ? element :
9766 i == Ydrip_s1 ? element :
9767 i == Ydrip_s1B ? element :
9768 i == Xball_1B ? element :
9769 i == Xball_2 ? element :
9770 i == Xball_2B ? element :
9771 i == Yball_eat ? element :
9772 i == Ykey_1_eat ? element :
9773 i == Ykey_2_eat ? element :
9774 i == Ykey_3_eat ? element :
9775 i == Ykey_4_eat ? element :
9776 i == Ykey_5_eat ? element :
9777 i == Ykey_6_eat ? element :
9778 i == Ykey_7_eat ? element :
9779 i == Ykey_8_eat ? element :
9780 i == Ylenses_eat ? element :
9781 i == Ymagnify_eat ? element :
9782 i == Ygrass_eat ? element :
9783 i == Ydirt_eat ? element :
9784 i == Yemerald_stone ? EL_EMERALD :
9785 i == Ydiamond_stone ? EL_ROCK :
9786 i == Xsand_stonein_1 ? element :
9787 i == Xsand_stonein_2 ? element :
9788 i == Xsand_stonein_3 ? element :
9789 i == Xsand_stonein_4 ? element :
9790 is_backside ? EL_EMPTY :
9791 action_removing ? EL_EMPTY :
9794 int effective_action = (j < 7 ? action :
9795 i == Xdrip_stretch ? action :
9796 i == Xdrip_stretchB ? action :
9797 i == Ydrip_s1 ? action :
9798 i == Ydrip_s1B ? action :
9799 i == Xball_1B ? action :
9800 i == Xball_2 ? action :
9801 i == Xball_2B ? action :
9802 i == Yball_eat ? action :
9803 i == Ykey_1_eat ? action :
9804 i == Ykey_2_eat ? action :
9805 i == Ykey_3_eat ? action :
9806 i == Ykey_4_eat ? action :
9807 i == Ykey_5_eat ? action :
9808 i == Ykey_6_eat ? action :
9809 i == Ykey_7_eat ? action :
9810 i == Ykey_8_eat ? action :
9811 i == Ylenses_eat ? action :
9812 i == Ymagnify_eat ? action :
9813 i == Ygrass_eat ? action :
9814 i == Ydirt_eat ? action :
9815 i == Xsand_stonein_1 ? action :
9816 i == Xsand_stonein_2 ? action :
9817 i == Xsand_stonein_3 ? action :
9818 i == Xsand_stonein_4 ? action :
9819 i == Xsand_stoneout_1 ? action :
9820 i == Xsand_stoneout_2 ? action :
9821 i == Xboom_android ? ACTION_EXPLODING :
9822 action_exploding ? ACTION_EXPLODING :
9823 action_active ? action :
9824 action_other ? action :
9826 int graphic = (el_act_dir2img(effective_element, effective_action,
9828 int crumbled = (el_act_dir2crm(effective_element, effective_action,
9830 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
9831 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
9832 boolean has_action_graphics = (graphic != base_graphic);
9833 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
9834 struct GraphicInfo *g = &graphic_info[graphic];
9836 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
9838 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
9841 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
9842 boolean special_animation = (action != ACTION_DEFAULT &&
9843 g->anim_frames == 3 &&
9844 g->anim_delay == 2 &&
9845 g->anim_mode & ANIM_LINEAR);
9846 xxx_sync_frame = (i == Xdrip_stretch ? 7 :
9847 i == Xdrip_stretchB ? 7 :
9848 i == Ydrip_s2 ? j + 8 :
9849 i == Ydrip_s2B ? j + 8 :
9858 i == Xfake_acid_1 ? 0 :
9859 i == Xfake_acid_2 ? 10 :
9860 i == Xfake_acid_3 ? 20 :
9861 i == Xfake_acid_4 ? 30 :
9862 i == Xfake_acid_5 ? 40 :
9863 i == Xfake_acid_6 ? 50 :
9864 i == Xfake_acid_7 ? 60 :
9865 i == Xfake_acid_8 ? 70 :
9867 i == Xball_2B ? j + 8 :
9868 i == Yball_eat ? j + 1 :
9869 i == Ykey_1_eat ? j + 1 :
9870 i == Ykey_2_eat ? j + 1 :
9871 i == Ykey_3_eat ? j + 1 :
9872 i == Ykey_4_eat ? j + 1 :
9873 i == Ykey_5_eat ? j + 1 :
9874 i == Ykey_6_eat ? j + 1 :
9875 i == Ykey_7_eat ? j + 1 :
9876 i == Ykey_8_eat ? j + 1 :
9877 i == Ylenses_eat ? j + 1 :
9878 i == Ymagnify_eat ? j + 1 :
9879 i == Ygrass_eat ? j + 1 :
9880 i == Ydirt_eat ? j + 1 :
9881 i == Xamoeba_1 ? 0 :
9882 i == Xamoeba_2 ? 1 :
9883 i == Xamoeba_3 ? 2 :
9884 i == Xamoeba_4 ? 3 :
9885 i == Xamoeba_5 ? 0 :
9886 i == Xamoeba_6 ? 1 :
9887 i == Xamoeba_7 ? 2 :
9888 i == Xamoeba_8 ? 3 :
9889 i == Xexit_2 ? j + 8 :
9890 i == Xexit_3 ? j + 16 :
9891 i == Xdynamite_1 ? 0 :
9892 i == Xdynamite_2 ? 8 :
9893 i == Xdynamite_3 ? 16 :
9894 i == Xdynamite_4 ? 24 :
9895 i == Xsand_stonein_1 ? j + 1 :
9896 i == Xsand_stonein_2 ? j + 9 :
9897 i == Xsand_stonein_3 ? j + 17 :
9898 i == Xsand_stonein_4 ? j + 25 :
9899 i == Xsand_stoneout_1 && j == 0 ? 0 :
9900 i == Xsand_stoneout_1 && j == 1 ? 0 :
9901 i == Xsand_stoneout_1 && j == 2 ? 1 :
9902 i == Xsand_stoneout_1 && j == 3 ? 2 :
9903 i == Xsand_stoneout_1 && j == 4 ? 2 :
9904 i == Xsand_stoneout_1 && j == 5 ? 3 :
9905 i == Xsand_stoneout_1 && j == 6 ? 4 :
9906 i == Xsand_stoneout_1 && j == 7 ? 4 :
9907 i == Xsand_stoneout_2 && j == 0 ? 5 :
9908 i == Xsand_stoneout_2 && j == 1 ? 6 :
9909 i == Xsand_stoneout_2 && j == 2 ? 7 :
9910 i == Xsand_stoneout_2 && j == 3 ? 8 :
9911 i == Xsand_stoneout_2 && j == 4 ? 9 :
9912 i == Xsand_stoneout_2 && j == 5 ? 11 :
9913 i == Xsand_stoneout_2 && j == 6 ? 13 :
9914 i == Xsand_stoneout_2 && j == 7 ? 15 :
9915 i == Xboom_bug && j == 1 ? 2 :
9916 i == Xboom_bug && j == 2 ? 2 :
9917 i == Xboom_bug && j == 3 ? 4 :
9918 i == Xboom_bug && j == 4 ? 4 :
9919 i == Xboom_bug && j == 5 ? 2 :
9920 i == Xboom_bug && j == 6 ? 2 :
9921 i == Xboom_bug && j == 7 ? 0 :
9922 i == Xboom_bomb && j == 1 ? 2 :
9923 i == Xboom_bomb && j == 2 ? 2 :
9924 i == Xboom_bomb && j == 3 ? 4 :
9925 i == Xboom_bomb && j == 4 ? 4 :
9926 i == Xboom_bomb && j == 5 ? 2 :
9927 i == Xboom_bomb && j == 6 ? 2 :
9928 i == Xboom_bomb && j == 7 ? 0 :
9929 i == Xboom_android && j == 7 ? 6 :
9930 i == Xboom_1 && j == 1 ? 2 :
9931 i == Xboom_1 && j == 2 ? 2 :
9932 i == Xboom_1 && j == 3 ? 4 :
9933 i == Xboom_1 && j == 4 ? 4 :
9934 i == Xboom_1 && j == 5 ? 6 :
9935 i == Xboom_1 && j == 6 ? 6 :
9936 i == Xboom_1 && j == 7 ? 8 :
9937 i == Xboom_2 && j == 0 ? 8 :
9938 i == Xboom_2 && j == 1 ? 8 :
9939 i == Xboom_2 && j == 2 ? 10 :
9940 i == Xboom_2 && j == 3 ? 10 :
9941 i == Xboom_2 && j == 4 ? 10 :
9942 i == Xboom_2 && j == 5 ? 12 :
9943 i == Xboom_2 && j == 6 ? 12 :
9944 i == Xboom_2 && j == 7 ? 12 :
9945 special_animation && j == 4 ? 3 :
9946 effective_action != action ? 0 :
9949 xxx_effective_action = effective_action;
9950 xxx_has_action_graphics = has_action_graphics;
9955 int frame = getAnimationFrame(g->anim_frames,
9958 g->anim_start_frame,
9972 int old_src_x = g_em->src_x;
9973 int old_src_y = g_em->src_y;
9977 getGraphicSourceExt(graphic, frame, &g_em->bitmap, &g_em->src_x, &g_em->src_y,
9978 g->double_movement && is_backside);
9980 getGraphicSourceExt(graphic, frame, &g_em->bitmap,
9981 &g_em->src_x, &g_em->src_y, FALSE);
9986 if (tile == Ydiamond_stone)
9987 printf("::: stone smashing diamond... %d: %d, %d, %d, %d, %d -> %d [%d, %d, %d, %d, %d, %d] [%d]\n",
9992 g->anim_start_frame,
9995 g_em->src_x, g_em->src_y,
9996 g_em->src_offset_x, g_em->src_offset_y,
9997 g_em->dst_offset_x, g_em->dst_offset_y,
10009 if (graphic == IMG_BUG_MOVING_RIGHT)
10010 printf("::: %d, %d, %d: %d, %d [%d, %d -> %d, %d]\n", graphic, x, y,
10011 g->double_movement, is_backside,
10012 old_src_x, old_src_y, g_em->src_x, g_em->src_y);
10020 g_em->src_offset_x = 0;
10021 g_em->src_offset_y = 0;
10022 g_em->dst_offset_x = 0;
10023 g_em->dst_offset_y = 0;
10024 g_em->width = TILEX;
10025 g_em->height = TILEY;
10027 g_em->preserve_background = FALSE;
10030 /* (updating the "crumbled" graphic definitions is probably not really needed,
10031 as animations for crumbled graphics can't be longer than one EMC cycle) */
10033 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
10038 g_em->crumbled_bitmap = NULL;
10039 g_em->crumbled_src_x = 0;
10040 g_em->crumbled_src_y = 0;
10042 g_em->has_crumbled_graphics = FALSE;
10044 if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
10046 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
10047 g_crumbled->anim_delay,
10048 g_crumbled->anim_mode,
10049 g_crumbled->anim_start_frame,
10052 getGraphicSource(crumbled, frame_crumbled, &g_em->crumbled_bitmap,
10053 &g_em->crumbled_src_x, &g_em->crumbled_src_y);
10055 g_em->has_crumbled_graphics = TRUE;
10061 int effective_action = xxx_effective_action;
10062 int has_action_graphics = xxx_has_action_graphics;
10064 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
10065 effective_action == ACTION_MOVING ||
10066 effective_action == ACTION_PUSHING ||
10067 effective_action == ACTION_EATING)) ||
10068 (!has_action_graphics && (effective_action == ACTION_FILLING ||
10069 effective_action == ACTION_EMPTYING)))
10072 (effective_action == ACTION_FALLING ||
10073 effective_action == ACTION_FILLING ||
10074 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
10075 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
10076 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
10077 int num_steps = (i == Ydrip_s1 ? 16 :
10078 i == Ydrip_s1B ? 16 :
10079 i == Ydrip_s2 ? 16 :
10080 i == Ydrip_s2B ? 16 :
10081 i == Xsand_stonein_1 ? 32 :
10082 i == Xsand_stonein_2 ? 32 :
10083 i == Xsand_stonein_3 ? 32 :
10084 i == Xsand_stonein_4 ? 32 :
10085 i == Xsand_stoneout_1 ? 16 :
10086 i == Xsand_stoneout_2 ? 16 : 8);
10087 int cx = ABS(dx) * (TILEX / num_steps);
10088 int cy = ABS(dy) * (TILEY / num_steps);
10089 int step_frame = (i == Ydrip_s2 ? j + 8 :
10090 i == Ydrip_s2B ? j + 8 :
10091 i == Xsand_stonein_2 ? j + 8 :
10092 i == Xsand_stonein_3 ? j + 16 :
10093 i == Xsand_stonein_4 ? j + 24 :
10094 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
10095 int step = (is_backside ? step_frame : num_steps - step_frame);
10097 if (is_backside) /* tile where movement starts */
10099 if (dx < 0 || dy < 0)
10101 g_em->src_offset_x = cx * step;
10102 g_em->src_offset_y = cy * step;
10106 g_em->dst_offset_x = cx * step;
10107 g_em->dst_offset_y = cy * step;
10110 else /* tile where movement ends */
10112 if (dx < 0 || dy < 0)
10114 g_em->dst_offset_x = cx * step;
10115 g_em->dst_offset_y = cy * step;
10119 g_em->src_offset_x = cx * step;
10120 g_em->src_offset_y = cy * step;
10124 g_em->width = TILEX - cx * step;
10125 g_em->height = TILEY - cy * step;
10128 /* create unique graphic identifier to decide if tile must be redrawn */
10129 /* bit 31 - 16 (16 bit): EM style graphic
10130 bit 15 - 12 ( 4 bit): EM style frame
10131 bit 11 - 6 ( 6 bit): graphic width
10132 bit 5 - 0 ( 6 bit): graphic height */
10133 g_em->unique_identifier =
10134 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
10140 void getGraphicSourcePlayerExt_EM(struct GraphicInfo_EM *g_em,
10141 int player_nr, int anim, int frame_em)
10143 int element = player_mapping[player_nr][anim].element_rnd;
10144 int action = player_mapping[player_nr][anim].action;
10145 int direction = player_mapping[player_nr][anim].direction;
10146 int graphic = (direction == MV_NONE ?
10147 el_act2img(element, action) :
10148 el_act_dir2img(element, action, direction));
10149 struct GraphicInfo *g = &graphic_info[graphic];
10152 InitPlayerGfxAnimation(&stored_player[player_nr], action, direction);
10154 stored_player[player_nr].StepFrame = frame_em;
10156 sync_frame = stored_player[player_nr].Frame;
10158 int frame = getAnimationFrame(g->anim_frames,
10161 g->anim_start_frame,
10164 getGraphicSourceExt(graphic, frame, &g_em->bitmap,
10165 &g_em->src_x, &g_em->src_y, FALSE);
10168 printf("::: %d: %d, %d [%d]\n",
10170 stored_player[player_nr].Frame,
10171 stored_player[player_nr].StepFrame,
10176 void InitGraphicInfo_EM(void)
10179 struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
10180 struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
10185 int num_em_gfx_errors = 0;
10187 if (graphic_info_em_object[0][0].bitmap == NULL)
10189 /* EM graphics not yet initialized in em_open_all() */
10194 printf("::: [4 errors can be ignored (1 x 'bomb', 3 x 'em_dynamite']\n");
10197 /* always start with reliable default values */
10198 for (i = 0; i < TILE_MAX; i++)
10200 object_mapping[i].element_rnd = EL_UNKNOWN;
10201 object_mapping[i].is_backside = FALSE;
10202 object_mapping[i].action = ACTION_DEFAULT;
10203 object_mapping[i].direction = MV_NONE;
10206 /* always start with reliable default values */
10207 for (p = 0; p < MAX_PLAYERS; p++)
10209 for (i = 0; i < SPR_MAX; i++)
10211 player_mapping[p][i].element_rnd = EL_UNKNOWN;
10212 player_mapping[p][i].action = ACTION_DEFAULT;
10213 player_mapping[p][i].direction = MV_NONE;
10217 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
10219 int e = em_object_mapping_list[i].element_em;
10221 object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd;
10222 object_mapping[e].is_backside = em_object_mapping_list[i].is_backside;
10224 if (em_object_mapping_list[i].action != -1)
10225 object_mapping[e].action = em_object_mapping_list[i].action;
10227 if (em_object_mapping_list[i].direction != -1)
10228 object_mapping[e].direction =
10229 MV_DIR_FROM_BIT(em_object_mapping_list[i].direction);
10232 for (i = 0; em_player_mapping_list[i].action_em != -1; i++)
10234 int a = em_player_mapping_list[i].action_em;
10235 int p = em_player_mapping_list[i].player_nr;
10237 player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd;
10239 if (em_player_mapping_list[i].action != -1)
10240 player_mapping[p][a].action = em_player_mapping_list[i].action;
10242 if (em_player_mapping_list[i].direction != -1)
10243 player_mapping[p][a].direction =
10244 MV_DIR_FROM_BIT(em_player_mapping_list[i].direction);
10247 for (i = 0; i < TILE_MAX; i++)
10249 int element = object_mapping[i].element_rnd;
10250 int action = object_mapping[i].action;
10251 int direction = object_mapping[i].direction;
10252 boolean is_backside = object_mapping[i].is_backside;
10254 boolean action_removing = (action == ACTION_DIGGING ||
10255 action == ACTION_SNAPPING ||
10256 action == ACTION_COLLECTING);
10258 boolean action_exploding = ((action == ACTION_EXPLODING ||
10259 action == ACTION_SMASHED_BY_ROCK ||
10260 action == ACTION_SMASHED_BY_SPRING) &&
10261 element != EL_DIAMOND);
10262 boolean action_active = (action == ACTION_ACTIVE);
10263 boolean action_other = (action == ACTION_OTHER);
10265 for (j = 0; j < 8; j++)
10268 int effective_element = get_effective_element_EM(i, j);
10270 int effective_element = (j > 5 && i == Yacid_splash_eB ? EL_EMPTY :
10271 j > 5 && i == Yacid_splash_wB ? EL_EMPTY :
10273 i == Xdrip_stretch ? element :
10274 i == Xdrip_stretchB ? element :
10275 i == Ydrip_s1 ? element :
10276 i == Ydrip_s1B ? element :
10277 i == Xball_1B ? element :
10278 i == Xball_2 ? element :
10279 i == Xball_2B ? element :
10280 i == Yball_eat ? element :
10281 i == Ykey_1_eat ? element :
10282 i == Ykey_2_eat ? element :
10283 i == Ykey_3_eat ? element :
10284 i == Ykey_4_eat ? element :
10285 i == Ykey_5_eat ? element :
10286 i == Ykey_6_eat ? element :
10287 i == Ykey_7_eat ? element :
10288 i == Ykey_8_eat ? element :
10289 i == Ylenses_eat ? element :
10290 i == Ymagnify_eat ? element :
10291 i == Ygrass_eat ? element :
10292 i == Ydirt_eat ? element :
10293 i == Yemerald_stone ? EL_EMERALD :
10294 i == Ydiamond_stone ? EL_ROCK :
10295 i == Xsand_stonein_1 ? element :
10296 i == Xsand_stonein_2 ? element :
10297 i == Xsand_stonein_3 ? element :
10298 i == Xsand_stonein_4 ? element :
10299 is_backside ? EL_EMPTY :
10300 action_removing ? EL_EMPTY :
10303 int effective_action = (j < 7 ? action :
10304 i == Xdrip_stretch ? action :
10305 i == Xdrip_stretchB ? action :
10306 i == Ydrip_s1 ? action :
10307 i == Ydrip_s1B ? action :
10308 i == Xball_1B ? action :
10309 i == Xball_2 ? action :
10310 i == Xball_2B ? action :
10311 i == Yball_eat ? action :
10312 i == Ykey_1_eat ? action :
10313 i == Ykey_2_eat ? action :
10314 i == Ykey_3_eat ? action :
10315 i == Ykey_4_eat ? action :
10316 i == Ykey_5_eat ? action :
10317 i == Ykey_6_eat ? action :
10318 i == Ykey_7_eat ? action :
10319 i == Ykey_8_eat ? action :
10320 i == Ylenses_eat ? action :
10321 i == Ymagnify_eat ? action :
10322 i == Ygrass_eat ? action :
10323 i == Ydirt_eat ? action :
10324 i == Xsand_stonein_1 ? action :
10325 i == Xsand_stonein_2 ? action :
10326 i == Xsand_stonein_3 ? action :
10327 i == Xsand_stonein_4 ? action :
10328 i == Xsand_stoneout_1 ? action :
10329 i == Xsand_stoneout_2 ? action :
10330 i == Xboom_android ? ACTION_EXPLODING :
10331 action_exploding ? ACTION_EXPLODING :
10332 action_active ? action :
10333 action_other ? action :
10335 int graphic = (el_act_dir2img(effective_element, effective_action,
10337 int crumbled = (el_act_dir2crm(effective_element, effective_action,
10339 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
10340 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
10341 boolean has_action_graphics = (graphic != base_graphic);
10342 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
10343 struct GraphicInfo *g = &graphic_info[graphic];
10345 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
10347 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
10348 Bitmap *src_bitmap;
10350 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
10351 boolean special_animation = (action != ACTION_DEFAULT &&
10352 g->anim_frames == 3 &&
10353 g->anim_delay == 2 &&
10354 g->anim_mode & ANIM_LINEAR);
10355 int sync_frame = (i == Xdrip_stretch ? 7 :
10356 i == Xdrip_stretchB ? 7 :
10357 i == Ydrip_s2 ? j + 8 :
10358 i == Ydrip_s2B ? j + 8 :
10360 i == Xacid_2 ? 10 :
10361 i == Xacid_3 ? 20 :
10362 i == Xacid_4 ? 30 :
10363 i == Xacid_5 ? 40 :
10364 i == Xacid_6 ? 50 :
10365 i == Xacid_7 ? 60 :
10366 i == Xacid_8 ? 70 :
10367 i == Xfake_acid_1 ? 0 :
10368 i == Xfake_acid_2 ? 10 :
10369 i == Xfake_acid_3 ? 20 :
10370 i == Xfake_acid_4 ? 30 :
10371 i == Xfake_acid_5 ? 40 :
10372 i == Xfake_acid_6 ? 50 :
10373 i == Xfake_acid_7 ? 60 :
10374 i == Xfake_acid_8 ? 70 :
10376 i == Xball_2B ? j + 8 :
10377 i == Yball_eat ? j + 1 :
10378 i == Ykey_1_eat ? j + 1 :
10379 i == Ykey_2_eat ? j + 1 :
10380 i == Ykey_3_eat ? j + 1 :
10381 i == Ykey_4_eat ? j + 1 :
10382 i == Ykey_5_eat ? j + 1 :
10383 i == Ykey_6_eat ? j + 1 :
10384 i == Ykey_7_eat ? j + 1 :
10385 i == Ykey_8_eat ? j + 1 :
10386 i == Ylenses_eat ? j + 1 :
10387 i == Ymagnify_eat ? j + 1 :
10388 i == Ygrass_eat ? j + 1 :
10389 i == Ydirt_eat ? j + 1 :
10390 i == Xamoeba_1 ? 0 :
10391 i == Xamoeba_2 ? 1 :
10392 i == Xamoeba_3 ? 2 :
10393 i == Xamoeba_4 ? 3 :
10394 i == Xamoeba_5 ? 0 :
10395 i == Xamoeba_6 ? 1 :
10396 i == Xamoeba_7 ? 2 :
10397 i == Xamoeba_8 ? 3 :
10398 i == Xexit_2 ? j + 8 :
10399 i == Xexit_3 ? j + 16 :
10400 i == Xdynamite_1 ? 0 :
10401 i == Xdynamite_2 ? 8 :
10402 i == Xdynamite_3 ? 16 :
10403 i == Xdynamite_4 ? 24 :
10404 i == Xsand_stonein_1 ? j + 1 :
10405 i == Xsand_stonein_2 ? j + 9 :
10406 i == Xsand_stonein_3 ? j + 17 :
10407 i == Xsand_stonein_4 ? j + 25 :
10408 i == Xsand_stoneout_1 && j == 0 ? 0 :
10409 i == Xsand_stoneout_1 && j == 1 ? 0 :
10410 i == Xsand_stoneout_1 && j == 2 ? 1 :
10411 i == Xsand_stoneout_1 && j == 3 ? 2 :
10412 i == Xsand_stoneout_1 && j == 4 ? 2 :
10413 i == Xsand_stoneout_1 && j == 5 ? 3 :
10414 i == Xsand_stoneout_1 && j == 6 ? 4 :
10415 i == Xsand_stoneout_1 && j == 7 ? 4 :
10416 i == Xsand_stoneout_2 && j == 0 ? 5 :
10417 i == Xsand_stoneout_2 && j == 1 ? 6 :
10418 i == Xsand_stoneout_2 && j == 2 ? 7 :
10419 i == Xsand_stoneout_2 && j == 3 ? 8 :
10420 i == Xsand_stoneout_2 && j == 4 ? 9 :
10421 i == Xsand_stoneout_2 && j == 5 ? 11 :
10422 i == Xsand_stoneout_2 && j == 6 ? 13 :
10423 i == Xsand_stoneout_2 && j == 7 ? 15 :
10424 i == Xboom_bug && j == 1 ? 2 :
10425 i == Xboom_bug && j == 2 ? 2 :
10426 i == Xboom_bug && j == 3 ? 4 :
10427 i == Xboom_bug && j == 4 ? 4 :
10428 i == Xboom_bug && j == 5 ? 2 :
10429 i == Xboom_bug && j == 6 ? 2 :
10430 i == Xboom_bug && j == 7 ? 0 :
10431 i == Xboom_bomb && j == 1 ? 2 :
10432 i == Xboom_bomb && j == 2 ? 2 :
10433 i == Xboom_bomb && j == 3 ? 4 :
10434 i == Xboom_bomb && j == 4 ? 4 :
10435 i == Xboom_bomb && j == 5 ? 2 :
10436 i == Xboom_bomb && j == 6 ? 2 :
10437 i == Xboom_bomb && j == 7 ? 0 :
10438 i == Xboom_android && j == 7 ? 6 :
10439 i == Xboom_1 && j == 1 ? 2 :
10440 i == Xboom_1 && j == 2 ? 2 :
10441 i == Xboom_1 && j == 3 ? 4 :
10442 i == Xboom_1 && j == 4 ? 4 :
10443 i == Xboom_1 && j == 5 ? 6 :
10444 i == Xboom_1 && j == 6 ? 6 :
10445 i == Xboom_1 && j == 7 ? 8 :
10446 i == Xboom_2 && j == 0 ? 8 :
10447 i == Xboom_2 && j == 1 ? 8 :
10448 i == Xboom_2 && j == 2 ? 10 :
10449 i == Xboom_2 && j == 3 ? 10 :
10450 i == Xboom_2 && j == 4 ? 10 :
10451 i == Xboom_2 && j == 5 ? 12 :
10452 i == Xboom_2 && j == 6 ? 12 :
10453 i == Xboom_2 && j == 7 ? 12 :
10454 special_animation && j == 4 ? 3 :
10455 effective_action != action ? 0 :
10459 Bitmap *debug_bitmap = g_em->bitmap;
10460 int debug_src_x = g_em->src_x;
10461 int debug_src_y = g_em->src_y;
10464 int frame = getAnimationFrame(g->anim_frames,
10467 g->anim_start_frame,
10470 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y,
10471 g->double_movement && is_backside);
10473 g_em->bitmap = src_bitmap;
10474 g_em->src_x = src_x;
10475 g_em->src_y = src_y;
10476 g_em->src_offset_x = 0;
10477 g_em->src_offset_y = 0;
10478 g_em->dst_offset_x = 0;
10479 g_em->dst_offset_y = 0;
10480 g_em->width = TILEX;
10481 g_em->height = TILEY;
10483 g_em->preserve_background = FALSE;
10486 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
10491 g_em->crumbled_bitmap = NULL;
10492 g_em->crumbled_src_x = 0;
10493 g_em->crumbled_src_y = 0;
10494 g_em->crumbled_border_size = 0;
10496 g_em->has_crumbled_graphics = FALSE;
10499 if (has_crumbled_graphics && crumbled == IMG_EMPTY_SPACE)
10500 printf("::: empty crumbled: %d [%s], %d, %d\n",
10501 effective_element, element_info[effective_element].token_name,
10502 effective_action, direction);
10505 /* if element can be crumbled, but certain action graphics are just empty
10506 space (like instantly snapping sand to empty space in 1 frame), do not
10507 treat these empty space graphics as crumbled graphics in EMC engine */
10508 if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
10510 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
10511 g_crumbled->anim_delay,
10512 g_crumbled->anim_mode,
10513 g_crumbled->anim_start_frame,
10516 getGraphicSource(crumbled, frame_crumbled, &src_bitmap, &src_x, &src_y);
10518 g_em->has_crumbled_graphics = TRUE;
10519 g_em->crumbled_bitmap = src_bitmap;
10520 g_em->crumbled_src_x = src_x;
10521 g_em->crumbled_src_y = src_y;
10522 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
10526 if (g_em == &graphic_info_em_object[207][0])
10527 printf("... %d, %d [%d, %d, %d, %d] [%d, %d, %d, %d, %d, %d => %d]\n",
10528 graphic_info_em_object[207][0].crumbled_src_x,
10529 graphic_info_em_object[207][0].crumbled_src_y,
10531 crumbled, frame, src_x, src_y,
10536 g->anim_start_frame,
10538 gfx.anim_random_frame,
10543 printf("::: EMC tile %d is crumbled\n", i);
10549 if (element == EL_ROCK &&
10550 effective_action == ACTION_FILLING)
10551 printf("::: has_action_graphics == %d\n", has_action_graphics);
10554 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
10555 effective_action == ACTION_MOVING ||
10556 effective_action == ACTION_PUSHING ||
10557 effective_action == ACTION_EATING)) ||
10558 (!has_action_graphics && (effective_action == ACTION_FILLING ||
10559 effective_action == ACTION_EMPTYING)))
10562 (effective_action == ACTION_FALLING ||
10563 effective_action == ACTION_FILLING ||
10564 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
10565 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
10566 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
10567 int num_steps = (i == Ydrip_s1 ? 16 :
10568 i == Ydrip_s1B ? 16 :
10569 i == Ydrip_s2 ? 16 :
10570 i == Ydrip_s2B ? 16 :
10571 i == Xsand_stonein_1 ? 32 :
10572 i == Xsand_stonein_2 ? 32 :
10573 i == Xsand_stonein_3 ? 32 :
10574 i == Xsand_stonein_4 ? 32 :
10575 i == Xsand_stoneout_1 ? 16 :
10576 i == Xsand_stoneout_2 ? 16 : 8);
10577 int cx = ABS(dx) * (TILEX / num_steps);
10578 int cy = ABS(dy) * (TILEY / num_steps);
10579 int step_frame = (i == Ydrip_s2 ? j + 8 :
10580 i == Ydrip_s2B ? j + 8 :
10581 i == Xsand_stonein_2 ? j + 8 :
10582 i == Xsand_stonein_3 ? j + 16 :
10583 i == Xsand_stonein_4 ? j + 24 :
10584 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
10585 int step = (is_backside ? step_frame : num_steps - step_frame);
10587 if (is_backside) /* tile where movement starts */
10589 if (dx < 0 || dy < 0)
10591 g_em->src_offset_x = cx * step;
10592 g_em->src_offset_y = cy * step;
10596 g_em->dst_offset_x = cx * step;
10597 g_em->dst_offset_y = cy * step;
10600 else /* tile where movement ends */
10602 if (dx < 0 || dy < 0)
10604 g_em->dst_offset_x = cx * step;
10605 g_em->dst_offset_y = cy * step;
10609 g_em->src_offset_x = cx * step;
10610 g_em->src_offset_y = cy * step;
10614 g_em->width = TILEX - cx * step;
10615 g_em->height = TILEY - cy * step;
10618 /* create unique graphic identifier to decide if tile must be redrawn */
10619 /* bit 31 - 16 (16 bit): EM style graphic
10620 bit 15 - 12 ( 4 bit): EM style frame
10621 bit 11 - 6 ( 6 bit): graphic width
10622 bit 5 - 0 ( 6 bit): graphic height */
10623 g_em->unique_identifier =
10624 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
10628 /* skip check for EMC elements not contained in original EMC artwork */
10629 if (element == EL_EMC_FAKE_ACID)
10632 if (g_em->bitmap != debug_bitmap ||
10633 g_em->src_x != debug_src_x ||
10634 g_em->src_y != debug_src_y ||
10635 g_em->src_offset_x != 0 ||
10636 g_em->src_offset_y != 0 ||
10637 g_em->dst_offset_x != 0 ||
10638 g_em->dst_offset_y != 0 ||
10639 g_em->width != TILEX ||
10640 g_em->height != TILEY)
10642 static int last_i = -1;
10650 printf("::: EMC GFX ERROR for element %d -> %d ('%s', '%s', %d)",
10651 i, element, element_info[element].token_name,
10652 element_action_info[effective_action].suffix, direction);
10654 if (element != effective_element)
10655 printf(" [%d ('%s')]",
10657 element_info[effective_element].token_name);
10661 if (g_em->bitmap != debug_bitmap)
10662 printf(" %d (%d): different bitmap! (0x%08x != 0x%08x)\n",
10663 j, is_backside, (int)(g_em->bitmap), (int)(debug_bitmap));
10665 if (g_em->src_x != debug_src_x ||
10666 g_em->src_y != debug_src_y)
10667 printf(" frame %d (%c): %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
10668 j, (is_backside ? 'B' : 'F'),
10669 g_em->src_x, g_em->src_y,
10670 g_em->src_x / 32, g_em->src_y / 32,
10671 debug_src_x, debug_src_y,
10672 debug_src_x / 32, debug_src_y / 32);
10674 if (g_em->src_offset_x != 0 ||
10675 g_em->src_offset_y != 0 ||
10676 g_em->dst_offset_x != 0 ||
10677 g_em->dst_offset_y != 0)
10678 printf(" %d (%d): offsets %d,%d and %d,%d should be all 0\n",
10680 g_em->src_offset_x, g_em->src_offset_y,
10681 g_em->dst_offset_x, g_em->dst_offset_y);
10683 if (g_em->width != TILEX ||
10684 g_em->height != TILEY)
10685 printf(" %d (%d): size %d,%d should be %d,%d\n",
10687 g_em->width, g_em->height, TILEX, TILEY);
10689 num_em_gfx_errors++;
10696 for (i = 0; i < TILE_MAX; i++)
10698 for (j = 0; j < 8; j++)
10700 int element = object_mapping[i].element_rnd;
10701 int action = object_mapping[i].action;
10702 int direction = object_mapping[i].direction;
10703 boolean is_backside = object_mapping[i].is_backside;
10704 int graphic_action = el_act_dir2img(element, action, direction);
10705 int graphic_default = el_act_dir2img(element, ACTION_DEFAULT, direction);
10707 if ((action == ACTION_SMASHED_BY_ROCK ||
10708 action == ACTION_SMASHED_BY_SPRING ||
10709 action == ACTION_EATING) &&
10710 graphic_action == graphic_default)
10712 int e = (action == ACTION_SMASHED_BY_ROCK ? Ystone_s :
10713 action == ACTION_SMASHED_BY_SPRING ? Yspring_s :
10714 direction == MV_LEFT ? (is_backside? Yspring_wB: Yspring_w) :
10715 direction == MV_RIGHT ? (is_backside? Yspring_eB: Yspring_e) :
10718 /* no separate animation for "smashed by rock" -- use rock instead */
10719 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
10720 struct GraphicInfo_EM *g_xx = &graphic_info_em_object[e][7 - j];
10722 g_em->bitmap = g_xx->bitmap;
10723 g_em->src_x = g_xx->src_x;
10724 g_em->src_y = g_xx->src_y;
10725 g_em->src_offset_x = g_xx->src_offset_x;
10726 g_em->src_offset_y = g_xx->src_offset_y;
10727 g_em->dst_offset_x = g_xx->dst_offset_x;
10728 g_em->dst_offset_y = g_xx->dst_offset_y;
10729 g_em->width = g_xx->width;
10730 g_em->height = g_xx->height;
10731 g_em->unique_identifier = g_xx->unique_identifier;
10734 g_em->preserve_background = TRUE;
10739 for (p = 0; p < MAX_PLAYERS; p++)
10741 for (i = 0; i < SPR_MAX; i++)
10743 int element = player_mapping[p][i].element_rnd;
10744 int action = player_mapping[p][i].action;
10745 int direction = player_mapping[p][i].direction;
10747 for (j = 0; j < 8; j++)
10749 int effective_element = element;
10750 int effective_action = action;
10751 int graphic = (direction == MV_NONE ?
10752 el_act2img(effective_element, effective_action) :
10753 el_act_dir2img(effective_element, effective_action,
10755 struct GraphicInfo *g = &graphic_info[graphic];
10756 struct GraphicInfo_EM *g_em = &graphic_info_em_player[p][i][7 - j];
10757 Bitmap *src_bitmap;
10759 int sync_frame = j;
10762 Bitmap *debug_bitmap = g_em->bitmap;
10763 int debug_src_x = g_em->src_x;
10764 int debug_src_y = g_em->src_y;
10767 int frame = getAnimationFrame(g->anim_frames,
10770 g->anim_start_frame,
10773 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
10775 g_em->bitmap = src_bitmap;
10776 g_em->src_x = src_x;
10777 g_em->src_y = src_y;
10778 g_em->src_offset_x = 0;
10779 g_em->src_offset_y = 0;
10780 g_em->dst_offset_x = 0;
10781 g_em->dst_offset_y = 0;
10782 g_em->width = TILEX;
10783 g_em->height = TILEY;
10787 /* skip check for EMC elements not contained in original EMC artwork */
10788 if (element == EL_PLAYER_3 ||
10789 element == EL_PLAYER_4)
10792 if (g_em->bitmap != debug_bitmap ||
10793 g_em->src_x != debug_src_x ||
10794 g_em->src_y != debug_src_y)
10796 static int last_i = -1;
10804 printf("::: EMC GFX ERROR for p/a %d/%d -> %d ('%s', '%s', %d)",
10805 p, i, element, element_info[element].token_name,
10806 element_action_info[effective_action].suffix, direction);
10808 if (element != effective_element)
10809 printf(" [%d ('%s')]",
10811 element_info[effective_element].token_name);
10815 if (g_em->bitmap != debug_bitmap)
10816 printf(" %d: different bitmap! (0x%08x != 0x%08x)\n",
10817 j, (int)(g_em->bitmap), (int)(debug_bitmap));
10819 if (g_em->src_x != debug_src_x ||
10820 g_em->src_y != debug_src_y)
10821 printf(" frame %d: %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
10823 g_em->src_x, g_em->src_y,
10824 g_em->src_x / 32, g_em->src_y / 32,
10825 debug_src_x, debug_src_y,
10826 debug_src_x / 32, debug_src_y / 32);
10828 num_em_gfx_errors++;
10838 printf("::: [%d errors found]\n", num_em_gfx_errors);
10844 void CheckSingleStepMode_EM(byte action[MAX_PLAYERS], int frame,
10845 boolean any_player_moving,
10846 boolean player_is_dropping)
10848 if (tape.single_step && tape.recording && !tape.pausing)
10851 boolean active_players = FALSE;
10854 for (i = 0; i < MAX_PLAYERS; i++)
10855 if (action[i] != JOY_NO_ACTION)
10856 active_players = TRUE;
10860 if (frame == 0 && !player_is_dropping)
10861 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
10865 void CheckSingleStepMode_SP(boolean murphy_is_waiting,
10866 boolean murphy_is_dropping)
10869 printf("::: waiting: %d, dropping: %d\n",
10870 murphy_is_waiting, murphy_is_dropping);
10873 if (tape.single_step && tape.recording && !tape.pausing)
10875 // if (murphy_is_waiting || murphy_is_dropping)
10876 if (murphy_is_waiting)
10879 printf("::: murphy is waiting -> pause mode\n");
10882 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
10887 void getGraphicSource_SP(struct GraphicInfo_SP *g_sp,
10888 int graphic, int sync_frame, int x, int y)
10890 int frame = getGraphicAnimationFrame(graphic, sync_frame);
10892 getGraphicSource(graphic, frame, &g_sp->bitmap, &g_sp->src_x, &g_sp->src_y);
10895 boolean isNextAnimationFrame_SP(int graphic, int sync_frame)
10897 return (IS_NEXT_FRAME(sync_frame, graphic));
10900 int getGraphicInfo_Delay(int graphic)
10902 return graphic_info[graphic].anim_delay;
10905 void PlayMenuSoundExt(int sound)
10907 if (sound == SND_UNDEFINED)
10910 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
10911 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
10914 if (IS_LOOP_SOUND(sound))
10915 PlaySoundLoop(sound);
10920 void PlayMenuSound()
10922 PlayMenuSoundExt(menu.sound[game_status]);
10925 void PlayMenuSoundStereo(int sound, int stereo_position)
10927 if (sound == SND_UNDEFINED)
10930 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
10931 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
10934 if (IS_LOOP_SOUND(sound))
10935 PlaySoundExt(sound, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_LOOP);
10937 PlaySoundStereo(sound, stereo_position);
10940 void PlayMenuSoundIfLoopExt(int sound)
10942 if (sound == SND_UNDEFINED)
10945 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
10946 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
10949 if (IS_LOOP_SOUND(sound))
10950 PlaySoundLoop(sound);
10953 void PlayMenuSoundIfLoop()
10955 PlayMenuSoundIfLoopExt(menu.sound[game_status]);
10958 void PlayMenuMusicExt(int music)
10960 if (music == MUS_UNDEFINED)
10963 if (!setup.sound_music)
10969 void PlayMenuMusic()
10971 PlayMenuMusicExt(menu.music[game_status]);
10974 void PlaySoundActivating()
10977 PlaySound(SND_MENU_ITEM_ACTIVATING);
10981 void PlaySoundSelecting()
10984 PlaySound(SND_MENU_ITEM_SELECTING);
10988 void ToggleFullscreenOrChangeWindowScalingIfNeeded()
10990 boolean change_fullscreen = (setup.fullscreen !=
10991 video.fullscreen_enabled);
10992 boolean change_fullscreen_mode = (video.fullscreen_enabled &&
10993 !strEqual(setup.fullscreen_mode,
10994 video.fullscreen_mode_current));
10995 boolean change_window_scaling_percent = (!video.fullscreen_enabled &&
10996 setup.window_scaling_percent !=
10997 video.window_scaling_percent);
10999 if (change_window_scaling_percent && video.fullscreen_enabled)
11002 if (!change_window_scaling_percent && !video.fullscreen_available)
11005 #if defined(TARGET_SDL2)
11006 if (change_window_scaling_percent)
11008 SDLSetWindowScaling(setup.window_scaling_percent);
11012 else if (change_fullscreen)
11014 SDLSetWindowFullscreen(setup.fullscreen);
11016 /* set setup value according to successfully changed fullscreen mode */
11017 setup.fullscreen = video.fullscreen_enabled;
11023 if (change_fullscreen ||
11024 change_fullscreen_mode ||
11025 change_window_scaling_percent)
11027 Bitmap *tmp_backbuffer = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
11029 /* save backbuffer content which gets lost when toggling fullscreen mode */
11030 BlitBitmap(backbuffer, tmp_backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
11032 if (change_fullscreen_mode)
11034 /* keep fullscreen, but change fullscreen mode (screen resolution) */
11035 video.fullscreen_enabled = FALSE; /* force new fullscreen mode */
11038 if (change_window_scaling_percent)
11040 /* keep window mode, but change window scaling */
11041 video.fullscreen_enabled = TRUE; /* force new window scaling */
11044 /* toggle fullscreen */
11045 ChangeVideoModeIfNeeded(setup.fullscreen);
11047 /* set setup value according to successfully changed fullscreen mode */
11048 setup.fullscreen = video.fullscreen_enabled;
11050 /* restore backbuffer content from temporary backbuffer backup bitmap */
11051 BlitBitmap(tmp_backbuffer, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
11053 FreeBitmap(tmp_backbuffer);
11056 /* update visible window/screen */
11057 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
11059 redraw_mask = REDRAW_ALL;
11064 void ChangeViewportPropertiesIfNeeded()
11067 int *door_1_x = &DX;
11068 int *door_1_y = &DY;
11069 int *door_2_x = (game_status == GAME_MODE_EDITOR ? &EX : &VX);
11070 int *door_2_y = (game_status == GAME_MODE_EDITOR ? &EY : &VY);
11072 int gfx_game_mode = (game_status == GAME_MODE_PLAYING ||
11073 game_status == GAME_MODE_EDITOR ? game_status :
11075 int gfx_game_mode2 = (game_status == GAME_MODE_EDITOR ? GAME_MODE_DEFAULT :
11077 struct RectWithBorder *vp_playfield = &viewport.playfield[gfx_game_mode];
11078 struct RectWithBorder *vp_door_1 = &viewport.door_1[gfx_game_mode];
11079 struct RectWithBorder *vp_door_2 = &viewport.door_2[gfx_game_mode2];
11080 struct RectWithBorder *vp_door_3 = &viewport.door_2[GAME_MODE_EDITOR];
11081 int border_size = vp_playfield->border_size;
11082 int new_sx = vp_playfield->x + border_size;
11083 int new_sy = vp_playfield->y + border_size;
11084 int new_sxsize = vp_playfield->width - 2 * border_size;
11085 int new_sysize = vp_playfield->height - 2 * border_size;
11086 int new_real_sx = vp_playfield->x;
11087 int new_real_sy = vp_playfield->y;
11088 int new_full_sxsize = vp_playfield->width;
11089 int new_full_sysize = vp_playfield->height;
11090 int new_dx = vp_door_1->x;
11091 int new_dy = vp_door_1->y;
11092 int new_dxsize = vp_door_1->width;
11093 int new_dysize = vp_door_1->height;
11094 int new_vx = vp_door_2->x;
11095 int new_vy = vp_door_2->y;
11096 int new_vxsize = vp_door_2->width;
11097 int new_vysize = vp_door_2->height;
11098 int new_ex = vp_door_3->x;
11099 int new_ey = vp_door_3->y;
11100 int new_exsize = vp_door_3->width;
11101 int new_eysize = vp_door_3->height;
11103 int new_tilesize_var = TILESIZE / (setup.small_game_graphics ? 2 : 1);
11104 int tilesize = (gfx_game_mode == GAME_MODE_PLAYING ? new_tilesize_var :
11105 gfx_game_mode == GAME_MODE_EDITOR ? MINI_TILESIZE : TILESIZE);
11106 int new_scr_fieldx = new_sxsize / tilesize;
11107 int new_scr_fieldy = new_sysize / tilesize;
11108 int new_scr_fieldx_buffers = new_sxsize / new_tilesize_var;
11109 int new_scr_fieldy_buffers = new_sysize / new_tilesize_var;
11111 int new_scr_fieldx = (vp_playfield->width - 2 * border_size) / TILESIZE;
11112 int new_scr_fieldy = (vp_playfield->height - 2 * border_size) / TILESIZE;
11114 boolean init_gfx_buffers = FALSE;
11115 boolean init_video_buffer = FALSE;
11116 boolean init_gadgets_and_toons = FALSE;
11119 /* !!! TEST ONLY !!! */
11120 // InitGfxBuffers();
11124 if (viewport.window.width != WIN_XSIZE ||
11125 viewport.window.height != WIN_YSIZE)
11127 WIN_XSIZE = viewport.window.width;
11128 WIN_YSIZE = viewport.window.height;
11131 init_video_buffer = TRUE;
11132 init_gfx_buffers = TRUE;
11134 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
11138 SetDrawDeactivationMask(REDRAW_NONE);
11139 SetDrawBackgroundMask(REDRAW_FIELD);
11141 // RedrawBackground();
11145 // printf("::: video: init_video_buffer, init_gfx_buffers\n");
11148 if (new_scr_fieldx != SCR_FIELDX ||
11149 new_scr_fieldy != SCR_FIELDY)
11151 /* this always toggles between MAIN and GAME when using small tile size */
11153 SCR_FIELDX = new_scr_fieldx;
11154 SCR_FIELDY = new_scr_fieldy;
11156 // printf("::: new_scr_fieldx != SCR_FIELDX ...\n");
11160 if (new_tilesize_var != TILESIZE_VAR &&
11161 gfx_game_mode == GAME_MODE_PLAYING)
11163 /* doing this outside GAME_MODE_PLAYING would give wrong playfield size */
11165 TILESIZE_VAR = new_tilesize_var;
11167 init_gfx_buffers = TRUE;
11169 // printf("::: tilesize: init_gfx_buffers\n");
11173 if (new_sx != SX ||
11181 new_sxsize != SXSIZE ||
11182 new_sysize != SYSIZE ||
11183 new_dxsize != DXSIZE ||
11184 new_dysize != DYSIZE ||
11185 new_vxsize != VXSIZE ||
11186 new_vysize != VYSIZE ||
11187 new_exsize != EXSIZE ||
11188 new_eysize != EYSIZE ||
11189 new_real_sx != REAL_SX ||
11190 new_real_sy != REAL_SY ||
11191 new_full_sxsize != FULL_SXSIZE ||
11192 new_full_sysize != FULL_SYSIZE ||
11193 new_tilesize_var != TILESIZE_VAR
11196 vp_door_1->x != *door_1_x ||
11197 vp_door_1->y != *door_1_y ||
11198 vp_door_2->x != *door_2_x ||
11199 vp_door_2->y != *door_2_y
11211 SXSIZE = new_sxsize;
11212 SYSIZE = new_sysize;
11213 DXSIZE = new_dxsize;
11214 DYSIZE = new_dysize;
11215 VXSIZE = new_vxsize;
11216 VYSIZE = new_vysize;
11217 EXSIZE = new_exsize;
11218 EYSIZE = new_eysize;
11219 REAL_SX = new_real_sx;
11220 REAL_SY = new_real_sy;
11221 FULL_SXSIZE = new_full_sxsize;
11222 FULL_SYSIZE = new_full_sysize;
11223 TILESIZE_VAR = new_tilesize_var;
11226 printf("::: %d, %d, %d [%d]\n",
11227 SCR_FIELDX, SCR_FIELDY, TILESIZE_VAR,
11228 setup.small_game_graphics);
11232 *door_1_x = vp_door_1->x;
11233 *door_1_y = vp_door_1->y;
11234 *door_2_x = vp_door_2->x;
11235 *door_2_y = vp_door_2->y;
11239 init_gfx_buffers = TRUE;
11241 // printf("::: viewports: init_gfx_buffers\n");
11246 if (gfx_game_mode == GAME_MODE_MAIN)
11249 init_gadgets_and_toons = TRUE;
11251 // printf("::: viewports: init_gadgets_and_toons\n");
11259 if (init_gfx_buffers)
11261 // printf("::: init_gfx_buffers\n");
11263 SCR_FIELDX = new_scr_fieldx_buffers;
11264 SCR_FIELDY = new_scr_fieldy_buffers;
11268 SCR_FIELDX = new_scr_fieldx;
11269 SCR_FIELDY = new_scr_fieldy;
11272 if (init_video_buffer)
11274 // printf("::: init_video_buffer\n");
11276 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
11278 SetDrawDeactivationMask(REDRAW_NONE);
11279 SetDrawBackgroundMask(REDRAW_FIELD);
11282 if (init_gadgets_and_toons)
11284 // printf("::: init_gadgets_and_toons\n");
11291 printf("::: %d, %d / %d, %d [%d]\n", VX, VY, EX, EY, game_status);