1 /***********************************************************
2 * Rocks'n'Diamonds -- McDuffin Strikes Back! *
3 *----------------------------------------------------------*
4 * (c) 1995-2006 Artsoft Entertainment *
6 * Detmolder Strasse 189 *
9 * e-mail: info@artsoft.org *
10 *----------------------------------------------------------*
12 ***********************************************************/
16 #include "libgame/libgame.h"
28 /* select level set with EMC X11 graphics before activating EM GFX debugging */
29 #define DEBUG_EM_GFX 0
31 /* tool button identifiers */
32 #define TOOL_CTRL_ID_YES 0
33 #define TOOL_CTRL_ID_NO 1
34 #define TOOL_CTRL_ID_CONFIRM 2
35 #define TOOL_CTRL_ID_PLAYER_1 3
36 #define TOOL_CTRL_ID_PLAYER_2 4
37 #define TOOL_CTRL_ID_PLAYER_3 5
38 #define TOOL_CTRL_ID_PLAYER_4 6
40 #define NUM_TOOL_BUTTONS 7
42 /* constants for number of doors and door parts */
44 #define NUM_PANELS NUM_DOORS
45 // #define NUM_PANELS 0
46 #define MAX_PARTS_PER_DOOR 8
47 #define MAX_DOOR_PARTS (NUM_DOORS * MAX_PARTS_PER_DOOR + NUM_PANELS)
48 #define DOOR_PART_IS_PANEL(i) ((i) >= NUM_DOORS * MAX_PARTS_PER_DOOR)
51 struct DoorPartOrderInfo
57 static struct DoorPartOrderInfo door_part_order[MAX_DOOR_PARTS];
59 struct DoorPartControlInfo
63 struct DoorPartPosInfo *pos;
66 static struct DoorPartControlInfo door_part_controls[] =
70 IMG_DOOR_1_GFX_PART_1,
75 IMG_DOOR_1_GFX_PART_2,
80 IMG_DOOR_1_GFX_PART_3,
85 IMG_DOOR_1_GFX_PART_4,
90 IMG_DOOR_1_GFX_PART_5,
95 IMG_DOOR_1_GFX_PART_6,
100 IMG_DOOR_1_GFX_PART_7,
105 IMG_DOOR_1_GFX_PART_8,
111 IMG_DOOR_2_GFX_PART_1,
116 IMG_DOOR_2_GFX_PART_2,
121 IMG_DOOR_2_GFX_PART_3,
126 IMG_DOOR_2_GFX_PART_4,
131 IMG_DOOR_2_GFX_PART_5,
136 IMG_DOOR_2_GFX_PART_6,
141 IMG_DOOR_2_GFX_PART_7,
146 IMG_DOOR_2_GFX_PART_8,
152 IMG_BACKGROUND_PANEL,
169 /* forward declaration for internal use */
170 static void UnmapToolButtons();
171 static void HandleToolButtons(struct GadgetInfo *);
172 static int el_act_dir2crm(int, int, int);
173 static int el_act2crm(int, int);
175 static struct GadgetInfo *tool_gadget[NUM_TOOL_BUTTONS];
176 static int request_gadget_id = -1;
178 static char *print_if_not_empty(int element)
180 static char *s = NULL;
181 char *token_name = element_info[element].token_name;
186 s = checked_malloc(strlen(token_name) + 10 + 1);
188 if (element != EL_EMPTY)
189 sprintf(s, "%d\t['%s']", element, token_name);
191 sprintf(s, "%d", element);
196 void DumpTile(int x, int y)
201 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
207 printf_line("-", 79);
208 printf("Field Info: SCREEN(%d, %d), LEVEL(%d, %d)\n", sx, sy, x, y);
209 printf_line("-", 79);
211 if (!IN_LEV_FIELD(x, y))
213 printf("(not in level field)\n");
219 printf(" Feld: %d\t['%s']\n", Feld[x][y],
220 element_info[Feld[x][y]].token_name);
221 printf(" Back: %s\n", print_if_not_empty(Back[x][y]));
222 printf(" Store: %s\n", print_if_not_empty(Store[x][y]));
223 printf(" Store2: %s\n", print_if_not_empty(Store2[x][y]));
224 printf(" StorePlayer: %s\n", print_if_not_empty(StorePlayer[x][y]));
225 printf(" MovPos: %d\n", MovPos[x][y]);
226 printf(" MovDir: %d\n", MovDir[x][y]);
227 printf(" MovDelay: %d\n", MovDelay[x][y]);
228 printf(" ChangeDelay: %d\n", ChangeDelay[x][y]);
229 printf(" CustomValue: %d\n", CustomValue[x][y]);
230 printf(" GfxElement: %d\n", GfxElement[x][y]);
231 printf(" GfxAction: %d\n", GfxAction[x][y]);
232 printf(" GfxFrame: %d\n", GfxFrame[x][y]);
236 void SetDrawtoField(int mode)
238 if (mode == DRAW_BUFFERED && setup.soft_scrolling)
246 BX2 = SCR_FIELDX + 1;
247 BY2 = SCR_FIELDY + 1;
266 BX2 = SCR_FIELDX + 1;
267 BY2 = SCR_FIELDY + 1;
282 drawto_field = fieldbuffer;
284 else /* DRAW_BACKBUFFER */
290 BX2 = SCR_FIELDX - 1;
291 BY2 = SCR_FIELDY - 1;
295 drawto_field = backbuffer;
299 void RedrawPlayfield(boolean force_redraw, int x, int y, int width, int height)
301 if (game_status == GAME_MODE_PLAYING &&
302 level.game_engine_type == GAME_ENGINE_TYPE_EM)
304 /* currently there is no partial redraw -- always redraw whole playfield */
305 RedrawPlayfield_EM(TRUE);
307 /* blit playfield from scroll buffer to normal back buffer for fading in */
308 BlitScreenToBitmap_EM(backbuffer);
310 else if (game_status == GAME_MODE_PLAYING &&
311 level.game_engine_type == GAME_ENGINE_TYPE_SP)
313 /* currently there is no partial redraw -- always redraw whole playfield */
314 RedrawPlayfield_SP(TRUE);
316 /* blit playfield from scroll buffer to normal back buffer for fading in */
317 BlitScreenToBitmap_SP(backbuffer);
319 else if (game_status == GAME_MODE_PLAYING &&
320 !game.envelope_active)
326 width = gfx.sxsize + 2 * TILEX;
327 height = gfx.sysize + 2 * TILEY;
333 int x1 = (x - SX) / TILEX, y1 = (y - SY) / TILEY;
334 int x2 = (x - SX + width) / TILEX, y2 = (y - SY + height) / TILEY;
336 for (xx = BX1; xx <= BX2; xx++)
337 for (yy = BY1; yy <= BY2; yy++)
338 if (xx >= x1 && xx <= x2 && yy >= y1 && yy <= y2)
339 DrawScreenField(xx, yy);
343 if (setup.soft_scrolling)
345 int fx = FX, fy = FY;
347 fx += (ScreenMovDir & (MV_LEFT|MV_RIGHT) ? ScreenGfxPos : 0);
348 fy += (ScreenMovDir & (MV_UP|MV_DOWN) ? ScreenGfxPos : 0);
350 BlitBitmap(fieldbuffer, backbuffer, fx,fy, SXSIZE,SYSIZE, SX,SY);
362 BlitBitmap(drawto, window, x, y, width, height, x, y);
365 void DrawMaskedBorder_Rect(int x, int y, int width, int height)
367 Bitmap *bitmap = graphic_info[IMG_GLOBAL_BORDER].bitmap;
369 SetClipOrigin(bitmap, bitmap->stored_clip_gc, 0, 0);
370 BlitBitmapMasked(bitmap, backbuffer, x, y, width, height, x, y);
373 void DrawMaskedBorder_FIELD()
375 if (global.border_status >= GAME_MODE_TITLE &&
376 global.border_status <= GAME_MODE_PLAYING &&
377 border.draw_masked[global.border_status])
378 DrawMaskedBorder_Rect(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
381 void DrawMaskedBorder_DOOR_1()
383 if (border.draw_masked[GFX_SPECIAL_ARG_DOOR] &&
384 (global.border_status != GAME_MODE_EDITOR ||
385 border.draw_masked[GFX_SPECIAL_ARG_EDITOR]))
386 DrawMaskedBorder_Rect(DX, DY, DXSIZE, DYSIZE);
389 void DrawMaskedBorder_DOOR_2()
391 if (border.draw_masked[GFX_SPECIAL_ARG_DOOR] &&
392 global.border_status != GAME_MODE_EDITOR)
393 DrawMaskedBorder_Rect(VX, VY, VXSIZE, VYSIZE);
396 void DrawMaskedBorder_DOOR_3()
398 /* currently not available */
401 void DrawMaskedBorder_ALL()
403 DrawMaskedBorder_FIELD();
404 DrawMaskedBorder_DOOR_1();
405 DrawMaskedBorder_DOOR_2();
406 DrawMaskedBorder_DOOR_3();
409 void DrawMaskedBorder(int redraw_mask)
411 /* never draw masked screen borders on borderless screens */
412 if (effectiveGameStatus() == GAME_MODE_LOADING ||
413 effectiveGameStatus() == GAME_MODE_TITLE)
416 /* never draw masked screen borders when displaying request outside door */
417 if (effectiveGameStatus() == GAME_MODE_PSEUDO_DOOR &&
418 global.use_envelope_request)
421 if (redraw_mask & REDRAW_ALL)
422 DrawMaskedBorder_ALL();
425 if (redraw_mask & REDRAW_FIELD)
426 DrawMaskedBorder_FIELD();
427 if (redraw_mask & REDRAW_DOOR_1)
428 DrawMaskedBorder_DOOR_1();
429 if (redraw_mask & REDRAW_DOOR_2)
430 DrawMaskedBorder_DOOR_2();
431 if (redraw_mask & REDRAW_DOOR_3)
432 DrawMaskedBorder_DOOR_3();
436 void BlitScreenToBitmap(Bitmap *target_bitmap)
438 DrawBuffer *buffer = (drawto_field == window ? backbuffer : drawto_field);
439 int fx = FX, fy = FY;
442 int dx = (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
443 int dy = (ScreenMovDir & (MV_UP | MV_DOWN) ? ScreenGfxPos : 0);
444 int dx_var = dx * TILESIZE_VAR / TILESIZE;
445 int dy_var = dy * TILESIZE_VAR / TILESIZE;
448 // fx += dx * TILESIZE_VAR / TILESIZE;
449 // fy += dy * TILESIZE_VAR / TILESIZE;
451 fx += (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
452 fy += (ScreenMovDir & (MV_UP | MV_DOWN) ? ScreenGfxPos : 0);
455 ffx = (scroll_x - SBX_Left) * TILEX_VAR + dx_var;
456 ffy = (scroll_y - SBY_Upper) * TILEY_VAR + dy_var;
458 if (EVEN(SCR_FIELDX))
460 if (ffx < SBX_Right * TILEX_VAR + TILEX_VAR / 2 + TILEX_VAR)
461 fx += dx_var - MIN(ffx, TILEX_VAR / 2) + TILEX_VAR;
463 fx += (dx_var > 0 ? TILEX_VAR : 0);
470 if (EVEN(SCR_FIELDY))
472 if (ffy < SBY_Lower * TILEY_VAR + TILEY_VAR / 2 + TILEY_VAR)
473 fy += dy_var - MIN(ffy, TILEY_VAR / 2) + TILEY_VAR;
475 fy += (dy_var > 0 ? TILEY_VAR : 0);
483 printf("::: (%d, %d) [(%d / %d, %d / %d)] => %d, %d\n",
486 SBY_Upper, SBY_Lower,
490 if (border.draw_masked[GAME_MODE_PLAYING])
492 if (buffer != backbuffer)
494 /* copy playfield buffer to backbuffer to add masked border */
495 BlitBitmap(buffer, backbuffer, fx, fy, SXSIZE, SYSIZE, SX, SY);
496 DrawMaskedBorder(REDRAW_FIELD);
499 BlitBitmap(backbuffer, target_bitmap,
500 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
505 BlitBitmap(buffer, target_bitmap, fx, fy, SXSIZE, SYSIZE, SX, SY);
512 DrawBuffer *buffer = (drawto_field == window ? backbuffer : drawto_field);
515 printf("::: TILES TO REFRESH: %d\n", redraw_tiles);
516 for (x = 0; x < SCR_FIELDX; x++)
517 for (y = 0 ; y < SCR_FIELDY; y++)
518 if (redraw[redraw_x1 + x][redraw_y1 + y])
519 printf("::: - %d, %d [%s]\n",
520 LEVELX(x), LEVELY(y),
521 EL_NAME(Feld[LEVELX(x)][LEVELY(y)]));
524 if (redraw_mask & REDRAW_TILES && redraw_tiles > REDRAWTILES_THRESHOLD)
525 redraw_mask |= REDRAW_FIELD;
528 // never redraw single tiles, always redraw the whole field
529 // (redrawing single tiles up to a certain threshold was faster on old,
530 // now legacy graphics, but slows things down on modern graphics now)
531 // UPDATE: this is now globally defined by value of REDRAWTILES_THRESHOLD
532 if (redraw_mask & REDRAW_TILES)
533 redraw_mask |= REDRAW_FIELD;
537 /* !!! TEST ONLY !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */
538 /* (force full redraw) */
539 if (game_status == GAME_MODE_PLAYING)
540 redraw_mask |= REDRAW_FIELD;
543 if (redraw_mask & REDRAW_FIELD)
544 redraw_mask &= ~REDRAW_TILES;
546 if (redraw_mask == REDRAW_NONE)
551 if (redraw_mask & REDRAW_ALL)
552 printf("[REDRAW_ALL]");
553 if (redraw_mask & REDRAW_FIELD)
554 printf("[REDRAW_FIELD]");
555 if (redraw_mask & REDRAW_TILES)
556 printf("[REDRAW_TILES]");
557 if (redraw_mask & REDRAW_DOOR_1)
558 printf("[REDRAW_DOOR_1]");
559 if (redraw_mask & REDRAW_DOOR_2)
560 printf("[REDRAW_DOOR_2]");
561 if (redraw_mask & REDRAW_FROM_BACKBUFFER)
562 printf("[REDRAW_FROM_BACKBUFFER]");
563 printf(" [%d]\n", FrameCounter);
566 if (redraw_mask & REDRAW_TILES &&
567 game_status == GAME_MODE_PLAYING &&
568 border.draw_masked[GAME_MODE_PLAYING])
569 redraw_mask |= REDRAW_FIELD;
571 if (global.fps_slowdown && game_status == GAME_MODE_PLAYING)
573 static boolean last_frame_skipped = FALSE;
574 boolean skip_even_when_not_scrolling = TRUE;
575 boolean just_scrolling = (ScreenMovDir != 0);
576 boolean verbose = FALSE;
578 if (global.fps_slowdown_factor > 1 &&
579 (FrameCounter % global.fps_slowdown_factor) &&
580 (just_scrolling || skip_even_when_not_scrolling))
582 redraw_mask &= ~REDRAW_MAIN;
584 last_frame_skipped = TRUE;
587 printf("FRAME SKIPPED\n");
591 if (last_frame_skipped)
592 redraw_mask |= REDRAW_FIELD;
594 last_frame_skipped = FALSE;
597 printf("frame not skipped\n");
601 /* synchronize X11 graphics at this point; if we would synchronize the
602 display immediately after the buffer switching (after the XFlush),
603 this could mean that we have to wait for the graphics to complete,
604 although we could go on doing calculations for the next frame */
608 /* never draw masked border to backbuffer when using playfield buffer */
609 if (game_status != GAME_MODE_PLAYING ||
610 redraw_mask & REDRAW_FROM_BACKBUFFER ||
611 buffer == backbuffer)
612 DrawMaskedBorder(redraw_mask);
614 DrawMaskedBorder(redraw_mask & REDRAW_DOORS);
616 if (redraw_mask & REDRAW_ALL)
618 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
620 redraw_mask = REDRAW_NONE;
623 if (redraw_mask & REDRAW_FIELD)
626 printf("::: REDRAW_FIELD\n");
629 if (game_status != GAME_MODE_PLAYING ||
630 redraw_mask & REDRAW_FROM_BACKBUFFER)
632 BlitBitmap(backbuffer, window,
633 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE, REAL_SX, REAL_SY);
638 BlitScreenToBitmap(window);
640 int fx = FX, fy = FY;
643 int dx = (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
644 int dy = (ScreenMovDir & (MV_UP | MV_DOWN) ? ScreenGfxPos : 0);
645 int dx_var = dx * TILESIZE_VAR / TILESIZE;
646 int dy_var = dy * TILESIZE_VAR / TILESIZE;
649 // fx += dx * TILESIZE_VAR / TILESIZE;
650 // fy += dy * TILESIZE_VAR / TILESIZE;
652 fx += (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
653 fy += (ScreenMovDir & (MV_UP | MV_DOWN) ? ScreenGfxPos : 0);
656 /* !!! THIS WORKS !!! */
658 printf("::: %d, %d\n", scroll_x, scroll_y);
660 ffx = (scroll_x - SBX_Left) * TILEX_VAR + dx_var;
661 ffy = (scroll_y - SBY_Upper) * TILEY_VAR + dy_var;
663 if (EVEN(SCR_FIELDX))
665 if (ffx < SBX_Right * TILEX_VAR + TILEX_VAR / 2 + TILEX_VAR)
666 fx += dx_var - MIN(ffx, TILEX_VAR / 2) + TILEX_VAR;
668 fx += (dx > 0 ? TILEX_VAR : 0);
675 if (EVEN(SCR_FIELDY))
677 if (ffy < SBY_Lower * TILEY_VAR + TILEY_VAR / 2 + TILEY_VAR)
678 fy += dy_var - MIN(ffy, TILEY_VAR / 2) + TILEY_VAR;
680 fy += (dy > 0 ? TILEY_VAR : 0);
687 if (border.draw_masked[GAME_MODE_PLAYING])
689 if (buffer != backbuffer)
691 /* copy playfield buffer to backbuffer to add masked border */
692 BlitBitmap(buffer, backbuffer, fx, fy, SXSIZE, SYSIZE, SX, SY);
693 DrawMaskedBorder(REDRAW_FIELD);
696 BlitBitmap(backbuffer, window,
697 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
702 BlitBitmap(buffer, window, fx, fy, SXSIZE, SYSIZE, SX, SY);
708 printf("redrawing all (ScreenGfxPos == %d) because %s\n",
710 (setup.soft_scrolling ?
711 "setup.soft_scrolling" :
712 ABS(ScreenGfxPos) + ScrollStepSize == TILEX ?
713 "ABS(ScreenGfxPos) + ScrollStepSize == TILEX" :
714 ABS(ScreenGfxPos) == ScrollStepSize ?
715 "ABS(ScreenGfxPos) == ScrollStepSize" :
716 "redraw_tiles > REDRAWTILES_THRESHOLD"));
721 redraw_mask &= ~REDRAW_MAIN;
724 if (redraw_mask & REDRAW_DOORS)
726 if (redraw_mask & REDRAW_DOOR_1)
727 BlitBitmap(backbuffer, window, DX, DY, DXSIZE, DYSIZE, DX, DY);
729 if (redraw_mask & REDRAW_DOOR_2)
730 BlitBitmap(backbuffer, window, VX, VY, VXSIZE, VYSIZE, VX, VY);
732 if (redraw_mask & REDRAW_DOOR_3)
733 BlitBitmap(backbuffer, window, EX, EY, EXSIZE, EYSIZE, EX, EY);
735 redraw_mask &= ~REDRAW_DOORS;
738 if (redraw_mask & REDRAW_MICROLEVEL)
740 BlitBitmap(backbuffer, window, SX, SY + 10 * TILEY, SXSIZE, 7 * TILEY,
741 SX, SY + 10 * TILEY);
743 redraw_mask &= ~REDRAW_MICROLEVEL;
746 if (redraw_mask & REDRAW_TILES)
749 printf("::: REDRAW_TILES\n");
755 InitGfxClipRegion(TRUE, SX, SY, SXSIZE, SYSIZE);
758 int sx = SX; // - (EVEN(SCR_FIELDX) ? TILEX_VAR / 2 : 0);
759 int sy = SY; // + (EVEN(SCR_FIELDY) ? TILEY_VAR / 2 : 0);
762 int dx_var = dx * TILESIZE_VAR / TILESIZE;
763 int dy_var = dy * TILESIZE_VAR / TILESIZE;
765 int fx = FX, fy = FY;
767 int scr_fieldx = SCR_FIELDX + (EVEN(SCR_FIELDX) ? 2 : 0);
768 int scr_fieldy = SCR_FIELDY + (EVEN(SCR_FIELDY) ? 2 : 0);
770 ffx = (scroll_x - SBX_Left) * TILEX_VAR + dx_var;
771 ffy = (scroll_y - SBY_Upper) * TILEY_VAR + dy_var;
773 if (EVEN(SCR_FIELDX))
775 if (ffx < SBX_Right * TILEX_VAR + TILEX_VAR / 2 + TILEX_VAR)
777 fx += dx_var - MIN(ffx, TILEX_VAR / 2) + TILEX_VAR;
786 fx += (dx_var > 0 ? TILEX_VAR : 0);
790 if (EVEN(SCR_FIELDY))
792 if (ffy < SBY_Lower * TILEY_VAR + TILEY_VAR / 2 + TILEY_VAR)
794 fy += dy_var - MIN(ffy, TILEY_VAR / 2) + TILEY_VAR;
803 fy += (dy_var > 0 ? TILEY_VAR : 0);
808 printf("::: %d, %d, %d, %d\n", sx, sy, SCR_FIELDX, SCR_FIELDY);
811 for (x = 0; x < scr_fieldx; x++)
812 for (y = 0 ; y < scr_fieldy; y++)
813 if (redraw[redraw_x1 + x][redraw_y1 + y])
814 BlitBitmap(buffer, window,
815 FX + x * TILEX_VAR, FY + y * TILEY_VAR,
816 TILEX_VAR, TILEY_VAR,
817 sx + x * TILEX_VAR, sy + y * TILEY_VAR);
820 InitGfxClipRegion(FALSE, -1, -1, -1, -1);
822 for (x = 0; x < SCR_FIELDX; x++)
823 for (y = 0 ; y < SCR_FIELDY; y++)
824 if (redraw[redraw_x1 + x][redraw_y1 + y])
825 BlitBitmap(buffer, window,
826 FX + x * TILEX_VAR, FY + y * TILEY_VAR,
827 TILEX_VAR, TILEY_VAR,
828 SX + x * TILEX_VAR, SY + y * TILEY_VAR);
832 for (x = 0; x < SCR_FIELDX; x++)
833 for (y = 0 ; y < SCR_FIELDY; y++)
834 if (redraw[redraw_x1 + x][redraw_y1 + y])
835 BlitBitmap(buffer, window,
836 FX + x * TILEX, FY + y * TILEY, TILEX, TILEY,
837 SX + x * TILEX, SY + y * TILEY);
841 if (redraw_mask & REDRAW_FPS) /* display frames per second */
846 sprintf(info1, " (only every %d. frame)", global.fps_slowdown_factor);
847 if (!global.fps_slowdown)
850 sprintf(text, "%04.1f fps%s", global.frames_per_second, info1);
852 DrawTextExt(window, SX + SXSIZE + SX, 0, text, FONT_TEXT_2, BLIT_OPAQUE);
854 DrawTextExt(window, SX, SY, text, FONT_TEXT_2, BLIT_OPAQUE);
860 for (x = 0; x < MAX_BUF_XSIZE; x++)
861 for (y = 0; y < MAX_BUF_YSIZE; y++)
864 redraw_mask = REDRAW_NONE;
867 static void FadeCrossSaveBackbuffer()
869 BlitBitmap(backbuffer, bitmap_db_cross, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
872 static void FadeExt(int fade_mask, int fade_mode, int fade_type)
874 static int fade_type_skip = FADE_TYPE_NONE;
875 void (*draw_border_function)(void) = NULL;
876 Bitmap *bitmap = (fade_mode & FADE_TYPE_TRANSFORM ? bitmap_db_cross : NULL);
877 int x, y, width, height;
878 int fade_delay, post_delay;
880 if (fade_type == FADE_TYPE_FADE_OUT)
882 if (fade_type_skip != FADE_TYPE_NONE)
885 printf("::: skipping %d ... [%d] (X)\n", fade_mode, fade_type_skip);
888 /* skip all fade operations until specified fade operation */
889 if (fade_type & fade_type_skip)
890 fade_type_skip = FADE_TYPE_NONE;
895 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
897 FadeCrossSaveBackbuffer();
903 redraw_mask |= fade_mask;
905 if (fade_type == FADE_TYPE_SKIP)
908 printf("::: will skip %d ... [%d]\n", fade_mode, fade_type_skip);
911 fade_type_skip = fade_mode;
917 printf("::: !!! FADING %d ... [%d] [%d]\n", fade_mode, fade_type,
922 fade_delay = fading.fade_delay;
923 post_delay = (fade_mode == FADE_MODE_FADE_OUT ? fading.post_delay : 0);
926 if (fade_type_skip != FADE_TYPE_NONE)
929 printf("::: skipping %d ... [%d]\n", fade_mode, fade_type_skip);
932 /* skip all fade operations until specified fade operation */
933 if (fade_type & fade_type_skip)
934 fade_type_skip = FADE_TYPE_NONE;
944 if (global.autoplay_leveldir)
946 // fading.fade_mode = FADE_MODE_NONE;
953 if (fading.fade_mode == FADE_MODE_NONE)
961 /* !!! what about fade_mask == REDRAW_FIELD | REDRAW_ALL ??? !!! */
964 printf("::: NOW FADING %d ... [%d]\n", fade_mode, fade_type);
968 if (fade_mask == REDRAW_NONE)
969 fade_mask = REDRAW_FIELD;
972 // if (fade_mask & REDRAW_FIELD)
973 if (fade_mask == REDRAW_FIELD)
978 height = FULL_SYSIZE;
981 fade_delay = fading.fade_delay;
982 post_delay = (fade_mode == FADE_MODE_FADE_OUT ? fading.post_delay : 0);
985 if (border.draw_masked_when_fading)
986 draw_border_function = DrawMaskedBorder_FIELD; /* update when fading */
988 DrawMaskedBorder_FIELD(); /* draw once */
990 else /* REDRAW_ALL */
998 fade_delay = fading.fade_delay;
999 post_delay = (fade_mode == FADE_MODE_FADE_OUT ? fading.post_delay : 0);
1004 if (!setup.fade_screens ||
1006 fading.fade_mode == FADE_MODE_NONE)
1008 if (!setup.fade_screens || fade_delay == 0)
1011 if (fade_mode == FADE_MODE_FADE_OUT)
1015 if (fade_mode == FADE_MODE_FADE_OUT &&
1016 fading.fade_mode != FADE_MODE_NONE)
1017 ClearRectangle(backbuffer, x, y, width, height);
1021 BlitBitmap(backbuffer, window, x, y, width, height, x, y);
1022 redraw_mask = REDRAW_NONE;
1030 FadeRectangle(bitmap, x, y, width, height, fade_mode, fade_delay, post_delay,
1031 draw_border_function);
1033 redraw_mask &= ~fade_mask;
1036 void FadeIn(int fade_mask)
1038 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
1039 FadeExt(fade_mask, fading.fade_mode, FADE_TYPE_FADE_IN);
1041 FadeExt(fade_mask, FADE_MODE_FADE_IN, FADE_TYPE_FADE_IN);
1044 void FadeOut(int fade_mask)
1046 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
1047 FadeExt(fade_mask, fading.fade_mode, FADE_TYPE_FADE_OUT);
1049 FadeExt(fade_mask, FADE_MODE_FADE_OUT, FADE_TYPE_FADE_OUT);
1051 global.border_status = game_status;
1054 static void FadeSetLeaveNext(struct TitleFadingInfo fading_leave, boolean set)
1056 static struct TitleFadingInfo fading_leave_stored;
1059 fading_leave_stored = fading_leave;
1061 fading = fading_leave_stored;
1064 void FadeSetEnterMenu()
1066 fading = menu.enter_menu;
1069 printf("::: storing enter_menu\n");
1072 FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
1075 void FadeSetLeaveMenu()
1077 fading = menu.leave_menu;
1080 printf("::: storing leave_menu\n");
1083 FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
1086 void FadeSetEnterScreen()
1088 fading = menu.enter_screen[game_status];
1091 printf("::: storing leave_screen[%d]\n", game_status);
1094 FadeSetLeaveNext(menu.leave_screen[game_status], TRUE); /* store */
1097 void FadeSetNextScreen()
1099 fading = menu.next_screen;
1102 printf("::: storing next_screen\n");
1105 // (do not overwrite fade mode set by FadeSetEnterScreen)
1106 // FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
1109 void FadeSetLeaveScreen()
1112 printf("::: recalling last stored value\n");
1115 FadeSetLeaveNext(menu.leave_screen[game_status], FALSE); /* recall */
1118 void FadeSetFromType(int type)
1120 if (type & TYPE_ENTER_SCREEN)
1121 FadeSetEnterScreen();
1122 else if (type & TYPE_ENTER)
1124 else if (type & TYPE_LEAVE)
1128 void FadeSetDisabled()
1130 static struct TitleFadingInfo fading_none = { FADE_MODE_NONE, -1, -1, -1 };
1132 fading = fading_none;
1135 void FadeSkipNextFadeIn()
1137 FadeExt(0, FADE_MODE_SKIP_FADE_IN, FADE_TYPE_SKIP);
1140 void FadeSkipNextFadeOut()
1142 FadeExt(0, FADE_MODE_SKIP_FADE_OUT, FADE_TYPE_SKIP);
1145 void SetWindowBackgroundImageIfDefined(int graphic)
1147 if (graphic_info[graphic].bitmap)
1148 SetWindowBackgroundBitmap(graphic_info[graphic].bitmap);
1151 void SetMainBackgroundImageIfDefined(int graphic)
1153 if (graphic_info[graphic].bitmap)
1154 SetMainBackgroundBitmap(graphic_info[graphic].bitmap);
1157 void SetDoorBackgroundImageIfDefined(int graphic)
1159 if (graphic_info[graphic].bitmap)
1160 SetDoorBackgroundBitmap(graphic_info[graphic].bitmap);
1163 void SetWindowBackgroundImage(int graphic)
1165 SetWindowBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
1166 graphic_info[graphic].bitmap ?
1167 graphic_info[graphic].bitmap :
1168 graphic_info[IMG_BACKGROUND].bitmap);
1171 void SetMainBackgroundImage(int graphic)
1173 SetMainBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
1174 graphic_info[graphic].bitmap ?
1175 graphic_info[graphic].bitmap :
1176 graphic_info[IMG_BACKGROUND].bitmap);
1179 void SetDoorBackgroundImage(int graphic)
1181 SetDoorBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
1182 graphic_info[graphic].bitmap ?
1183 graphic_info[graphic].bitmap :
1184 graphic_info[IMG_BACKGROUND].bitmap);
1187 void SetPanelBackground()
1190 struct GraphicInfo *gfx = &graphic_info[IMG_BACKGROUND_PANEL];
1193 BlitBitmapTiled(gfx->bitmap, bitmap_db_panel, gfx->src_x, gfx->src_y,
1194 gfx->width, gfx->height, 0, 0, DXSIZE, DYSIZE);
1196 /* (ClearRectangle() only needed if panel bitmap is smaller than panel) */
1197 ClearRectangle(bitmap_db_panel, DX, DY, DXSIZE, DYSIZE);
1198 BlitBitmap(gfx->bitmap, bitmap_db_panel, gfx->src_x, gfx->src_y,
1199 MIN(gfx->width, DXSIZE), MIN(gfx->height, DYSIZE), 0, 0);
1202 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, bitmap_db_panel,
1203 DOOR_GFX_PAGEX5, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE, 0, 0);
1206 SetDoorBackgroundBitmap(bitmap_db_panel);
1209 void DrawBackground(int x, int y, int width, int height)
1211 /* !!! "drawto" might still point to playfield buffer here (see below) !!! */
1212 /* (when entering hall of fame after playing) */
1214 ClearRectangleOnBackground(drawto, x, y, width, height);
1216 ClearRectangleOnBackground(backbuffer, x, y, width, height);
1222 if (IN_GFX_FIELD_FULL(x, y))
1223 redraw_mask |= REDRAW_FIELD;
1224 else if (IN_GFX_DOOR_1(x, y))
1225 redraw_mask |= REDRAW_DOOR_1;
1226 else if (IN_GFX_DOOR_2(x, y))
1227 redraw_mask |= REDRAW_DOOR_2;
1228 else if (IN_GFX_DOOR_3(x, y))
1229 redraw_mask |= REDRAW_DOOR_3;
1231 /* (this only works for the current arrangement of playfield and panels) */
1233 redraw_mask |= REDRAW_FIELD;
1234 else if (y < gfx.vy)
1235 redraw_mask |= REDRAW_DOOR_1;
1237 redraw_mask |= REDRAW_DOOR_2;
1241 /* (this is just wrong (when drawing to one of the two door panel areas)) */
1242 redraw_mask |= REDRAW_FIELD;
1246 void DrawBackgroundForFont(int x, int y, int width, int height, int font_nr)
1248 struct FontBitmapInfo *font = getFontBitmapInfo(font_nr);
1250 if (font->bitmap == NULL)
1253 DrawBackground(x, y, width, height);
1256 void DrawBackgroundForGraphic(int x, int y, int width, int height, int graphic)
1258 struct GraphicInfo *g = &graphic_info[graphic];
1260 if (g->bitmap == NULL)
1263 DrawBackground(x, y, width, height);
1268 /* !!! "drawto" might still point to playfield buffer here (see above) !!! */
1269 /* (when entering hall of fame after playing) */
1270 DrawBackground(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
1272 /* !!! maybe this should be done before clearing the background !!! */
1273 if (setup.soft_scrolling && game_status == GAME_MODE_PLAYING)
1275 ClearRectangle(fieldbuffer, 0, 0, FXSIZE, FYSIZE);
1276 SetDrawtoField(DRAW_BUFFERED);
1279 SetDrawtoField(DRAW_BACKBUFFER);
1282 void MarkTileDirty(int x, int y)
1284 int xx = redraw_x1 + x;
1285 int yy = redraw_y1 + y;
1287 if (!redraw[xx][yy])
1290 redraw[xx][yy] = TRUE;
1291 redraw_mask |= REDRAW_TILES;
1294 void SetBorderElement()
1298 BorderElement = EL_EMPTY;
1300 for (y = 0; y < lev_fieldy && BorderElement == EL_EMPTY; y++)
1302 for (x = 0; x < lev_fieldx; x++)
1304 if (!IS_INDESTRUCTIBLE(Feld[x][y]))
1305 BorderElement = EL_STEELWALL;
1307 if (y != 0 && y != lev_fieldy - 1 && x != lev_fieldx - 1)
1313 void FloodFillLevel(int from_x, int from_y, int fill_element,
1314 short field[MAX_LEV_FIELDX][MAX_LEV_FIELDY],
1315 int max_fieldx, int max_fieldy)
1319 static int check[4][2] = { { -1, 0 }, { 0, -1 }, { 1, 0 }, { 0, 1 } };
1320 static int safety = 0;
1322 /* check if starting field still has the desired content */
1323 if (field[from_x][from_y] == fill_element)
1328 if (safety > max_fieldx * max_fieldy)
1329 Error(ERR_EXIT, "Something went wrong in 'FloodFill()'. Please debug.");
1331 old_element = field[from_x][from_y];
1332 field[from_x][from_y] = fill_element;
1334 for (i = 0; i < 4; i++)
1336 x = from_x + check[i][0];
1337 y = from_y + check[i][1];
1339 if (IN_FIELD(x, y, max_fieldx, max_fieldy) && field[x][y] == old_element)
1340 FloodFillLevel(x, y, fill_element, field, max_fieldx, max_fieldy);
1346 void SetRandomAnimationValue(int x, int y)
1348 gfx.anim_random_frame = GfxRandom[x][y];
1351 inline int getGraphicAnimationFrame(int graphic, int sync_frame)
1353 /* animation synchronized with global frame counter, not move position */
1354 if (graphic_info[graphic].anim_global_sync || sync_frame < 0)
1355 sync_frame = FrameCounter;
1357 return getAnimationFrame(graphic_info[graphic].anim_frames,
1358 graphic_info[graphic].anim_delay,
1359 graphic_info[graphic].anim_mode,
1360 graphic_info[graphic].anim_start_frame,
1364 void getSizedGraphicSourceExt(int graphic, int frame, int tilesize_raw,
1365 Bitmap **bitmap, int *x, int *y,
1366 boolean get_backside)
1370 int width_mult, width_div;
1371 int height_mult, height_div;
1375 { 15, 16, 2, 3 }, /* 1 x 1 */
1376 { 7, 8, 2, 3 }, /* 2 x 2 */
1377 { 3, 4, 2, 3 }, /* 4 x 4 */
1378 { 1, 2, 2, 3 }, /* 8 x 8 */
1379 { 0, 1, 2, 3 }, /* 16 x 16 */
1380 { 0, 1, 0, 1 }, /* 32 x 32 */
1382 struct GraphicInfo *g = &graphic_info[graphic];
1383 Bitmap *src_bitmap = g->bitmap;
1384 int tilesize = MIN(MAX(1, tilesize_raw), TILESIZE);
1385 int offset_calc_pos = log_2(tilesize);
1386 int width_mult = offset_calc[offset_calc_pos].width_mult;
1387 int width_div = offset_calc[offset_calc_pos].width_div;
1388 int height_mult = offset_calc[offset_calc_pos].height_mult;
1389 int height_div = offset_calc[offset_calc_pos].height_div;
1390 int startx = src_bitmap->width * width_mult / width_div;
1391 int starty = src_bitmap->height * height_mult / height_div;
1393 int src_x = (g->src_x + (get_backside ? g->offset2_x : 0)) *
1394 tilesize / TILESIZE;
1395 int src_y = (g->src_y + (get_backside ? g->offset2_y : 0)) *
1396 tilesize / TILESIZE;
1398 int src_x = g->src_x * tilesize / TILESIZE;
1399 int src_y = g->src_y * tilesize / TILESIZE;
1401 int width = g->width * tilesize / TILESIZE;
1402 int height = g->height * tilesize / TILESIZE;
1403 int offset_x = g->offset_x * tilesize / TILESIZE;
1404 int offset_y = g->offset_y * tilesize / TILESIZE;
1406 if (g->offset_y == 0) /* frames are ordered horizontally */
1408 int max_width = g->anim_frames_per_line * width;
1409 int pos = (src_y / height) * max_width + src_x + frame * offset_x;
1411 src_x = pos % max_width;
1412 src_y = src_y % height + pos / max_width * height;
1414 else if (g->offset_x == 0) /* frames are ordered vertically */
1416 int max_height = g->anim_frames_per_line * height;
1417 int pos = (src_x / width) * max_height + src_y + frame * offset_y;
1419 src_x = src_x % width + pos / max_height * width;
1420 src_y = pos % max_height;
1422 else /* frames are ordered diagonally */
1424 src_x = src_x + frame * offset_x;
1425 src_y = src_y + frame * offset_y;
1428 *bitmap = src_bitmap;
1429 *x = startx + src_x;
1430 *y = starty + src_y;
1433 void getFixedGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
1434 int *x, int *y, boolean get_backside)
1436 getSizedGraphicSourceExt(graphic, frame, TILESIZE, bitmap, x, y,
1440 void getSizedGraphicSource(int graphic, int frame, int tilesize_raw,
1441 Bitmap **bitmap, int *x, int *y)
1443 getSizedGraphicSourceExt(graphic, frame, tilesize_raw, bitmap, x, y, FALSE);
1446 void getFixedGraphicSource(int graphic, int frame,
1447 Bitmap **bitmap, int *x, int *y)
1449 getSizedGraphicSourceExt(graphic, frame, TILESIZE, bitmap, x, y, FALSE);
1452 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
1455 getSizedGraphicSource(graphic, 0, MINI_TILESIZE, bitmap, x, y);
1457 struct GraphicInfo *g = &graphic_info[graphic];
1458 int mini_startx = 0;
1459 int mini_starty = g->bitmap->height * 2 / 3;
1461 *bitmap = g->bitmap;
1462 *x = mini_startx + g->src_x / 2;
1463 *y = mini_starty + g->src_y / 2;
1467 inline void getGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
1468 int *x, int *y, boolean get_backside)
1470 struct GraphicInfo *g = &graphic_info[graphic];
1471 int src_x = g->src_x + (get_backside ? g->offset2_x : 0);
1472 int src_y = g->src_y + (get_backside ? g->offset2_y : 0);
1475 if (TILESIZE_VAR != TILESIZE)
1476 return getSizedGraphicSourceExt(graphic, frame, TILESIZE_VAR, bitmap, x, y,
1480 *bitmap = g->bitmap;
1482 if (g->offset_y == 0) /* frames are ordered horizontally */
1484 int max_width = g->anim_frames_per_line * g->width;
1485 int pos = (src_y / g->height) * max_width + src_x + frame * g->offset_x;
1487 *x = pos % max_width;
1488 *y = src_y % g->height + pos / max_width * g->height;
1490 else if (g->offset_x == 0) /* frames are ordered vertically */
1492 int max_height = g->anim_frames_per_line * g->height;
1493 int pos = (src_x / g->width) * max_height + src_y + frame * g->offset_y;
1495 *x = src_x % g->width + pos / max_height * g->width;
1496 *y = pos % max_height;
1498 else /* frames are ordered diagonally */
1500 *x = src_x + frame * g->offset_x;
1501 *y = src_y + frame * g->offset_y;
1505 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
1507 getGraphicSourceExt(graphic, frame, bitmap, x, y, FALSE);
1510 void DrawGraphic(int x, int y, int graphic, int frame)
1513 if (!IN_SCR_FIELD(x, y))
1515 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
1516 printf("DrawGraphic(): This should never happen!\n");
1522 DrawGraphicExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR, graphic,
1525 DrawGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic, frame);
1527 MarkTileDirty(x, y);
1530 void DrawFixedGraphic(int x, int y, int graphic, int frame)
1533 if (!IN_SCR_FIELD(x, y))
1535 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
1536 printf("DrawGraphic(): This should never happen!\n");
1541 DrawFixedGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic,
1543 MarkTileDirty(x, y);
1546 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
1552 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1554 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX_VAR, TILEY_VAR, x, y);
1556 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
1560 void DrawFixedGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
1566 getFixedGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1567 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
1570 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
1573 if (!IN_SCR_FIELD(x, y))
1575 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
1576 printf("DrawGraphicThruMask(): This should never happen!\n");
1582 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR,
1585 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic,
1588 MarkTileDirty(x, y);
1591 void DrawFixedGraphicThruMask(int x, int y, int graphic, int frame)
1594 if (!IN_SCR_FIELD(x, y))
1596 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
1597 printf("DrawGraphicThruMask(): This should never happen!\n");
1602 DrawFixedGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
1604 MarkTileDirty(x, y);
1607 void DrawGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y, int graphic,
1613 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1615 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1616 dst_x - src_x, dst_y - src_y);
1618 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX_VAR, TILEY_VAR,
1621 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dst_x, dst_y);
1625 void DrawFixedGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y,
1626 int graphic, int frame)
1631 getFixedGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1633 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1634 dst_x - src_x, dst_y - src_y);
1635 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dst_x, dst_y);
1638 void DrawSizedGraphic(int x, int y, int graphic, int frame, int tilesize)
1640 DrawSizedGraphicExt(drawto, SX + x * tilesize, SY + y * tilesize, graphic,
1642 MarkTileDirty(x / tilesize, y / tilesize);
1645 void DrawSizedGraphicExt(DrawBuffer *d, int x, int y, int graphic, int frame,
1651 getSizedGraphicSource(graphic, frame, tilesize, &src_bitmap, &src_x, &src_y);
1652 BlitBitmap(src_bitmap, d, src_x, src_y, tilesize, tilesize, x, y);
1655 void DrawMiniGraphic(int x, int y, int graphic)
1657 DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
1658 MarkTileDirty(x / 2, y / 2);
1661 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
1666 getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1667 BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
1670 inline static void DrawGraphicShiftedNormal(int x, int y, int dx, int dy,
1671 int graphic, int frame,
1672 int cut_mode, int mask_mode)
1677 int width = TILEX, height = TILEY;
1680 if (dx || dy) /* shifted graphic */
1682 if (x < BX1) /* object enters playfield from the left */
1689 else if (x > BX2) /* object enters playfield from the right */
1695 else if (x==BX1 && dx < 0) /* object leaves playfield to the left */
1701 else if (x==BX2 && dx > 0) /* object leaves playfield to the right */
1703 else if (dx) /* general horizontal movement */
1704 MarkTileDirty(x + SIGN(dx), y);
1706 if (y < BY1) /* object enters playfield from the top */
1708 if (cut_mode==CUT_BELOW) /* object completely above top border */
1716 else if (y > BY2) /* object enters playfield from the bottom */
1722 else if (y==BY1 && dy < 0) /* object leaves playfield to the top */
1728 else if (dy > 0 && cut_mode == CUT_ABOVE)
1730 if (y == BY2) /* object completely above bottom border */
1736 MarkTileDirty(x, y + 1);
1737 } /* object leaves playfield to the bottom */
1738 else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
1740 else if (dy) /* general vertical movement */
1741 MarkTileDirty(x, y + SIGN(dy));
1745 if (!IN_SCR_FIELD(x, y))
1747 printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
1748 printf("DrawGraphicShifted(): This should never happen!\n");
1754 width = width * TILESIZE_VAR / TILESIZE;
1755 height = height * TILESIZE_VAR / TILESIZE;
1756 cx = cx * TILESIZE_VAR / TILESIZE;
1757 cy = cy * TILESIZE_VAR / TILESIZE;
1758 dx = dx * TILESIZE_VAR / TILESIZE;
1759 dy = dy * TILESIZE_VAR / TILESIZE;
1762 if (width > 0 && height > 0)
1764 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1770 dst_x = FX + x * TILEX_VAR + dx;
1771 dst_y = FY + y * TILEY_VAR + dy;
1773 dst_x = FX + x * TILEX + dx;
1774 dst_y = FY + y * TILEY + dy;
1777 if (mask_mode == USE_MASKING)
1779 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1780 dst_x - src_x, dst_y - src_y);
1781 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1785 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1788 MarkTileDirty(x, y);
1792 inline static void DrawGraphicShiftedDouble(int x, int y, int dx, int dy,
1793 int graphic, int frame,
1794 int cut_mode, int mask_mode)
1800 int width = TILEX_VAR, height = TILEY_VAR;
1802 int width = TILEX, height = TILEY;
1806 int x2 = x + SIGN(dx);
1807 int y2 = y + SIGN(dy);
1809 /* !!! DOES NOT WORK FOR SLOW MOVEMENT !!! */
1810 int sync_frame = GfxFrame[LEVELX(x)][LEVELY(y)];
1812 /* movement with two-tile animations must be sync'ed with movement position,
1813 not with current GfxFrame (which can be higher when using slow movement) */
1814 int anim_pos = (dx ? ABS(dx) : ABS(dy));
1815 int anim_frames = graphic_info[graphic].anim_frames;
1817 /* (we also need anim_delay here for movement animations with less frames) */
1818 int anim_delay = graphic_info[graphic].anim_delay;
1819 int sync_frame = anim_pos * anim_frames * anim_delay / TILESIZE;
1821 int sync_frame = anim_pos * anim_frames / TILESIZE;
1824 boolean draw_start_tile = (cut_mode != CUT_ABOVE); /* only for falling! */
1825 boolean draw_end_tile = (cut_mode != CUT_BELOW); /* only for falling! */
1827 /* re-calculate animation frame for two-tile movement animation */
1828 frame = getGraphicAnimationFrame(graphic, sync_frame);
1832 printf("::: %d, %d, %d => %d [%d]\n",
1833 anim_pos, anim_frames, anim_delay, sync_frame, graphic);
1835 printf("::: %d, %d => %d\n",
1836 anim_pos, anim_frames, sync_frame);
1841 printf("::: %d [%d, %d] [%d] [%d]\n", frame, sync_frame, dy,
1842 GfxFrame[LEVELX(x)][LEVELY(y)], mask_mode);
1845 /* check if movement start graphic inside screen area and should be drawn */
1846 if (draw_start_tile && IN_SCR_FIELD(x1, y1))
1848 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, TRUE);
1851 dst_x = FX + x1 * TILEX_VAR;
1852 dst_y = FY + y1 * TILEY_VAR;
1854 dst_x = FX + x1 * TILEX;
1855 dst_y = FY + y1 * TILEY;
1858 if (mask_mode == USE_MASKING)
1860 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1861 dst_x - src_x, dst_y - src_y);
1862 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1866 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1869 MarkTileDirty(x1, y1);
1872 /* check if movement end graphic inside screen area and should be drawn */
1873 if (draw_end_tile && IN_SCR_FIELD(x2, y2))
1875 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
1878 dst_x = FX + x2 * TILEX_VAR;
1879 dst_y = FY + y2 * TILEY_VAR;
1881 dst_x = FX + x2 * TILEX;
1882 dst_y = FY + y2 * TILEY;
1885 if (mask_mode == USE_MASKING)
1887 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1888 dst_x - src_x, dst_y - src_y);
1889 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1893 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1896 MarkTileDirty(x2, y2);
1900 static void DrawGraphicShifted(int x, int y, int dx, int dy,
1901 int graphic, int frame,
1902 int cut_mode, int mask_mode)
1906 DrawGraphic(x, y, graphic, frame);
1911 if (graphic_info[graphic].double_movement) /* EM style movement images */
1912 DrawGraphicShiftedDouble(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1914 DrawGraphicShiftedNormal(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1917 void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
1918 int frame, int cut_mode)
1920 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, USE_MASKING);
1923 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
1924 int cut_mode, int mask_mode)
1926 int lx = LEVELX(x), ly = LEVELY(y);
1930 if (IN_LEV_FIELD(lx, ly))
1932 SetRandomAnimationValue(lx, ly);
1934 graphic = el_act_dir2img(element, GfxAction[lx][ly], GfxDir[lx][ly]);
1935 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1937 /* do not use double (EM style) movement graphic when not moving */
1938 if (graphic_info[graphic].double_movement && !dx && !dy)
1940 graphic = el_act_dir2img(element, ACTION_DEFAULT, GfxDir[lx][ly]);
1941 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1944 else /* border element */
1946 graphic = el2img(element);
1947 frame = getGraphicAnimationFrame(graphic, -1);
1950 if (element == EL_EXPANDABLE_WALL)
1952 boolean left_stopped = FALSE, right_stopped = FALSE;
1954 if (!IN_LEV_FIELD(lx - 1, ly) || IS_WALL(Feld[lx - 1][ly]))
1955 left_stopped = TRUE;
1956 if (!IN_LEV_FIELD(lx + 1, ly) || IS_WALL(Feld[lx + 1][ly]))
1957 right_stopped = TRUE;
1959 if (left_stopped && right_stopped)
1961 else if (left_stopped)
1963 graphic = IMG_EXPANDABLE_WALL_GROWING_RIGHT;
1964 frame = graphic_info[graphic].anim_frames - 1;
1966 else if (right_stopped)
1968 graphic = IMG_EXPANDABLE_WALL_GROWING_LEFT;
1969 frame = graphic_info[graphic].anim_frames - 1;
1974 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
1975 else if (mask_mode == USE_MASKING)
1976 DrawGraphicThruMask(x, y, graphic, frame);
1978 DrawGraphic(x, y, graphic, frame);
1981 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
1982 int cut_mode, int mask_mode)
1984 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1985 DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
1986 cut_mode, mask_mode);
1989 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
1992 DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1995 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
1998 DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
2001 void DrawLevelElementThruMask(int x, int y, int element)
2003 DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
2006 void DrawLevelFieldThruMask(int x, int y)
2008 DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
2011 /* !!! implementation of quicksand is totally broken !!! */
2012 #define IS_CRUMBLED_TILE(x, y, e) \
2013 (GFX_CRUMBLED(e) && (!IN_LEV_FIELD(x, y) || \
2014 !IS_MOVING(x, y) || \
2015 (e) == EL_QUICKSAND_EMPTYING || \
2016 (e) == EL_QUICKSAND_FAST_EMPTYING))
2018 static void DrawLevelFieldCrumbledInnerCorners(int x, int y, int dx, int dy,
2023 int width, height, cx, cy;
2024 int sx = SCREENX(x), sy = SCREENY(y);
2025 int crumbled_border_size = graphic_info[graphic].border_size;
2028 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
2030 for (i = 1; i < 4; i++)
2032 int dxx = (i & 1 ? dx : 0);
2033 int dyy = (i & 2 ? dy : 0);
2036 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
2039 /* check if neighbour field is of same crumble type */
2040 boolean same = (IS_CRUMBLED_TILE(xx, yy, element) &&
2041 graphic_info[graphic].class ==
2042 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class);
2044 /* return if check prevents inner corner */
2045 if (same == (dxx == dx && dyy == dy))
2049 /* if we reach this point, we have an inner corner */
2051 getGraphicSource(graphic, 1, &src_bitmap, &src_x, &src_y);
2054 width = crumbled_border_size * TILESIZE_VAR / TILESIZE;
2055 height = crumbled_border_size * TILESIZE_VAR / TILESIZE;
2056 cx = (dx > 0 ? TILEX - crumbled_border_size : 0) * TILESIZE_VAR / TILESIZE;
2057 cy = (dy > 0 ? TILEY - crumbled_border_size : 0) * TILESIZE_VAR / TILESIZE;
2059 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
2060 width, height, FX + sx * TILEX_VAR + cx, FY + sy * TILEY_VAR + cy);
2062 width = crumbled_border_size;
2063 height = crumbled_border_size;
2064 cx = (dx > 0 ? TILEX - crumbled_border_size : 0);
2065 cy = (dy > 0 ? TILEY - crumbled_border_size : 0);
2067 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
2068 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
2072 static void DrawLevelFieldCrumbledBorders(int x, int y, int graphic, int frame,
2077 int width, height, bx, by, cx, cy;
2078 int sx = SCREENX(x), sy = SCREENY(y);
2079 int crumbled_border_size = graphic_info[graphic].border_size;
2082 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
2084 /* draw simple, sloppy, non-corner-accurate crumbled border */
2087 width = (dir == 1 || dir == 2 ? crumbled_border_size : TILEX);
2088 height = (dir == 0 || dir == 3 ? crumbled_border_size : TILEY);
2089 cx = (dir == 2 ? TILEX - crumbled_border_size : 0);
2090 cy = (dir == 3 ? TILEY - crumbled_border_size : 0);
2092 if (dir == 1 || dir == 2) /* left or right crumbled border */
2094 width = crumbled_border_size;
2096 cx = (dir == 2 ? TILEX - crumbled_border_size : 0);
2099 else /* top or bottom crumbled border */
2102 height = crumbled_border_size;
2104 cy = (dir == 3 ? TILEY - crumbled_border_size : 0);
2109 BlitBitmap(src_bitmap, drawto_field,
2110 src_x + cx * TILESIZE_VAR / TILESIZE,
2111 src_y + cy * TILESIZE_VAR / TILESIZE,
2112 width * TILESIZE_VAR / TILESIZE,
2113 height * TILESIZE_VAR / TILESIZE,
2114 FX + sx * TILEX_VAR + cx * TILESIZE_VAR / TILESIZE,
2115 FY + sy * TILEY_VAR + cy * TILESIZE_VAR / TILESIZE);
2117 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
2118 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
2121 /* (remaining middle border part must be at least as big as corner part) */
2122 if (!(graphic_info[graphic].style & STYLE_ACCURATE_BORDERS) ||
2123 crumbled_border_size >= TILESIZE / 3)
2126 /* correct corners of crumbled border, if needed */
2129 for (i = -1; i <= 1; i+=2)
2131 int xx = x + (dir == 0 || dir == 3 ? i : 0);
2132 int yy = y + (dir == 1 || dir == 2 ? i : 0);
2133 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
2136 /* check if neighbour field is of same crumble type */
2137 if (IS_CRUMBLED_TILE(xx, yy, element) &&
2138 graphic_info[graphic].class ==
2139 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
2141 /* no crumbled corner, but continued crumbled border */
2143 int c1 = (dir == 2 || dir == 3 ? TILESIZE - crumbled_border_size : 0);
2144 int c2 = (i == 1 ? TILESIZE - crumbled_border_size : 0);
2145 int b1 = (i == 1 ? crumbled_border_size :
2146 TILESIZE - 2 * crumbled_border_size);
2148 width = crumbled_border_size;
2149 height = crumbled_border_size;
2151 if (dir == 1 || dir == 2)
2167 BlitBitmap(src_bitmap, drawto_field,
2168 src_x + bx * TILESIZE_VAR / TILESIZE,
2169 src_y + by * TILESIZE_VAR / TILESIZE,
2170 width * TILESIZE_VAR / TILESIZE,
2171 height * TILESIZE_VAR / TILESIZE,
2172 FX + sx * TILEX_VAR + cx * TILESIZE_VAR / TILESIZE,
2173 FY + sy * TILEY_VAR + cy * TILESIZE_VAR / TILESIZE);
2175 BlitBitmap(src_bitmap, drawto_field, src_x + bx, src_y + by,
2176 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
2181 if (dir == 1 || dir == 2) /* left or right crumbled border */
2183 for (i = -1; i <= 1; i+=2)
2187 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
2190 /* check if neighbour field is of same crumble type */
2191 if (IS_CRUMBLED_TILE(xx, yy, element) &&
2192 graphic_info[graphic].class ==
2193 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
2195 /* no crumbled corner, but continued crumbled border */
2197 width = crumbled_border_size;
2198 height = crumbled_border_size;
2199 cx = (dir == 2 ? TILEX - crumbled_border_size : 0);
2200 cy = (i == 1 ? TILEY - crumbled_border_size : 0);
2202 by = (i == 1 ? crumbled_border_size :
2203 TILEY - 2 * crumbled_border_size);
2205 BlitBitmap(src_bitmap, drawto_field, src_x + bx, src_y + by,
2206 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
2210 else /* top or bottom crumbled border */
2212 for (i = -1; i <= 1; i+=2)
2216 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
2219 /* check if neighbour field is of same crumble type */
2220 if (IS_CRUMBLED_TILE(xx, yy, element) &&
2221 graphic_info[graphic].class ==
2222 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
2224 /* no crumbled corner, but continued crumbled border */
2226 width = crumbled_border_size;
2227 height = crumbled_border_size;
2228 cx = (i == 1 ? TILEX - crumbled_border_size : 0);
2229 cy = (dir == 3 ? TILEY - crumbled_border_size : 0);
2230 bx = (i == 1 ? crumbled_border_size :
2231 TILEX - 2 * crumbled_border_size);
2234 BlitBitmap(src_bitmap, drawto_field, src_x + bx, src_y + by,
2235 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
2242 static void DrawLevelFieldCrumbledExt(int x, int y, int graphic, int frame)
2244 int sx = SCREENX(x), sy = SCREENY(y);
2247 static int xy[4][2] =
2255 if (!IN_LEV_FIELD(x, y))
2258 element = TILE_GFX_ELEMENT(x, y);
2260 /* crumble field itself */
2261 if (IS_CRUMBLED_TILE(x, y, element))
2263 if (!IN_SCR_FIELD(sx, sy))
2266 for (i = 0; i < 4; i++)
2268 int xx = x + xy[i][0];
2269 int yy = y + xy[i][1];
2271 element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
2274 /* check if neighbour field is of same crumble type */
2276 if (IS_CRUMBLED_TILE(xx, yy, element) &&
2277 graphic_info[graphic].class ==
2278 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
2281 if (IS_CRUMBLED_TILE(xx, yy, element))
2285 DrawLevelFieldCrumbledBorders(x, y, graphic, frame, i);
2288 if ((graphic_info[graphic].style & STYLE_INNER_CORNERS) &&
2289 graphic_info[graphic].anim_frames == 2)
2291 for (i = 0; i < 4; i++)
2293 int dx = (i & 1 ? +1 : -1);
2294 int dy = (i & 2 ? +1 : -1);
2296 DrawLevelFieldCrumbledInnerCorners(x, y, dx, dy, graphic);
2300 MarkTileDirty(sx, sy);
2302 else /* center field not crumbled -- crumble neighbour fields */
2304 for (i = 0; i < 4; i++)
2306 int xx = x + xy[i][0];
2307 int yy = y + xy[i][1];
2308 int sxx = sx + xy[i][0];
2309 int syy = sy + xy[i][1];
2311 if (!IN_LEV_FIELD(xx, yy) ||
2312 !IN_SCR_FIELD(sxx, syy))
2315 if (Feld[xx][yy] == EL_ELEMENT_SNAPPING)
2318 element = TILE_GFX_ELEMENT(xx, yy);
2320 if (!IS_CRUMBLED_TILE(xx, yy, element))
2323 graphic = el_act2crm(element, ACTION_DEFAULT);
2325 DrawLevelFieldCrumbledBorders(xx, yy, graphic, 0, 3 - i);
2327 MarkTileDirty(sxx, syy);
2332 void DrawLevelFieldCrumbled(int x, int y)
2336 if (!IN_LEV_FIELD(x, y))
2340 /* !!! CHECK THIS !!! */
2343 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
2344 GFX_CRUMBLED(GfxElement[x][y]))
2347 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
2348 GfxElement[x][y] != EL_UNDEFINED &&
2349 GFX_CRUMBLED(GfxElement[x][y]))
2351 DrawLevelFieldCrumbledDigging(x, y, GfxDir[x][y], GfxFrame[x][y]);
2358 graphic = el_act2crm(TILE_GFX_ELEMENT(x, y), ACTION_DEFAULT);
2360 graphic = el_act2crm(Feld[x][y], ACTION_DEFAULT);
2363 DrawLevelFieldCrumbledExt(x, y, graphic, 0);
2366 void DrawLevelFieldCrumbledDigging(int x, int y, int direction,
2369 int graphic1 = el_act_dir2img(GfxElement[x][y], ACTION_DIGGING, direction);
2370 int graphic2 = el_act_dir2crm(GfxElement[x][y], ACTION_DIGGING, direction);
2371 int frame1 = getGraphicAnimationFrame(graphic1, step_frame);
2372 int frame2 = getGraphicAnimationFrame(graphic2, step_frame);
2373 int sx = SCREENX(x), sy = SCREENY(y);
2375 DrawGraphic(sx, sy, graphic1, frame1);
2376 DrawLevelFieldCrumbledExt(x, y, graphic2, frame2);
2379 void DrawLevelFieldCrumbledNeighbours(int x, int y)
2381 int sx = SCREENX(x), sy = SCREENY(y);
2382 static int xy[4][2] =
2391 for (i = 0; i < 4; i++)
2393 int xx = x + xy[i][0];
2394 int yy = y + xy[i][1];
2395 int sxx = sx + xy[i][0];
2396 int syy = sy + xy[i][1];
2398 if (!IN_LEV_FIELD(xx, yy) ||
2399 !IN_SCR_FIELD(sxx, syy) ||
2400 !GFX_CRUMBLED(Feld[xx][yy]) ||
2404 DrawLevelField(xx, yy);
2408 static int getBorderElement(int x, int y)
2412 { EL_STEELWALL_TOPLEFT, EL_INVISIBLE_STEELWALL_TOPLEFT },
2413 { EL_STEELWALL_TOPRIGHT, EL_INVISIBLE_STEELWALL_TOPRIGHT },
2414 { EL_STEELWALL_BOTTOMLEFT, EL_INVISIBLE_STEELWALL_BOTTOMLEFT },
2415 { EL_STEELWALL_BOTTOMRIGHT, EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
2416 { EL_STEELWALL_VERTICAL, EL_INVISIBLE_STEELWALL_VERTICAL },
2417 { EL_STEELWALL_HORIZONTAL, EL_INVISIBLE_STEELWALL_HORIZONTAL },
2418 { EL_STEELWALL, EL_INVISIBLE_STEELWALL }
2420 int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
2421 int steel_position = (x == -1 && y == -1 ? 0 :
2422 x == lev_fieldx && y == -1 ? 1 :
2423 x == -1 && y == lev_fieldy ? 2 :
2424 x == lev_fieldx && y == lev_fieldy ? 3 :
2425 x == -1 || x == lev_fieldx ? 4 :
2426 y == -1 || y == lev_fieldy ? 5 : 6);
2428 return border[steel_position][steel_type];
2431 void DrawScreenElement(int x, int y, int element)
2433 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
2434 DrawLevelFieldCrumbled(LEVELX(x), LEVELY(y));
2437 void DrawLevelElement(int x, int y, int element)
2439 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
2440 DrawScreenElement(SCREENX(x), SCREENY(y), element);
2443 void DrawScreenField(int x, int y)
2445 int lx = LEVELX(x), ly = LEVELY(y);
2446 int element, content;
2448 if (!IN_LEV_FIELD(lx, ly))
2450 if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
2453 element = getBorderElement(lx, ly);
2455 DrawScreenElement(x, y, element);
2460 element = Feld[lx][ly];
2461 content = Store[lx][ly];
2463 if (IS_MOVING(lx, ly))
2465 int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
2466 boolean cut_mode = NO_CUTTING;
2468 if (element == EL_QUICKSAND_EMPTYING ||
2469 element == EL_QUICKSAND_FAST_EMPTYING ||
2470 element == EL_MAGIC_WALL_EMPTYING ||
2471 element == EL_BD_MAGIC_WALL_EMPTYING ||
2472 element == EL_DC_MAGIC_WALL_EMPTYING ||
2473 element == EL_AMOEBA_DROPPING)
2474 cut_mode = CUT_ABOVE;
2475 else if (element == EL_QUICKSAND_FILLING ||
2476 element == EL_QUICKSAND_FAST_FILLING ||
2477 element == EL_MAGIC_WALL_FILLING ||
2478 element == EL_BD_MAGIC_WALL_FILLING ||
2479 element == EL_DC_MAGIC_WALL_FILLING)
2480 cut_mode = CUT_BELOW;
2483 if (lx == 9 && ly == 1)
2484 printf("::: %s [%d] [%d, %d] [%d]\n",
2485 EL_NAME(TILE_GFX_ELEMENT(lx, ly)),
2486 el_act2crm(TILE_GFX_ELEMENT(lx, ly), ACTION_DEFAULT),
2487 element_info[EL_QUICKSAND_EMPTYING].graphic[ACTION_DEFAULT],
2488 element_info[EL_QUICKSAND_EMPTYING].crumbled[ACTION_DEFAULT],
2489 GFX_CRUMBLED(TILE_GFX_ELEMENT(lx, ly)));
2492 if (cut_mode == CUT_ABOVE)
2494 DrawScreenElement(x, y, element);
2496 DrawScreenElementShifted(x, y, 0, 0, element, NO_CUTTING);
2499 DrawScreenElement(x, y, EL_EMPTY);
2502 DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
2503 else if (cut_mode == NO_CUTTING)
2504 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
2507 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
2510 if (cut_mode == CUT_BELOW &&
2511 IN_LEV_FIELD(lx, ly + 1) && IN_SCR_FIELD(x, y + 1))
2512 DrawLevelElement(lx, ly + 1, element);
2516 if (content == EL_ACID)
2518 int dir = MovDir[lx][ly];
2519 int newlx = lx + (dir == MV_LEFT ? -1 : dir == MV_RIGHT ? +1 : 0);
2520 int newly = ly + (dir == MV_UP ? -1 : dir == MV_DOWN ? +1 : 0);
2522 DrawLevelElementThruMask(newlx, newly, EL_ACID);
2525 else if (IS_BLOCKED(lx, ly))
2530 boolean cut_mode = NO_CUTTING;
2531 int element_old, content_old;
2533 Blocked2Moving(lx, ly, &oldx, &oldy);
2536 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
2537 MovDir[oldx][oldy] == MV_RIGHT);
2539 element_old = Feld[oldx][oldy];
2540 content_old = Store[oldx][oldy];
2542 if (element_old == EL_QUICKSAND_EMPTYING ||
2543 element_old == EL_QUICKSAND_FAST_EMPTYING ||
2544 element_old == EL_MAGIC_WALL_EMPTYING ||
2545 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
2546 element_old == EL_DC_MAGIC_WALL_EMPTYING ||
2547 element_old == EL_AMOEBA_DROPPING)
2548 cut_mode = CUT_ABOVE;
2550 DrawScreenElement(x, y, EL_EMPTY);
2553 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
2555 else if (cut_mode == NO_CUTTING)
2556 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
2559 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
2562 else if (IS_DRAWABLE(element))
2563 DrawScreenElement(x, y, element);
2565 DrawScreenElement(x, y, EL_EMPTY);
2568 void DrawLevelField(int x, int y)
2570 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
2571 DrawScreenField(SCREENX(x), SCREENY(y));
2572 else if (IS_MOVING(x, y))
2576 Moving2Blocked(x, y, &newx, &newy);
2577 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
2578 DrawScreenField(SCREENX(newx), SCREENY(newy));
2580 else if (IS_BLOCKED(x, y))
2584 Blocked2Moving(x, y, &oldx, &oldy);
2585 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
2586 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
2590 void DrawMiniElement(int x, int y, int element)
2594 graphic = el2edimg(element);
2595 DrawMiniGraphic(x, y, graphic);
2598 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
2600 int x = sx + scroll_x, y = sy + scroll_y;
2602 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
2603 DrawMiniElement(sx, sy, EL_EMPTY);
2604 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
2605 DrawMiniElement(sx, sy, Feld[x][y]);
2607 DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
2610 void DrawEnvelopeBackgroundTiles(int graphic, int startx, int starty,
2611 int x, int y, int xsize, int ysize,
2612 int tile_width, int tile_height)
2616 int dst_x = startx + x * tile_width;
2617 int dst_y = starty + y * tile_height;
2618 int width = graphic_info[graphic].width;
2619 int height = graphic_info[graphic].height;
2620 int inner_width_raw = MAX(width - 2 * tile_width, tile_width);
2621 int inner_height_raw = MAX(height - 2 * tile_height, tile_height);
2622 int inner_width = inner_width_raw - (inner_width_raw % tile_width);
2623 int inner_height = inner_height_raw - (inner_height_raw % tile_height);
2624 int inner_sx = (width >= 3 * tile_width ? tile_width : 0);
2625 int inner_sy = (height >= 3 * tile_height ? tile_height : 0);
2626 boolean draw_masked = graphic_info[graphic].draw_masked;
2628 getFixedGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
2630 if (src_bitmap == NULL || width < tile_width || height < tile_height)
2632 ClearRectangle(drawto, dst_x, dst_y, tile_width, tile_height);
2636 src_x += (x == 0 ? 0 : x == xsize - 1 ? width - tile_width :
2637 inner_sx + (x - 1) * tile_width % inner_width);
2638 src_y += (y == 0 ? 0 : y == ysize - 1 ? height - tile_height :
2639 inner_sy + (y - 1) * tile_height % inner_height);
2643 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
2644 dst_x - src_x, dst_y - src_y);
2645 BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, tile_width, tile_height,
2649 BlitBitmap(src_bitmap, drawto, src_x, src_y, tile_width, tile_height,
2653 void DrawEnvelopeBackground(int graphic, int startx, int starty,
2654 int x, int y, int xsize, int ysize, int font_nr)
2656 int font_width = getFontWidth(font_nr);
2657 int font_height = getFontHeight(font_nr);
2659 DrawEnvelopeBackgroundTiles(graphic, startx, starty, x, y, xsize, ysize,
2660 font_width, font_height);
2663 void AnimateEnvelope(int envelope_nr, int anim_mode, int action)
2665 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2666 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
2667 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
2668 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2669 boolean no_delay = (tape.warp_forward);
2670 unsigned int anim_delay = 0;
2671 int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
2672 int anim_delay_value = (no_delay ? 0 : frame_delay_value);
2673 int font_nr = FONT_ENVELOPE_1 + envelope_nr;
2674 int font_width = getFontWidth(font_nr);
2675 int font_height = getFontHeight(font_nr);
2676 int max_xsize = level.envelope[envelope_nr].xsize;
2677 int max_ysize = level.envelope[envelope_nr].ysize;
2678 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
2679 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
2680 int xend = max_xsize;
2681 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
2682 int xstep = (xstart < xend ? 1 : 0);
2683 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
2686 for (x = xstart, y = ystart; x <= xend && y <= yend; x += xstep, y += ystep)
2688 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
2689 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
2690 int sx = SX + (SXSIZE - xsize * font_width) / 2;
2691 int sy = SY + (SYSIZE - ysize * font_height) / 2;
2694 SetDrawtoField(DRAW_BUFFERED);
2697 BlitScreenToBitmap(backbuffer);
2699 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
2702 SetDrawtoField(DRAW_BACKBUFFER);
2704 for (yy = 0; yy < ysize; yy++)
2705 for (xx = 0; xx < xsize; xx++)
2706 DrawEnvelopeBackground(graphic, sx, sy, xx, yy, xsize, ysize, font_nr);
2709 DrawTextBuffer(sx + font_width, sy + font_height,
2710 level.envelope[envelope_nr].text, font_nr, max_xsize,
2711 xsize - 2, ysize - 2, 0, mask_mode,
2712 level.envelope[envelope_nr].autowrap,
2713 level.envelope[envelope_nr].centered, FALSE);
2715 DrawTextToTextArea(sx + font_width, sy + font_height,
2716 level.envelope[envelope_nr].text, font_nr, max_xsize,
2717 xsize - 2, ysize - 2, mask_mode);
2720 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
2723 WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
2727 void ShowEnvelope(int envelope_nr)
2729 int element = EL_ENVELOPE_1 + envelope_nr;
2730 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2731 int sound_opening = element_info[element].sound[ACTION_OPENING];
2732 int sound_closing = element_info[element].sound[ACTION_CLOSING];
2733 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2734 boolean no_delay = (tape.warp_forward);
2735 int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
2736 int wait_delay_value = (no_delay ? 0 : normal_delay_value);
2737 int anim_mode = graphic_info[graphic].anim_mode;
2738 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
2739 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
2741 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
2743 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
2745 if (anim_mode == ANIM_DEFAULT)
2746 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_OPENING);
2748 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_OPENING);
2751 Delay(wait_delay_value);
2753 WaitForEventToContinue();
2755 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
2757 if (anim_mode != ANIM_NONE)
2758 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_CLOSING);
2760 if (anim_mode == ANIM_DEFAULT)
2761 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_CLOSING);
2763 game.envelope_active = FALSE;
2765 SetDrawtoField(DRAW_BUFFERED);
2767 redraw_mask |= REDRAW_FIELD;
2771 static void setRequestPosition(int *x, int *y, boolean add_border_size)
2773 int border_size = request.border_size;
2774 int sx_center = (request.x != -1 ? request.x : SX + SXSIZE / 2);
2775 int sy_center = (request.y != -1 ? request.y : SY + SYSIZE / 2);
2776 int sx = sx_center - request.width / 2;
2777 int sy = sy_center - request.height / 2;
2779 if (add_border_size)
2789 void DrawEnvelopeRequest(char *text)
2791 char *text_final = text;
2792 char *text_door_style = NULL;
2793 int graphic = IMG_BACKGROUND_REQUEST;
2794 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
2795 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
2796 int font_nr = FONT_REQUEST;
2797 int font_width = getFontWidth(font_nr);
2798 int font_height = getFontHeight(font_nr);
2799 int border_size = request.border_size;
2800 int line_spacing = request.line_spacing;
2801 int line_height = font_height + line_spacing;
2802 int text_width = request.width - 2 * border_size;
2803 int text_height = request.height - 2 * border_size;
2804 int line_length = text_width / font_width;
2805 int max_lines = text_height / line_height;
2806 int width = request.width;
2807 int height = request.height;
2808 int tile_size = request.step_offset;
2809 int x_steps = width / tile_size;
2810 int y_steps = height / tile_size;
2814 if (request.wrap_single_words)
2816 char *src_text_ptr, *dst_text_ptr;
2818 text_door_style = checked_malloc(2 * strlen(text) + 1);
2820 src_text_ptr = text;
2821 dst_text_ptr = text_door_style;
2823 while (*src_text_ptr)
2825 if (*src_text_ptr == ' ' ||
2826 *src_text_ptr == '?' ||
2827 *src_text_ptr == '!')
2828 *dst_text_ptr++ = '\n';
2830 if (*src_text_ptr != ' ')
2831 *dst_text_ptr++ = *src_text_ptr;
2836 *dst_text_ptr = '\0';
2838 text_final = text_door_style;
2841 setRequestPosition(&sx, &sy, FALSE);
2843 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
2845 for (y = 0; y < y_steps; y++)
2846 for (x = 0; x < x_steps; x++)
2847 DrawEnvelopeBackgroundTiles(graphic, sx, sy,
2848 x, y, x_steps, y_steps,
2849 tile_size, tile_size);
2851 DrawTextBuffer(sx + border_size, sy + border_size, text_final, font_nr,
2852 line_length, -1, max_lines, line_spacing, mask_mode,
2853 request.autowrap, request.centered, FALSE);
2855 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
2856 RedrawGadget(tool_gadget[i]);
2858 // store readily prepared envelope request for later use when animating
2859 BlitBitmap(backbuffer, bitmap_db_cross, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2863 BlitBitmap(bitmap_db_store, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2864 BlitBitmap(bitmap_db_cross, backbuffer, sx, sy, width, height, sx, sy);
2866 redraw_mask = REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
2871 BlitBitmap(bitmap_db_store, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2873 redraw_mask = REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
2879 if (text_door_style)
2880 free(text_door_style);
2885 void AnimateEnvelopeRequest(int anim_mode, int action)
2887 int graphic = IMG_BACKGROUND_REQUEST;
2888 boolean draw_masked = graphic_info[graphic].draw_masked;
2890 int delay_value_normal = request.step_delay;
2891 int delay_value_fast = delay_value_normal / 2;
2893 int delay_value_normal = GameFrameDelay;
2894 int delay_value_fast = FfwdFrameDelay;
2896 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2897 boolean no_delay = (tape.warp_forward);
2898 int delay_value = (ffwd_delay ? delay_value_fast : delay_value_normal);
2899 int anim_delay_value = (no_delay ? 0 : delay_value + 500 * 0);
2900 unsigned int anim_delay = 0;
2902 int width = request.width;
2903 int height = request.height;
2904 int tile_size = request.step_offset;
2905 int max_xsize = width / tile_size;
2906 int max_ysize = height / tile_size;
2907 int max_xsize_inner = max_xsize - 2;
2908 int max_ysize_inner = max_ysize - 2;
2910 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize_inner : 0);
2911 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize_inner : 0);
2912 int xend = max_xsize_inner;
2913 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize_inner : 0);
2914 int xstep = (xstart < xend ? 1 : 0);
2915 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
2918 for (x = xstart, y = ystart; x <= xend && y <= yend; x += xstep, y += ystep)
2920 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
2921 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
2922 int sx_center = (request.x != -1 ? request.x : SX + SXSIZE / 2);
2923 int sy_center = (request.y != -1 ? request.y : SY + SYSIZE / 2);
2924 int src_x = sx_center - width / 2;
2925 int src_y = sy_center - height / 2;
2926 int dst_x = sx_center - xsize * tile_size / 2;
2927 int dst_y = sy_center - ysize * tile_size / 2;
2928 int xsize_size_left = (xsize - 1) * tile_size;
2929 int ysize_size_top = (ysize - 1) * tile_size;
2930 int max_xsize_pos = (max_xsize - 1) * tile_size;
2931 int max_ysize_pos = (max_ysize - 1) * tile_size;
2934 BlitBitmap(bitmap_db_store, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2937 for (yy = 0; yy < 2; yy++)
2939 for (xx = 0; xx < 2; xx++)
2941 int src_xx = src_x + xx * max_xsize_pos;
2942 int src_yy = src_y + yy * max_ysize_pos;
2943 int dst_xx = dst_x + xx * xsize_size_left;
2944 int dst_yy = dst_y + yy * ysize_size_top;
2945 int xx_size = (xx ? tile_size : xsize_size_left);
2946 int yy_size = (yy ? tile_size : ysize_size_top);
2949 BlitBitmapMasked(bitmap_db_cross, backbuffer,
2950 src_xx, src_yy, xx_size, yy_size, dst_xx, dst_yy);
2952 BlitBitmap(bitmap_db_cross, backbuffer,
2953 src_xx, src_yy, xx_size, yy_size, dst_xx, dst_yy);
2957 BlitBitmap(bitmap_db_cross, backbuffer,
2959 xsize_size_left, ysize_size_top,
2961 BlitBitmap(bitmap_db_cross, backbuffer,
2962 src_x + max_xsize_pos, src_y,
2963 tile_size, ysize_size_top,
2964 dst_x + xsize_size_left, dst_y);
2965 BlitBitmap(bitmap_db_cross, backbuffer,
2966 src_x, src_y + max_ysize_pos,
2967 xsize_size_left, tile_size,
2968 dst_x, dst_y + ysize_size_top);
2969 BlitBitmap(bitmap_db_cross, backbuffer,
2970 src_x + max_xsize_pos, src_y + max_ysize_pos,
2971 tile_size, tile_size,
2972 dst_x + xsize_size_left, dst_y + ysize_size_top);
2976 redraw_mask = REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
2977 // redraw_mask |= REDRAW_ALL | REDRAW_FROM_BACKBUFFER;
2979 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
2989 WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
2995 void AnimateEnvelopeRequest(char *text, int anim_mode, int action)
2998 int envelope_nr = 0;
3001 int graphic = IMG_BACKGROUND_REQUEST;
3003 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
3005 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
3006 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
3007 boolean ffwd_delay = (tape.playing && tape.fast_forward);
3008 boolean no_delay = (tape.warp_forward);
3009 unsigned int anim_delay = 0;
3010 int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
3011 int anim_delay_value = (no_delay ? 0 : frame_delay_value + 500 * 0);
3013 int max_word_len = maxWordLengthInString(text);
3014 int font_nr = (max_word_len > 7 ? FONT_TEXT_1 : FONT_TEXT_2);
3016 int font_nr = FONT_ENVELOPE_1 + envelope_nr;
3018 int font_width = getFontWidth(font_nr);
3019 int font_height = getFontHeight(font_nr);
3020 int line_spacing = 2 * 1;
3024 int max_xsize = DXSIZE / font_width;
3025 // int max_ysize = DYSIZE / font_height;
3026 int max_ysize = DYSIZE / (font_height + line_spacing);
3028 int max_xsize = 7; /* tools.c: MAX_REQUEST_LINE_FONT1_LEN == 7 */
3029 int max_ysize = 13; /* tools.c: MAX_REQUEST_LINES == 13 */
3033 int max_xsize = level.envelope[envelope_nr].xsize;
3034 int max_ysize = level.envelope[envelope_nr].ysize;
3036 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
3037 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
3038 int xend = max_xsize;
3039 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
3040 int xstep = (xstart < xend ? 1 : 0);
3041 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
3046 char *text_copy = getStringCopy(text);
3049 font_nr = FONT_TEXT_2;
3051 if (maxWordLengthInString(text) > 7) /* MAX_REQUEST_LINE_FONT1_LEN == 7 */
3053 max_xsize = 10; /* tools.c: MAX_REQUEST_LINE_FONT2_LEN == 10 */
3054 font_nr = FONT_TEXT_1;
3057 int max_word_len = 0;
3059 char *text_copy = getStringCopy(text);
3061 font_nr = FONT_TEXT_2;
3063 for (text_ptr = text; *text_ptr; text_ptr++)
3065 max_word_len = (*text_ptr != ' ' ? max_word_len + 1 : 0);
3067 if (max_word_len > 7) /* tools.c: MAX_REQUEST_LINE_FONT1_LEN == 7 */
3069 max_xsize = 10; /* tools.c: MAX_REQUEST_LINE_FONT2_LEN == 10 */
3070 font_nr = FONT_TEXT_1;
3079 for (text_ptr = text_copy; *text_ptr; text_ptr++)
3080 if (*text_ptr == ' ')
3085 dDX = SX + (SXSIZE - DXSIZE) / 2 - DX;
3086 dDY = SY + (SYSIZE - DYSIZE) / 2 - DY;
3088 dDX = SX + SXSIZE / 2 - max_xsize * font_width / 2 - DX;
3089 dDY = SY + SYSIZE / 2 - max_ysize * font_height / 2 - DY;
3092 for (x = xstart, y = ystart; x <= xend && y <= yend; x += xstep, y += ystep)
3094 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
3095 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
3096 int sx = SX + (SXSIZE - xsize * font_width) / 2;
3097 // int sy = SX + (SYSIZE - ysize * font_height) / 2;
3098 int sy = SY + (SYSIZE - ysize * (font_height + line_spacing)) / 2;
3102 BlitBitmap(bitmap_db_store, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
3104 SetDrawtoField(DRAW_BUFFERED);
3107 BlitScreenToBitmap(backbuffer);
3109 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
3112 SetDrawtoField(DRAW_BACKBUFFER);
3115 for (yy = 0; yy < ysize; yy++)
3116 for (xx = 0; xx < xsize; xx++)
3117 DrawEnvelopeBackgroundTiles(graphic, sx, sy, xx, yy, xsize, ysize,
3118 getFontWidth(font_nr),
3119 getFontHeight(font_nr) + line_spacing);
3124 DrawTextBuffer(sx + font_width, sy + font_height + 8,
3125 text_copy, font_nr, max_xsize,
3126 xsize - 2, ysize - 2, line_spacing, mask_mode,
3127 FALSE, TRUE, FALSE);
3129 DrawTextBuffer(sx + font_width, sy + font_height,
3130 level.envelope[envelope_nr].text, font_nr, max_xsize,
3131 xsize - 2, ysize - 2, 0, mask_mode,
3132 level.envelope[envelope_nr].autowrap,
3133 level.envelope[envelope_nr].centered, FALSE);
3137 DrawTextToTextArea(sx + font_width, sy + font_height,
3138 level.envelope[envelope_nr].text, font_nr, max_xsize,
3139 xsize - 2, ysize - 2, mask_mode);
3142 /* copy request gadgets to door backbuffer */
3145 if ((ysize - 2) > 13)
3146 BlitBitmap(bitmap_db_door, drawto,
3147 DOOR_GFX_PAGEX1 + (DXSIZE - (xsize - 2) * font_width) / 2,
3148 DOOR_GFX_PAGEY1 + 13 * font_height,
3149 (xsize - 2) * font_width,
3150 (ysize - 2 - 13) * font_height,
3152 sy + font_height * (1 + 13));
3154 if ((ysize - 2) > 13)
3155 BlitBitmap(bitmap_db_door, drawto,
3156 DOOR_GFX_PAGEX1 + (DXSIZE - (xsize - 2) * font_width) / 2,
3157 DOOR_GFX_PAGEY1 + 11 * (font_height + line_spacing * 0),
3158 (xsize - 2) * font_width,
3159 (ysize - 2 - 13) * (font_height + line_spacing),
3161 sy + (font_height + line_spacing) * (1 + 13));
3163 if ((ysize - 2) > 13)
3164 BlitBitmap(bitmap_db_door, drawto,
3165 DOOR_GFX_PAGEX1 + (DXSIZE - (xsize - 2) * font_width) / 2,
3166 DOOR_GFX_PAGEY1 + 13 * font_height,
3167 (xsize - 2) * font_width,
3168 (ysize - 2 - 13) * font_height,
3170 sy + font_height * (1 + 13));
3174 redraw_mask = REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
3175 // redraw_mask |= REDRAW_ALL | REDRAW_FROM_BACKBUFFER;
3177 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
3187 WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
3197 void ShowEnvelopeRequest(char *text, unsigned int req_state, int action)
3200 int last_game_status = game_status; /* save current game status */
3201 // int last_draw_background_mask = gfx.draw_background_mask;
3204 int graphic = IMG_BACKGROUND_REQUEST;
3205 int sound_opening = SND_REQUEST_OPENING;
3206 int sound_closing = SND_REQUEST_CLOSING;
3208 int envelope_nr = 0;
3209 int element = EL_ENVELOPE_1 + envelope_nr;
3210 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
3211 int sound_opening = element_info[element].sound[ACTION_OPENING];
3212 int sound_closing = element_info[element].sound[ACTION_CLOSING];
3215 boolean ffwd_delay = (tape.playing && tape.fast_forward);
3216 boolean no_delay = (tape.warp_forward);
3217 int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
3218 int wait_delay_value = (no_delay ? 0 : normal_delay_value);
3220 int anim_mode = graphic_info[graphic].anim_mode;
3221 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
3222 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
3224 char *text_copy = getStringCopy(text);
3227 for (text_ptr = text_copy; *text_ptr; text_ptr++)
3228 if (*text_ptr == ' ')
3233 if (game_status == GAME_MODE_PLAYING)
3235 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
3236 BlitScreenToBitmap_EM(backbuffer);
3237 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
3238 BlitScreenToBitmap_SP(backbuffer);
3241 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
3245 SetDrawtoField(DRAW_BACKBUFFER);
3247 // SetDrawBackgroundMask(REDRAW_NONE);
3249 if (action == ACTION_OPENING)
3251 BlitBitmap(backbuffer, bitmap_db_store, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
3254 if (req_state & REQ_ASK)
3256 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
3257 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
3259 else if (req_state & REQ_CONFIRM)
3261 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
3263 else if (req_state & REQ_PLAYER)
3265 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
3266 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
3267 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
3268 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
3273 DrawEnvelopeRequest(text);
3275 DrawEnvelopeRequest(text_copy);
3278 if (game_status != GAME_MODE_MAIN)
3282 /* force DOOR font inside door area */
3283 game_status = GAME_MODE_PSEUDO_DOOR;
3286 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
3288 if (action == ACTION_OPENING)
3290 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
3292 if (anim_mode == ANIM_DEFAULT)
3293 AnimateEnvelopeRequest(ANIM_DEFAULT, ACTION_OPENING);
3295 AnimateEnvelopeRequest(main_anim_mode, ACTION_OPENING);
3299 Delay(wait_delay_value);
3301 WaitForEventToContinue();
3306 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
3308 if (anim_mode != ANIM_NONE)
3309 AnimateEnvelopeRequest(main_anim_mode, ACTION_CLOSING);
3311 if (anim_mode == ANIM_DEFAULT)
3312 AnimateEnvelopeRequest(ANIM_DEFAULT, ACTION_CLOSING);
3315 game.envelope_active = FALSE;
3318 // game_status = last_game_status; /* restore current game status */
3320 if (action == ACTION_CLOSING)
3322 if (game_status != GAME_MODE_MAIN)
3325 BlitBitmap(bitmap_db_store, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
3328 SetDrawtoField(DRAW_BUFFERED);
3331 // SetDrawBackgroundMask(last_draw_background_mask);
3334 redraw_mask = REDRAW_FIELD;
3335 // redraw_mask |= REDRAW_ALL;
3337 redraw_mask |= REDRAW_FIELD;
3341 if (game_status == GAME_MODE_MAIN)
3346 /* (important: after "BackToFront()", but before "SetDrawtoField()") */
3347 game_status = last_game_status; /* restore current game status */
3350 if (action == ACTION_CLOSING &&
3351 game_status == GAME_MODE_PLAYING &&
3352 level.game_engine_type == GAME_ENGINE_TYPE_RND)
3353 SetDrawtoField(DRAW_BUFFERED);
3355 if (game_status == GAME_MODE_PLAYING &&
3356 level.game_engine_type == GAME_ENGINE_TYPE_RND)
3357 SetDrawtoField(DRAW_BUFFERED);
3369 void DrawPreviewElement(int dst_x, int dst_y, int element, int tilesize)
3373 int graphic = el2preimg(element);
3375 getSizedGraphicSource(graphic, 0, tilesize, &src_bitmap, &src_x, &src_y);
3376 BlitBitmap(src_bitmap, drawto, src_x, src_y, tilesize, tilesize, dst_x,dst_y);
3384 SetMainBackgroundImage(IMG_BACKGROUND_PLAYING);
3385 SetDrawBackgroundMask(REDRAW_FIELD);
3387 SetDrawBackgroundMask(REDRAW_NONE);
3392 for (x = BX1; x <= BX2; x++)
3393 for (y = BY1; y <= BY2; y++)
3394 DrawScreenField(x, y);
3396 redraw_mask |= REDRAW_FIELD;
3399 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
3403 for (x = 0; x < size_x; x++)
3404 for (y = 0; y < size_y; y++)
3405 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
3407 redraw_mask |= REDRAW_FIELD;
3410 static void DrawPreviewLevelPlayfieldExt(int from_x, int from_y)
3412 boolean show_level_border = (BorderElement != EL_EMPTY);
3413 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
3414 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
3415 int tile_size = preview.tile_size;
3416 int preview_width = preview.xsize * tile_size;
3417 int preview_height = preview.ysize * tile_size;
3418 int real_preview_xsize = MIN(level_xsize, preview.xsize);
3419 int real_preview_ysize = MIN(level_ysize, preview.ysize);
3420 int dst_x = SX + ALIGNED_XPOS(preview.x, preview_width, preview.align);
3421 int dst_y = SY + ALIGNED_YPOS(preview.y, preview_height, preview.valign);
3424 DrawBackground(dst_x, dst_y, preview_width, preview_height);
3426 dst_x += (preview_width - real_preview_xsize * tile_size) / 2;
3427 dst_y += (preview_height - real_preview_ysize * tile_size) / 2;
3429 for (x = 0; x < real_preview_xsize; x++)
3431 for (y = 0; y < real_preview_ysize; y++)
3433 int lx = from_x + x + (show_level_border ? -1 : 0);
3434 int ly = from_y + y + (show_level_border ? -1 : 0);
3435 int element = (IN_LEV_FIELD(lx, ly) ? level.field[lx][ly] :
3436 getBorderElement(lx, ly));
3438 DrawPreviewElement(dst_x + x * tile_size, dst_y + y * tile_size,
3439 element, tile_size);
3443 redraw_mask |= REDRAW_MICROLEVEL;
3446 #define MICROLABEL_EMPTY 0
3447 #define MICROLABEL_LEVEL_NAME 1
3448 #define MICROLABEL_LEVEL_AUTHOR_HEAD 2
3449 #define MICROLABEL_LEVEL_AUTHOR 3
3450 #define MICROLABEL_IMPORTED_FROM_HEAD 4
3451 #define MICROLABEL_IMPORTED_FROM 5
3452 #define MICROLABEL_IMPORTED_BY_HEAD 6
3453 #define MICROLABEL_IMPORTED_BY 7
3455 static int getMaxTextLength(struct TextPosInfo *pos, int font_nr)
3457 int max_text_width = SXSIZE;
3458 int font_width = getFontWidth(font_nr);
3460 if (pos->align == ALIGN_CENTER)
3461 max_text_width = (pos->x < SXSIZE / 2 ? pos->x * 2 : (SXSIZE - pos->x) * 2);
3462 else if (pos->align == ALIGN_RIGHT)
3463 max_text_width = pos->x;
3465 max_text_width = SXSIZE - pos->x;
3467 return max_text_width / font_width;
3470 static void DrawPreviewLevelLabelExt(int mode)
3472 struct TextPosInfo *pos = &menu.main.text.level_info_2;
3473 char label_text[MAX_OUTPUT_LINESIZE + 1];
3474 int max_len_label_text;
3476 int font_nr = pos->font;
3479 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
3480 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
3481 mode == MICROLABEL_IMPORTED_BY_HEAD)
3482 font_nr = pos->font_alt;
3484 int font_nr = FONT_TEXT_2;
3487 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
3488 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
3489 mode == MICROLABEL_IMPORTED_BY_HEAD)
3490 font_nr = FONT_TEXT_3;
3494 max_len_label_text = getMaxTextLength(pos, font_nr);
3496 max_len_label_text = SXSIZE / getFontWidth(font_nr);
3500 if (pos->size != -1)
3501 max_len_label_text = pos->size;
3504 for (i = 0; i < max_len_label_text; i++)
3505 label_text[i] = ' ';
3506 label_text[max_len_label_text] = '\0';
3508 if (strlen(label_text) > 0)
3511 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
3513 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
3514 int lypos = MICROLABEL2_YPOS;
3516 DrawText(lxpos, lypos, label_text, font_nr);
3521 (mode == MICROLABEL_LEVEL_NAME ? level.name :
3522 mode == MICROLABEL_LEVEL_AUTHOR_HEAD ? "created by" :
3523 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
3524 mode == MICROLABEL_IMPORTED_FROM_HEAD ? "imported from" :
3525 mode == MICROLABEL_IMPORTED_FROM ? leveldir_current->imported_from :
3526 mode == MICROLABEL_IMPORTED_BY_HEAD ? "imported by" :
3527 mode == MICROLABEL_IMPORTED_BY ? leveldir_current->imported_by :""),
3528 max_len_label_text);
3529 label_text[max_len_label_text] = '\0';
3531 if (strlen(label_text) > 0)
3534 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
3536 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
3537 int lypos = MICROLABEL2_YPOS;
3539 DrawText(lxpos, lypos, label_text, font_nr);
3543 redraw_mask |= REDRAW_MICROLEVEL;
3546 static void DrawPreviewLevelExt(boolean restart)
3548 static unsigned int scroll_delay = 0;
3549 static unsigned int label_delay = 0;
3550 static int from_x, from_y, scroll_direction;
3551 static int label_state, label_counter;
3552 unsigned int scroll_delay_value = preview.step_delay;
3553 boolean show_level_border = (BorderElement != EL_EMPTY);
3554 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
3555 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
3556 int last_game_status = game_status; /* save current game status */
3559 /* force PREVIEW font on preview level */
3560 game_status = GAME_MODE_PSEUDO_PREVIEW;
3568 if (preview.anim_mode == ANIM_CENTERED)
3570 if (level_xsize > preview.xsize)
3571 from_x = (level_xsize - preview.xsize) / 2;
3572 if (level_ysize > preview.ysize)
3573 from_y = (level_ysize - preview.ysize) / 2;
3576 from_x += preview.xoffset;
3577 from_y += preview.yoffset;
3579 scroll_direction = MV_RIGHT;
3583 DrawPreviewLevelPlayfieldExt(from_x, from_y);
3584 DrawPreviewLevelLabelExt(label_state);
3586 /* initialize delay counters */
3587 DelayReached(&scroll_delay, 0);
3588 DelayReached(&label_delay, 0);
3590 if (leveldir_current->name)
3592 struct TextPosInfo *pos = &menu.main.text.level_info_1;
3593 char label_text[MAX_OUTPUT_LINESIZE + 1];
3595 int font_nr = pos->font;
3597 int font_nr = FONT_TEXT_1;
3600 int max_len_label_text = getMaxTextLength(pos, font_nr);
3602 int max_len_label_text = SXSIZE / getFontWidth(font_nr);
3610 if (pos->size != -1)
3611 max_len_label_text = pos->size;
3614 strncpy(label_text, leveldir_current->name, max_len_label_text);
3615 label_text[max_len_label_text] = '\0';
3618 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
3620 lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
3621 lypos = SY + MICROLABEL1_YPOS;
3623 DrawText(lxpos, lypos, label_text, font_nr);
3627 game_status = last_game_status; /* restore current game status */
3632 /* scroll preview level, if needed */
3633 if (preview.anim_mode != ANIM_NONE &&
3634 (level_xsize > preview.xsize || level_ysize > preview.ysize) &&
3635 DelayReached(&scroll_delay, scroll_delay_value))
3637 switch (scroll_direction)
3642 from_x -= preview.step_offset;
3643 from_x = (from_x < 0 ? 0 : from_x);
3646 scroll_direction = MV_UP;
3650 if (from_x < level_xsize - preview.xsize)
3652 from_x += preview.step_offset;
3653 from_x = (from_x > level_xsize - preview.xsize ?
3654 level_xsize - preview.xsize : from_x);
3657 scroll_direction = MV_DOWN;
3663 from_y -= preview.step_offset;
3664 from_y = (from_y < 0 ? 0 : from_y);
3667 scroll_direction = MV_RIGHT;
3671 if (from_y < level_ysize - preview.ysize)
3673 from_y += preview.step_offset;
3674 from_y = (from_y > level_ysize - preview.ysize ?
3675 level_ysize - preview.ysize : from_y);
3678 scroll_direction = MV_LEFT;
3685 DrawPreviewLevelPlayfieldExt(from_x, from_y);
3688 /* !!! THIS ALL SUCKS -- SHOULD BE CLEANLY REWRITTEN !!! */
3689 /* redraw micro level label, if needed */
3690 if (!strEqual(level.name, NAMELESS_LEVEL_NAME) &&
3691 !strEqual(level.author, ANONYMOUS_NAME) &&
3692 !strEqual(level.author, leveldir_current->name) &&
3693 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
3695 int max_label_counter = 23;
3697 if (leveldir_current->imported_from != NULL &&
3698 strlen(leveldir_current->imported_from) > 0)
3699 max_label_counter += 14;
3700 if (leveldir_current->imported_by != NULL &&
3701 strlen(leveldir_current->imported_by) > 0)
3702 max_label_counter += 14;
3704 label_counter = (label_counter + 1) % max_label_counter;
3705 label_state = (label_counter >= 0 && label_counter <= 7 ?
3706 MICROLABEL_LEVEL_NAME :
3707 label_counter >= 9 && label_counter <= 12 ?
3708 MICROLABEL_LEVEL_AUTHOR_HEAD :
3709 label_counter >= 14 && label_counter <= 21 ?
3710 MICROLABEL_LEVEL_AUTHOR :
3711 label_counter >= 23 && label_counter <= 26 ?
3712 MICROLABEL_IMPORTED_FROM_HEAD :
3713 label_counter >= 28 && label_counter <= 35 ?
3714 MICROLABEL_IMPORTED_FROM :
3715 label_counter >= 37 && label_counter <= 40 ?
3716 MICROLABEL_IMPORTED_BY_HEAD :
3717 label_counter >= 42 && label_counter <= 49 ?
3718 MICROLABEL_IMPORTED_BY : MICROLABEL_EMPTY);
3720 if (leveldir_current->imported_from == NULL &&
3721 (label_state == MICROLABEL_IMPORTED_FROM_HEAD ||
3722 label_state == MICROLABEL_IMPORTED_FROM))
3723 label_state = (label_state == MICROLABEL_IMPORTED_FROM_HEAD ?
3724 MICROLABEL_IMPORTED_BY_HEAD : MICROLABEL_IMPORTED_BY);
3726 DrawPreviewLevelLabelExt(label_state);
3729 game_status = last_game_status; /* restore current game status */
3732 void DrawPreviewLevelInitial()
3734 DrawPreviewLevelExt(TRUE);
3737 void DrawPreviewLevelAnimation()
3739 DrawPreviewLevelExt(FALSE);
3742 inline void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
3743 int graphic, int sync_frame, int mask_mode)
3745 int frame = getGraphicAnimationFrame(graphic, sync_frame);
3747 if (mask_mode == USE_MASKING)
3748 DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
3750 DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
3753 inline void DrawFixedGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
3754 int graphic, int sync_frame,
3757 int frame = getGraphicAnimationFrame(graphic, sync_frame);
3759 if (mask_mode == USE_MASKING)
3760 DrawFixedGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
3762 DrawFixedGraphicExt(dst_bitmap, x, y, graphic, frame);
3765 inline void DrawGraphicAnimation(int x, int y, int graphic)
3767 int lx = LEVELX(x), ly = LEVELY(y);
3769 if (!IN_SCR_FIELD(x, y))
3773 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR,
3774 graphic, GfxFrame[lx][ly], NO_MASKING);
3776 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
3777 graphic, GfxFrame[lx][ly], NO_MASKING);
3779 MarkTileDirty(x, y);
3782 inline void DrawFixedGraphicAnimation(int x, int y, int graphic)
3784 int lx = LEVELX(x), ly = LEVELY(y);
3786 if (!IN_SCR_FIELD(x, y))
3789 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
3790 graphic, GfxFrame[lx][ly], NO_MASKING);
3791 MarkTileDirty(x, y);
3794 void DrawLevelGraphicAnimation(int x, int y, int graphic)
3796 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
3799 void DrawLevelElementAnimation(int x, int y, int element)
3801 int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
3803 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
3806 inline void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
3808 int sx = SCREENX(x), sy = SCREENY(y);
3810 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
3813 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
3816 DrawGraphicAnimation(sx, sy, graphic);
3819 if (GFX_CRUMBLED(TILE_GFX_ELEMENT(x, y)))
3820 DrawLevelFieldCrumbled(x, y);
3822 if (GFX_CRUMBLED(Feld[x][y]))
3823 DrawLevelFieldCrumbled(x, y);
3827 void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
3829 int sx = SCREENX(x), sy = SCREENY(y);
3832 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
3835 graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
3837 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
3840 DrawGraphicAnimation(sx, sy, graphic);
3842 if (GFX_CRUMBLED(element))
3843 DrawLevelFieldCrumbled(x, y);
3846 static int getPlayerGraphic(struct PlayerInfo *player, int move_dir)
3848 if (player->use_murphy)
3850 /* this works only because currently only one player can be "murphy" ... */
3851 static int last_horizontal_dir = MV_LEFT;
3852 int graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir);
3854 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3855 last_horizontal_dir = move_dir;
3857 if (graphic == IMG_SP_MURPHY) /* undefined => use special graphic */
3859 int direction = (player->is_snapping ? move_dir : last_horizontal_dir);
3861 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
3867 return el_act_dir2img(player->artwork_element, player->GfxAction,move_dir);
3870 static boolean equalGraphics(int graphic1, int graphic2)
3872 struct GraphicInfo *g1 = &graphic_info[graphic1];
3873 struct GraphicInfo *g2 = &graphic_info[graphic2];
3875 return (g1->bitmap == g2->bitmap &&
3876 g1->src_x == g2->src_x &&
3877 g1->src_y == g2->src_y &&
3878 g1->anim_frames == g2->anim_frames &&
3879 g1->anim_delay == g2->anim_delay &&
3880 g1->anim_mode == g2->anim_mode);
3883 void DrawAllPlayers()
3887 for (i = 0; i < MAX_PLAYERS; i++)
3888 if (stored_player[i].active)
3889 DrawPlayer(&stored_player[i]);
3892 void DrawPlayerField(int x, int y)
3894 if (!IS_PLAYER(x, y))
3897 DrawPlayer(PLAYERINFO(x, y));
3900 #define DRAW_PLAYER_OVER_PUSHED_ELEMENT 1
3902 void DrawPlayer(struct PlayerInfo *player)
3904 int jx = player->jx;
3905 int jy = player->jy;
3906 int move_dir = player->MovDir;
3907 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? +1 : 0);
3908 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? +1 : 0);
3909 int last_jx = (player->is_moving ? jx - dx : jx);
3910 int last_jy = (player->is_moving ? jy - dy : jy);
3911 int next_jx = jx + dx;
3912 int next_jy = jy + dy;
3913 boolean player_is_moving = (player->MovPos ? TRUE : FALSE);
3914 boolean player_is_opaque = FALSE;
3915 int sx = SCREENX(jx), sy = SCREENY(jy);
3916 int sxx = 0, syy = 0;
3917 int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
3919 int action = ACTION_DEFAULT;
3920 int last_player_graphic = getPlayerGraphic(player, move_dir);
3921 int last_player_frame = player->Frame;
3924 /* GfxElement[][] is set to the element the player is digging or collecting;
3925 remove also for off-screen player if the player is not moving anymore */
3926 if (IN_LEV_FIELD(jx, jy) && !player_is_moving)
3927 GfxElement[jx][jy] = EL_UNDEFINED;
3929 if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
3933 if (!IN_LEV_FIELD(jx, jy))
3935 printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
3936 printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
3937 printf("DrawPlayerField(): This should never happen!\n");
3942 if (element == EL_EXPLOSION)
3945 action = (player->is_pushing ? ACTION_PUSHING :
3946 player->is_digging ? ACTION_DIGGING :
3947 player->is_collecting ? ACTION_COLLECTING :
3948 player->is_moving ? ACTION_MOVING :
3949 player->is_snapping ? ACTION_SNAPPING :
3950 player->is_dropping ? ACTION_DROPPING :
3951 player->is_waiting ? player->action_waiting : ACTION_DEFAULT);
3953 if (player->is_waiting)
3954 move_dir = player->dir_waiting;
3956 InitPlayerGfxAnimation(player, action, move_dir);
3958 /* ----------------------------------------------------------------------- */
3959 /* draw things in the field the player is leaving, if needed */
3960 /* ----------------------------------------------------------------------- */
3962 if (player->is_moving)
3964 if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
3966 DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
3968 if (last_element == EL_DYNAMITE_ACTIVE ||
3969 last_element == EL_EM_DYNAMITE_ACTIVE ||
3970 last_element == EL_SP_DISK_RED_ACTIVE)
3971 DrawDynamite(last_jx, last_jy);
3973 DrawLevelFieldThruMask(last_jx, last_jy);
3975 else if (last_element == EL_DYNAMITE_ACTIVE ||
3976 last_element == EL_EM_DYNAMITE_ACTIVE ||
3977 last_element == EL_SP_DISK_RED_ACTIVE)
3978 DrawDynamite(last_jx, last_jy);
3980 /* !!! this is not enough to prevent flickering of players which are
3981 moving next to each others without a free tile between them -- this
3982 can only be solved by drawing all players layer by layer (first the
3983 background, then the foreground etc.) !!! => TODO */
3984 else if (!IS_PLAYER(last_jx, last_jy))
3985 DrawLevelField(last_jx, last_jy);
3988 DrawLevelField(last_jx, last_jy);
3991 if (player->is_pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
3992 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
3995 if (!IN_SCR_FIELD(sx, sy))
3998 /* ----------------------------------------------------------------------- */
3999 /* draw things behind the player, if needed */
4000 /* ----------------------------------------------------------------------- */
4003 DrawLevelElement(jx, jy, Back[jx][jy]);
4004 else if (IS_ACTIVE_BOMB(element))
4005 DrawLevelElement(jx, jy, EL_EMPTY);
4008 if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
4010 int old_element = GfxElement[jx][jy];
4011 int old_graphic = el_act_dir2img(old_element, action, move_dir);
4012 int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
4014 if (GFX_CRUMBLED(old_element))
4015 DrawLevelFieldCrumbledDigging(jx, jy, move_dir, player->StepFrame);
4017 DrawGraphic(sx, sy, old_graphic, frame);
4019 if (graphic_info[old_graphic].anim_mode & ANIM_OPAQUE_PLAYER)
4020 player_is_opaque = TRUE;
4024 GfxElement[jx][jy] = EL_UNDEFINED;
4026 /* make sure that pushed elements are drawn with correct frame rate */
4028 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
4030 if (player->is_pushing && player->is_moving && !IS_ANIM_MODE_CE(graphic))
4031 GfxFrame[jx][jy] = player->StepFrame;
4033 if (player->is_pushing && player->is_moving)
4034 GfxFrame[jx][jy] = player->StepFrame;
4037 DrawLevelField(jx, jy);
4041 #if !DRAW_PLAYER_OVER_PUSHED_ELEMENT
4042 /* ----------------------------------------------------------------------- */
4043 /* draw player himself */
4044 /* ----------------------------------------------------------------------- */
4046 graphic = getPlayerGraphic(player, move_dir);
4048 /* in the case of changed player action or direction, prevent the current
4049 animation frame from being restarted for identical animations */
4050 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
4051 player->Frame = last_player_frame;
4053 frame = getGraphicAnimationFrame(graphic, player->Frame);
4057 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
4058 sxx = player->GfxPos;
4060 syy = player->GfxPos;
4063 if (!setup.soft_scrolling && ScreenMovPos)
4066 if (player_is_opaque)
4067 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
4069 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
4071 if (SHIELD_ON(player))
4073 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
4074 IMG_SHIELD_NORMAL_ACTIVE);
4075 int frame = getGraphicAnimationFrame(graphic, -1);
4077 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
4081 #if DRAW_PLAYER_OVER_PUSHED_ELEMENT
4084 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
4085 sxx = player->GfxPos;
4087 syy = player->GfxPos;
4091 /* ----------------------------------------------------------------------- */
4092 /* draw things the player is pushing, if needed */
4093 /* ----------------------------------------------------------------------- */
4096 printf("::: %d, %d [%d, %d] [%d]\n",
4097 player->is_pushing, player_is_moving, player->GfxAction,
4098 player->is_moving, player_is_moving);
4102 if (player->is_pushing && player->is_moving)
4104 int px = SCREENX(jx), py = SCREENY(jy);
4105 int pxx = (TILEX - ABS(sxx)) * dx;
4106 int pyy = (TILEY - ABS(syy)) * dy;
4107 int gfx_frame = GfxFrame[jx][jy];
4113 if (!IS_MOVING(jx, jy)) /* push movement already finished */
4115 element = Feld[next_jx][next_jy];
4116 gfx_frame = GfxFrame[next_jx][next_jy];
4119 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
4122 sync_frame = (IS_ANIM_MODE_CE(graphic) ? gfx_frame : player->StepFrame);
4123 frame = getGraphicAnimationFrame(graphic, sync_frame);
4125 frame = getGraphicAnimationFrame(graphic, player->StepFrame);
4128 /* draw background element under pushed element (like the Sokoban field) */
4130 if (game.use_masked_pushing && IS_MOVING(jx, jy))
4132 /* this allows transparent pushing animation over non-black background */
4135 DrawLevelElement(jx, jy, Back[jx][jy]);
4137 DrawLevelElement(jx, jy, EL_EMPTY);
4139 if (Back[next_jx][next_jy])
4140 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
4142 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
4144 else if (Back[next_jx][next_jy])
4145 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
4147 if (Back[next_jx][next_jy])
4148 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
4152 printf("::: %d, %d, %d, %d [%d] [%d, %d, %d] [%d] [%d, %d] [%d, %d]\n",
4153 jx, px, player->GfxPos, player->StepFrame,
4158 GfxFrame[jx][jy], GfxFrame[next_jx][next_jy]);
4162 /* do not draw (EM style) pushing animation when pushing is finished */
4163 /* (two-tile animations usually do not contain start and end frame) */
4164 if (graphic_info[graphic].double_movement && !IS_MOVING(jx, jy))
4165 DrawLevelElement(next_jx, next_jy, Feld[next_jx][next_jy]);
4167 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
4169 /* masked drawing is needed for EMC style (double) movement graphics */
4170 /* !!! (ONLY WHEN DRAWING PUSHED ELEMENT OVER THE PLAYER) !!! */
4171 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
4176 #if DRAW_PLAYER_OVER_PUSHED_ELEMENT
4177 /* ----------------------------------------------------------------------- */
4178 /* draw player himself */
4179 /* ----------------------------------------------------------------------- */
4181 graphic = getPlayerGraphic(player, move_dir);
4183 /* in the case of changed player action or direction, prevent the current
4184 animation frame from being restarted for identical animations */
4185 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
4186 player->Frame = last_player_frame;
4188 frame = getGraphicAnimationFrame(graphic, player->Frame);
4192 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
4193 sxx = player->GfxPos;
4195 syy = player->GfxPos;
4198 if (!setup.soft_scrolling && ScreenMovPos)
4201 if (player_is_opaque)
4202 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
4204 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
4206 if (SHIELD_ON(player))
4208 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
4209 IMG_SHIELD_NORMAL_ACTIVE);
4210 int frame = getGraphicAnimationFrame(graphic, -1);
4212 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
4216 /* ----------------------------------------------------------------------- */
4217 /* draw things in front of player (active dynamite or dynabombs) */
4218 /* ----------------------------------------------------------------------- */
4220 if (IS_ACTIVE_BOMB(element))
4222 graphic = el2img(element);
4223 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
4225 if (game.emulation == EMU_SUPAPLEX)
4226 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
4228 DrawGraphicThruMask(sx, sy, graphic, frame);
4231 if (player_is_moving && last_element == EL_EXPLOSION)
4233 int element = (GfxElement[last_jx][last_jy] != EL_UNDEFINED ?
4234 GfxElement[last_jx][last_jy] : EL_EMPTY);
4235 int graphic = el_act2img(element, ACTION_EXPLODING);
4236 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
4237 int phase = ExplodePhase[last_jx][last_jy] - 1;
4238 int frame = getGraphicAnimationFrame(graphic, phase - delay);
4241 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
4244 /* ----------------------------------------------------------------------- */
4245 /* draw elements the player is just walking/passing through/under */
4246 /* ----------------------------------------------------------------------- */
4248 if (player_is_moving)
4250 /* handle the field the player is leaving ... */
4251 if (IS_ACCESSIBLE_INSIDE(last_element))
4252 DrawLevelField(last_jx, last_jy);
4253 else if (IS_ACCESSIBLE_UNDER(last_element))
4254 DrawLevelFieldThruMask(last_jx, last_jy);
4257 /* do not redraw accessible elements if the player is just pushing them */
4258 if (!player_is_moving || !player->is_pushing)
4260 /* ... and the field the player is entering */
4261 if (IS_ACCESSIBLE_INSIDE(element))
4262 DrawLevelField(jx, jy);
4263 else if (IS_ACCESSIBLE_UNDER(element))
4264 DrawLevelFieldThruMask(jx, jy);
4267 MarkTileDirty(sx, sy);
4270 /* ------------------------------------------------------------------------- */
4272 void WaitForEventToContinue()
4274 boolean still_wait = TRUE;
4276 /* simulate releasing mouse button over last gadget, if still pressed */
4278 HandleGadgets(-1, -1, 0);
4280 button_status = MB_RELEASED;
4296 case EVENT_BUTTONPRESS:
4297 case EVENT_KEYPRESS:
4301 case EVENT_KEYRELEASE:
4302 ClearPlayerAction();
4306 HandleOtherEvents(&event);
4310 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
4317 /* don't eat all CPU time */
4322 #define MAX_REQUEST_LINES 13
4323 #define MAX_REQUEST_LINE_FONT1_LEN 7
4324 #define MAX_REQUEST_LINE_FONT2_LEN 10
4328 static int RequestHandleEvents(unsigned int req_state)
4330 int last_game_status = game_status; /* save current game status */
4334 button_status = MB_RELEASED;
4336 request_gadget_id = -1;
4349 case EVENT_BUTTONPRESS:
4350 case EVENT_BUTTONRELEASE:
4351 case EVENT_MOTIONNOTIFY:
4353 if (event.type == EVENT_MOTIONNOTIFY)
4355 if (!PointerInWindow(window))
4356 continue; /* window and pointer are on different screens */
4361 motion_status = TRUE;
4362 mx = ((MotionEvent *) &event)->x;
4363 my = ((MotionEvent *) &event)->y;
4367 motion_status = FALSE;
4368 mx = ((ButtonEvent *) &event)->x;
4369 my = ((ButtonEvent *) &event)->y;
4370 if (event.type == EVENT_BUTTONPRESS)
4371 button_status = ((ButtonEvent *) &event)->button;
4373 button_status = MB_RELEASED;
4376 /* this sets 'request_gadget_id' */
4377 HandleGadgets(mx, my, button_status);
4379 switch (request_gadget_id)
4381 case TOOL_CTRL_ID_YES:
4384 case TOOL_CTRL_ID_NO:
4387 case TOOL_CTRL_ID_CONFIRM:
4388 result = TRUE | FALSE;
4391 case TOOL_CTRL_ID_PLAYER_1:
4394 case TOOL_CTRL_ID_PLAYER_2:
4397 case TOOL_CTRL_ID_PLAYER_3:
4400 case TOOL_CTRL_ID_PLAYER_4:
4411 case EVENT_KEYPRESS:
4412 switch (GetEventKey((KeyEvent *)&event, TRUE))
4415 if (req_state & REQ_CONFIRM)
4424 #if defined(TARGET_SDL2)
4434 if (req_state & REQ_PLAYER)
4438 case EVENT_KEYRELEASE:
4439 ClearPlayerAction();
4443 HandleOtherEvents(&event);
4447 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
4449 int joy = AnyJoystick();
4451 if (joy & JOY_BUTTON_1)
4453 else if (joy & JOY_BUTTON_2)
4459 if (game_status == GAME_MODE_PLAYING && local_player->LevelSolved_GameEnd)
4461 HandleGameActions();
4467 if (!PendingEvent()) /* delay only if no pending events */
4472 game_status = GAME_MODE_PSEUDO_DOOR;
4478 game_status = last_game_status; /* restore current game status */
4486 if (!PendingEvent()) /* delay only if no pending events */
4489 /* don't eat all CPU time */
4499 static boolean RequestDoor(char *text, unsigned int req_state)
4501 unsigned int old_door_state;
4502 int last_game_status = game_status; /* save current game status */
4503 int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
4504 int font_nr = FONT_TEXT_2;
4509 if (maxWordLengthInString(text) > MAX_REQUEST_LINE_FONT1_LEN)
4511 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
4512 font_nr = FONT_TEXT_1;
4515 if (game_status == GAME_MODE_PLAYING)
4517 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
4518 BlitScreenToBitmap_EM(backbuffer);
4519 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
4520 BlitScreenToBitmap_SP(backbuffer);
4523 /* disable deactivated drawing when quick-loading level tape recording */
4524 if (tape.playing && tape.deactivate_display)
4525 TapeDeactivateDisplayOff(TRUE);
4527 SetMouseCursor(CURSOR_DEFAULT);
4529 #if defined(NETWORK_AVALIABLE)
4530 /* pause network game while waiting for request to answer */
4531 if (options.network &&
4532 game_status == GAME_MODE_PLAYING &&
4533 req_state & REQUEST_WAIT_FOR_INPUT)
4534 SendToServer_PausePlaying();
4537 old_door_state = GetDoorState();
4539 /* simulate releasing mouse button over last gadget, if still pressed */
4541 HandleGadgets(-1, -1, 0);
4545 /* draw released gadget before proceeding */
4548 if (old_door_state & DOOR_OPEN_1)
4550 CloseDoor(DOOR_CLOSE_1);
4552 /* save old door content */
4553 BlitBitmap(bitmap_db_door, bitmap_db_door,
4554 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
4555 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
4558 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
4559 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
4561 /* clear door drawing field */
4562 DrawBackground(DX, DY, DXSIZE, DYSIZE);
4564 /* force DOOR font inside door area */
4565 game_status = GAME_MODE_PSEUDO_DOOR;
4567 /* write text for request */
4568 for (text_ptr = text, ty = 0; ty < MAX_REQUEST_LINES; ty++)
4570 char text_line[max_request_line_len + 1];
4576 for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
4578 tc = *(text_ptr + tx);
4579 // if (!tc || tc == ' ')
4580 if (!tc || tc == ' ' || tc == '?' || tc == '!')
4584 if ((tc == '?' || tc == '!') && tl == 0)
4594 strncpy(text_line, text_ptr, tl);
4597 DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
4598 DY + 8 + ty * (getFontHeight(font_nr) + 2),
4599 text_line, font_nr);
4601 text_ptr += tl + (tc == ' ' ? 1 : 0);
4602 // text_ptr += tl + (tc == ' ' || tc == '?' || tc == '!' ? 1 : 0);
4605 game_status = last_game_status; /* restore current game status */
4607 if (req_state & REQ_ASK)
4609 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
4610 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
4612 else if (req_state & REQ_CONFIRM)
4614 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
4616 else if (req_state & REQ_PLAYER)
4618 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
4619 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
4620 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
4621 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
4624 /* copy request gadgets to door backbuffer */
4625 BlitBitmap(drawto, bitmap_db_door,
4626 DX, DY, DXSIZE, DYSIZE,
4627 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
4629 OpenDoor(DOOR_OPEN_1);
4631 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
4633 if (game_status == GAME_MODE_PLAYING)
4635 SetPanelBackground();
4636 SetDrawBackgroundMask(REDRAW_DOOR_1);
4640 SetDrawBackgroundMask(REDRAW_FIELD);
4646 if (game_status != GAME_MODE_MAIN)
4649 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
4651 // ---------- handle request buttons ----------
4652 result = RequestHandleEvents(req_state);
4654 if (game_status != GAME_MODE_MAIN)
4659 if (!(req_state & REQ_STAY_OPEN))
4661 CloseDoor(DOOR_CLOSE_1);
4663 if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
4664 (req_state & REQ_REOPEN))
4665 OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
4670 if (game_status == GAME_MODE_PLAYING)
4672 SetPanelBackground();
4673 SetDrawBackgroundMask(REDRAW_DOOR_1);
4677 SetDrawBackgroundMask(REDRAW_FIELD);
4680 #if defined(NETWORK_AVALIABLE)
4681 /* continue network game after request */
4682 if (options.network &&
4683 game_status == GAME_MODE_PLAYING &&
4684 req_state & REQUEST_WAIT_FOR_INPUT)
4685 SendToServer_ContinuePlaying();
4688 /* restore deactivated drawing when quick-loading level tape recording */
4689 if (tape.playing && tape.deactivate_display)
4690 TapeDeactivateDisplayOn();
4695 static boolean RequestEnvelope(char *text, unsigned int req_state)
4702 if (game_status == GAME_MODE_PLAYING)
4704 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
4705 BlitScreenToBitmap_EM(backbuffer);
4706 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
4707 BlitScreenToBitmap_SP(backbuffer);
4710 /* disable deactivated drawing when quick-loading level tape recording */
4711 if (tape.playing && tape.deactivate_display)
4712 TapeDeactivateDisplayOff(TRUE);
4714 SetMouseCursor(CURSOR_DEFAULT);
4716 #if defined(NETWORK_AVALIABLE)
4717 /* pause network game while waiting for request to answer */
4718 if (options.network &&
4719 game_status == GAME_MODE_PLAYING &&
4720 req_state & REQUEST_WAIT_FOR_INPUT)
4721 SendToServer_PausePlaying();
4724 /* simulate releasing mouse button over last gadget, if still pressed */
4726 HandleGadgets(-1, -1, 0);
4730 // (replace with setting corresponding request background)
4731 // SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
4732 // SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
4734 /* clear door drawing field */
4735 // DrawBackground(DX, DY, DXSIZE, DYSIZE);
4738 if (global.use_envelope_request)
4742 CreateToolButtons();
4748 if (req_state & REQ_ASK)
4750 MapGadgetExt(tool_gadget[TOOL_CTRL_ID_YES], FALSE);
4751 MapGadgetExt(tool_gadget[TOOL_CTRL_ID_NO], FALSE);
4753 else if (req_state & REQ_CONFIRM)
4755 MapGadgetExt(tool_gadget[TOOL_CTRL_ID_CONFIRM], FALSE);
4757 else if (req_state & REQ_PLAYER)
4759 MapGadgetExt(tool_gadget[TOOL_CTRL_ID_PLAYER_1], FALSE);
4760 MapGadgetExt(tool_gadget[TOOL_CTRL_ID_PLAYER_2], FALSE);
4761 MapGadgetExt(tool_gadget[TOOL_CTRL_ID_PLAYER_3], FALSE);
4762 MapGadgetExt(tool_gadget[TOOL_CTRL_ID_PLAYER_4], FALSE);
4765 if (req_state & REQ_ASK)
4767 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
4768 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
4770 else if (req_state & REQ_CONFIRM)
4772 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
4774 else if (req_state & REQ_PLAYER)
4776 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
4777 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
4778 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
4779 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
4784 ShowEnvelopeRequest(text, req_state, ACTION_OPENING);
4787 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4789 if ((req_state & REQ_ASK && (i == TOOL_CTRL_ID_YES ||
4790 i == TOOL_CTRL_ID_NO)) ||
4791 (req_state & REQ_CONFIRM && i == TOOL_CTRL_ID_CONFIRM) ||
4792 (req_state & REQ_PLAYER && (i == TOOL_CTRL_ID_PLAYER_1 &&
4793 i == TOOL_CTRL_ID_PLAYER_2 &&
4794 i == TOOL_CTRL_ID_PLAYER_3 &&
4795 i == TOOL_CTRL_ID_PLAYER_4)))
4797 int x = tool_gadget[i]->x + dDX;
4798 int y = tool_gadget[i]->y + dDY;
4800 ModifyGadget(tool_gadget[i], GDI_X, x, GDI_Y, y, GDI_END);
4805 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
4807 if (game_status == GAME_MODE_PLAYING)
4809 SetPanelBackground();
4810 SetDrawBackgroundMask(REDRAW_DOOR_1);
4814 SetDrawBackgroundMask(REDRAW_FIELD);
4821 if (game_status != GAME_MODE_MAIN)
4825 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
4827 // ---------- handle request buttons ----------
4828 result = RequestHandleEvents(req_state);
4830 if (game_status != GAME_MODE_MAIN)
4835 ShowEnvelopeRequest(text, req_state, ACTION_CLOSING);
4839 if (game_status == GAME_MODE_PLAYING)
4841 SetPanelBackground();
4842 SetDrawBackgroundMask(REDRAW_DOOR_1);
4846 SetDrawBackgroundMask(REDRAW_FIELD);
4849 #if defined(NETWORK_AVALIABLE)
4850 /* continue network game after request */
4851 if (options.network &&
4852 game_status == GAME_MODE_PLAYING &&
4853 req_state & REQUEST_WAIT_FOR_INPUT)
4854 SendToServer_ContinuePlaying();
4857 /* restore deactivated drawing when quick-loading level tape recording */
4858 if (tape.playing && tape.deactivate_display)
4859 TapeDeactivateDisplayOn();
4864 boolean Request(char *text, unsigned int req_state)
4866 if (global.use_envelope_request)
4867 return RequestEnvelope(text, req_state);
4869 return RequestDoor(text, req_state);
4872 #else // =====================================================================
4874 boolean Request(char *text, unsigned int req_state)
4876 int mx, my, ty, result = -1;
4877 unsigned int old_door_state;
4878 int last_game_status = game_status; /* save current game status */
4879 int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
4880 int font_nr = FONT_TEXT_2;
4882 int max_word_len = 0;
4888 global.use_envelope_request = 1;
4892 if (maxWordLengthInString(text) > MAX_REQUEST_LINE_FONT1_LEN)
4894 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
4895 font_nr = FONT_TEXT_1;
4898 for (text_ptr = text; *text_ptr; text_ptr++)
4900 max_word_len = (*text_ptr != ' ' ? max_word_len + 1 : 0);
4902 if (max_word_len > MAX_REQUEST_LINE_FONT1_LEN)
4904 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
4906 font_nr = FONT_TEXT_1;
4908 font_nr = FONT_LEVEL_NUMBER;
4916 if (game_status == GAME_MODE_PLAYING)
4918 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
4919 BlitScreenToBitmap_EM(backbuffer);
4920 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
4921 BlitScreenToBitmap_SP(backbuffer);
4924 /* disable deactivated drawing when quick-loading level tape recording */
4925 if (tape.playing && tape.deactivate_display)
4926 TapeDeactivateDisplayOff(TRUE);
4928 SetMouseCursor(CURSOR_DEFAULT);
4930 #if defined(NETWORK_AVALIABLE)
4931 /* pause network game while waiting for request to answer */
4932 if (options.network &&
4933 game_status == GAME_MODE_PLAYING &&
4934 req_state & REQUEST_WAIT_FOR_INPUT)
4935 SendToServer_PausePlaying();
4938 old_door_state = GetDoorState();
4940 /* simulate releasing mouse button over last gadget, if still pressed */
4942 HandleGadgets(-1, -1, 0);
4946 /* draw released gadget before proceeding */
4950 if (old_door_state & DOOR_OPEN_1 && !global.use_envelope_request)
4952 if (old_door_state & DOOR_OPEN_1)
4956 if (!global.use_envelope_request)
4957 CloseDoor(DOOR_CLOSE_1);
4959 CloseDoor(DOOR_CLOSE_1);
4962 /* save old door content */
4963 BlitBitmap(bitmap_db_door, bitmap_db_door,
4964 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
4965 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
4969 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
4972 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
4974 /* clear door drawing field */
4975 DrawBackground(DX, DY, DXSIZE, DYSIZE);
4977 /* force DOOR font inside door area */
4978 game_status = GAME_MODE_PSEUDO_DOOR;
4980 /* write text for request */
4981 for (text_ptr = text, ty = 0; ty < MAX_REQUEST_LINES; ty++)
4983 char text_line[max_request_line_len + 1];
4989 for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
4991 tc = *(text_ptr + tx);
4992 if (!tc || tc == ' ')
5003 strncpy(text_line, text_ptr, tl);
5006 DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
5007 DY + 8 + ty * (getFontHeight(font_nr) + 2),
5008 text_line, font_nr);
5010 text_ptr += tl + (tc == ' ' ? 1 : 0);
5013 game_status = last_game_status; /* restore current game status */
5016 if (global.use_envelope_request)
5020 CreateToolButtons();
5024 if (req_state & REQ_ASK)
5026 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
5027 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
5029 else if (req_state & REQ_CONFIRM)
5031 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
5033 else if (req_state & REQ_PLAYER)
5035 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
5036 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
5037 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
5038 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
5041 /* copy request gadgets to door backbuffer */
5042 BlitBitmap(drawto, bitmap_db_door,
5043 DX, DY, DXSIZE, DYSIZE,
5044 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
5047 if (global.use_envelope_request)
5049 ShowEnvelopeRequest(text, ACTION_OPENING);
5051 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
5053 if ((req_state & REQ_ASK && (i == TOOL_CTRL_ID_YES ||
5054 i == TOOL_CTRL_ID_NO)) ||
5055 (req_state & REQ_CONFIRM && i == TOOL_CTRL_ID_CONFIRM) ||
5056 (req_state & REQ_PLAYER && (i == TOOL_CTRL_ID_PLAYER_1 &&
5057 i == TOOL_CTRL_ID_PLAYER_2 &&
5058 i == TOOL_CTRL_ID_PLAYER_3 &&
5059 i == TOOL_CTRL_ID_PLAYER_4)))
5061 int x = tool_gadget[i]->x + dDX;
5062 int y = tool_gadget[i]->y + dDY;
5064 ModifyGadget(tool_gadget[i], GDI_X, x, GDI_Y, y, GDI_END);
5071 if (!global.use_envelope_request)
5072 OpenDoor(DOOR_OPEN_1);
5074 OpenDoor(DOOR_OPEN_1);
5077 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
5079 if (game_status == GAME_MODE_PLAYING)
5081 SetPanelBackground();
5082 SetDrawBackgroundMask(REDRAW_DOOR_1);
5086 SetDrawBackgroundMask(REDRAW_FIELD);
5093 if (game_status != GAME_MODE_MAIN && !global.use_envelope_request)
5096 if (game_status != GAME_MODE_MAIN)
5100 button_status = MB_RELEASED;
5102 request_gadget_id = -1;
5104 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
5116 case EVENT_BUTTONPRESS:
5117 case EVENT_BUTTONRELEASE:
5118 case EVENT_MOTIONNOTIFY:
5120 if (event.type == EVENT_MOTIONNOTIFY)
5122 if (!PointerInWindow(window))
5123 continue; /* window and pointer are on different screens */
5128 motion_status = TRUE;
5129 mx = ((MotionEvent *) &event)->x;
5130 my = ((MotionEvent *) &event)->y;
5134 motion_status = FALSE;
5135 mx = ((ButtonEvent *) &event)->x;
5136 my = ((ButtonEvent *) &event)->y;
5137 if (event.type == EVENT_BUTTONPRESS)
5138 button_status = ((ButtonEvent *) &event)->button;
5140 button_status = MB_RELEASED;
5143 /* this sets 'request_gadget_id' */
5144 HandleGadgets(mx, my, button_status);
5146 switch (request_gadget_id)
5148 case TOOL_CTRL_ID_YES:
5151 case TOOL_CTRL_ID_NO:
5154 case TOOL_CTRL_ID_CONFIRM:
5155 result = TRUE | FALSE;
5158 case TOOL_CTRL_ID_PLAYER_1:
5161 case TOOL_CTRL_ID_PLAYER_2:
5164 case TOOL_CTRL_ID_PLAYER_3:
5167 case TOOL_CTRL_ID_PLAYER_4:
5178 case EVENT_KEYPRESS:
5179 switch (GetEventKey((KeyEvent *)&event, TRUE))
5182 if (req_state & REQ_CONFIRM)
5191 #if defined(TARGET_SDL2)
5201 if (req_state & REQ_PLAYER)
5205 case EVENT_KEYRELEASE:
5206 ClearPlayerAction();
5210 HandleOtherEvents(&event);
5214 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
5216 int joy = AnyJoystick();
5218 if (joy & JOY_BUTTON_1)
5220 else if (joy & JOY_BUTTON_2)
5226 if (game_status == GAME_MODE_PLAYING && local_player->LevelSolved_GameEnd)
5228 HandleGameActions();
5234 if (!PendingEvent()) /* delay only if no pending events */
5239 game_status = GAME_MODE_PSEUDO_DOOR;
5245 game_status = last_game_status; /* restore current game status */
5253 if (!PendingEvent()) /* delay only if no pending events */
5256 /* don't eat all CPU time */
5263 if (game_status != GAME_MODE_MAIN)
5269 if (global.use_envelope_request)
5270 ShowEnvelopeRequest(text, ACTION_CLOSING);
5274 if (!(req_state & REQ_STAY_OPEN) && !global.use_envelope_request)
5276 if (!(req_state & REQ_STAY_OPEN))
5279 CloseDoor(DOOR_CLOSE_1);
5281 if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
5282 (req_state & REQ_REOPEN))
5283 OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
5288 if (game_status == GAME_MODE_PLAYING)
5290 SetPanelBackground();
5291 SetDrawBackgroundMask(REDRAW_DOOR_1);
5295 SetDrawBackgroundMask(REDRAW_FIELD);
5298 #if defined(NETWORK_AVALIABLE)
5299 /* continue network game after request */
5300 if (options.network &&
5301 game_status == GAME_MODE_PLAYING &&
5302 req_state & REQUEST_WAIT_FOR_INPUT)
5303 SendToServer_ContinuePlaying();
5306 /* restore deactivated drawing when quick-loading level tape recording */
5307 if (tape.playing && tape.deactivate_display)
5308 TapeDeactivateDisplayOn();
5315 static int compareDoorPartOrderInfo(const void *object1, const void *object2)
5317 const struct DoorPartOrderInfo *dpo1 = (struct DoorPartOrderInfo *)object1;
5318 const struct DoorPartOrderInfo *dpo2 = (struct DoorPartOrderInfo *)object2;
5321 if (dpo1->sort_priority != dpo2->sort_priority)
5322 compare_result = dpo1->sort_priority - dpo2->sort_priority;
5324 compare_result = dpo1->nr - dpo2->nr;
5326 return compare_result;
5333 for (i = 0; door_part_controls[i].door_nr != -1; i++)
5335 struct DoorPartControlInfo *dpc = &door_part_controls[i];
5336 struct DoorPartOrderInfo *dpo = &door_part_order[i];
5338 /* initialize "start_step_opening" and "start_step_closing", if needed */
5339 if (dpc->pos->start_step_opening == 0 &&
5340 dpc->pos->start_step_closing == 0)
5342 dpc->pos->start_step_opening = dpc->pos->start_step;
5343 dpc->pos->start_step_closing = dpc->pos->start_step;
5346 /* fill structure for door part draw order (sorted below) */
5348 dpo->sort_priority = dpc->pos->sort_priority;
5351 struct DoorPartPosInfo *pos = dpc->pos;
5353 printf(":0: step_xoffset == %d, step_yoffset == %d\n",
5354 pos->step_xoffset, pos->step_yoffset);
5358 /* sort door part controls according to sort_priority and graphic number */
5359 qsort(door_part_order, MAX_DOOR_PARTS,
5360 sizeof(struct DoorPartOrderInfo), compareDoorPartOrderInfo);
5363 unsigned int OpenDoor(unsigned int door_state)
5365 if (door_state & DOOR_COPY_BACK)
5367 if (door_state & DOOR_OPEN_1)
5368 BlitBitmap(bitmap_db_door, bitmap_db_door,
5369 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
5370 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
5372 if (door_state & DOOR_OPEN_2)
5373 BlitBitmap(bitmap_db_door, bitmap_db_door,
5374 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY2, VXSIZE, VYSIZE,
5375 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
5377 door_state &= ~DOOR_COPY_BACK;
5380 return MoveDoor(door_state);
5383 unsigned int CloseDoor(unsigned int door_state)
5385 unsigned int old_door_state = GetDoorState();
5387 if (!(door_state & DOOR_NO_COPY_BACK))
5389 if (old_door_state & DOOR_OPEN_1)
5390 BlitBitmap(backbuffer, bitmap_db_door,
5391 DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
5393 if (old_door_state & DOOR_OPEN_2)
5394 BlitBitmap(backbuffer, bitmap_db_door,
5395 VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
5397 door_state &= ~DOOR_NO_COPY_BACK;
5400 return MoveDoor(door_state);
5403 unsigned int GetDoorState()
5405 return MoveDoor(DOOR_GET_STATE);
5408 unsigned int SetDoorState(unsigned int door_state)
5410 return MoveDoor(door_state | DOOR_SET_STATE);
5415 // ========== TEST 1 ===========================================================
5417 int euclid(int a, int b)
5419 return (b ? euclid(b, a % b) : a);
5422 unsigned int MoveDoor(unsigned int door_state)
5424 struct XY panel_pos_list[] =
5426 { DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 },
5427 { DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 },
5429 struct Rect door_rect_list[] =
5431 { DX, DY, DXSIZE, DYSIZE },
5432 { VX, VY, VXSIZE, VYSIZE }
5434 static int door1 = DOOR_OPEN_1;
5435 static int door2 = DOOR_CLOSE_2;
5436 unsigned int door_delay = 0;
5437 unsigned int door_delay_value;
5441 if (door_1.width < 0 || door_1.width > DXSIZE)
5442 door_1.width = DXSIZE;
5443 if (door_1.height < 0 || door_1.height > DYSIZE)
5444 door_1.height = DYSIZE;
5445 if (door_2.width < 0 || door_2.width > VXSIZE)
5446 door_2.width = VXSIZE;
5447 if (door_2.height < 0 || door_2.height > VYSIZE)
5448 door_2.height = VYSIZE;
5451 if (door_state == DOOR_GET_STATE)
5452 return (door1 | door2);
5454 if (door_state & DOOR_SET_STATE)
5456 if (door_state & DOOR_ACTION_1)
5457 door1 = door_state & DOOR_ACTION_1;
5458 if (door_state & DOOR_ACTION_2)
5459 door2 = door_state & DOOR_ACTION_2;
5461 return (door1 | door2);
5464 if (!(door_state & DOOR_FORCE_REDRAW))
5466 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
5467 door_state &= ~DOOR_OPEN_1;
5468 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
5469 door_state &= ~DOOR_CLOSE_1;
5470 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
5471 door_state &= ~DOOR_OPEN_2;
5472 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
5473 door_state &= ~DOOR_CLOSE_2;
5477 door_delay_value = (door_state & DOOR_ACTION_1 ? door_1.step_delay :
5480 if (setup.quick_doors)
5482 stepsize = 20; /* must be chosen to always draw last frame */
5483 door_delay_value = 0;
5487 if (global.autoplay_leveldir)
5489 door_state |= DOOR_NO_DELAY;
5490 door_state &= ~DOOR_CLOSE_ALL;
5494 if (game_status == GAME_MODE_EDITOR)
5495 door_state |= DOOR_NO_DELAY;
5498 if (door_state & DOOR_ACTION)
5500 boolean door_panel_drawn[NUM_DOORS];
5501 boolean door_part_done[MAX_DOOR_PARTS];
5502 boolean door_part_done_all;
5503 int num_steps[MAX_DOOR_PARTS];
5504 int max_move_delay = 0; // delay for complete animations of all doors
5505 int max_step_delay = 0; // delay (ms) between two animation frames
5506 int num_move_steps = 0; // number of animation steps for all doors
5507 int current_move_delay = 0;
5510 for (i = 0; i < MAX_DOOR_PARTS; i++)
5512 struct DoorPartControlInfo *dpc = &door_part_controls[i];
5513 struct GraphicInfo *g = &graphic_info[dpc->graphic];
5514 int door_token = dpc->door_nr;
5516 door_part_done[i] = (!(door_state & door_token) ||
5521 for (i = 0; i < MAX_DOOR_PARTS; i++)
5523 struct DoorPartControlInfo *dpc = &door_part_controls[i];
5524 struct DoorPartPosInfo *pos = dpc->pos;
5525 int start_step = pos->start_step;
5527 printf("::: ---> %d: start_step == %d [%d]\n",
5528 i, start_step, door_part_done[i]);
5532 for (i = 0; i < MAX_DOOR_PARTS; i++)
5534 int nr = door_part_order[i].nr;
5535 struct DoorPartControlInfo *dpc = &door_part_controls[nr];
5536 struct DoorPartPosInfo *pos = dpc->pos;
5537 struct GraphicInfo *g = &graphic_info[dpc->graphic];
5538 int door_token = dpc->door_nr;
5539 boolean is_panel = DOOR_PART_IS_PANEL(nr);
5540 int step_xoffset = ABS(pos->step_xoffset);
5541 int step_yoffset = ABS(pos->step_yoffset);
5542 int step_delay = pos->step_delay;
5543 int current_door_state = door_state & door_token;
5544 boolean door_opening = ((current_door_state & DOOR_OPEN) != 0);
5545 boolean door_closing = ((current_door_state & DOOR_CLOSE) != 0);
5546 boolean part_opening = (is_panel ? door_closing : door_opening);
5547 int start_step = (part_opening ? pos->start_step_opening :
5548 pos->start_step_closing);
5549 float move_xsize = (step_xoffset ? g->width : 0);
5550 float move_ysize = (step_yoffset ? g->height : 0);
5551 int move_xsteps = (step_xoffset ? ceil(move_xsize / step_xoffset) : 0);
5552 int move_ysteps = (step_yoffset ? ceil(move_ysize / step_yoffset) : 0);
5553 int move_steps = (move_xsteps && move_ysteps ?
5554 MIN(move_xsteps, move_ysteps) :
5555 move_xsteps ? move_xsteps : move_ysteps) - start_step;
5556 int move_delay = move_steps * step_delay;
5558 if (door_part_done[nr])
5561 max_move_delay = MAX(max_move_delay, move_delay);
5562 max_step_delay = (max_step_delay == 0 ? step_delay :
5563 euclid(max_step_delay, step_delay));
5564 num_steps[nr] = move_steps;
5568 printf("::: %d: move_delay == %d, start_step == %d [%d]\n",
5569 i, move_delay, start_step, door_part_order[i].nr);
5571 if (DOOR_PART_IS_PANEL(i))
5572 printf("::: %d: move_delay == %d, start_step == %d\n",
5573 i, move_delay, start_step);
5578 num_move_steps = max_move_delay / max_step_delay;
5580 door_delay_value = max_step_delay;
5583 door_delay_value *= 10;
5587 printf("::: num_move_steps == %d, max_move_delay == %d, max_step_delay == %d\n", num_move_steps, max_move_delay, max_step_delay);
5590 for (k = 0; k < num_move_steps; k++)
5592 for (i = 0; i < NUM_DOORS; i++)
5593 door_panel_drawn[i] = FALSE;
5595 for (i = 0; i < MAX_DOOR_PARTS; i++)
5597 int nr = door_part_order[i].nr;
5598 struct DoorPartControlInfo *dpc = &door_part_controls[nr];
5599 struct DoorPartPosInfo *pos = dpc->pos;
5600 struct GraphicInfo *g = &graphic_info[dpc->graphic];
5601 int door_token = dpc->door_nr;
5602 int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
5603 boolean is_panel = DOOR_PART_IS_PANEL(nr);
5604 struct XY *panel_pos = &panel_pos_list[door_index];
5605 struct Rect *door_rect = &door_rect_list[door_index];
5606 Bitmap *bitmap = (is_panel ? bitmap_db_door : g->bitmap);
5607 int current_door_state = door_state & door_token;
5608 boolean door_opening = ((current_door_state & DOOR_OPEN) != 0);
5609 boolean door_closing = ((current_door_state & DOOR_CLOSE) != 0);
5610 boolean part_opening = (is_panel ? door_closing : door_opening);
5611 int start_step = (part_opening ? pos->start_step_opening :
5612 pos->start_step_closing);
5613 int step_delay = pos->step_delay;
5614 int step_factor = step_delay / max_step_delay;
5615 int k1 = (step_factor ? k / step_factor + 1 : k);
5616 int k2 = (part_opening ? k1 + start_step : num_steps[nr] - k1);
5617 int kk = (k2 < 0 ? 0 : k2);
5618 int src_x, src_y, src_xx, src_yy;
5619 int dst_x, dst_y, dst_xx, dst_yy;
5623 if (DOOR_PART_IS_PANEL(nr))
5625 int start_step = pos->start_step;
5627 k2 = (door_closing ? k1 : num_steps[nr] - k1);// - start_step;
5628 kk = (k2 < 0 ? 0 : k2);
5634 if (nr != 16 && nr != 0)
5639 if (door_part_done[nr])
5643 if (!(door_state & door_token))
5650 if (current_move_delay % step_delay)
5656 if (!door_panel_drawn[door_index])
5659 ClearRectangle(drawto, door_rect->x, door_rect->y,
5660 door_rect->width, door_rect->height);
5662 BlitBitmap(bitmap_db_door, drawto, panel_pos->x, panel_pos->y,
5663 door_rect->width, door_rect->height,
5664 door_rect->x, door_rect->y);
5667 door_panel_drawn[door_index] = TRUE;
5670 // draw opening or closing door parts
5672 if (pos->step_xoffset < 0) // door part on right side
5675 dst_xx = pos->x + ABS(kk * pos->step_xoffset);
5678 if (dst_xx + width > door_rect->width)
5679 width = door_rect->width - dst_xx;
5681 else // door part on left side
5684 dst_xx = pos->x - kk * pos->step_xoffset;
5688 src_xx = ABS(dst_xx);
5692 width = g->width - src_xx;
5694 // printf("::: k == %d [%d] \n", k, start_step);
5697 if (pos->step_yoffset < 0) // door part on bottom side
5700 dst_yy = pos->y + ABS(kk * pos->step_yoffset);
5703 if (dst_yy + height > door_rect->height)
5704 height = door_rect->height - dst_yy;
5706 else // door part on top side
5709 dst_yy = pos->y - kk * pos->step_yoffset;
5713 src_yy = ABS(dst_yy);
5717 height = g->height - src_yy;
5722 src_x = panel_pos->x + src_xx;
5723 src_y = panel_pos->y + src_yy;
5727 src_x = g->src_x + src_xx;
5728 src_y = g->src_y + src_yy;
5731 dst_x = door_rect->x + dst_xx;
5732 dst_y = door_rect->y + dst_yy;
5735 if (DOOR_PART_IS_PANEL(nr))
5737 printf("::: width == %d, height == %d [%d, %d] [%d, %d]\n",
5738 width, height, g->width, g->height, src_x, src_y);
5742 if (width >= 0 && width <= g->width &&
5743 height >= 0 && height <= g->height)
5745 if (is_panel || !pos->draw_masked)
5746 BlitBitmap(bitmap, drawto, src_x, src_y, width, height,
5749 BlitBitmapMasked(bitmap, drawto, src_x, src_y, width, height,
5754 if (DOOR_PART_IS_PANEL(nr))
5756 bitmap = bitmap_db_door;
5757 src_x = panel_pos->x + src_xx;
5758 src_y = panel_pos->y + src_yy;
5760 printf("::: width == %d, height == %d [%d, %d] [%d, %d]\n",
5761 width, height, g->width, g->height, src_x, src_y);
5763 if (width >= 0 && width <= g->width &&
5764 height >= 0 && height <= g->height)
5765 BlitBitmap(bitmap, drawto, src_x, src_y,
5771 redraw_mask |= REDRAW_DOOR_FROM_TOKEN(door_token);
5773 if ((door_opening && (width < 0 || height < 0)) ||
5774 (door_closing && (width >= g->width && height >= g->height)))
5775 door_part_done[nr] = TRUE;
5778 if (!(door_state & DOOR_NO_DELAY))
5782 if (game_status == GAME_MODE_MAIN)
5785 WaitUntilDelayReached(&door_delay, door_delay_value);
5787 current_move_delay += max_step_delay;
5790 door_part_done_all = TRUE;
5792 for (i = 0; i < MAX_DOOR_PARTS; i++)
5793 if (!door_part_done[i])
5794 door_part_done_all = FALSE;
5797 if (door_part_done_all)
5803 if (door_state & DOOR_ACTION_1)
5804 door1 = door_state & DOOR_ACTION_1;
5805 if (door_state & DOOR_ACTION_2)
5806 door2 = door_state & DOOR_ACTION_2;
5808 return (door1 | door2);
5813 // ========== OLD ==============================================================
5815 unsigned int MoveDoor(unsigned int door_state)
5817 static int door1 = DOOR_OPEN_1;
5818 static int door2 = DOOR_CLOSE_2;
5819 unsigned int door_delay = 0;
5820 unsigned int door_delay_value;
5824 if (door_1.width < 0 || door_1.width > DXSIZE)
5825 door_1.width = DXSIZE;
5826 if (door_1.height < 0 || door_1.height > DYSIZE)
5827 door_1.height = DYSIZE;
5828 if (door_2.width < 0 || door_2.width > VXSIZE)
5829 door_2.width = VXSIZE;
5830 if (door_2.height < 0 || door_2.height > VYSIZE)
5831 door_2.height = VYSIZE;
5834 if (door_state == DOOR_GET_STATE)
5835 return (door1 | door2);
5837 if (door_state & DOOR_SET_STATE)
5839 if (door_state & DOOR_ACTION_1)
5840 door1 = door_state & DOOR_ACTION_1;
5841 if (door_state & DOOR_ACTION_2)
5842 door2 = door_state & DOOR_ACTION_2;
5844 return (door1 | door2);
5847 if (!(door_state & DOOR_FORCE_REDRAW))
5849 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
5850 door_state &= ~DOOR_OPEN_1;
5851 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
5852 door_state &= ~DOOR_CLOSE_1;
5853 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
5854 door_state &= ~DOOR_OPEN_2;
5855 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
5856 door_state &= ~DOOR_CLOSE_2;
5859 door_delay_value = (door_state & DOOR_ACTION_1 ? door_1.step_delay :
5862 // door_delay_value *= 4; // !!! TEST ONLY !!!
5864 if (setup.quick_doors)
5866 stepsize = 20; /* must be chosen to always draw last frame */
5867 door_delay_value = 0;
5870 if (global.autoplay_leveldir)
5872 door_state |= DOOR_NO_DELAY;
5873 door_state &= ~DOOR_CLOSE_ALL;
5877 if (game_status == GAME_MODE_EDITOR)
5878 door_state |= DOOR_NO_DELAY;
5881 if (door_state & DOOR_ACTION)
5884 struct GraphicInfo *g1_left = &graphic_info[IMG_DOOR_1_WING_LEFT];
5885 struct GraphicInfo *g1_right = &graphic_info[IMG_DOOR_1_WING_RIGHT];
5886 struct GraphicInfo *g2_left = &graphic_info[IMG_DOOR_2_WING_LEFT];
5887 struct GraphicInfo *g2_right = &graphic_info[IMG_DOOR_2_WING_RIGHT];
5888 int door_1_left_width = g1_left->width;
5889 int door_1_left_height = g1_left->height;
5890 int door_1_right_width = g1_right->width;
5891 int door_1_right_height = g1_right->height;
5892 int door_2_left_width = g2_left->width;
5893 int door_2_left_height = g2_left->height;
5894 int door_2_right_width = g2_right->width;
5895 int door_2_right_height = g2_right->height;
5896 int door_1_width = MAX(door_1_left_width, door_1_right_width);
5897 int door_1_height = MAX(door_1_left_height, door_1_right_height);
5898 int door_2_width = MAX(door_2_left_width, door_2_right_width);
5899 int door_2_height = MAX(door_2_left_height, door_2_right_height);
5901 boolean handle_door_1 = (door_state & DOOR_ACTION_1);
5902 boolean handle_door_2 = (door_state & DOOR_ACTION_2);
5903 boolean door_1_done = (!handle_door_1);
5904 boolean door_2_done = (!handle_door_2);
5905 boolean door_1_vertical = (door_1.anim_mode & ANIM_VERTICAL);
5906 boolean door_2_vertical = (door_2.anim_mode & ANIM_VERTICAL);
5909 int door_size_1 = (door_1_vertical ? door_1_height : door_1_width);
5910 int door_size_2 = (door_2_vertical ? door_2_height : door_2_width);
5912 int door_size_1 = (door_1_vertical ? DYSIZE : DXSIZE);
5913 int door_size_2 = (door_2_vertical ? VYSIZE : VXSIZE);
5916 int door_size_1 = (door_1_vertical ? door_1.height : door_1.width);
5917 int door_size_2 = (door_2_vertical ? door_2.height : door_2.width);
5919 int max_door_size_1 = (door_1_vertical ? DYSIZE : DXSIZE);
5920 int max_door_size_2 = (door_2_vertical ? VYSIZE : VXSIZE);
5921 // int door_size = (handle_door_1 ? door_size_1 : door_size_2);
5922 int door_size = (handle_door_2 ? door_size_2 : door_size_1);
5923 int max_door_size = (handle_door_1 ? max_door_size_1 : max_door_size_2);
5924 int door_skip = max_door_size - door_size;
5925 int end = door_size;
5926 int start = ((door_state & DOOR_NO_DELAY) ? end : 0);
5929 if (!(door_state & DOOR_NO_DELAY) && !setup.quick_doors)
5931 /* opening door sound has priority over simultaneously closing door */
5932 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
5933 PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
5934 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
5935 PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
5938 for (k = start; k <= end && !(door_1_done && door_2_done); k += stepsize)
5942 Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
5943 GC gc = bitmap->stored_clip_gc;
5946 if (door_state & DOOR_ACTION_1 &&
5947 x * door_1.step_offset <= door_size_1)
5949 int a = MIN(x * door_1.step_offset, end);
5950 int p = (door_state & DOOR_OPEN_1 ? end - a : a);
5954 int i = p + door_skip;
5958 struct GraphicInfo *g_left = &graphic_info[IMG_DOOR_1_WING_LEFT];
5959 struct GraphicInfo *g_right = &graphic_info[IMG_DOOR_1_WING_RIGHT];
5960 Bitmap *bm_left = g_left->bitmap;
5961 Bitmap *bm_right = g_right->bitmap;
5962 GC gc_left = bm_left->stored_clip_gc;
5963 GC gc_right = bm_right->stored_clip_gc;
5966 int classic_dxsize = 100;
5967 int classic_dysize = 280;
5968 boolean classic_door_1_size = (DXSIZE == classic_dxsize &&
5969 DYSIZE == classic_dysize);
5971 if (door_1.anim_mode & ANIM_STATIC_PANEL)
5973 BlitBitmap(bitmap_db_door, drawto,
5974 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1,
5975 DXSIZE, DYSIZE, DX, DY);
5979 BlitBitmap(bitmap_db_door, drawto,
5980 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + p / 2,
5981 DXSIZE, DYSIZE - p / 2, DX, DY);
5984 // printf("::: p == %d\n", p);
5985 ClearRectangle(drawto, DX, DY + DYSIZE - p / 2, DXSIZE, p / 2);
5989 if (door_1.anim_mode & ANIM_HORIZONTAL && x <= DXSIZE)
5992 int src1_x = g_right->src_x;
5993 int src1_y = g_right->src_y;
5994 int src2_x = g_left->src_x + g_left->width - i;
5995 int src2_y = g_left->src_y;
5996 int dst1_x = DX + DXSIZE - i;
6001 int height = DYSIZE;
6003 SetClipOrigin(bm_right, gc_right, dst1_x - src1_x, dst1_y - src1_y);
6004 BlitBitmapMasked(bm_right, drawto, src1_x, src1_y, width, height,
6007 SetClipOrigin(bm_left, gc_left, dst2_x - src2_x, dst2_y - src2_y);
6008 BlitBitmapMasked(bm_left, drawto, src2_x, src2_y, width, height,
6011 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
6012 int src2_x = DXSIZE - i, src2_y = DOOR_GFX_PAGEY1;
6013 int dst1_x = DX + DXSIZE - i, dst1_y = DY;
6014 int dst2_x = DX, dst2_y = DY;
6015 int width = i, height = DYSIZE;
6017 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
6018 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
6021 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
6022 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
6026 else if (door_1.anim_mode & ANIM_VERTICAL && x <= DYSIZE)
6029 int src1_x = g_right->src_x;
6030 int src1_y = g_right->src_y;
6031 int src2_x = g_left->src_x;
6032 int src2_y = g_left->src_y + g_left->height - i;
6034 int dst1_y = DY + DYSIZE - i;
6040 SetClipOrigin(bm_right, gc_right, dst1_x - src1_x, dst1_y - src1_y);
6041 BlitBitmapMasked(bm_right, drawto, src1_x, src1_y, width, height,
6044 SetClipOrigin(bm_left, gc_left, dst2_x - src2_x, dst2_y - src2_y);
6045 BlitBitmapMasked(bm_left, drawto, src2_x, src2_y, width, height,
6048 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
6049 int src2_x = 0, src2_y = DOOR_GFX_PAGEY1 + DYSIZE - i;
6050 int dst1_x = DX, dst1_y = DY + DYSIZE - i;
6051 int dst2_x = DX, dst2_y = DY;
6052 int width = DXSIZE, height = i;
6054 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
6055 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
6058 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
6059 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
6063 else if (classic_door_1_size && x <= DXSIZE) /* ANIM_DEFAULT */
6065 int j = (door_1.anim_mode == ANIM_DEFAULT ? (DXSIZE - i) / 3 : 0);
6068 int src1_x = g_right->src_x;
6069 int src1_y = g_right->src_y;
6070 int src2_x = g_left->src_x + g_left->width - i;
6071 int src2_y = g_left->src_y;
6072 int dst1_x = DX + DXSIZE - i;
6077 int height1 = 63, height2 = DYSIZE / 2 - height1;
6078 int ypos1 = 0, ypos2 = height2;
6079 int ypos3 = DYSIZE / 2, ypos4 = DYSIZE - height2;
6081 SetClipOrigin(bm_right, gc_right,
6082 dst1_x - src1_x, dst1_y - src1_y + j);
6083 BlitBitmapMasked(bm_right, drawto,
6084 src1_x, src1_y + ypos1, width, height2,
6085 dst1_x, dst1_y + ypos1 + j);
6086 BlitBitmapMasked(bm_right, drawto,
6087 src1_x, src1_y + ypos3, width, height1,
6088 dst1_x, dst1_y + ypos3 + j);
6089 SetClipOrigin(bm_left, gc_left,
6090 dst2_x - src2_x, dst2_y - src2_y - j);
6091 BlitBitmapMasked(bm_left, drawto,
6092 src2_x, src2_y + ypos1 + j, width, height2 - j,
6093 dst2_x, dst2_y + ypos1);
6094 BlitBitmapMasked(bm_left, drawto,
6095 src2_x, src2_y + ypos3, width, height1,
6096 dst2_x, dst2_y + ypos3 - j);
6098 SetClipOrigin(bm_left, gc_left,
6099 dst2_x - src2_x, dst2_y - src2_y - j);
6100 BlitBitmapMasked(bm_left, drawto,
6101 src2_x, src2_y + ypos2, width, height1,
6102 dst2_x, dst2_y + ypos2 - j);
6103 BlitBitmapMasked(bm_left, drawto,
6104 src2_x, src2_y + ypos4, width, height2,
6105 dst2_x, dst2_y + ypos4 - j);
6106 SetClipOrigin(bm_right, gc_right,
6107 dst1_x - src1_x, dst1_y - src1_y + j);
6108 BlitBitmapMasked(bm_right, drawto,
6109 src1_x, src1_y + ypos2, width, height1,
6110 dst1_x, dst1_y + ypos2 + j);
6111 BlitBitmapMasked(bm_right, drawto,
6112 src1_x, src1_y + ypos4, width, height2 - j,
6113 dst1_x, dst1_y + ypos4 + j);
6116 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
6117 int src2_x = DXSIZE - i, src2_y = DOOR_GFX_PAGEY1;
6118 int dst1_x = DX + DXSIZE - i, dst1_y = DY;
6119 int dst2_x = DX, dst2_y = DY;
6120 int width = i, height = DYSIZE;
6121 int ypos1 = 63, ypos2 = 77, ypos3 = 140, ypos4 = 203;
6123 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y + j);
6124 BlitBitmapMasked(bitmap, drawto,
6125 src1_x, src1_y, width, ypos2,
6126 dst1_x, dst1_y + j);
6127 BlitBitmapMasked(bitmap, drawto,
6128 src1_x, src1_y + ypos3, width, ypos1,
6129 dst1_x, dst1_y + ypos3 + j);
6130 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y - j);
6131 BlitBitmapMasked(bitmap, drawto,
6132 src2_x, src2_y + j, width, ypos2 - j,
6134 BlitBitmapMasked(bitmap, drawto,
6135 src2_x, src2_y + ypos3, width, ypos1,
6136 dst2_x, dst2_y + ypos3 - j);
6138 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y - j);
6139 BlitBitmapMasked(bitmap, drawto,
6140 src2_x, src2_y + ypos2, width, ypos1,
6141 dst2_x, dst2_y + ypos2 - j);
6142 BlitBitmapMasked(bitmap, drawto,
6143 src2_x, src2_y + ypos4, width, ypos2,
6144 dst2_x, dst2_y + ypos4 - j);
6145 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y + j);
6146 BlitBitmapMasked(bitmap, drawto,
6147 src1_x, src1_y + ypos2, width, ypos1,
6148 dst1_x, dst1_y + ypos2 + j);
6149 BlitBitmapMasked(bitmap, drawto,
6150 src1_x, src1_y + ypos4, width, ypos2 - j,
6151 dst1_x, dst1_y + ypos4 + j);
6154 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
6155 BlitBitmapMasked(bitmap, drawto,
6156 DXSIZE, DOOR_GFX_PAGEY1, i, 77,
6157 DX + DXSIZE - i, DY + j);
6158 BlitBitmapMasked(bitmap, drawto,
6159 DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
6160 DX + DXSIZE - i, DY + 140 + j);
6161 SetClipOrigin(bitmap, gc, DX - DXSIZE + i,
6162 DY - (DOOR_GFX_PAGEY1 + j));
6163 BlitBitmapMasked(bitmap, drawto,
6164 DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
6166 BlitBitmapMasked(bitmap, drawto,
6167 DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
6170 BlitBitmapMasked(bitmap, drawto,
6171 DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
6173 BlitBitmapMasked(bitmap, drawto,
6174 DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
6176 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
6177 BlitBitmapMasked(bitmap, drawto,
6178 DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
6179 DX + DXSIZE - i, DY + 77 + j);
6180 BlitBitmapMasked(bitmap, drawto,
6181 DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
6182 DX + DXSIZE - i, DY + 203 + j);
6187 redraw_mask |= REDRAW_DOOR_1;
6188 door_1_done = (a == end);
6191 if (door_state & DOOR_ACTION_2 &&
6192 x * door_2.step_offset <= door_size_2)
6194 int a = MIN(x * door_2.step_offset, door_size);
6195 int p = (door_state & DOOR_OPEN_2 ? door_size - a : a);
6196 int i = p + door_skip;
6199 struct GraphicInfo *g_left = &graphic_info[IMG_DOOR_2_WING_LEFT];
6200 struct GraphicInfo *g_right = &graphic_info[IMG_DOOR_2_WING_RIGHT];
6201 Bitmap *bm_left = g_left->bitmap;
6202 Bitmap *bm_right = g_right->bitmap;
6203 GC gc_left = bm_left->stored_clip_gc;
6204 GC gc_right = bm_right->stored_clip_gc;
6207 int classic_vxsize = 100;
6208 int classic_vysize = 100;
6209 boolean classic_door_2_size = (VXSIZE == classic_vxsize &&
6210 VYSIZE == classic_vysize);
6212 if (door_2.anim_mode & ANIM_STATIC_PANEL)
6214 BlitBitmap(bitmap_db_door, drawto,
6215 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2,
6216 VXSIZE, VYSIZE, VX, VY);
6218 else if (x <= VYSIZE)
6220 BlitBitmap(bitmap_db_door, drawto,
6221 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + p / 2,
6222 VXSIZE, VYSIZE - p / 2, VX, VY);
6224 ClearRectangle(drawto, VX, VY + VYSIZE - p / 2, VXSIZE, p / 2);
6227 if (door_2.anim_mode & ANIM_HORIZONTAL && x <= VXSIZE)
6230 int src1_x = g_right->src_x;
6231 int src1_y = g_right->src_y;
6232 int src2_x = g_left->src_x + g_left->width - i;
6233 int src2_y = g_left->src_y;
6234 int dst1_x = VX + VXSIZE - i;
6239 int height = VYSIZE;
6241 SetClipOrigin(bm_right, gc_right, dst1_x - src1_x, dst1_y - src1_y);
6242 BlitBitmapMasked(bm_right, drawto, src1_x, src1_y, width, height,
6245 SetClipOrigin(bm_left, gc_left, dst2_x - src2_x, dst2_y - src2_y);
6246 BlitBitmapMasked(bm_left, drawto, src2_x, src2_y, width, height,
6249 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
6250 int src2_x = VXSIZE - i, src2_y = DOOR_GFX_PAGEY2;
6251 int dst1_x = VX + VXSIZE - i, dst1_y = VY;
6252 int dst2_x = VX, dst2_y = VY;
6253 int width = i, height = VYSIZE;
6255 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
6256 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
6259 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
6260 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
6264 else if (door_2.anim_mode & ANIM_VERTICAL && x <= VYSIZE)
6267 int src1_x = g_right->src_x;
6268 int src1_y = g_right->src_y;
6269 int src2_x = g_left->src_x;
6270 int src2_y = g_left->src_y + g_left->height - i;
6272 int dst1_y = VY + VYSIZE - i;
6278 SetClipOrigin(bm_right, gc_right, dst1_x - src1_x, dst1_y - src1_y);
6279 BlitBitmapMasked(bm_right, drawto, src1_x, src1_y, width, height,
6282 SetClipOrigin(bm_left, gc_left, dst2_x - src2_x, dst2_y - src2_y);
6283 BlitBitmapMasked(bm_left, drawto, src2_x, src2_y, width, height,
6286 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
6287 int src2_x = 0, src2_y = DOOR_GFX_PAGEY2 + VYSIZE - i;
6288 int dst1_x = VX, dst1_y = VY + VYSIZE - i;
6289 int dst2_x = VX, dst2_y = VY;
6290 int width = VXSIZE, height = i;
6292 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
6293 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
6296 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
6297 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
6301 else if (classic_door_2_size && x <= VXSIZE) /* ANIM_DEFAULT */
6303 int j = (door_2.anim_mode == ANIM_DEFAULT ? (VXSIZE - i) / 3 : 0);
6306 int src1_x = g_right->src_x;
6307 int src1_y = g_right->src_y;
6308 int src2_x = g_left->src_x + g_left->width - i;
6309 int src2_y = g_left->src_y;
6310 int dst1_x = VX + VXSIZE - i;
6315 int height = VYSIZE / 2;
6316 int ypos1 = 0, ypos2 = VYSIZE / 2;
6318 SetClipOrigin(bm_right, gc_right,
6319 dst1_x - src1_x, dst1_y - src1_y + j);
6320 BlitBitmapMasked(bm_right, drawto,
6321 src1_x, src1_y + ypos1, width, height,
6322 dst1_x, dst1_y + ypos1 + j);
6323 SetClipOrigin(bm_left, gc_left,
6324 dst2_x - src2_x, dst2_y - src2_y - j);
6325 BlitBitmapMasked(bm_left, drawto,
6326 src2_x, src2_y + ypos1 + j, width, height - j,
6327 dst2_x, dst2_y + ypos1);
6329 SetClipOrigin(bm_left, gc_left,
6330 dst2_x - src2_x, dst2_y - src2_y - j);
6331 BlitBitmapMasked(bm_left, drawto,
6332 src2_x, src2_y + ypos2, width, height,
6333 dst2_x, dst2_y + ypos2 - j);
6334 SetClipOrigin(bm_right, gc_right,
6335 dst1_x - src1_x, dst1_y - src1_y + j);
6336 BlitBitmapMasked(bm_right, drawto,
6337 src1_x, src1_y + ypos2, width, height - j,
6338 dst1_x, dst1_y + ypos2 + j);
6340 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
6341 int src2_x = VXSIZE - i, src2_y = DOOR_GFX_PAGEY2;
6342 int dst1_x = VX + VXSIZE - i, dst1_y = VY;
6343 int dst2_x = VX, dst2_y = VY;
6344 int width = i, height = VYSIZE;
6345 int ypos = VYSIZE / 2;
6347 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y + j);
6348 BlitBitmapMasked(bitmap, drawto,
6349 src1_x, src1_y, width, ypos,
6350 dst1_x, dst1_y + j);
6351 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src1_y - j);
6352 BlitBitmapMasked(bitmap, drawto,
6353 src2_x, src2_y + j, width, ypos - j,
6356 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src1_y - j);
6357 BlitBitmapMasked(bitmap, drawto,
6358 src2_x, src2_y + ypos, width, ypos,
6359 dst2_x, dst2_y + ypos - j);
6360 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y + j);
6361 BlitBitmapMasked(bitmap, drawto,
6362 src1_x, src1_y + ypos, width, ypos - j,
6363 dst1_x, dst1_y + ypos + j);
6366 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
6367 BlitBitmapMasked(bitmap, drawto,
6368 VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
6369 VX + VXSIZE - i, VY + j);
6370 SetClipOrigin(bitmap, gc,
6371 VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
6372 BlitBitmapMasked(bitmap, drawto,
6373 VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
6376 BlitBitmapMasked(bitmap, drawto,
6377 VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
6378 i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
6379 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
6380 BlitBitmapMasked(bitmap, drawto,
6381 VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
6383 VX + VXSIZE - i, VY + VYSIZE / 2 + j);
6388 redraw_mask |= REDRAW_DOOR_2;
6389 door_2_done = (a == VXSIZE);
6392 if (!(door_state & DOOR_NO_DELAY))
6396 if (game_status == GAME_MODE_MAIN)
6399 WaitUntilDelayReached(&door_delay, door_delay_value);
6404 if (door_state & DOOR_ACTION_1)
6405 door1 = door_state & DOOR_ACTION_1;
6406 if (door_state & DOOR_ACTION_2)
6407 door2 = door_state & DOOR_ACTION_2;
6409 return (door1 | door2);
6414 void DrawSpecialEditorDoor()
6417 struct GraphicInfo *gfx1 = &graphic_info[IMG_DOOR_2_TOP_BORDER_CORRECTION];
6418 int top_border_width = gfx1->width;
6419 int top_border_height = gfx1->height;
6420 int outer_border = viewport.door_2[GAME_MODE_EDITOR].border_size;
6421 int ex = EX - outer_border;
6422 int ey = EY - outer_border;
6423 int vy = VY - outer_border;
6424 int exsize = EXSIZE + 2 * outer_border;
6426 CloseDoor(DOOR_CLOSE_2);
6428 /* draw bigger level editor toolbox window */
6429 BlitBitmap(gfx1->bitmap, drawto, gfx1->src_x, gfx1->src_y,
6430 top_border_width, top_border_height, ex, ey - top_border_height);
6431 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto, ex, vy,
6432 exsize, EYSIZE - VYSIZE + outer_border, ex, ey);
6434 /* draw bigger level editor toolbox window */
6435 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
6436 DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
6438 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
6439 EX - 6, VY - 4, EXSIZE + 12, EYSIZE - VYSIZE + 4,
6443 redraw_mask |= REDRAW_ALL;
6446 void UndrawSpecialEditorDoor()
6449 struct GraphicInfo *gfx1 = &graphic_info[IMG_DOOR_2_TOP_BORDER_CORRECTION];
6450 int top_border_width = gfx1->width;
6451 int top_border_height = gfx1->height;
6452 int outer_border = viewport.door_2[GAME_MODE_EDITOR].border_size;
6453 int ex = EX - outer_border;
6454 int ey = EY - outer_border;
6455 int ey_top = ey - top_border_height;
6456 int exsize = EXSIZE + 2 * outer_border;
6457 int eysize = EYSIZE + 2 * outer_border;
6459 /* draw normal tape recorder window */
6460 if (graphic_info[IMG_GLOBAL_BORDER].bitmap)
6462 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
6463 ex, ey_top, top_border_width, top_border_height,
6465 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
6466 ex, ey, exsize, eysize, ex, ey);
6470 // if screen background is set to "[NONE]", clear editor toolbox window
6471 ClearRectangle(drawto, ex, ey_top, top_border_width, top_border_height);
6472 ClearRectangle(drawto, ex, ey, exsize, eysize);
6475 /* draw normal tape recorder window */
6476 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
6477 EX - 6, EY - 12, EXSIZE + 12, EYSIZE - VYSIZE + 12,
6481 redraw_mask |= REDRAW_ALL;
6485 /* ---------- new tool button stuff ---------------------------------------- */
6492 struct TextPosInfo *pos;
6495 } toolbutton_info[NUM_TOOL_BUTTONS] =
6498 IMG_REQUEST_BUTTON_GFX_YES, &request.button.yes,
6499 TOOL_CTRL_ID_YES, "yes"
6502 IMG_REQUEST_BUTTON_GFX_NO, &request.button.no,
6503 TOOL_CTRL_ID_NO, "no"
6506 IMG_REQUEST_BUTTON_GFX_CONFIRM, &request.button.confirm,
6507 TOOL_CTRL_ID_CONFIRM, "confirm"
6510 IMG_REQUEST_BUTTON_GFX_PLAYER_1, &request.button.player_1,
6511 TOOL_CTRL_ID_PLAYER_1, "player 1"
6514 IMG_REQUEST_BUTTON_GFX_PLAYER_2, &request.button.player_2,
6515 TOOL_CTRL_ID_PLAYER_2, "player 2"
6518 IMG_REQUEST_BUTTON_GFX_PLAYER_3, &request.button.player_3,
6519 TOOL_CTRL_ID_PLAYER_3, "player 3"
6522 IMG_REQUEST_BUTTON_GFX_PLAYER_4, &request.button.player_4,
6523 TOOL_CTRL_ID_PLAYER_4, "player 4"
6527 void CreateToolButtons()
6531 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
6533 struct GraphicInfo *gfx = &graphic_info[toolbutton_info[i].graphic];
6534 struct TextPosInfo *pos = toolbutton_info[i].pos;
6535 struct GadgetInfo *gi;
6536 Bitmap *deco_bitmap = None;
6537 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
6538 unsigned int event_mask = GD_EVENT_RELEASED;
6541 int gd_x = gfx->src_x;
6542 int gd_y = gfx->src_y;
6543 int gd_xp = gfx->src_x + gfx->pressed_xoffset;
6544 int gd_yp = gfx->src_y + gfx->pressed_yoffset;
6547 if (global.use_envelope_request)
6548 setRequestPosition(&dx, &dy, TRUE);
6550 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
6552 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
6554 getSizedGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr), 0,
6555 pos->size, &deco_bitmap, &deco_x, &deco_y);
6556 deco_xpos = (gfx->width - pos->size) / 2;
6557 deco_ypos = (gfx->height - pos->size) / 2;
6560 gi = CreateGadget(GDI_CUSTOM_ID, id,
6561 GDI_INFO_TEXT, toolbutton_info[i].infotext,
6564 GDI_WIDTH, gfx->width,
6565 GDI_HEIGHT, gfx->height,
6566 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
6567 GDI_STATE, GD_BUTTON_UNPRESSED,
6568 GDI_DESIGN_UNPRESSED, gfx->bitmap, gd_x, gd_y,
6569 GDI_DESIGN_PRESSED, gfx->bitmap, gd_xp, gd_yp,
6570 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
6571 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
6572 GDI_DECORATION_SIZE, pos->size, pos->size,
6573 GDI_DECORATION_SHIFTING, 1, 1,
6574 GDI_DIRECT_DRAW, FALSE,
6575 GDI_EVENT_MASK, event_mask,
6576 GDI_CALLBACK_ACTION, HandleToolButtons,
6580 Error(ERR_EXIT, "cannot create gadget");
6582 tool_gadget[id] = gi;
6588 /* graphic position values for tool buttons */
6589 #define TOOL_BUTTON_YES_XPOS 2
6590 #define TOOL_BUTTON_YES_YPOS 250
6591 #define TOOL_BUTTON_YES_GFX_YPOS 0
6592 #define TOOL_BUTTON_YES_XSIZE 46
6593 #define TOOL_BUTTON_YES_YSIZE 28
6594 #define TOOL_BUTTON_NO_XPOS 52
6595 #define TOOL_BUTTON_NO_YPOS TOOL_BUTTON_YES_YPOS
6596 #define TOOL_BUTTON_NO_GFX_YPOS TOOL_BUTTON_YES_GFX_YPOS
6597 #define TOOL_BUTTON_NO_XSIZE TOOL_BUTTON_YES_XSIZE
6598 #define TOOL_BUTTON_NO_YSIZE TOOL_BUTTON_YES_YSIZE
6599 #define TOOL_BUTTON_CONFIRM_XPOS TOOL_BUTTON_YES_XPOS
6600 #define TOOL_BUTTON_CONFIRM_YPOS TOOL_BUTTON_YES_YPOS
6601 #define TOOL_BUTTON_CONFIRM_GFX_YPOS 30
6602 #define TOOL_BUTTON_CONFIRM_XSIZE 96
6603 #define TOOL_BUTTON_CONFIRM_YSIZE TOOL_BUTTON_YES_YSIZE
6604 #define TOOL_BUTTON_PLAYER_XSIZE 30
6605 #define TOOL_BUTTON_PLAYER_YSIZE 30
6606 #define TOOL_BUTTON_PLAYER_GFX_XPOS 5
6607 #define TOOL_BUTTON_PLAYER_GFX_YPOS 185
6608 #define TOOL_BUTTON_PLAYER_XPOS (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
6609 #define TOOL_BUTTON_PLAYER_YPOS (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
6610 #define TOOL_BUTTON_PLAYER1_XPOS (TOOL_BUTTON_PLAYER_XPOS \
6611 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
6612 #define TOOL_BUTTON_PLAYER2_XPOS (TOOL_BUTTON_PLAYER_XPOS \
6613 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
6614 #define TOOL_BUTTON_PLAYER3_XPOS (TOOL_BUTTON_PLAYER_XPOS \
6615 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
6616 #define TOOL_BUTTON_PLAYER4_XPOS (TOOL_BUTTON_PLAYER_XPOS \
6617 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
6618 #define TOOL_BUTTON_PLAYER1_YPOS (TOOL_BUTTON_PLAYER_YPOS \
6619 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
6620 #define TOOL_BUTTON_PLAYER2_YPOS (TOOL_BUTTON_PLAYER_YPOS \
6621 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
6622 #define TOOL_BUTTON_PLAYER3_YPOS (TOOL_BUTTON_PLAYER_YPOS \
6623 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
6624 #define TOOL_BUTTON_PLAYER4_YPOS (TOOL_BUTTON_PLAYER_YPOS \
6625 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
6634 } toolbutton_info[NUM_TOOL_BUTTONS] =
6637 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_GFX_YPOS,
6638 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_YPOS,
6639 TOOL_BUTTON_YES_XSIZE, TOOL_BUTTON_YES_YSIZE,
6644 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_GFX_YPOS,
6645 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_YPOS,
6646 TOOL_BUTTON_NO_XSIZE, TOOL_BUTTON_NO_YSIZE,
6651 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_GFX_YPOS,
6652 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_YPOS,
6653 TOOL_BUTTON_CONFIRM_XSIZE, TOOL_BUTTON_CONFIRM_YSIZE,
6654 TOOL_CTRL_ID_CONFIRM,
6658 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
6659 TOOL_BUTTON_PLAYER1_XPOS, TOOL_BUTTON_PLAYER1_YPOS,
6660 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
6661 TOOL_CTRL_ID_PLAYER_1,
6665 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
6666 TOOL_BUTTON_PLAYER2_XPOS, TOOL_BUTTON_PLAYER2_YPOS,
6667 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
6668 TOOL_CTRL_ID_PLAYER_2,
6672 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
6673 TOOL_BUTTON_PLAYER3_XPOS, TOOL_BUTTON_PLAYER3_YPOS,
6674 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
6675 TOOL_CTRL_ID_PLAYER_3,
6679 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
6680 TOOL_BUTTON_PLAYER4_XPOS, TOOL_BUTTON_PLAYER4_YPOS,
6681 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
6682 TOOL_CTRL_ID_PLAYER_4,
6687 void CreateToolButtons()
6691 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
6693 Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
6694 Bitmap *deco_bitmap = None;
6695 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
6696 struct GadgetInfo *gi;
6697 unsigned int event_mask;
6698 int gd_xoffset, gd_yoffset;
6699 int gd_x1, gd_x2, gd_y;
6702 event_mask = GD_EVENT_RELEASED;
6704 gd_xoffset = toolbutton_info[i].xpos;
6705 gd_yoffset = toolbutton_info[i].ypos;
6706 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
6707 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
6708 gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
6710 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
6712 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
6714 getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr),
6715 &deco_bitmap, &deco_x, &deco_y);
6716 deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
6717 deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
6720 gi = CreateGadget(GDI_CUSTOM_ID, id,
6721 GDI_INFO_TEXT, toolbutton_info[i].infotext,
6722 GDI_X, DX + toolbutton_info[i].x,
6723 GDI_Y, DY + toolbutton_info[i].y,
6724 GDI_WIDTH, toolbutton_info[i].width,
6725 GDI_HEIGHT, toolbutton_info[i].height,
6726 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
6727 GDI_STATE, GD_BUTTON_UNPRESSED,
6728 GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
6729 GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
6730 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
6731 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
6732 GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
6733 GDI_DECORATION_SHIFTING, 1, 1,
6734 GDI_DIRECT_DRAW, FALSE,
6735 GDI_EVENT_MASK, event_mask,
6736 GDI_CALLBACK_ACTION, HandleToolButtons,
6740 Error(ERR_EXIT, "cannot create gadget");
6742 tool_gadget[id] = gi;
6748 void FreeToolButtons()
6752 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
6753 FreeGadget(tool_gadget[i]);
6756 static void UnmapToolButtons()
6760 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
6761 UnmapGadget(tool_gadget[i]);
6764 static void HandleToolButtons(struct GadgetInfo *gi)
6766 request_gadget_id = gi->custom_id;
6769 static struct Mapping_EM_to_RND_object
6772 boolean is_rnd_to_em_mapping; /* unique mapping EM <-> RND */
6773 boolean is_backside; /* backside of moving element */
6779 em_object_mapping_list[] =
6782 Xblank, TRUE, FALSE,
6786 Yacid_splash_eB, FALSE, FALSE,
6787 EL_ACID_SPLASH_RIGHT, -1, -1
6790 Yacid_splash_wB, FALSE, FALSE,
6791 EL_ACID_SPLASH_LEFT, -1, -1
6794 #ifdef EM_ENGINE_BAD_ROLL
6796 Xstone_force_e, FALSE, FALSE,
6797 EL_ROCK, -1, MV_BIT_RIGHT
6800 Xstone_force_w, FALSE, FALSE,
6801 EL_ROCK, -1, MV_BIT_LEFT
6804 Xnut_force_e, FALSE, FALSE,
6805 EL_NUT, -1, MV_BIT_RIGHT
6808 Xnut_force_w, FALSE, FALSE,
6809 EL_NUT, -1, MV_BIT_LEFT
6812 Xspring_force_e, FALSE, FALSE,
6813 EL_SPRING, -1, MV_BIT_RIGHT
6816 Xspring_force_w, FALSE, FALSE,
6817 EL_SPRING, -1, MV_BIT_LEFT
6820 Xemerald_force_e, FALSE, FALSE,
6821 EL_EMERALD, -1, MV_BIT_RIGHT
6824 Xemerald_force_w, FALSE, FALSE,
6825 EL_EMERALD, -1, MV_BIT_LEFT
6828 Xdiamond_force_e, FALSE, FALSE,
6829 EL_DIAMOND, -1, MV_BIT_RIGHT
6832 Xdiamond_force_w, FALSE, FALSE,
6833 EL_DIAMOND, -1, MV_BIT_LEFT
6836 Xbomb_force_e, FALSE, FALSE,
6837 EL_BOMB, -1, MV_BIT_RIGHT
6840 Xbomb_force_w, FALSE, FALSE,
6841 EL_BOMB, -1, MV_BIT_LEFT
6843 #endif /* EM_ENGINE_BAD_ROLL */
6846 Xstone, TRUE, FALSE,
6850 Xstone_pause, FALSE, FALSE,
6854 Xstone_fall, FALSE, FALSE,
6858 Ystone_s, FALSE, FALSE,
6859 EL_ROCK, ACTION_FALLING, -1
6862 Ystone_sB, FALSE, TRUE,
6863 EL_ROCK, ACTION_FALLING, -1
6866 Ystone_e, FALSE, FALSE,
6867 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
6870 Ystone_eB, FALSE, TRUE,
6871 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
6874 Ystone_w, FALSE, FALSE,
6875 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
6878 Ystone_wB, FALSE, TRUE,
6879 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
6886 Xnut_pause, FALSE, FALSE,
6890 Xnut_fall, FALSE, FALSE,
6894 Ynut_s, FALSE, FALSE,
6895 EL_NUT, ACTION_FALLING, -1
6898 Ynut_sB, FALSE, TRUE,
6899 EL_NUT, ACTION_FALLING, -1
6902 Ynut_e, FALSE, FALSE,
6903 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
6906 Ynut_eB, FALSE, TRUE,
6907 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
6910 Ynut_w, FALSE, FALSE,
6911 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
6914 Ynut_wB, FALSE, TRUE,
6915 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
6918 Xbug_n, TRUE, FALSE,
6922 Xbug_e, TRUE, FALSE,
6923 EL_BUG_RIGHT, -1, -1
6926 Xbug_s, TRUE, FALSE,
6930 Xbug_w, TRUE, FALSE,
6934 Xbug_gon, FALSE, FALSE,
6938 Xbug_goe, FALSE, FALSE,
6939 EL_BUG_RIGHT, -1, -1
6942 Xbug_gos, FALSE, FALSE,
6946 Xbug_gow, FALSE, FALSE,
6950 Ybug_n, FALSE, FALSE,
6951 EL_BUG, ACTION_MOVING, MV_BIT_UP
6954 Ybug_nB, FALSE, TRUE,
6955 EL_BUG, ACTION_MOVING, MV_BIT_UP
6958 Ybug_e, FALSE, FALSE,
6959 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
6962 Ybug_eB, FALSE, TRUE,
6963 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
6966 Ybug_s, FALSE, FALSE,
6967 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
6970 Ybug_sB, FALSE, TRUE,
6971 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
6974 Ybug_w, FALSE, FALSE,
6975 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
6978 Ybug_wB, FALSE, TRUE,
6979 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
6982 Ybug_w_n, FALSE, FALSE,
6983 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
6986 Ybug_n_e, FALSE, FALSE,
6987 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
6990 Ybug_e_s, FALSE, FALSE,
6991 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
6994 Ybug_s_w, FALSE, FALSE,
6995 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
6998 Ybug_e_n, FALSE, FALSE,
6999 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
7002 Ybug_s_e, FALSE, FALSE,
7003 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
7006 Ybug_w_s, FALSE, FALSE,
7007 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
7010 Ybug_n_w, FALSE, FALSE,
7011 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
7014 Ybug_stone, FALSE, FALSE,
7015 EL_BUG, ACTION_SMASHED_BY_ROCK, -1
7018 Ybug_spring, FALSE, FALSE,
7019 EL_BUG, ACTION_SMASHED_BY_SPRING, -1
7022 Xtank_n, TRUE, FALSE,
7023 EL_SPACESHIP_UP, -1, -1
7026 Xtank_e, TRUE, FALSE,
7027 EL_SPACESHIP_RIGHT, -1, -1
7030 Xtank_s, TRUE, FALSE,
7031 EL_SPACESHIP_DOWN, -1, -1
7034 Xtank_w, TRUE, FALSE,
7035 EL_SPACESHIP_LEFT, -1, -1
7038 Xtank_gon, FALSE, FALSE,
7039 EL_SPACESHIP_UP, -1, -1
7042 Xtank_goe, FALSE, FALSE,
7043 EL_SPACESHIP_RIGHT, -1, -1
7046 Xtank_gos, FALSE, FALSE,
7047 EL_SPACESHIP_DOWN, -1, -1
7050 Xtank_gow, FALSE, FALSE,
7051 EL_SPACESHIP_LEFT, -1, -1
7054 Ytank_n, FALSE, FALSE,
7055 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
7058 Ytank_nB, FALSE, TRUE,
7059 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
7062 Ytank_e, FALSE, FALSE,
7063 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
7066 Ytank_eB, FALSE, TRUE,
7067 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
7070 Ytank_s, FALSE, FALSE,
7071 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
7074 Ytank_sB, FALSE, TRUE,
7075 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
7078 Ytank_w, FALSE, FALSE,
7079 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
7082 Ytank_wB, FALSE, TRUE,
7083 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
7086 Ytank_w_n, FALSE, FALSE,
7087 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
7090 Ytank_n_e, FALSE, FALSE,
7091 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
7094 Ytank_e_s, FALSE, FALSE,
7095 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
7098 Ytank_s_w, FALSE, FALSE,
7099 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
7102 Ytank_e_n, FALSE, FALSE,
7103 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
7106 Ytank_s_e, FALSE, FALSE,
7107 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
7110 Ytank_w_s, FALSE, FALSE,
7111 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
7114 Ytank_n_w, FALSE, FALSE,
7115 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
7118 Ytank_stone, FALSE, FALSE,
7119 EL_SPACESHIP, ACTION_SMASHED_BY_ROCK, -1
7122 Ytank_spring, FALSE, FALSE,
7123 EL_SPACESHIP, ACTION_SMASHED_BY_SPRING, -1
7126 Xandroid, TRUE, FALSE,
7127 EL_EMC_ANDROID, ACTION_ACTIVE, -1
7130 Xandroid_1_n, FALSE, FALSE,
7131 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
7134 Xandroid_2_n, FALSE, FALSE,
7135 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
7138 Xandroid_1_e, FALSE, FALSE,
7139 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
7142 Xandroid_2_e, FALSE, FALSE,
7143 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
7146 Xandroid_1_w, FALSE, FALSE,
7147 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
7150 Xandroid_2_w, FALSE, FALSE,
7151 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
7154 Xandroid_1_s, FALSE, FALSE,
7155 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
7158 Xandroid_2_s, FALSE, FALSE,
7159 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
7162 Yandroid_n, FALSE, FALSE,
7163 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
7166 Yandroid_nB, FALSE, TRUE,
7167 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
7170 Yandroid_ne, FALSE, FALSE,
7171 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPRIGHT
7174 Yandroid_neB, FALSE, TRUE,
7175 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPRIGHT
7178 Yandroid_e, FALSE, FALSE,
7179 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
7182 Yandroid_eB, FALSE, TRUE,
7183 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
7186 Yandroid_se, FALSE, FALSE,
7187 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNRIGHT
7190 Yandroid_seB, FALSE, TRUE,
7191 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNRIGHT
7194 Yandroid_s, FALSE, FALSE,
7195 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
7198 Yandroid_sB, FALSE, TRUE,
7199 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
7202 Yandroid_sw, FALSE, FALSE,
7203 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNLEFT
7206 Yandroid_swB, FALSE, TRUE,
7207 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNLEFT
7210 Yandroid_w, FALSE, FALSE,
7211 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
7214 Yandroid_wB, FALSE, TRUE,
7215 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
7218 Yandroid_nw, FALSE, FALSE,
7219 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPLEFT
7222 Yandroid_nwB, FALSE, TRUE,
7223 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPLEFT
7226 Xspring, TRUE, FALSE,
7230 Xspring_pause, FALSE, FALSE,
7234 Xspring_e, FALSE, FALSE,
7238 Xspring_w, FALSE, FALSE,
7242 Xspring_fall, FALSE, FALSE,
7246 Yspring_s, FALSE, FALSE,
7247 EL_SPRING, ACTION_FALLING, -1
7250 Yspring_sB, FALSE, TRUE,
7251 EL_SPRING, ACTION_FALLING, -1
7254 Yspring_e, FALSE, FALSE,
7255 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
7258 Yspring_eB, FALSE, TRUE,
7259 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
7262 Yspring_w, FALSE, FALSE,
7263 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
7266 Yspring_wB, FALSE, TRUE,
7267 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
7270 Yspring_kill_e, FALSE, FALSE,
7271 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
7274 Yspring_kill_eB, FALSE, TRUE,
7275 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
7278 Yspring_kill_w, FALSE, FALSE,
7279 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
7282 Yspring_kill_wB, FALSE, TRUE,
7283 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
7286 Xeater_n, TRUE, FALSE,
7287 EL_YAMYAM_UP, -1, -1
7290 Xeater_e, TRUE, FALSE,
7291 EL_YAMYAM_RIGHT, -1, -1
7294 Xeater_w, TRUE, FALSE,
7295 EL_YAMYAM_LEFT, -1, -1
7298 Xeater_s, TRUE, FALSE,
7299 EL_YAMYAM_DOWN, -1, -1
7302 Yeater_n, FALSE, FALSE,
7303 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
7306 Yeater_nB, FALSE, TRUE,
7307 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
7310 Yeater_e, FALSE, FALSE,
7311 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
7314 Yeater_eB, FALSE, TRUE,
7315 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
7318 Yeater_s, FALSE, FALSE,
7319 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
7322 Yeater_sB, FALSE, TRUE,
7323 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
7326 Yeater_w, FALSE, FALSE,
7327 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
7330 Yeater_wB, FALSE, TRUE,
7331 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
7334 Yeater_stone, FALSE, FALSE,
7335 EL_YAMYAM, ACTION_SMASHED_BY_ROCK, -1
7338 Yeater_spring, FALSE, FALSE,
7339 EL_YAMYAM, ACTION_SMASHED_BY_SPRING, -1
7342 Xalien, TRUE, FALSE,
7346 Xalien_pause, FALSE, FALSE,
7350 Yalien_n, FALSE, FALSE,
7351 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
7354 Yalien_nB, FALSE, TRUE,
7355 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
7358 Yalien_e, FALSE, FALSE,
7359 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
7362 Yalien_eB, FALSE, TRUE,
7363 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
7366 Yalien_s, FALSE, FALSE,
7367 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
7370 Yalien_sB, FALSE, TRUE,
7371 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
7374 Yalien_w, FALSE, FALSE,
7375 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
7378 Yalien_wB, FALSE, TRUE,
7379 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
7382 Yalien_stone, FALSE, FALSE,
7383 EL_ROBOT, ACTION_SMASHED_BY_ROCK, -1
7386 Yalien_spring, FALSE, FALSE,
7387 EL_ROBOT, ACTION_SMASHED_BY_SPRING, -1
7390 Xemerald, TRUE, FALSE,
7394 Xemerald_pause, FALSE, FALSE,
7398 Xemerald_fall, FALSE, FALSE,
7402 Xemerald_shine, FALSE, FALSE,
7403 EL_EMERALD, ACTION_TWINKLING, -1
7406 Yemerald_s, FALSE, FALSE,
7407 EL_EMERALD, ACTION_FALLING, -1
7410 Yemerald_sB, FALSE, TRUE,
7411 EL_EMERALD, ACTION_FALLING, -1
7414 Yemerald_e, FALSE, FALSE,
7415 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
7418 Yemerald_eB, FALSE, TRUE,
7419 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
7422 Yemerald_w, FALSE, FALSE,
7423 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
7426 Yemerald_wB, FALSE, TRUE,
7427 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
7430 Yemerald_eat, FALSE, FALSE,
7431 EL_EMERALD, ACTION_COLLECTING, -1
7434 Yemerald_stone, FALSE, FALSE,
7435 EL_NUT, ACTION_BREAKING, -1
7438 Xdiamond, TRUE, FALSE,
7442 Xdiamond_pause, FALSE, FALSE,
7446 Xdiamond_fall, FALSE, FALSE,
7450 Xdiamond_shine, FALSE, FALSE,
7451 EL_DIAMOND, ACTION_TWINKLING, -1
7454 Ydiamond_s, FALSE, FALSE,
7455 EL_DIAMOND, ACTION_FALLING, -1
7458 Ydiamond_sB, FALSE, TRUE,
7459 EL_DIAMOND, ACTION_FALLING, -1
7462 Ydiamond_e, FALSE, FALSE,
7463 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
7466 Ydiamond_eB, FALSE, TRUE,
7467 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
7470 Ydiamond_w, FALSE, FALSE,
7471 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
7474 Ydiamond_wB, FALSE, TRUE,
7475 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
7478 Ydiamond_eat, FALSE, FALSE,
7479 EL_DIAMOND, ACTION_COLLECTING, -1
7482 Ydiamond_stone, FALSE, FALSE,
7483 EL_DIAMOND, ACTION_SMASHED_BY_ROCK, -1
7486 Xdrip_fall, TRUE, FALSE,
7487 EL_AMOEBA_DROP, -1, -1
7490 Xdrip_stretch, FALSE, FALSE,
7491 EL_AMOEBA_DROP, ACTION_FALLING, -1
7494 Xdrip_stretchB, FALSE, TRUE,
7495 EL_AMOEBA_DROP, ACTION_FALLING, -1
7498 Xdrip_eat, FALSE, FALSE,
7499 EL_AMOEBA_DROP, ACTION_GROWING, -1
7502 Ydrip_s1, FALSE, FALSE,
7503 EL_AMOEBA_DROP, ACTION_FALLING, -1
7506 Ydrip_s1B, FALSE, TRUE,
7507 EL_AMOEBA_DROP, ACTION_FALLING, -1
7510 Ydrip_s2, FALSE, FALSE,
7511 EL_AMOEBA_DROP, ACTION_FALLING, -1
7514 Ydrip_s2B, FALSE, TRUE,
7515 EL_AMOEBA_DROP, ACTION_FALLING, -1
7522 Xbomb_pause, FALSE, FALSE,
7526 Xbomb_fall, FALSE, FALSE,
7530 Ybomb_s, FALSE, FALSE,
7531 EL_BOMB, ACTION_FALLING, -1
7534 Ybomb_sB, FALSE, TRUE,
7535 EL_BOMB, ACTION_FALLING, -1
7538 Ybomb_e, FALSE, FALSE,
7539 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
7542 Ybomb_eB, FALSE, TRUE,
7543 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
7546 Ybomb_w, FALSE, FALSE,
7547 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
7550 Ybomb_wB, FALSE, TRUE,
7551 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
7554 Ybomb_eat, FALSE, FALSE,
7555 EL_BOMB, ACTION_ACTIVATING, -1
7558 Xballoon, TRUE, FALSE,
7562 Yballoon_n, FALSE, FALSE,
7563 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
7566 Yballoon_nB, FALSE, TRUE,
7567 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
7570 Yballoon_e, FALSE, FALSE,
7571 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
7574 Yballoon_eB, FALSE, TRUE,
7575 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
7578 Yballoon_s, FALSE, FALSE,
7579 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
7582 Yballoon_sB, FALSE, TRUE,
7583 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
7586 Yballoon_w, FALSE, FALSE,
7587 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
7590 Yballoon_wB, FALSE, TRUE,
7591 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
7594 Xgrass, TRUE, FALSE,
7595 EL_EMC_GRASS, -1, -1
7598 Ygrass_nB, FALSE, FALSE,
7599 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_UP
7602 Ygrass_eB, FALSE, FALSE,
7603 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_RIGHT
7606 Ygrass_sB, FALSE, FALSE,
7607 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_DOWN
7610 Ygrass_wB, FALSE, FALSE,
7611 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_LEFT
7618 Ydirt_nB, FALSE, FALSE,
7619 EL_SAND, ACTION_DIGGING, MV_BIT_UP
7622 Ydirt_eB, FALSE, FALSE,
7623 EL_SAND, ACTION_DIGGING, MV_BIT_RIGHT
7626 Ydirt_sB, FALSE, FALSE,
7627 EL_SAND, ACTION_DIGGING, MV_BIT_DOWN
7630 Ydirt_wB, FALSE, FALSE,
7631 EL_SAND, ACTION_DIGGING, MV_BIT_LEFT
7634 Xacid_ne, TRUE, FALSE,
7635 EL_ACID_POOL_TOPRIGHT, -1, -1
7638 Xacid_se, TRUE, FALSE,
7639 EL_ACID_POOL_BOTTOMRIGHT, -1, -1
7642 Xacid_s, TRUE, FALSE,
7643 EL_ACID_POOL_BOTTOM, -1, -1
7646 Xacid_sw, TRUE, FALSE,
7647 EL_ACID_POOL_BOTTOMLEFT, -1, -1
7650 Xacid_nw, TRUE, FALSE,
7651 EL_ACID_POOL_TOPLEFT, -1, -1
7654 Xacid_1, TRUE, FALSE,
7658 Xacid_2, FALSE, FALSE,
7662 Xacid_3, FALSE, FALSE,
7666 Xacid_4, FALSE, FALSE,
7670 Xacid_5, FALSE, FALSE,
7674 Xacid_6, FALSE, FALSE,
7678 Xacid_7, FALSE, FALSE,
7682 Xacid_8, FALSE, FALSE,
7686 Xball_1, TRUE, FALSE,
7687 EL_EMC_MAGIC_BALL, -1, -1
7690 Xball_1B, FALSE, FALSE,
7691 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
7694 Xball_2, FALSE, FALSE,
7695 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
7698 Xball_2B, FALSE, FALSE,
7699 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
7702 Yball_eat, FALSE, FALSE,
7703 EL_EMC_MAGIC_BALL, ACTION_DROPPING, -1
7706 Ykey_1_eat, FALSE, FALSE,
7707 EL_EM_KEY_1, ACTION_COLLECTING, -1
7710 Ykey_2_eat, FALSE, FALSE,
7711 EL_EM_KEY_2, ACTION_COLLECTING, -1
7714 Ykey_3_eat, FALSE, FALSE,
7715 EL_EM_KEY_3, ACTION_COLLECTING, -1
7718 Ykey_4_eat, FALSE, FALSE,
7719 EL_EM_KEY_4, ACTION_COLLECTING, -1
7722 Ykey_5_eat, FALSE, FALSE,
7723 EL_EMC_KEY_5, ACTION_COLLECTING, -1
7726 Ykey_6_eat, FALSE, FALSE,
7727 EL_EMC_KEY_6, ACTION_COLLECTING, -1
7730 Ykey_7_eat, FALSE, FALSE,
7731 EL_EMC_KEY_7, ACTION_COLLECTING, -1
7734 Ykey_8_eat, FALSE, FALSE,
7735 EL_EMC_KEY_8, ACTION_COLLECTING, -1
7738 Ylenses_eat, FALSE, FALSE,
7739 EL_EMC_LENSES, ACTION_COLLECTING, -1
7742 Ymagnify_eat, FALSE, FALSE,
7743 EL_EMC_MAGNIFIER, ACTION_COLLECTING, -1
7746 Ygrass_eat, FALSE, FALSE,
7747 EL_EMC_GRASS, ACTION_SNAPPING, -1
7750 Ydirt_eat, FALSE, FALSE,
7751 EL_SAND, ACTION_SNAPPING, -1
7754 Xgrow_ns, TRUE, FALSE,
7755 EL_EXPANDABLE_WALL_VERTICAL, -1, -1
7758 Ygrow_ns_eat, FALSE, FALSE,
7759 EL_EXPANDABLE_WALL_VERTICAL, ACTION_GROWING, -1
7762 Xgrow_ew, TRUE, FALSE,
7763 EL_EXPANDABLE_WALL_HORIZONTAL, -1, -1
7766 Ygrow_ew_eat, FALSE, FALSE,
7767 EL_EXPANDABLE_WALL_HORIZONTAL, ACTION_GROWING, -1
7770 Xwonderwall, TRUE, FALSE,
7771 EL_MAGIC_WALL, -1, -1
7774 XwonderwallB, FALSE, FALSE,
7775 EL_MAGIC_WALL, ACTION_ACTIVE, -1
7778 Xamoeba_1, TRUE, FALSE,
7779 EL_AMOEBA_DRY, ACTION_OTHER, -1
7782 Xamoeba_2, FALSE, FALSE,
7783 EL_AMOEBA_DRY, ACTION_OTHER, -1
7786 Xamoeba_3, FALSE, FALSE,
7787 EL_AMOEBA_DRY, ACTION_OTHER, -1
7790 Xamoeba_4, FALSE, FALSE,
7791 EL_AMOEBA_DRY, ACTION_OTHER, -1
7794 Xamoeba_5, TRUE, FALSE,
7795 EL_AMOEBA_WET, ACTION_OTHER, -1
7798 Xamoeba_6, FALSE, FALSE,
7799 EL_AMOEBA_WET, ACTION_OTHER, -1
7802 Xamoeba_7, FALSE, FALSE,
7803 EL_AMOEBA_WET, ACTION_OTHER, -1
7806 Xamoeba_8, FALSE, FALSE,
7807 EL_AMOEBA_WET, ACTION_OTHER, -1
7810 Xdoor_1, TRUE, FALSE,
7811 EL_EM_GATE_1, -1, -1
7814 Xdoor_2, TRUE, FALSE,
7815 EL_EM_GATE_2, -1, -1
7818 Xdoor_3, TRUE, FALSE,
7819 EL_EM_GATE_3, -1, -1
7822 Xdoor_4, TRUE, FALSE,
7823 EL_EM_GATE_4, -1, -1
7826 Xdoor_5, TRUE, FALSE,
7827 EL_EMC_GATE_5, -1, -1
7830 Xdoor_6, TRUE, FALSE,
7831 EL_EMC_GATE_6, -1, -1
7834 Xdoor_7, TRUE, FALSE,
7835 EL_EMC_GATE_7, -1, -1
7838 Xdoor_8, TRUE, FALSE,
7839 EL_EMC_GATE_8, -1, -1
7842 Xkey_1, TRUE, FALSE,
7846 Xkey_2, TRUE, FALSE,
7850 Xkey_3, TRUE, FALSE,
7854 Xkey_4, TRUE, FALSE,
7858 Xkey_5, TRUE, FALSE,
7859 EL_EMC_KEY_5, -1, -1
7862 Xkey_6, TRUE, FALSE,
7863 EL_EMC_KEY_6, -1, -1
7866 Xkey_7, TRUE, FALSE,
7867 EL_EMC_KEY_7, -1, -1
7870 Xkey_8, TRUE, FALSE,
7871 EL_EMC_KEY_8, -1, -1
7874 Xwind_n, TRUE, FALSE,
7875 EL_BALLOON_SWITCH_UP, -1, -1
7878 Xwind_e, TRUE, FALSE,
7879 EL_BALLOON_SWITCH_RIGHT, -1, -1
7882 Xwind_s, TRUE, FALSE,
7883 EL_BALLOON_SWITCH_DOWN, -1, -1
7886 Xwind_w, TRUE, FALSE,
7887 EL_BALLOON_SWITCH_LEFT, -1, -1
7890 Xwind_nesw, TRUE, FALSE,
7891 EL_BALLOON_SWITCH_ANY, -1, -1
7894 Xwind_stop, TRUE, FALSE,
7895 EL_BALLOON_SWITCH_NONE, -1, -1
7899 EL_EM_EXIT_CLOSED, -1, -1
7902 Xexit_1, TRUE, FALSE,
7903 EL_EM_EXIT_OPEN, -1, -1
7906 Xexit_2, FALSE, FALSE,
7907 EL_EM_EXIT_OPEN, -1, -1
7910 Xexit_3, FALSE, FALSE,
7911 EL_EM_EXIT_OPEN, -1, -1
7914 Xdynamite, TRUE, FALSE,
7915 EL_EM_DYNAMITE, -1, -1
7918 Ydynamite_eat, FALSE, FALSE,
7919 EL_EM_DYNAMITE, ACTION_COLLECTING, -1
7922 Xdynamite_1, TRUE, FALSE,
7923 EL_EM_DYNAMITE_ACTIVE, -1, -1
7926 Xdynamite_2, FALSE, FALSE,
7927 EL_EM_DYNAMITE_ACTIVE, -1, -1
7930 Xdynamite_3, FALSE, FALSE,
7931 EL_EM_DYNAMITE_ACTIVE, -1, -1
7934 Xdynamite_4, FALSE, FALSE,
7935 EL_EM_DYNAMITE_ACTIVE, -1, -1
7938 Xbumper, TRUE, FALSE,
7939 EL_EMC_SPRING_BUMPER, -1, -1
7942 XbumperB, FALSE, FALSE,
7943 EL_EMC_SPRING_BUMPER, ACTION_ACTIVE, -1
7946 Xwheel, TRUE, FALSE,
7947 EL_ROBOT_WHEEL, -1, -1
7950 XwheelB, FALSE, FALSE,
7951 EL_ROBOT_WHEEL, ACTION_ACTIVE, -1
7954 Xswitch, TRUE, FALSE,
7955 EL_EMC_MAGIC_BALL_SWITCH, -1, -1
7958 XswitchB, FALSE, FALSE,
7959 EL_EMC_MAGIC_BALL_SWITCH, ACTION_ACTIVE, -1
7963 EL_QUICKSAND_EMPTY, -1, -1
7966 Xsand_stone, TRUE, FALSE,
7967 EL_QUICKSAND_FULL, -1, -1
7970 Xsand_stonein_1, FALSE, TRUE,
7971 EL_ROCK, ACTION_FILLING, -1
7974 Xsand_stonein_2, FALSE, TRUE,
7975 EL_ROCK, ACTION_FILLING, -1
7978 Xsand_stonein_3, FALSE, TRUE,
7979 EL_ROCK, ACTION_FILLING, -1
7982 Xsand_stonein_4, FALSE, TRUE,
7983 EL_ROCK, ACTION_FILLING, -1
7987 Xsand_stonesand_1, FALSE, FALSE,
7988 EL_QUICKSAND_EMPTYING, -1, -1
7991 Xsand_stonesand_2, FALSE, FALSE,
7992 EL_QUICKSAND_EMPTYING, -1, -1
7995 Xsand_stonesand_3, FALSE, FALSE,
7996 EL_QUICKSAND_EMPTYING, -1, -1
7999 Xsand_stonesand_4, FALSE, FALSE,
8000 EL_QUICKSAND_EMPTYING, -1, -1
8003 Xsand_stonesand_quickout_1, FALSE, FALSE,
8004 EL_QUICKSAND_EMPTYING, -1, -1
8007 Xsand_stonesand_quickout_2, FALSE, FALSE,
8008 EL_QUICKSAND_EMPTYING, -1, -1
8012 Xsand_stonesand_1, FALSE, FALSE,
8013 EL_QUICKSAND_FULL, -1, -1
8016 Xsand_stonesand_2, FALSE, FALSE,
8017 EL_QUICKSAND_FULL, -1, -1
8020 Xsand_stonesand_3, FALSE, FALSE,
8021 EL_QUICKSAND_FULL, -1, -1
8024 Xsand_stonesand_4, FALSE, FALSE,
8025 EL_QUICKSAND_FULL, -1, -1
8029 Xsand_stoneout_1, FALSE, FALSE,
8030 EL_ROCK, ACTION_EMPTYING, -1
8033 Xsand_stoneout_2, FALSE, FALSE,
8034 EL_ROCK, ACTION_EMPTYING, -1
8038 Xsand_sandstone_1, FALSE, FALSE,
8039 EL_QUICKSAND_FILLING, -1, -1
8042 Xsand_sandstone_2, FALSE, FALSE,
8043 EL_QUICKSAND_FILLING, -1, -1
8046 Xsand_sandstone_3, FALSE, FALSE,
8047 EL_QUICKSAND_FILLING, -1, -1
8050 Xsand_sandstone_4, FALSE, FALSE,
8051 EL_QUICKSAND_FILLING, -1, -1
8055 Xsand_sandstone_1, FALSE, FALSE,
8056 EL_QUICKSAND_FULL, -1, -1
8059 Xsand_sandstone_2, FALSE, FALSE,
8060 EL_QUICKSAND_FULL, -1, -1
8063 Xsand_sandstone_3, FALSE, FALSE,
8064 EL_QUICKSAND_FULL, -1, -1
8067 Xsand_sandstone_4, FALSE, FALSE,
8068 EL_QUICKSAND_FULL, -1, -1
8072 Xplant, TRUE, FALSE,
8073 EL_EMC_PLANT, -1, -1
8076 Yplant, FALSE, FALSE,
8077 EL_EMC_PLANT, -1, -1
8080 Xlenses, TRUE, FALSE,
8081 EL_EMC_LENSES, -1, -1
8084 Xmagnify, TRUE, FALSE,
8085 EL_EMC_MAGNIFIER, -1, -1
8088 Xdripper, TRUE, FALSE,
8089 EL_EMC_DRIPPER, -1, -1
8092 XdripperB, FALSE, FALSE,
8093 EL_EMC_DRIPPER, ACTION_ACTIVE, -1
8096 Xfake_blank, TRUE, FALSE,
8097 EL_INVISIBLE_WALL, -1, -1
8100 Xfake_blankB, FALSE, FALSE,
8101 EL_INVISIBLE_WALL, ACTION_ACTIVE, -1
8104 Xfake_grass, TRUE, FALSE,
8105 EL_EMC_FAKE_GRASS, -1, -1
8108 Xfake_grassB, FALSE, FALSE,
8109 EL_EMC_FAKE_GRASS, ACTION_ACTIVE, -1
8112 Xfake_door_1, TRUE, FALSE,
8113 EL_EM_GATE_1_GRAY, -1, -1
8116 Xfake_door_2, TRUE, FALSE,
8117 EL_EM_GATE_2_GRAY, -1, -1
8120 Xfake_door_3, TRUE, FALSE,
8121 EL_EM_GATE_3_GRAY, -1, -1
8124 Xfake_door_4, TRUE, FALSE,
8125 EL_EM_GATE_4_GRAY, -1, -1
8128 Xfake_door_5, TRUE, FALSE,
8129 EL_EMC_GATE_5_GRAY, -1, -1
8132 Xfake_door_6, TRUE, FALSE,
8133 EL_EMC_GATE_6_GRAY, -1, -1
8136 Xfake_door_7, TRUE, FALSE,
8137 EL_EMC_GATE_7_GRAY, -1, -1
8140 Xfake_door_8, TRUE, FALSE,
8141 EL_EMC_GATE_8_GRAY, -1, -1
8144 Xfake_acid_1, TRUE, FALSE,
8145 EL_EMC_FAKE_ACID, -1, -1
8148 Xfake_acid_2, FALSE, FALSE,
8149 EL_EMC_FAKE_ACID, -1, -1
8152 Xfake_acid_3, FALSE, FALSE,
8153 EL_EMC_FAKE_ACID, -1, -1
8156 Xfake_acid_4, FALSE, FALSE,
8157 EL_EMC_FAKE_ACID, -1, -1
8160 Xfake_acid_5, FALSE, FALSE,
8161 EL_EMC_FAKE_ACID, -1, -1
8164 Xfake_acid_6, FALSE, FALSE,
8165 EL_EMC_FAKE_ACID, -1, -1
8168 Xfake_acid_7, FALSE, FALSE,
8169 EL_EMC_FAKE_ACID, -1, -1
8172 Xfake_acid_8, FALSE, FALSE,
8173 EL_EMC_FAKE_ACID, -1, -1
8176 Xsteel_1, TRUE, FALSE,
8177 EL_STEELWALL, -1, -1
8180 Xsteel_2, TRUE, FALSE,
8181 EL_EMC_STEELWALL_2, -1, -1
8184 Xsteel_3, TRUE, FALSE,
8185 EL_EMC_STEELWALL_3, -1, -1
8188 Xsteel_4, TRUE, FALSE,
8189 EL_EMC_STEELWALL_4, -1, -1
8192 Xwall_1, TRUE, FALSE,
8196 Xwall_2, TRUE, FALSE,
8197 EL_EMC_WALL_14, -1, -1
8200 Xwall_3, TRUE, FALSE,
8201 EL_EMC_WALL_15, -1, -1
8204 Xwall_4, TRUE, FALSE,
8205 EL_EMC_WALL_16, -1, -1
8208 Xround_wall_1, TRUE, FALSE,
8209 EL_WALL_SLIPPERY, -1, -1
8212 Xround_wall_2, TRUE, FALSE,
8213 EL_EMC_WALL_SLIPPERY_2, -1, -1
8216 Xround_wall_3, TRUE, FALSE,
8217 EL_EMC_WALL_SLIPPERY_3, -1, -1
8220 Xround_wall_4, TRUE, FALSE,
8221 EL_EMC_WALL_SLIPPERY_4, -1, -1
8224 Xdecor_1, TRUE, FALSE,
8225 EL_EMC_WALL_8, -1, -1
8228 Xdecor_2, TRUE, FALSE,
8229 EL_EMC_WALL_6, -1, -1
8232 Xdecor_3, TRUE, FALSE,
8233 EL_EMC_WALL_4, -1, -1
8236 Xdecor_4, TRUE, FALSE,
8237 EL_EMC_WALL_7, -1, -1
8240 Xdecor_5, TRUE, FALSE,
8241 EL_EMC_WALL_5, -1, -1
8244 Xdecor_6, TRUE, FALSE,
8245 EL_EMC_WALL_9, -1, -1
8248 Xdecor_7, TRUE, FALSE,
8249 EL_EMC_WALL_10, -1, -1
8252 Xdecor_8, TRUE, FALSE,
8253 EL_EMC_WALL_1, -1, -1
8256 Xdecor_9, TRUE, FALSE,
8257 EL_EMC_WALL_2, -1, -1
8260 Xdecor_10, TRUE, FALSE,
8261 EL_EMC_WALL_3, -1, -1
8264 Xdecor_11, TRUE, FALSE,
8265 EL_EMC_WALL_11, -1, -1
8268 Xdecor_12, TRUE, FALSE,
8269 EL_EMC_WALL_12, -1, -1
8272 Xalpha_0, TRUE, FALSE,
8273 EL_CHAR('0'), -1, -1
8276 Xalpha_1, TRUE, FALSE,
8277 EL_CHAR('1'), -1, -1
8280 Xalpha_2, TRUE, FALSE,
8281 EL_CHAR('2'), -1, -1
8284 Xalpha_3, TRUE, FALSE,
8285 EL_CHAR('3'), -1, -1
8288 Xalpha_4, TRUE, FALSE,
8289 EL_CHAR('4'), -1, -1
8292 Xalpha_5, TRUE, FALSE,
8293 EL_CHAR('5'), -1, -1
8296 Xalpha_6, TRUE, FALSE,
8297 EL_CHAR('6'), -1, -1
8300 Xalpha_7, TRUE, FALSE,
8301 EL_CHAR('7'), -1, -1
8304 Xalpha_8, TRUE, FALSE,
8305 EL_CHAR('8'), -1, -1
8308 Xalpha_9, TRUE, FALSE,
8309 EL_CHAR('9'), -1, -1
8312 Xalpha_excla, TRUE, FALSE,
8313 EL_CHAR('!'), -1, -1
8316 Xalpha_quote, TRUE, FALSE,
8317 EL_CHAR('"'), -1, -1
8320 Xalpha_comma, TRUE, FALSE,
8321 EL_CHAR(','), -1, -1
8324 Xalpha_minus, TRUE, FALSE,
8325 EL_CHAR('-'), -1, -1
8328 Xalpha_perio, TRUE, FALSE,
8329 EL_CHAR('.'), -1, -1
8332 Xalpha_colon, TRUE, FALSE,
8333 EL_CHAR(':'), -1, -1
8336 Xalpha_quest, TRUE, FALSE,
8337 EL_CHAR('?'), -1, -1
8340 Xalpha_a, TRUE, FALSE,
8341 EL_CHAR('A'), -1, -1
8344 Xalpha_b, TRUE, FALSE,
8345 EL_CHAR('B'), -1, -1
8348 Xalpha_c, TRUE, FALSE,
8349 EL_CHAR('C'), -1, -1
8352 Xalpha_d, TRUE, FALSE,
8353 EL_CHAR('D'), -1, -1
8356 Xalpha_e, TRUE, FALSE,
8357 EL_CHAR('E'), -1, -1
8360 Xalpha_f, TRUE, FALSE,
8361 EL_CHAR('F'), -1, -1
8364 Xalpha_g, TRUE, FALSE,
8365 EL_CHAR('G'), -1, -1
8368 Xalpha_h, TRUE, FALSE,
8369 EL_CHAR('H'), -1, -1
8372 Xalpha_i, TRUE, FALSE,
8373 EL_CHAR('I'), -1, -1
8376 Xalpha_j, TRUE, FALSE,
8377 EL_CHAR('J'), -1, -1
8380 Xalpha_k, TRUE, FALSE,
8381 EL_CHAR('K'), -1, -1
8384 Xalpha_l, TRUE, FALSE,
8385 EL_CHAR('L'), -1, -1
8388 Xalpha_m, TRUE, FALSE,
8389 EL_CHAR('M'), -1, -1
8392 Xalpha_n, TRUE, FALSE,
8393 EL_CHAR('N'), -1, -1
8396 Xalpha_o, TRUE, FALSE,
8397 EL_CHAR('O'), -1, -1
8400 Xalpha_p, TRUE, FALSE,
8401 EL_CHAR('P'), -1, -1
8404 Xalpha_q, TRUE, FALSE,
8405 EL_CHAR('Q'), -1, -1
8408 Xalpha_r, TRUE, FALSE,
8409 EL_CHAR('R'), -1, -1
8412 Xalpha_s, TRUE, FALSE,
8413 EL_CHAR('S'), -1, -1
8416 Xalpha_t, TRUE, FALSE,
8417 EL_CHAR('T'), -1, -1
8420 Xalpha_u, TRUE, FALSE,
8421 EL_CHAR('U'), -1, -1
8424 Xalpha_v, TRUE, FALSE,
8425 EL_CHAR('V'), -1, -1
8428 Xalpha_w, TRUE, FALSE,
8429 EL_CHAR('W'), -1, -1
8432 Xalpha_x, TRUE, FALSE,
8433 EL_CHAR('X'), -1, -1
8436 Xalpha_y, TRUE, FALSE,
8437 EL_CHAR('Y'), -1, -1
8440 Xalpha_z, TRUE, FALSE,
8441 EL_CHAR('Z'), -1, -1
8444 Xalpha_arrow_e, TRUE, FALSE,
8445 EL_CHAR('>'), -1, -1
8448 Xalpha_arrow_w, TRUE, FALSE,
8449 EL_CHAR('<'), -1, -1
8452 Xalpha_copyr, TRUE, FALSE,
8453 EL_CHAR('©'), -1, -1
8457 Xboom_bug, FALSE, FALSE,
8458 EL_BUG, ACTION_EXPLODING, -1
8461 Xboom_bomb, FALSE, FALSE,
8462 EL_BOMB, ACTION_EXPLODING, -1
8465 Xboom_android, FALSE, FALSE,
8466 EL_EMC_ANDROID, ACTION_OTHER, -1
8469 Xboom_1, FALSE, FALSE,
8470 EL_DEFAULT, ACTION_EXPLODING, -1
8473 Xboom_2, FALSE, FALSE,
8474 EL_DEFAULT, ACTION_EXPLODING, -1
8477 Znormal, FALSE, FALSE,
8481 Zdynamite, FALSE, FALSE,
8485 Zplayer, FALSE, FALSE,
8489 ZBORDER, FALSE, FALSE,
8499 static struct Mapping_EM_to_RND_player
8508 em_player_mapping_list[] =
8512 EL_PLAYER_1, ACTION_MOVING, MV_BIT_UP,
8516 EL_PLAYER_1, ACTION_MOVING, MV_BIT_RIGHT,
8520 EL_PLAYER_1, ACTION_MOVING, MV_BIT_DOWN,
8524 EL_PLAYER_1, ACTION_MOVING, MV_BIT_LEFT,
8528 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_UP,
8532 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_RIGHT,
8536 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_DOWN,
8540 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_LEFT,
8544 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_UP,
8548 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_RIGHT,
8552 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_DOWN,
8556 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_LEFT,
8560 EL_PLAYER_2, ACTION_MOVING, MV_BIT_UP,
8564 EL_PLAYER_2, ACTION_MOVING, MV_BIT_RIGHT,
8568 EL_PLAYER_2, ACTION_MOVING, MV_BIT_DOWN,
8572 EL_PLAYER_2, ACTION_MOVING, MV_BIT_LEFT,
8576 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_UP,
8580 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_RIGHT,
8584 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_DOWN,
8588 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_LEFT,
8592 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_UP,
8596 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_RIGHT,
8600 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_DOWN,
8604 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_LEFT,
8608 EL_PLAYER_1, ACTION_DEFAULT, -1,
8612 EL_PLAYER_2, ACTION_DEFAULT, -1,
8616 EL_PLAYER_3, ACTION_MOVING, MV_BIT_UP,
8620 EL_PLAYER_3, ACTION_MOVING, MV_BIT_RIGHT,
8624 EL_PLAYER_3, ACTION_MOVING, MV_BIT_DOWN,
8628 EL_PLAYER_3, ACTION_MOVING, MV_BIT_LEFT,
8632 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_UP,
8636 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_RIGHT,
8640 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_DOWN,
8644 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_LEFT,
8648 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_UP,
8652 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_RIGHT,
8656 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_DOWN,
8660 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_LEFT,
8664 EL_PLAYER_4, ACTION_MOVING, MV_BIT_UP,
8668 EL_PLAYER_4, ACTION_MOVING, MV_BIT_RIGHT,
8672 EL_PLAYER_4, ACTION_MOVING, MV_BIT_DOWN,
8676 EL_PLAYER_4, ACTION_MOVING, MV_BIT_LEFT,
8680 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_UP,
8684 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_RIGHT,
8688 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_DOWN,
8692 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_LEFT,
8696 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_UP,
8700 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_RIGHT,
8704 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_DOWN,
8708 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_LEFT,
8712 EL_PLAYER_3, ACTION_DEFAULT, -1,
8716 EL_PLAYER_4, ACTION_DEFAULT, -1,
8725 int map_element_RND_to_EM(int element_rnd)
8727 static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
8728 static boolean mapping_initialized = FALSE;
8730 if (!mapping_initialized)
8734 /* return "Xalpha_quest" for all undefined elements in mapping array */
8735 for (i = 0; i < NUM_FILE_ELEMENTS; i++)
8736 mapping_RND_to_EM[i] = Xalpha_quest;
8738 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
8739 if (em_object_mapping_list[i].is_rnd_to_em_mapping)
8740 mapping_RND_to_EM[em_object_mapping_list[i].element_rnd] =
8741 em_object_mapping_list[i].element_em;
8743 mapping_initialized = TRUE;
8746 if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
8747 return mapping_RND_to_EM[element_rnd];
8749 Error(ERR_WARN, "invalid RND level element %d", element_rnd);
8754 int map_element_EM_to_RND(int element_em)
8756 static unsigned short mapping_EM_to_RND[TILE_MAX];
8757 static boolean mapping_initialized = FALSE;
8759 if (!mapping_initialized)
8763 /* return "EL_UNKNOWN" for all undefined elements in mapping array */
8764 for (i = 0; i < TILE_MAX; i++)
8765 mapping_EM_to_RND[i] = EL_UNKNOWN;
8767 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
8768 mapping_EM_to_RND[em_object_mapping_list[i].element_em] =
8769 em_object_mapping_list[i].element_rnd;
8771 mapping_initialized = TRUE;
8774 if (element_em >= 0 && element_em < TILE_MAX)
8775 return mapping_EM_to_RND[element_em];
8777 Error(ERR_WARN, "invalid EM level element %d", element_em);
8782 void map_android_clone_elements_RND_to_EM(struct LevelInfo *level)
8784 struct LevelInfo_EM *level_em = level->native_em_level;
8785 struct LEVEL *lev = level_em->lev;
8788 for (i = 0; i < TILE_MAX; i++)
8789 lev->android_array[i] = Xblank;
8791 for (i = 0; i < level->num_android_clone_elements; i++)
8793 int element_rnd = level->android_clone_element[i];
8794 int element_em = map_element_RND_to_EM(element_rnd);
8796 for (j = 0; em_object_mapping_list[j].element_em != -1; j++)
8797 if (em_object_mapping_list[j].element_rnd == element_rnd)
8798 lev->android_array[em_object_mapping_list[j].element_em] = element_em;
8802 void map_android_clone_elements_EM_to_RND(struct LevelInfo *level)
8804 struct LevelInfo_EM *level_em = level->native_em_level;
8805 struct LEVEL *lev = level_em->lev;
8808 level->num_android_clone_elements = 0;
8810 for (i = 0; i < TILE_MAX; i++)
8812 int element_em = lev->android_array[i];
8814 boolean element_found = FALSE;
8816 if (element_em == Xblank)
8819 element_rnd = map_element_EM_to_RND(element_em);
8821 for (j = 0; j < level->num_android_clone_elements; j++)
8822 if (level->android_clone_element[j] == element_rnd)
8823 element_found = TRUE;
8827 level->android_clone_element[level->num_android_clone_elements++] =
8830 if (level->num_android_clone_elements == MAX_ANDROID_ELEMENTS)
8835 if (level->num_android_clone_elements == 0)
8837 level->num_android_clone_elements = 1;
8838 level->android_clone_element[0] = EL_EMPTY;
8842 int map_direction_RND_to_EM(int direction)
8844 return (direction == MV_UP ? 0 :
8845 direction == MV_RIGHT ? 1 :
8846 direction == MV_DOWN ? 2 :
8847 direction == MV_LEFT ? 3 :
8851 int map_direction_EM_to_RND(int direction)
8853 return (direction == 0 ? MV_UP :
8854 direction == 1 ? MV_RIGHT :
8855 direction == 2 ? MV_DOWN :
8856 direction == 3 ? MV_LEFT :
8860 int map_element_RND_to_SP(int element_rnd)
8862 int element_sp = 0x20; /* map unknown elements to yellow "hardware" */
8864 if (element_rnd >= EL_SP_START &&
8865 element_rnd <= EL_SP_END)
8866 element_sp = element_rnd - EL_SP_START;
8867 else if (element_rnd == EL_EMPTY_SPACE)
8869 else if (element_rnd == EL_INVISIBLE_WALL)
8875 int map_element_SP_to_RND(int element_sp)
8877 int element_rnd = EL_UNKNOWN;
8879 if (element_sp >= 0x00 &&
8881 element_rnd = EL_SP_START + element_sp;
8882 else if (element_sp == 0x28)
8883 element_rnd = EL_INVISIBLE_WALL;
8888 int map_action_SP_to_RND(int action_sp)
8892 case actActive: return ACTION_ACTIVE;
8893 case actImpact: return ACTION_IMPACT;
8894 case actExploding: return ACTION_EXPLODING;
8895 case actDigging: return ACTION_DIGGING;
8896 case actSnapping: return ACTION_SNAPPING;
8897 case actCollecting: return ACTION_COLLECTING;
8898 case actPassing: return ACTION_PASSING;
8899 case actPushing: return ACTION_PUSHING;
8900 case actDropping: return ACTION_DROPPING;
8902 default: return ACTION_DEFAULT;
8906 int get_next_element(int element)
8910 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
8911 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
8912 case EL_QUICKSAND_FAST_FILLING: return EL_QUICKSAND_FAST_FULL;
8913 case EL_QUICKSAND_FAST_EMPTYING: return EL_QUICKSAND_FAST_EMPTY;
8914 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
8915 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
8916 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
8917 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
8918 case EL_DC_MAGIC_WALL_FILLING: return EL_DC_MAGIC_WALL_FULL;
8919 case EL_DC_MAGIC_WALL_EMPTYING: return EL_DC_MAGIC_WALL_ACTIVE;
8920 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
8922 default: return element;
8927 int el_act_dir2img(int element, int action, int direction)
8929 element = GFX_ELEMENT(element);
8931 if (direction == MV_NONE)
8932 return element_info[element].graphic[action];
8934 direction = MV_DIR_TO_BIT(direction);
8936 return element_info[element].direction_graphic[action][direction];
8939 int el_act_dir2img(int element, int action, int direction)
8941 element = GFX_ELEMENT(element);
8942 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
8944 /* direction_graphic[][] == graphic[] for undefined direction graphics */
8945 return element_info[element].direction_graphic[action][direction];
8950 static int el_act_dir2crm(int element, int action, int direction)
8952 element = GFX_ELEMENT(element);
8954 if (direction == MV_NONE)
8955 return element_info[element].crumbled[action];
8957 direction = MV_DIR_TO_BIT(direction);
8959 return element_info[element].direction_crumbled[action][direction];
8962 static int el_act_dir2crm(int element, int action, int direction)
8964 element = GFX_ELEMENT(element);
8965 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
8967 /* direction_graphic[][] == graphic[] for undefined direction graphics */
8968 return element_info[element].direction_crumbled[action][direction];
8972 int el_act2img(int element, int action)
8974 element = GFX_ELEMENT(element);
8976 return element_info[element].graphic[action];
8979 int el_act2crm(int element, int action)
8981 element = GFX_ELEMENT(element);
8983 return element_info[element].crumbled[action];
8986 int el_dir2img(int element, int direction)
8988 element = GFX_ELEMENT(element);
8990 return el_act_dir2img(element, ACTION_DEFAULT, direction);
8993 int el2baseimg(int element)
8995 return element_info[element].graphic[ACTION_DEFAULT];
8998 int el2img(int element)
9000 element = GFX_ELEMENT(element);
9002 return element_info[element].graphic[ACTION_DEFAULT];
9005 int el2edimg(int element)
9007 element = GFX_ELEMENT(element);
9009 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
9012 int el2preimg(int element)
9014 element = GFX_ELEMENT(element);
9016 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
9019 int el2panelimg(int element)
9021 element = GFX_ELEMENT(element);
9023 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PANEL];
9026 int font2baseimg(int font_nr)
9028 return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
9031 int getBeltNrFromBeltElement(int element)
9033 return (element < EL_CONVEYOR_BELT_2_LEFT ? 0 :
9034 element < EL_CONVEYOR_BELT_3_LEFT ? 1 :
9035 element < EL_CONVEYOR_BELT_4_LEFT ? 2 : 3);
9038 int getBeltNrFromBeltActiveElement(int element)
9040 return (element < EL_CONVEYOR_BELT_2_LEFT_ACTIVE ? 0 :
9041 element < EL_CONVEYOR_BELT_3_LEFT_ACTIVE ? 1 :
9042 element < EL_CONVEYOR_BELT_4_LEFT_ACTIVE ? 2 : 3);
9045 int getBeltNrFromBeltSwitchElement(int element)
9047 return (element < EL_CONVEYOR_BELT_2_SWITCH_LEFT ? 0 :
9048 element < EL_CONVEYOR_BELT_3_SWITCH_LEFT ? 1 :
9049 element < EL_CONVEYOR_BELT_4_SWITCH_LEFT ? 2 : 3);
9052 int getBeltDirNrFromBeltElement(int element)
9054 static int belt_base_element[4] =
9056 EL_CONVEYOR_BELT_1_LEFT,
9057 EL_CONVEYOR_BELT_2_LEFT,
9058 EL_CONVEYOR_BELT_3_LEFT,
9059 EL_CONVEYOR_BELT_4_LEFT
9062 int belt_nr = getBeltNrFromBeltElement(element);
9063 int belt_dir_nr = element - belt_base_element[belt_nr];
9065 return (belt_dir_nr % 3);
9068 int getBeltDirNrFromBeltSwitchElement(int element)
9070 static int belt_base_element[4] =
9072 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
9073 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
9074 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
9075 EL_CONVEYOR_BELT_4_SWITCH_LEFT
9078 int belt_nr = getBeltNrFromBeltSwitchElement(element);
9079 int belt_dir_nr = element - belt_base_element[belt_nr];
9081 return (belt_dir_nr % 3);
9084 int getBeltDirFromBeltElement(int element)
9086 static int belt_move_dir[3] =
9093 int belt_dir_nr = getBeltDirNrFromBeltElement(element);
9095 return belt_move_dir[belt_dir_nr];
9098 int getBeltDirFromBeltSwitchElement(int element)
9100 static int belt_move_dir[3] =
9107 int belt_dir_nr = getBeltDirNrFromBeltSwitchElement(element);
9109 return belt_move_dir[belt_dir_nr];
9112 int getBeltElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
9114 static int belt_base_element[4] =
9116 EL_CONVEYOR_BELT_1_LEFT,
9117 EL_CONVEYOR_BELT_2_LEFT,
9118 EL_CONVEYOR_BELT_3_LEFT,
9119 EL_CONVEYOR_BELT_4_LEFT
9122 return belt_base_element[belt_nr] + belt_dir_nr;
9125 int getBeltElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
9127 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
9129 return getBeltElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
9132 int getBeltSwitchElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
9134 static int belt_base_element[4] =
9136 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
9137 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
9138 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
9139 EL_CONVEYOR_BELT_4_SWITCH_LEFT
9142 return belt_base_element[belt_nr] + belt_dir_nr;
9145 int getBeltSwitchElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
9147 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
9149 return getBeltSwitchElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
9153 boolean getTeamMode_EM()
9155 return game.team_mode;
9158 int getNumActivePlayers_EM()
9161 int num_players = 0;
9165 return (setup.team_mode ? MAX_PLAYERS : 1);
9167 for (i = 0; i < MAX_PLAYERS; i++)
9168 if (tape.player_participates[i])
9171 return (num_players > 1 ? MAX_PLAYERS : 1);
9175 int num_players = 0;
9178 /* when recording game, activate all connected players */
9182 for (i = 0; i < MAX_PLAYERS; i++)
9183 if (tape.player_participates[i])
9191 int getGameFrameDelay_EM(int native_em_game_frame_delay)
9193 int game_frame_delay_value;
9195 game_frame_delay_value =
9196 (tape.playing && tape.fast_forward ? FfwdFrameDelay :
9197 GameFrameDelay == GAME_FRAME_DELAY ? native_em_game_frame_delay :
9200 if (tape.playing && tape.warp_forward && !tape.pausing)
9201 game_frame_delay_value = 0;
9203 return game_frame_delay_value;
9206 unsigned int InitRND(int seed)
9208 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
9209 return InitEngineRandom_EM(seed);
9210 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
9211 return InitEngineRandom_SP(seed);
9213 return InitEngineRandom_RND(seed);
9217 static struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
9218 static struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
9221 inline static int get_effective_element_EM(int tile, int frame_em)
9223 int element = object_mapping[tile].element_rnd;
9224 int action = object_mapping[tile].action;
9225 boolean is_backside = object_mapping[tile].is_backside;
9226 boolean action_removing = (action == ACTION_DIGGING ||
9227 action == ACTION_SNAPPING ||
9228 action == ACTION_COLLECTING);
9234 case Yacid_splash_eB:
9235 case Yacid_splash_wB:
9236 return (frame_em > 5 ? EL_EMPTY : element);
9240 case Ydiamond_stone:
9241 // if (!game.use_native_emc_graphics_engine)
9249 else /* frame_em == 7 */
9253 case Yacid_splash_eB:
9254 case Yacid_splash_wB:
9257 case Yemerald_stone:
9260 case Ydiamond_stone:
9264 case Xdrip_stretchB:
9283 case Xsand_stonein_1:
9284 case Xsand_stonein_2:
9285 case Xsand_stonein_3:
9286 case Xsand_stonein_4:
9290 return (is_backside || action_removing ? EL_EMPTY : element);
9295 inline static boolean check_linear_animation_EM(int tile)
9299 case Xsand_stonesand_1:
9300 case Xsand_stonesand_quickout_1:
9301 case Xsand_sandstone_1:
9302 case Xsand_stonein_1:
9303 case Xsand_stoneout_1:
9323 case Yacid_splash_eB:
9324 case Yacid_splash_wB:
9325 case Yemerald_stone:
9333 inline static void set_crumbled_graphics_EM(struct GraphicInfo_EM *g_em,
9334 boolean has_crumbled_graphics,
9335 int crumbled, int sync_frame)
9337 /* if element can be crumbled, but certain action graphics are just empty
9338 space (like instantly snapping sand to empty space in 1 frame), do not
9339 treat these empty space graphics as crumbled graphics in EMC engine */
9340 if (crumbled == IMG_EMPTY_SPACE)
9341 has_crumbled_graphics = FALSE;
9343 if (has_crumbled_graphics)
9345 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
9346 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
9347 g_crumbled->anim_delay,
9348 g_crumbled->anim_mode,
9349 g_crumbled->anim_start_frame,
9352 getGraphicSource(crumbled, frame_crumbled, &g_em->crumbled_bitmap,
9353 &g_em->crumbled_src_x, &g_em->crumbled_src_y);
9355 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
9357 g_em->has_crumbled_graphics = TRUE;
9361 g_em->crumbled_bitmap = NULL;
9362 g_em->crumbled_src_x = 0;
9363 g_em->crumbled_src_y = 0;
9364 g_em->crumbled_border_size = 0;
9366 g_em->has_crumbled_graphics = FALSE;
9370 void ResetGfxAnimation_EM(int x, int y, int tile)
9375 void SetGfxAnimation_EM(struct GraphicInfo_EM *g_em,
9376 int tile, int frame_em, int x, int y)
9378 int action = object_mapping[tile].action;
9380 int direction = object_mapping[tile].direction;
9381 int effective_element = get_effective_element_EM(tile, frame_em);
9382 int graphic = (direction == MV_NONE ?
9383 el_act2img(effective_element, action) :
9384 el_act_dir2img(effective_element, action, direction));
9385 struct GraphicInfo *g = &graphic_info[graphic];
9388 boolean action_removing = (action == ACTION_DIGGING ||
9389 action == ACTION_SNAPPING ||
9390 action == ACTION_COLLECTING);
9391 boolean action_moving = (action == ACTION_FALLING ||
9392 action == ACTION_MOVING ||
9393 action == ACTION_PUSHING ||
9394 action == ACTION_EATING ||
9395 action == ACTION_FILLING ||
9396 action == ACTION_EMPTYING);
9397 boolean action_falling = (action == ACTION_FALLING ||
9398 action == ACTION_FILLING ||
9399 action == ACTION_EMPTYING);
9401 /* special case: graphic uses "2nd movement tile" and has defined
9402 7 frames for movement animation (or less) => use default graphic
9403 for last (8th) frame which ends the movement animation */
9404 if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
9406 action = ACTION_DEFAULT; /* (keep action_* unchanged for now) */
9407 graphic = (direction == MV_NONE ?
9408 el_act2img(effective_element, action) :
9409 el_act_dir2img(effective_element, action, direction));
9411 g = &graphic_info[graphic];
9415 if (tile == Xsand_stonesand_1 ||
9416 tile == Xsand_stonesand_2 ||
9417 tile == Xsand_stonesand_3 ||
9418 tile == Xsand_stonesand_4)
9419 printf("::: 1: quicksand frame %d [%d]\n", GfxFrame[x][y], tile);
9423 if ((action_removing || check_linear_animation_EM(tile)) && frame_em == 0)
9427 // printf("::: resetting... [%d]\n", tile);
9430 if (action_removing || check_linear_animation_EM(tile))
9432 GfxFrame[x][y] = frame_em;
9434 // printf("::: resetting... [%d]\n", tile);
9437 else if (action_moving)
9439 boolean is_backside = object_mapping[tile].is_backside;
9443 int direction = object_mapping[tile].direction;
9444 int move_dir = (action_falling ? MV_DOWN : direction);
9449 /* !!! TEST !!! NEW !!! DOES NOT WORK RIGHT YET !!! */
9450 if (g->double_movement && frame_em == 0)
9454 // printf("::: resetting... [%d]\n", tile);
9458 if (move_dir == MV_LEFT)
9459 GfxFrame[x - 1][y] = GfxFrame[x][y];
9460 else if (move_dir == MV_RIGHT)
9461 GfxFrame[x + 1][y] = GfxFrame[x][y];
9462 else if (move_dir == MV_UP)
9463 GfxFrame[x][y - 1] = GfxFrame[x][y];
9464 else if (move_dir == MV_DOWN)
9465 GfxFrame[x][y + 1] = GfxFrame[x][y];
9472 /* special case: animation for Xsand_stonesand_quickout_1/2 twice as fast */
9473 if (tile == Xsand_stonesand_quickout_1 ||
9474 tile == Xsand_stonesand_quickout_2)
9479 if (tile == Xsand_stonesand_1 ||
9480 tile == Xsand_stonesand_2 ||
9481 tile == Xsand_stonesand_3 ||
9482 tile == Xsand_stonesand_4)
9483 printf("::: 2: quicksand frame %d [%d]\n", GfxFrame[x][y], tile);
9487 if (graphic_info[graphic].anim_global_sync)
9488 sync_frame = FrameCounter;
9489 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
9490 sync_frame = GfxFrame[x][y];
9492 sync_frame = 0; /* playfield border (pseudo steel) */
9494 SetRandomAnimationValue(x, y);
9496 int frame = getAnimationFrame(g->anim_frames,
9499 g->anim_start_frame,
9502 g_em->unique_identifier =
9503 (graphic << 16) | ((frame % 8) << 12) | (g_em->width << 6) | g_em->height;
9507 void getGraphicSourceObjectExt_EM(struct GraphicInfo_EM *g_em,
9508 int tile, int frame_em, int x, int y)
9510 int action = object_mapping[tile].action;
9511 int direction = object_mapping[tile].direction;
9512 boolean is_backside = object_mapping[tile].is_backside;
9513 int effective_element = get_effective_element_EM(tile, frame_em);
9515 int effective_action = action;
9517 int effective_action = (frame_em < 7 ? action : ACTION_DEFAULT);
9519 int graphic = (direction == MV_NONE ?
9520 el_act2img(effective_element, effective_action) :
9521 el_act_dir2img(effective_element, effective_action,
9523 int crumbled = (direction == MV_NONE ?
9524 el_act2crm(effective_element, effective_action) :
9525 el_act_dir2crm(effective_element, effective_action,
9527 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
9528 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
9529 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
9530 struct GraphicInfo *g = &graphic_info[graphic];
9532 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
9536 /* special case: graphic uses "2nd movement tile" and has defined
9537 7 frames for movement animation (or less) => use default graphic
9538 for last (8th) frame which ends the movement animation */
9539 if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
9541 effective_action = ACTION_DEFAULT;
9542 graphic = (direction == MV_NONE ?
9543 el_act2img(effective_element, effective_action) :
9544 el_act_dir2img(effective_element, effective_action,
9546 crumbled = (direction == MV_NONE ?
9547 el_act2crm(effective_element, effective_action) :
9548 el_act_dir2crm(effective_element, effective_action,
9551 g = &graphic_info[graphic];
9561 if (frame_em == 0) /* reset animation frame for certain elements */
9563 if (check_linear_animation_EM(tile))
9568 if (graphic_info[graphic].anim_global_sync)
9569 sync_frame = FrameCounter;
9570 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
9571 sync_frame = GfxFrame[x][y];
9573 sync_frame = 0; /* playfield border (pseudo steel) */
9575 SetRandomAnimationValue(x, y);
9580 int xxx_sync_frame = (i == Xdrip_stretch ? 7 :
9581 i == Xdrip_stretchB ? 7 :
9582 i == Ydrip_s2 ? j + 8 :
9583 i == Ydrip_s2B ? j + 8 :
9592 i == Xfake_acid_1 ? 0 :
9593 i == Xfake_acid_2 ? 10 :
9594 i == Xfake_acid_3 ? 20 :
9595 i == Xfake_acid_4 ? 30 :
9596 i == Xfake_acid_5 ? 40 :
9597 i == Xfake_acid_6 ? 50 :
9598 i == Xfake_acid_7 ? 60 :
9599 i == Xfake_acid_8 ? 70 :
9601 i == Xball_2B ? j + 8 :
9602 i == Yball_eat ? j + 1 :
9603 i == Ykey_1_eat ? j + 1 :
9604 i == Ykey_2_eat ? j + 1 :
9605 i == Ykey_3_eat ? j + 1 :
9606 i == Ykey_4_eat ? j + 1 :
9607 i == Ykey_5_eat ? j + 1 :
9608 i == Ykey_6_eat ? j + 1 :
9609 i == Ykey_7_eat ? j + 1 :
9610 i == Ykey_8_eat ? j + 1 :
9611 i == Ylenses_eat ? j + 1 :
9612 i == Ymagnify_eat ? j + 1 :
9613 i == Ygrass_eat ? j + 1 :
9614 i == Ydirt_eat ? j + 1 :
9615 i == Xamoeba_1 ? 0 :
9616 i == Xamoeba_2 ? 1 :
9617 i == Xamoeba_3 ? 2 :
9618 i == Xamoeba_4 ? 3 :
9619 i == Xamoeba_5 ? 0 :
9620 i == Xamoeba_6 ? 1 :
9621 i == Xamoeba_7 ? 2 :
9622 i == Xamoeba_8 ? 3 :
9623 i == Xexit_2 ? j + 8 :
9624 i == Xexit_3 ? j + 16 :
9625 i == Xdynamite_1 ? 0 :
9626 i == Xdynamite_2 ? 8 :
9627 i == Xdynamite_3 ? 16 :
9628 i == Xdynamite_4 ? 24 :
9629 i == Xsand_stonein_1 ? j + 1 :
9630 i == Xsand_stonein_2 ? j + 9 :
9631 i == Xsand_stonein_3 ? j + 17 :
9632 i == Xsand_stonein_4 ? j + 25 :
9633 i == Xsand_stoneout_1 && j == 0 ? 0 :
9634 i == Xsand_stoneout_1 && j == 1 ? 0 :
9635 i == Xsand_stoneout_1 && j == 2 ? 1 :
9636 i == Xsand_stoneout_1 && j == 3 ? 2 :
9637 i == Xsand_stoneout_1 && j == 4 ? 2 :
9638 i == Xsand_stoneout_1 && j == 5 ? 3 :
9639 i == Xsand_stoneout_1 && j == 6 ? 4 :
9640 i == Xsand_stoneout_1 && j == 7 ? 4 :
9641 i == Xsand_stoneout_2 && j == 0 ? 5 :
9642 i == Xsand_stoneout_2 && j == 1 ? 6 :
9643 i == Xsand_stoneout_2 && j == 2 ? 7 :
9644 i == Xsand_stoneout_2 && j == 3 ? 8 :
9645 i == Xsand_stoneout_2 && j == 4 ? 9 :
9646 i == Xsand_stoneout_2 && j == 5 ? 11 :
9647 i == Xsand_stoneout_2 && j == 6 ? 13 :
9648 i == Xsand_stoneout_2 && j == 7 ? 15 :
9649 i == Xboom_bug && j == 1 ? 2 :
9650 i == Xboom_bug && j == 2 ? 2 :
9651 i == Xboom_bug && j == 3 ? 4 :
9652 i == Xboom_bug && j == 4 ? 4 :
9653 i == Xboom_bug && j == 5 ? 2 :
9654 i == Xboom_bug && j == 6 ? 2 :
9655 i == Xboom_bug && j == 7 ? 0 :
9656 i == Xboom_bomb && j == 1 ? 2 :
9657 i == Xboom_bomb && j == 2 ? 2 :
9658 i == Xboom_bomb && j == 3 ? 4 :
9659 i == Xboom_bomb && j == 4 ? 4 :
9660 i == Xboom_bomb && j == 5 ? 2 :
9661 i == Xboom_bomb && j == 6 ? 2 :
9662 i == Xboom_bomb && j == 7 ? 0 :
9663 i == Xboom_android && j == 7 ? 6 :
9664 i == Xboom_1 && j == 1 ? 2 :
9665 i == Xboom_1 && j == 2 ? 2 :
9666 i == Xboom_1 && j == 3 ? 4 :
9667 i == Xboom_1 && j == 4 ? 4 :
9668 i == Xboom_1 && j == 5 ? 6 :
9669 i == Xboom_1 && j == 6 ? 6 :
9670 i == Xboom_1 && j == 7 ? 8 :
9671 i == Xboom_2 && j == 0 ? 8 :
9672 i == Xboom_2 && j == 1 ? 8 :
9673 i == Xboom_2 && j == 2 ? 10 :
9674 i == Xboom_2 && j == 3 ? 10 :
9675 i == Xboom_2 && j == 4 ? 10 :
9676 i == Xboom_2 && j == 5 ? 12 :
9677 i == Xboom_2 && j == 6 ? 12 :
9678 i == Xboom_2 && j == 7 ? 12 :
9680 special_animation && j == 4 ? 3 :
9681 effective_action != action ? 0 :
9687 int xxx_effective_action;
9688 int xxx_has_action_graphics;
9691 int element = object_mapping[i].element_rnd;
9692 int action = object_mapping[i].action;
9693 int direction = object_mapping[i].direction;
9694 boolean is_backside = object_mapping[i].is_backside;
9696 boolean action_removing = (action == ACTION_DIGGING ||
9697 action == ACTION_SNAPPING ||
9698 action == ACTION_COLLECTING);
9700 boolean action_exploding = ((action == ACTION_EXPLODING ||
9701 action == ACTION_SMASHED_BY_ROCK ||
9702 action == ACTION_SMASHED_BY_SPRING) &&
9703 element != EL_DIAMOND);
9704 boolean action_active = (action == ACTION_ACTIVE);
9705 boolean action_other = (action == ACTION_OTHER);
9709 int effective_element = get_effective_element_EM(i, j);
9711 int effective_element = (j > 5 && i == Yacid_splash_eB ? EL_EMPTY :
9712 j > 5 && i == Yacid_splash_wB ? EL_EMPTY :
9714 i == Xdrip_stretch ? element :
9715 i == Xdrip_stretchB ? element :
9716 i == Ydrip_s1 ? element :
9717 i == Ydrip_s1B ? element :
9718 i == Xball_1B ? element :
9719 i == Xball_2 ? element :
9720 i == Xball_2B ? element :
9721 i == Yball_eat ? element :
9722 i == Ykey_1_eat ? element :
9723 i == Ykey_2_eat ? element :
9724 i == Ykey_3_eat ? element :
9725 i == Ykey_4_eat ? element :
9726 i == Ykey_5_eat ? element :
9727 i == Ykey_6_eat ? element :
9728 i == Ykey_7_eat ? element :
9729 i == Ykey_8_eat ? element :
9730 i == Ylenses_eat ? element :
9731 i == Ymagnify_eat ? element :
9732 i == Ygrass_eat ? element :
9733 i == Ydirt_eat ? element :
9734 i == Yemerald_stone ? EL_EMERALD :
9735 i == Ydiamond_stone ? EL_ROCK :
9736 i == Xsand_stonein_1 ? element :
9737 i == Xsand_stonein_2 ? element :
9738 i == Xsand_stonein_3 ? element :
9739 i == Xsand_stonein_4 ? element :
9740 is_backside ? EL_EMPTY :
9741 action_removing ? EL_EMPTY :
9744 int effective_action = (j < 7 ? action :
9745 i == Xdrip_stretch ? action :
9746 i == Xdrip_stretchB ? action :
9747 i == Ydrip_s1 ? action :
9748 i == Ydrip_s1B ? action :
9749 i == Xball_1B ? action :
9750 i == Xball_2 ? action :
9751 i == Xball_2B ? action :
9752 i == Yball_eat ? action :
9753 i == Ykey_1_eat ? action :
9754 i == Ykey_2_eat ? action :
9755 i == Ykey_3_eat ? action :
9756 i == Ykey_4_eat ? action :
9757 i == Ykey_5_eat ? action :
9758 i == Ykey_6_eat ? action :
9759 i == Ykey_7_eat ? action :
9760 i == Ykey_8_eat ? action :
9761 i == Ylenses_eat ? action :
9762 i == Ymagnify_eat ? action :
9763 i == Ygrass_eat ? action :
9764 i == Ydirt_eat ? action :
9765 i == Xsand_stonein_1 ? action :
9766 i == Xsand_stonein_2 ? action :
9767 i == Xsand_stonein_3 ? action :
9768 i == Xsand_stonein_4 ? action :
9769 i == Xsand_stoneout_1 ? action :
9770 i == Xsand_stoneout_2 ? action :
9771 i == Xboom_android ? ACTION_EXPLODING :
9772 action_exploding ? ACTION_EXPLODING :
9773 action_active ? action :
9774 action_other ? action :
9776 int graphic = (el_act_dir2img(effective_element, effective_action,
9778 int crumbled = (el_act_dir2crm(effective_element, effective_action,
9780 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
9781 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
9782 boolean has_action_graphics = (graphic != base_graphic);
9783 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
9784 struct GraphicInfo *g = &graphic_info[graphic];
9786 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
9788 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
9791 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
9792 boolean special_animation = (action != ACTION_DEFAULT &&
9793 g->anim_frames == 3 &&
9794 g->anim_delay == 2 &&
9795 g->anim_mode & ANIM_LINEAR);
9796 xxx_sync_frame = (i == Xdrip_stretch ? 7 :
9797 i == Xdrip_stretchB ? 7 :
9798 i == Ydrip_s2 ? j + 8 :
9799 i == Ydrip_s2B ? j + 8 :
9808 i == Xfake_acid_1 ? 0 :
9809 i == Xfake_acid_2 ? 10 :
9810 i == Xfake_acid_3 ? 20 :
9811 i == Xfake_acid_4 ? 30 :
9812 i == Xfake_acid_5 ? 40 :
9813 i == Xfake_acid_6 ? 50 :
9814 i == Xfake_acid_7 ? 60 :
9815 i == Xfake_acid_8 ? 70 :
9817 i == Xball_2B ? j + 8 :
9818 i == Yball_eat ? j + 1 :
9819 i == Ykey_1_eat ? j + 1 :
9820 i == Ykey_2_eat ? j + 1 :
9821 i == Ykey_3_eat ? j + 1 :
9822 i == Ykey_4_eat ? j + 1 :
9823 i == Ykey_5_eat ? j + 1 :
9824 i == Ykey_6_eat ? j + 1 :
9825 i == Ykey_7_eat ? j + 1 :
9826 i == Ykey_8_eat ? j + 1 :
9827 i == Ylenses_eat ? j + 1 :
9828 i == Ymagnify_eat ? j + 1 :
9829 i == Ygrass_eat ? j + 1 :
9830 i == Ydirt_eat ? j + 1 :
9831 i == Xamoeba_1 ? 0 :
9832 i == Xamoeba_2 ? 1 :
9833 i == Xamoeba_3 ? 2 :
9834 i == Xamoeba_4 ? 3 :
9835 i == Xamoeba_5 ? 0 :
9836 i == Xamoeba_6 ? 1 :
9837 i == Xamoeba_7 ? 2 :
9838 i == Xamoeba_8 ? 3 :
9839 i == Xexit_2 ? j + 8 :
9840 i == Xexit_3 ? j + 16 :
9841 i == Xdynamite_1 ? 0 :
9842 i == Xdynamite_2 ? 8 :
9843 i == Xdynamite_3 ? 16 :
9844 i == Xdynamite_4 ? 24 :
9845 i == Xsand_stonein_1 ? j + 1 :
9846 i == Xsand_stonein_2 ? j + 9 :
9847 i == Xsand_stonein_3 ? j + 17 :
9848 i == Xsand_stonein_4 ? j + 25 :
9849 i == Xsand_stoneout_1 && j == 0 ? 0 :
9850 i == Xsand_stoneout_1 && j == 1 ? 0 :
9851 i == Xsand_stoneout_1 && j == 2 ? 1 :
9852 i == Xsand_stoneout_1 && j == 3 ? 2 :
9853 i == Xsand_stoneout_1 && j == 4 ? 2 :
9854 i == Xsand_stoneout_1 && j == 5 ? 3 :
9855 i == Xsand_stoneout_1 && j == 6 ? 4 :
9856 i == Xsand_stoneout_1 && j == 7 ? 4 :
9857 i == Xsand_stoneout_2 && j == 0 ? 5 :
9858 i == Xsand_stoneout_2 && j == 1 ? 6 :
9859 i == Xsand_stoneout_2 && j == 2 ? 7 :
9860 i == Xsand_stoneout_2 && j == 3 ? 8 :
9861 i == Xsand_stoneout_2 && j == 4 ? 9 :
9862 i == Xsand_stoneout_2 && j == 5 ? 11 :
9863 i == Xsand_stoneout_2 && j == 6 ? 13 :
9864 i == Xsand_stoneout_2 && j == 7 ? 15 :
9865 i == Xboom_bug && j == 1 ? 2 :
9866 i == Xboom_bug && j == 2 ? 2 :
9867 i == Xboom_bug && j == 3 ? 4 :
9868 i == Xboom_bug && j == 4 ? 4 :
9869 i == Xboom_bug && j == 5 ? 2 :
9870 i == Xboom_bug && j == 6 ? 2 :
9871 i == Xboom_bug && j == 7 ? 0 :
9872 i == Xboom_bomb && j == 1 ? 2 :
9873 i == Xboom_bomb && j == 2 ? 2 :
9874 i == Xboom_bomb && j == 3 ? 4 :
9875 i == Xboom_bomb && j == 4 ? 4 :
9876 i == Xboom_bomb && j == 5 ? 2 :
9877 i == Xboom_bomb && j == 6 ? 2 :
9878 i == Xboom_bomb && j == 7 ? 0 :
9879 i == Xboom_android && j == 7 ? 6 :
9880 i == Xboom_1 && j == 1 ? 2 :
9881 i == Xboom_1 && j == 2 ? 2 :
9882 i == Xboom_1 && j == 3 ? 4 :
9883 i == Xboom_1 && j == 4 ? 4 :
9884 i == Xboom_1 && j == 5 ? 6 :
9885 i == Xboom_1 && j == 6 ? 6 :
9886 i == Xboom_1 && j == 7 ? 8 :
9887 i == Xboom_2 && j == 0 ? 8 :
9888 i == Xboom_2 && j == 1 ? 8 :
9889 i == Xboom_2 && j == 2 ? 10 :
9890 i == Xboom_2 && j == 3 ? 10 :
9891 i == Xboom_2 && j == 4 ? 10 :
9892 i == Xboom_2 && j == 5 ? 12 :
9893 i == Xboom_2 && j == 6 ? 12 :
9894 i == Xboom_2 && j == 7 ? 12 :
9895 special_animation && j == 4 ? 3 :
9896 effective_action != action ? 0 :
9899 xxx_effective_action = effective_action;
9900 xxx_has_action_graphics = has_action_graphics;
9905 int frame = getAnimationFrame(g->anim_frames,
9908 g->anim_start_frame,
9922 int old_src_x = g_em->src_x;
9923 int old_src_y = g_em->src_y;
9927 getGraphicSourceExt(graphic, frame, &g_em->bitmap, &g_em->src_x, &g_em->src_y,
9928 g->double_movement && is_backside);
9930 getGraphicSourceExt(graphic, frame, &g_em->bitmap,
9931 &g_em->src_x, &g_em->src_y, FALSE);
9936 if (tile == Ydiamond_stone)
9937 printf("::: stone smashing diamond... %d: %d, %d, %d, %d, %d -> %d [%d, %d, %d, %d, %d, %d] [%d]\n",
9942 g->anim_start_frame,
9945 g_em->src_x, g_em->src_y,
9946 g_em->src_offset_x, g_em->src_offset_y,
9947 g_em->dst_offset_x, g_em->dst_offset_y,
9959 if (graphic == IMG_BUG_MOVING_RIGHT)
9960 printf("::: %d, %d, %d: %d, %d [%d, %d -> %d, %d]\n", graphic, x, y,
9961 g->double_movement, is_backside,
9962 old_src_x, old_src_y, g_em->src_x, g_em->src_y);
9970 g_em->src_offset_x = 0;
9971 g_em->src_offset_y = 0;
9972 g_em->dst_offset_x = 0;
9973 g_em->dst_offset_y = 0;
9974 g_em->width = TILEX;
9975 g_em->height = TILEY;
9977 g_em->preserve_background = FALSE;
9980 /* (updating the "crumbled" graphic definitions is probably not really needed,
9981 as animations for crumbled graphics can't be longer than one EMC cycle) */
9983 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
9988 g_em->crumbled_bitmap = NULL;
9989 g_em->crumbled_src_x = 0;
9990 g_em->crumbled_src_y = 0;
9992 g_em->has_crumbled_graphics = FALSE;
9994 if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
9996 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
9997 g_crumbled->anim_delay,
9998 g_crumbled->anim_mode,
9999 g_crumbled->anim_start_frame,
10002 getGraphicSource(crumbled, frame_crumbled, &g_em->crumbled_bitmap,
10003 &g_em->crumbled_src_x, &g_em->crumbled_src_y);
10005 g_em->has_crumbled_graphics = TRUE;
10011 int effective_action = xxx_effective_action;
10012 int has_action_graphics = xxx_has_action_graphics;
10014 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
10015 effective_action == ACTION_MOVING ||
10016 effective_action == ACTION_PUSHING ||
10017 effective_action == ACTION_EATING)) ||
10018 (!has_action_graphics && (effective_action == ACTION_FILLING ||
10019 effective_action == ACTION_EMPTYING)))
10022 (effective_action == ACTION_FALLING ||
10023 effective_action == ACTION_FILLING ||
10024 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
10025 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
10026 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
10027 int num_steps = (i == Ydrip_s1 ? 16 :
10028 i == Ydrip_s1B ? 16 :
10029 i == Ydrip_s2 ? 16 :
10030 i == Ydrip_s2B ? 16 :
10031 i == Xsand_stonein_1 ? 32 :
10032 i == Xsand_stonein_2 ? 32 :
10033 i == Xsand_stonein_3 ? 32 :
10034 i == Xsand_stonein_4 ? 32 :
10035 i == Xsand_stoneout_1 ? 16 :
10036 i == Xsand_stoneout_2 ? 16 : 8);
10037 int cx = ABS(dx) * (TILEX / num_steps);
10038 int cy = ABS(dy) * (TILEY / num_steps);
10039 int step_frame = (i == Ydrip_s2 ? j + 8 :
10040 i == Ydrip_s2B ? j + 8 :
10041 i == Xsand_stonein_2 ? j + 8 :
10042 i == Xsand_stonein_3 ? j + 16 :
10043 i == Xsand_stonein_4 ? j + 24 :
10044 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
10045 int step = (is_backside ? step_frame : num_steps - step_frame);
10047 if (is_backside) /* tile where movement starts */
10049 if (dx < 0 || dy < 0)
10051 g_em->src_offset_x = cx * step;
10052 g_em->src_offset_y = cy * step;
10056 g_em->dst_offset_x = cx * step;
10057 g_em->dst_offset_y = cy * step;
10060 else /* tile where movement ends */
10062 if (dx < 0 || dy < 0)
10064 g_em->dst_offset_x = cx * step;
10065 g_em->dst_offset_y = cy * step;
10069 g_em->src_offset_x = cx * step;
10070 g_em->src_offset_y = cy * step;
10074 g_em->width = TILEX - cx * step;
10075 g_em->height = TILEY - cy * step;
10078 /* create unique graphic identifier to decide if tile must be redrawn */
10079 /* bit 31 - 16 (16 bit): EM style graphic
10080 bit 15 - 12 ( 4 bit): EM style frame
10081 bit 11 - 6 ( 6 bit): graphic width
10082 bit 5 - 0 ( 6 bit): graphic height */
10083 g_em->unique_identifier =
10084 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
10090 void getGraphicSourcePlayerExt_EM(struct GraphicInfo_EM *g_em,
10091 int player_nr, int anim, int frame_em)
10093 int element = player_mapping[player_nr][anim].element_rnd;
10094 int action = player_mapping[player_nr][anim].action;
10095 int direction = player_mapping[player_nr][anim].direction;
10096 int graphic = (direction == MV_NONE ?
10097 el_act2img(element, action) :
10098 el_act_dir2img(element, action, direction));
10099 struct GraphicInfo *g = &graphic_info[graphic];
10102 InitPlayerGfxAnimation(&stored_player[player_nr], action, direction);
10104 stored_player[player_nr].StepFrame = frame_em;
10106 sync_frame = stored_player[player_nr].Frame;
10108 int frame = getAnimationFrame(g->anim_frames,
10111 g->anim_start_frame,
10114 getGraphicSourceExt(graphic, frame, &g_em->bitmap,
10115 &g_em->src_x, &g_em->src_y, FALSE);
10118 printf("::: %d: %d, %d [%d]\n",
10120 stored_player[player_nr].Frame,
10121 stored_player[player_nr].StepFrame,
10126 void InitGraphicInfo_EM(void)
10129 struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
10130 struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
10135 int num_em_gfx_errors = 0;
10137 if (graphic_info_em_object[0][0].bitmap == NULL)
10139 /* EM graphics not yet initialized in em_open_all() */
10144 printf("::: [4 errors can be ignored (1 x 'bomb', 3 x 'em_dynamite']\n");
10147 /* always start with reliable default values */
10148 for (i = 0; i < TILE_MAX; i++)
10150 object_mapping[i].element_rnd = EL_UNKNOWN;
10151 object_mapping[i].is_backside = FALSE;
10152 object_mapping[i].action = ACTION_DEFAULT;
10153 object_mapping[i].direction = MV_NONE;
10156 /* always start with reliable default values */
10157 for (p = 0; p < MAX_PLAYERS; p++)
10159 for (i = 0; i < SPR_MAX; i++)
10161 player_mapping[p][i].element_rnd = EL_UNKNOWN;
10162 player_mapping[p][i].action = ACTION_DEFAULT;
10163 player_mapping[p][i].direction = MV_NONE;
10167 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
10169 int e = em_object_mapping_list[i].element_em;
10171 object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd;
10172 object_mapping[e].is_backside = em_object_mapping_list[i].is_backside;
10174 if (em_object_mapping_list[i].action != -1)
10175 object_mapping[e].action = em_object_mapping_list[i].action;
10177 if (em_object_mapping_list[i].direction != -1)
10178 object_mapping[e].direction =
10179 MV_DIR_FROM_BIT(em_object_mapping_list[i].direction);
10182 for (i = 0; em_player_mapping_list[i].action_em != -1; i++)
10184 int a = em_player_mapping_list[i].action_em;
10185 int p = em_player_mapping_list[i].player_nr;
10187 player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd;
10189 if (em_player_mapping_list[i].action != -1)
10190 player_mapping[p][a].action = em_player_mapping_list[i].action;
10192 if (em_player_mapping_list[i].direction != -1)
10193 player_mapping[p][a].direction =
10194 MV_DIR_FROM_BIT(em_player_mapping_list[i].direction);
10197 for (i = 0; i < TILE_MAX; i++)
10199 int element = object_mapping[i].element_rnd;
10200 int action = object_mapping[i].action;
10201 int direction = object_mapping[i].direction;
10202 boolean is_backside = object_mapping[i].is_backside;
10204 boolean action_removing = (action == ACTION_DIGGING ||
10205 action == ACTION_SNAPPING ||
10206 action == ACTION_COLLECTING);
10208 boolean action_exploding = ((action == ACTION_EXPLODING ||
10209 action == ACTION_SMASHED_BY_ROCK ||
10210 action == ACTION_SMASHED_BY_SPRING) &&
10211 element != EL_DIAMOND);
10212 boolean action_active = (action == ACTION_ACTIVE);
10213 boolean action_other = (action == ACTION_OTHER);
10215 for (j = 0; j < 8; j++)
10218 int effective_element = get_effective_element_EM(i, j);
10220 int effective_element = (j > 5 && i == Yacid_splash_eB ? EL_EMPTY :
10221 j > 5 && i == Yacid_splash_wB ? EL_EMPTY :
10223 i == Xdrip_stretch ? element :
10224 i == Xdrip_stretchB ? element :
10225 i == Ydrip_s1 ? element :
10226 i == Ydrip_s1B ? element :
10227 i == Xball_1B ? element :
10228 i == Xball_2 ? element :
10229 i == Xball_2B ? element :
10230 i == Yball_eat ? element :
10231 i == Ykey_1_eat ? element :
10232 i == Ykey_2_eat ? element :
10233 i == Ykey_3_eat ? element :
10234 i == Ykey_4_eat ? element :
10235 i == Ykey_5_eat ? element :
10236 i == Ykey_6_eat ? element :
10237 i == Ykey_7_eat ? element :
10238 i == Ykey_8_eat ? element :
10239 i == Ylenses_eat ? element :
10240 i == Ymagnify_eat ? element :
10241 i == Ygrass_eat ? element :
10242 i == Ydirt_eat ? element :
10243 i == Yemerald_stone ? EL_EMERALD :
10244 i == Ydiamond_stone ? EL_ROCK :
10245 i == Xsand_stonein_1 ? element :
10246 i == Xsand_stonein_2 ? element :
10247 i == Xsand_stonein_3 ? element :
10248 i == Xsand_stonein_4 ? element :
10249 is_backside ? EL_EMPTY :
10250 action_removing ? EL_EMPTY :
10253 int effective_action = (j < 7 ? action :
10254 i == Xdrip_stretch ? action :
10255 i == Xdrip_stretchB ? action :
10256 i == Ydrip_s1 ? action :
10257 i == Ydrip_s1B ? action :
10258 i == Xball_1B ? action :
10259 i == Xball_2 ? action :
10260 i == Xball_2B ? action :
10261 i == Yball_eat ? action :
10262 i == Ykey_1_eat ? action :
10263 i == Ykey_2_eat ? action :
10264 i == Ykey_3_eat ? action :
10265 i == Ykey_4_eat ? action :
10266 i == Ykey_5_eat ? action :
10267 i == Ykey_6_eat ? action :
10268 i == Ykey_7_eat ? action :
10269 i == Ykey_8_eat ? action :
10270 i == Ylenses_eat ? action :
10271 i == Ymagnify_eat ? action :
10272 i == Ygrass_eat ? action :
10273 i == Ydirt_eat ? action :
10274 i == Xsand_stonein_1 ? action :
10275 i == Xsand_stonein_2 ? action :
10276 i == Xsand_stonein_3 ? action :
10277 i == Xsand_stonein_4 ? action :
10278 i == Xsand_stoneout_1 ? action :
10279 i == Xsand_stoneout_2 ? action :
10280 i == Xboom_android ? ACTION_EXPLODING :
10281 action_exploding ? ACTION_EXPLODING :
10282 action_active ? action :
10283 action_other ? action :
10285 int graphic = (el_act_dir2img(effective_element, effective_action,
10287 int crumbled = (el_act_dir2crm(effective_element, effective_action,
10289 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
10290 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
10291 boolean has_action_graphics = (graphic != base_graphic);
10292 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
10293 struct GraphicInfo *g = &graphic_info[graphic];
10295 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
10297 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
10298 Bitmap *src_bitmap;
10300 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
10301 boolean special_animation = (action != ACTION_DEFAULT &&
10302 g->anim_frames == 3 &&
10303 g->anim_delay == 2 &&
10304 g->anim_mode & ANIM_LINEAR);
10305 int sync_frame = (i == Xdrip_stretch ? 7 :
10306 i == Xdrip_stretchB ? 7 :
10307 i == Ydrip_s2 ? j + 8 :
10308 i == Ydrip_s2B ? j + 8 :
10310 i == Xacid_2 ? 10 :
10311 i == Xacid_3 ? 20 :
10312 i == Xacid_4 ? 30 :
10313 i == Xacid_5 ? 40 :
10314 i == Xacid_6 ? 50 :
10315 i == Xacid_7 ? 60 :
10316 i == Xacid_8 ? 70 :
10317 i == Xfake_acid_1 ? 0 :
10318 i == Xfake_acid_2 ? 10 :
10319 i == Xfake_acid_3 ? 20 :
10320 i == Xfake_acid_4 ? 30 :
10321 i == Xfake_acid_5 ? 40 :
10322 i == Xfake_acid_6 ? 50 :
10323 i == Xfake_acid_7 ? 60 :
10324 i == Xfake_acid_8 ? 70 :
10326 i == Xball_2B ? j + 8 :
10327 i == Yball_eat ? j + 1 :
10328 i == Ykey_1_eat ? j + 1 :
10329 i == Ykey_2_eat ? j + 1 :
10330 i == Ykey_3_eat ? j + 1 :
10331 i == Ykey_4_eat ? j + 1 :
10332 i == Ykey_5_eat ? j + 1 :
10333 i == Ykey_6_eat ? j + 1 :
10334 i == Ykey_7_eat ? j + 1 :
10335 i == Ykey_8_eat ? j + 1 :
10336 i == Ylenses_eat ? j + 1 :
10337 i == Ymagnify_eat ? j + 1 :
10338 i == Ygrass_eat ? j + 1 :
10339 i == Ydirt_eat ? j + 1 :
10340 i == Xamoeba_1 ? 0 :
10341 i == Xamoeba_2 ? 1 :
10342 i == Xamoeba_3 ? 2 :
10343 i == Xamoeba_4 ? 3 :
10344 i == Xamoeba_5 ? 0 :
10345 i == Xamoeba_6 ? 1 :
10346 i == Xamoeba_7 ? 2 :
10347 i == Xamoeba_8 ? 3 :
10348 i == Xexit_2 ? j + 8 :
10349 i == Xexit_3 ? j + 16 :
10350 i == Xdynamite_1 ? 0 :
10351 i == Xdynamite_2 ? 8 :
10352 i == Xdynamite_3 ? 16 :
10353 i == Xdynamite_4 ? 24 :
10354 i == Xsand_stonein_1 ? j + 1 :
10355 i == Xsand_stonein_2 ? j + 9 :
10356 i == Xsand_stonein_3 ? j + 17 :
10357 i == Xsand_stonein_4 ? j + 25 :
10358 i == Xsand_stoneout_1 && j == 0 ? 0 :
10359 i == Xsand_stoneout_1 && j == 1 ? 0 :
10360 i == Xsand_stoneout_1 && j == 2 ? 1 :
10361 i == Xsand_stoneout_1 && j == 3 ? 2 :
10362 i == Xsand_stoneout_1 && j == 4 ? 2 :
10363 i == Xsand_stoneout_1 && j == 5 ? 3 :
10364 i == Xsand_stoneout_1 && j == 6 ? 4 :
10365 i == Xsand_stoneout_1 && j == 7 ? 4 :
10366 i == Xsand_stoneout_2 && j == 0 ? 5 :
10367 i == Xsand_stoneout_2 && j == 1 ? 6 :
10368 i == Xsand_stoneout_2 && j == 2 ? 7 :
10369 i == Xsand_stoneout_2 && j == 3 ? 8 :
10370 i == Xsand_stoneout_2 && j == 4 ? 9 :
10371 i == Xsand_stoneout_2 && j == 5 ? 11 :
10372 i == Xsand_stoneout_2 && j == 6 ? 13 :
10373 i == Xsand_stoneout_2 && j == 7 ? 15 :
10374 i == Xboom_bug && j == 1 ? 2 :
10375 i == Xboom_bug && j == 2 ? 2 :
10376 i == Xboom_bug && j == 3 ? 4 :
10377 i == Xboom_bug && j == 4 ? 4 :
10378 i == Xboom_bug && j == 5 ? 2 :
10379 i == Xboom_bug && j == 6 ? 2 :
10380 i == Xboom_bug && j == 7 ? 0 :
10381 i == Xboom_bomb && j == 1 ? 2 :
10382 i == Xboom_bomb && j == 2 ? 2 :
10383 i == Xboom_bomb && j == 3 ? 4 :
10384 i == Xboom_bomb && j == 4 ? 4 :
10385 i == Xboom_bomb && j == 5 ? 2 :
10386 i == Xboom_bomb && j == 6 ? 2 :
10387 i == Xboom_bomb && j == 7 ? 0 :
10388 i == Xboom_android && j == 7 ? 6 :
10389 i == Xboom_1 && j == 1 ? 2 :
10390 i == Xboom_1 && j == 2 ? 2 :
10391 i == Xboom_1 && j == 3 ? 4 :
10392 i == Xboom_1 && j == 4 ? 4 :
10393 i == Xboom_1 && j == 5 ? 6 :
10394 i == Xboom_1 && j == 6 ? 6 :
10395 i == Xboom_1 && j == 7 ? 8 :
10396 i == Xboom_2 && j == 0 ? 8 :
10397 i == Xboom_2 && j == 1 ? 8 :
10398 i == Xboom_2 && j == 2 ? 10 :
10399 i == Xboom_2 && j == 3 ? 10 :
10400 i == Xboom_2 && j == 4 ? 10 :
10401 i == Xboom_2 && j == 5 ? 12 :
10402 i == Xboom_2 && j == 6 ? 12 :
10403 i == Xboom_2 && j == 7 ? 12 :
10404 special_animation && j == 4 ? 3 :
10405 effective_action != action ? 0 :
10409 Bitmap *debug_bitmap = g_em->bitmap;
10410 int debug_src_x = g_em->src_x;
10411 int debug_src_y = g_em->src_y;
10414 int frame = getAnimationFrame(g->anim_frames,
10417 g->anim_start_frame,
10420 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y,
10421 g->double_movement && is_backside);
10423 g_em->bitmap = src_bitmap;
10424 g_em->src_x = src_x;
10425 g_em->src_y = src_y;
10426 g_em->src_offset_x = 0;
10427 g_em->src_offset_y = 0;
10428 g_em->dst_offset_x = 0;
10429 g_em->dst_offset_y = 0;
10430 g_em->width = TILEX;
10431 g_em->height = TILEY;
10433 g_em->preserve_background = FALSE;
10436 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
10441 g_em->crumbled_bitmap = NULL;
10442 g_em->crumbled_src_x = 0;
10443 g_em->crumbled_src_y = 0;
10444 g_em->crumbled_border_size = 0;
10446 g_em->has_crumbled_graphics = FALSE;
10449 if (has_crumbled_graphics && crumbled == IMG_EMPTY_SPACE)
10450 printf("::: empty crumbled: %d [%s], %d, %d\n",
10451 effective_element, element_info[effective_element].token_name,
10452 effective_action, direction);
10455 /* if element can be crumbled, but certain action graphics are just empty
10456 space (like instantly snapping sand to empty space in 1 frame), do not
10457 treat these empty space graphics as crumbled graphics in EMC engine */
10458 if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
10460 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
10461 g_crumbled->anim_delay,
10462 g_crumbled->anim_mode,
10463 g_crumbled->anim_start_frame,
10466 getGraphicSource(crumbled, frame_crumbled, &src_bitmap, &src_x, &src_y);
10468 g_em->has_crumbled_graphics = TRUE;
10469 g_em->crumbled_bitmap = src_bitmap;
10470 g_em->crumbled_src_x = src_x;
10471 g_em->crumbled_src_y = src_y;
10472 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
10476 if (g_em == &graphic_info_em_object[207][0])
10477 printf("... %d, %d [%d, %d, %d, %d] [%d, %d, %d, %d, %d, %d => %d]\n",
10478 graphic_info_em_object[207][0].crumbled_src_x,
10479 graphic_info_em_object[207][0].crumbled_src_y,
10481 crumbled, frame, src_x, src_y,
10486 g->anim_start_frame,
10488 gfx.anim_random_frame,
10493 printf("::: EMC tile %d is crumbled\n", i);
10499 if (element == EL_ROCK &&
10500 effective_action == ACTION_FILLING)
10501 printf("::: has_action_graphics == %d\n", has_action_graphics);
10504 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
10505 effective_action == ACTION_MOVING ||
10506 effective_action == ACTION_PUSHING ||
10507 effective_action == ACTION_EATING)) ||
10508 (!has_action_graphics && (effective_action == ACTION_FILLING ||
10509 effective_action == ACTION_EMPTYING)))
10512 (effective_action == ACTION_FALLING ||
10513 effective_action == ACTION_FILLING ||
10514 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
10515 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
10516 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
10517 int num_steps = (i == Ydrip_s1 ? 16 :
10518 i == Ydrip_s1B ? 16 :
10519 i == Ydrip_s2 ? 16 :
10520 i == Ydrip_s2B ? 16 :
10521 i == Xsand_stonein_1 ? 32 :
10522 i == Xsand_stonein_2 ? 32 :
10523 i == Xsand_stonein_3 ? 32 :
10524 i == Xsand_stonein_4 ? 32 :
10525 i == Xsand_stoneout_1 ? 16 :
10526 i == Xsand_stoneout_2 ? 16 : 8);
10527 int cx = ABS(dx) * (TILEX / num_steps);
10528 int cy = ABS(dy) * (TILEY / num_steps);
10529 int step_frame = (i == Ydrip_s2 ? j + 8 :
10530 i == Ydrip_s2B ? j + 8 :
10531 i == Xsand_stonein_2 ? j + 8 :
10532 i == Xsand_stonein_3 ? j + 16 :
10533 i == Xsand_stonein_4 ? j + 24 :
10534 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
10535 int step = (is_backside ? step_frame : num_steps - step_frame);
10537 if (is_backside) /* tile where movement starts */
10539 if (dx < 0 || dy < 0)
10541 g_em->src_offset_x = cx * step;
10542 g_em->src_offset_y = cy * step;
10546 g_em->dst_offset_x = cx * step;
10547 g_em->dst_offset_y = cy * step;
10550 else /* tile where movement ends */
10552 if (dx < 0 || dy < 0)
10554 g_em->dst_offset_x = cx * step;
10555 g_em->dst_offset_y = cy * step;
10559 g_em->src_offset_x = cx * step;
10560 g_em->src_offset_y = cy * step;
10564 g_em->width = TILEX - cx * step;
10565 g_em->height = TILEY - cy * step;
10568 /* create unique graphic identifier to decide if tile must be redrawn */
10569 /* bit 31 - 16 (16 bit): EM style graphic
10570 bit 15 - 12 ( 4 bit): EM style frame
10571 bit 11 - 6 ( 6 bit): graphic width
10572 bit 5 - 0 ( 6 bit): graphic height */
10573 g_em->unique_identifier =
10574 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
10578 /* skip check for EMC elements not contained in original EMC artwork */
10579 if (element == EL_EMC_FAKE_ACID)
10582 if (g_em->bitmap != debug_bitmap ||
10583 g_em->src_x != debug_src_x ||
10584 g_em->src_y != debug_src_y ||
10585 g_em->src_offset_x != 0 ||
10586 g_em->src_offset_y != 0 ||
10587 g_em->dst_offset_x != 0 ||
10588 g_em->dst_offset_y != 0 ||
10589 g_em->width != TILEX ||
10590 g_em->height != TILEY)
10592 static int last_i = -1;
10600 printf("::: EMC GFX ERROR for element %d -> %d ('%s', '%s', %d)",
10601 i, element, element_info[element].token_name,
10602 element_action_info[effective_action].suffix, direction);
10604 if (element != effective_element)
10605 printf(" [%d ('%s')]",
10607 element_info[effective_element].token_name);
10611 if (g_em->bitmap != debug_bitmap)
10612 printf(" %d (%d): different bitmap! (0x%08x != 0x%08x)\n",
10613 j, is_backside, (int)(g_em->bitmap), (int)(debug_bitmap));
10615 if (g_em->src_x != debug_src_x ||
10616 g_em->src_y != debug_src_y)
10617 printf(" frame %d (%c): %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
10618 j, (is_backside ? 'B' : 'F'),
10619 g_em->src_x, g_em->src_y,
10620 g_em->src_x / 32, g_em->src_y / 32,
10621 debug_src_x, debug_src_y,
10622 debug_src_x / 32, debug_src_y / 32);
10624 if (g_em->src_offset_x != 0 ||
10625 g_em->src_offset_y != 0 ||
10626 g_em->dst_offset_x != 0 ||
10627 g_em->dst_offset_y != 0)
10628 printf(" %d (%d): offsets %d,%d and %d,%d should be all 0\n",
10630 g_em->src_offset_x, g_em->src_offset_y,
10631 g_em->dst_offset_x, g_em->dst_offset_y);
10633 if (g_em->width != TILEX ||
10634 g_em->height != TILEY)
10635 printf(" %d (%d): size %d,%d should be %d,%d\n",
10637 g_em->width, g_em->height, TILEX, TILEY);
10639 num_em_gfx_errors++;
10646 for (i = 0; i < TILE_MAX; i++)
10648 for (j = 0; j < 8; j++)
10650 int element = object_mapping[i].element_rnd;
10651 int action = object_mapping[i].action;
10652 int direction = object_mapping[i].direction;
10653 boolean is_backside = object_mapping[i].is_backside;
10654 int graphic_action = el_act_dir2img(element, action, direction);
10655 int graphic_default = el_act_dir2img(element, ACTION_DEFAULT, direction);
10657 if ((action == ACTION_SMASHED_BY_ROCK ||
10658 action == ACTION_SMASHED_BY_SPRING ||
10659 action == ACTION_EATING) &&
10660 graphic_action == graphic_default)
10662 int e = (action == ACTION_SMASHED_BY_ROCK ? Ystone_s :
10663 action == ACTION_SMASHED_BY_SPRING ? Yspring_s :
10664 direction == MV_LEFT ? (is_backside? Yspring_wB: Yspring_w) :
10665 direction == MV_RIGHT ? (is_backside? Yspring_eB: Yspring_e) :
10668 /* no separate animation for "smashed by rock" -- use rock instead */
10669 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
10670 struct GraphicInfo_EM *g_xx = &graphic_info_em_object[e][7 - j];
10672 g_em->bitmap = g_xx->bitmap;
10673 g_em->src_x = g_xx->src_x;
10674 g_em->src_y = g_xx->src_y;
10675 g_em->src_offset_x = g_xx->src_offset_x;
10676 g_em->src_offset_y = g_xx->src_offset_y;
10677 g_em->dst_offset_x = g_xx->dst_offset_x;
10678 g_em->dst_offset_y = g_xx->dst_offset_y;
10679 g_em->width = g_xx->width;
10680 g_em->height = g_xx->height;
10681 g_em->unique_identifier = g_xx->unique_identifier;
10684 g_em->preserve_background = TRUE;
10689 for (p = 0; p < MAX_PLAYERS; p++)
10691 for (i = 0; i < SPR_MAX; i++)
10693 int element = player_mapping[p][i].element_rnd;
10694 int action = player_mapping[p][i].action;
10695 int direction = player_mapping[p][i].direction;
10697 for (j = 0; j < 8; j++)
10699 int effective_element = element;
10700 int effective_action = action;
10701 int graphic = (direction == MV_NONE ?
10702 el_act2img(effective_element, effective_action) :
10703 el_act_dir2img(effective_element, effective_action,
10705 struct GraphicInfo *g = &graphic_info[graphic];
10706 struct GraphicInfo_EM *g_em = &graphic_info_em_player[p][i][7 - j];
10707 Bitmap *src_bitmap;
10709 int sync_frame = j;
10712 Bitmap *debug_bitmap = g_em->bitmap;
10713 int debug_src_x = g_em->src_x;
10714 int debug_src_y = g_em->src_y;
10717 int frame = getAnimationFrame(g->anim_frames,
10720 g->anim_start_frame,
10723 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
10725 g_em->bitmap = src_bitmap;
10726 g_em->src_x = src_x;
10727 g_em->src_y = src_y;
10728 g_em->src_offset_x = 0;
10729 g_em->src_offset_y = 0;
10730 g_em->dst_offset_x = 0;
10731 g_em->dst_offset_y = 0;
10732 g_em->width = TILEX;
10733 g_em->height = TILEY;
10737 /* skip check for EMC elements not contained in original EMC artwork */
10738 if (element == EL_PLAYER_3 ||
10739 element == EL_PLAYER_4)
10742 if (g_em->bitmap != debug_bitmap ||
10743 g_em->src_x != debug_src_x ||
10744 g_em->src_y != debug_src_y)
10746 static int last_i = -1;
10754 printf("::: EMC GFX ERROR for p/a %d/%d -> %d ('%s', '%s', %d)",
10755 p, i, element, element_info[element].token_name,
10756 element_action_info[effective_action].suffix, direction);
10758 if (element != effective_element)
10759 printf(" [%d ('%s')]",
10761 element_info[effective_element].token_name);
10765 if (g_em->bitmap != debug_bitmap)
10766 printf(" %d: different bitmap! (0x%08x != 0x%08x)\n",
10767 j, (int)(g_em->bitmap), (int)(debug_bitmap));
10769 if (g_em->src_x != debug_src_x ||
10770 g_em->src_y != debug_src_y)
10771 printf(" frame %d: %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
10773 g_em->src_x, g_em->src_y,
10774 g_em->src_x / 32, g_em->src_y / 32,
10775 debug_src_x, debug_src_y,
10776 debug_src_x / 32, debug_src_y / 32);
10778 num_em_gfx_errors++;
10788 printf("::: [%d errors found]\n", num_em_gfx_errors);
10794 void CheckSingleStepMode_EM(byte action[MAX_PLAYERS], int frame,
10795 boolean any_player_moving,
10796 boolean player_is_dropping)
10798 if (tape.single_step && tape.recording && !tape.pausing)
10801 boolean active_players = FALSE;
10804 for (i = 0; i < MAX_PLAYERS; i++)
10805 if (action[i] != JOY_NO_ACTION)
10806 active_players = TRUE;
10810 if (frame == 0 && !player_is_dropping)
10811 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
10815 void CheckSingleStepMode_SP(boolean murphy_is_waiting,
10816 boolean murphy_is_dropping)
10819 printf("::: waiting: %d, dropping: %d\n",
10820 murphy_is_waiting, murphy_is_dropping);
10823 if (tape.single_step && tape.recording && !tape.pausing)
10825 // if (murphy_is_waiting || murphy_is_dropping)
10826 if (murphy_is_waiting)
10829 printf("::: murphy is waiting -> pause mode\n");
10832 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
10837 void getGraphicSource_SP(struct GraphicInfo_SP *g_sp,
10838 int graphic, int sync_frame, int x, int y)
10840 int frame = getGraphicAnimationFrame(graphic, sync_frame);
10842 getGraphicSource(graphic, frame, &g_sp->bitmap, &g_sp->src_x, &g_sp->src_y);
10845 boolean isNextAnimationFrame_SP(int graphic, int sync_frame)
10847 return (IS_NEXT_FRAME(sync_frame, graphic));
10850 int getGraphicInfo_Delay(int graphic)
10852 return graphic_info[graphic].anim_delay;
10855 void PlayMenuSoundExt(int sound)
10857 if (sound == SND_UNDEFINED)
10860 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
10861 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
10864 if (IS_LOOP_SOUND(sound))
10865 PlaySoundLoop(sound);
10870 void PlayMenuSound()
10872 PlayMenuSoundExt(menu.sound[game_status]);
10875 void PlayMenuSoundStereo(int sound, int stereo_position)
10877 if (sound == SND_UNDEFINED)
10880 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
10881 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
10884 if (IS_LOOP_SOUND(sound))
10885 PlaySoundExt(sound, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_LOOP);
10887 PlaySoundStereo(sound, stereo_position);
10890 void PlayMenuSoundIfLoopExt(int sound)
10892 if (sound == SND_UNDEFINED)
10895 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
10896 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
10899 if (IS_LOOP_SOUND(sound))
10900 PlaySoundLoop(sound);
10903 void PlayMenuSoundIfLoop()
10905 PlayMenuSoundIfLoopExt(menu.sound[game_status]);
10908 void PlayMenuMusicExt(int music)
10910 if (music == MUS_UNDEFINED)
10913 if (!setup.sound_music)
10919 void PlayMenuMusic()
10921 PlayMenuMusicExt(menu.music[game_status]);
10924 void PlaySoundActivating()
10927 PlaySound(SND_MENU_ITEM_ACTIVATING);
10931 void PlaySoundSelecting()
10934 PlaySound(SND_MENU_ITEM_SELECTING);
10938 void ToggleFullscreenOrChangeWindowScalingIfNeeded()
10940 boolean change_fullscreen = (setup.fullscreen !=
10941 video.fullscreen_enabled);
10942 boolean change_fullscreen_mode = (video.fullscreen_enabled &&
10943 !strEqual(setup.fullscreen_mode,
10944 video.fullscreen_mode_current));
10945 boolean change_window_scaling_percent = (!video.fullscreen_enabled &&
10946 setup.window_scaling_percent !=
10947 video.window_scaling_percent);
10949 if (change_window_scaling_percent && video.fullscreen_enabled)
10952 if (!change_window_scaling_percent && !video.fullscreen_available)
10955 #if defined(TARGET_SDL2)
10956 if (change_window_scaling_percent)
10958 SDLSetWindowScaling(setup.window_scaling_percent);
10962 else if (change_fullscreen)
10964 SDLSetWindowFullscreen(setup.fullscreen);
10966 /* set setup value according to successfully changed fullscreen mode */
10967 setup.fullscreen = video.fullscreen_enabled;
10973 if (change_fullscreen ||
10974 change_fullscreen_mode ||
10975 change_window_scaling_percent)
10977 Bitmap *tmp_backbuffer = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
10979 /* save backbuffer content which gets lost when toggling fullscreen mode */
10980 BlitBitmap(backbuffer, tmp_backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
10982 if (change_fullscreen_mode)
10984 /* keep fullscreen, but change fullscreen mode (screen resolution) */
10985 video.fullscreen_enabled = FALSE; /* force new fullscreen mode */
10988 if (change_window_scaling_percent)
10990 /* keep window mode, but change window scaling */
10991 video.fullscreen_enabled = TRUE; /* force new window scaling */
10994 /* toggle fullscreen */
10995 ChangeVideoModeIfNeeded(setup.fullscreen);
10997 /* set setup value according to successfully changed fullscreen mode */
10998 setup.fullscreen = video.fullscreen_enabled;
11000 /* restore backbuffer content from temporary backbuffer backup bitmap */
11001 BlitBitmap(tmp_backbuffer, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
11003 FreeBitmap(tmp_backbuffer);
11006 /* update visible window/screen */
11007 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
11009 redraw_mask = REDRAW_ALL;
11014 void ChangeViewportPropertiesIfNeeded()
11017 int *door_1_x = &DX;
11018 int *door_1_y = &DY;
11019 int *door_2_x = (game_status == GAME_MODE_EDITOR ? &EX : &VX);
11020 int *door_2_y = (game_status == GAME_MODE_EDITOR ? &EY : &VY);
11022 int gfx_game_mode = (game_status == GAME_MODE_PLAYING ||
11023 game_status == GAME_MODE_EDITOR ? game_status :
11025 int gfx_game_mode2 = (game_status == GAME_MODE_EDITOR ? GAME_MODE_DEFAULT :
11027 struct RectWithBorder *vp_playfield = &viewport.playfield[gfx_game_mode];
11028 struct RectWithBorder *vp_door_1 = &viewport.door_1[gfx_game_mode];
11029 struct RectWithBorder *vp_door_2 = &viewport.door_2[gfx_game_mode2];
11030 struct RectWithBorder *vp_door_3 = &viewport.door_2[GAME_MODE_EDITOR];
11031 int border_size = vp_playfield->border_size;
11032 int new_sx = vp_playfield->x + border_size;
11033 int new_sy = vp_playfield->y + border_size;
11034 int new_sxsize = vp_playfield->width - 2 * border_size;
11035 int new_sysize = vp_playfield->height - 2 * border_size;
11036 int new_real_sx = vp_playfield->x;
11037 int new_real_sy = vp_playfield->y;
11038 int new_full_sxsize = vp_playfield->width;
11039 int new_full_sysize = vp_playfield->height;
11040 int new_dx = vp_door_1->x;
11041 int new_dy = vp_door_1->y;
11042 int new_dxsize = vp_door_1->width;
11043 int new_dysize = vp_door_1->height;
11044 int new_vx = vp_door_2->x;
11045 int new_vy = vp_door_2->y;
11046 int new_vxsize = vp_door_2->width;
11047 int new_vysize = vp_door_2->height;
11048 int new_ex = vp_door_3->x;
11049 int new_ey = vp_door_3->y;
11050 int new_exsize = vp_door_3->width;
11051 int new_eysize = vp_door_3->height;
11053 int new_tilesize_var = TILESIZE / (setup.small_game_graphics ? 2 : 1);
11054 int tilesize = (gfx_game_mode == GAME_MODE_PLAYING ? new_tilesize_var :
11055 gfx_game_mode == GAME_MODE_EDITOR ? MINI_TILESIZE : TILESIZE);
11056 int new_scr_fieldx = new_sxsize / tilesize;
11057 int new_scr_fieldy = new_sysize / tilesize;
11058 int new_scr_fieldx_buffers = new_sxsize / new_tilesize_var;
11059 int new_scr_fieldy_buffers = new_sysize / new_tilesize_var;
11061 int new_scr_fieldx = (vp_playfield->width - 2 * border_size) / TILESIZE;
11062 int new_scr_fieldy = (vp_playfield->height - 2 * border_size) / TILESIZE;
11064 boolean init_gfx_buffers = FALSE;
11065 boolean init_video_buffer = FALSE;
11066 boolean init_gadgets_and_toons = FALSE;
11069 /* !!! TEST ONLY !!! */
11070 // InitGfxBuffers();
11074 if (viewport.window.width != WIN_XSIZE ||
11075 viewport.window.height != WIN_YSIZE)
11077 WIN_XSIZE = viewport.window.width;
11078 WIN_YSIZE = viewport.window.height;
11081 init_video_buffer = TRUE;
11082 init_gfx_buffers = TRUE;
11084 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
11088 SetDrawDeactivationMask(REDRAW_NONE);
11089 SetDrawBackgroundMask(REDRAW_FIELD);
11091 // RedrawBackground();
11095 // printf("::: video: init_video_buffer, init_gfx_buffers\n");
11098 if (new_scr_fieldx != SCR_FIELDX ||
11099 new_scr_fieldy != SCR_FIELDY)
11101 /* this always toggles between MAIN and GAME when using small tile size */
11103 SCR_FIELDX = new_scr_fieldx;
11104 SCR_FIELDY = new_scr_fieldy;
11106 // printf("::: new_scr_fieldx != SCR_FIELDX ...\n");
11110 if (new_tilesize_var != TILESIZE_VAR &&
11111 gfx_game_mode == GAME_MODE_PLAYING)
11113 /* doing this outside GAME_MODE_PLAYING would give wrong playfield size */
11115 TILESIZE_VAR = new_tilesize_var;
11117 init_gfx_buffers = TRUE;
11119 // printf("::: tilesize: init_gfx_buffers\n");
11123 if (new_sx != SX ||
11131 new_sxsize != SXSIZE ||
11132 new_sysize != SYSIZE ||
11133 new_dxsize != DXSIZE ||
11134 new_dysize != DYSIZE ||
11135 new_vxsize != VXSIZE ||
11136 new_vysize != VYSIZE ||
11137 new_exsize != EXSIZE ||
11138 new_eysize != EYSIZE ||
11139 new_real_sx != REAL_SX ||
11140 new_real_sy != REAL_SY ||
11141 new_full_sxsize != FULL_SXSIZE ||
11142 new_full_sysize != FULL_SYSIZE ||
11143 new_tilesize_var != TILESIZE_VAR
11146 vp_door_1->x != *door_1_x ||
11147 vp_door_1->y != *door_1_y ||
11148 vp_door_2->x != *door_2_x ||
11149 vp_door_2->y != *door_2_y
11161 SXSIZE = new_sxsize;
11162 SYSIZE = new_sysize;
11163 DXSIZE = new_dxsize;
11164 DYSIZE = new_dysize;
11165 VXSIZE = new_vxsize;
11166 VYSIZE = new_vysize;
11167 EXSIZE = new_exsize;
11168 EYSIZE = new_eysize;
11169 REAL_SX = new_real_sx;
11170 REAL_SY = new_real_sy;
11171 FULL_SXSIZE = new_full_sxsize;
11172 FULL_SYSIZE = new_full_sysize;
11173 TILESIZE_VAR = new_tilesize_var;
11176 printf("::: %d, %d, %d [%d]\n",
11177 SCR_FIELDX, SCR_FIELDY, TILESIZE_VAR,
11178 setup.small_game_graphics);
11182 *door_1_x = vp_door_1->x;
11183 *door_1_y = vp_door_1->y;
11184 *door_2_x = vp_door_2->x;
11185 *door_2_y = vp_door_2->y;
11189 init_gfx_buffers = TRUE;
11191 // printf("::: viewports: init_gfx_buffers\n");
11196 if (gfx_game_mode == GAME_MODE_MAIN)
11199 init_gadgets_and_toons = TRUE;
11201 // printf("::: viewports: init_gadgets_and_toons\n");
11209 if (init_gfx_buffers)
11211 // printf("::: init_gfx_buffers\n");
11213 SCR_FIELDX = new_scr_fieldx_buffers;
11214 SCR_FIELDY = new_scr_fieldy_buffers;
11218 SCR_FIELDX = new_scr_fieldx;
11219 SCR_FIELDY = new_scr_fieldy;
11222 if (init_video_buffer)
11224 // printf("::: init_video_buffer\n");
11226 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
11228 SetDrawDeactivationMask(REDRAW_NONE);
11229 SetDrawBackgroundMask(REDRAW_FIELD);
11232 if (init_gadgets_and_toons)
11234 // printf("::: init_gadgets_and_toons\n");
11241 printf("::: %d, %d / %d, %d [%d]\n", VX, VY, EX, EY, game_status);