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 ***********************************************************/
14 #include "libgame/libgame.h"
26 /* select level set with EMC X11 graphics before activating EM GFX debugging */
27 #define DEBUG_EM_GFX 0
29 /* tool button identifiers */
30 #define TOOL_CTRL_ID_YES 0
31 #define TOOL_CTRL_ID_NO 1
32 #define TOOL_CTRL_ID_CONFIRM 2
33 #define TOOL_CTRL_ID_PLAYER_1 3
34 #define TOOL_CTRL_ID_PLAYER_2 4
35 #define TOOL_CTRL_ID_PLAYER_3 5
36 #define TOOL_CTRL_ID_PLAYER_4 6
38 #define NUM_TOOL_BUTTONS 7
40 /* constants for number of doors and door parts */
42 #define MAX_NUM_DOOR_PARTS 8
45 struct DoorPartOrderInfo
51 static struct DoorPartOrderInfo door_part_order[NUM_DOORS * MAX_NUM_DOOR_PARTS];
53 struct DoorPartControlInfo
57 struct DoorPartPosInfo *pos;
60 static struct DoorPartControlInfo door_part_controls[] =
64 IMG_DOOR_1_GFX_PART_1,
69 IMG_DOOR_1_GFX_PART_2,
74 IMG_DOOR_1_GFX_PART_3,
79 IMG_DOOR_1_GFX_PART_4,
84 IMG_DOOR_1_GFX_PART_5,
89 IMG_DOOR_1_GFX_PART_6,
94 IMG_DOOR_1_GFX_PART_7,
99 IMG_DOOR_1_GFX_PART_8,
104 IMG_DOOR_2_GFX_PART_1,
109 IMG_DOOR_2_GFX_PART_2,
114 IMG_DOOR_2_GFX_PART_3,
119 IMG_DOOR_2_GFX_PART_4,
124 IMG_DOOR_2_GFX_PART_5,
129 IMG_DOOR_2_GFX_PART_6,
134 IMG_DOOR_2_GFX_PART_7,
139 IMG_DOOR_2_GFX_PART_8,
151 /* forward declaration for internal use */
152 static void UnmapToolButtons();
153 static void HandleToolButtons(struct GadgetInfo *);
154 static int el_act_dir2crm(int, int, int);
155 static int el_act2crm(int, int);
157 static struct GadgetInfo *tool_gadget[NUM_TOOL_BUTTONS];
158 static int request_gadget_id = -1;
160 static char *print_if_not_empty(int element)
162 static char *s = NULL;
163 char *token_name = element_info[element].token_name;
168 s = checked_malloc(strlen(token_name) + 10 + 1);
170 if (element != EL_EMPTY)
171 sprintf(s, "%d\t['%s']", element, token_name);
173 sprintf(s, "%d", element);
178 void DumpTile(int x, int y)
183 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
189 printf_line("-", 79);
190 printf("Field Info: SCREEN(%d, %d), LEVEL(%d, %d)\n", sx, sy, x, y);
191 printf_line("-", 79);
193 if (!IN_LEV_FIELD(x, y))
195 printf("(not in level field)\n");
201 printf(" Feld: %d\t['%s']\n", Feld[x][y],
202 element_info[Feld[x][y]].token_name);
203 printf(" Back: %s\n", print_if_not_empty(Back[x][y]));
204 printf(" Store: %s\n", print_if_not_empty(Store[x][y]));
205 printf(" Store2: %s\n", print_if_not_empty(Store2[x][y]));
206 printf(" StorePlayer: %s\n", print_if_not_empty(StorePlayer[x][y]));
207 printf(" MovPos: %d\n", MovPos[x][y]);
208 printf(" MovDir: %d\n", MovDir[x][y]);
209 printf(" MovDelay: %d\n", MovDelay[x][y]);
210 printf(" ChangeDelay: %d\n", ChangeDelay[x][y]);
211 printf(" CustomValue: %d\n", CustomValue[x][y]);
212 printf(" GfxElement: %d\n", GfxElement[x][y]);
213 printf(" GfxAction: %d\n", GfxAction[x][y]);
214 printf(" GfxFrame: %d\n", GfxFrame[x][y]);
218 void SetDrawtoField(int mode)
220 if (mode == DRAW_BUFFERED && setup.soft_scrolling)
228 BX2 = SCR_FIELDX + 1;
229 BY2 = SCR_FIELDY + 1;
248 BX2 = SCR_FIELDX + 1;
249 BY2 = SCR_FIELDY + 1;
264 drawto_field = fieldbuffer;
266 else /* DRAW_BACKBUFFER */
272 BX2 = SCR_FIELDX - 1;
273 BY2 = SCR_FIELDY - 1;
277 drawto_field = backbuffer;
281 void RedrawPlayfield(boolean force_redraw, int x, int y, int width, int height)
283 if (game_status == GAME_MODE_PLAYING &&
284 level.game_engine_type == GAME_ENGINE_TYPE_EM)
286 /* currently there is no partial redraw -- always redraw whole playfield */
287 RedrawPlayfield_EM(TRUE);
289 /* blit playfield from scroll buffer to normal back buffer for fading in */
290 BlitScreenToBitmap_EM(backbuffer);
292 else if (game_status == GAME_MODE_PLAYING &&
293 level.game_engine_type == GAME_ENGINE_TYPE_SP)
295 /* currently there is no partial redraw -- always redraw whole playfield */
296 RedrawPlayfield_SP(TRUE);
298 /* blit playfield from scroll buffer to normal back buffer for fading in */
299 BlitScreenToBitmap_SP(backbuffer);
301 else if (game_status == GAME_MODE_PLAYING &&
302 !game.envelope_active)
308 width = gfx.sxsize + 2 * TILEX;
309 height = gfx.sysize + 2 * TILEY;
315 int x1 = (x - SX) / TILEX, y1 = (y - SY) / TILEY;
316 int x2 = (x - SX + width) / TILEX, y2 = (y - SY + height) / TILEY;
318 for (xx = BX1; xx <= BX2; xx++)
319 for (yy = BY1; yy <= BY2; yy++)
320 if (xx >= x1 && xx <= x2 && yy >= y1 && yy <= y2)
321 DrawScreenField(xx, yy);
325 if (setup.soft_scrolling)
327 int fx = FX, fy = FY;
329 fx += (ScreenMovDir & (MV_LEFT|MV_RIGHT) ? ScreenGfxPos : 0);
330 fy += (ScreenMovDir & (MV_UP|MV_DOWN) ? ScreenGfxPos : 0);
332 BlitBitmap(fieldbuffer, backbuffer, fx,fy, SXSIZE,SYSIZE, SX,SY);
344 BlitBitmap(drawto, window, x, y, width, height, x, y);
347 void DrawMaskedBorder_Rect(int x, int y, int width, int height)
349 Bitmap *bitmap = graphic_info[IMG_GLOBAL_BORDER].bitmap;
351 SetClipOrigin(bitmap, bitmap->stored_clip_gc, 0, 0);
352 BlitBitmapMasked(bitmap, backbuffer, x, y, width, height, x, y);
355 void DrawMaskedBorder_FIELD()
357 if (global.border_status >= GAME_MODE_TITLE &&
358 global.border_status <= GAME_MODE_PLAYING &&
359 border.draw_masked[global.border_status])
360 DrawMaskedBorder_Rect(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
363 void DrawMaskedBorder_DOOR_1()
365 if (border.draw_masked[GFX_SPECIAL_ARG_DOOR] &&
366 (global.border_status != GAME_MODE_EDITOR ||
367 border.draw_masked[GFX_SPECIAL_ARG_EDITOR]))
368 DrawMaskedBorder_Rect(DX, DY, DXSIZE, DYSIZE);
371 void DrawMaskedBorder_DOOR_2()
373 if (border.draw_masked[GFX_SPECIAL_ARG_DOOR] &&
374 global.border_status != GAME_MODE_EDITOR)
375 DrawMaskedBorder_Rect(VX, VY, VXSIZE, VYSIZE);
378 void DrawMaskedBorder_DOOR_3()
380 /* currently not available */
383 void DrawMaskedBorder_ALL()
385 DrawMaskedBorder_FIELD();
386 DrawMaskedBorder_DOOR_1();
387 DrawMaskedBorder_DOOR_2();
388 DrawMaskedBorder_DOOR_3();
391 void DrawMaskedBorder(int redraw_mask)
393 /* never draw masked screen borders on borderless screens */
394 if (effectiveGameStatus() == GAME_MODE_LOADING ||
395 effectiveGameStatus() == GAME_MODE_TITLE)
398 /* never draw masked screen borders when displaying request outside door */
399 if (effectiveGameStatus() == GAME_MODE_PSEUDO_DOOR &&
400 global.use_envelope_request)
403 if (redraw_mask & REDRAW_ALL)
404 DrawMaskedBorder_ALL();
407 if (redraw_mask & REDRAW_FIELD)
408 DrawMaskedBorder_FIELD();
409 if (redraw_mask & REDRAW_DOOR_1)
410 DrawMaskedBorder_DOOR_1();
411 if (redraw_mask & REDRAW_DOOR_2)
412 DrawMaskedBorder_DOOR_2();
413 if (redraw_mask & REDRAW_DOOR_3)
414 DrawMaskedBorder_DOOR_3();
418 void BlitScreenToBitmap(Bitmap *target_bitmap)
420 DrawBuffer *buffer = (drawto_field == window ? backbuffer : drawto_field);
421 int fx = FX, fy = FY;
424 int dx = (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
425 int dy = (ScreenMovDir & (MV_UP | MV_DOWN) ? ScreenGfxPos : 0);
426 int dx_var = dx * TILESIZE_VAR / TILESIZE;
427 int dy_var = dy * TILESIZE_VAR / TILESIZE;
430 // fx += dx * TILESIZE_VAR / TILESIZE;
431 // fy += dy * TILESIZE_VAR / TILESIZE;
433 fx += (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
434 fy += (ScreenMovDir & (MV_UP | MV_DOWN) ? ScreenGfxPos : 0);
437 ffx = (scroll_x - SBX_Left) * TILEX_VAR + dx_var;
438 ffy = (scroll_y - SBY_Upper) * TILEY_VAR + dy_var;
440 if (EVEN(SCR_FIELDX))
442 if (ffx < SBX_Right * TILEX_VAR + TILEX_VAR / 2 + TILEX_VAR)
443 fx += dx_var - MIN(ffx, TILEX_VAR / 2) + TILEX_VAR;
445 fx += (dx_var > 0 ? TILEX_VAR : 0);
452 if (EVEN(SCR_FIELDY))
454 if (ffy < SBY_Lower * TILEY_VAR + TILEY_VAR / 2 + TILEY_VAR)
455 fy += dy_var - MIN(ffy, TILEY_VAR / 2) + TILEY_VAR;
457 fy += (dy_var > 0 ? TILEY_VAR : 0);
465 printf("::: (%d, %d) [(%d / %d, %d / %d)] => %d, %d\n",
468 SBY_Upper, SBY_Lower,
472 if (border.draw_masked[GAME_MODE_PLAYING])
474 if (buffer != backbuffer)
476 /* copy playfield buffer to backbuffer to add masked border */
477 BlitBitmap(buffer, backbuffer, fx, fy, SXSIZE, SYSIZE, SX, SY);
478 DrawMaskedBorder(REDRAW_FIELD);
481 BlitBitmap(backbuffer, target_bitmap,
482 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
487 BlitBitmap(buffer, target_bitmap, fx, fy, SXSIZE, SYSIZE, SX, SY);
494 DrawBuffer *buffer = (drawto_field == window ? backbuffer : drawto_field);
497 printf("::: TILES TO REFRESH: %d\n", redraw_tiles);
498 for (x = 0; x < SCR_FIELDX; x++)
499 for (y = 0 ; y < SCR_FIELDY; y++)
500 if (redraw[redraw_x1 + x][redraw_y1 + y])
501 printf("::: - %d, %d [%s]\n",
502 LEVELX(x), LEVELY(y),
503 EL_NAME(Feld[LEVELX(x)][LEVELY(y)]));
506 if (redraw_mask & REDRAW_TILES && redraw_tiles > REDRAWTILES_THRESHOLD)
507 redraw_mask |= REDRAW_FIELD;
510 // never redraw single tiles, always redraw the whole field
511 // (redrawing single tiles up to a certain threshold was faster on old,
512 // now legacy graphics, but slows things down on modern graphics now)
513 // UPDATE: this is now globally defined by value of REDRAWTILES_THRESHOLD
514 if (redraw_mask & REDRAW_TILES)
515 redraw_mask |= REDRAW_FIELD;
519 /* !!! TEST ONLY !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */
520 /* (force full redraw) */
521 if (game_status == GAME_MODE_PLAYING)
522 redraw_mask |= REDRAW_FIELD;
525 if (redraw_mask & REDRAW_FIELD)
526 redraw_mask &= ~REDRAW_TILES;
528 if (redraw_mask == REDRAW_NONE)
533 if (redraw_mask & REDRAW_ALL)
534 printf("[REDRAW_ALL]");
535 if (redraw_mask & REDRAW_FIELD)
536 printf("[REDRAW_FIELD]");
537 if (redraw_mask & REDRAW_TILES)
538 printf("[REDRAW_TILES]");
539 if (redraw_mask & REDRAW_DOOR_1)
540 printf("[REDRAW_DOOR_1]");
541 if (redraw_mask & REDRAW_DOOR_2)
542 printf("[REDRAW_DOOR_2]");
543 if (redraw_mask & REDRAW_FROM_BACKBUFFER)
544 printf("[REDRAW_FROM_BACKBUFFER]");
545 printf(" [%d]\n", FrameCounter);
548 if (redraw_mask & REDRAW_TILES &&
549 game_status == GAME_MODE_PLAYING &&
550 border.draw_masked[GAME_MODE_PLAYING])
551 redraw_mask |= REDRAW_FIELD;
553 if (global.fps_slowdown && game_status == GAME_MODE_PLAYING)
555 static boolean last_frame_skipped = FALSE;
556 boolean skip_even_when_not_scrolling = TRUE;
557 boolean just_scrolling = (ScreenMovDir != 0);
558 boolean verbose = FALSE;
560 if (global.fps_slowdown_factor > 1 &&
561 (FrameCounter % global.fps_slowdown_factor) &&
562 (just_scrolling || skip_even_when_not_scrolling))
564 redraw_mask &= ~REDRAW_MAIN;
566 last_frame_skipped = TRUE;
569 printf("FRAME SKIPPED\n");
573 if (last_frame_skipped)
574 redraw_mask |= REDRAW_FIELD;
576 last_frame_skipped = FALSE;
579 printf("frame not skipped\n");
583 /* synchronize X11 graphics at this point; if we would synchronize the
584 display immediately after the buffer switching (after the XFlush),
585 this could mean that we have to wait for the graphics to complete,
586 although we could go on doing calculations for the next frame */
590 /* never draw masked border to backbuffer when using playfield buffer */
591 if (game_status != GAME_MODE_PLAYING ||
592 redraw_mask & REDRAW_FROM_BACKBUFFER ||
593 buffer == backbuffer)
594 DrawMaskedBorder(redraw_mask);
596 DrawMaskedBorder(redraw_mask & REDRAW_DOORS);
598 if (redraw_mask & REDRAW_ALL)
600 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
602 redraw_mask = REDRAW_NONE;
605 if (redraw_mask & REDRAW_FIELD)
608 printf("::: REDRAW_FIELD\n");
611 if (game_status != GAME_MODE_PLAYING ||
612 redraw_mask & REDRAW_FROM_BACKBUFFER)
614 BlitBitmap(backbuffer, window,
615 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE, REAL_SX, REAL_SY);
620 BlitScreenToBitmap(window);
622 int fx = FX, fy = FY;
625 int dx = (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
626 int dy = (ScreenMovDir & (MV_UP | MV_DOWN) ? ScreenGfxPos : 0);
627 int dx_var = dx * TILESIZE_VAR / TILESIZE;
628 int dy_var = dy * TILESIZE_VAR / TILESIZE;
631 // fx += dx * TILESIZE_VAR / TILESIZE;
632 // fy += dy * TILESIZE_VAR / TILESIZE;
634 fx += (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
635 fy += (ScreenMovDir & (MV_UP | MV_DOWN) ? ScreenGfxPos : 0);
638 /* !!! THIS WORKS !!! */
640 printf("::: %d, %d\n", scroll_x, scroll_y);
642 ffx = (scroll_x - SBX_Left) * TILEX_VAR + dx_var;
643 ffy = (scroll_y - SBY_Upper) * TILEY_VAR + dy_var;
645 if (EVEN(SCR_FIELDX))
647 if (ffx < SBX_Right * TILEX_VAR + TILEX_VAR / 2 + TILEX_VAR)
648 fx += dx_var - MIN(ffx, TILEX_VAR / 2) + TILEX_VAR;
650 fx += (dx > 0 ? TILEX_VAR : 0);
657 if (EVEN(SCR_FIELDY))
659 if (ffy < SBY_Lower * TILEY_VAR + TILEY_VAR / 2 + TILEY_VAR)
660 fy += dy_var - MIN(ffy, TILEY_VAR / 2) + TILEY_VAR;
662 fy += (dy > 0 ? TILEY_VAR : 0);
669 if (border.draw_masked[GAME_MODE_PLAYING])
671 if (buffer != backbuffer)
673 /* copy playfield buffer to backbuffer to add masked border */
674 BlitBitmap(buffer, backbuffer, fx, fy, SXSIZE, SYSIZE, SX, SY);
675 DrawMaskedBorder(REDRAW_FIELD);
678 BlitBitmap(backbuffer, window,
679 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
684 BlitBitmap(buffer, window, fx, fy, SXSIZE, SYSIZE, SX, SY);
690 printf("redrawing all (ScreenGfxPos == %d) because %s\n",
692 (setup.soft_scrolling ?
693 "setup.soft_scrolling" :
694 ABS(ScreenGfxPos) + ScrollStepSize == TILEX ?
695 "ABS(ScreenGfxPos) + ScrollStepSize == TILEX" :
696 ABS(ScreenGfxPos) == ScrollStepSize ?
697 "ABS(ScreenGfxPos) == ScrollStepSize" :
698 "redraw_tiles > REDRAWTILES_THRESHOLD"));
703 redraw_mask &= ~REDRAW_MAIN;
706 if (redraw_mask & REDRAW_DOORS)
708 if (redraw_mask & REDRAW_DOOR_1)
709 BlitBitmap(backbuffer, window, DX, DY, DXSIZE, DYSIZE, DX, DY);
711 if (redraw_mask & REDRAW_DOOR_2)
712 BlitBitmap(backbuffer, window, VX, VY, VXSIZE, VYSIZE, VX, VY);
714 if (redraw_mask & REDRAW_DOOR_3)
715 BlitBitmap(backbuffer, window, EX, EY, EXSIZE, EYSIZE, EX, EY);
717 redraw_mask &= ~REDRAW_DOORS;
720 if (redraw_mask & REDRAW_MICROLEVEL)
722 BlitBitmap(backbuffer, window, SX, SY + 10 * TILEY, SXSIZE, 7 * TILEY,
723 SX, SY + 10 * TILEY);
725 redraw_mask &= ~REDRAW_MICROLEVEL;
728 if (redraw_mask & REDRAW_TILES)
731 printf("::: REDRAW_TILES\n");
737 InitGfxClipRegion(TRUE, SX, SY, SXSIZE, SYSIZE);
740 int sx = SX; // - (EVEN(SCR_FIELDX) ? TILEX_VAR / 2 : 0);
741 int sy = SY; // + (EVEN(SCR_FIELDY) ? TILEY_VAR / 2 : 0);
744 int dx_var = dx * TILESIZE_VAR / TILESIZE;
745 int dy_var = dy * TILESIZE_VAR / TILESIZE;
747 int fx = FX, fy = FY;
749 int scr_fieldx = SCR_FIELDX + (EVEN(SCR_FIELDX) ? 2 : 0);
750 int scr_fieldy = SCR_FIELDY + (EVEN(SCR_FIELDY) ? 2 : 0);
752 ffx = (scroll_x - SBX_Left) * TILEX_VAR + dx_var;
753 ffy = (scroll_y - SBY_Upper) * TILEY_VAR + dy_var;
755 if (EVEN(SCR_FIELDX))
757 if (ffx < SBX_Right * TILEX_VAR + TILEX_VAR / 2 + TILEX_VAR)
759 fx += dx_var - MIN(ffx, TILEX_VAR / 2) + TILEX_VAR;
768 fx += (dx_var > 0 ? TILEX_VAR : 0);
772 if (EVEN(SCR_FIELDY))
774 if (ffy < SBY_Lower * TILEY_VAR + TILEY_VAR / 2 + TILEY_VAR)
776 fy += dy_var - MIN(ffy, TILEY_VAR / 2) + TILEY_VAR;
785 fy += (dy_var > 0 ? TILEY_VAR : 0);
790 printf("::: %d, %d, %d, %d\n", sx, sy, SCR_FIELDX, SCR_FIELDY);
793 for (x = 0; x < scr_fieldx; x++)
794 for (y = 0 ; y < scr_fieldy; y++)
795 if (redraw[redraw_x1 + x][redraw_y1 + y])
796 BlitBitmap(buffer, window,
797 FX + x * TILEX_VAR, FY + y * TILEY_VAR,
798 TILEX_VAR, TILEY_VAR,
799 sx + x * TILEX_VAR, sy + y * TILEY_VAR);
802 InitGfxClipRegion(FALSE, -1, -1, -1, -1);
804 for (x = 0; x < SCR_FIELDX; x++)
805 for (y = 0 ; y < SCR_FIELDY; y++)
806 if (redraw[redraw_x1 + x][redraw_y1 + y])
807 BlitBitmap(buffer, window,
808 FX + x * TILEX_VAR, FY + y * TILEY_VAR,
809 TILEX_VAR, TILEY_VAR,
810 SX + x * TILEX_VAR, SY + y * TILEY_VAR);
814 for (x = 0; x < SCR_FIELDX; x++)
815 for (y = 0 ; y < SCR_FIELDY; y++)
816 if (redraw[redraw_x1 + x][redraw_y1 + y])
817 BlitBitmap(buffer, window,
818 FX + x * TILEX, FY + y * TILEY, TILEX, TILEY,
819 SX + x * TILEX, SY + y * TILEY);
823 if (redraw_mask & REDRAW_FPS) /* display frames per second */
828 sprintf(info1, " (only every %d. frame)", global.fps_slowdown_factor);
829 if (!global.fps_slowdown)
832 sprintf(text, "%04.1f fps%s", global.frames_per_second, info1);
834 DrawTextExt(window, SX + SXSIZE + SX, 0, text, FONT_TEXT_2, BLIT_OPAQUE);
836 DrawTextExt(window, SX, SY, text, FONT_TEXT_2, BLIT_OPAQUE);
842 for (x = 0; x < MAX_BUF_XSIZE; x++)
843 for (y = 0; y < MAX_BUF_YSIZE; y++)
846 redraw_mask = REDRAW_NONE;
849 static void FadeCrossSaveBackbuffer()
851 BlitBitmap(backbuffer, bitmap_db_cross, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
854 static void FadeExt(int fade_mask, int fade_mode, int fade_type)
856 static int fade_type_skip = FADE_TYPE_NONE;
857 void (*draw_border_function)(void) = NULL;
858 Bitmap *bitmap = (fade_mode & FADE_TYPE_TRANSFORM ? bitmap_db_cross : NULL);
859 int x, y, width, height;
860 int fade_delay, post_delay;
862 if (fade_type == FADE_TYPE_FADE_OUT)
864 if (fade_type_skip != FADE_TYPE_NONE)
867 printf("::: skipping %d ... [%d] (X)\n", fade_mode, fade_type_skip);
870 /* skip all fade operations until specified fade operation */
871 if (fade_type & fade_type_skip)
872 fade_type_skip = FADE_TYPE_NONE;
877 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
879 FadeCrossSaveBackbuffer();
885 redraw_mask |= fade_mask;
887 if (fade_type == FADE_TYPE_SKIP)
890 printf("::: will skip %d ... [%d]\n", fade_mode, fade_type_skip);
893 fade_type_skip = fade_mode;
899 printf("::: !!! FADING %d ... [%d] [%d]\n", fade_mode, fade_type,
904 fade_delay = fading.fade_delay;
905 post_delay = (fade_mode == FADE_MODE_FADE_OUT ? fading.post_delay : 0);
908 if (fade_type_skip != FADE_TYPE_NONE)
911 printf("::: skipping %d ... [%d]\n", fade_mode, fade_type_skip);
914 /* skip all fade operations until specified fade operation */
915 if (fade_type & fade_type_skip)
916 fade_type_skip = FADE_TYPE_NONE;
926 if (global.autoplay_leveldir)
928 // fading.fade_mode = FADE_MODE_NONE;
935 if (fading.fade_mode == FADE_MODE_NONE)
943 /* !!! what about fade_mask == REDRAW_FIELD | REDRAW_ALL ??? !!! */
946 printf("::: NOW FADING %d ... [%d]\n", fade_mode, fade_type);
950 if (fade_mask == REDRAW_NONE)
951 fade_mask = REDRAW_FIELD;
954 // if (fade_mask & REDRAW_FIELD)
955 if (fade_mask == REDRAW_FIELD)
960 height = FULL_SYSIZE;
963 fade_delay = fading.fade_delay;
964 post_delay = (fade_mode == FADE_MODE_FADE_OUT ? fading.post_delay : 0);
967 if (border.draw_masked_when_fading)
968 draw_border_function = DrawMaskedBorder_FIELD; /* update when fading */
970 DrawMaskedBorder_FIELD(); /* draw once */
972 else /* REDRAW_ALL */
980 fade_delay = fading.fade_delay;
981 post_delay = (fade_mode == FADE_MODE_FADE_OUT ? fading.post_delay : 0);
986 if (!setup.fade_screens ||
988 fading.fade_mode == FADE_MODE_NONE)
990 if (!setup.fade_screens || fade_delay == 0)
993 if (fade_mode == FADE_MODE_FADE_OUT)
997 if (fade_mode == FADE_MODE_FADE_OUT &&
998 fading.fade_mode != FADE_MODE_NONE)
999 ClearRectangle(backbuffer, x, y, width, height);
1003 BlitBitmap(backbuffer, window, x, y, width, height, x, y);
1004 redraw_mask = REDRAW_NONE;
1012 FadeRectangle(bitmap, x, y, width, height, fade_mode, fade_delay, post_delay,
1013 draw_border_function);
1015 redraw_mask &= ~fade_mask;
1018 void FadeIn(int fade_mask)
1020 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
1021 FadeExt(fade_mask, fading.fade_mode, FADE_TYPE_FADE_IN);
1023 FadeExt(fade_mask, FADE_MODE_FADE_IN, FADE_TYPE_FADE_IN);
1026 void FadeOut(int fade_mask)
1028 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
1029 FadeExt(fade_mask, fading.fade_mode, FADE_TYPE_FADE_OUT);
1031 FadeExt(fade_mask, FADE_MODE_FADE_OUT, FADE_TYPE_FADE_OUT);
1033 global.border_status = game_status;
1036 static void FadeSetLeaveNext(struct TitleFadingInfo fading_leave, boolean set)
1038 static struct TitleFadingInfo fading_leave_stored;
1041 fading_leave_stored = fading_leave;
1043 fading = fading_leave_stored;
1046 void FadeSetEnterMenu()
1048 fading = menu.enter_menu;
1051 printf("::: storing enter_menu\n");
1054 FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
1057 void FadeSetLeaveMenu()
1059 fading = menu.leave_menu;
1062 printf("::: storing leave_menu\n");
1065 FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
1068 void FadeSetEnterScreen()
1070 fading = menu.enter_screen[game_status];
1073 printf("::: storing leave_screen[%d]\n", game_status);
1076 FadeSetLeaveNext(menu.leave_screen[game_status], TRUE); /* store */
1079 void FadeSetNextScreen()
1081 fading = menu.next_screen;
1084 printf("::: storing next_screen\n");
1087 // (do not overwrite fade mode set by FadeSetEnterScreen)
1088 // FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
1091 void FadeSetLeaveScreen()
1094 printf("::: recalling last stored value\n");
1097 FadeSetLeaveNext(menu.leave_screen[game_status], FALSE); /* recall */
1100 void FadeSetFromType(int type)
1102 if (type & TYPE_ENTER_SCREEN)
1103 FadeSetEnterScreen();
1104 else if (type & TYPE_ENTER)
1106 else if (type & TYPE_LEAVE)
1110 void FadeSetDisabled()
1112 static struct TitleFadingInfo fading_none = { FADE_MODE_NONE, -1, -1, -1 };
1114 fading = fading_none;
1117 void FadeSkipNextFadeIn()
1119 FadeExt(0, FADE_MODE_SKIP_FADE_IN, FADE_TYPE_SKIP);
1122 void FadeSkipNextFadeOut()
1124 FadeExt(0, FADE_MODE_SKIP_FADE_OUT, FADE_TYPE_SKIP);
1127 void SetWindowBackgroundImageIfDefined(int graphic)
1129 if (graphic_info[graphic].bitmap)
1130 SetWindowBackgroundBitmap(graphic_info[graphic].bitmap);
1133 void SetMainBackgroundImageIfDefined(int graphic)
1135 if (graphic_info[graphic].bitmap)
1136 SetMainBackgroundBitmap(graphic_info[graphic].bitmap);
1139 void SetDoorBackgroundImageIfDefined(int graphic)
1141 if (graphic_info[graphic].bitmap)
1142 SetDoorBackgroundBitmap(graphic_info[graphic].bitmap);
1145 void SetWindowBackgroundImage(int graphic)
1147 SetWindowBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
1148 graphic_info[graphic].bitmap ?
1149 graphic_info[graphic].bitmap :
1150 graphic_info[IMG_BACKGROUND].bitmap);
1153 void SetMainBackgroundImage(int graphic)
1155 SetMainBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
1156 graphic_info[graphic].bitmap ?
1157 graphic_info[graphic].bitmap :
1158 graphic_info[IMG_BACKGROUND].bitmap);
1161 void SetDoorBackgroundImage(int graphic)
1163 SetDoorBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
1164 graphic_info[graphic].bitmap ?
1165 graphic_info[graphic].bitmap :
1166 graphic_info[IMG_BACKGROUND].bitmap);
1169 void SetPanelBackground()
1172 struct GraphicInfo *gfx = &graphic_info[IMG_BACKGROUND_PANEL];
1175 BlitBitmapTiled(gfx->bitmap, bitmap_db_panel, gfx->src_x, gfx->src_y,
1176 gfx->width, gfx->height, 0, 0, DXSIZE, DYSIZE);
1178 /* (ClearRectangle() only needed if panel bitmap is smaller than panel) */
1179 ClearRectangle(bitmap_db_panel, DX, DY, DXSIZE, DYSIZE);
1180 BlitBitmap(gfx->bitmap, bitmap_db_panel, gfx->src_x, gfx->src_y,
1181 MIN(gfx->width, DXSIZE), MIN(gfx->height, DYSIZE), 0, 0);
1184 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, bitmap_db_panel,
1185 DOOR_GFX_PAGEX5, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE, 0, 0);
1188 SetDoorBackgroundBitmap(bitmap_db_panel);
1191 void DrawBackground(int x, int y, int width, int height)
1193 /* !!! "drawto" might still point to playfield buffer here (see below) !!! */
1194 /* (when entering hall of fame after playing) */
1196 ClearRectangleOnBackground(drawto, x, y, width, height);
1198 ClearRectangleOnBackground(backbuffer, x, y, width, height);
1204 if (IN_GFX_FIELD_FULL(x, y))
1205 redraw_mask |= REDRAW_FIELD;
1206 else if (IN_GFX_DOOR_1(x, y))
1207 redraw_mask |= REDRAW_DOOR_1;
1208 else if (IN_GFX_DOOR_2(x, y))
1209 redraw_mask |= REDRAW_DOOR_2;
1210 else if (IN_GFX_DOOR_3(x, y))
1211 redraw_mask |= REDRAW_DOOR_3;
1213 /* (this only works for the current arrangement of playfield and panels) */
1215 redraw_mask |= REDRAW_FIELD;
1216 else if (y < gfx.vy)
1217 redraw_mask |= REDRAW_DOOR_1;
1219 redraw_mask |= REDRAW_DOOR_2;
1223 /* (this is just wrong (when drawing to one of the two door panel areas)) */
1224 redraw_mask |= REDRAW_FIELD;
1228 void DrawBackgroundForFont(int x, int y, int width, int height, int font_nr)
1230 struct FontBitmapInfo *font = getFontBitmapInfo(font_nr);
1232 if (font->bitmap == NULL)
1235 DrawBackground(x, y, width, height);
1238 void DrawBackgroundForGraphic(int x, int y, int width, int height, int graphic)
1240 struct GraphicInfo *g = &graphic_info[graphic];
1242 if (g->bitmap == NULL)
1245 DrawBackground(x, y, width, height);
1250 /* !!! "drawto" might still point to playfield buffer here (see above) !!! */
1251 /* (when entering hall of fame after playing) */
1252 DrawBackground(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
1254 /* !!! maybe this should be done before clearing the background !!! */
1255 if (setup.soft_scrolling && game_status == GAME_MODE_PLAYING)
1257 ClearRectangle(fieldbuffer, 0, 0, FXSIZE, FYSIZE);
1258 SetDrawtoField(DRAW_BUFFERED);
1261 SetDrawtoField(DRAW_BACKBUFFER);
1264 void MarkTileDirty(int x, int y)
1266 int xx = redraw_x1 + x;
1267 int yy = redraw_y1 + y;
1269 if (!redraw[xx][yy])
1272 redraw[xx][yy] = TRUE;
1273 redraw_mask |= REDRAW_TILES;
1276 void SetBorderElement()
1280 BorderElement = EL_EMPTY;
1282 for (y = 0; y < lev_fieldy && BorderElement == EL_EMPTY; y++)
1284 for (x = 0; x < lev_fieldx; x++)
1286 if (!IS_INDESTRUCTIBLE(Feld[x][y]))
1287 BorderElement = EL_STEELWALL;
1289 if (y != 0 && y != lev_fieldy - 1 && x != lev_fieldx - 1)
1295 void FloodFillLevel(int from_x, int from_y, int fill_element,
1296 short field[MAX_LEV_FIELDX][MAX_LEV_FIELDY],
1297 int max_fieldx, int max_fieldy)
1301 static int check[4][2] = { { -1, 0 }, { 0, -1 }, { 1, 0 }, { 0, 1 } };
1302 static int safety = 0;
1304 /* check if starting field still has the desired content */
1305 if (field[from_x][from_y] == fill_element)
1310 if (safety > max_fieldx * max_fieldy)
1311 Error(ERR_EXIT, "Something went wrong in 'FloodFill()'. Please debug.");
1313 old_element = field[from_x][from_y];
1314 field[from_x][from_y] = fill_element;
1316 for (i = 0; i < 4; i++)
1318 x = from_x + check[i][0];
1319 y = from_y + check[i][1];
1321 if (IN_FIELD(x, y, max_fieldx, max_fieldy) && field[x][y] == old_element)
1322 FloodFillLevel(x, y, fill_element, field, max_fieldx, max_fieldy);
1328 void SetRandomAnimationValue(int x, int y)
1330 gfx.anim_random_frame = GfxRandom[x][y];
1333 inline int getGraphicAnimationFrame(int graphic, int sync_frame)
1335 /* animation synchronized with global frame counter, not move position */
1336 if (graphic_info[graphic].anim_global_sync || sync_frame < 0)
1337 sync_frame = FrameCounter;
1339 return getAnimationFrame(graphic_info[graphic].anim_frames,
1340 graphic_info[graphic].anim_delay,
1341 graphic_info[graphic].anim_mode,
1342 graphic_info[graphic].anim_start_frame,
1346 void getSizedGraphicSourceExt(int graphic, int frame, int tilesize_raw,
1347 Bitmap **bitmap, int *x, int *y,
1348 boolean get_backside)
1352 int width_mult, width_div;
1353 int height_mult, height_div;
1357 { 15, 16, 2, 3 }, /* 1 x 1 */
1358 { 7, 8, 2, 3 }, /* 2 x 2 */
1359 { 3, 4, 2, 3 }, /* 4 x 4 */
1360 { 1, 2, 2, 3 }, /* 8 x 8 */
1361 { 0, 1, 2, 3 }, /* 16 x 16 */
1362 { 0, 1, 0, 1 }, /* 32 x 32 */
1364 struct GraphicInfo *g = &graphic_info[graphic];
1365 Bitmap *src_bitmap = g->bitmap;
1366 int tilesize = MIN(MAX(1, tilesize_raw), TILESIZE);
1367 int offset_calc_pos = log_2(tilesize);
1368 int width_mult = offset_calc[offset_calc_pos].width_mult;
1369 int width_div = offset_calc[offset_calc_pos].width_div;
1370 int height_mult = offset_calc[offset_calc_pos].height_mult;
1371 int height_div = offset_calc[offset_calc_pos].height_div;
1372 int startx = src_bitmap->width * width_mult / width_div;
1373 int starty = src_bitmap->height * height_mult / height_div;
1375 int src_x = (g->src_x + (get_backside ? g->offset2_x : 0)) *
1376 tilesize / TILESIZE;
1377 int src_y = (g->src_y + (get_backside ? g->offset2_y : 0)) *
1378 tilesize / TILESIZE;
1380 int src_x = g->src_x * tilesize / TILESIZE;
1381 int src_y = g->src_y * tilesize / TILESIZE;
1383 int width = g->width * tilesize / TILESIZE;
1384 int height = g->height * tilesize / TILESIZE;
1385 int offset_x = g->offset_x * tilesize / TILESIZE;
1386 int offset_y = g->offset_y * tilesize / TILESIZE;
1388 if (g->offset_y == 0) /* frames are ordered horizontally */
1390 int max_width = g->anim_frames_per_line * width;
1391 int pos = (src_y / height) * max_width + src_x + frame * offset_x;
1393 src_x = pos % max_width;
1394 src_y = src_y % height + pos / max_width * height;
1396 else if (g->offset_x == 0) /* frames are ordered vertically */
1398 int max_height = g->anim_frames_per_line * height;
1399 int pos = (src_x / width) * max_height + src_y + frame * offset_y;
1401 src_x = src_x % width + pos / max_height * width;
1402 src_y = pos % max_height;
1404 else /* frames are ordered diagonally */
1406 src_x = src_x + frame * offset_x;
1407 src_y = src_y + frame * offset_y;
1410 *bitmap = src_bitmap;
1411 *x = startx + src_x;
1412 *y = starty + src_y;
1415 void getFixedGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
1416 int *x, int *y, boolean get_backside)
1418 getSizedGraphicSourceExt(graphic, frame, TILESIZE, bitmap, x, y,
1422 void getSizedGraphicSource(int graphic, int frame, int tilesize_raw,
1423 Bitmap **bitmap, int *x, int *y)
1425 getSizedGraphicSourceExt(graphic, frame, tilesize_raw, bitmap, x, y, FALSE);
1428 void getFixedGraphicSource(int graphic, int frame,
1429 Bitmap **bitmap, int *x, int *y)
1431 getSizedGraphicSourceExt(graphic, frame, TILESIZE, bitmap, x, y, FALSE);
1434 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
1437 getSizedGraphicSource(graphic, 0, MINI_TILESIZE, bitmap, x, y);
1439 struct GraphicInfo *g = &graphic_info[graphic];
1440 int mini_startx = 0;
1441 int mini_starty = g->bitmap->height * 2 / 3;
1443 *bitmap = g->bitmap;
1444 *x = mini_startx + g->src_x / 2;
1445 *y = mini_starty + g->src_y / 2;
1449 inline void getGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
1450 int *x, int *y, boolean get_backside)
1452 struct GraphicInfo *g = &graphic_info[graphic];
1453 int src_x = g->src_x + (get_backside ? g->offset2_x : 0);
1454 int src_y = g->src_y + (get_backside ? g->offset2_y : 0);
1457 if (TILESIZE_VAR != TILESIZE)
1458 return getSizedGraphicSourceExt(graphic, frame, TILESIZE_VAR, bitmap, x, y,
1462 *bitmap = g->bitmap;
1464 if (g->offset_y == 0) /* frames are ordered horizontally */
1466 int max_width = g->anim_frames_per_line * g->width;
1467 int pos = (src_y / g->height) * max_width + src_x + frame * g->offset_x;
1469 *x = pos % max_width;
1470 *y = src_y % g->height + pos / max_width * g->height;
1472 else if (g->offset_x == 0) /* frames are ordered vertically */
1474 int max_height = g->anim_frames_per_line * g->height;
1475 int pos = (src_x / g->width) * max_height + src_y + frame * g->offset_y;
1477 *x = src_x % g->width + pos / max_height * g->width;
1478 *y = pos % max_height;
1480 else /* frames are ordered diagonally */
1482 *x = src_x + frame * g->offset_x;
1483 *y = src_y + frame * g->offset_y;
1487 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
1489 getGraphicSourceExt(graphic, frame, bitmap, x, y, FALSE);
1492 void DrawGraphic(int x, int y, int graphic, int frame)
1495 if (!IN_SCR_FIELD(x, y))
1497 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
1498 printf("DrawGraphic(): This should never happen!\n");
1504 DrawGraphicExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR, graphic,
1507 DrawGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic, frame);
1509 MarkTileDirty(x, y);
1512 void DrawFixedGraphic(int x, int y, int graphic, int frame)
1515 if (!IN_SCR_FIELD(x, y))
1517 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
1518 printf("DrawGraphic(): This should never happen!\n");
1523 DrawFixedGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic,
1525 MarkTileDirty(x, y);
1528 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
1534 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1536 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX_VAR, TILEY_VAR, x, y);
1538 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
1542 void DrawFixedGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
1548 getFixedGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1549 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
1552 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
1555 if (!IN_SCR_FIELD(x, y))
1557 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
1558 printf("DrawGraphicThruMask(): This should never happen!\n");
1564 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR,
1567 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic,
1570 MarkTileDirty(x, y);
1573 void DrawFixedGraphicThruMask(int x, int y, int graphic, int frame)
1576 if (!IN_SCR_FIELD(x, y))
1578 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
1579 printf("DrawGraphicThruMask(): This should never happen!\n");
1584 DrawFixedGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
1586 MarkTileDirty(x, y);
1589 void DrawGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y, int graphic,
1595 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1597 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1598 dst_x - src_x, dst_y - src_y);
1600 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX_VAR, TILEY_VAR,
1603 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dst_x, dst_y);
1607 void DrawFixedGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y,
1608 int graphic, int frame)
1613 getFixedGraphicSource(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);
1617 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dst_x, dst_y);
1620 void DrawSizedGraphic(int x, int y, int graphic, int frame, int tilesize)
1622 DrawSizedGraphicExt(drawto, SX + x * tilesize, SY + y * tilesize, graphic,
1624 MarkTileDirty(x / tilesize, y / tilesize);
1627 void DrawSizedGraphicExt(DrawBuffer *d, int x, int y, int graphic, int frame,
1633 getSizedGraphicSource(graphic, frame, tilesize, &src_bitmap, &src_x, &src_y);
1634 BlitBitmap(src_bitmap, d, src_x, src_y, tilesize, tilesize, x, y);
1637 void DrawMiniGraphic(int x, int y, int graphic)
1639 DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
1640 MarkTileDirty(x / 2, y / 2);
1643 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
1648 getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1649 BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
1652 inline static void DrawGraphicShiftedNormal(int x, int y, int dx, int dy,
1653 int graphic, int frame,
1654 int cut_mode, int mask_mode)
1659 int width = TILEX, height = TILEY;
1662 if (dx || dy) /* shifted graphic */
1664 if (x < BX1) /* object enters playfield from the left */
1671 else if (x > BX2) /* object enters playfield from the right */
1677 else if (x==BX1 && dx < 0) /* object leaves playfield to the left */
1683 else if (x==BX2 && dx > 0) /* object leaves playfield to the right */
1685 else if (dx) /* general horizontal movement */
1686 MarkTileDirty(x + SIGN(dx), y);
1688 if (y < BY1) /* object enters playfield from the top */
1690 if (cut_mode==CUT_BELOW) /* object completely above top border */
1698 else if (y > BY2) /* object enters playfield from the bottom */
1704 else if (y==BY1 && dy < 0) /* object leaves playfield to the top */
1710 else if (dy > 0 && cut_mode == CUT_ABOVE)
1712 if (y == BY2) /* object completely above bottom border */
1718 MarkTileDirty(x, y + 1);
1719 } /* object leaves playfield to the bottom */
1720 else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
1722 else if (dy) /* general vertical movement */
1723 MarkTileDirty(x, y + SIGN(dy));
1727 if (!IN_SCR_FIELD(x, y))
1729 printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
1730 printf("DrawGraphicShifted(): This should never happen!\n");
1736 width = width * TILESIZE_VAR / TILESIZE;
1737 height = height * TILESIZE_VAR / TILESIZE;
1738 cx = cx * TILESIZE_VAR / TILESIZE;
1739 cy = cy * TILESIZE_VAR / TILESIZE;
1740 dx = dx * TILESIZE_VAR / TILESIZE;
1741 dy = dy * TILESIZE_VAR / TILESIZE;
1744 if (width > 0 && height > 0)
1746 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1752 dst_x = FX + x * TILEX_VAR + dx;
1753 dst_y = FY + y * TILEY_VAR + dy;
1755 dst_x = FX + x * TILEX + dx;
1756 dst_y = FY + y * TILEY + dy;
1759 if (mask_mode == USE_MASKING)
1761 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1762 dst_x - src_x, dst_y - src_y);
1763 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1767 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1770 MarkTileDirty(x, y);
1774 inline static void DrawGraphicShiftedDouble(int x, int y, int dx, int dy,
1775 int graphic, int frame,
1776 int cut_mode, int mask_mode)
1782 int width = TILEX_VAR, height = TILEY_VAR;
1784 int width = TILEX, height = TILEY;
1788 int x2 = x + SIGN(dx);
1789 int y2 = y + SIGN(dy);
1791 /* !!! DOES NOT WORK FOR SLOW MOVEMENT !!! */
1792 int sync_frame = GfxFrame[LEVELX(x)][LEVELY(y)];
1794 /* movement with two-tile animations must be sync'ed with movement position,
1795 not with current GfxFrame (which can be higher when using slow movement) */
1796 int anim_pos = (dx ? ABS(dx) : ABS(dy));
1797 int anim_frames = graphic_info[graphic].anim_frames;
1799 /* (we also need anim_delay here for movement animations with less frames) */
1800 int anim_delay = graphic_info[graphic].anim_delay;
1801 int sync_frame = anim_pos * anim_frames * anim_delay / TILESIZE;
1803 int sync_frame = anim_pos * anim_frames / TILESIZE;
1806 boolean draw_start_tile = (cut_mode != CUT_ABOVE); /* only for falling! */
1807 boolean draw_end_tile = (cut_mode != CUT_BELOW); /* only for falling! */
1809 /* re-calculate animation frame for two-tile movement animation */
1810 frame = getGraphicAnimationFrame(graphic, sync_frame);
1814 printf("::: %d, %d, %d => %d [%d]\n",
1815 anim_pos, anim_frames, anim_delay, sync_frame, graphic);
1817 printf("::: %d, %d => %d\n",
1818 anim_pos, anim_frames, sync_frame);
1823 printf("::: %d [%d, %d] [%d] [%d]\n", frame, sync_frame, dy,
1824 GfxFrame[LEVELX(x)][LEVELY(y)], mask_mode);
1827 /* check if movement start graphic inside screen area and should be drawn */
1828 if (draw_start_tile && IN_SCR_FIELD(x1, y1))
1830 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, TRUE);
1833 dst_x = FX + x1 * TILEX_VAR;
1834 dst_y = FY + y1 * TILEY_VAR;
1836 dst_x = FX + x1 * TILEX;
1837 dst_y = FY + y1 * TILEY;
1840 if (mask_mode == USE_MASKING)
1842 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1843 dst_x - src_x, dst_y - src_y);
1844 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1848 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1851 MarkTileDirty(x1, y1);
1854 /* check if movement end graphic inside screen area and should be drawn */
1855 if (draw_end_tile && IN_SCR_FIELD(x2, y2))
1857 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
1860 dst_x = FX + x2 * TILEX_VAR;
1861 dst_y = FY + y2 * TILEY_VAR;
1863 dst_x = FX + x2 * TILEX;
1864 dst_y = FY + y2 * TILEY;
1867 if (mask_mode == USE_MASKING)
1869 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1870 dst_x - src_x, dst_y - src_y);
1871 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1875 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1878 MarkTileDirty(x2, y2);
1882 static void DrawGraphicShifted(int x, int y, int dx, int dy,
1883 int graphic, int frame,
1884 int cut_mode, int mask_mode)
1888 DrawGraphic(x, y, graphic, frame);
1893 if (graphic_info[graphic].double_movement) /* EM style movement images */
1894 DrawGraphicShiftedDouble(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1896 DrawGraphicShiftedNormal(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1899 void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
1900 int frame, int cut_mode)
1902 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, USE_MASKING);
1905 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
1906 int cut_mode, int mask_mode)
1908 int lx = LEVELX(x), ly = LEVELY(y);
1912 if (IN_LEV_FIELD(lx, ly))
1914 SetRandomAnimationValue(lx, ly);
1916 graphic = el_act_dir2img(element, GfxAction[lx][ly], GfxDir[lx][ly]);
1917 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1919 /* do not use double (EM style) movement graphic when not moving */
1920 if (graphic_info[graphic].double_movement && !dx && !dy)
1922 graphic = el_act_dir2img(element, ACTION_DEFAULT, GfxDir[lx][ly]);
1923 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1926 else /* border element */
1928 graphic = el2img(element);
1929 frame = getGraphicAnimationFrame(graphic, -1);
1932 if (element == EL_EXPANDABLE_WALL)
1934 boolean left_stopped = FALSE, right_stopped = FALSE;
1936 if (!IN_LEV_FIELD(lx - 1, ly) || IS_WALL(Feld[lx - 1][ly]))
1937 left_stopped = TRUE;
1938 if (!IN_LEV_FIELD(lx + 1, ly) || IS_WALL(Feld[lx + 1][ly]))
1939 right_stopped = TRUE;
1941 if (left_stopped && right_stopped)
1943 else if (left_stopped)
1945 graphic = IMG_EXPANDABLE_WALL_GROWING_RIGHT;
1946 frame = graphic_info[graphic].anim_frames - 1;
1948 else if (right_stopped)
1950 graphic = IMG_EXPANDABLE_WALL_GROWING_LEFT;
1951 frame = graphic_info[graphic].anim_frames - 1;
1956 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
1957 else if (mask_mode == USE_MASKING)
1958 DrawGraphicThruMask(x, y, graphic, frame);
1960 DrawGraphic(x, y, graphic, frame);
1963 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
1964 int cut_mode, int mask_mode)
1966 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1967 DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
1968 cut_mode, mask_mode);
1971 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
1974 DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1977 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
1980 DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1983 void DrawLevelElementThruMask(int x, int y, int element)
1985 DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1988 void DrawLevelFieldThruMask(int x, int y)
1990 DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
1993 /* !!! implementation of quicksand is totally broken !!! */
1994 #define IS_CRUMBLED_TILE(x, y, e) \
1995 (GFX_CRUMBLED(e) && (!IN_LEV_FIELD(x, y) || \
1996 !IS_MOVING(x, y) || \
1997 (e) == EL_QUICKSAND_EMPTYING || \
1998 (e) == EL_QUICKSAND_FAST_EMPTYING))
2000 static void DrawLevelFieldCrumbledInnerCorners(int x, int y, int dx, int dy,
2005 int width, height, cx, cy;
2006 int sx = SCREENX(x), sy = SCREENY(y);
2007 int crumbled_border_size = graphic_info[graphic].border_size;
2010 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
2012 for (i = 1; i < 4; i++)
2014 int dxx = (i & 1 ? dx : 0);
2015 int dyy = (i & 2 ? dy : 0);
2018 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
2021 /* check if neighbour field is of same crumble type */
2022 boolean same = (IS_CRUMBLED_TILE(xx, yy, element) &&
2023 graphic_info[graphic].class ==
2024 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class);
2026 /* return if check prevents inner corner */
2027 if (same == (dxx == dx && dyy == dy))
2031 /* if we reach this point, we have an inner corner */
2033 getGraphicSource(graphic, 1, &src_bitmap, &src_x, &src_y);
2036 width = crumbled_border_size * TILESIZE_VAR / TILESIZE;
2037 height = crumbled_border_size * TILESIZE_VAR / TILESIZE;
2038 cx = (dx > 0 ? TILEX - crumbled_border_size : 0) * TILESIZE_VAR / TILESIZE;
2039 cy = (dy > 0 ? TILEY - crumbled_border_size : 0) * TILESIZE_VAR / TILESIZE;
2041 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
2042 width, height, FX + sx * TILEX_VAR + cx, FY + sy * TILEY_VAR + cy);
2044 width = crumbled_border_size;
2045 height = crumbled_border_size;
2046 cx = (dx > 0 ? TILEX - crumbled_border_size : 0);
2047 cy = (dy > 0 ? TILEY - crumbled_border_size : 0);
2049 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
2050 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
2054 static void DrawLevelFieldCrumbledBorders(int x, int y, int graphic, int frame,
2059 int width, height, bx, by, cx, cy;
2060 int sx = SCREENX(x), sy = SCREENY(y);
2061 int crumbled_border_size = graphic_info[graphic].border_size;
2064 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
2066 /* draw simple, sloppy, non-corner-accurate crumbled border */
2069 width = (dir == 1 || dir == 2 ? crumbled_border_size : TILEX);
2070 height = (dir == 0 || dir == 3 ? crumbled_border_size : TILEY);
2071 cx = (dir == 2 ? TILEX - crumbled_border_size : 0);
2072 cy = (dir == 3 ? TILEY - crumbled_border_size : 0);
2074 if (dir == 1 || dir == 2) /* left or right crumbled border */
2076 width = crumbled_border_size;
2078 cx = (dir == 2 ? TILEX - crumbled_border_size : 0);
2081 else /* top or bottom crumbled border */
2084 height = crumbled_border_size;
2086 cy = (dir == 3 ? TILEY - crumbled_border_size : 0);
2091 BlitBitmap(src_bitmap, drawto_field,
2092 src_x + cx * TILESIZE_VAR / TILESIZE,
2093 src_y + cy * TILESIZE_VAR / TILESIZE,
2094 width * TILESIZE_VAR / TILESIZE,
2095 height * TILESIZE_VAR / TILESIZE,
2096 FX + sx * TILEX_VAR + cx * TILESIZE_VAR / TILESIZE,
2097 FY + sy * TILEY_VAR + cy * TILESIZE_VAR / TILESIZE);
2099 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
2100 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
2103 /* (remaining middle border part must be at least as big as corner part) */
2104 if (!(graphic_info[graphic].style & STYLE_ACCURATE_BORDERS) ||
2105 crumbled_border_size >= TILESIZE / 3)
2108 /* correct corners of crumbled border, if needed */
2111 for (i = -1; i <= 1; i+=2)
2113 int xx = x + (dir == 0 || dir == 3 ? i : 0);
2114 int yy = y + (dir == 1 || dir == 2 ? i : 0);
2115 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
2118 /* check if neighbour field is of same crumble type */
2119 if (IS_CRUMBLED_TILE(xx, yy, element) &&
2120 graphic_info[graphic].class ==
2121 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
2123 /* no crumbled corner, but continued crumbled border */
2125 int c1 = (dir == 2 || dir == 3 ? TILESIZE - crumbled_border_size : 0);
2126 int c2 = (i == 1 ? TILESIZE - crumbled_border_size : 0);
2127 int b1 = (i == 1 ? crumbled_border_size :
2128 TILESIZE - 2 * crumbled_border_size);
2130 width = crumbled_border_size;
2131 height = crumbled_border_size;
2133 if (dir == 1 || dir == 2)
2149 BlitBitmap(src_bitmap, drawto_field,
2150 src_x + bx * TILESIZE_VAR / TILESIZE,
2151 src_y + by * TILESIZE_VAR / TILESIZE,
2152 width * TILESIZE_VAR / TILESIZE,
2153 height * TILESIZE_VAR / TILESIZE,
2154 FX + sx * TILEX_VAR + cx * TILESIZE_VAR / TILESIZE,
2155 FY + sy * TILEY_VAR + cy * TILESIZE_VAR / TILESIZE);
2157 BlitBitmap(src_bitmap, drawto_field, src_x + bx, src_y + by,
2158 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
2163 if (dir == 1 || dir == 2) /* left or right crumbled border */
2165 for (i = -1; i <= 1; i+=2)
2169 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
2172 /* check if neighbour field is of same crumble type */
2173 if (IS_CRUMBLED_TILE(xx, yy, element) &&
2174 graphic_info[graphic].class ==
2175 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
2177 /* no crumbled corner, but continued crumbled border */
2179 width = crumbled_border_size;
2180 height = crumbled_border_size;
2181 cx = (dir == 2 ? TILEX - crumbled_border_size : 0);
2182 cy = (i == 1 ? TILEY - crumbled_border_size : 0);
2184 by = (i == 1 ? crumbled_border_size :
2185 TILEY - 2 * crumbled_border_size);
2187 BlitBitmap(src_bitmap, drawto_field, src_x + bx, src_y + by,
2188 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
2192 else /* top or bottom crumbled border */
2194 for (i = -1; i <= 1; i+=2)
2198 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
2201 /* check if neighbour field is of same crumble type */
2202 if (IS_CRUMBLED_TILE(xx, yy, element) &&
2203 graphic_info[graphic].class ==
2204 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
2206 /* no crumbled corner, but continued crumbled border */
2208 width = crumbled_border_size;
2209 height = crumbled_border_size;
2210 cx = (i == 1 ? TILEX - crumbled_border_size : 0);
2211 cy = (dir == 3 ? TILEY - crumbled_border_size : 0);
2212 bx = (i == 1 ? crumbled_border_size :
2213 TILEX - 2 * crumbled_border_size);
2216 BlitBitmap(src_bitmap, drawto_field, src_x + bx, src_y + by,
2217 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
2224 static void DrawLevelFieldCrumbledExt(int x, int y, int graphic, int frame)
2226 int sx = SCREENX(x), sy = SCREENY(y);
2229 static int xy[4][2] =
2237 if (!IN_LEV_FIELD(x, y))
2240 element = TILE_GFX_ELEMENT(x, y);
2242 /* crumble field itself */
2243 if (IS_CRUMBLED_TILE(x, y, element))
2245 if (!IN_SCR_FIELD(sx, sy))
2248 for (i = 0; i < 4; i++)
2250 int xx = x + xy[i][0];
2251 int yy = y + xy[i][1];
2253 element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
2256 /* check if neighbour field is of same crumble type */
2258 if (IS_CRUMBLED_TILE(xx, yy, element) &&
2259 graphic_info[graphic].class ==
2260 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
2263 if (IS_CRUMBLED_TILE(xx, yy, element))
2267 DrawLevelFieldCrumbledBorders(x, y, graphic, frame, i);
2270 if ((graphic_info[graphic].style & STYLE_INNER_CORNERS) &&
2271 graphic_info[graphic].anim_frames == 2)
2273 for (i = 0; i < 4; i++)
2275 int dx = (i & 1 ? +1 : -1);
2276 int dy = (i & 2 ? +1 : -1);
2278 DrawLevelFieldCrumbledInnerCorners(x, y, dx, dy, graphic);
2282 MarkTileDirty(sx, sy);
2284 else /* center field not crumbled -- crumble neighbour fields */
2286 for (i = 0; i < 4; i++)
2288 int xx = x + xy[i][0];
2289 int yy = y + xy[i][1];
2290 int sxx = sx + xy[i][0];
2291 int syy = sy + xy[i][1];
2293 if (!IN_LEV_FIELD(xx, yy) ||
2294 !IN_SCR_FIELD(sxx, syy))
2297 if (Feld[xx][yy] == EL_ELEMENT_SNAPPING)
2300 element = TILE_GFX_ELEMENT(xx, yy);
2302 if (!IS_CRUMBLED_TILE(xx, yy, element))
2305 graphic = el_act2crm(element, ACTION_DEFAULT);
2307 DrawLevelFieldCrumbledBorders(xx, yy, graphic, 0, 3 - i);
2309 MarkTileDirty(sxx, syy);
2314 void DrawLevelFieldCrumbled(int x, int y)
2318 if (!IN_LEV_FIELD(x, y))
2322 /* !!! CHECK THIS !!! */
2325 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
2326 GFX_CRUMBLED(GfxElement[x][y]))
2329 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
2330 GfxElement[x][y] != EL_UNDEFINED &&
2331 GFX_CRUMBLED(GfxElement[x][y]))
2333 DrawLevelFieldCrumbledDigging(x, y, GfxDir[x][y], GfxFrame[x][y]);
2340 graphic = el_act2crm(TILE_GFX_ELEMENT(x, y), ACTION_DEFAULT);
2342 graphic = el_act2crm(Feld[x][y], ACTION_DEFAULT);
2345 DrawLevelFieldCrumbledExt(x, y, graphic, 0);
2348 void DrawLevelFieldCrumbledDigging(int x, int y, int direction,
2351 int graphic1 = el_act_dir2img(GfxElement[x][y], ACTION_DIGGING, direction);
2352 int graphic2 = el_act_dir2crm(GfxElement[x][y], ACTION_DIGGING, direction);
2353 int frame1 = getGraphicAnimationFrame(graphic1, step_frame);
2354 int frame2 = getGraphicAnimationFrame(graphic2, step_frame);
2355 int sx = SCREENX(x), sy = SCREENY(y);
2357 DrawGraphic(sx, sy, graphic1, frame1);
2358 DrawLevelFieldCrumbledExt(x, y, graphic2, frame2);
2361 void DrawLevelFieldCrumbledNeighbours(int x, int y)
2363 int sx = SCREENX(x), sy = SCREENY(y);
2364 static int xy[4][2] =
2373 for (i = 0; i < 4; i++)
2375 int xx = x + xy[i][0];
2376 int yy = y + xy[i][1];
2377 int sxx = sx + xy[i][0];
2378 int syy = sy + xy[i][1];
2380 if (!IN_LEV_FIELD(xx, yy) ||
2381 !IN_SCR_FIELD(sxx, syy) ||
2382 !GFX_CRUMBLED(Feld[xx][yy]) ||
2386 DrawLevelField(xx, yy);
2390 static int getBorderElement(int x, int y)
2394 { EL_STEELWALL_TOPLEFT, EL_INVISIBLE_STEELWALL_TOPLEFT },
2395 { EL_STEELWALL_TOPRIGHT, EL_INVISIBLE_STEELWALL_TOPRIGHT },
2396 { EL_STEELWALL_BOTTOMLEFT, EL_INVISIBLE_STEELWALL_BOTTOMLEFT },
2397 { EL_STEELWALL_BOTTOMRIGHT, EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
2398 { EL_STEELWALL_VERTICAL, EL_INVISIBLE_STEELWALL_VERTICAL },
2399 { EL_STEELWALL_HORIZONTAL, EL_INVISIBLE_STEELWALL_HORIZONTAL },
2400 { EL_STEELWALL, EL_INVISIBLE_STEELWALL }
2402 int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
2403 int steel_position = (x == -1 && y == -1 ? 0 :
2404 x == lev_fieldx && y == -1 ? 1 :
2405 x == -1 && y == lev_fieldy ? 2 :
2406 x == lev_fieldx && y == lev_fieldy ? 3 :
2407 x == -1 || x == lev_fieldx ? 4 :
2408 y == -1 || y == lev_fieldy ? 5 : 6);
2410 return border[steel_position][steel_type];
2413 void DrawScreenElement(int x, int y, int element)
2415 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
2416 DrawLevelFieldCrumbled(LEVELX(x), LEVELY(y));
2419 void DrawLevelElement(int x, int y, int element)
2421 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
2422 DrawScreenElement(SCREENX(x), SCREENY(y), element);
2425 void DrawScreenField(int x, int y)
2427 int lx = LEVELX(x), ly = LEVELY(y);
2428 int element, content;
2430 if (!IN_LEV_FIELD(lx, ly))
2432 if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
2435 element = getBorderElement(lx, ly);
2437 DrawScreenElement(x, y, element);
2442 element = Feld[lx][ly];
2443 content = Store[lx][ly];
2445 if (IS_MOVING(lx, ly))
2447 int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
2448 boolean cut_mode = NO_CUTTING;
2450 if (element == EL_QUICKSAND_EMPTYING ||
2451 element == EL_QUICKSAND_FAST_EMPTYING ||
2452 element == EL_MAGIC_WALL_EMPTYING ||
2453 element == EL_BD_MAGIC_WALL_EMPTYING ||
2454 element == EL_DC_MAGIC_WALL_EMPTYING ||
2455 element == EL_AMOEBA_DROPPING)
2456 cut_mode = CUT_ABOVE;
2457 else if (element == EL_QUICKSAND_FILLING ||
2458 element == EL_QUICKSAND_FAST_FILLING ||
2459 element == EL_MAGIC_WALL_FILLING ||
2460 element == EL_BD_MAGIC_WALL_FILLING ||
2461 element == EL_DC_MAGIC_WALL_FILLING)
2462 cut_mode = CUT_BELOW;
2465 if (lx == 9 && ly == 1)
2466 printf("::: %s [%d] [%d, %d] [%d]\n",
2467 EL_NAME(TILE_GFX_ELEMENT(lx, ly)),
2468 el_act2crm(TILE_GFX_ELEMENT(lx, ly), ACTION_DEFAULT),
2469 element_info[EL_QUICKSAND_EMPTYING].graphic[ACTION_DEFAULT],
2470 element_info[EL_QUICKSAND_EMPTYING].crumbled[ACTION_DEFAULT],
2471 GFX_CRUMBLED(TILE_GFX_ELEMENT(lx, ly)));
2474 if (cut_mode == CUT_ABOVE)
2476 DrawScreenElement(x, y, element);
2478 DrawScreenElementShifted(x, y, 0, 0, element, NO_CUTTING);
2481 DrawScreenElement(x, y, EL_EMPTY);
2484 DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
2485 else if (cut_mode == NO_CUTTING)
2486 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
2489 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
2492 if (cut_mode == CUT_BELOW &&
2493 IN_LEV_FIELD(lx, ly + 1) && IN_SCR_FIELD(x, y + 1))
2494 DrawLevelElement(lx, ly + 1, element);
2498 if (content == EL_ACID)
2500 int dir = MovDir[lx][ly];
2501 int newlx = lx + (dir == MV_LEFT ? -1 : dir == MV_RIGHT ? +1 : 0);
2502 int newly = ly + (dir == MV_UP ? -1 : dir == MV_DOWN ? +1 : 0);
2504 DrawLevelElementThruMask(newlx, newly, EL_ACID);
2507 else if (IS_BLOCKED(lx, ly))
2512 boolean cut_mode = NO_CUTTING;
2513 int element_old, content_old;
2515 Blocked2Moving(lx, ly, &oldx, &oldy);
2518 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
2519 MovDir[oldx][oldy] == MV_RIGHT);
2521 element_old = Feld[oldx][oldy];
2522 content_old = Store[oldx][oldy];
2524 if (element_old == EL_QUICKSAND_EMPTYING ||
2525 element_old == EL_QUICKSAND_FAST_EMPTYING ||
2526 element_old == EL_MAGIC_WALL_EMPTYING ||
2527 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
2528 element_old == EL_DC_MAGIC_WALL_EMPTYING ||
2529 element_old == EL_AMOEBA_DROPPING)
2530 cut_mode = CUT_ABOVE;
2532 DrawScreenElement(x, y, EL_EMPTY);
2535 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
2537 else if (cut_mode == NO_CUTTING)
2538 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
2541 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
2544 else if (IS_DRAWABLE(element))
2545 DrawScreenElement(x, y, element);
2547 DrawScreenElement(x, y, EL_EMPTY);
2550 void DrawLevelField(int x, int y)
2552 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
2553 DrawScreenField(SCREENX(x), SCREENY(y));
2554 else if (IS_MOVING(x, y))
2558 Moving2Blocked(x, y, &newx, &newy);
2559 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
2560 DrawScreenField(SCREENX(newx), SCREENY(newy));
2562 else if (IS_BLOCKED(x, y))
2566 Blocked2Moving(x, y, &oldx, &oldy);
2567 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
2568 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
2572 void DrawMiniElement(int x, int y, int element)
2576 graphic = el2edimg(element);
2577 DrawMiniGraphic(x, y, graphic);
2580 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
2582 int x = sx + scroll_x, y = sy + scroll_y;
2584 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
2585 DrawMiniElement(sx, sy, EL_EMPTY);
2586 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
2587 DrawMiniElement(sx, sy, Feld[x][y]);
2589 DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
2592 void DrawEnvelopeBackgroundTiles(int graphic, int startx, int starty,
2593 int x, int y, int xsize, int ysize,
2594 int tile_width, int tile_height)
2598 int dst_x = startx + x * tile_width;
2599 int dst_y = starty + y * tile_height;
2600 int width = graphic_info[graphic].width;
2601 int height = graphic_info[graphic].height;
2602 int inner_width_raw = MAX(width - 2 * tile_width, tile_width);
2603 int inner_height_raw = MAX(height - 2 * tile_height, tile_height);
2604 int inner_width = inner_width_raw - (inner_width_raw % tile_width);
2605 int inner_height = inner_height_raw - (inner_height_raw % tile_height);
2606 int inner_sx = (width >= 3 * tile_width ? tile_width : 0);
2607 int inner_sy = (height >= 3 * tile_height ? tile_height : 0);
2608 boolean draw_masked = graphic_info[graphic].draw_masked;
2610 getFixedGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
2612 if (src_bitmap == NULL || width < tile_width || height < tile_height)
2614 ClearRectangle(drawto, dst_x, dst_y, tile_width, tile_height);
2618 src_x += (x == 0 ? 0 : x == xsize - 1 ? width - tile_width :
2619 inner_sx + (x - 1) * tile_width % inner_width);
2620 src_y += (y == 0 ? 0 : y == ysize - 1 ? height - tile_height :
2621 inner_sy + (y - 1) * tile_height % inner_height);
2625 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
2626 dst_x - src_x, dst_y - src_y);
2627 BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, tile_width, tile_height,
2631 BlitBitmap(src_bitmap, drawto, src_x, src_y, tile_width, tile_height,
2635 void DrawEnvelopeBackground(int graphic, int startx, int starty,
2636 int x, int y, int xsize, int ysize, int font_nr)
2638 int font_width = getFontWidth(font_nr);
2639 int font_height = getFontHeight(font_nr);
2641 DrawEnvelopeBackgroundTiles(graphic, startx, starty, x, y, xsize, ysize,
2642 font_width, font_height);
2645 void AnimateEnvelope(int envelope_nr, int anim_mode, int action)
2647 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2648 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
2649 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
2650 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2651 boolean no_delay = (tape.warp_forward);
2652 unsigned int anim_delay = 0;
2653 int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
2654 int anim_delay_value = (no_delay ? 0 : frame_delay_value);
2655 int font_nr = FONT_ENVELOPE_1 + envelope_nr;
2656 int font_width = getFontWidth(font_nr);
2657 int font_height = getFontHeight(font_nr);
2658 int max_xsize = level.envelope[envelope_nr].xsize;
2659 int max_ysize = level.envelope[envelope_nr].ysize;
2660 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
2661 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
2662 int xend = max_xsize;
2663 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
2664 int xstep = (xstart < xend ? 1 : 0);
2665 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
2668 for (x = xstart, y = ystart; x <= xend && y <= yend; x += xstep, y += ystep)
2670 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
2671 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
2672 int sx = SX + (SXSIZE - xsize * font_width) / 2;
2673 int sy = SY + (SYSIZE - ysize * font_height) / 2;
2676 SetDrawtoField(DRAW_BUFFERED);
2679 BlitScreenToBitmap(backbuffer);
2681 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
2684 SetDrawtoField(DRAW_BACKBUFFER);
2686 for (yy = 0; yy < ysize; yy++)
2687 for (xx = 0; xx < xsize; xx++)
2688 DrawEnvelopeBackground(graphic, sx, sy, xx, yy, xsize, ysize, font_nr);
2691 DrawTextBuffer(sx + font_width, sy + font_height,
2692 level.envelope[envelope_nr].text, font_nr, max_xsize,
2693 xsize - 2, ysize - 2, 0, mask_mode,
2694 level.envelope[envelope_nr].autowrap,
2695 level.envelope[envelope_nr].centered, FALSE);
2697 DrawTextToTextArea(sx + font_width, sy + font_height,
2698 level.envelope[envelope_nr].text, font_nr, max_xsize,
2699 xsize - 2, ysize - 2, mask_mode);
2702 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
2705 WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
2709 void ShowEnvelope(int envelope_nr)
2711 int element = EL_ENVELOPE_1 + envelope_nr;
2712 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2713 int sound_opening = element_info[element].sound[ACTION_OPENING];
2714 int sound_closing = element_info[element].sound[ACTION_CLOSING];
2715 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2716 boolean no_delay = (tape.warp_forward);
2717 int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
2718 int wait_delay_value = (no_delay ? 0 : normal_delay_value);
2719 int anim_mode = graphic_info[graphic].anim_mode;
2720 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
2721 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
2723 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
2725 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
2727 if (anim_mode == ANIM_DEFAULT)
2728 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_OPENING);
2730 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_OPENING);
2733 Delay(wait_delay_value);
2735 WaitForEventToContinue();
2737 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
2739 if (anim_mode != ANIM_NONE)
2740 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_CLOSING);
2742 if (anim_mode == ANIM_DEFAULT)
2743 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_CLOSING);
2745 game.envelope_active = FALSE;
2747 SetDrawtoField(DRAW_BUFFERED);
2749 redraw_mask |= REDRAW_FIELD;
2753 static void setRequestPosition(int *x, int *y, boolean add_border_size)
2755 int border_size = request.border_size;
2756 int sx_center = (request.x != -1 ? request.x : SX + SXSIZE / 2);
2757 int sy_center = (request.y != -1 ? request.y : SY + SYSIZE / 2);
2758 int sx = sx_center - request.width / 2;
2759 int sy = sy_center - request.height / 2;
2761 if (add_border_size)
2771 void DrawEnvelopeRequest(char *text)
2773 char *text_final = text;
2774 char *text_door_style = NULL;
2775 int graphic = IMG_BACKGROUND_REQUEST;
2776 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
2777 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
2778 int font_nr = FONT_REQUEST;
2779 int font_width = getFontWidth(font_nr);
2780 int font_height = getFontHeight(font_nr);
2781 int border_size = request.border_size;
2782 int line_spacing = request.line_spacing;
2783 int line_height = font_height + line_spacing;
2784 int text_width = request.width - 2 * border_size;
2785 int text_height = request.height - 2 * border_size;
2786 int line_length = text_width / font_width;
2787 int max_lines = text_height / line_height;
2788 int width = request.width;
2789 int height = request.height;
2790 int tile_size = request.step_offset;
2791 int x_steps = width / tile_size;
2792 int y_steps = height / tile_size;
2796 if (request.wrap_single_words)
2798 char *src_text_ptr, *dst_text_ptr;
2800 text_door_style = checked_malloc(2 * strlen(text) + 1);
2802 src_text_ptr = text;
2803 dst_text_ptr = text_door_style;
2805 while (*src_text_ptr)
2807 if (*src_text_ptr == ' ' ||
2808 *src_text_ptr == '?' ||
2809 *src_text_ptr == '!')
2810 *dst_text_ptr++ = '\n';
2812 if (*src_text_ptr != ' ')
2813 *dst_text_ptr++ = *src_text_ptr;
2818 *dst_text_ptr = '\0';
2820 text_final = text_door_style;
2823 setRequestPosition(&sx, &sy, FALSE);
2825 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
2827 for (y = 0; y < y_steps; y++)
2828 for (x = 0; x < x_steps; x++)
2829 DrawEnvelopeBackgroundTiles(graphic, sx, sy,
2830 x, y, x_steps, y_steps,
2831 tile_size, tile_size);
2833 DrawTextBuffer(sx + border_size, sy + border_size, text_final, font_nr,
2834 line_length, -1, max_lines, line_spacing, mask_mode,
2835 request.autowrap, request.centered, FALSE);
2837 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
2838 RedrawGadget(tool_gadget[i]);
2840 // store readily prepared envelope request for later use when animating
2841 BlitBitmap(backbuffer, bitmap_db_cross, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2845 BlitBitmap(bitmap_db_store, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2846 BlitBitmap(bitmap_db_cross, backbuffer, sx, sy, width, height, sx, sy);
2848 redraw_mask = REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
2853 BlitBitmap(bitmap_db_store, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2855 redraw_mask = REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
2861 if (text_door_style)
2862 free(text_door_style);
2867 void AnimateEnvelopeRequest(int anim_mode, int action)
2869 int graphic = IMG_BACKGROUND_REQUEST;
2870 boolean draw_masked = graphic_info[graphic].draw_masked;
2872 int delay_value_normal = request.step_delay;
2873 int delay_value_fast = delay_value_normal / 2;
2875 int delay_value_normal = GameFrameDelay;
2876 int delay_value_fast = FfwdFrameDelay;
2878 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2879 boolean no_delay = (tape.warp_forward);
2880 int delay_value = (ffwd_delay ? delay_value_fast : delay_value_normal);
2881 int anim_delay_value = (no_delay ? 0 : delay_value + 500 * 0);
2882 unsigned int anim_delay = 0;
2884 int width = request.width;
2885 int height = request.height;
2886 int tile_size = request.step_offset;
2887 int max_xsize = width / tile_size;
2888 int max_ysize = height / tile_size;
2889 int max_xsize_inner = max_xsize - 2;
2890 int max_ysize_inner = max_ysize - 2;
2892 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize_inner : 0);
2893 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize_inner : 0);
2894 int xend = max_xsize_inner;
2895 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize_inner : 0);
2896 int xstep = (xstart < xend ? 1 : 0);
2897 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
2900 for (x = xstart, y = ystart; x <= xend && y <= yend; x += xstep, y += ystep)
2902 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
2903 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
2904 int sx_center = (request.x != -1 ? request.x : SX + SXSIZE / 2);
2905 int sy_center = (request.y != -1 ? request.y : SY + SYSIZE / 2);
2906 int src_x = sx_center - width / 2;
2907 int src_y = sy_center - height / 2;
2908 int dst_x = sx_center - xsize * tile_size / 2;
2909 int dst_y = sy_center - ysize * tile_size / 2;
2910 int xsize_size_left = (xsize - 1) * tile_size;
2911 int ysize_size_top = (ysize - 1) * tile_size;
2912 int max_xsize_pos = (max_xsize - 1) * tile_size;
2913 int max_ysize_pos = (max_ysize - 1) * tile_size;
2916 BlitBitmap(bitmap_db_store, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2919 for (yy = 0; yy < 2; yy++)
2921 for (xx = 0; xx < 2; xx++)
2923 int src_xx = src_x + xx * max_xsize_pos;
2924 int src_yy = src_y + yy * max_ysize_pos;
2925 int dst_xx = dst_x + xx * xsize_size_left;
2926 int dst_yy = dst_y + yy * ysize_size_top;
2927 int xx_size = (xx ? tile_size : xsize_size_left);
2928 int yy_size = (yy ? tile_size : ysize_size_top);
2931 BlitBitmapMasked(bitmap_db_cross, backbuffer,
2932 src_xx, src_yy, xx_size, yy_size, dst_xx, dst_yy);
2934 BlitBitmap(bitmap_db_cross, backbuffer,
2935 src_xx, src_yy, xx_size, yy_size, dst_xx, dst_yy);
2939 BlitBitmap(bitmap_db_cross, backbuffer,
2941 xsize_size_left, ysize_size_top,
2943 BlitBitmap(bitmap_db_cross, backbuffer,
2944 src_x + max_xsize_pos, src_y,
2945 tile_size, ysize_size_top,
2946 dst_x + xsize_size_left, dst_y);
2947 BlitBitmap(bitmap_db_cross, backbuffer,
2948 src_x, src_y + max_ysize_pos,
2949 xsize_size_left, tile_size,
2950 dst_x, dst_y + ysize_size_top);
2951 BlitBitmap(bitmap_db_cross, backbuffer,
2952 src_x + max_xsize_pos, src_y + max_ysize_pos,
2953 tile_size, tile_size,
2954 dst_x + xsize_size_left, dst_y + ysize_size_top);
2958 redraw_mask = REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
2959 // redraw_mask |= REDRAW_ALL | REDRAW_FROM_BACKBUFFER;
2961 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
2971 WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
2977 void AnimateEnvelopeRequest(char *text, int anim_mode, int action)
2980 int envelope_nr = 0;
2983 int graphic = IMG_BACKGROUND_REQUEST;
2985 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2987 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
2988 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
2989 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2990 boolean no_delay = (tape.warp_forward);
2991 unsigned int anim_delay = 0;
2992 int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
2993 int anim_delay_value = (no_delay ? 0 : frame_delay_value + 500 * 0);
2995 int max_word_len = maxWordLengthInString(text);
2996 int font_nr = (max_word_len > 7 ? FONT_TEXT_1 : FONT_TEXT_2);
2998 int font_nr = FONT_ENVELOPE_1 + envelope_nr;
3000 int font_width = getFontWidth(font_nr);
3001 int font_height = getFontHeight(font_nr);
3002 int line_spacing = 2 * 1;
3006 int max_xsize = DXSIZE / font_width;
3007 // int max_ysize = DYSIZE / font_height;
3008 int max_ysize = DYSIZE / (font_height + line_spacing);
3010 int max_xsize = 7; /* tools.c: MAX_REQUEST_LINE_FONT1_LEN == 7 */
3011 int max_ysize = 13; /* tools.c: MAX_REQUEST_LINES == 13 */
3015 int max_xsize = level.envelope[envelope_nr].xsize;
3016 int max_ysize = level.envelope[envelope_nr].ysize;
3018 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
3019 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
3020 int xend = max_xsize;
3021 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
3022 int xstep = (xstart < xend ? 1 : 0);
3023 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
3028 char *text_copy = getStringCopy(text);
3031 font_nr = FONT_TEXT_2;
3033 if (maxWordLengthInString(text) > 7) /* MAX_REQUEST_LINE_FONT1_LEN == 7 */
3035 max_xsize = 10; /* tools.c: MAX_REQUEST_LINE_FONT2_LEN == 10 */
3036 font_nr = FONT_TEXT_1;
3039 int max_word_len = 0;
3041 char *text_copy = getStringCopy(text);
3043 font_nr = FONT_TEXT_2;
3045 for (text_ptr = text; *text_ptr; text_ptr++)
3047 max_word_len = (*text_ptr != ' ' ? max_word_len + 1 : 0);
3049 if (max_word_len > 7) /* tools.c: MAX_REQUEST_LINE_FONT1_LEN == 7 */
3051 max_xsize = 10; /* tools.c: MAX_REQUEST_LINE_FONT2_LEN == 10 */
3052 font_nr = FONT_TEXT_1;
3061 for (text_ptr = text_copy; *text_ptr; text_ptr++)
3062 if (*text_ptr == ' ')
3067 dDX = SX + (SXSIZE - DXSIZE) / 2 - DX;
3068 dDY = SY + (SYSIZE - DYSIZE) / 2 - DY;
3070 dDX = SX + SXSIZE / 2 - max_xsize * font_width / 2 - DX;
3071 dDY = SY + SYSIZE / 2 - max_ysize * font_height / 2 - DY;
3074 for (x = xstart, y = ystart; x <= xend && y <= yend; x += xstep, y += ystep)
3076 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
3077 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
3078 int sx = SX + (SXSIZE - xsize * font_width) / 2;
3079 // int sy = SX + (SYSIZE - ysize * font_height) / 2;
3080 int sy = SY + (SYSIZE - ysize * (font_height + line_spacing)) / 2;
3084 BlitBitmap(bitmap_db_store, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
3086 SetDrawtoField(DRAW_BUFFERED);
3089 BlitScreenToBitmap(backbuffer);
3091 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
3094 SetDrawtoField(DRAW_BACKBUFFER);
3097 for (yy = 0; yy < ysize; yy++)
3098 for (xx = 0; xx < xsize; xx++)
3099 DrawEnvelopeBackgroundTiles(graphic, sx, sy, xx, yy, xsize, ysize,
3100 getFontWidth(font_nr),
3101 getFontHeight(font_nr) + line_spacing);
3106 DrawTextBuffer(sx + font_width, sy + font_height + 8,
3107 text_copy, font_nr, max_xsize,
3108 xsize - 2, ysize - 2, line_spacing, mask_mode,
3109 FALSE, TRUE, FALSE);
3111 DrawTextBuffer(sx + font_width, sy + font_height,
3112 level.envelope[envelope_nr].text, font_nr, max_xsize,
3113 xsize - 2, ysize - 2, 0, mask_mode,
3114 level.envelope[envelope_nr].autowrap,
3115 level.envelope[envelope_nr].centered, FALSE);
3119 DrawTextToTextArea(sx + font_width, sy + font_height,
3120 level.envelope[envelope_nr].text, font_nr, max_xsize,
3121 xsize - 2, ysize - 2, mask_mode);
3124 /* copy request gadgets to door backbuffer */
3127 if ((ysize - 2) > 13)
3128 BlitBitmap(bitmap_db_door, drawto,
3129 DOOR_GFX_PAGEX1 + (DXSIZE - (xsize - 2) * font_width) / 2,
3130 DOOR_GFX_PAGEY1 + 13 * font_height,
3131 (xsize - 2) * font_width,
3132 (ysize - 2 - 13) * font_height,
3134 sy + font_height * (1 + 13));
3136 if ((ysize - 2) > 13)
3137 BlitBitmap(bitmap_db_door, drawto,
3138 DOOR_GFX_PAGEX1 + (DXSIZE - (xsize - 2) * font_width) / 2,
3139 DOOR_GFX_PAGEY1 + 11 * (font_height + line_spacing * 0),
3140 (xsize - 2) * font_width,
3141 (ysize - 2 - 13) * (font_height + line_spacing),
3143 sy + (font_height + line_spacing) * (1 + 13));
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));
3156 redraw_mask = REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
3157 // redraw_mask |= REDRAW_ALL | REDRAW_FROM_BACKBUFFER;
3159 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
3169 WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
3179 void ShowEnvelopeRequest(char *text, unsigned int req_state, int action)
3182 int last_game_status = game_status; /* save current game status */
3183 // int last_draw_background_mask = gfx.draw_background_mask;
3186 int graphic = IMG_BACKGROUND_REQUEST;
3187 int sound_opening = SND_REQUEST_OPENING;
3188 int sound_closing = SND_REQUEST_CLOSING;
3190 int envelope_nr = 0;
3191 int element = EL_ENVELOPE_1 + envelope_nr;
3192 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
3193 int sound_opening = element_info[element].sound[ACTION_OPENING];
3194 int sound_closing = element_info[element].sound[ACTION_CLOSING];
3197 boolean ffwd_delay = (tape.playing && tape.fast_forward);
3198 boolean no_delay = (tape.warp_forward);
3199 int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
3200 int wait_delay_value = (no_delay ? 0 : normal_delay_value);
3202 int anim_mode = graphic_info[graphic].anim_mode;
3203 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
3204 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
3206 char *text_copy = getStringCopy(text);
3209 for (text_ptr = text_copy; *text_ptr; text_ptr++)
3210 if (*text_ptr == ' ')
3215 if (game_status == GAME_MODE_PLAYING)
3217 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
3218 BlitScreenToBitmap_EM(backbuffer);
3219 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
3220 BlitScreenToBitmap_SP(backbuffer);
3223 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
3227 SetDrawtoField(DRAW_BACKBUFFER);
3229 // SetDrawBackgroundMask(REDRAW_NONE);
3231 if (action == ACTION_OPENING)
3233 BlitBitmap(backbuffer, bitmap_db_store, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
3236 if (req_state & REQ_ASK)
3238 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
3239 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
3241 else if (req_state & REQ_CONFIRM)
3243 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
3245 else if (req_state & REQ_PLAYER)
3247 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
3248 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
3249 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
3250 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
3255 DrawEnvelopeRequest(text);
3257 DrawEnvelopeRequest(text_copy);
3260 if (game_status != GAME_MODE_MAIN)
3264 /* force DOOR font inside door area */
3265 game_status = GAME_MODE_PSEUDO_DOOR;
3268 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
3270 if (action == ACTION_OPENING)
3272 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
3274 if (anim_mode == ANIM_DEFAULT)
3275 AnimateEnvelopeRequest(ANIM_DEFAULT, ACTION_OPENING);
3277 AnimateEnvelopeRequest(main_anim_mode, ACTION_OPENING);
3281 Delay(wait_delay_value);
3283 WaitForEventToContinue();
3288 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
3290 if (anim_mode != ANIM_NONE)
3291 AnimateEnvelopeRequest(main_anim_mode, ACTION_CLOSING);
3293 if (anim_mode == ANIM_DEFAULT)
3294 AnimateEnvelopeRequest(ANIM_DEFAULT, ACTION_CLOSING);
3297 game.envelope_active = FALSE;
3300 // game_status = last_game_status; /* restore current game status */
3302 if (action == ACTION_CLOSING)
3304 if (game_status != GAME_MODE_MAIN)
3307 BlitBitmap(bitmap_db_store, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
3310 SetDrawtoField(DRAW_BUFFERED);
3313 // SetDrawBackgroundMask(last_draw_background_mask);
3316 redraw_mask = REDRAW_FIELD;
3317 // redraw_mask |= REDRAW_ALL;
3319 redraw_mask |= REDRAW_FIELD;
3323 if (game_status == GAME_MODE_MAIN)
3328 /* (important: after "BackToFront()", but before "SetDrawtoField()") */
3329 game_status = last_game_status; /* restore current game status */
3332 if (action == ACTION_CLOSING &&
3333 game_status == GAME_MODE_PLAYING &&
3334 level.game_engine_type == GAME_ENGINE_TYPE_RND)
3335 SetDrawtoField(DRAW_BUFFERED);
3337 if (game_status == GAME_MODE_PLAYING &&
3338 level.game_engine_type == GAME_ENGINE_TYPE_RND)
3339 SetDrawtoField(DRAW_BUFFERED);
3351 void DrawPreviewElement(int dst_x, int dst_y, int element, int tilesize)
3355 int graphic = el2preimg(element);
3357 getSizedGraphicSource(graphic, 0, tilesize, &src_bitmap, &src_x, &src_y);
3358 BlitBitmap(src_bitmap, drawto, src_x, src_y, tilesize, tilesize, dst_x,dst_y);
3366 SetMainBackgroundImage(IMG_BACKGROUND_PLAYING);
3367 SetDrawBackgroundMask(REDRAW_FIELD);
3369 SetDrawBackgroundMask(REDRAW_NONE);
3374 for (x = BX1; x <= BX2; x++)
3375 for (y = BY1; y <= BY2; y++)
3376 DrawScreenField(x, y);
3378 redraw_mask |= REDRAW_FIELD;
3381 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
3385 for (x = 0; x < size_x; x++)
3386 for (y = 0; y < size_y; y++)
3387 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
3389 redraw_mask |= REDRAW_FIELD;
3392 static void DrawPreviewLevelPlayfieldExt(int from_x, int from_y)
3394 boolean show_level_border = (BorderElement != EL_EMPTY);
3395 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
3396 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
3397 int tile_size = preview.tile_size;
3398 int preview_width = preview.xsize * tile_size;
3399 int preview_height = preview.ysize * tile_size;
3400 int real_preview_xsize = MIN(level_xsize, preview.xsize);
3401 int real_preview_ysize = MIN(level_ysize, preview.ysize);
3402 int dst_x = SX + ALIGNED_XPOS(preview.x, preview_width, preview.align);
3403 int dst_y = SY + ALIGNED_YPOS(preview.y, preview_height, preview.valign);
3406 DrawBackground(dst_x, dst_y, preview_width, preview_height);
3408 dst_x += (preview_width - real_preview_xsize * tile_size) / 2;
3409 dst_y += (preview_height - real_preview_ysize * tile_size) / 2;
3411 for (x = 0; x < real_preview_xsize; x++)
3413 for (y = 0; y < real_preview_ysize; y++)
3415 int lx = from_x + x + (show_level_border ? -1 : 0);
3416 int ly = from_y + y + (show_level_border ? -1 : 0);
3417 int element = (IN_LEV_FIELD(lx, ly) ? level.field[lx][ly] :
3418 getBorderElement(lx, ly));
3420 DrawPreviewElement(dst_x + x * tile_size, dst_y + y * tile_size,
3421 element, tile_size);
3425 redraw_mask |= REDRAW_MICROLEVEL;
3428 #define MICROLABEL_EMPTY 0
3429 #define MICROLABEL_LEVEL_NAME 1
3430 #define MICROLABEL_LEVEL_AUTHOR_HEAD 2
3431 #define MICROLABEL_LEVEL_AUTHOR 3
3432 #define MICROLABEL_IMPORTED_FROM_HEAD 4
3433 #define MICROLABEL_IMPORTED_FROM 5
3434 #define MICROLABEL_IMPORTED_BY_HEAD 6
3435 #define MICROLABEL_IMPORTED_BY 7
3437 static int getMaxTextLength(struct TextPosInfo *pos, int font_nr)
3439 int max_text_width = SXSIZE;
3440 int font_width = getFontWidth(font_nr);
3442 if (pos->align == ALIGN_CENTER)
3443 max_text_width = (pos->x < SXSIZE / 2 ? pos->x * 2 : (SXSIZE - pos->x) * 2);
3444 else if (pos->align == ALIGN_RIGHT)
3445 max_text_width = pos->x;
3447 max_text_width = SXSIZE - pos->x;
3449 return max_text_width / font_width;
3452 static void DrawPreviewLevelLabelExt(int mode)
3454 struct TextPosInfo *pos = &menu.main.text.level_info_2;
3455 char label_text[MAX_OUTPUT_LINESIZE + 1];
3456 int max_len_label_text;
3458 int font_nr = pos->font;
3461 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
3462 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
3463 mode == MICROLABEL_IMPORTED_BY_HEAD)
3464 font_nr = pos->font_alt;
3466 int font_nr = FONT_TEXT_2;
3469 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
3470 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
3471 mode == MICROLABEL_IMPORTED_BY_HEAD)
3472 font_nr = FONT_TEXT_3;
3476 max_len_label_text = getMaxTextLength(pos, font_nr);
3478 max_len_label_text = SXSIZE / getFontWidth(font_nr);
3482 if (pos->size != -1)
3483 max_len_label_text = pos->size;
3486 for (i = 0; i < max_len_label_text; i++)
3487 label_text[i] = ' ';
3488 label_text[max_len_label_text] = '\0';
3490 if (strlen(label_text) > 0)
3493 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
3495 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
3496 int lypos = MICROLABEL2_YPOS;
3498 DrawText(lxpos, lypos, label_text, font_nr);
3503 (mode == MICROLABEL_LEVEL_NAME ? level.name :
3504 mode == MICROLABEL_LEVEL_AUTHOR_HEAD ? "created by" :
3505 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
3506 mode == MICROLABEL_IMPORTED_FROM_HEAD ? "imported from" :
3507 mode == MICROLABEL_IMPORTED_FROM ? leveldir_current->imported_from :
3508 mode == MICROLABEL_IMPORTED_BY_HEAD ? "imported by" :
3509 mode == MICROLABEL_IMPORTED_BY ? leveldir_current->imported_by :""),
3510 max_len_label_text);
3511 label_text[max_len_label_text] = '\0';
3513 if (strlen(label_text) > 0)
3516 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
3518 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
3519 int lypos = MICROLABEL2_YPOS;
3521 DrawText(lxpos, lypos, label_text, font_nr);
3525 redraw_mask |= REDRAW_MICROLEVEL;
3528 static void DrawPreviewLevelExt(boolean restart)
3530 static unsigned int scroll_delay = 0;
3531 static unsigned int label_delay = 0;
3532 static int from_x, from_y, scroll_direction;
3533 static int label_state, label_counter;
3534 unsigned int scroll_delay_value = preview.step_delay;
3535 boolean show_level_border = (BorderElement != EL_EMPTY);
3536 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
3537 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
3538 int last_game_status = game_status; /* save current game status */
3541 /* force PREVIEW font on preview level */
3542 game_status = GAME_MODE_PSEUDO_PREVIEW;
3550 if (preview.anim_mode == ANIM_CENTERED)
3552 if (level_xsize > preview.xsize)
3553 from_x = (level_xsize - preview.xsize) / 2;
3554 if (level_ysize > preview.ysize)
3555 from_y = (level_ysize - preview.ysize) / 2;
3558 from_x += preview.xoffset;
3559 from_y += preview.yoffset;
3561 scroll_direction = MV_RIGHT;
3565 DrawPreviewLevelPlayfieldExt(from_x, from_y);
3566 DrawPreviewLevelLabelExt(label_state);
3568 /* initialize delay counters */
3569 DelayReached(&scroll_delay, 0);
3570 DelayReached(&label_delay, 0);
3572 if (leveldir_current->name)
3574 struct TextPosInfo *pos = &menu.main.text.level_info_1;
3575 char label_text[MAX_OUTPUT_LINESIZE + 1];
3577 int font_nr = pos->font;
3579 int font_nr = FONT_TEXT_1;
3582 int max_len_label_text = getMaxTextLength(pos, font_nr);
3584 int max_len_label_text = SXSIZE / getFontWidth(font_nr);
3592 if (pos->size != -1)
3593 max_len_label_text = pos->size;
3596 strncpy(label_text, leveldir_current->name, max_len_label_text);
3597 label_text[max_len_label_text] = '\0';
3600 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
3602 lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
3603 lypos = SY + MICROLABEL1_YPOS;
3605 DrawText(lxpos, lypos, label_text, font_nr);
3609 game_status = last_game_status; /* restore current game status */
3614 /* scroll preview level, if needed */
3615 if (preview.anim_mode != ANIM_NONE &&
3616 (level_xsize > preview.xsize || level_ysize > preview.ysize) &&
3617 DelayReached(&scroll_delay, scroll_delay_value))
3619 switch (scroll_direction)
3624 from_x -= preview.step_offset;
3625 from_x = (from_x < 0 ? 0 : from_x);
3628 scroll_direction = MV_UP;
3632 if (from_x < level_xsize - preview.xsize)
3634 from_x += preview.step_offset;
3635 from_x = (from_x > level_xsize - preview.xsize ?
3636 level_xsize - preview.xsize : from_x);
3639 scroll_direction = MV_DOWN;
3645 from_y -= preview.step_offset;
3646 from_y = (from_y < 0 ? 0 : from_y);
3649 scroll_direction = MV_RIGHT;
3653 if (from_y < level_ysize - preview.ysize)
3655 from_y += preview.step_offset;
3656 from_y = (from_y > level_ysize - preview.ysize ?
3657 level_ysize - preview.ysize : from_y);
3660 scroll_direction = MV_LEFT;
3667 DrawPreviewLevelPlayfieldExt(from_x, from_y);
3670 /* !!! THIS ALL SUCKS -- SHOULD BE CLEANLY REWRITTEN !!! */
3671 /* redraw micro level label, if needed */
3672 if (!strEqual(level.name, NAMELESS_LEVEL_NAME) &&
3673 !strEqual(level.author, ANONYMOUS_NAME) &&
3674 !strEqual(level.author, leveldir_current->name) &&
3675 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
3677 int max_label_counter = 23;
3679 if (leveldir_current->imported_from != NULL &&
3680 strlen(leveldir_current->imported_from) > 0)
3681 max_label_counter += 14;
3682 if (leveldir_current->imported_by != NULL &&
3683 strlen(leveldir_current->imported_by) > 0)
3684 max_label_counter += 14;
3686 label_counter = (label_counter + 1) % max_label_counter;
3687 label_state = (label_counter >= 0 && label_counter <= 7 ?
3688 MICROLABEL_LEVEL_NAME :
3689 label_counter >= 9 && label_counter <= 12 ?
3690 MICROLABEL_LEVEL_AUTHOR_HEAD :
3691 label_counter >= 14 && label_counter <= 21 ?
3692 MICROLABEL_LEVEL_AUTHOR :
3693 label_counter >= 23 && label_counter <= 26 ?
3694 MICROLABEL_IMPORTED_FROM_HEAD :
3695 label_counter >= 28 && label_counter <= 35 ?
3696 MICROLABEL_IMPORTED_FROM :
3697 label_counter >= 37 && label_counter <= 40 ?
3698 MICROLABEL_IMPORTED_BY_HEAD :
3699 label_counter >= 42 && label_counter <= 49 ?
3700 MICROLABEL_IMPORTED_BY : MICROLABEL_EMPTY);
3702 if (leveldir_current->imported_from == NULL &&
3703 (label_state == MICROLABEL_IMPORTED_FROM_HEAD ||
3704 label_state == MICROLABEL_IMPORTED_FROM))
3705 label_state = (label_state == MICROLABEL_IMPORTED_FROM_HEAD ?
3706 MICROLABEL_IMPORTED_BY_HEAD : MICROLABEL_IMPORTED_BY);
3708 DrawPreviewLevelLabelExt(label_state);
3711 game_status = last_game_status; /* restore current game status */
3714 void DrawPreviewLevelInitial()
3716 DrawPreviewLevelExt(TRUE);
3719 void DrawPreviewLevelAnimation()
3721 DrawPreviewLevelExt(FALSE);
3724 inline void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
3725 int graphic, int sync_frame, int mask_mode)
3727 int frame = getGraphicAnimationFrame(graphic, sync_frame);
3729 if (mask_mode == USE_MASKING)
3730 DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
3732 DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
3735 inline void DrawFixedGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
3736 int graphic, int sync_frame,
3739 int frame = getGraphicAnimationFrame(graphic, sync_frame);
3741 if (mask_mode == USE_MASKING)
3742 DrawFixedGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
3744 DrawFixedGraphicExt(dst_bitmap, x, y, graphic, frame);
3747 inline void DrawGraphicAnimation(int x, int y, int graphic)
3749 int lx = LEVELX(x), ly = LEVELY(y);
3751 if (!IN_SCR_FIELD(x, y))
3755 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR,
3756 graphic, GfxFrame[lx][ly], NO_MASKING);
3758 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
3759 graphic, GfxFrame[lx][ly], NO_MASKING);
3761 MarkTileDirty(x, y);
3764 inline void DrawFixedGraphicAnimation(int x, int y, int graphic)
3766 int lx = LEVELX(x), ly = LEVELY(y);
3768 if (!IN_SCR_FIELD(x, y))
3771 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
3772 graphic, GfxFrame[lx][ly], NO_MASKING);
3773 MarkTileDirty(x, y);
3776 void DrawLevelGraphicAnimation(int x, int y, int graphic)
3778 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
3781 void DrawLevelElementAnimation(int x, int y, int element)
3783 int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
3785 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
3788 inline void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
3790 int sx = SCREENX(x), sy = SCREENY(y);
3792 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
3795 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
3798 DrawGraphicAnimation(sx, sy, graphic);
3801 if (GFX_CRUMBLED(TILE_GFX_ELEMENT(x, y)))
3802 DrawLevelFieldCrumbled(x, y);
3804 if (GFX_CRUMBLED(Feld[x][y]))
3805 DrawLevelFieldCrumbled(x, y);
3809 void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
3811 int sx = SCREENX(x), sy = SCREENY(y);
3814 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
3817 graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
3819 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
3822 DrawGraphicAnimation(sx, sy, graphic);
3824 if (GFX_CRUMBLED(element))
3825 DrawLevelFieldCrumbled(x, y);
3828 static int getPlayerGraphic(struct PlayerInfo *player, int move_dir)
3830 if (player->use_murphy)
3832 /* this works only because currently only one player can be "murphy" ... */
3833 static int last_horizontal_dir = MV_LEFT;
3834 int graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir);
3836 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3837 last_horizontal_dir = move_dir;
3839 if (graphic == IMG_SP_MURPHY) /* undefined => use special graphic */
3841 int direction = (player->is_snapping ? move_dir : last_horizontal_dir);
3843 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
3849 return el_act_dir2img(player->artwork_element, player->GfxAction,move_dir);
3852 static boolean equalGraphics(int graphic1, int graphic2)
3854 struct GraphicInfo *g1 = &graphic_info[graphic1];
3855 struct GraphicInfo *g2 = &graphic_info[graphic2];
3857 return (g1->bitmap == g2->bitmap &&
3858 g1->src_x == g2->src_x &&
3859 g1->src_y == g2->src_y &&
3860 g1->anim_frames == g2->anim_frames &&
3861 g1->anim_delay == g2->anim_delay &&
3862 g1->anim_mode == g2->anim_mode);
3865 void DrawAllPlayers()
3869 for (i = 0; i < MAX_PLAYERS; i++)
3870 if (stored_player[i].active)
3871 DrawPlayer(&stored_player[i]);
3874 void DrawPlayerField(int x, int y)
3876 if (!IS_PLAYER(x, y))
3879 DrawPlayer(PLAYERINFO(x, y));
3882 #define DRAW_PLAYER_OVER_PUSHED_ELEMENT 1
3884 void DrawPlayer(struct PlayerInfo *player)
3886 int jx = player->jx;
3887 int jy = player->jy;
3888 int move_dir = player->MovDir;
3889 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? +1 : 0);
3890 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? +1 : 0);
3891 int last_jx = (player->is_moving ? jx - dx : jx);
3892 int last_jy = (player->is_moving ? jy - dy : jy);
3893 int next_jx = jx + dx;
3894 int next_jy = jy + dy;
3895 boolean player_is_moving = (player->MovPos ? TRUE : FALSE);
3896 boolean player_is_opaque = FALSE;
3897 int sx = SCREENX(jx), sy = SCREENY(jy);
3898 int sxx = 0, syy = 0;
3899 int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
3901 int action = ACTION_DEFAULT;
3902 int last_player_graphic = getPlayerGraphic(player, move_dir);
3903 int last_player_frame = player->Frame;
3906 /* GfxElement[][] is set to the element the player is digging or collecting;
3907 remove also for off-screen player if the player is not moving anymore */
3908 if (IN_LEV_FIELD(jx, jy) && !player_is_moving)
3909 GfxElement[jx][jy] = EL_UNDEFINED;
3911 if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
3915 if (!IN_LEV_FIELD(jx, jy))
3917 printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
3918 printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
3919 printf("DrawPlayerField(): This should never happen!\n");
3924 if (element == EL_EXPLOSION)
3927 action = (player->is_pushing ? ACTION_PUSHING :
3928 player->is_digging ? ACTION_DIGGING :
3929 player->is_collecting ? ACTION_COLLECTING :
3930 player->is_moving ? ACTION_MOVING :
3931 player->is_snapping ? ACTION_SNAPPING :
3932 player->is_dropping ? ACTION_DROPPING :
3933 player->is_waiting ? player->action_waiting : ACTION_DEFAULT);
3935 if (player->is_waiting)
3936 move_dir = player->dir_waiting;
3938 InitPlayerGfxAnimation(player, action, move_dir);
3940 /* ----------------------------------------------------------------------- */
3941 /* draw things in the field the player is leaving, if needed */
3942 /* ----------------------------------------------------------------------- */
3944 if (player->is_moving)
3946 if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
3948 DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
3950 if (last_element == EL_DYNAMITE_ACTIVE ||
3951 last_element == EL_EM_DYNAMITE_ACTIVE ||
3952 last_element == EL_SP_DISK_RED_ACTIVE)
3953 DrawDynamite(last_jx, last_jy);
3955 DrawLevelFieldThruMask(last_jx, last_jy);
3957 else if (last_element == EL_DYNAMITE_ACTIVE ||
3958 last_element == EL_EM_DYNAMITE_ACTIVE ||
3959 last_element == EL_SP_DISK_RED_ACTIVE)
3960 DrawDynamite(last_jx, last_jy);
3962 /* !!! this is not enough to prevent flickering of players which are
3963 moving next to each others without a free tile between them -- this
3964 can only be solved by drawing all players layer by layer (first the
3965 background, then the foreground etc.) !!! => TODO */
3966 else if (!IS_PLAYER(last_jx, last_jy))
3967 DrawLevelField(last_jx, last_jy);
3970 DrawLevelField(last_jx, last_jy);
3973 if (player->is_pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
3974 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
3977 if (!IN_SCR_FIELD(sx, sy))
3980 /* ----------------------------------------------------------------------- */
3981 /* draw things behind the player, if needed */
3982 /* ----------------------------------------------------------------------- */
3985 DrawLevelElement(jx, jy, Back[jx][jy]);
3986 else if (IS_ACTIVE_BOMB(element))
3987 DrawLevelElement(jx, jy, EL_EMPTY);
3990 if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
3992 int old_element = GfxElement[jx][jy];
3993 int old_graphic = el_act_dir2img(old_element, action, move_dir);
3994 int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
3996 if (GFX_CRUMBLED(old_element))
3997 DrawLevelFieldCrumbledDigging(jx, jy, move_dir, player->StepFrame);
3999 DrawGraphic(sx, sy, old_graphic, frame);
4001 if (graphic_info[old_graphic].anim_mode & ANIM_OPAQUE_PLAYER)
4002 player_is_opaque = TRUE;
4006 GfxElement[jx][jy] = EL_UNDEFINED;
4008 /* make sure that pushed elements are drawn with correct frame rate */
4010 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
4012 if (player->is_pushing && player->is_moving && !IS_ANIM_MODE_CE(graphic))
4013 GfxFrame[jx][jy] = player->StepFrame;
4015 if (player->is_pushing && player->is_moving)
4016 GfxFrame[jx][jy] = player->StepFrame;
4019 DrawLevelField(jx, jy);
4023 #if !DRAW_PLAYER_OVER_PUSHED_ELEMENT
4024 /* ----------------------------------------------------------------------- */
4025 /* draw player himself */
4026 /* ----------------------------------------------------------------------- */
4028 graphic = getPlayerGraphic(player, move_dir);
4030 /* in the case of changed player action or direction, prevent the current
4031 animation frame from being restarted for identical animations */
4032 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
4033 player->Frame = last_player_frame;
4035 frame = getGraphicAnimationFrame(graphic, player->Frame);
4039 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
4040 sxx = player->GfxPos;
4042 syy = player->GfxPos;
4045 if (!setup.soft_scrolling && ScreenMovPos)
4048 if (player_is_opaque)
4049 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
4051 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
4053 if (SHIELD_ON(player))
4055 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
4056 IMG_SHIELD_NORMAL_ACTIVE);
4057 int frame = getGraphicAnimationFrame(graphic, -1);
4059 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
4063 #if DRAW_PLAYER_OVER_PUSHED_ELEMENT
4066 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
4067 sxx = player->GfxPos;
4069 syy = player->GfxPos;
4073 /* ----------------------------------------------------------------------- */
4074 /* draw things the player is pushing, if needed */
4075 /* ----------------------------------------------------------------------- */
4078 printf("::: %d, %d [%d, %d] [%d]\n",
4079 player->is_pushing, player_is_moving, player->GfxAction,
4080 player->is_moving, player_is_moving);
4084 if (player->is_pushing && player->is_moving)
4086 int px = SCREENX(jx), py = SCREENY(jy);
4087 int pxx = (TILEX - ABS(sxx)) * dx;
4088 int pyy = (TILEY - ABS(syy)) * dy;
4089 int gfx_frame = GfxFrame[jx][jy];
4095 if (!IS_MOVING(jx, jy)) /* push movement already finished */
4097 element = Feld[next_jx][next_jy];
4098 gfx_frame = GfxFrame[next_jx][next_jy];
4101 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
4104 sync_frame = (IS_ANIM_MODE_CE(graphic) ? gfx_frame : player->StepFrame);
4105 frame = getGraphicAnimationFrame(graphic, sync_frame);
4107 frame = getGraphicAnimationFrame(graphic, player->StepFrame);
4110 /* draw background element under pushed element (like the Sokoban field) */
4112 if (game.use_masked_pushing && IS_MOVING(jx, jy))
4114 /* this allows transparent pushing animation over non-black background */
4117 DrawLevelElement(jx, jy, Back[jx][jy]);
4119 DrawLevelElement(jx, jy, EL_EMPTY);
4121 if (Back[next_jx][next_jy])
4122 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
4124 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
4126 else if (Back[next_jx][next_jy])
4127 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
4129 if (Back[next_jx][next_jy])
4130 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
4134 printf("::: %d, %d, %d, %d [%d] [%d, %d, %d] [%d] [%d, %d] [%d, %d]\n",
4135 jx, px, player->GfxPos, player->StepFrame,
4140 GfxFrame[jx][jy], GfxFrame[next_jx][next_jy]);
4144 /* do not draw (EM style) pushing animation when pushing is finished */
4145 /* (two-tile animations usually do not contain start and end frame) */
4146 if (graphic_info[graphic].double_movement && !IS_MOVING(jx, jy))
4147 DrawLevelElement(next_jx, next_jy, Feld[next_jx][next_jy]);
4149 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
4151 /* masked drawing is needed for EMC style (double) movement graphics */
4152 /* !!! (ONLY WHEN DRAWING PUSHED ELEMENT OVER THE PLAYER) !!! */
4153 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
4158 #if DRAW_PLAYER_OVER_PUSHED_ELEMENT
4159 /* ----------------------------------------------------------------------- */
4160 /* draw player himself */
4161 /* ----------------------------------------------------------------------- */
4163 graphic = getPlayerGraphic(player, move_dir);
4165 /* in the case of changed player action or direction, prevent the current
4166 animation frame from being restarted for identical animations */
4167 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
4168 player->Frame = last_player_frame;
4170 frame = getGraphicAnimationFrame(graphic, player->Frame);
4174 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
4175 sxx = player->GfxPos;
4177 syy = player->GfxPos;
4180 if (!setup.soft_scrolling && ScreenMovPos)
4183 if (player_is_opaque)
4184 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
4186 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
4188 if (SHIELD_ON(player))
4190 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
4191 IMG_SHIELD_NORMAL_ACTIVE);
4192 int frame = getGraphicAnimationFrame(graphic, -1);
4194 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
4198 /* ----------------------------------------------------------------------- */
4199 /* draw things in front of player (active dynamite or dynabombs) */
4200 /* ----------------------------------------------------------------------- */
4202 if (IS_ACTIVE_BOMB(element))
4204 graphic = el2img(element);
4205 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
4207 if (game.emulation == EMU_SUPAPLEX)
4208 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
4210 DrawGraphicThruMask(sx, sy, graphic, frame);
4213 if (player_is_moving && last_element == EL_EXPLOSION)
4215 int element = (GfxElement[last_jx][last_jy] != EL_UNDEFINED ?
4216 GfxElement[last_jx][last_jy] : EL_EMPTY);
4217 int graphic = el_act2img(element, ACTION_EXPLODING);
4218 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
4219 int phase = ExplodePhase[last_jx][last_jy] - 1;
4220 int frame = getGraphicAnimationFrame(graphic, phase - delay);
4223 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
4226 /* ----------------------------------------------------------------------- */
4227 /* draw elements the player is just walking/passing through/under */
4228 /* ----------------------------------------------------------------------- */
4230 if (player_is_moving)
4232 /* handle the field the player is leaving ... */
4233 if (IS_ACCESSIBLE_INSIDE(last_element))
4234 DrawLevelField(last_jx, last_jy);
4235 else if (IS_ACCESSIBLE_UNDER(last_element))
4236 DrawLevelFieldThruMask(last_jx, last_jy);
4239 /* do not redraw accessible elements if the player is just pushing them */
4240 if (!player_is_moving || !player->is_pushing)
4242 /* ... and the field the player is entering */
4243 if (IS_ACCESSIBLE_INSIDE(element))
4244 DrawLevelField(jx, jy);
4245 else if (IS_ACCESSIBLE_UNDER(element))
4246 DrawLevelFieldThruMask(jx, jy);
4249 MarkTileDirty(sx, sy);
4252 /* ------------------------------------------------------------------------- */
4254 void WaitForEventToContinue()
4256 boolean still_wait = TRUE;
4258 /* simulate releasing mouse button over last gadget, if still pressed */
4260 HandleGadgets(-1, -1, 0);
4262 button_status = MB_RELEASED;
4278 case EVENT_BUTTONPRESS:
4279 case EVENT_KEYPRESS:
4283 case EVENT_KEYRELEASE:
4284 ClearPlayerAction();
4288 HandleOtherEvents(&event);
4292 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
4299 /* don't eat all CPU time */
4304 #define MAX_REQUEST_LINES 13
4305 #define MAX_REQUEST_LINE_FONT1_LEN 7
4306 #define MAX_REQUEST_LINE_FONT2_LEN 10
4310 static int RequestHandleEvents(unsigned int req_state)
4312 int last_game_status = game_status; /* save current game status */
4316 button_status = MB_RELEASED;
4318 request_gadget_id = -1;
4331 case EVENT_BUTTONPRESS:
4332 case EVENT_BUTTONRELEASE:
4333 case EVENT_MOTIONNOTIFY:
4335 if (event.type == EVENT_MOTIONNOTIFY)
4337 if (!PointerInWindow(window))
4338 continue; /* window and pointer are on different screens */
4343 motion_status = TRUE;
4344 mx = ((MotionEvent *) &event)->x;
4345 my = ((MotionEvent *) &event)->y;
4349 motion_status = FALSE;
4350 mx = ((ButtonEvent *) &event)->x;
4351 my = ((ButtonEvent *) &event)->y;
4352 if (event.type == EVENT_BUTTONPRESS)
4353 button_status = ((ButtonEvent *) &event)->button;
4355 button_status = MB_RELEASED;
4358 /* this sets 'request_gadget_id' */
4359 HandleGadgets(mx, my, button_status);
4361 switch (request_gadget_id)
4363 case TOOL_CTRL_ID_YES:
4366 case TOOL_CTRL_ID_NO:
4369 case TOOL_CTRL_ID_CONFIRM:
4370 result = TRUE | FALSE;
4373 case TOOL_CTRL_ID_PLAYER_1:
4376 case TOOL_CTRL_ID_PLAYER_2:
4379 case TOOL_CTRL_ID_PLAYER_3:
4382 case TOOL_CTRL_ID_PLAYER_4:
4393 case EVENT_KEYPRESS:
4394 switch (GetEventKey((KeyEvent *)&event, TRUE))
4397 if (req_state & REQ_CONFIRM)
4406 #if defined(TARGET_SDL2)
4416 if (req_state & REQ_PLAYER)
4420 case EVENT_KEYRELEASE:
4421 ClearPlayerAction();
4425 HandleOtherEvents(&event);
4429 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
4431 int joy = AnyJoystick();
4433 if (joy & JOY_BUTTON_1)
4435 else if (joy & JOY_BUTTON_2)
4441 if (game_status == GAME_MODE_PLAYING && local_player->LevelSolved_GameEnd)
4443 HandleGameActions();
4449 if (!PendingEvent()) /* delay only if no pending events */
4454 game_status = GAME_MODE_PSEUDO_DOOR;
4460 game_status = last_game_status; /* restore current game status */
4468 if (!PendingEvent()) /* delay only if no pending events */
4471 /* don't eat all CPU time */
4481 static boolean RequestDoor(char *text, unsigned int req_state)
4483 unsigned int old_door_state;
4484 int last_game_status = game_status; /* save current game status */
4485 int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
4486 int font_nr = FONT_TEXT_2;
4491 if (maxWordLengthInString(text) > MAX_REQUEST_LINE_FONT1_LEN)
4493 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
4494 font_nr = FONT_TEXT_1;
4497 if (game_status == GAME_MODE_PLAYING)
4499 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
4500 BlitScreenToBitmap_EM(backbuffer);
4501 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
4502 BlitScreenToBitmap_SP(backbuffer);
4505 /* disable deactivated drawing when quick-loading level tape recording */
4506 if (tape.playing && tape.deactivate_display)
4507 TapeDeactivateDisplayOff(TRUE);
4509 SetMouseCursor(CURSOR_DEFAULT);
4511 #if defined(NETWORK_AVALIABLE)
4512 /* pause network game while waiting for request to answer */
4513 if (options.network &&
4514 game_status == GAME_MODE_PLAYING &&
4515 req_state & REQUEST_WAIT_FOR_INPUT)
4516 SendToServer_PausePlaying();
4519 old_door_state = GetDoorState();
4521 /* simulate releasing mouse button over last gadget, if still pressed */
4523 HandleGadgets(-1, -1, 0);
4527 /* draw released gadget before proceeding */
4530 if (old_door_state & DOOR_OPEN_1)
4532 CloseDoor(DOOR_CLOSE_1);
4534 /* save old door content */
4535 BlitBitmap(bitmap_db_door, bitmap_db_door,
4536 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
4537 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
4540 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
4541 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
4543 /* clear door drawing field */
4544 DrawBackground(DX, DY, DXSIZE, DYSIZE);
4546 /* force DOOR font inside door area */
4547 game_status = GAME_MODE_PSEUDO_DOOR;
4549 /* write text for request */
4550 for (text_ptr = text, ty = 0; ty < MAX_REQUEST_LINES; ty++)
4552 char text_line[max_request_line_len + 1];
4558 for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
4560 tc = *(text_ptr + tx);
4561 // if (!tc || tc == ' ')
4562 if (!tc || tc == ' ' || tc == '?' || tc == '!')
4566 if ((tc == '?' || tc == '!') && tl == 0)
4576 strncpy(text_line, text_ptr, tl);
4579 DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
4580 DY + 8 + ty * (getFontHeight(font_nr) + 2),
4581 text_line, font_nr);
4583 text_ptr += tl + (tc == ' ' ? 1 : 0);
4584 // text_ptr += tl + (tc == ' ' || tc == '?' || tc == '!' ? 1 : 0);
4587 game_status = last_game_status; /* restore current game status */
4589 if (req_state & REQ_ASK)
4591 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
4592 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
4594 else if (req_state & REQ_CONFIRM)
4596 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
4598 else if (req_state & REQ_PLAYER)
4600 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
4601 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
4602 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
4603 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
4606 /* copy request gadgets to door backbuffer */
4607 BlitBitmap(drawto, bitmap_db_door,
4608 DX, DY, DXSIZE, DYSIZE,
4609 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
4611 OpenDoor(DOOR_OPEN_1);
4613 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
4615 if (game_status == GAME_MODE_PLAYING)
4617 SetPanelBackground();
4618 SetDrawBackgroundMask(REDRAW_DOOR_1);
4622 SetDrawBackgroundMask(REDRAW_FIELD);
4628 if (game_status != GAME_MODE_MAIN)
4631 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
4633 // ---------- handle request buttons ----------
4634 result = RequestHandleEvents(req_state);
4636 if (game_status != GAME_MODE_MAIN)
4641 if (!(req_state & REQ_STAY_OPEN))
4643 CloseDoor(DOOR_CLOSE_1);
4645 if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
4646 (req_state & REQ_REOPEN))
4647 OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
4652 if (game_status == GAME_MODE_PLAYING)
4654 SetPanelBackground();
4655 SetDrawBackgroundMask(REDRAW_DOOR_1);
4659 SetDrawBackgroundMask(REDRAW_FIELD);
4662 #if defined(NETWORK_AVALIABLE)
4663 /* continue network game after request */
4664 if (options.network &&
4665 game_status == GAME_MODE_PLAYING &&
4666 req_state & REQUEST_WAIT_FOR_INPUT)
4667 SendToServer_ContinuePlaying();
4670 /* restore deactivated drawing when quick-loading level tape recording */
4671 if (tape.playing && tape.deactivate_display)
4672 TapeDeactivateDisplayOn();
4677 static boolean RequestEnvelope(char *text, unsigned int req_state)
4684 if (game_status == GAME_MODE_PLAYING)
4686 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
4687 BlitScreenToBitmap_EM(backbuffer);
4688 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
4689 BlitScreenToBitmap_SP(backbuffer);
4692 /* disable deactivated drawing when quick-loading level tape recording */
4693 if (tape.playing && tape.deactivate_display)
4694 TapeDeactivateDisplayOff(TRUE);
4696 SetMouseCursor(CURSOR_DEFAULT);
4698 #if defined(NETWORK_AVALIABLE)
4699 /* pause network game while waiting for request to answer */
4700 if (options.network &&
4701 game_status == GAME_MODE_PLAYING &&
4702 req_state & REQUEST_WAIT_FOR_INPUT)
4703 SendToServer_PausePlaying();
4706 /* simulate releasing mouse button over last gadget, if still pressed */
4708 HandleGadgets(-1, -1, 0);
4712 // (replace with setting corresponding request background)
4713 // SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
4714 // SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
4716 /* clear door drawing field */
4717 // DrawBackground(DX, DY, DXSIZE, DYSIZE);
4720 if (global.use_envelope_request)
4724 CreateToolButtons();
4730 if (req_state & REQ_ASK)
4732 MapGadgetExt(tool_gadget[TOOL_CTRL_ID_YES], FALSE);
4733 MapGadgetExt(tool_gadget[TOOL_CTRL_ID_NO], FALSE);
4735 else if (req_state & REQ_CONFIRM)
4737 MapGadgetExt(tool_gadget[TOOL_CTRL_ID_CONFIRM], FALSE);
4739 else if (req_state & REQ_PLAYER)
4741 MapGadgetExt(tool_gadget[TOOL_CTRL_ID_PLAYER_1], FALSE);
4742 MapGadgetExt(tool_gadget[TOOL_CTRL_ID_PLAYER_2], FALSE);
4743 MapGadgetExt(tool_gadget[TOOL_CTRL_ID_PLAYER_3], FALSE);
4744 MapGadgetExt(tool_gadget[TOOL_CTRL_ID_PLAYER_4], FALSE);
4747 if (req_state & REQ_ASK)
4749 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
4750 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
4752 else if (req_state & REQ_CONFIRM)
4754 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
4756 else if (req_state & REQ_PLAYER)
4758 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
4759 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
4760 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
4761 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
4766 ShowEnvelopeRequest(text, req_state, ACTION_OPENING);
4769 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4771 if ((req_state & REQ_ASK && (i == TOOL_CTRL_ID_YES ||
4772 i == TOOL_CTRL_ID_NO)) ||
4773 (req_state & REQ_CONFIRM && i == TOOL_CTRL_ID_CONFIRM) ||
4774 (req_state & REQ_PLAYER && (i == TOOL_CTRL_ID_PLAYER_1 &&
4775 i == TOOL_CTRL_ID_PLAYER_2 &&
4776 i == TOOL_CTRL_ID_PLAYER_3 &&
4777 i == TOOL_CTRL_ID_PLAYER_4)))
4779 int x = tool_gadget[i]->x + dDX;
4780 int y = tool_gadget[i]->y + dDY;
4782 ModifyGadget(tool_gadget[i], GDI_X, x, GDI_Y, y, GDI_END);
4787 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
4789 if (game_status == GAME_MODE_PLAYING)
4791 SetPanelBackground();
4792 SetDrawBackgroundMask(REDRAW_DOOR_1);
4796 SetDrawBackgroundMask(REDRAW_FIELD);
4803 if (game_status != GAME_MODE_MAIN)
4807 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
4809 // ---------- handle request buttons ----------
4810 result = RequestHandleEvents(req_state);
4812 if (game_status != GAME_MODE_MAIN)
4817 ShowEnvelopeRequest(text, req_state, ACTION_CLOSING);
4821 if (game_status == GAME_MODE_PLAYING)
4823 SetPanelBackground();
4824 SetDrawBackgroundMask(REDRAW_DOOR_1);
4828 SetDrawBackgroundMask(REDRAW_FIELD);
4831 #if defined(NETWORK_AVALIABLE)
4832 /* continue network game after request */
4833 if (options.network &&
4834 game_status == GAME_MODE_PLAYING &&
4835 req_state & REQUEST_WAIT_FOR_INPUT)
4836 SendToServer_ContinuePlaying();
4839 /* restore deactivated drawing when quick-loading level tape recording */
4840 if (tape.playing && tape.deactivate_display)
4841 TapeDeactivateDisplayOn();
4846 boolean Request(char *text, unsigned int req_state)
4848 if (global.use_envelope_request)
4849 return RequestEnvelope(text, req_state);
4851 return RequestDoor(text, req_state);
4854 #else // =====================================================================
4856 boolean Request(char *text, unsigned int req_state)
4858 int mx, my, ty, result = -1;
4859 unsigned int old_door_state;
4860 int last_game_status = game_status; /* save current game status */
4861 int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
4862 int font_nr = FONT_TEXT_2;
4864 int max_word_len = 0;
4870 global.use_envelope_request = 1;
4874 if (maxWordLengthInString(text) > MAX_REQUEST_LINE_FONT1_LEN)
4876 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
4877 font_nr = FONT_TEXT_1;
4880 for (text_ptr = text; *text_ptr; text_ptr++)
4882 max_word_len = (*text_ptr != ' ' ? max_word_len + 1 : 0);
4884 if (max_word_len > MAX_REQUEST_LINE_FONT1_LEN)
4886 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
4888 font_nr = FONT_TEXT_1;
4890 font_nr = FONT_LEVEL_NUMBER;
4898 if (game_status == GAME_MODE_PLAYING)
4900 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
4901 BlitScreenToBitmap_EM(backbuffer);
4902 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
4903 BlitScreenToBitmap_SP(backbuffer);
4906 /* disable deactivated drawing when quick-loading level tape recording */
4907 if (tape.playing && tape.deactivate_display)
4908 TapeDeactivateDisplayOff(TRUE);
4910 SetMouseCursor(CURSOR_DEFAULT);
4912 #if defined(NETWORK_AVALIABLE)
4913 /* pause network game while waiting for request to answer */
4914 if (options.network &&
4915 game_status == GAME_MODE_PLAYING &&
4916 req_state & REQUEST_WAIT_FOR_INPUT)
4917 SendToServer_PausePlaying();
4920 old_door_state = GetDoorState();
4922 /* simulate releasing mouse button over last gadget, if still pressed */
4924 HandleGadgets(-1, -1, 0);
4928 /* draw released gadget before proceeding */
4932 if (old_door_state & DOOR_OPEN_1 && !global.use_envelope_request)
4934 if (old_door_state & DOOR_OPEN_1)
4938 if (!global.use_envelope_request)
4939 CloseDoor(DOOR_CLOSE_1);
4941 CloseDoor(DOOR_CLOSE_1);
4944 /* save old door content */
4945 BlitBitmap(bitmap_db_door, bitmap_db_door,
4946 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
4947 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
4951 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
4954 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
4956 /* clear door drawing field */
4957 DrawBackground(DX, DY, DXSIZE, DYSIZE);
4959 /* force DOOR font inside door area */
4960 game_status = GAME_MODE_PSEUDO_DOOR;
4962 /* write text for request */
4963 for (text_ptr = text, ty = 0; ty < MAX_REQUEST_LINES; ty++)
4965 char text_line[max_request_line_len + 1];
4971 for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
4973 tc = *(text_ptr + tx);
4974 if (!tc || tc == ' ')
4985 strncpy(text_line, text_ptr, tl);
4988 DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
4989 DY + 8 + ty * (getFontHeight(font_nr) + 2),
4990 text_line, font_nr);
4992 text_ptr += tl + (tc == ' ' ? 1 : 0);
4995 game_status = last_game_status; /* restore current game status */
4998 if (global.use_envelope_request)
5002 CreateToolButtons();
5006 if (req_state & REQ_ASK)
5008 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
5009 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
5011 else if (req_state & REQ_CONFIRM)
5013 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
5015 else if (req_state & REQ_PLAYER)
5017 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
5018 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
5019 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
5020 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
5023 /* copy request gadgets to door backbuffer */
5024 BlitBitmap(drawto, bitmap_db_door,
5025 DX, DY, DXSIZE, DYSIZE,
5026 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
5029 if (global.use_envelope_request)
5031 ShowEnvelopeRequest(text, ACTION_OPENING);
5033 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
5035 if ((req_state & REQ_ASK && (i == TOOL_CTRL_ID_YES ||
5036 i == TOOL_CTRL_ID_NO)) ||
5037 (req_state & REQ_CONFIRM && i == TOOL_CTRL_ID_CONFIRM) ||
5038 (req_state & REQ_PLAYER && (i == TOOL_CTRL_ID_PLAYER_1 &&
5039 i == TOOL_CTRL_ID_PLAYER_2 &&
5040 i == TOOL_CTRL_ID_PLAYER_3 &&
5041 i == TOOL_CTRL_ID_PLAYER_4)))
5043 int x = tool_gadget[i]->x + dDX;
5044 int y = tool_gadget[i]->y + dDY;
5046 ModifyGadget(tool_gadget[i], GDI_X, x, GDI_Y, y, GDI_END);
5053 if (!global.use_envelope_request)
5054 OpenDoor(DOOR_OPEN_1);
5056 OpenDoor(DOOR_OPEN_1);
5059 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
5061 if (game_status == GAME_MODE_PLAYING)
5063 SetPanelBackground();
5064 SetDrawBackgroundMask(REDRAW_DOOR_1);
5068 SetDrawBackgroundMask(REDRAW_FIELD);
5075 if (game_status != GAME_MODE_MAIN && !global.use_envelope_request)
5078 if (game_status != GAME_MODE_MAIN)
5082 button_status = MB_RELEASED;
5084 request_gadget_id = -1;
5086 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
5098 case EVENT_BUTTONPRESS:
5099 case EVENT_BUTTONRELEASE:
5100 case EVENT_MOTIONNOTIFY:
5102 if (event.type == EVENT_MOTIONNOTIFY)
5104 if (!PointerInWindow(window))
5105 continue; /* window and pointer are on different screens */
5110 motion_status = TRUE;
5111 mx = ((MotionEvent *) &event)->x;
5112 my = ((MotionEvent *) &event)->y;
5116 motion_status = FALSE;
5117 mx = ((ButtonEvent *) &event)->x;
5118 my = ((ButtonEvent *) &event)->y;
5119 if (event.type == EVENT_BUTTONPRESS)
5120 button_status = ((ButtonEvent *) &event)->button;
5122 button_status = MB_RELEASED;
5125 /* this sets 'request_gadget_id' */
5126 HandleGadgets(mx, my, button_status);
5128 switch (request_gadget_id)
5130 case TOOL_CTRL_ID_YES:
5133 case TOOL_CTRL_ID_NO:
5136 case TOOL_CTRL_ID_CONFIRM:
5137 result = TRUE | FALSE;
5140 case TOOL_CTRL_ID_PLAYER_1:
5143 case TOOL_CTRL_ID_PLAYER_2:
5146 case TOOL_CTRL_ID_PLAYER_3:
5149 case TOOL_CTRL_ID_PLAYER_4:
5160 case EVENT_KEYPRESS:
5161 switch (GetEventKey((KeyEvent *)&event, TRUE))
5164 if (req_state & REQ_CONFIRM)
5173 #if defined(TARGET_SDL2)
5183 if (req_state & REQ_PLAYER)
5187 case EVENT_KEYRELEASE:
5188 ClearPlayerAction();
5192 HandleOtherEvents(&event);
5196 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
5198 int joy = AnyJoystick();
5200 if (joy & JOY_BUTTON_1)
5202 else if (joy & JOY_BUTTON_2)
5208 if (game_status == GAME_MODE_PLAYING && local_player->LevelSolved_GameEnd)
5210 HandleGameActions();
5216 if (!PendingEvent()) /* delay only if no pending events */
5221 game_status = GAME_MODE_PSEUDO_DOOR;
5227 game_status = last_game_status; /* restore current game status */
5235 if (!PendingEvent()) /* delay only if no pending events */
5238 /* don't eat all CPU time */
5245 if (game_status != GAME_MODE_MAIN)
5251 if (global.use_envelope_request)
5252 ShowEnvelopeRequest(text, ACTION_CLOSING);
5256 if (!(req_state & REQ_STAY_OPEN) && !global.use_envelope_request)
5258 if (!(req_state & REQ_STAY_OPEN))
5261 CloseDoor(DOOR_CLOSE_1);
5263 if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
5264 (req_state & REQ_REOPEN))
5265 OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
5270 if (game_status == GAME_MODE_PLAYING)
5272 SetPanelBackground();
5273 SetDrawBackgroundMask(REDRAW_DOOR_1);
5277 SetDrawBackgroundMask(REDRAW_FIELD);
5280 #if defined(NETWORK_AVALIABLE)
5281 /* continue network game after request */
5282 if (options.network &&
5283 game_status == GAME_MODE_PLAYING &&
5284 req_state & REQUEST_WAIT_FOR_INPUT)
5285 SendToServer_ContinuePlaying();
5288 /* restore deactivated drawing when quick-loading level tape recording */
5289 if (tape.playing && tape.deactivate_display)
5290 TapeDeactivateDisplayOn();
5297 static int compareDoorPartOrderInfo(const void *object1, const void *object2)
5299 const struct DoorPartOrderInfo *dpo1 = (struct DoorPartOrderInfo *)object1;
5300 const struct DoorPartOrderInfo *dpo2 = (struct DoorPartOrderInfo *)object2;
5303 if (dpo1->sort_priority != dpo2->sort_priority)
5304 compare_result = dpo1->sort_priority - dpo2->sort_priority;
5306 compare_result = dpo1->nr - dpo2->nr;
5308 return compare_result;
5315 for (i = 0; door_part_controls[i].door_nr != -1; i++)
5317 struct DoorPartControlInfo *dpc = &door_part_controls[i];
5318 struct DoorPartOrderInfo *dpo = &door_part_order[i];
5320 /* fill structure for door part draw order */
5322 dpo->sort_priority = dpc->pos->sort_priority;
5325 struct DoorPartPosInfo *pos = dpc->pos;
5327 printf(":0: step_xoffset == %d, step_yoffset == %d\n",
5328 pos->step_xoffset, pos->step_yoffset);
5332 /* sort door part controls according to sort_priority and graphic number */
5333 qsort(door_part_order, NUM_DOORS * MAX_NUM_DOOR_PARTS,
5334 sizeof(struct DoorPartOrderInfo), compareDoorPartOrderInfo);
5337 unsigned int OpenDoor(unsigned int door_state)
5339 if (door_state & DOOR_COPY_BACK)
5341 if (door_state & DOOR_OPEN_1)
5342 BlitBitmap(bitmap_db_door, bitmap_db_door,
5343 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
5344 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
5346 if (door_state & DOOR_OPEN_2)
5347 BlitBitmap(bitmap_db_door, bitmap_db_door,
5348 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY2, VXSIZE, VYSIZE,
5349 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
5351 door_state &= ~DOOR_COPY_BACK;
5354 return MoveDoor(door_state);
5357 unsigned int CloseDoor(unsigned int door_state)
5359 unsigned int old_door_state = GetDoorState();
5361 if (!(door_state & DOOR_NO_COPY_BACK))
5363 if (old_door_state & DOOR_OPEN_1)
5364 BlitBitmap(backbuffer, bitmap_db_door,
5365 DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
5367 if (old_door_state & DOOR_OPEN_2)
5368 BlitBitmap(backbuffer, bitmap_db_door,
5369 VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
5371 door_state &= ~DOOR_NO_COPY_BACK;
5374 return MoveDoor(door_state);
5377 unsigned int GetDoorState()
5379 return MoveDoor(DOOR_GET_STATE);
5382 unsigned int SetDoorState(unsigned int door_state)
5384 return MoveDoor(door_state | DOOR_SET_STATE);
5389 // ========== TEST 1 ===========================================================
5391 int euclid(int a, int b)
5393 return (b ? euclid(b, a % b) : a);
5396 unsigned int MoveDoor(unsigned int door_state)
5398 struct XY panel_pos_list[] =
5400 { DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 },
5401 { DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 },
5403 struct Rect door_rect_list[] =
5405 { DX, DY, DXSIZE, DYSIZE },
5406 { VX, VY, VXSIZE, VYSIZE }
5408 static int door1 = DOOR_OPEN_1;
5409 static int door2 = DOOR_CLOSE_2;
5411 unsigned int door_delay = 0;
5412 unsigned int door_delay_value;
5420 if (door_1.width < 0 || door_1.width > DXSIZE)
5421 door_1.width = DXSIZE;
5422 if (door_1.height < 0 || door_1.height > DYSIZE)
5423 door_1.height = DYSIZE;
5424 if (door_2.width < 0 || door_2.width > VXSIZE)
5425 door_2.width = VXSIZE;
5426 if (door_2.height < 0 || door_2.height > VYSIZE)
5427 door_2.height = VYSIZE;
5430 if (door_state == DOOR_GET_STATE)
5431 return (door1 | door2);
5433 if (door_state & DOOR_SET_STATE)
5435 if (door_state & DOOR_ACTION_1)
5436 door1 = door_state & DOOR_ACTION_1;
5437 if (door_state & DOOR_ACTION_2)
5438 door2 = door_state & DOOR_ACTION_2;
5440 return (door1 | door2);
5443 if (!(door_state & DOOR_FORCE_REDRAW))
5445 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
5446 door_state &= ~DOOR_OPEN_1;
5447 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
5448 door_state &= ~DOOR_CLOSE_1;
5449 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
5450 door_state &= ~DOOR_OPEN_2;
5451 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
5452 door_state &= ~DOOR_CLOSE_2;
5456 door_delay_value = (door_state & DOOR_ACTION_1 ? door_1.step_delay :
5459 if (setup.quick_doors)
5461 stepsize = 20; /* must be chosen to always draw last frame */
5462 door_delay_value = 0;
5466 if (global.autoplay_leveldir)
5468 door_state |= DOOR_NO_DELAY;
5469 door_state &= ~DOOR_CLOSE_ALL;
5473 if (game_status == GAME_MODE_EDITOR)
5474 door_state |= DOOR_NO_DELAY;
5477 if (door_state & DOOR_ACTION)
5479 boolean door_panel_drawn[NUM_DOORS];
5480 boolean door_part_done[NUM_DOORS * MAX_NUM_DOOR_PARTS];
5481 boolean door_part_done_all;
5483 int num_xsteps[NUM_DOORS * MAX_NUM_DOOR_PARTS];
5484 int num_ysteps[NUM_DOORS * MAX_NUM_DOOR_PARTS];
5486 int max_move_delay = 0; // delay for complete animations of all doors
5487 int max_step_delay = 0; // delay (ms) between two animation frames
5488 int num_move_steps = 0; // number of animation steps for all doors
5491 for (i = 0; i < NUM_DOORS * MAX_NUM_DOOR_PARTS; i++)
5493 int nr = door_part_order[i].nr;
5494 struct DoorPartControlInfo *dpc = &door_part_controls[nr];
5495 struct GraphicInfo *g = &graphic_info[dpc->graphic];
5496 int door_token = dpc->door_nr;
5498 door_part_done[nr] = (!(door_state & door_token) ||
5502 for (i = 0; i < NUM_DOORS * MAX_NUM_DOOR_PARTS; i++)
5504 struct DoorPartControlInfo *dpc = &door_part_controls[i];
5505 struct GraphicInfo *g = &graphic_info[dpc->graphic];
5506 struct DoorPartPosInfo *pos = dpc->pos;
5507 int step_xoffset = ABS(pos->step_xoffset);
5508 int step_yoffset = ABS(pos->step_yoffset);
5509 int step_delay = pos->step_delay;
5510 int move_xsize = (step_xoffset ? g->width : 0);
5511 int move_ysize = (step_yoffset ? g->height : 0);
5513 int move_size = (move_xsize && move_ysize ?
5514 MIN(move_xsize, move_ysize) :
5515 move_xsize ? move_xsize : move_ysize);
5517 int move_xsteps = (step_xoffset ? CEIL(move_xsize, step_xoffset) : 0);
5518 int move_ysteps = (step_yoffset ? CEIL(move_ysize, step_yoffset) : 0);
5520 int move_xdelay = move_xsteps * step_delay;
5521 int move_ydelay = move_ysteps * step_delay;
5522 int move_delay = (move_xdelay && move_ydelay ?
5523 MIN(move_xdelay, move_ydelay) :
5524 move_xdelay ? move_xdelay : move_ydelay);
5526 int move_steps = (move_xsteps && move_ysteps ?
5527 MIN(move_xsteps, move_ysteps) :
5528 move_xsteps ? move_xsteps : move_ysteps);
5529 int move_delay = move_steps * step_delay;
5530 // int move_delay = MAX(move_xsize, move_ysize) * step_delay;
5532 max_move_delay = MAX(max_move_delay, move_delay);
5533 max_step_delay = (max_step_delay == 0 ? step_delay :
5534 euclid(max_step_delay, step_delay));
5536 num_xsteps[i] = move_xsteps;
5537 num_ysteps[i] = move_ysteps;
5541 num_move_steps = max_move_delay / max_step_delay;
5543 door_delay_value = max_step_delay;
5546 printf("::: max_move_delay == %d, max_step_delay == %d, num_move_steps == %d\n",
5547 max_move_delay, max_step_delay, num_move_steps);
5551 for (i = 0; i < NUM_DOORS * MAX_NUM_DOOR_PARTS; i++)
5552 printf("::: door_part_done[%d] == %d\n", i, door_part_done[i]);
5556 for (k = 0; k < num_move_steps; k++)
5558 for (i = 0; i < NUM_DOORS; i++)
5559 door_panel_drawn[i] = FALSE;
5561 for (i = 0; i < NUM_DOORS * MAX_NUM_DOOR_PARTS; i++)
5563 int nr = door_part_order[i].nr;
5564 struct DoorPartControlInfo *dpc = &door_part_controls[nr];
5565 int door_token = dpc->door_nr;
5566 int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
5567 struct GraphicInfo *g = &graphic_info[dpc->graphic];
5568 struct DoorPartPosInfo *pos = dpc->pos;
5569 struct XY *panel_pos = &panel_pos_list[door_index];
5570 struct Rect *door_rect = &door_rect_list[door_index];
5575 if (door_part_done[nr])
5578 if (!(door_state & door_token))
5584 if (!door_panel_drawn[door_index])
5586 BlitBitmap(bitmap_db_door, drawto, panel_pos->x, panel_pos->y,
5587 door_rect->width, door_rect->height,
5588 door_rect->x, door_rect->y);
5590 door_panel_drawn[door_index] = TRUE;
5594 if ((door_state & door_token) & DOOR_OPEN)
5604 printf("::: step_xoffset == %d, step_yoffset == %d\n",
5605 pos->step_xoffset, pos->step_yoffset);
5608 if (pos->step_xoffset < 0)
5612 dst_xx = pos->x + ABS(k * pos->step_xoffset);
5615 if (dst_xx + width > door_rect->width)
5616 width = door_rect->width - dst_xx;
5619 width = g->width + k * pos->step_xoffset;
5621 if (width > door_rect->width)
5622 width = door_rect->width;
5624 dst_xx = door_rect->width - width;
5630 dst_xx = pos->x - k * pos->step_xoffset;
5634 src_xx = ABS(dst_xx);
5638 width = g->width - src_xx;
5641 if (pos->step_yoffset < 0)
5645 dst_yy = pos->y + ABS(k * pos->step_yoffset);
5648 if (dst_yy + height > door_rect->height)
5649 height = door_rect->height - dst_yy;
5652 height = g->height + k * pos->step_yoffset;
5654 if (height > door_rect->height)
5655 height = door_rect->height;
5657 dst_yy = door_rect->height - height;
5663 dst_yy = pos->y - k * pos->step_yoffset;
5667 src_yy = ABS(dst_yy);
5671 height = g->height - src_yy;
5674 if (width < 0 || height < 0)
5675 door_part_done[nr] = TRUE;
5682 door_part_done[nr] = TRUE;
5684 BlitBitmapMasked(g->bitmap, drawto, g->src_x, g->src_y,
5685 g->width, g->height,
5686 door_rect->x + pos->x, door_rect->y + pos->y);
5688 redraw_mask |= REDRAW_DOOR_FROM_TOKEN(door_token);
5690 src_xx = (num_xsteps[nr] - k) * pos->step_xoffset;
5691 src_yy = (num_ysteps[nr] - k) * pos->step_yoffset;
5694 width = g->width - src_xx;
5695 height = g->height - src_yy;
5697 // if (width < ABS(pos->step_xoffset)
5702 src_xx = g->width - k * pos->step_xoffset;
5703 src_yy = g->height - k * pos->step_yoffset;
5707 if (width < 0 || height < 0)
5708 door_part_done[nr] = TRUE;
5712 if (door_part_done[nr])
5721 BlitBitmapMasked(g->bitmap, drawto,
5722 g->src_x + src_xx, g->src_y + src_yy, width, height,
5723 door_rect->x + dst_xx, door_rect->y + dst_yy);
5726 if (!((door_state & door_token) & DOOR_CLOSE))
5729 BlitBitmapMasked(g->bitmap, drawto, g->src_x, g->src_y,
5730 g->width, g->height,
5731 door_rect->x + pos->x, door_rect->y + pos->y);
5734 redraw_mask |= REDRAW_DOOR_FROM_TOKEN(door_token);
5737 door_part_done_all = TRUE;
5739 for (i = 0; i < NUM_DOORS * MAX_NUM_DOOR_PARTS; i++)
5740 if (!door_part_done[i])
5741 door_part_done_all = FALSE;
5743 if (door_part_done_all)
5746 if (!(door_state & DOOR_NO_DELAY))
5750 if (game_status == GAME_MODE_MAIN)
5753 WaitUntilDelayReached(&door_delay, door_delay_value);
5758 redraw_mask |= REDRAW_ALL;
5760 if (door_state & DOOR_ACTION_1)
5761 door1 = door_state & DOOR_ACTION_1;
5762 if (door_state & DOOR_ACTION_2)
5763 door2 = door_state & DOOR_ACTION_2;
5765 return (door1 | door2);
5770 // ========== OLD ==============================================================
5772 unsigned int MoveDoor(unsigned int door_state)
5774 static int door1 = DOOR_OPEN_1;
5775 static int door2 = DOOR_CLOSE_2;
5776 unsigned int door_delay = 0;
5777 unsigned int door_delay_value;
5781 if (door_1.width < 0 || door_1.width > DXSIZE)
5782 door_1.width = DXSIZE;
5783 if (door_1.height < 0 || door_1.height > DYSIZE)
5784 door_1.height = DYSIZE;
5785 if (door_2.width < 0 || door_2.width > VXSIZE)
5786 door_2.width = VXSIZE;
5787 if (door_2.height < 0 || door_2.height > VYSIZE)
5788 door_2.height = VYSIZE;
5791 if (door_state == DOOR_GET_STATE)
5792 return (door1 | door2);
5794 if (door_state & DOOR_SET_STATE)
5796 if (door_state & DOOR_ACTION_1)
5797 door1 = door_state & DOOR_ACTION_1;
5798 if (door_state & DOOR_ACTION_2)
5799 door2 = door_state & DOOR_ACTION_2;
5801 return (door1 | door2);
5804 if (!(door_state & DOOR_FORCE_REDRAW))
5806 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
5807 door_state &= ~DOOR_OPEN_1;
5808 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
5809 door_state &= ~DOOR_CLOSE_1;
5810 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
5811 door_state &= ~DOOR_OPEN_2;
5812 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
5813 door_state &= ~DOOR_CLOSE_2;
5816 door_delay_value = (door_state & DOOR_ACTION_1 ? door_1.step_delay :
5819 // door_delay_value *= 4; // !!! TEST ONLY !!!
5821 if (setup.quick_doors)
5823 stepsize = 20; /* must be chosen to always draw last frame */
5824 door_delay_value = 0;
5827 if (global.autoplay_leveldir)
5829 door_state |= DOOR_NO_DELAY;
5830 door_state &= ~DOOR_CLOSE_ALL;
5834 if (game_status == GAME_MODE_EDITOR)
5835 door_state |= DOOR_NO_DELAY;
5838 if (door_state & DOOR_ACTION)
5841 struct GraphicInfo *g1_left = &graphic_info[IMG_DOOR_1_WING_LEFT];
5842 struct GraphicInfo *g1_right = &graphic_info[IMG_DOOR_1_WING_RIGHT];
5843 struct GraphicInfo *g2_left = &graphic_info[IMG_DOOR_2_WING_LEFT];
5844 struct GraphicInfo *g2_right = &graphic_info[IMG_DOOR_2_WING_RIGHT];
5845 int door_1_left_width = g1_left->width;
5846 int door_1_left_height = g1_left->height;
5847 int door_1_right_width = g1_right->width;
5848 int door_1_right_height = g1_right->height;
5849 int door_2_left_width = g2_left->width;
5850 int door_2_left_height = g2_left->height;
5851 int door_2_right_width = g2_right->width;
5852 int door_2_right_height = g2_right->height;
5853 int door_1_width = MAX(door_1_left_width, door_1_right_width);
5854 int door_1_height = MAX(door_1_left_height, door_1_right_height);
5855 int door_2_width = MAX(door_2_left_width, door_2_right_width);
5856 int door_2_height = MAX(door_2_left_height, door_2_right_height);
5858 boolean handle_door_1 = (door_state & DOOR_ACTION_1);
5859 boolean handle_door_2 = (door_state & DOOR_ACTION_2);
5860 boolean door_1_done = (!handle_door_1);
5861 boolean door_2_done = (!handle_door_2);
5862 boolean door_1_vertical = (door_1.anim_mode & ANIM_VERTICAL);
5863 boolean door_2_vertical = (door_2.anim_mode & ANIM_VERTICAL);
5866 int door_size_1 = (door_1_vertical ? door_1_height : door_1_width);
5867 int door_size_2 = (door_2_vertical ? door_2_height : door_2_width);
5869 int door_size_1 = (door_1_vertical ? DYSIZE : DXSIZE);
5870 int door_size_2 = (door_2_vertical ? VYSIZE : VXSIZE);
5873 int door_size_1 = (door_1_vertical ? door_1.height : door_1.width);
5874 int door_size_2 = (door_2_vertical ? door_2.height : door_2.width);
5876 int max_door_size_1 = (door_1_vertical ? DYSIZE : DXSIZE);
5877 int max_door_size_2 = (door_2_vertical ? VYSIZE : VXSIZE);
5878 // int door_size = (handle_door_1 ? door_size_1 : door_size_2);
5879 int door_size = (handle_door_2 ? door_size_2 : door_size_1);
5880 int max_door_size = (handle_door_1 ? max_door_size_1 : max_door_size_2);
5881 int door_skip = max_door_size - door_size;
5882 int end = door_size;
5883 int start = ((door_state & DOOR_NO_DELAY) ? end : 0);
5886 if (!(door_state & DOOR_NO_DELAY) && !setup.quick_doors)
5888 /* opening door sound has priority over simultaneously closing door */
5889 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
5890 PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
5891 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
5892 PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
5895 for (k = start; k <= end && !(door_1_done && door_2_done); k += stepsize)
5899 Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
5900 GC gc = bitmap->stored_clip_gc;
5903 if (door_state & DOOR_ACTION_1 &&
5904 x * door_1.step_offset <= door_size_1)
5906 int a = MIN(x * door_1.step_offset, end);
5907 int p = (door_state & DOOR_OPEN_1 ? end - a : a);
5911 int i = p + door_skip;
5915 struct GraphicInfo *g_left = &graphic_info[IMG_DOOR_1_WING_LEFT];
5916 struct GraphicInfo *g_right = &graphic_info[IMG_DOOR_1_WING_RIGHT];
5917 Bitmap *bm_left = g_left->bitmap;
5918 Bitmap *bm_right = g_right->bitmap;
5919 GC gc_left = bm_left->stored_clip_gc;
5920 GC gc_right = bm_right->stored_clip_gc;
5923 int classic_dxsize = 100;
5924 int classic_dysize = 280;
5925 boolean classic_door_1_size = (DXSIZE == classic_dxsize &&
5926 DYSIZE == classic_dysize);
5928 if (door_1.anim_mode & ANIM_STATIC_PANEL)
5930 BlitBitmap(bitmap_db_door, drawto,
5931 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1,
5932 DXSIZE, DYSIZE, DX, DY);
5936 BlitBitmap(bitmap_db_door, drawto,
5937 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + p / 2,
5938 DXSIZE, DYSIZE - p / 2, DX, DY);
5941 // printf("::: p == %d\n", p);
5942 ClearRectangle(drawto, DX, DY + DYSIZE - p / 2, DXSIZE, p / 2);
5946 if (door_1.anim_mode & ANIM_HORIZONTAL && x <= DXSIZE)
5949 int src1_x = g_right->src_x;
5950 int src1_y = g_right->src_y;
5951 int src2_x = g_left->src_x + g_left->width - i;
5952 int src2_y = g_left->src_y;
5953 int dst1_x = DX + DXSIZE - i;
5958 int height = DYSIZE;
5960 SetClipOrigin(bm_right, gc_right, dst1_x - src1_x, dst1_y - src1_y);
5961 BlitBitmapMasked(bm_right, drawto, src1_x, src1_y, width, height,
5964 SetClipOrigin(bm_left, gc_left, dst2_x - src2_x, dst2_y - src2_y);
5965 BlitBitmapMasked(bm_left, drawto, src2_x, src2_y, width, height,
5968 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
5969 int src2_x = DXSIZE - i, src2_y = DOOR_GFX_PAGEY1;
5970 int dst1_x = DX + DXSIZE - i, dst1_y = DY;
5971 int dst2_x = DX, dst2_y = DY;
5972 int width = i, height = DYSIZE;
5974 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
5975 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
5978 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
5979 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
5983 else if (door_1.anim_mode & ANIM_VERTICAL && x <= DYSIZE)
5986 int src1_x = g_right->src_x;
5987 int src1_y = g_right->src_y;
5988 int src2_x = g_left->src_x;
5989 int src2_y = g_left->src_y + g_left->height - i;
5991 int dst1_y = DY + DYSIZE - i;
5997 SetClipOrigin(bm_right, gc_right, dst1_x - src1_x, dst1_y - src1_y);
5998 BlitBitmapMasked(bm_right, drawto, src1_x, src1_y, width, height,
6001 SetClipOrigin(bm_left, gc_left, dst2_x - src2_x, dst2_y - src2_y);
6002 BlitBitmapMasked(bm_left, drawto, src2_x, src2_y, width, height,
6005 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
6006 int src2_x = 0, src2_y = DOOR_GFX_PAGEY1 + DYSIZE - i;
6007 int dst1_x = DX, dst1_y = DY + DYSIZE - i;
6008 int dst2_x = DX, dst2_y = DY;
6009 int width = DXSIZE, height = i;
6011 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
6012 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
6015 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
6016 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
6020 else if (classic_door_1_size && x <= DXSIZE) /* ANIM_DEFAULT */
6022 int j = (door_1.anim_mode == ANIM_DEFAULT ? (DXSIZE - i) / 3 : 0);
6025 int src1_x = g_right->src_x;
6026 int src1_y = g_right->src_y;
6027 int src2_x = g_left->src_x + g_left->width - i;
6028 int src2_y = g_left->src_y;
6029 int dst1_x = DX + DXSIZE - i;
6034 int height1 = 63, height2 = DYSIZE / 2 - height1;
6035 int ypos1 = 0, ypos2 = height2;
6036 int ypos3 = DYSIZE / 2, ypos4 = DYSIZE - height2;
6038 SetClipOrigin(bm_right, gc_right,
6039 dst1_x - src1_x, dst1_y - src1_y + j);
6040 BlitBitmapMasked(bm_right, drawto,
6041 src1_x, src1_y + ypos1, width, height2,
6042 dst1_x, dst1_y + ypos1 + j);
6043 BlitBitmapMasked(bm_right, drawto,
6044 src1_x, src1_y + ypos3, width, height1,
6045 dst1_x, dst1_y + ypos3 + j);
6046 SetClipOrigin(bm_left, gc_left,
6047 dst2_x - src2_x, dst2_y - src2_y - j);
6048 BlitBitmapMasked(bm_left, drawto,
6049 src2_x, src2_y + ypos1 + j, width, height2 - j,
6050 dst2_x, dst2_y + ypos1);
6051 BlitBitmapMasked(bm_left, drawto,
6052 src2_x, src2_y + ypos3, width, height1,
6053 dst2_x, dst2_y + ypos3 - j);
6055 SetClipOrigin(bm_left, gc_left,
6056 dst2_x - src2_x, dst2_y - src2_y - j);
6057 BlitBitmapMasked(bm_left, drawto,
6058 src2_x, src2_y + ypos2, width, height1,
6059 dst2_x, dst2_y + ypos2 - j);
6060 BlitBitmapMasked(bm_left, drawto,
6061 src2_x, src2_y + ypos4, width, height2,
6062 dst2_x, dst2_y + ypos4 - j);
6063 SetClipOrigin(bm_right, gc_right,
6064 dst1_x - src1_x, dst1_y - src1_y + j);
6065 BlitBitmapMasked(bm_right, drawto,
6066 src1_x, src1_y + ypos2, width, height1,
6067 dst1_x, dst1_y + ypos2 + j);
6068 BlitBitmapMasked(bm_right, drawto,
6069 src1_x, src1_y + ypos4, width, height2 - j,
6070 dst1_x, dst1_y + ypos4 + j);
6073 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
6074 int src2_x = DXSIZE - i, src2_y = DOOR_GFX_PAGEY1;
6075 int dst1_x = DX + DXSIZE - i, dst1_y = DY;
6076 int dst2_x = DX, dst2_y = DY;
6077 int width = i, height = DYSIZE;
6078 int ypos1 = 63, ypos2 = 77, ypos3 = 140, ypos4 = 203;
6080 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y + j);
6081 BlitBitmapMasked(bitmap, drawto,
6082 src1_x, src1_y, width, ypos2,
6083 dst1_x, dst1_y + j);
6084 BlitBitmapMasked(bitmap, drawto,
6085 src1_x, src1_y + ypos3, width, ypos1,
6086 dst1_x, dst1_y + ypos3 + j);
6087 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y - j);
6088 BlitBitmapMasked(bitmap, drawto,
6089 src2_x, src2_y + j, width, ypos2 - j,
6091 BlitBitmapMasked(bitmap, drawto,
6092 src2_x, src2_y + ypos3, width, ypos1,
6093 dst2_x, dst2_y + ypos3 - j);
6095 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y - j);
6096 BlitBitmapMasked(bitmap, drawto,
6097 src2_x, src2_y + ypos2, width, ypos1,
6098 dst2_x, dst2_y + ypos2 - j);
6099 BlitBitmapMasked(bitmap, drawto,
6100 src2_x, src2_y + ypos4, width, ypos2,
6101 dst2_x, dst2_y + ypos4 - j);
6102 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y + j);
6103 BlitBitmapMasked(bitmap, drawto,
6104 src1_x, src1_y + ypos2, width, ypos1,
6105 dst1_x, dst1_y + ypos2 + j);
6106 BlitBitmapMasked(bitmap, drawto,
6107 src1_x, src1_y + ypos4, width, ypos2 - j,
6108 dst1_x, dst1_y + ypos4 + j);
6111 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
6112 BlitBitmapMasked(bitmap, drawto,
6113 DXSIZE, DOOR_GFX_PAGEY1, i, 77,
6114 DX + DXSIZE - i, DY + j);
6115 BlitBitmapMasked(bitmap, drawto,
6116 DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
6117 DX + DXSIZE - i, DY + 140 + j);
6118 SetClipOrigin(bitmap, gc, DX - DXSIZE + i,
6119 DY - (DOOR_GFX_PAGEY1 + j));
6120 BlitBitmapMasked(bitmap, drawto,
6121 DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
6123 BlitBitmapMasked(bitmap, drawto,
6124 DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
6127 BlitBitmapMasked(bitmap, drawto,
6128 DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
6130 BlitBitmapMasked(bitmap, drawto,
6131 DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
6133 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
6134 BlitBitmapMasked(bitmap, drawto,
6135 DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
6136 DX + DXSIZE - i, DY + 77 + j);
6137 BlitBitmapMasked(bitmap, drawto,
6138 DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
6139 DX + DXSIZE - i, DY + 203 + j);
6144 redraw_mask |= REDRAW_DOOR_1;
6145 door_1_done = (a == end);
6148 if (door_state & DOOR_ACTION_2 &&
6149 x * door_2.step_offset <= door_size_2)
6151 int a = MIN(x * door_2.step_offset, door_size);
6152 int p = (door_state & DOOR_OPEN_2 ? door_size - a : a);
6153 int i = p + door_skip;
6156 struct GraphicInfo *g_left = &graphic_info[IMG_DOOR_2_WING_LEFT];
6157 struct GraphicInfo *g_right = &graphic_info[IMG_DOOR_2_WING_RIGHT];
6158 Bitmap *bm_left = g_left->bitmap;
6159 Bitmap *bm_right = g_right->bitmap;
6160 GC gc_left = bm_left->stored_clip_gc;
6161 GC gc_right = bm_right->stored_clip_gc;
6164 int classic_vxsize = 100;
6165 int classic_vysize = 100;
6166 boolean classic_door_2_size = (VXSIZE == classic_vxsize &&
6167 VYSIZE == classic_vysize);
6169 if (door_2.anim_mode & ANIM_STATIC_PANEL)
6171 BlitBitmap(bitmap_db_door, drawto,
6172 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2,
6173 VXSIZE, VYSIZE, VX, VY);
6175 else if (x <= VYSIZE)
6177 BlitBitmap(bitmap_db_door, drawto,
6178 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + p / 2,
6179 VXSIZE, VYSIZE - p / 2, VX, VY);
6181 ClearRectangle(drawto, VX, VY + VYSIZE - p / 2, VXSIZE, p / 2);
6184 if (door_2.anim_mode & ANIM_HORIZONTAL && x <= VXSIZE)
6187 int src1_x = g_right->src_x;
6188 int src1_y = g_right->src_y;
6189 int src2_x = g_left->src_x + g_left->width - i;
6190 int src2_y = g_left->src_y;
6191 int dst1_x = VX + VXSIZE - i;
6196 int height = VYSIZE;
6198 SetClipOrigin(bm_right, gc_right, dst1_x - src1_x, dst1_y - src1_y);
6199 BlitBitmapMasked(bm_right, drawto, src1_x, src1_y, width, height,
6202 SetClipOrigin(bm_left, gc_left, dst2_x - src2_x, dst2_y - src2_y);
6203 BlitBitmapMasked(bm_left, drawto, src2_x, src2_y, width, height,
6206 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
6207 int src2_x = VXSIZE - i, src2_y = DOOR_GFX_PAGEY2;
6208 int dst1_x = VX + VXSIZE - i, dst1_y = VY;
6209 int dst2_x = VX, dst2_y = VY;
6210 int width = i, height = VYSIZE;
6212 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
6213 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
6216 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
6217 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
6221 else if (door_2.anim_mode & ANIM_VERTICAL && x <= VYSIZE)
6224 int src1_x = g_right->src_x;
6225 int src1_y = g_right->src_y;
6226 int src2_x = g_left->src_x;
6227 int src2_y = g_left->src_y + g_left->height - i;
6229 int dst1_y = VY + VYSIZE - i;
6235 SetClipOrigin(bm_right, gc_right, dst1_x - src1_x, dst1_y - src1_y);
6236 BlitBitmapMasked(bm_right, drawto, src1_x, src1_y, width, height,
6239 SetClipOrigin(bm_left, gc_left, dst2_x - src2_x, dst2_y - src2_y);
6240 BlitBitmapMasked(bm_left, drawto, src2_x, src2_y, width, height,
6243 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
6244 int src2_x = 0, src2_y = DOOR_GFX_PAGEY2 + VYSIZE - i;
6245 int dst1_x = VX, dst1_y = VY + VYSIZE - i;
6246 int dst2_x = VX, dst2_y = VY;
6247 int width = VXSIZE, height = i;
6249 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
6250 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
6253 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
6254 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
6258 else if (classic_door_2_size && x <= VXSIZE) /* ANIM_DEFAULT */
6260 int j = (door_2.anim_mode == ANIM_DEFAULT ? (VXSIZE - i) / 3 : 0);
6263 int src1_x = g_right->src_x;
6264 int src1_y = g_right->src_y;
6265 int src2_x = g_left->src_x + g_left->width - i;
6266 int src2_y = g_left->src_y;
6267 int dst1_x = VX + VXSIZE - i;
6272 int height = VYSIZE / 2;
6273 int ypos1 = 0, ypos2 = VYSIZE / 2;
6275 SetClipOrigin(bm_right, gc_right,
6276 dst1_x - src1_x, dst1_y - src1_y + j);
6277 BlitBitmapMasked(bm_right, drawto,
6278 src1_x, src1_y + ypos1, width, height,
6279 dst1_x, dst1_y + ypos1 + j);
6280 SetClipOrigin(bm_left, gc_left,
6281 dst2_x - src2_x, dst2_y - src2_y - j);
6282 BlitBitmapMasked(bm_left, drawto,
6283 src2_x, src2_y + ypos1 + j, width, height - j,
6284 dst2_x, dst2_y + ypos1);
6286 SetClipOrigin(bm_left, gc_left,
6287 dst2_x - src2_x, dst2_y - src2_y - j);
6288 BlitBitmapMasked(bm_left, drawto,
6289 src2_x, src2_y + ypos2, width, height,
6290 dst2_x, dst2_y + ypos2 - j);
6291 SetClipOrigin(bm_right, gc_right,
6292 dst1_x - src1_x, dst1_y - src1_y + j);
6293 BlitBitmapMasked(bm_right, drawto,
6294 src1_x, src1_y + ypos2, width, height - j,
6295 dst1_x, dst1_y + ypos2 + j);
6297 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
6298 int src2_x = VXSIZE - i, src2_y = DOOR_GFX_PAGEY2;
6299 int dst1_x = VX + VXSIZE - i, dst1_y = VY;
6300 int dst2_x = VX, dst2_y = VY;
6301 int width = i, height = VYSIZE;
6302 int ypos = VYSIZE / 2;
6304 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y + j);
6305 BlitBitmapMasked(bitmap, drawto,
6306 src1_x, src1_y, width, ypos,
6307 dst1_x, dst1_y + j);
6308 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src1_y - j);
6309 BlitBitmapMasked(bitmap, drawto,
6310 src2_x, src2_y + j, width, ypos - j,
6313 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src1_y - j);
6314 BlitBitmapMasked(bitmap, drawto,
6315 src2_x, src2_y + ypos, width, ypos,
6316 dst2_x, dst2_y + ypos - j);
6317 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y + j);
6318 BlitBitmapMasked(bitmap, drawto,
6319 src1_x, src1_y + ypos, width, ypos - j,
6320 dst1_x, dst1_y + ypos + j);
6323 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
6324 BlitBitmapMasked(bitmap, drawto,
6325 VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
6326 VX + VXSIZE - i, VY + j);
6327 SetClipOrigin(bitmap, gc,
6328 VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
6329 BlitBitmapMasked(bitmap, drawto,
6330 VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
6333 BlitBitmapMasked(bitmap, drawto,
6334 VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
6335 i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
6336 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
6337 BlitBitmapMasked(bitmap, drawto,
6338 VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
6340 VX + VXSIZE - i, VY + VYSIZE / 2 + j);
6345 redraw_mask |= REDRAW_DOOR_2;
6346 door_2_done = (a == VXSIZE);
6349 if (!(door_state & DOOR_NO_DELAY))
6353 if (game_status == GAME_MODE_MAIN)
6356 WaitUntilDelayReached(&door_delay, door_delay_value);
6361 if (door_state & DOOR_ACTION_1)
6362 door1 = door_state & DOOR_ACTION_1;
6363 if (door_state & DOOR_ACTION_2)
6364 door2 = door_state & DOOR_ACTION_2;
6366 return (door1 | door2);
6371 void DrawSpecialEditorDoor()
6374 struct GraphicInfo *gfx1 = &graphic_info[IMG_DOOR_2_TOP_BORDER_CORRECTION];
6375 int top_border_width = gfx1->width;
6376 int top_border_height = gfx1->height;
6377 int outer_border = viewport.door_2[GAME_MODE_EDITOR].border_size;
6378 int ex = EX - outer_border;
6379 int ey = EY - outer_border;
6380 int vy = VY - outer_border;
6381 int exsize = EXSIZE + 2 * outer_border;
6383 CloseDoor(DOOR_CLOSE_2);
6385 /* draw bigger level editor toolbox window */
6386 BlitBitmap(gfx1->bitmap, drawto, gfx1->src_x, gfx1->src_y,
6387 top_border_width, top_border_height, ex, ey - top_border_height);
6388 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto, ex, vy,
6389 exsize, EYSIZE - VYSIZE + outer_border, ex, ey);
6391 /* draw bigger level editor toolbox window */
6392 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
6393 DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
6395 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
6396 EX - 6, VY - 4, EXSIZE + 12, EYSIZE - VYSIZE + 4,
6400 redraw_mask |= REDRAW_ALL;
6403 void UndrawSpecialEditorDoor()
6406 struct GraphicInfo *gfx1 = &graphic_info[IMG_DOOR_2_TOP_BORDER_CORRECTION];
6407 int top_border_width = gfx1->width;
6408 int top_border_height = gfx1->height;
6409 int outer_border = viewport.door_2[GAME_MODE_EDITOR].border_size;
6410 int ex = EX - outer_border;
6411 int ey = EY - outer_border;
6412 int ey_top = ey - top_border_height;
6413 int exsize = EXSIZE + 2 * outer_border;
6414 int eysize = EYSIZE + 2 * outer_border;
6416 /* draw normal tape recorder window */
6417 if (graphic_info[IMG_GLOBAL_BORDER].bitmap)
6419 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
6420 ex, ey_top, top_border_width, top_border_height,
6422 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
6423 ex, ey, exsize, eysize, ex, ey);
6427 // if screen background is set to "[NONE]", clear editor toolbox window
6428 ClearRectangle(drawto, ex, ey_top, top_border_width, top_border_height);
6429 ClearRectangle(drawto, ex, ey, exsize, eysize);
6432 /* draw normal tape recorder window */
6433 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
6434 EX - 6, EY - 12, EXSIZE + 12, EYSIZE - VYSIZE + 12,
6438 redraw_mask |= REDRAW_ALL;
6442 /* ---------- new tool button stuff ---------------------------------------- */
6449 struct TextPosInfo *pos;
6452 } toolbutton_info[NUM_TOOL_BUTTONS] =
6455 IMG_REQUEST_BUTTON_GFX_YES, &request.button.yes,
6456 TOOL_CTRL_ID_YES, "yes"
6459 IMG_REQUEST_BUTTON_GFX_NO, &request.button.no,
6460 TOOL_CTRL_ID_NO, "no"
6463 IMG_REQUEST_BUTTON_GFX_CONFIRM, &request.button.confirm,
6464 TOOL_CTRL_ID_CONFIRM, "confirm"
6467 IMG_REQUEST_BUTTON_GFX_PLAYER_1, &request.button.player_1,
6468 TOOL_CTRL_ID_PLAYER_1, "player 1"
6471 IMG_REQUEST_BUTTON_GFX_PLAYER_2, &request.button.player_2,
6472 TOOL_CTRL_ID_PLAYER_2, "player 2"
6475 IMG_REQUEST_BUTTON_GFX_PLAYER_3, &request.button.player_3,
6476 TOOL_CTRL_ID_PLAYER_3, "player 3"
6479 IMG_REQUEST_BUTTON_GFX_PLAYER_4, &request.button.player_4,
6480 TOOL_CTRL_ID_PLAYER_4, "player 4"
6484 void CreateToolButtons()
6488 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
6490 struct GraphicInfo *gfx = &graphic_info[toolbutton_info[i].graphic];
6491 struct TextPosInfo *pos = toolbutton_info[i].pos;
6492 struct GadgetInfo *gi;
6493 Bitmap *deco_bitmap = None;
6494 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
6495 unsigned int event_mask = GD_EVENT_RELEASED;
6498 int gd_x = gfx->src_x;
6499 int gd_y = gfx->src_y;
6500 int gd_xp = gfx->src_x + gfx->pressed_xoffset;
6501 int gd_yp = gfx->src_y + gfx->pressed_yoffset;
6504 if (global.use_envelope_request)
6505 setRequestPosition(&dx, &dy, TRUE);
6507 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
6509 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
6511 getSizedGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr), 0,
6512 pos->size, &deco_bitmap, &deco_x, &deco_y);
6513 deco_xpos = (gfx->width - pos->size) / 2;
6514 deco_ypos = (gfx->height - pos->size) / 2;
6517 gi = CreateGadget(GDI_CUSTOM_ID, id,
6518 GDI_INFO_TEXT, toolbutton_info[i].infotext,
6521 GDI_WIDTH, gfx->width,
6522 GDI_HEIGHT, gfx->height,
6523 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
6524 GDI_STATE, GD_BUTTON_UNPRESSED,
6525 GDI_DESIGN_UNPRESSED, gfx->bitmap, gd_x, gd_y,
6526 GDI_DESIGN_PRESSED, gfx->bitmap, gd_xp, gd_yp,
6527 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
6528 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
6529 GDI_DECORATION_SIZE, pos->size, pos->size,
6530 GDI_DECORATION_SHIFTING, 1, 1,
6531 GDI_DIRECT_DRAW, FALSE,
6532 GDI_EVENT_MASK, event_mask,
6533 GDI_CALLBACK_ACTION, HandleToolButtons,
6537 Error(ERR_EXIT, "cannot create gadget");
6539 tool_gadget[id] = gi;
6545 /* graphic position values for tool buttons */
6546 #define TOOL_BUTTON_YES_XPOS 2
6547 #define TOOL_BUTTON_YES_YPOS 250
6548 #define TOOL_BUTTON_YES_GFX_YPOS 0
6549 #define TOOL_BUTTON_YES_XSIZE 46
6550 #define TOOL_BUTTON_YES_YSIZE 28
6551 #define TOOL_BUTTON_NO_XPOS 52
6552 #define TOOL_BUTTON_NO_YPOS TOOL_BUTTON_YES_YPOS
6553 #define TOOL_BUTTON_NO_GFX_YPOS TOOL_BUTTON_YES_GFX_YPOS
6554 #define TOOL_BUTTON_NO_XSIZE TOOL_BUTTON_YES_XSIZE
6555 #define TOOL_BUTTON_NO_YSIZE TOOL_BUTTON_YES_YSIZE
6556 #define TOOL_BUTTON_CONFIRM_XPOS TOOL_BUTTON_YES_XPOS
6557 #define TOOL_BUTTON_CONFIRM_YPOS TOOL_BUTTON_YES_YPOS
6558 #define TOOL_BUTTON_CONFIRM_GFX_YPOS 30
6559 #define TOOL_BUTTON_CONFIRM_XSIZE 96
6560 #define TOOL_BUTTON_CONFIRM_YSIZE TOOL_BUTTON_YES_YSIZE
6561 #define TOOL_BUTTON_PLAYER_XSIZE 30
6562 #define TOOL_BUTTON_PLAYER_YSIZE 30
6563 #define TOOL_BUTTON_PLAYER_GFX_XPOS 5
6564 #define TOOL_BUTTON_PLAYER_GFX_YPOS 185
6565 #define TOOL_BUTTON_PLAYER_XPOS (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
6566 #define TOOL_BUTTON_PLAYER_YPOS (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
6567 #define TOOL_BUTTON_PLAYER1_XPOS (TOOL_BUTTON_PLAYER_XPOS \
6568 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
6569 #define TOOL_BUTTON_PLAYER2_XPOS (TOOL_BUTTON_PLAYER_XPOS \
6570 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
6571 #define TOOL_BUTTON_PLAYER3_XPOS (TOOL_BUTTON_PLAYER_XPOS \
6572 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
6573 #define TOOL_BUTTON_PLAYER4_XPOS (TOOL_BUTTON_PLAYER_XPOS \
6574 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
6575 #define TOOL_BUTTON_PLAYER1_YPOS (TOOL_BUTTON_PLAYER_YPOS \
6576 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
6577 #define TOOL_BUTTON_PLAYER2_YPOS (TOOL_BUTTON_PLAYER_YPOS \
6578 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
6579 #define TOOL_BUTTON_PLAYER3_YPOS (TOOL_BUTTON_PLAYER_YPOS \
6580 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
6581 #define TOOL_BUTTON_PLAYER4_YPOS (TOOL_BUTTON_PLAYER_YPOS \
6582 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
6591 } toolbutton_info[NUM_TOOL_BUTTONS] =
6594 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_GFX_YPOS,
6595 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_YPOS,
6596 TOOL_BUTTON_YES_XSIZE, TOOL_BUTTON_YES_YSIZE,
6601 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_GFX_YPOS,
6602 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_YPOS,
6603 TOOL_BUTTON_NO_XSIZE, TOOL_BUTTON_NO_YSIZE,
6608 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_GFX_YPOS,
6609 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_YPOS,
6610 TOOL_BUTTON_CONFIRM_XSIZE, TOOL_BUTTON_CONFIRM_YSIZE,
6611 TOOL_CTRL_ID_CONFIRM,
6615 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
6616 TOOL_BUTTON_PLAYER1_XPOS, TOOL_BUTTON_PLAYER1_YPOS,
6617 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
6618 TOOL_CTRL_ID_PLAYER_1,
6622 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
6623 TOOL_BUTTON_PLAYER2_XPOS, TOOL_BUTTON_PLAYER2_YPOS,
6624 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
6625 TOOL_CTRL_ID_PLAYER_2,
6629 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
6630 TOOL_BUTTON_PLAYER3_XPOS, TOOL_BUTTON_PLAYER3_YPOS,
6631 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
6632 TOOL_CTRL_ID_PLAYER_3,
6636 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
6637 TOOL_BUTTON_PLAYER4_XPOS, TOOL_BUTTON_PLAYER4_YPOS,
6638 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
6639 TOOL_CTRL_ID_PLAYER_4,
6644 void CreateToolButtons()
6648 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
6650 Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
6651 Bitmap *deco_bitmap = None;
6652 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
6653 struct GadgetInfo *gi;
6654 unsigned int event_mask;
6655 int gd_xoffset, gd_yoffset;
6656 int gd_x1, gd_x2, gd_y;
6659 event_mask = GD_EVENT_RELEASED;
6661 gd_xoffset = toolbutton_info[i].xpos;
6662 gd_yoffset = toolbutton_info[i].ypos;
6663 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
6664 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
6665 gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
6667 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
6669 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
6671 getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr),
6672 &deco_bitmap, &deco_x, &deco_y);
6673 deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
6674 deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
6677 gi = CreateGadget(GDI_CUSTOM_ID, id,
6678 GDI_INFO_TEXT, toolbutton_info[i].infotext,
6679 GDI_X, DX + toolbutton_info[i].x,
6680 GDI_Y, DY + toolbutton_info[i].y,
6681 GDI_WIDTH, toolbutton_info[i].width,
6682 GDI_HEIGHT, toolbutton_info[i].height,
6683 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
6684 GDI_STATE, GD_BUTTON_UNPRESSED,
6685 GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
6686 GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
6687 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
6688 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
6689 GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
6690 GDI_DECORATION_SHIFTING, 1, 1,
6691 GDI_DIRECT_DRAW, FALSE,
6692 GDI_EVENT_MASK, event_mask,
6693 GDI_CALLBACK_ACTION, HandleToolButtons,
6697 Error(ERR_EXIT, "cannot create gadget");
6699 tool_gadget[id] = gi;
6705 void FreeToolButtons()
6709 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
6710 FreeGadget(tool_gadget[i]);
6713 static void UnmapToolButtons()
6717 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
6718 UnmapGadget(tool_gadget[i]);
6721 static void HandleToolButtons(struct GadgetInfo *gi)
6723 request_gadget_id = gi->custom_id;
6726 static struct Mapping_EM_to_RND_object
6729 boolean is_rnd_to_em_mapping; /* unique mapping EM <-> RND */
6730 boolean is_backside; /* backside of moving element */
6736 em_object_mapping_list[] =
6739 Xblank, TRUE, FALSE,
6743 Yacid_splash_eB, FALSE, FALSE,
6744 EL_ACID_SPLASH_RIGHT, -1, -1
6747 Yacid_splash_wB, FALSE, FALSE,
6748 EL_ACID_SPLASH_LEFT, -1, -1
6751 #ifdef EM_ENGINE_BAD_ROLL
6753 Xstone_force_e, FALSE, FALSE,
6754 EL_ROCK, -1, MV_BIT_RIGHT
6757 Xstone_force_w, FALSE, FALSE,
6758 EL_ROCK, -1, MV_BIT_LEFT
6761 Xnut_force_e, FALSE, FALSE,
6762 EL_NUT, -1, MV_BIT_RIGHT
6765 Xnut_force_w, FALSE, FALSE,
6766 EL_NUT, -1, MV_BIT_LEFT
6769 Xspring_force_e, FALSE, FALSE,
6770 EL_SPRING, -1, MV_BIT_RIGHT
6773 Xspring_force_w, FALSE, FALSE,
6774 EL_SPRING, -1, MV_BIT_LEFT
6777 Xemerald_force_e, FALSE, FALSE,
6778 EL_EMERALD, -1, MV_BIT_RIGHT
6781 Xemerald_force_w, FALSE, FALSE,
6782 EL_EMERALD, -1, MV_BIT_LEFT
6785 Xdiamond_force_e, FALSE, FALSE,
6786 EL_DIAMOND, -1, MV_BIT_RIGHT
6789 Xdiamond_force_w, FALSE, FALSE,
6790 EL_DIAMOND, -1, MV_BIT_LEFT
6793 Xbomb_force_e, FALSE, FALSE,
6794 EL_BOMB, -1, MV_BIT_RIGHT
6797 Xbomb_force_w, FALSE, FALSE,
6798 EL_BOMB, -1, MV_BIT_LEFT
6800 #endif /* EM_ENGINE_BAD_ROLL */
6803 Xstone, TRUE, FALSE,
6807 Xstone_pause, FALSE, FALSE,
6811 Xstone_fall, FALSE, FALSE,
6815 Ystone_s, FALSE, FALSE,
6816 EL_ROCK, ACTION_FALLING, -1
6819 Ystone_sB, FALSE, TRUE,
6820 EL_ROCK, ACTION_FALLING, -1
6823 Ystone_e, FALSE, FALSE,
6824 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
6827 Ystone_eB, FALSE, TRUE,
6828 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
6831 Ystone_w, FALSE, FALSE,
6832 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
6835 Ystone_wB, FALSE, TRUE,
6836 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
6843 Xnut_pause, FALSE, FALSE,
6847 Xnut_fall, FALSE, FALSE,
6851 Ynut_s, FALSE, FALSE,
6852 EL_NUT, ACTION_FALLING, -1
6855 Ynut_sB, FALSE, TRUE,
6856 EL_NUT, ACTION_FALLING, -1
6859 Ynut_e, FALSE, FALSE,
6860 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
6863 Ynut_eB, FALSE, TRUE,
6864 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
6867 Ynut_w, FALSE, FALSE,
6868 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
6871 Ynut_wB, FALSE, TRUE,
6872 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
6875 Xbug_n, TRUE, FALSE,
6879 Xbug_e, TRUE, FALSE,
6880 EL_BUG_RIGHT, -1, -1
6883 Xbug_s, TRUE, FALSE,
6887 Xbug_w, TRUE, FALSE,
6891 Xbug_gon, FALSE, FALSE,
6895 Xbug_goe, FALSE, FALSE,
6896 EL_BUG_RIGHT, -1, -1
6899 Xbug_gos, FALSE, FALSE,
6903 Xbug_gow, FALSE, FALSE,
6907 Ybug_n, FALSE, FALSE,
6908 EL_BUG, ACTION_MOVING, MV_BIT_UP
6911 Ybug_nB, FALSE, TRUE,
6912 EL_BUG, ACTION_MOVING, MV_BIT_UP
6915 Ybug_e, FALSE, FALSE,
6916 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
6919 Ybug_eB, FALSE, TRUE,
6920 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
6923 Ybug_s, FALSE, FALSE,
6924 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
6927 Ybug_sB, FALSE, TRUE,
6928 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
6931 Ybug_w, FALSE, FALSE,
6932 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
6935 Ybug_wB, FALSE, TRUE,
6936 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
6939 Ybug_w_n, FALSE, FALSE,
6940 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
6943 Ybug_n_e, FALSE, FALSE,
6944 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
6947 Ybug_e_s, FALSE, FALSE,
6948 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
6951 Ybug_s_w, FALSE, FALSE,
6952 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
6955 Ybug_e_n, FALSE, FALSE,
6956 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
6959 Ybug_s_e, FALSE, FALSE,
6960 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
6963 Ybug_w_s, FALSE, FALSE,
6964 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
6967 Ybug_n_w, FALSE, FALSE,
6968 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
6971 Ybug_stone, FALSE, FALSE,
6972 EL_BUG, ACTION_SMASHED_BY_ROCK, -1
6975 Ybug_spring, FALSE, FALSE,
6976 EL_BUG, ACTION_SMASHED_BY_SPRING, -1
6979 Xtank_n, TRUE, FALSE,
6980 EL_SPACESHIP_UP, -1, -1
6983 Xtank_e, TRUE, FALSE,
6984 EL_SPACESHIP_RIGHT, -1, -1
6987 Xtank_s, TRUE, FALSE,
6988 EL_SPACESHIP_DOWN, -1, -1
6991 Xtank_w, TRUE, FALSE,
6992 EL_SPACESHIP_LEFT, -1, -1
6995 Xtank_gon, FALSE, FALSE,
6996 EL_SPACESHIP_UP, -1, -1
6999 Xtank_goe, FALSE, FALSE,
7000 EL_SPACESHIP_RIGHT, -1, -1
7003 Xtank_gos, FALSE, FALSE,
7004 EL_SPACESHIP_DOWN, -1, -1
7007 Xtank_gow, FALSE, FALSE,
7008 EL_SPACESHIP_LEFT, -1, -1
7011 Ytank_n, FALSE, FALSE,
7012 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
7015 Ytank_nB, FALSE, TRUE,
7016 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
7019 Ytank_e, FALSE, FALSE,
7020 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
7023 Ytank_eB, FALSE, TRUE,
7024 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
7027 Ytank_s, FALSE, FALSE,
7028 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
7031 Ytank_sB, FALSE, TRUE,
7032 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
7035 Ytank_w, FALSE, FALSE,
7036 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
7039 Ytank_wB, FALSE, TRUE,
7040 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
7043 Ytank_w_n, FALSE, FALSE,
7044 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
7047 Ytank_n_e, FALSE, FALSE,
7048 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
7051 Ytank_e_s, FALSE, FALSE,
7052 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
7055 Ytank_s_w, FALSE, FALSE,
7056 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
7059 Ytank_e_n, FALSE, FALSE,
7060 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
7063 Ytank_s_e, FALSE, FALSE,
7064 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
7067 Ytank_w_s, FALSE, FALSE,
7068 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
7071 Ytank_n_w, FALSE, FALSE,
7072 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
7075 Ytank_stone, FALSE, FALSE,
7076 EL_SPACESHIP, ACTION_SMASHED_BY_ROCK, -1
7079 Ytank_spring, FALSE, FALSE,
7080 EL_SPACESHIP, ACTION_SMASHED_BY_SPRING, -1
7083 Xandroid, TRUE, FALSE,
7084 EL_EMC_ANDROID, ACTION_ACTIVE, -1
7087 Xandroid_1_n, FALSE, FALSE,
7088 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
7091 Xandroid_2_n, FALSE, FALSE,
7092 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
7095 Xandroid_1_e, FALSE, FALSE,
7096 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
7099 Xandroid_2_e, FALSE, FALSE,
7100 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
7103 Xandroid_1_w, FALSE, FALSE,
7104 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
7107 Xandroid_2_w, FALSE, FALSE,
7108 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
7111 Xandroid_1_s, FALSE, FALSE,
7112 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
7115 Xandroid_2_s, FALSE, FALSE,
7116 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
7119 Yandroid_n, FALSE, FALSE,
7120 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
7123 Yandroid_nB, FALSE, TRUE,
7124 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
7127 Yandroid_ne, FALSE, FALSE,
7128 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPRIGHT
7131 Yandroid_neB, FALSE, TRUE,
7132 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPRIGHT
7135 Yandroid_e, FALSE, FALSE,
7136 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
7139 Yandroid_eB, FALSE, TRUE,
7140 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
7143 Yandroid_se, FALSE, FALSE,
7144 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNRIGHT
7147 Yandroid_seB, FALSE, TRUE,
7148 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNRIGHT
7151 Yandroid_s, FALSE, FALSE,
7152 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
7155 Yandroid_sB, FALSE, TRUE,
7156 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
7159 Yandroid_sw, FALSE, FALSE,
7160 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNLEFT
7163 Yandroid_swB, FALSE, TRUE,
7164 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNLEFT
7167 Yandroid_w, FALSE, FALSE,
7168 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
7171 Yandroid_wB, FALSE, TRUE,
7172 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
7175 Yandroid_nw, FALSE, FALSE,
7176 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPLEFT
7179 Yandroid_nwB, FALSE, TRUE,
7180 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPLEFT
7183 Xspring, TRUE, FALSE,
7187 Xspring_pause, FALSE, FALSE,
7191 Xspring_e, FALSE, FALSE,
7195 Xspring_w, FALSE, FALSE,
7199 Xspring_fall, FALSE, FALSE,
7203 Yspring_s, FALSE, FALSE,
7204 EL_SPRING, ACTION_FALLING, -1
7207 Yspring_sB, FALSE, TRUE,
7208 EL_SPRING, ACTION_FALLING, -1
7211 Yspring_e, FALSE, FALSE,
7212 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
7215 Yspring_eB, FALSE, TRUE,
7216 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
7219 Yspring_w, FALSE, FALSE,
7220 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
7223 Yspring_wB, FALSE, TRUE,
7224 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
7227 Yspring_kill_e, FALSE, FALSE,
7228 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
7231 Yspring_kill_eB, FALSE, TRUE,
7232 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
7235 Yspring_kill_w, FALSE, FALSE,
7236 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
7239 Yspring_kill_wB, FALSE, TRUE,
7240 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
7243 Xeater_n, TRUE, FALSE,
7244 EL_YAMYAM_UP, -1, -1
7247 Xeater_e, TRUE, FALSE,
7248 EL_YAMYAM_RIGHT, -1, -1
7251 Xeater_w, TRUE, FALSE,
7252 EL_YAMYAM_LEFT, -1, -1
7255 Xeater_s, TRUE, FALSE,
7256 EL_YAMYAM_DOWN, -1, -1
7259 Yeater_n, FALSE, FALSE,
7260 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
7263 Yeater_nB, FALSE, TRUE,
7264 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
7267 Yeater_e, FALSE, FALSE,
7268 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
7271 Yeater_eB, FALSE, TRUE,
7272 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
7275 Yeater_s, FALSE, FALSE,
7276 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
7279 Yeater_sB, FALSE, TRUE,
7280 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
7283 Yeater_w, FALSE, FALSE,
7284 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
7287 Yeater_wB, FALSE, TRUE,
7288 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
7291 Yeater_stone, FALSE, FALSE,
7292 EL_YAMYAM, ACTION_SMASHED_BY_ROCK, -1
7295 Yeater_spring, FALSE, FALSE,
7296 EL_YAMYAM, ACTION_SMASHED_BY_SPRING, -1
7299 Xalien, TRUE, FALSE,
7303 Xalien_pause, FALSE, FALSE,
7307 Yalien_n, FALSE, FALSE,
7308 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
7311 Yalien_nB, FALSE, TRUE,
7312 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
7315 Yalien_e, FALSE, FALSE,
7316 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
7319 Yalien_eB, FALSE, TRUE,
7320 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
7323 Yalien_s, FALSE, FALSE,
7324 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
7327 Yalien_sB, FALSE, TRUE,
7328 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
7331 Yalien_w, FALSE, FALSE,
7332 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
7335 Yalien_wB, FALSE, TRUE,
7336 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
7339 Yalien_stone, FALSE, FALSE,
7340 EL_ROBOT, ACTION_SMASHED_BY_ROCK, -1
7343 Yalien_spring, FALSE, FALSE,
7344 EL_ROBOT, ACTION_SMASHED_BY_SPRING, -1
7347 Xemerald, TRUE, FALSE,
7351 Xemerald_pause, FALSE, FALSE,
7355 Xemerald_fall, FALSE, FALSE,
7359 Xemerald_shine, FALSE, FALSE,
7360 EL_EMERALD, ACTION_TWINKLING, -1
7363 Yemerald_s, FALSE, FALSE,
7364 EL_EMERALD, ACTION_FALLING, -1
7367 Yemerald_sB, FALSE, TRUE,
7368 EL_EMERALD, ACTION_FALLING, -1
7371 Yemerald_e, FALSE, FALSE,
7372 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
7375 Yemerald_eB, FALSE, TRUE,
7376 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
7379 Yemerald_w, FALSE, FALSE,
7380 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
7383 Yemerald_wB, FALSE, TRUE,
7384 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
7387 Yemerald_eat, FALSE, FALSE,
7388 EL_EMERALD, ACTION_COLLECTING, -1
7391 Yemerald_stone, FALSE, FALSE,
7392 EL_NUT, ACTION_BREAKING, -1
7395 Xdiamond, TRUE, FALSE,
7399 Xdiamond_pause, FALSE, FALSE,
7403 Xdiamond_fall, FALSE, FALSE,
7407 Xdiamond_shine, FALSE, FALSE,
7408 EL_DIAMOND, ACTION_TWINKLING, -1
7411 Ydiamond_s, FALSE, FALSE,
7412 EL_DIAMOND, ACTION_FALLING, -1
7415 Ydiamond_sB, FALSE, TRUE,
7416 EL_DIAMOND, ACTION_FALLING, -1
7419 Ydiamond_e, FALSE, FALSE,
7420 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
7423 Ydiamond_eB, FALSE, TRUE,
7424 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
7427 Ydiamond_w, FALSE, FALSE,
7428 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
7431 Ydiamond_wB, FALSE, TRUE,
7432 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
7435 Ydiamond_eat, FALSE, FALSE,
7436 EL_DIAMOND, ACTION_COLLECTING, -1
7439 Ydiamond_stone, FALSE, FALSE,
7440 EL_DIAMOND, ACTION_SMASHED_BY_ROCK, -1
7443 Xdrip_fall, TRUE, FALSE,
7444 EL_AMOEBA_DROP, -1, -1
7447 Xdrip_stretch, FALSE, FALSE,
7448 EL_AMOEBA_DROP, ACTION_FALLING, -1
7451 Xdrip_stretchB, FALSE, TRUE,
7452 EL_AMOEBA_DROP, ACTION_FALLING, -1
7455 Xdrip_eat, FALSE, FALSE,
7456 EL_AMOEBA_DROP, ACTION_GROWING, -1
7459 Ydrip_s1, FALSE, FALSE,
7460 EL_AMOEBA_DROP, ACTION_FALLING, -1
7463 Ydrip_s1B, FALSE, TRUE,
7464 EL_AMOEBA_DROP, ACTION_FALLING, -1
7467 Ydrip_s2, FALSE, FALSE,
7468 EL_AMOEBA_DROP, ACTION_FALLING, -1
7471 Ydrip_s2B, FALSE, TRUE,
7472 EL_AMOEBA_DROP, ACTION_FALLING, -1
7479 Xbomb_pause, FALSE, FALSE,
7483 Xbomb_fall, FALSE, FALSE,
7487 Ybomb_s, FALSE, FALSE,
7488 EL_BOMB, ACTION_FALLING, -1
7491 Ybomb_sB, FALSE, TRUE,
7492 EL_BOMB, ACTION_FALLING, -1
7495 Ybomb_e, FALSE, FALSE,
7496 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
7499 Ybomb_eB, FALSE, TRUE,
7500 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
7503 Ybomb_w, FALSE, FALSE,
7504 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
7507 Ybomb_wB, FALSE, TRUE,
7508 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
7511 Ybomb_eat, FALSE, FALSE,
7512 EL_BOMB, ACTION_ACTIVATING, -1
7515 Xballoon, TRUE, FALSE,
7519 Yballoon_n, FALSE, FALSE,
7520 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
7523 Yballoon_nB, FALSE, TRUE,
7524 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
7527 Yballoon_e, FALSE, FALSE,
7528 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
7531 Yballoon_eB, FALSE, TRUE,
7532 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
7535 Yballoon_s, FALSE, FALSE,
7536 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
7539 Yballoon_sB, FALSE, TRUE,
7540 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
7543 Yballoon_w, FALSE, FALSE,
7544 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
7547 Yballoon_wB, FALSE, TRUE,
7548 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
7551 Xgrass, TRUE, FALSE,
7552 EL_EMC_GRASS, -1, -1
7555 Ygrass_nB, FALSE, FALSE,
7556 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_UP
7559 Ygrass_eB, FALSE, FALSE,
7560 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_RIGHT
7563 Ygrass_sB, FALSE, FALSE,
7564 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_DOWN
7567 Ygrass_wB, FALSE, FALSE,
7568 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_LEFT
7575 Ydirt_nB, FALSE, FALSE,
7576 EL_SAND, ACTION_DIGGING, MV_BIT_UP
7579 Ydirt_eB, FALSE, FALSE,
7580 EL_SAND, ACTION_DIGGING, MV_BIT_RIGHT
7583 Ydirt_sB, FALSE, FALSE,
7584 EL_SAND, ACTION_DIGGING, MV_BIT_DOWN
7587 Ydirt_wB, FALSE, FALSE,
7588 EL_SAND, ACTION_DIGGING, MV_BIT_LEFT
7591 Xacid_ne, TRUE, FALSE,
7592 EL_ACID_POOL_TOPRIGHT, -1, -1
7595 Xacid_se, TRUE, FALSE,
7596 EL_ACID_POOL_BOTTOMRIGHT, -1, -1
7599 Xacid_s, TRUE, FALSE,
7600 EL_ACID_POOL_BOTTOM, -1, -1
7603 Xacid_sw, TRUE, FALSE,
7604 EL_ACID_POOL_BOTTOMLEFT, -1, -1
7607 Xacid_nw, TRUE, FALSE,
7608 EL_ACID_POOL_TOPLEFT, -1, -1
7611 Xacid_1, TRUE, FALSE,
7615 Xacid_2, FALSE, FALSE,
7619 Xacid_3, FALSE, FALSE,
7623 Xacid_4, FALSE, FALSE,
7627 Xacid_5, FALSE, FALSE,
7631 Xacid_6, FALSE, FALSE,
7635 Xacid_7, FALSE, FALSE,
7639 Xacid_8, FALSE, FALSE,
7643 Xball_1, TRUE, FALSE,
7644 EL_EMC_MAGIC_BALL, -1, -1
7647 Xball_1B, FALSE, FALSE,
7648 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
7651 Xball_2, FALSE, FALSE,
7652 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
7655 Xball_2B, FALSE, FALSE,
7656 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
7659 Yball_eat, FALSE, FALSE,
7660 EL_EMC_MAGIC_BALL, ACTION_DROPPING, -1
7663 Ykey_1_eat, FALSE, FALSE,
7664 EL_EM_KEY_1, ACTION_COLLECTING, -1
7667 Ykey_2_eat, FALSE, FALSE,
7668 EL_EM_KEY_2, ACTION_COLLECTING, -1
7671 Ykey_3_eat, FALSE, FALSE,
7672 EL_EM_KEY_3, ACTION_COLLECTING, -1
7675 Ykey_4_eat, FALSE, FALSE,
7676 EL_EM_KEY_4, ACTION_COLLECTING, -1
7679 Ykey_5_eat, FALSE, FALSE,
7680 EL_EMC_KEY_5, ACTION_COLLECTING, -1
7683 Ykey_6_eat, FALSE, FALSE,
7684 EL_EMC_KEY_6, ACTION_COLLECTING, -1
7687 Ykey_7_eat, FALSE, FALSE,
7688 EL_EMC_KEY_7, ACTION_COLLECTING, -1
7691 Ykey_8_eat, FALSE, FALSE,
7692 EL_EMC_KEY_8, ACTION_COLLECTING, -1
7695 Ylenses_eat, FALSE, FALSE,
7696 EL_EMC_LENSES, ACTION_COLLECTING, -1
7699 Ymagnify_eat, FALSE, FALSE,
7700 EL_EMC_MAGNIFIER, ACTION_COLLECTING, -1
7703 Ygrass_eat, FALSE, FALSE,
7704 EL_EMC_GRASS, ACTION_SNAPPING, -1
7707 Ydirt_eat, FALSE, FALSE,
7708 EL_SAND, ACTION_SNAPPING, -1
7711 Xgrow_ns, TRUE, FALSE,
7712 EL_EXPANDABLE_WALL_VERTICAL, -1, -1
7715 Ygrow_ns_eat, FALSE, FALSE,
7716 EL_EXPANDABLE_WALL_VERTICAL, ACTION_GROWING, -1
7719 Xgrow_ew, TRUE, FALSE,
7720 EL_EXPANDABLE_WALL_HORIZONTAL, -1, -1
7723 Ygrow_ew_eat, FALSE, FALSE,
7724 EL_EXPANDABLE_WALL_HORIZONTAL, ACTION_GROWING, -1
7727 Xwonderwall, TRUE, FALSE,
7728 EL_MAGIC_WALL, -1, -1
7731 XwonderwallB, FALSE, FALSE,
7732 EL_MAGIC_WALL, ACTION_ACTIVE, -1
7735 Xamoeba_1, TRUE, FALSE,
7736 EL_AMOEBA_DRY, ACTION_OTHER, -1
7739 Xamoeba_2, FALSE, FALSE,
7740 EL_AMOEBA_DRY, ACTION_OTHER, -1
7743 Xamoeba_3, FALSE, FALSE,
7744 EL_AMOEBA_DRY, ACTION_OTHER, -1
7747 Xamoeba_4, FALSE, FALSE,
7748 EL_AMOEBA_DRY, ACTION_OTHER, -1
7751 Xamoeba_5, TRUE, FALSE,
7752 EL_AMOEBA_WET, ACTION_OTHER, -1
7755 Xamoeba_6, FALSE, FALSE,
7756 EL_AMOEBA_WET, ACTION_OTHER, -1
7759 Xamoeba_7, FALSE, FALSE,
7760 EL_AMOEBA_WET, ACTION_OTHER, -1
7763 Xamoeba_8, FALSE, FALSE,
7764 EL_AMOEBA_WET, ACTION_OTHER, -1
7767 Xdoor_1, TRUE, FALSE,
7768 EL_EM_GATE_1, -1, -1
7771 Xdoor_2, TRUE, FALSE,
7772 EL_EM_GATE_2, -1, -1
7775 Xdoor_3, TRUE, FALSE,
7776 EL_EM_GATE_3, -1, -1
7779 Xdoor_4, TRUE, FALSE,
7780 EL_EM_GATE_4, -1, -1
7783 Xdoor_5, TRUE, FALSE,
7784 EL_EMC_GATE_5, -1, -1
7787 Xdoor_6, TRUE, FALSE,
7788 EL_EMC_GATE_6, -1, -1
7791 Xdoor_7, TRUE, FALSE,
7792 EL_EMC_GATE_7, -1, -1
7795 Xdoor_8, TRUE, FALSE,
7796 EL_EMC_GATE_8, -1, -1
7799 Xkey_1, TRUE, FALSE,
7803 Xkey_2, TRUE, FALSE,
7807 Xkey_3, TRUE, FALSE,
7811 Xkey_4, TRUE, FALSE,
7815 Xkey_5, TRUE, FALSE,
7816 EL_EMC_KEY_5, -1, -1
7819 Xkey_6, TRUE, FALSE,
7820 EL_EMC_KEY_6, -1, -1
7823 Xkey_7, TRUE, FALSE,
7824 EL_EMC_KEY_7, -1, -1
7827 Xkey_8, TRUE, FALSE,
7828 EL_EMC_KEY_8, -1, -1
7831 Xwind_n, TRUE, FALSE,
7832 EL_BALLOON_SWITCH_UP, -1, -1
7835 Xwind_e, TRUE, FALSE,
7836 EL_BALLOON_SWITCH_RIGHT, -1, -1
7839 Xwind_s, TRUE, FALSE,
7840 EL_BALLOON_SWITCH_DOWN, -1, -1
7843 Xwind_w, TRUE, FALSE,
7844 EL_BALLOON_SWITCH_LEFT, -1, -1
7847 Xwind_nesw, TRUE, FALSE,
7848 EL_BALLOON_SWITCH_ANY, -1, -1
7851 Xwind_stop, TRUE, FALSE,
7852 EL_BALLOON_SWITCH_NONE, -1, -1
7856 EL_EM_EXIT_CLOSED, -1, -1
7859 Xexit_1, TRUE, FALSE,
7860 EL_EM_EXIT_OPEN, -1, -1
7863 Xexit_2, FALSE, FALSE,
7864 EL_EM_EXIT_OPEN, -1, -1
7867 Xexit_3, FALSE, FALSE,
7868 EL_EM_EXIT_OPEN, -1, -1
7871 Xdynamite, TRUE, FALSE,
7872 EL_EM_DYNAMITE, -1, -1
7875 Ydynamite_eat, FALSE, FALSE,
7876 EL_EM_DYNAMITE, ACTION_COLLECTING, -1
7879 Xdynamite_1, TRUE, FALSE,
7880 EL_EM_DYNAMITE_ACTIVE, -1, -1
7883 Xdynamite_2, FALSE, FALSE,
7884 EL_EM_DYNAMITE_ACTIVE, -1, -1
7887 Xdynamite_3, FALSE, FALSE,
7888 EL_EM_DYNAMITE_ACTIVE, -1, -1
7891 Xdynamite_4, FALSE, FALSE,
7892 EL_EM_DYNAMITE_ACTIVE, -1, -1
7895 Xbumper, TRUE, FALSE,
7896 EL_EMC_SPRING_BUMPER, -1, -1
7899 XbumperB, FALSE, FALSE,
7900 EL_EMC_SPRING_BUMPER, ACTION_ACTIVE, -1
7903 Xwheel, TRUE, FALSE,
7904 EL_ROBOT_WHEEL, -1, -1
7907 XwheelB, FALSE, FALSE,
7908 EL_ROBOT_WHEEL, ACTION_ACTIVE, -1
7911 Xswitch, TRUE, FALSE,
7912 EL_EMC_MAGIC_BALL_SWITCH, -1, -1
7915 XswitchB, FALSE, FALSE,
7916 EL_EMC_MAGIC_BALL_SWITCH, ACTION_ACTIVE, -1
7920 EL_QUICKSAND_EMPTY, -1, -1
7923 Xsand_stone, TRUE, FALSE,
7924 EL_QUICKSAND_FULL, -1, -1
7927 Xsand_stonein_1, FALSE, TRUE,
7928 EL_ROCK, ACTION_FILLING, -1
7931 Xsand_stonein_2, FALSE, TRUE,
7932 EL_ROCK, ACTION_FILLING, -1
7935 Xsand_stonein_3, FALSE, TRUE,
7936 EL_ROCK, ACTION_FILLING, -1
7939 Xsand_stonein_4, FALSE, TRUE,
7940 EL_ROCK, ACTION_FILLING, -1
7944 Xsand_stonesand_1, FALSE, FALSE,
7945 EL_QUICKSAND_EMPTYING, -1, -1
7948 Xsand_stonesand_2, FALSE, FALSE,
7949 EL_QUICKSAND_EMPTYING, -1, -1
7952 Xsand_stonesand_3, FALSE, FALSE,
7953 EL_QUICKSAND_EMPTYING, -1, -1
7956 Xsand_stonesand_4, FALSE, FALSE,
7957 EL_QUICKSAND_EMPTYING, -1, -1
7960 Xsand_stonesand_quickout_1, FALSE, FALSE,
7961 EL_QUICKSAND_EMPTYING, -1, -1
7964 Xsand_stonesand_quickout_2, FALSE, FALSE,
7965 EL_QUICKSAND_EMPTYING, -1, -1
7969 Xsand_stonesand_1, FALSE, FALSE,
7970 EL_QUICKSAND_FULL, -1, -1
7973 Xsand_stonesand_2, FALSE, FALSE,
7974 EL_QUICKSAND_FULL, -1, -1
7977 Xsand_stonesand_3, FALSE, FALSE,
7978 EL_QUICKSAND_FULL, -1, -1
7981 Xsand_stonesand_4, FALSE, FALSE,
7982 EL_QUICKSAND_FULL, -1, -1
7986 Xsand_stoneout_1, FALSE, FALSE,
7987 EL_ROCK, ACTION_EMPTYING, -1
7990 Xsand_stoneout_2, FALSE, FALSE,
7991 EL_ROCK, ACTION_EMPTYING, -1
7995 Xsand_sandstone_1, FALSE, FALSE,
7996 EL_QUICKSAND_FILLING, -1, -1
7999 Xsand_sandstone_2, FALSE, FALSE,
8000 EL_QUICKSAND_FILLING, -1, -1
8003 Xsand_sandstone_3, FALSE, FALSE,
8004 EL_QUICKSAND_FILLING, -1, -1
8007 Xsand_sandstone_4, FALSE, FALSE,
8008 EL_QUICKSAND_FILLING, -1, -1
8012 Xsand_sandstone_1, FALSE, FALSE,
8013 EL_QUICKSAND_FULL, -1, -1
8016 Xsand_sandstone_2, FALSE, FALSE,
8017 EL_QUICKSAND_FULL, -1, -1
8020 Xsand_sandstone_3, FALSE, FALSE,
8021 EL_QUICKSAND_FULL, -1, -1
8024 Xsand_sandstone_4, FALSE, FALSE,
8025 EL_QUICKSAND_FULL, -1, -1
8029 Xplant, TRUE, FALSE,
8030 EL_EMC_PLANT, -1, -1
8033 Yplant, FALSE, FALSE,
8034 EL_EMC_PLANT, -1, -1
8037 Xlenses, TRUE, FALSE,
8038 EL_EMC_LENSES, -1, -1
8041 Xmagnify, TRUE, FALSE,
8042 EL_EMC_MAGNIFIER, -1, -1
8045 Xdripper, TRUE, FALSE,
8046 EL_EMC_DRIPPER, -1, -1
8049 XdripperB, FALSE, FALSE,
8050 EL_EMC_DRIPPER, ACTION_ACTIVE, -1
8053 Xfake_blank, TRUE, FALSE,
8054 EL_INVISIBLE_WALL, -1, -1
8057 Xfake_blankB, FALSE, FALSE,
8058 EL_INVISIBLE_WALL, ACTION_ACTIVE, -1
8061 Xfake_grass, TRUE, FALSE,
8062 EL_EMC_FAKE_GRASS, -1, -1
8065 Xfake_grassB, FALSE, FALSE,
8066 EL_EMC_FAKE_GRASS, ACTION_ACTIVE, -1
8069 Xfake_door_1, TRUE, FALSE,
8070 EL_EM_GATE_1_GRAY, -1, -1
8073 Xfake_door_2, TRUE, FALSE,
8074 EL_EM_GATE_2_GRAY, -1, -1
8077 Xfake_door_3, TRUE, FALSE,
8078 EL_EM_GATE_3_GRAY, -1, -1
8081 Xfake_door_4, TRUE, FALSE,
8082 EL_EM_GATE_4_GRAY, -1, -1
8085 Xfake_door_5, TRUE, FALSE,
8086 EL_EMC_GATE_5_GRAY, -1, -1
8089 Xfake_door_6, TRUE, FALSE,
8090 EL_EMC_GATE_6_GRAY, -1, -1
8093 Xfake_door_7, TRUE, FALSE,
8094 EL_EMC_GATE_7_GRAY, -1, -1
8097 Xfake_door_8, TRUE, FALSE,
8098 EL_EMC_GATE_8_GRAY, -1, -1
8101 Xfake_acid_1, TRUE, FALSE,
8102 EL_EMC_FAKE_ACID, -1, -1
8105 Xfake_acid_2, FALSE, FALSE,
8106 EL_EMC_FAKE_ACID, -1, -1
8109 Xfake_acid_3, FALSE, FALSE,
8110 EL_EMC_FAKE_ACID, -1, -1
8113 Xfake_acid_4, FALSE, FALSE,
8114 EL_EMC_FAKE_ACID, -1, -1
8117 Xfake_acid_5, FALSE, FALSE,
8118 EL_EMC_FAKE_ACID, -1, -1
8121 Xfake_acid_6, FALSE, FALSE,
8122 EL_EMC_FAKE_ACID, -1, -1
8125 Xfake_acid_7, FALSE, FALSE,
8126 EL_EMC_FAKE_ACID, -1, -1
8129 Xfake_acid_8, FALSE, FALSE,
8130 EL_EMC_FAKE_ACID, -1, -1
8133 Xsteel_1, TRUE, FALSE,
8134 EL_STEELWALL, -1, -1
8137 Xsteel_2, TRUE, FALSE,
8138 EL_EMC_STEELWALL_2, -1, -1
8141 Xsteel_3, TRUE, FALSE,
8142 EL_EMC_STEELWALL_3, -1, -1
8145 Xsteel_4, TRUE, FALSE,
8146 EL_EMC_STEELWALL_4, -1, -1
8149 Xwall_1, TRUE, FALSE,
8153 Xwall_2, TRUE, FALSE,
8154 EL_EMC_WALL_14, -1, -1
8157 Xwall_3, TRUE, FALSE,
8158 EL_EMC_WALL_15, -1, -1
8161 Xwall_4, TRUE, FALSE,
8162 EL_EMC_WALL_16, -1, -1
8165 Xround_wall_1, TRUE, FALSE,
8166 EL_WALL_SLIPPERY, -1, -1
8169 Xround_wall_2, TRUE, FALSE,
8170 EL_EMC_WALL_SLIPPERY_2, -1, -1
8173 Xround_wall_3, TRUE, FALSE,
8174 EL_EMC_WALL_SLIPPERY_3, -1, -1
8177 Xround_wall_4, TRUE, FALSE,
8178 EL_EMC_WALL_SLIPPERY_4, -1, -1
8181 Xdecor_1, TRUE, FALSE,
8182 EL_EMC_WALL_8, -1, -1
8185 Xdecor_2, TRUE, FALSE,
8186 EL_EMC_WALL_6, -1, -1
8189 Xdecor_3, TRUE, FALSE,
8190 EL_EMC_WALL_4, -1, -1
8193 Xdecor_4, TRUE, FALSE,
8194 EL_EMC_WALL_7, -1, -1
8197 Xdecor_5, TRUE, FALSE,
8198 EL_EMC_WALL_5, -1, -1
8201 Xdecor_6, TRUE, FALSE,
8202 EL_EMC_WALL_9, -1, -1
8205 Xdecor_7, TRUE, FALSE,
8206 EL_EMC_WALL_10, -1, -1
8209 Xdecor_8, TRUE, FALSE,
8210 EL_EMC_WALL_1, -1, -1
8213 Xdecor_9, TRUE, FALSE,
8214 EL_EMC_WALL_2, -1, -1
8217 Xdecor_10, TRUE, FALSE,
8218 EL_EMC_WALL_3, -1, -1
8221 Xdecor_11, TRUE, FALSE,
8222 EL_EMC_WALL_11, -1, -1
8225 Xdecor_12, TRUE, FALSE,
8226 EL_EMC_WALL_12, -1, -1
8229 Xalpha_0, TRUE, FALSE,
8230 EL_CHAR('0'), -1, -1
8233 Xalpha_1, TRUE, FALSE,
8234 EL_CHAR('1'), -1, -1
8237 Xalpha_2, TRUE, FALSE,
8238 EL_CHAR('2'), -1, -1
8241 Xalpha_3, TRUE, FALSE,
8242 EL_CHAR('3'), -1, -1
8245 Xalpha_4, TRUE, FALSE,
8246 EL_CHAR('4'), -1, -1
8249 Xalpha_5, TRUE, FALSE,
8250 EL_CHAR('5'), -1, -1
8253 Xalpha_6, TRUE, FALSE,
8254 EL_CHAR('6'), -1, -1
8257 Xalpha_7, TRUE, FALSE,
8258 EL_CHAR('7'), -1, -1
8261 Xalpha_8, TRUE, FALSE,
8262 EL_CHAR('8'), -1, -1
8265 Xalpha_9, TRUE, FALSE,
8266 EL_CHAR('9'), -1, -1
8269 Xalpha_excla, TRUE, FALSE,
8270 EL_CHAR('!'), -1, -1
8273 Xalpha_quote, TRUE, FALSE,
8274 EL_CHAR('"'), -1, -1
8277 Xalpha_comma, TRUE, FALSE,
8278 EL_CHAR(','), -1, -1
8281 Xalpha_minus, TRUE, FALSE,
8282 EL_CHAR('-'), -1, -1
8285 Xalpha_perio, TRUE, FALSE,
8286 EL_CHAR('.'), -1, -1
8289 Xalpha_colon, TRUE, FALSE,
8290 EL_CHAR(':'), -1, -1
8293 Xalpha_quest, TRUE, FALSE,
8294 EL_CHAR('?'), -1, -1
8297 Xalpha_a, TRUE, FALSE,
8298 EL_CHAR('A'), -1, -1
8301 Xalpha_b, TRUE, FALSE,
8302 EL_CHAR('B'), -1, -1
8305 Xalpha_c, TRUE, FALSE,
8306 EL_CHAR('C'), -1, -1
8309 Xalpha_d, TRUE, FALSE,
8310 EL_CHAR('D'), -1, -1
8313 Xalpha_e, TRUE, FALSE,
8314 EL_CHAR('E'), -1, -1
8317 Xalpha_f, TRUE, FALSE,
8318 EL_CHAR('F'), -1, -1
8321 Xalpha_g, TRUE, FALSE,
8322 EL_CHAR('G'), -1, -1
8325 Xalpha_h, TRUE, FALSE,
8326 EL_CHAR('H'), -1, -1
8329 Xalpha_i, TRUE, FALSE,
8330 EL_CHAR('I'), -1, -1
8333 Xalpha_j, TRUE, FALSE,
8334 EL_CHAR('J'), -1, -1
8337 Xalpha_k, TRUE, FALSE,
8338 EL_CHAR('K'), -1, -1
8341 Xalpha_l, TRUE, FALSE,
8342 EL_CHAR('L'), -1, -1
8345 Xalpha_m, TRUE, FALSE,
8346 EL_CHAR('M'), -1, -1
8349 Xalpha_n, TRUE, FALSE,
8350 EL_CHAR('N'), -1, -1
8353 Xalpha_o, TRUE, FALSE,
8354 EL_CHAR('O'), -1, -1
8357 Xalpha_p, TRUE, FALSE,
8358 EL_CHAR('P'), -1, -1
8361 Xalpha_q, TRUE, FALSE,
8362 EL_CHAR('Q'), -1, -1
8365 Xalpha_r, TRUE, FALSE,
8366 EL_CHAR('R'), -1, -1
8369 Xalpha_s, TRUE, FALSE,
8370 EL_CHAR('S'), -1, -1
8373 Xalpha_t, TRUE, FALSE,
8374 EL_CHAR('T'), -1, -1
8377 Xalpha_u, TRUE, FALSE,
8378 EL_CHAR('U'), -1, -1
8381 Xalpha_v, TRUE, FALSE,
8382 EL_CHAR('V'), -1, -1
8385 Xalpha_w, TRUE, FALSE,
8386 EL_CHAR('W'), -1, -1
8389 Xalpha_x, TRUE, FALSE,
8390 EL_CHAR('X'), -1, -1
8393 Xalpha_y, TRUE, FALSE,
8394 EL_CHAR('Y'), -1, -1
8397 Xalpha_z, TRUE, FALSE,
8398 EL_CHAR('Z'), -1, -1
8401 Xalpha_arrow_e, TRUE, FALSE,
8402 EL_CHAR('>'), -1, -1
8405 Xalpha_arrow_w, TRUE, FALSE,
8406 EL_CHAR('<'), -1, -1
8409 Xalpha_copyr, TRUE, FALSE,
8410 EL_CHAR('©'), -1, -1
8414 Xboom_bug, FALSE, FALSE,
8415 EL_BUG, ACTION_EXPLODING, -1
8418 Xboom_bomb, FALSE, FALSE,
8419 EL_BOMB, ACTION_EXPLODING, -1
8422 Xboom_android, FALSE, FALSE,
8423 EL_EMC_ANDROID, ACTION_OTHER, -1
8426 Xboom_1, FALSE, FALSE,
8427 EL_DEFAULT, ACTION_EXPLODING, -1
8430 Xboom_2, FALSE, FALSE,
8431 EL_DEFAULT, ACTION_EXPLODING, -1
8434 Znormal, FALSE, FALSE,
8438 Zdynamite, FALSE, FALSE,
8442 Zplayer, FALSE, FALSE,
8446 ZBORDER, FALSE, FALSE,
8456 static struct Mapping_EM_to_RND_player
8465 em_player_mapping_list[] =
8469 EL_PLAYER_1, ACTION_MOVING, MV_BIT_UP,
8473 EL_PLAYER_1, ACTION_MOVING, MV_BIT_RIGHT,
8477 EL_PLAYER_1, ACTION_MOVING, MV_BIT_DOWN,
8481 EL_PLAYER_1, ACTION_MOVING, MV_BIT_LEFT,
8485 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_UP,
8489 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_RIGHT,
8493 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_DOWN,
8497 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_LEFT,
8501 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_UP,
8505 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_RIGHT,
8509 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_DOWN,
8513 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_LEFT,
8517 EL_PLAYER_2, ACTION_MOVING, MV_BIT_UP,
8521 EL_PLAYER_2, ACTION_MOVING, MV_BIT_RIGHT,
8525 EL_PLAYER_2, ACTION_MOVING, MV_BIT_DOWN,
8529 EL_PLAYER_2, ACTION_MOVING, MV_BIT_LEFT,
8533 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_UP,
8537 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_RIGHT,
8541 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_DOWN,
8545 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_LEFT,
8549 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_UP,
8553 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_RIGHT,
8557 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_DOWN,
8561 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_LEFT,
8565 EL_PLAYER_1, ACTION_DEFAULT, -1,
8569 EL_PLAYER_2, ACTION_DEFAULT, -1,
8573 EL_PLAYER_3, ACTION_MOVING, MV_BIT_UP,
8577 EL_PLAYER_3, ACTION_MOVING, MV_BIT_RIGHT,
8581 EL_PLAYER_3, ACTION_MOVING, MV_BIT_DOWN,
8585 EL_PLAYER_3, ACTION_MOVING, MV_BIT_LEFT,
8589 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_UP,
8593 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_RIGHT,
8597 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_DOWN,
8601 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_LEFT,
8605 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_UP,
8609 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_RIGHT,
8613 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_DOWN,
8617 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_LEFT,
8621 EL_PLAYER_4, ACTION_MOVING, MV_BIT_UP,
8625 EL_PLAYER_4, ACTION_MOVING, MV_BIT_RIGHT,
8629 EL_PLAYER_4, ACTION_MOVING, MV_BIT_DOWN,
8633 EL_PLAYER_4, ACTION_MOVING, MV_BIT_LEFT,
8637 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_UP,
8641 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_RIGHT,
8645 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_DOWN,
8649 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_LEFT,
8653 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_UP,
8657 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_RIGHT,
8661 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_DOWN,
8665 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_LEFT,
8669 EL_PLAYER_3, ACTION_DEFAULT, -1,
8673 EL_PLAYER_4, ACTION_DEFAULT, -1,
8682 int map_element_RND_to_EM(int element_rnd)
8684 static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
8685 static boolean mapping_initialized = FALSE;
8687 if (!mapping_initialized)
8691 /* return "Xalpha_quest" for all undefined elements in mapping array */
8692 for (i = 0; i < NUM_FILE_ELEMENTS; i++)
8693 mapping_RND_to_EM[i] = Xalpha_quest;
8695 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
8696 if (em_object_mapping_list[i].is_rnd_to_em_mapping)
8697 mapping_RND_to_EM[em_object_mapping_list[i].element_rnd] =
8698 em_object_mapping_list[i].element_em;
8700 mapping_initialized = TRUE;
8703 if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
8704 return mapping_RND_to_EM[element_rnd];
8706 Error(ERR_WARN, "invalid RND level element %d", element_rnd);
8711 int map_element_EM_to_RND(int element_em)
8713 static unsigned short mapping_EM_to_RND[TILE_MAX];
8714 static boolean mapping_initialized = FALSE;
8716 if (!mapping_initialized)
8720 /* return "EL_UNKNOWN" for all undefined elements in mapping array */
8721 for (i = 0; i < TILE_MAX; i++)
8722 mapping_EM_to_RND[i] = EL_UNKNOWN;
8724 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
8725 mapping_EM_to_RND[em_object_mapping_list[i].element_em] =
8726 em_object_mapping_list[i].element_rnd;
8728 mapping_initialized = TRUE;
8731 if (element_em >= 0 && element_em < TILE_MAX)
8732 return mapping_EM_to_RND[element_em];
8734 Error(ERR_WARN, "invalid EM level element %d", element_em);
8739 void map_android_clone_elements_RND_to_EM(struct LevelInfo *level)
8741 struct LevelInfo_EM *level_em = level->native_em_level;
8742 struct LEVEL *lev = level_em->lev;
8745 for (i = 0; i < TILE_MAX; i++)
8746 lev->android_array[i] = Xblank;
8748 for (i = 0; i < level->num_android_clone_elements; i++)
8750 int element_rnd = level->android_clone_element[i];
8751 int element_em = map_element_RND_to_EM(element_rnd);
8753 for (j = 0; em_object_mapping_list[j].element_em != -1; j++)
8754 if (em_object_mapping_list[j].element_rnd == element_rnd)
8755 lev->android_array[em_object_mapping_list[j].element_em] = element_em;
8759 void map_android_clone_elements_EM_to_RND(struct LevelInfo *level)
8761 struct LevelInfo_EM *level_em = level->native_em_level;
8762 struct LEVEL *lev = level_em->lev;
8765 level->num_android_clone_elements = 0;
8767 for (i = 0; i < TILE_MAX; i++)
8769 int element_em = lev->android_array[i];
8771 boolean element_found = FALSE;
8773 if (element_em == Xblank)
8776 element_rnd = map_element_EM_to_RND(element_em);
8778 for (j = 0; j < level->num_android_clone_elements; j++)
8779 if (level->android_clone_element[j] == element_rnd)
8780 element_found = TRUE;
8784 level->android_clone_element[level->num_android_clone_elements++] =
8787 if (level->num_android_clone_elements == MAX_ANDROID_ELEMENTS)
8792 if (level->num_android_clone_elements == 0)
8794 level->num_android_clone_elements = 1;
8795 level->android_clone_element[0] = EL_EMPTY;
8799 int map_direction_RND_to_EM(int direction)
8801 return (direction == MV_UP ? 0 :
8802 direction == MV_RIGHT ? 1 :
8803 direction == MV_DOWN ? 2 :
8804 direction == MV_LEFT ? 3 :
8808 int map_direction_EM_to_RND(int direction)
8810 return (direction == 0 ? MV_UP :
8811 direction == 1 ? MV_RIGHT :
8812 direction == 2 ? MV_DOWN :
8813 direction == 3 ? MV_LEFT :
8817 int map_element_RND_to_SP(int element_rnd)
8819 int element_sp = 0x20; /* map unknown elements to yellow "hardware" */
8821 if (element_rnd >= EL_SP_START &&
8822 element_rnd <= EL_SP_END)
8823 element_sp = element_rnd - EL_SP_START;
8824 else if (element_rnd == EL_EMPTY_SPACE)
8826 else if (element_rnd == EL_INVISIBLE_WALL)
8832 int map_element_SP_to_RND(int element_sp)
8834 int element_rnd = EL_UNKNOWN;
8836 if (element_sp >= 0x00 &&
8838 element_rnd = EL_SP_START + element_sp;
8839 else if (element_sp == 0x28)
8840 element_rnd = EL_INVISIBLE_WALL;
8845 int map_action_SP_to_RND(int action_sp)
8849 case actActive: return ACTION_ACTIVE;
8850 case actImpact: return ACTION_IMPACT;
8851 case actExploding: return ACTION_EXPLODING;
8852 case actDigging: return ACTION_DIGGING;
8853 case actSnapping: return ACTION_SNAPPING;
8854 case actCollecting: return ACTION_COLLECTING;
8855 case actPassing: return ACTION_PASSING;
8856 case actPushing: return ACTION_PUSHING;
8857 case actDropping: return ACTION_DROPPING;
8859 default: return ACTION_DEFAULT;
8863 int get_next_element(int element)
8867 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
8868 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
8869 case EL_QUICKSAND_FAST_FILLING: return EL_QUICKSAND_FAST_FULL;
8870 case EL_QUICKSAND_FAST_EMPTYING: return EL_QUICKSAND_FAST_EMPTY;
8871 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
8872 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
8873 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
8874 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
8875 case EL_DC_MAGIC_WALL_FILLING: return EL_DC_MAGIC_WALL_FULL;
8876 case EL_DC_MAGIC_WALL_EMPTYING: return EL_DC_MAGIC_WALL_ACTIVE;
8877 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
8879 default: return element;
8884 int el_act_dir2img(int element, int action, int direction)
8886 element = GFX_ELEMENT(element);
8888 if (direction == MV_NONE)
8889 return element_info[element].graphic[action];
8891 direction = MV_DIR_TO_BIT(direction);
8893 return element_info[element].direction_graphic[action][direction];
8896 int el_act_dir2img(int element, int action, int direction)
8898 element = GFX_ELEMENT(element);
8899 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
8901 /* direction_graphic[][] == graphic[] for undefined direction graphics */
8902 return element_info[element].direction_graphic[action][direction];
8907 static int el_act_dir2crm(int element, int action, int direction)
8909 element = GFX_ELEMENT(element);
8911 if (direction == MV_NONE)
8912 return element_info[element].crumbled[action];
8914 direction = MV_DIR_TO_BIT(direction);
8916 return element_info[element].direction_crumbled[action][direction];
8919 static int el_act_dir2crm(int element, int action, int direction)
8921 element = GFX_ELEMENT(element);
8922 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
8924 /* direction_graphic[][] == graphic[] for undefined direction graphics */
8925 return element_info[element].direction_crumbled[action][direction];
8929 int el_act2img(int element, int action)
8931 element = GFX_ELEMENT(element);
8933 return element_info[element].graphic[action];
8936 int el_act2crm(int element, int action)
8938 element = GFX_ELEMENT(element);
8940 return element_info[element].crumbled[action];
8943 int el_dir2img(int element, int direction)
8945 element = GFX_ELEMENT(element);
8947 return el_act_dir2img(element, ACTION_DEFAULT, direction);
8950 int el2baseimg(int element)
8952 return element_info[element].graphic[ACTION_DEFAULT];
8955 int el2img(int element)
8957 element = GFX_ELEMENT(element);
8959 return element_info[element].graphic[ACTION_DEFAULT];
8962 int el2edimg(int element)
8964 element = GFX_ELEMENT(element);
8966 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
8969 int el2preimg(int element)
8971 element = GFX_ELEMENT(element);
8973 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
8976 int el2panelimg(int element)
8978 element = GFX_ELEMENT(element);
8980 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PANEL];
8983 int font2baseimg(int font_nr)
8985 return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
8988 int getBeltNrFromBeltElement(int element)
8990 return (element < EL_CONVEYOR_BELT_2_LEFT ? 0 :
8991 element < EL_CONVEYOR_BELT_3_LEFT ? 1 :
8992 element < EL_CONVEYOR_BELT_4_LEFT ? 2 : 3);
8995 int getBeltNrFromBeltActiveElement(int element)
8997 return (element < EL_CONVEYOR_BELT_2_LEFT_ACTIVE ? 0 :
8998 element < EL_CONVEYOR_BELT_3_LEFT_ACTIVE ? 1 :
8999 element < EL_CONVEYOR_BELT_4_LEFT_ACTIVE ? 2 : 3);
9002 int getBeltNrFromBeltSwitchElement(int element)
9004 return (element < EL_CONVEYOR_BELT_2_SWITCH_LEFT ? 0 :
9005 element < EL_CONVEYOR_BELT_3_SWITCH_LEFT ? 1 :
9006 element < EL_CONVEYOR_BELT_4_SWITCH_LEFT ? 2 : 3);
9009 int getBeltDirNrFromBeltElement(int element)
9011 static int belt_base_element[4] =
9013 EL_CONVEYOR_BELT_1_LEFT,
9014 EL_CONVEYOR_BELT_2_LEFT,
9015 EL_CONVEYOR_BELT_3_LEFT,
9016 EL_CONVEYOR_BELT_4_LEFT
9019 int belt_nr = getBeltNrFromBeltElement(element);
9020 int belt_dir_nr = element - belt_base_element[belt_nr];
9022 return (belt_dir_nr % 3);
9025 int getBeltDirNrFromBeltSwitchElement(int element)
9027 static int belt_base_element[4] =
9029 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
9030 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
9031 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
9032 EL_CONVEYOR_BELT_4_SWITCH_LEFT
9035 int belt_nr = getBeltNrFromBeltSwitchElement(element);
9036 int belt_dir_nr = element - belt_base_element[belt_nr];
9038 return (belt_dir_nr % 3);
9041 int getBeltDirFromBeltElement(int element)
9043 static int belt_move_dir[3] =
9050 int belt_dir_nr = getBeltDirNrFromBeltElement(element);
9052 return belt_move_dir[belt_dir_nr];
9055 int getBeltDirFromBeltSwitchElement(int element)
9057 static int belt_move_dir[3] =
9064 int belt_dir_nr = getBeltDirNrFromBeltSwitchElement(element);
9066 return belt_move_dir[belt_dir_nr];
9069 int getBeltElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
9071 static int belt_base_element[4] =
9073 EL_CONVEYOR_BELT_1_LEFT,
9074 EL_CONVEYOR_BELT_2_LEFT,
9075 EL_CONVEYOR_BELT_3_LEFT,
9076 EL_CONVEYOR_BELT_4_LEFT
9079 return belt_base_element[belt_nr] + belt_dir_nr;
9082 int getBeltElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
9084 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
9086 return getBeltElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
9089 int getBeltSwitchElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
9091 static int belt_base_element[4] =
9093 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
9094 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
9095 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
9096 EL_CONVEYOR_BELT_4_SWITCH_LEFT
9099 return belt_base_element[belt_nr] + belt_dir_nr;
9102 int getBeltSwitchElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
9104 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
9106 return getBeltSwitchElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
9110 boolean getTeamMode_EM()
9112 return game.team_mode;
9115 int getNumActivePlayers_EM()
9118 int num_players = 0;
9122 return (setup.team_mode ? MAX_PLAYERS : 1);
9124 for (i = 0; i < MAX_PLAYERS; i++)
9125 if (tape.player_participates[i])
9128 return (num_players > 1 ? MAX_PLAYERS : 1);
9132 int num_players = 0;
9135 /* when recording game, activate all connected players */
9139 for (i = 0; i < MAX_PLAYERS; i++)
9140 if (tape.player_participates[i])
9148 int getGameFrameDelay_EM(int native_em_game_frame_delay)
9150 int game_frame_delay_value;
9152 game_frame_delay_value =
9153 (tape.playing && tape.fast_forward ? FfwdFrameDelay :
9154 GameFrameDelay == GAME_FRAME_DELAY ? native_em_game_frame_delay :
9157 if (tape.playing && tape.warp_forward && !tape.pausing)
9158 game_frame_delay_value = 0;
9160 return game_frame_delay_value;
9163 unsigned int InitRND(int seed)
9165 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
9166 return InitEngineRandom_EM(seed);
9167 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
9168 return InitEngineRandom_SP(seed);
9170 return InitEngineRandom_RND(seed);
9174 static struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
9175 static struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
9178 inline static int get_effective_element_EM(int tile, int frame_em)
9180 int element = object_mapping[tile].element_rnd;
9181 int action = object_mapping[tile].action;
9182 boolean is_backside = object_mapping[tile].is_backside;
9183 boolean action_removing = (action == ACTION_DIGGING ||
9184 action == ACTION_SNAPPING ||
9185 action == ACTION_COLLECTING);
9191 case Yacid_splash_eB:
9192 case Yacid_splash_wB:
9193 return (frame_em > 5 ? EL_EMPTY : element);
9197 case Ydiamond_stone:
9198 // if (!game.use_native_emc_graphics_engine)
9206 else /* frame_em == 7 */
9210 case Yacid_splash_eB:
9211 case Yacid_splash_wB:
9214 case Yemerald_stone:
9217 case Ydiamond_stone:
9221 case Xdrip_stretchB:
9240 case Xsand_stonein_1:
9241 case Xsand_stonein_2:
9242 case Xsand_stonein_3:
9243 case Xsand_stonein_4:
9247 return (is_backside || action_removing ? EL_EMPTY : element);
9252 inline static boolean check_linear_animation_EM(int tile)
9256 case Xsand_stonesand_1:
9257 case Xsand_stonesand_quickout_1:
9258 case Xsand_sandstone_1:
9259 case Xsand_stonein_1:
9260 case Xsand_stoneout_1:
9280 case Yacid_splash_eB:
9281 case Yacid_splash_wB:
9282 case Yemerald_stone:
9290 inline static void set_crumbled_graphics_EM(struct GraphicInfo_EM *g_em,
9291 boolean has_crumbled_graphics,
9292 int crumbled, int sync_frame)
9294 /* if element can be crumbled, but certain action graphics are just empty
9295 space (like instantly snapping sand to empty space in 1 frame), do not
9296 treat these empty space graphics as crumbled graphics in EMC engine */
9297 if (crumbled == IMG_EMPTY_SPACE)
9298 has_crumbled_graphics = FALSE;
9300 if (has_crumbled_graphics)
9302 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
9303 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
9304 g_crumbled->anim_delay,
9305 g_crumbled->anim_mode,
9306 g_crumbled->anim_start_frame,
9309 getGraphicSource(crumbled, frame_crumbled, &g_em->crumbled_bitmap,
9310 &g_em->crumbled_src_x, &g_em->crumbled_src_y);
9312 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
9314 g_em->has_crumbled_graphics = TRUE;
9318 g_em->crumbled_bitmap = NULL;
9319 g_em->crumbled_src_x = 0;
9320 g_em->crumbled_src_y = 0;
9321 g_em->crumbled_border_size = 0;
9323 g_em->has_crumbled_graphics = FALSE;
9327 void ResetGfxAnimation_EM(int x, int y, int tile)
9332 void SetGfxAnimation_EM(struct GraphicInfo_EM *g_em,
9333 int tile, int frame_em, int x, int y)
9335 int action = object_mapping[tile].action;
9337 int direction = object_mapping[tile].direction;
9338 int effective_element = get_effective_element_EM(tile, frame_em);
9339 int graphic = (direction == MV_NONE ?
9340 el_act2img(effective_element, action) :
9341 el_act_dir2img(effective_element, action, direction));
9342 struct GraphicInfo *g = &graphic_info[graphic];
9345 boolean action_removing = (action == ACTION_DIGGING ||
9346 action == ACTION_SNAPPING ||
9347 action == ACTION_COLLECTING);
9348 boolean action_moving = (action == ACTION_FALLING ||
9349 action == ACTION_MOVING ||
9350 action == ACTION_PUSHING ||
9351 action == ACTION_EATING ||
9352 action == ACTION_FILLING ||
9353 action == ACTION_EMPTYING);
9354 boolean action_falling = (action == ACTION_FALLING ||
9355 action == ACTION_FILLING ||
9356 action == ACTION_EMPTYING);
9358 /* special case: graphic uses "2nd movement tile" and has defined
9359 7 frames for movement animation (or less) => use default graphic
9360 for last (8th) frame which ends the movement animation */
9361 if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
9363 action = ACTION_DEFAULT; /* (keep action_* unchanged for now) */
9364 graphic = (direction == MV_NONE ?
9365 el_act2img(effective_element, action) :
9366 el_act_dir2img(effective_element, action, direction));
9368 g = &graphic_info[graphic];
9372 if (tile == Xsand_stonesand_1 ||
9373 tile == Xsand_stonesand_2 ||
9374 tile == Xsand_stonesand_3 ||
9375 tile == Xsand_stonesand_4)
9376 printf("::: 1: quicksand frame %d [%d]\n", GfxFrame[x][y], tile);
9380 if ((action_removing || check_linear_animation_EM(tile)) && frame_em == 0)
9384 // printf("::: resetting... [%d]\n", tile);
9387 if (action_removing || check_linear_animation_EM(tile))
9389 GfxFrame[x][y] = frame_em;
9391 // printf("::: resetting... [%d]\n", tile);
9394 else if (action_moving)
9396 boolean is_backside = object_mapping[tile].is_backside;
9400 int direction = object_mapping[tile].direction;
9401 int move_dir = (action_falling ? MV_DOWN : direction);
9406 /* !!! TEST !!! NEW !!! DOES NOT WORK RIGHT YET !!! */
9407 if (g->double_movement && frame_em == 0)
9411 // printf("::: resetting... [%d]\n", tile);
9415 if (move_dir == MV_LEFT)
9416 GfxFrame[x - 1][y] = GfxFrame[x][y];
9417 else if (move_dir == MV_RIGHT)
9418 GfxFrame[x + 1][y] = GfxFrame[x][y];
9419 else if (move_dir == MV_UP)
9420 GfxFrame[x][y - 1] = GfxFrame[x][y];
9421 else if (move_dir == MV_DOWN)
9422 GfxFrame[x][y + 1] = GfxFrame[x][y];
9429 /* special case: animation for Xsand_stonesand_quickout_1/2 twice as fast */
9430 if (tile == Xsand_stonesand_quickout_1 ||
9431 tile == Xsand_stonesand_quickout_2)
9436 if (tile == Xsand_stonesand_1 ||
9437 tile == Xsand_stonesand_2 ||
9438 tile == Xsand_stonesand_3 ||
9439 tile == Xsand_stonesand_4)
9440 printf("::: 2: quicksand frame %d [%d]\n", GfxFrame[x][y], tile);
9444 if (graphic_info[graphic].anim_global_sync)
9445 sync_frame = FrameCounter;
9446 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
9447 sync_frame = GfxFrame[x][y];
9449 sync_frame = 0; /* playfield border (pseudo steel) */
9451 SetRandomAnimationValue(x, y);
9453 int frame = getAnimationFrame(g->anim_frames,
9456 g->anim_start_frame,
9459 g_em->unique_identifier =
9460 (graphic << 16) | ((frame % 8) << 12) | (g_em->width << 6) | g_em->height;
9464 void getGraphicSourceObjectExt_EM(struct GraphicInfo_EM *g_em,
9465 int tile, int frame_em, int x, int y)
9467 int action = object_mapping[tile].action;
9468 int direction = object_mapping[tile].direction;
9469 boolean is_backside = object_mapping[tile].is_backside;
9470 int effective_element = get_effective_element_EM(tile, frame_em);
9472 int effective_action = action;
9474 int effective_action = (frame_em < 7 ? action : ACTION_DEFAULT);
9476 int graphic = (direction == MV_NONE ?
9477 el_act2img(effective_element, effective_action) :
9478 el_act_dir2img(effective_element, effective_action,
9480 int crumbled = (direction == MV_NONE ?
9481 el_act2crm(effective_element, effective_action) :
9482 el_act_dir2crm(effective_element, effective_action,
9484 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
9485 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
9486 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
9487 struct GraphicInfo *g = &graphic_info[graphic];
9489 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
9493 /* special case: graphic uses "2nd movement tile" and has defined
9494 7 frames for movement animation (or less) => use default graphic
9495 for last (8th) frame which ends the movement animation */
9496 if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
9498 effective_action = ACTION_DEFAULT;
9499 graphic = (direction == MV_NONE ?
9500 el_act2img(effective_element, effective_action) :
9501 el_act_dir2img(effective_element, effective_action,
9503 crumbled = (direction == MV_NONE ?
9504 el_act2crm(effective_element, effective_action) :
9505 el_act_dir2crm(effective_element, effective_action,
9508 g = &graphic_info[graphic];
9518 if (frame_em == 0) /* reset animation frame for certain elements */
9520 if (check_linear_animation_EM(tile))
9525 if (graphic_info[graphic].anim_global_sync)
9526 sync_frame = FrameCounter;
9527 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
9528 sync_frame = GfxFrame[x][y];
9530 sync_frame = 0; /* playfield border (pseudo steel) */
9532 SetRandomAnimationValue(x, y);
9537 int xxx_sync_frame = (i == Xdrip_stretch ? 7 :
9538 i == Xdrip_stretchB ? 7 :
9539 i == Ydrip_s2 ? j + 8 :
9540 i == Ydrip_s2B ? j + 8 :
9549 i == Xfake_acid_1 ? 0 :
9550 i == Xfake_acid_2 ? 10 :
9551 i == Xfake_acid_3 ? 20 :
9552 i == Xfake_acid_4 ? 30 :
9553 i == Xfake_acid_5 ? 40 :
9554 i == Xfake_acid_6 ? 50 :
9555 i == Xfake_acid_7 ? 60 :
9556 i == Xfake_acid_8 ? 70 :
9558 i == Xball_2B ? j + 8 :
9559 i == Yball_eat ? j + 1 :
9560 i == Ykey_1_eat ? j + 1 :
9561 i == Ykey_2_eat ? j + 1 :
9562 i == Ykey_3_eat ? j + 1 :
9563 i == Ykey_4_eat ? j + 1 :
9564 i == Ykey_5_eat ? j + 1 :
9565 i == Ykey_6_eat ? j + 1 :
9566 i == Ykey_7_eat ? j + 1 :
9567 i == Ykey_8_eat ? j + 1 :
9568 i == Ylenses_eat ? j + 1 :
9569 i == Ymagnify_eat ? j + 1 :
9570 i == Ygrass_eat ? j + 1 :
9571 i == Ydirt_eat ? j + 1 :
9572 i == Xamoeba_1 ? 0 :
9573 i == Xamoeba_2 ? 1 :
9574 i == Xamoeba_3 ? 2 :
9575 i == Xamoeba_4 ? 3 :
9576 i == Xamoeba_5 ? 0 :
9577 i == Xamoeba_6 ? 1 :
9578 i == Xamoeba_7 ? 2 :
9579 i == Xamoeba_8 ? 3 :
9580 i == Xexit_2 ? j + 8 :
9581 i == Xexit_3 ? j + 16 :
9582 i == Xdynamite_1 ? 0 :
9583 i == Xdynamite_2 ? 8 :
9584 i == Xdynamite_3 ? 16 :
9585 i == Xdynamite_4 ? 24 :
9586 i == Xsand_stonein_1 ? j + 1 :
9587 i == Xsand_stonein_2 ? j + 9 :
9588 i == Xsand_stonein_3 ? j + 17 :
9589 i == Xsand_stonein_4 ? j + 25 :
9590 i == Xsand_stoneout_1 && j == 0 ? 0 :
9591 i == Xsand_stoneout_1 && j == 1 ? 0 :
9592 i == Xsand_stoneout_1 && j == 2 ? 1 :
9593 i == Xsand_stoneout_1 && j == 3 ? 2 :
9594 i == Xsand_stoneout_1 && j == 4 ? 2 :
9595 i == Xsand_stoneout_1 && j == 5 ? 3 :
9596 i == Xsand_stoneout_1 && j == 6 ? 4 :
9597 i == Xsand_stoneout_1 && j == 7 ? 4 :
9598 i == Xsand_stoneout_2 && j == 0 ? 5 :
9599 i == Xsand_stoneout_2 && j == 1 ? 6 :
9600 i == Xsand_stoneout_2 && j == 2 ? 7 :
9601 i == Xsand_stoneout_2 && j == 3 ? 8 :
9602 i == Xsand_stoneout_2 && j == 4 ? 9 :
9603 i == Xsand_stoneout_2 && j == 5 ? 11 :
9604 i == Xsand_stoneout_2 && j == 6 ? 13 :
9605 i == Xsand_stoneout_2 && j == 7 ? 15 :
9606 i == Xboom_bug && j == 1 ? 2 :
9607 i == Xboom_bug && j == 2 ? 2 :
9608 i == Xboom_bug && j == 3 ? 4 :
9609 i == Xboom_bug && j == 4 ? 4 :
9610 i == Xboom_bug && j == 5 ? 2 :
9611 i == Xboom_bug && j == 6 ? 2 :
9612 i == Xboom_bug && j == 7 ? 0 :
9613 i == Xboom_bomb && j == 1 ? 2 :
9614 i == Xboom_bomb && j == 2 ? 2 :
9615 i == Xboom_bomb && j == 3 ? 4 :
9616 i == Xboom_bomb && j == 4 ? 4 :
9617 i == Xboom_bomb && j == 5 ? 2 :
9618 i == Xboom_bomb && j == 6 ? 2 :
9619 i == Xboom_bomb && j == 7 ? 0 :
9620 i == Xboom_android && j == 7 ? 6 :
9621 i == Xboom_1 && j == 1 ? 2 :
9622 i == Xboom_1 && j == 2 ? 2 :
9623 i == Xboom_1 && j == 3 ? 4 :
9624 i == Xboom_1 && j == 4 ? 4 :
9625 i == Xboom_1 && j == 5 ? 6 :
9626 i == Xboom_1 && j == 6 ? 6 :
9627 i == Xboom_1 && j == 7 ? 8 :
9628 i == Xboom_2 && j == 0 ? 8 :
9629 i == Xboom_2 && j == 1 ? 8 :
9630 i == Xboom_2 && j == 2 ? 10 :
9631 i == Xboom_2 && j == 3 ? 10 :
9632 i == Xboom_2 && j == 4 ? 10 :
9633 i == Xboom_2 && j == 5 ? 12 :
9634 i == Xboom_2 && j == 6 ? 12 :
9635 i == Xboom_2 && j == 7 ? 12 :
9637 special_animation && j == 4 ? 3 :
9638 effective_action != action ? 0 :
9644 int xxx_effective_action;
9645 int xxx_has_action_graphics;
9648 int element = object_mapping[i].element_rnd;
9649 int action = object_mapping[i].action;
9650 int direction = object_mapping[i].direction;
9651 boolean is_backside = object_mapping[i].is_backside;
9653 boolean action_removing = (action == ACTION_DIGGING ||
9654 action == ACTION_SNAPPING ||
9655 action == ACTION_COLLECTING);
9657 boolean action_exploding = ((action == ACTION_EXPLODING ||
9658 action == ACTION_SMASHED_BY_ROCK ||
9659 action == ACTION_SMASHED_BY_SPRING) &&
9660 element != EL_DIAMOND);
9661 boolean action_active = (action == ACTION_ACTIVE);
9662 boolean action_other = (action == ACTION_OTHER);
9666 int effective_element = get_effective_element_EM(i, j);
9668 int effective_element = (j > 5 && i == Yacid_splash_eB ? EL_EMPTY :
9669 j > 5 && i == Yacid_splash_wB ? EL_EMPTY :
9671 i == Xdrip_stretch ? element :
9672 i == Xdrip_stretchB ? element :
9673 i == Ydrip_s1 ? element :
9674 i == Ydrip_s1B ? element :
9675 i == Xball_1B ? element :
9676 i == Xball_2 ? element :
9677 i == Xball_2B ? element :
9678 i == Yball_eat ? element :
9679 i == Ykey_1_eat ? element :
9680 i == Ykey_2_eat ? element :
9681 i == Ykey_3_eat ? element :
9682 i == Ykey_4_eat ? element :
9683 i == Ykey_5_eat ? element :
9684 i == Ykey_6_eat ? element :
9685 i == Ykey_7_eat ? element :
9686 i == Ykey_8_eat ? element :
9687 i == Ylenses_eat ? element :
9688 i == Ymagnify_eat ? element :
9689 i == Ygrass_eat ? element :
9690 i == Ydirt_eat ? element :
9691 i == Yemerald_stone ? EL_EMERALD :
9692 i == Ydiamond_stone ? EL_ROCK :
9693 i == Xsand_stonein_1 ? element :
9694 i == Xsand_stonein_2 ? element :
9695 i == Xsand_stonein_3 ? element :
9696 i == Xsand_stonein_4 ? element :
9697 is_backside ? EL_EMPTY :
9698 action_removing ? EL_EMPTY :
9701 int effective_action = (j < 7 ? action :
9702 i == Xdrip_stretch ? action :
9703 i == Xdrip_stretchB ? action :
9704 i == Ydrip_s1 ? action :
9705 i == Ydrip_s1B ? action :
9706 i == Xball_1B ? action :
9707 i == Xball_2 ? action :
9708 i == Xball_2B ? action :
9709 i == Yball_eat ? action :
9710 i == Ykey_1_eat ? action :
9711 i == Ykey_2_eat ? action :
9712 i == Ykey_3_eat ? action :
9713 i == Ykey_4_eat ? action :
9714 i == Ykey_5_eat ? action :
9715 i == Ykey_6_eat ? action :
9716 i == Ykey_7_eat ? action :
9717 i == Ykey_8_eat ? action :
9718 i == Ylenses_eat ? action :
9719 i == Ymagnify_eat ? action :
9720 i == Ygrass_eat ? action :
9721 i == Ydirt_eat ? action :
9722 i == Xsand_stonein_1 ? action :
9723 i == Xsand_stonein_2 ? action :
9724 i == Xsand_stonein_3 ? action :
9725 i == Xsand_stonein_4 ? action :
9726 i == Xsand_stoneout_1 ? action :
9727 i == Xsand_stoneout_2 ? action :
9728 i == Xboom_android ? ACTION_EXPLODING :
9729 action_exploding ? ACTION_EXPLODING :
9730 action_active ? action :
9731 action_other ? action :
9733 int graphic = (el_act_dir2img(effective_element, effective_action,
9735 int crumbled = (el_act_dir2crm(effective_element, effective_action,
9737 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
9738 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
9739 boolean has_action_graphics = (graphic != base_graphic);
9740 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
9741 struct GraphicInfo *g = &graphic_info[graphic];
9743 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
9745 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
9748 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
9749 boolean special_animation = (action != ACTION_DEFAULT &&
9750 g->anim_frames == 3 &&
9751 g->anim_delay == 2 &&
9752 g->anim_mode & ANIM_LINEAR);
9753 xxx_sync_frame = (i == Xdrip_stretch ? 7 :
9754 i == Xdrip_stretchB ? 7 :
9755 i == Ydrip_s2 ? j + 8 :
9756 i == Ydrip_s2B ? j + 8 :
9765 i == Xfake_acid_1 ? 0 :
9766 i == Xfake_acid_2 ? 10 :
9767 i == Xfake_acid_3 ? 20 :
9768 i == Xfake_acid_4 ? 30 :
9769 i == Xfake_acid_5 ? 40 :
9770 i == Xfake_acid_6 ? 50 :
9771 i == Xfake_acid_7 ? 60 :
9772 i == Xfake_acid_8 ? 70 :
9774 i == Xball_2B ? j + 8 :
9775 i == Yball_eat ? j + 1 :
9776 i == Ykey_1_eat ? j + 1 :
9777 i == Ykey_2_eat ? j + 1 :
9778 i == Ykey_3_eat ? j + 1 :
9779 i == Ykey_4_eat ? j + 1 :
9780 i == Ykey_5_eat ? j + 1 :
9781 i == Ykey_6_eat ? j + 1 :
9782 i == Ykey_7_eat ? j + 1 :
9783 i == Ykey_8_eat ? j + 1 :
9784 i == Ylenses_eat ? j + 1 :
9785 i == Ymagnify_eat ? j + 1 :
9786 i == Ygrass_eat ? j + 1 :
9787 i == Ydirt_eat ? j + 1 :
9788 i == Xamoeba_1 ? 0 :
9789 i == Xamoeba_2 ? 1 :
9790 i == Xamoeba_3 ? 2 :
9791 i == Xamoeba_4 ? 3 :
9792 i == Xamoeba_5 ? 0 :
9793 i == Xamoeba_6 ? 1 :
9794 i == Xamoeba_7 ? 2 :
9795 i == Xamoeba_8 ? 3 :
9796 i == Xexit_2 ? j + 8 :
9797 i == Xexit_3 ? j + 16 :
9798 i == Xdynamite_1 ? 0 :
9799 i == Xdynamite_2 ? 8 :
9800 i == Xdynamite_3 ? 16 :
9801 i == Xdynamite_4 ? 24 :
9802 i == Xsand_stonein_1 ? j + 1 :
9803 i == Xsand_stonein_2 ? j + 9 :
9804 i == Xsand_stonein_3 ? j + 17 :
9805 i == Xsand_stonein_4 ? j + 25 :
9806 i == Xsand_stoneout_1 && j == 0 ? 0 :
9807 i == Xsand_stoneout_1 && j == 1 ? 0 :
9808 i == Xsand_stoneout_1 && j == 2 ? 1 :
9809 i == Xsand_stoneout_1 && j == 3 ? 2 :
9810 i == Xsand_stoneout_1 && j == 4 ? 2 :
9811 i == Xsand_stoneout_1 && j == 5 ? 3 :
9812 i == Xsand_stoneout_1 && j == 6 ? 4 :
9813 i == Xsand_stoneout_1 && j == 7 ? 4 :
9814 i == Xsand_stoneout_2 && j == 0 ? 5 :
9815 i == Xsand_stoneout_2 && j == 1 ? 6 :
9816 i == Xsand_stoneout_2 && j == 2 ? 7 :
9817 i == Xsand_stoneout_2 && j == 3 ? 8 :
9818 i == Xsand_stoneout_2 && j == 4 ? 9 :
9819 i == Xsand_stoneout_2 && j == 5 ? 11 :
9820 i == Xsand_stoneout_2 && j == 6 ? 13 :
9821 i == Xsand_stoneout_2 && j == 7 ? 15 :
9822 i == Xboom_bug && j == 1 ? 2 :
9823 i == Xboom_bug && j == 2 ? 2 :
9824 i == Xboom_bug && j == 3 ? 4 :
9825 i == Xboom_bug && j == 4 ? 4 :
9826 i == Xboom_bug && j == 5 ? 2 :
9827 i == Xboom_bug && j == 6 ? 2 :
9828 i == Xboom_bug && j == 7 ? 0 :
9829 i == Xboom_bomb && j == 1 ? 2 :
9830 i == Xboom_bomb && j == 2 ? 2 :
9831 i == Xboom_bomb && j == 3 ? 4 :
9832 i == Xboom_bomb && j == 4 ? 4 :
9833 i == Xboom_bomb && j == 5 ? 2 :
9834 i == Xboom_bomb && j == 6 ? 2 :
9835 i == Xboom_bomb && j == 7 ? 0 :
9836 i == Xboom_android && j == 7 ? 6 :
9837 i == Xboom_1 && j == 1 ? 2 :
9838 i == Xboom_1 && j == 2 ? 2 :
9839 i == Xboom_1 && j == 3 ? 4 :
9840 i == Xboom_1 && j == 4 ? 4 :
9841 i == Xboom_1 && j == 5 ? 6 :
9842 i == Xboom_1 && j == 6 ? 6 :
9843 i == Xboom_1 && j == 7 ? 8 :
9844 i == Xboom_2 && j == 0 ? 8 :
9845 i == Xboom_2 && j == 1 ? 8 :
9846 i == Xboom_2 && j == 2 ? 10 :
9847 i == Xboom_2 && j == 3 ? 10 :
9848 i == Xboom_2 && j == 4 ? 10 :
9849 i == Xboom_2 && j == 5 ? 12 :
9850 i == Xboom_2 && j == 6 ? 12 :
9851 i == Xboom_2 && j == 7 ? 12 :
9852 special_animation && j == 4 ? 3 :
9853 effective_action != action ? 0 :
9856 xxx_effective_action = effective_action;
9857 xxx_has_action_graphics = has_action_graphics;
9862 int frame = getAnimationFrame(g->anim_frames,
9865 g->anim_start_frame,
9879 int old_src_x = g_em->src_x;
9880 int old_src_y = g_em->src_y;
9884 getGraphicSourceExt(graphic, frame, &g_em->bitmap, &g_em->src_x, &g_em->src_y,
9885 g->double_movement && is_backside);
9887 getGraphicSourceExt(graphic, frame, &g_em->bitmap,
9888 &g_em->src_x, &g_em->src_y, FALSE);
9893 if (tile == Ydiamond_stone)
9894 printf("::: stone smashing diamond... %d: %d, %d, %d, %d, %d -> %d [%d, %d, %d, %d, %d, %d] [%d]\n",
9899 g->anim_start_frame,
9902 g_em->src_x, g_em->src_y,
9903 g_em->src_offset_x, g_em->src_offset_y,
9904 g_em->dst_offset_x, g_em->dst_offset_y,
9916 if (graphic == IMG_BUG_MOVING_RIGHT)
9917 printf("::: %d, %d, %d: %d, %d [%d, %d -> %d, %d]\n", graphic, x, y,
9918 g->double_movement, is_backside,
9919 old_src_x, old_src_y, g_em->src_x, g_em->src_y);
9927 g_em->src_offset_x = 0;
9928 g_em->src_offset_y = 0;
9929 g_em->dst_offset_x = 0;
9930 g_em->dst_offset_y = 0;
9931 g_em->width = TILEX;
9932 g_em->height = TILEY;
9934 g_em->preserve_background = FALSE;
9937 /* (updating the "crumbled" graphic definitions is probably not really needed,
9938 as animations for crumbled graphics can't be longer than one EMC cycle) */
9940 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
9945 g_em->crumbled_bitmap = NULL;
9946 g_em->crumbled_src_x = 0;
9947 g_em->crumbled_src_y = 0;
9949 g_em->has_crumbled_graphics = FALSE;
9951 if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
9953 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
9954 g_crumbled->anim_delay,
9955 g_crumbled->anim_mode,
9956 g_crumbled->anim_start_frame,
9959 getGraphicSource(crumbled, frame_crumbled, &g_em->crumbled_bitmap,
9960 &g_em->crumbled_src_x, &g_em->crumbled_src_y);
9962 g_em->has_crumbled_graphics = TRUE;
9968 int effective_action = xxx_effective_action;
9969 int has_action_graphics = xxx_has_action_graphics;
9971 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
9972 effective_action == ACTION_MOVING ||
9973 effective_action == ACTION_PUSHING ||
9974 effective_action == ACTION_EATING)) ||
9975 (!has_action_graphics && (effective_action == ACTION_FILLING ||
9976 effective_action == ACTION_EMPTYING)))
9979 (effective_action == ACTION_FALLING ||
9980 effective_action == ACTION_FILLING ||
9981 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
9982 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
9983 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
9984 int num_steps = (i == Ydrip_s1 ? 16 :
9985 i == Ydrip_s1B ? 16 :
9986 i == Ydrip_s2 ? 16 :
9987 i == Ydrip_s2B ? 16 :
9988 i == Xsand_stonein_1 ? 32 :
9989 i == Xsand_stonein_2 ? 32 :
9990 i == Xsand_stonein_3 ? 32 :
9991 i == Xsand_stonein_4 ? 32 :
9992 i == Xsand_stoneout_1 ? 16 :
9993 i == Xsand_stoneout_2 ? 16 : 8);
9994 int cx = ABS(dx) * (TILEX / num_steps);
9995 int cy = ABS(dy) * (TILEY / num_steps);
9996 int step_frame = (i == Ydrip_s2 ? j + 8 :
9997 i == Ydrip_s2B ? j + 8 :
9998 i == Xsand_stonein_2 ? j + 8 :
9999 i == Xsand_stonein_3 ? j + 16 :
10000 i == Xsand_stonein_4 ? j + 24 :
10001 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
10002 int step = (is_backside ? step_frame : num_steps - step_frame);
10004 if (is_backside) /* tile where movement starts */
10006 if (dx < 0 || dy < 0)
10008 g_em->src_offset_x = cx * step;
10009 g_em->src_offset_y = cy * step;
10013 g_em->dst_offset_x = cx * step;
10014 g_em->dst_offset_y = cy * step;
10017 else /* tile where movement ends */
10019 if (dx < 0 || dy < 0)
10021 g_em->dst_offset_x = cx * step;
10022 g_em->dst_offset_y = cy * step;
10026 g_em->src_offset_x = cx * step;
10027 g_em->src_offset_y = cy * step;
10031 g_em->width = TILEX - cx * step;
10032 g_em->height = TILEY - cy * step;
10035 /* create unique graphic identifier to decide if tile must be redrawn */
10036 /* bit 31 - 16 (16 bit): EM style graphic
10037 bit 15 - 12 ( 4 bit): EM style frame
10038 bit 11 - 6 ( 6 bit): graphic width
10039 bit 5 - 0 ( 6 bit): graphic height */
10040 g_em->unique_identifier =
10041 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
10047 void getGraphicSourcePlayerExt_EM(struct GraphicInfo_EM *g_em,
10048 int player_nr, int anim, int frame_em)
10050 int element = player_mapping[player_nr][anim].element_rnd;
10051 int action = player_mapping[player_nr][anim].action;
10052 int direction = player_mapping[player_nr][anim].direction;
10053 int graphic = (direction == MV_NONE ?
10054 el_act2img(element, action) :
10055 el_act_dir2img(element, action, direction));
10056 struct GraphicInfo *g = &graphic_info[graphic];
10059 InitPlayerGfxAnimation(&stored_player[player_nr], action, direction);
10061 stored_player[player_nr].StepFrame = frame_em;
10063 sync_frame = stored_player[player_nr].Frame;
10065 int frame = getAnimationFrame(g->anim_frames,
10068 g->anim_start_frame,
10071 getGraphicSourceExt(graphic, frame, &g_em->bitmap,
10072 &g_em->src_x, &g_em->src_y, FALSE);
10075 printf("::: %d: %d, %d [%d]\n",
10077 stored_player[player_nr].Frame,
10078 stored_player[player_nr].StepFrame,
10083 void InitGraphicInfo_EM(void)
10086 struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
10087 struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
10092 int num_em_gfx_errors = 0;
10094 if (graphic_info_em_object[0][0].bitmap == NULL)
10096 /* EM graphics not yet initialized in em_open_all() */
10101 printf("::: [4 errors can be ignored (1 x 'bomb', 3 x 'em_dynamite']\n");
10104 /* always start with reliable default values */
10105 for (i = 0; i < TILE_MAX; i++)
10107 object_mapping[i].element_rnd = EL_UNKNOWN;
10108 object_mapping[i].is_backside = FALSE;
10109 object_mapping[i].action = ACTION_DEFAULT;
10110 object_mapping[i].direction = MV_NONE;
10113 /* always start with reliable default values */
10114 for (p = 0; p < MAX_PLAYERS; p++)
10116 for (i = 0; i < SPR_MAX; i++)
10118 player_mapping[p][i].element_rnd = EL_UNKNOWN;
10119 player_mapping[p][i].action = ACTION_DEFAULT;
10120 player_mapping[p][i].direction = MV_NONE;
10124 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
10126 int e = em_object_mapping_list[i].element_em;
10128 object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd;
10129 object_mapping[e].is_backside = em_object_mapping_list[i].is_backside;
10131 if (em_object_mapping_list[i].action != -1)
10132 object_mapping[e].action = em_object_mapping_list[i].action;
10134 if (em_object_mapping_list[i].direction != -1)
10135 object_mapping[e].direction =
10136 MV_DIR_FROM_BIT(em_object_mapping_list[i].direction);
10139 for (i = 0; em_player_mapping_list[i].action_em != -1; i++)
10141 int a = em_player_mapping_list[i].action_em;
10142 int p = em_player_mapping_list[i].player_nr;
10144 player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd;
10146 if (em_player_mapping_list[i].action != -1)
10147 player_mapping[p][a].action = em_player_mapping_list[i].action;
10149 if (em_player_mapping_list[i].direction != -1)
10150 player_mapping[p][a].direction =
10151 MV_DIR_FROM_BIT(em_player_mapping_list[i].direction);
10154 for (i = 0; i < TILE_MAX; i++)
10156 int element = object_mapping[i].element_rnd;
10157 int action = object_mapping[i].action;
10158 int direction = object_mapping[i].direction;
10159 boolean is_backside = object_mapping[i].is_backside;
10161 boolean action_removing = (action == ACTION_DIGGING ||
10162 action == ACTION_SNAPPING ||
10163 action == ACTION_COLLECTING);
10165 boolean action_exploding = ((action == ACTION_EXPLODING ||
10166 action == ACTION_SMASHED_BY_ROCK ||
10167 action == ACTION_SMASHED_BY_SPRING) &&
10168 element != EL_DIAMOND);
10169 boolean action_active = (action == ACTION_ACTIVE);
10170 boolean action_other = (action == ACTION_OTHER);
10172 for (j = 0; j < 8; j++)
10175 int effective_element = get_effective_element_EM(i, j);
10177 int effective_element = (j > 5 && i == Yacid_splash_eB ? EL_EMPTY :
10178 j > 5 && i == Yacid_splash_wB ? EL_EMPTY :
10180 i == Xdrip_stretch ? element :
10181 i == Xdrip_stretchB ? element :
10182 i == Ydrip_s1 ? element :
10183 i == Ydrip_s1B ? element :
10184 i == Xball_1B ? element :
10185 i == Xball_2 ? element :
10186 i == Xball_2B ? element :
10187 i == Yball_eat ? element :
10188 i == Ykey_1_eat ? element :
10189 i == Ykey_2_eat ? element :
10190 i == Ykey_3_eat ? element :
10191 i == Ykey_4_eat ? element :
10192 i == Ykey_5_eat ? element :
10193 i == Ykey_6_eat ? element :
10194 i == Ykey_7_eat ? element :
10195 i == Ykey_8_eat ? element :
10196 i == Ylenses_eat ? element :
10197 i == Ymagnify_eat ? element :
10198 i == Ygrass_eat ? element :
10199 i == Ydirt_eat ? element :
10200 i == Yemerald_stone ? EL_EMERALD :
10201 i == Ydiamond_stone ? EL_ROCK :
10202 i == Xsand_stonein_1 ? element :
10203 i == Xsand_stonein_2 ? element :
10204 i == Xsand_stonein_3 ? element :
10205 i == Xsand_stonein_4 ? element :
10206 is_backside ? EL_EMPTY :
10207 action_removing ? EL_EMPTY :
10210 int effective_action = (j < 7 ? action :
10211 i == Xdrip_stretch ? action :
10212 i == Xdrip_stretchB ? action :
10213 i == Ydrip_s1 ? action :
10214 i == Ydrip_s1B ? action :
10215 i == Xball_1B ? action :
10216 i == Xball_2 ? action :
10217 i == Xball_2B ? action :
10218 i == Yball_eat ? action :
10219 i == Ykey_1_eat ? action :
10220 i == Ykey_2_eat ? action :
10221 i == Ykey_3_eat ? action :
10222 i == Ykey_4_eat ? action :
10223 i == Ykey_5_eat ? action :
10224 i == Ykey_6_eat ? action :
10225 i == Ykey_7_eat ? action :
10226 i == Ykey_8_eat ? action :
10227 i == Ylenses_eat ? action :
10228 i == Ymagnify_eat ? action :
10229 i == Ygrass_eat ? action :
10230 i == Ydirt_eat ? action :
10231 i == Xsand_stonein_1 ? action :
10232 i == Xsand_stonein_2 ? action :
10233 i == Xsand_stonein_3 ? action :
10234 i == Xsand_stonein_4 ? action :
10235 i == Xsand_stoneout_1 ? action :
10236 i == Xsand_stoneout_2 ? action :
10237 i == Xboom_android ? ACTION_EXPLODING :
10238 action_exploding ? ACTION_EXPLODING :
10239 action_active ? action :
10240 action_other ? action :
10242 int graphic = (el_act_dir2img(effective_element, effective_action,
10244 int crumbled = (el_act_dir2crm(effective_element, effective_action,
10246 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
10247 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
10248 boolean has_action_graphics = (graphic != base_graphic);
10249 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
10250 struct GraphicInfo *g = &graphic_info[graphic];
10252 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
10254 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
10255 Bitmap *src_bitmap;
10257 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
10258 boolean special_animation = (action != ACTION_DEFAULT &&
10259 g->anim_frames == 3 &&
10260 g->anim_delay == 2 &&
10261 g->anim_mode & ANIM_LINEAR);
10262 int sync_frame = (i == Xdrip_stretch ? 7 :
10263 i == Xdrip_stretchB ? 7 :
10264 i == Ydrip_s2 ? j + 8 :
10265 i == Ydrip_s2B ? j + 8 :
10267 i == Xacid_2 ? 10 :
10268 i == Xacid_3 ? 20 :
10269 i == Xacid_4 ? 30 :
10270 i == Xacid_5 ? 40 :
10271 i == Xacid_6 ? 50 :
10272 i == Xacid_7 ? 60 :
10273 i == Xacid_8 ? 70 :
10274 i == Xfake_acid_1 ? 0 :
10275 i == Xfake_acid_2 ? 10 :
10276 i == Xfake_acid_3 ? 20 :
10277 i == Xfake_acid_4 ? 30 :
10278 i == Xfake_acid_5 ? 40 :
10279 i == Xfake_acid_6 ? 50 :
10280 i == Xfake_acid_7 ? 60 :
10281 i == Xfake_acid_8 ? 70 :
10283 i == Xball_2B ? j + 8 :
10284 i == Yball_eat ? j + 1 :
10285 i == Ykey_1_eat ? j + 1 :
10286 i == Ykey_2_eat ? j + 1 :
10287 i == Ykey_3_eat ? j + 1 :
10288 i == Ykey_4_eat ? j + 1 :
10289 i == Ykey_5_eat ? j + 1 :
10290 i == Ykey_6_eat ? j + 1 :
10291 i == Ykey_7_eat ? j + 1 :
10292 i == Ykey_8_eat ? j + 1 :
10293 i == Ylenses_eat ? j + 1 :
10294 i == Ymagnify_eat ? j + 1 :
10295 i == Ygrass_eat ? j + 1 :
10296 i == Ydirt_eat ? j + 1 :
10297 i == Xamoeba_1 ? 0 :
10298 i == Xamoeba_2 ? 1 :
10299 i == Xamoeba_3 ? 2 :
10300 i == Xamoeba_4 ? 3 :
10301 i == Xamoeba_5 ? 0 :
10302 i == Xamoeba_6 ? 1 :
10303 i == Xamoeba_7 ? 2 :
10304 i == Xamoeba_8 ? 3 :
10305 i == Xexit_2 ? j + 8 :
10306 i == Xexit_3 ? j + 16 :
10307 i == Xdynamite_1 ? 0 :
10308 i == Xdynamite_2 ? 8 :
10309 i == Xdynamite_3 ? 16 :
10310 i == Xdynamite_4 ? 24 :
10311 i == Xsand_stonein_1 ? j + 1 :
10312 i == Xsand_stonein_2 ? j + 9 :
10313 i == Xsand_stonein_3 ? j + 17 :
10314 i == Xsand_stonein_4 ? j + 25 :
10315 i == Xsand_stoneout_1 && j == 0 ? 0 :
10316 i == Xsand_stoneout_1 && j == 1 ? 0 :
10317 i == Xsand_stoneout_1 && j == 2 ? 1 :
10318 i == Xsand_stoneout_1 && j == 3 ? 2 :
10319 i == Xsand_stoneout_1 && j == 4 ? 2 :
10320 i == Xsand_stoneout_1 && j == 5 ? 3 :
10321 i == Xsand_stoneout_1 && j == 6 ? 4 :
10322 i == Xsand_stoneout_1 && j == 7 ? 4 :
10323 i == Xsand_stoneout_2 && j == 0 ? 5 :
10324 i == Xsand_stoneout_2 && j == 1 ? 6 :
10325 i == Xsand_stoneout_2 && j == 2 ? 7 :
10326 i == Xsand_stoneout_2 && j == 3 ? 8 :
10327 i == Xsand_stoneout_2 && j == 4 ? 9 :
10328 i == Xsand_stoneout_2 && j == 5 ? 11 :
10329 i == Xsand_stoneout_2 && j == 6 ? 13 :
10330 i == Xsand_stoneout_2 && j == 7 ? 15 :
10331 i == Xboom_bug && j == 1 ? 2 :
10332 i == Xboom_bug && j == 2 ? 2 :
10333 i == Xboom_bug && j == 3 ? 4 :
10334 i == Xboom_bug && j == 4 ? 4 :
10335 i == Xboom_bug && j == 5 ? 2 :
10336 i == Xboom_bug && j == 6 ? 2 :
10337 i == Xboom_bug && j == 7 ? 0 :
10338 i == Xboom_bomb && j == 1 ? 2 :
10339 i == Xboom_bomb && j == 2 ? 2 :
10340 i == Xboom_bomb && j == 3 ? 4 :
10341 i == Xboom_bomb && j == 4 ? 4 :
10342 i == Xboom_bomb && j == 5 ? 2 :
10343 i == Xboom_bomb && j == 6 ? 2 :
10344 i == Xboom_bomb && j == 7 ? 0 :
10345 i == Xboom_android && j == 7 ? 6 :
10346 i == Xboom_1 && j == 1 ? 2 :
10347 i == Xboom_1 && j == 2 ? 2 :
10348 i == Xboom_1 && j == 3 ? 4 :
10349 i == Xboom_1 && j == 4 ? 4 :
10350 i == Xboom_1 && j == 5 ? 6 :
10351 i == Xboom_1 && j == 6 ? 6 :
10352 i == Xboom_1 && j == 7 ? 8 :
10353 i == Xboom_2 && j == 0 ? 8 :
10354 i == Xboom_2 && j == 1 ? 8 :
10355 i == Xboom_2 && j == 2 ? 10 :
10356 i == Xboom_2 && j == 3 ? 10 :
10357 i == Xboom_2 && j == 4 ? 10 :
10358 i == Xboom_2 && j == 5 ? 12 :
10359 i == Xboom_2 && j == 6 ? 12 :
10360 i == Xboom_2 && j == 7 ? 12 :
10361 special_animation && j == 4 ? 3 :
10362 effective_action != action ? 0 :
10366 Bitmap *debug_bitmap = g_em->bitmap;
10367 int debug_src_x = g_em->src_x;
10368 int debug_src_y = g_em->src_y;
10371 int frame = getAnimationFrame(g->anim_frames,
10374 g->anim_start_frame,
10377 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y,
10378 g->double_movement && is_backside);
10380 g_em->bitmap = src_bitmap;
10381 g_em->src_x = src_x;
10382 g_em->src_y = src_y;
10383 g_em->src_offset_x = 0;
10384 g_em->src_offset_y = 0;
10385 g_em->dst_offset_x = 0;
10386 g_em->dst_offset_y = 0;
10387 g_em->width = TILEX;
10388 g_em->height = TILEY;
10390 g_em->preserve_background = FALSE;
10393 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
10398 g_em->crumbled_bitmap = NULL;
10399 g_em->crumbled_src_x = 0;
10400 g_em->crumbled_src_y = 0;
10401 g_em->crumbled_border_size = 0;
10403 g_em->has_crumbled_graphics = FALSE;
10406 if (has_crumbled_graphics && crumbled == IMG_EMPTY_SPACE)
10407 printf("::: empty crumbled: %d [%s], %d, %d\n",
10408 effective_element, element_info[effective_element].token_name,
10409 effective_action, direction);
10412 /* if element can be crumbled, but certain action graphics are just empty
10413 space (like instantly snapping sand to empty space in 1 frame), do not
10414 treat these empty space graphics as crumbled graphics in EMC engine */
10415 if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
10417 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
10418 g_crumbled->anim_delay,
10419 g_crumbled->anim_mode,
10420 g_crumbled->anim_start_frame,
10423 getGraphicSource(crumbled, frame_crumbled, &src_bitmap, &src_x, &src_y);
10425 g_em->has_crumbled_graphics = TRUE;
10426 g_em->crumbled_bitmap = src_bitmap;
10427 g_em->crumbled_src_x = src_x;
10428 g_em->crumbled_src_y = src_y;
10429 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
10433 if (g_em == &graphic_info_em_object[207][0])
10434 printf("... %d, %d [%d, %d, %d, %d] [%d, %d, %d, %d, %d, %d => %d]\n",
10435 graphic_info_em_object[207][0].crumbled_src_x,
10436 graphic_info_em_object[207][0].crumbled_src_y,
10438 crumbled, frame, src_x, src_y,
10443 g->anim_start_frame,
10445 gfx.anim_random_frame,
10450 printf("::: EMC tile %d is crumbled\n", i);
10456 if (element == EL_ROCK &&
10457 effective_action == ACTION_FILLING)
10458 printf("::: has_action_graphics == %d\n", has_action_graphics);
10461 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
10462 effective_action == ACTION_MOVING ||
10463 effective_action == ACTION_PUSHING ||
10464 effective_action == ACTION_EATING)) ||
10465 (!has_action_graphics && (effective_action == ACTION_FILLING ||
10466 effective_action == ACTION_EMPTYING)))
10469 (effective_action == ACTION_FALLING ||
10470 effective_action == ACTION_FILLING ||
10471 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
10472 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
10473 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
10474 int num_steps = (i == Ydrip_s1 ? 16 :
10475 i == Ydrip_s1B ? 16 :
10476 i == Ydrip_s2 ? 16 :
10477 i == Ydrip_s2B ? 16 :
10478 i == Xsand_stonein_1 ? 32 :
10479 i == Xsand_stonein_2 ? 32 :
10480 i == Xsand_stonein_3 ? 32 :
10481 i == Xsand_stonein_4 ? 32 :
10482 i == Xsand_stoneout_1 ? 16 :
10483 i == Xsand_stoneout_2 ? 16 : 8);
10484 int cx = ABS(dx) * (TILEX / num_steps);
10485 int cy = ABS(dy) * (TILEY / num_steps);
10486 int step_frame = (i == Ydrip_s2 ? j + 8 :
10487 i == Ydrip_s2B ? j + 8 :
10488 i == Xsand_stonein_2 ? j + 8 :
10489 i == Xsand_stonein_3 ? j + 16 :
10490 i == Xsand_stonein_4 ? j + 24 :
10491 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
10492 int step = (is_backside ? step_frame : num_steps - step_frame);
10494 if (is_backside) /* tile where movement starts */
10496 if (dx < 0 || dy < 0)
10498 g_em->src_offset_x = cx * step;
10499 g_em->src_offset_y = cy * step;
10503 g_em->dst_offset_x = cx * step;
10504 g_em->dst_offset_y = cy * step;
10507 else /* tile where movement ends */
10509 if (dx < 0 || dy < 0)
10511 g_em->dst_offset_x = cx * step;
10512 g_em->dst_offset_y = cy * step;
10516 g_em->src_offset_x = cx * step;
10517 g_em->src_offset_y = cy * step;
10521 g_em->width = TILEX - cx * step;
10522 g_em->height = TILEY - cy * step;
10525 /* create unique graphic identifier to decide if tile must be redrawn */
10526 /* bit 31 - 16 (16 bit): EM style graphic
10527 bit 15 - 12 ( 4 bit): EM style frame
10528 bit 11 - 6 ( 6 bit): graphic width
10529 bit 5 - 0 ( 6 bit): graphic height */
10530 g_em->unique_identifier =
10531 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
10535 /* skip check for EMC elements not contained in original EMC artwork */
10536 if (element == EL_EMC_FAKE_ACID)
10539 if (g_em->bitmap != debug_bitmap ||
10540 g_em->src_x != debug_src_x ||
10541 g_em->src_y != debug_src_y ||
10542 g_em->src_offset_x != 0 ||
10543 g_em->src_offset_y != 0 ||
10544 g_em->dst_offset_x != 0 ||
10545 g_em->dst_offset_y != 0 ||
10546 g_em->width != TILEX ||
10547 g_em->height != TILEY)
10549 static int last_i = -1;
10557 printf("::: EMC GFX ERROR for element %d -> %d ('%s', '%s', %d)",
10558 i, element, element_info[element].token_name,
10559 element_action_info[effective_action].suffix, direction);
10561 if (element != effective_element)
10562 printf(" [%d ('%s')]",
10564 element_info[effective_element].token_name);
10568 if (g_em->bitmap != debug_bitmap)
10569 printf(" %d (%d): different bitmap! (0x%08x != 0x%08x)\n",
10570 j, is_backside, (int)(g_em->bitmap), (int)(debug_bitmap));
10572 if (g_em->src_x != debug_src_x ||
10573 g_em->src_y != debug_src_y)
10574 printf(" frame %d (%c): %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
10575 j, (is_backside ? 'B' : 'F'),
10576 g_em->src_x, g_em->src_y,
10577 g_em->src_x / 32, g_em->src_y / 32,
10578 debug_src_x, debug_src_y,
10579 debug_src_x / 32, debug_src_y / 32);
10581 if (g_em->src_offset_x != 0 ||
10582 g_em->src_offset_y != 0 ||
10583 g_em->dst_offset_x != 0 ||
10584 g_em->dst_offset_y != 0)
10585 printf(" %d (%d): offsets %d,%d and %d,%d should be all 0\n",
10587 g_em->src_offset_x, g_em->src_offset_y,
10588 g_em->dst_offset_x, g_em->dst_offset_y);
10590 if (g_em->width != TILEX ||
10591 g_em->height != TILEY)
10592 printf(" %d (%d): size %d,%d should be %d,%d\n",
10594 g_em->width, g_em->height, TILEX, TILEY);
10596 num_em_gfx_errors++;
10603 for (i = 0; i < TILE_MAX; i++)
10605 for (j = 0; j < 8; j++)
10607 int element = object_mapping[i].element_rnd;
10608 int action = object_mapping[i].action;
10609 int direction = object_mapping[i].direction;
10610 boolean is_backside = object_mapping[i].is_backside;
10611 int graphic_action = el_act_dir2img(element, action, direction);
10612 int graphic_default = el_act_dir2img(element, ACTION_DEFAULT, direction);
10614 if ((action == ACTION_SMASHED_BY_ROCK ||
10615 action == ACTION_SMASHED_BY_SPRING ||
10616 action == ACTION_EATING) &&
10617 graphic_action == graphic_default)
10619 int e = (action == ACTION_SMASHED_BY_ROCK ? Ystone_s :
10620 action == ACTION_SMASHED_BY_SPRING ? Yspring_s :
10621 direction == MV_LEFT ? (is_backside? Yspring_wB: Yspring_w) :
10622 direction == MV_RIGHT ? (is_backside? Yspring_eB: Yspring_e) :
10625 /* no separate animation for "smashed by rock" -- use rock instead */
10626 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
10627 struct GraphicInfo_EM *g_xx = &graphic_info_em_object[e][7 - j];
10629 g_em->bitmap = g_xx->bitmap;
10630 g_em->src_x = g_xx->src_x;
10631 g_em->src_y = g_xx->src_y;
10632 g_em->src_offset_x = g_xx->src_offset_x;
10633 g_em->src_offset_y = g_xx->src_offset_y;
10634 g_em->dst_offset_x = g_xx->dst_offset_x;
10635 g_em->dst_offset_y = g_xx->dst_offset_y;
10636 g_em->width = g_xx->width;
10637 g_em->height = g_xx->height;
10638 g_em->unique_identifier = g_xx->unique_identifier;
10641 g_em->preserve_background = TRUE;
10646 for (p = 0; p < MAX_PLAYERS; p++)
10648 for (i = 0; i < SPR_MAX; i++)
10650 int element = player_mapping[p][i].element_rnd;
10651 int action = player_mapping[p][i].action;
10652 int direction = player_mapping[p][i].direction;
10654 for (j = 0; j < 8; j++)
10656 int effective_element = element;
10657 int effective_action = action;
10658 int graphic = (direction == MV_NONE ?
10659 el_act2img(effective_element, effective_action) :
10660 el_act_dir2img(effective_element, effective_action,
10662 struct GraphicInfo *g = &graphic_info[graphic];
10663 struct GraphicInfo_EM *g_em = &graphic_info_em_player[p][i][7 - j];
10664 Bitmap *src_bitmap;
10666 int sync_frame = j;
10669 Bitmap *debug_bitmap = g_em->bitmap;
10670 int debug_src_x = g_em->src_x;
10671 int debug_src_y = g_em->src_y;
10674 int frame = getAnimationFrame(g->anim_frames,
10677 g->anim_start_frame,
10680 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
10682 g_em->bitmap = src_bitmap;
10683 g_em->src_x = src_x;
10684 g_em->src_y = src_y;
10685 g_em->src_offset_x = 0;
10686 g_em->src_offset_y = 0;
10687 g_em->dst_offset_x = 0;
10688 g_em->dst_offset_y = 0;
10689 g_em->width = TILEX;
10690 g_em->height = TILEY;
10694 /* skip check for EMC elements not contained in original EMC artwork */
10695 if (element == EL_PLAYER_3 ||
10696 element == EL_PLAYER_4)
10699 if (g_em->bitmap != debug_bitmap ||
10700 g_em->src_x != debug_src_x ||
10701 g_em->src_y != debug_src_y)
10703 static int last_i = -1;
10711 printf("::: EMC GFX ERROR for p/a %d/%d -> %d ('%s', '%s', %d)",
10712 p, i, element, element_info[element].token_name,
10713 element_action_info[effective_action].suffix, direction);
10715 if (element != effective_element)
10716 printf(" [%d ('%s')]",
10718 element_info[effective_element].token_name);
10722 if (g_em->bitmap != debug_bitmap)
10723 printf(" %d: different bitmap! (0x%08x != 0x%08x)\n",
10724 j, (int)(g_em->bitmap), (int)(debug_bitmap));
10726 if (g_em->src_x != debug_src_x ||
10727 g_em->src_y != debug_src_y)
10728 printf(" frame %d: %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
10730 g_em->src_x, g_em->src_y,
10731 g_em->src_x / 32, g_em->src_y / 32,
10732 debug_src_x, debug_src_y,
10733 debug_src_x / 32, debug_src_y / 32);
10735 num_em_gfx_errors++;
10745 printf("::: [%d errors found]\n", num_em_gfx_errors);
10751 void CheckSingleStepMode_EM(byte action[MAX_PLAYERS], int frame,
10752 boolean any_player_moving,
10753 boolean player_is_dropping)
10755 if (tape.single_step && tape.recording && !tape.pausing)
10758 boolean active_players = FALSE;
10761 for (i = 0; i < MAX_PLAYERS; i++)
10762 if (action[i] != JOY_NO_ACTION)
10763 active_players = TRUE;
10767 if (frame == 0 && !player_is_dropping)
10768 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
10772 void CheckSingleStepMode_SP(boolean murphy_is_waiting,
10773 boolean murphy_is_dropping)
10776 printf("::: waiting: %d, dropping: %d\n",
10777 murphy_is_waiting, murphy_is_dropping);
10780 if (tape.single_step && tape.recording && !tape.pausing)
10782 // if (murphy_is_waiting || murphy_is_dropping)
10783 if (murphy_is_waiting)
10786 printf("::: murphy is waiting -> pause mode\n");
10789 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
10794 void getGraphicSource_SP(struct GraphicInfo_SP *g_sp,
10795 int graphic, int sync_frame, int x, int y)
10797 int frame = getGraphicAnimationFrame(graphic, sync_frame);
10799 getGraphicSource(graphic, frame, &g_sp->bitmap, &g_sp->src_x, &g_sp->src_y);
10802 boolean isNextAnimationFrame_SP(int graphic, int sync_frame)
10804 return (IS_NEXT_FRAME(sync_frame, graphic));
10807 int getGraphicInfo_Delay(int graphic)
10809 return graphic_info[graphic].anim_delay;
10812 void PlayMenuSoundExt(int sound)
10814 if (sound == SND_UNDEFINED)
10817 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
10818 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
10821 if (IS_LOOP_SOUND(sound))
10822 PlaySoundLoop(sound);
10827 void PlayMenuSound()
10829 PlayMenuSoundExt(menu.sound[game_status]);
10832 void PlayMenuSoundStereo(int sound, int stereo_position)
10834 if (sound == SND_UNDEFINED)
10837 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
10838 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
10841 if (IS_LOOP_SOUND(sound))
10842 PlaySoundExt(sound, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_LOOP);
10844 PlaySoundStereo(sound, stereo_position);
10847 void PlayMenuSoundIfLoopExt(int sound)
10849 if (sound == SND_UNDEFINED)
10852 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
10853 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
10856 if (IS_LOOP_SOUND(sound))
10857 PlaySoundLoop(sound);
10860 void PlayMenuSoundIfLoop()
10862 PlayMenuSoundIfLoopExt(menu.sound[game_status]);
10865 void PlayMenuMusicExt(int music)
10867 if (music == MUS_UNDEFINED)
10870 if (!setup.sound_music)
10876 void PlayMenuMusic()
10878 PlayMenuMusicExt(menu.music[game_status]);
10881 void PlaySoundActivating()
10884 PlaySound(SND_MENU_ITEM_ACTIVATING);
10888 void PlaySoundSelecting()
10891 PlaySound(SND_MENU_ITEM_SELECTING);
10895 void ToggleFullscreenOrChangeWindowScalingIfNeeded()
10897 boolean change_fullscreen = (setup.fullscreen !=
10898 video.fullscreen_enabled);
10899 boolean change_fullscreen_mode = (video.fullscreen_enabled &&
10900 !strEqual(setup.fullscreen_mode,
10901 video.fullscreen_mode_current));
10902 boolean change_window_scaling_percent = (!video.fullscreen_enabled &&
10903 setup.window_scaling_percent !=
10904 video.window_scaling_percent);
10906 if (change_window_scaling_percent && video.fullscreen_enabled)
10909 if (!change_window_scaling_percent && !video.fullscreen_available)
10912 #if defined(TARGET_SDL2)
10913 if (change_window_scaling_percent)
10915 SDLSetWindowScaling(setup.window_scaling_percent);
10919 else if (change_fullscreen)
10921 SDLSetWindowFullscreen(setup.fullscreen);
10923 /* set setup value according to successfully changed fullscreen mode */
10924 setup.fullscreen = video.fullscreen_enabled;
10930 if (change_fullscreen ||
10931 change_fullscreen_mode ||
10932 change_window_scaling_percent)
10934 Bitmap *tmp_backbuffer = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
10936 /* save backbuffer content which gets lost when toggling fullscreen mode */
10937 BlitBitmap(backbuffer, tmp_backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
10939 if (change_fullscreen_mode)
10941 /* keep fullscreen, but change fullscreen mode (screen resolution) */
10942 video.fullscreen_enabled = FALSE; /* force new fullscreen mode */
10945 if (change_window_scaling_percent)
10947 /* keep window mode, but change window scaling */
10948 video.fullscreen_enabled = TRUE; /* force new window scaling */
10951 /* toggle fullscreen */
10952 ChangeVideoModeIfNeeded(setup.fullscreen);
10954 /* set setup value according to successfully changed fullscreen mode */
10955 setup.fullscreen = video.fullscreen_enabled;
10957 /* restore backbuffer content from temporary backbuffer backup bitmap */
10958 BlitBitmap(tmp_backbuffer, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
10960 FreeBitmap(tmp_backbuffer);
10963 /* update visible window/screen */
10964 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
10966 redraw_mask = REDRAW_ALL;
10971 void ChangeViewportPropertiesIfNeeded()
10974 int *door_1_x = &DX;
10975 int *door_1_y = &DY;
10976 int *door_2_x = (game_status == GAME_MODE_EDITOR ? &EX : &VX);
10977 int *door_2_y = (game_status == GAME_MODE_EDITOR ? &EY : &VY);
10979 int gfx_game_mode = (game_status == GAME_MODE_PLAYING ||
10980 game_status == GAME_MODE_EDITOR ? game_status :
10982 int gfx_game_mode2 = (game_status == GAME_MODE_EDITOR ? GAME_MODE_DEFAULT :
10984 struct RectWithBorder *vp_playfield = &viewport.playfield[gfx_game_mode];
10985 struct RectWithBorder *vp_door_1 = &viewport.door_1[gfx_game_mode];
10986 struct RectWithBorder *vp_door_2 = &viewport.door_2[gfx_game_mode2];
10987 struct RectWithBorder *vp_door_3 = &viewport.door_2[GAME_MODE_EDITOR];
10988 int border_size = vp_playfield->border_size;
10989 int new_sx = vp_playfield->x + border_size;
10990 int new_sy = vp_playfield->y + border_size;
10991 int new_sxsize = vp_playfield->width - 2 * border_size;
10992 int new_sysize = vp_playfield->height - 2 * border_size;
10993 int new_real_sx = vp_playfield->x;
10994 int new_real_sy = vp_playfield->y;
10995 int new_full_sxsize = vp_playfield->width;
10996 int new_full_sysize = vp_playfield->height;
10997 int new_dx = vp_door_1->x;
10998 int new_dy = vp_door_1->y;
10999 int new_dxsize = vp_door_1->width;
11000 int new_dysize = vp_door_1->height;
11001 int new_vx = vp_door_2->x;
11002 int new_vy = vp_door_2->y;
11003 int new_vxsize = vp_door_2->width;
11004 int new_vysize = vp_door_2->height;
11005 int new_ex = vp_door_3->x;
11006 int new_ey = vp_door_3->y;
11007 int new_exsize = vp_door_3->width;
11008 int new_eysize = vp_door_3->height;
11010 int new_tilesize_var = TILESIZE / (setup.small_game_graphics ? 2 : 1);
11011 int tilesize = (gfx_game_mode == GAME_MODE_PLAYING ? new_tilesize_var :
11012 gfx_game_mode == GAME_MODE_EDITOR ? MINI_TILESIZE : TILESIZE);
11013 int new_scr_fieldx = new_sxsize / tilesize;
11014 int new_scr_fieldy = new_sysize / tilesize;
11015 int new_scr_fieldx_buffers = new_sxsize / new_tilesize_var;
11016 int new_scr_fieldy_buffers = new_sysize / new_tilesize_var;
11018 int new_scr_fieldx = (vp_playfield->width - 2 * border_size) / TILESIZE;
11019 int new_scr_fieldy = (vp_playfield->height - 2 * border_size) / TILESIZE;
11021 boolean init_gfx_buffers = FALSE;
11022 boolean init_video_buffer = FALSE;
11023 boolean init_gadgets_and_toons = FALSE;
11026 /* !!! TEST ONLY !!! */
11027 // InitGfxBuffers();
11031 if (viewport.window.width != WIN_XSIZE ||
11032 viewport.window.height != WIN_YSIZE)
11034 WIN_XSIZE = viewport.window.width;
11035 WIN_YSIZE = viewport.window.height;
11038 init_video_buffer = TRUE;
11039 init_gfx_buffers = TRUE;
11041 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
11045 SetDrawDeactivationMask(REDRAW_NONE);
11046 SetDrawBackgroundMask(REDRAW_FIELD);
11048 // RedrawBackground();
11052 // printf("::: video: init_video_buffer, init_gfx_buffers\n");
11055 if (new_scr_fieldx != SCR_FIELDX ||
11056 new_scr_fieldy != SCR_FIELDY)
11058 /* this always toggles between MAIN and GAME when using small tile size */
11060 SCR_FIELDX = new_scr_fieldx;
11061 SCR_FIELDY = new_scr_fieldy;
11063 // printf("::: new_scr_fieldx != SCR_FIELDX ...\n");
11067 if (new_tilesize_var != TILESIZE_VAR &&
11068 gfx_game_mode == GAME_MODE_PLAYING)
11070 /* doing this outside GAME_MODE_PLAYING would give wrong playfield size */
11072 TILESIZE_VAR = new_tilesize_var;
11074 init_gfx_buffers = TRUE;
11076 // printf("::: tilesize: init_gfx_buffers\n");
11080 if (new_sx != SX ||
11088 new_sxsize != SXSIZE ||
11089 new_sysize != SYSIZE ||
11090 new_dxsize != DXSIZE ||
11091 new_dysize != DYSIZE ||
11092 new_vxsize != VXSIZE ||
11093 new_vysize != VYSIZE ||
11094 new_exsize != EXSIZE ||
11095 new_eysize != EYSIZE ||
11096 new_real_sx != REAL_SX ||
11097 new_real_sy != REAL_SY ||
11098 new_full_sxsize != FULL_SXSIZE ||
11099 new_full_sysize != FULL_SYSIZE ||
11100 new_tilesize_var != TILESIZE_VAR
11103 vp_door_1->x != *door_1_x ||
11104 vp_door_1->y != *door_1_y ||
11105 vp_door_2->x != *door_2_x ||
11106 vp_door_2->y != *door_2_y
11118 SXSIZE = new_sxsize;
11119 SYSIZE = new_sysize;
11120 DXSIZE = new_dxsize;
11121 DYSIZE = new_dysize;
11122 VXSIZE = new_vxsize;
11123 VYSIZE = new_vysize;
11124 EXSIZE = new_exsize;
11125 EYSIZE = new_eysize;
11126 REAL_SX = new_real_sx;
11127 REAL_SY = new_real_sy;
11128 FULL_SXSIZE = new_full_sxsize;
11129 FULL_SYSIZE = new_full_sysize;
11130 TILESIZE_VAR = new_tilesize_var;
11133 printf("::: %d, %d, %d [%d]\n",
11134 SCR_FIELDX, SCR_FIELDY, TILESIZE_VAR,
11135 setup.small_game_graphics);
11139 *door_1_x = vp_door_1->x;
11140 *door_1_y = vp_door_1->y;
11141 *door_2_x = vp_door_2->x;
11142 *door_2_y = vp_door_2->y;
11146 init_gfx_buffers = TRUE;
11148 // printf("::: viewports: init_gfx_buffers\n");
11153 if (gfx_game_mode == GAME_MODE_MAIN)
11156 init_gadgets_and_toons = TRUE;
11158 // printf("::: viewports: init_gadgets_and_toons\n");
11166 if (init_gfx_buffers)
11168 // printf("::: init_gfx_buffers\n");
11170 SCR_FIELDX = new_scr_fieldx_buffers;
11171 SCR_FIELDY = new_scr_fieldy_buffers;
11175 SCR_FIELDX = new_scr_fieldx;
11176 SCR_FIELDY = new_scr_fieldy;
11179 if (init_video_buffer)
11181 // printf("::: init_video_buffer\n");
11183 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
11185 SetDrawDeactivationMask(REDRAW_NONE);
11186 SetDrawBackgroundMask(REDRAW_FIELD);
11189 if (init_gadgets_and_toons)
11191 // printf("::: init_gadgets_and_toons\n");
11198 printf("::: %d, %d / %d, %d [%d]\n", VX, VY, EX, EY, game_status);