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;
5482 int num_xsteps[NUM_DOORS * MAX_NUM_DOOR_PARTS];
5483 int num_ysteps[NUM_DOORS * MAX_NUM_DOOR_PARTS];
5484 int max_move_delay = 0; // delay for complete animations of all doors
5485 int max_step_delay = 0; // delay (ms) between two animation frames
5486 int num_move_steps = 0; // number of animation steps for all doors
5489 for (i = 0; i < NUM_DOORS * MAX_NUM_DOOR_PARTS; i++)
5491 int nr = door_part_order[i].nr;
5492 struct DoorPartControlInfo *dpc = &door_part_controls[nr];
5493 int door_token = dpc->door_nr;
5495 door_part_done[nr] = !(door_state & door_token);
5498 for (i = 0; i < NUM_DOORS * MAX_NUM_DOOR_PARTS; i++)
5500 struct DoorPartControlInfo *dpc = &door_part_controls[i];
5501 struct GraphicInfo *g = &graphic_info[dpc->graphic];
5502 struct DoorPartPosInfo *pos = dpc->pos;
5503 int step_xoffset = ABS(pos->step_xoffset);
5504 int step_yoffset = ABS(pos->step_yoffset);
5505 int step_delay = pos->step_delay;
5506 int move_xsize = (step_xoffset ? g->width : 0);
5507 int move_ysize = (step_yoffset ? g->height : 0);
5509 int move_size = (move_xsize && move_ysize ?
5510 MIN(move_xsize, move_ysize) :
5511 move_xsize ? move_xsize : move_ysize);
5513 int move_xsteps = (step_xoffset ? CEIL(move_xsize, step_xoffset) : 0);
5514 int move_ysteps = (step_yoffset ? CEIL(move_ysize, step_yoffset) : 0);
5516 int move_xdelay = move_xsteps * step_delay;
5517 int move_ydelay = move_ysteps * step_delay;
5518 int move_delay = (move_xdelay && move_ydelay ?
5519 MIN(move_xdelay, move_ydelay) :
5520 move_xdelay ? move_xdelay : move_ydelay);
5522 int move_steps = (move_xsteps && move_ysteps ?
5523 MIN(move_xsteps, move_ysteps) :
5524 move_xsteps ? move_xsteps : move_ysteps);
5525 int move_delay = move_steps * step_delay;
5526 // int move_delay = MAX(move_xsize, move_ysize) * step_delay;
5528 max_move_delay = MAX(max_move_delay, move_delay);
5529 max_step_delay = (max_step_delay == 0 ? step_delay :
5530 euclid(max_step_delay, step_delay));
5532 num_xsteps[i] = move_xsteps;
5533 num_ysteps[i] = move_ysteps;
5536 num_move_steps = max_move_delay / max_step_delay;
5538 door_delay_value = max_step_delay;
5541 printf("::: max_move_delay == %d, max_step_delay == %d, num_move_steps == %d\n",
5542 max_move_delay, max_step_delay, num_move_steps);
5545 for (k = 0; k < num_move_steps; k++)
5547 for (i = 0; i < NUM_DOORS; i++)
5548 door_panel_drawn[i] = FALSE;
5550 for (i = 0; i < NUM_DOORS * MAX_NUM_DOOR_PARTS; i++)
5552 int nr = door_part_order[i].nr;
5553 struct DoorPartControlInfo *dpc = &door_part_controls[nr];
5554 int door_token = dpc->door_nr;
5555 int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
5556 struct GraphicInfo *g = &graphic_info[dpc->graphic];
5557 struct DoorPartPosInfo *pos = dpc->pos;
5558 struct XY *panel_pos = &panel_pos_list[door_index];
5559 struct Rect *door_rect = &door_rect_list[door_index];
5564 if (door_part_done[nr])
5567 if (!(door_state & door_token))
5573 if (!door_panel_drawn[door_index])
5575 BlitBitmap(bitmap_db_door, drawto, panel_pos->x, panel_pos->y,
5576 door_rect->width, door_rect->height,
5577 door_rect->x, door_rect->y);
5579 door_panel_drawn[door_index] = TRUE;
5583 if ((door_state & door_token) & DOOR_OPEN)
5593 printf("::: step_xoffset == %d, step_yoffset == %d\n",
5594 pos->step_xoffset, pos->step_yoffset);
5597 if (pos->step_xoffset < 0)
5601 dst_xx = pos->x + ABS(k * pos->step_xoffset);
5604 if (dst_xx + width > door_rect->width)
5605 width = door_rect->width - dst_xx;
5608 width = g->width + k * pos->step_xoffset;
5610 if (width > door_rect->width)
5611 width = door_rect->width;
5613 dst_xx = door_rect->width - width;
5619 dst_xx = pos->x - k * pos->step_xoffset;
5623 src_xx = ABS(dst_xx);
5627 width = g->width - src_xx;
5630 if (pos->step_yoffset < 0)
5634 dst_yy = pos->y + ABS(k * pos->step_yoffset);
5637 if (dst_yy + height > door_rect->height)
5638 height = door_rect->height - dst_yy;
5641 height = g->height + k * pos->step_yoffset;
5643 if (height > door_rect->height)
5644 height = door_rect->height;
5646 dst_yy = door_rect->height - height;
5652 dst_yy = pos->y - k * pos->step_yoffset;
5656 src_yy = ABS(dst_yy);
5660 height = g->height - src_yy;
5663 if (width < 0 || height < 0)
5664 door_part_done[nr] = TRUE;
5671 door_part_done[nr] = TRUE;
5673 BlitBitmapMasked(g->bitmap, drawto, g->src_x, g->src_y,
5674 g->width, g->height,
5675 door_rect->x + pos->x, door_rect->y + pos->y);
5677 redraw_mask |= REDRAW_DOOR_FROM_TOKEN(door_token);
5679 src_xx = (num_xsteps[nr] - k) * pos->step_xoffset;
5680 src_yy = (num_ysteps[nr] - k) * pos->step_yoffset;
5683 width = g->width - src_xx;
5684 height = g->height - src_yy;
5686 // if (width < ABS(pos->step_xoffset)
5691 src_xx = g->width - k * pos->step_xoffset;
5692 src_yy = g->height - k * pos->step_yoffset;
5696 if (width < 0 || height < 0)
5697 door_part_done[nr] = TRUE;
5701 if (door_part_done[nr])
5710 BlitBitmapMasked(g->bitmap, drawto,
5711 g->src_x + src_xx, g->src_y + src_yy, width, height,
5712 door_rect->x + dst_xx, door_rect->y + dst_yy);
5715 if (!((door_state & door_token) & DOOR_CLOSE))
5718 BlitBitmapMasked(g->bitmap, drawto, g->src_x, g->src_y,
5719 g->width, g->height,
5720 door_rect->x + pos->x, door_rect->y + pos->y);
5723 redraw_mask |= REDRAW_DOOR_FROM_TOKEN(door_token);
5726 door_part_done_all = TRUE;
5728 for (i = 0; i < NUM_DOORS * MAX_NUM_DOOR_PARTS; i++)
5729 if (!door_part_done[i])
5730 door_part_done_all = FALSE;
5732 if (door_part_done_all)
5735 if (!(door_state & DOOR_NO_DELAY))
5739 if (game_status == GAME_MODE_MAIN)
5742 WaitUntilDelayReached(&door_delay, door_delay_value);
5747 redraw_mask |= REDRAW_ALL;
5749 if (door_state & DOOR_ACTION_1)
5750 door1 = door_state & DOOR_ACTION_1;
5751 if (door_state & DOOR_ACTION_2)
5752 door2 = door_state & DOOR_ACTION_2;
5754 return (door1 | door2);
5759 // ========== OLD ==============================================================
5761 unsigned int MoveDoor(unsigned int door_state)
5763 static int door1 = DOOR_OPEN_1;
5764 static int door2 = DOOR_CLOSE_2;
5765 unsigned int door_delay = 0;
5766 unsigned int door_delay_value;
5770 if (door_1.width < 0 || door_1.width > DXSIZE)
5771 door_1.width = DXSIZE;
5772 if (door_1.height < 0 || door_1.height > DYSIZE)
5773 door_1.height = DYSIZE;
5774 if (door_2.width < 0 || door_2.width > VXSIZE)
5775 door_2.width = VXSIZE;
5776 if (door_2.height < 0 || door_2.height > VYSIZE)
5777 door_2.height = VYSIZE;
5780 if (door_state == DOOR_GET_STATE)
5781 return (door1 | door2);
5783 if (door_state & DOOR_SET_STATE)
5785 if (door_state & DOOR_ACTION_1)
5786 door1 = door_state & DOOR_ACTION_1;
5787 if (door_state & DOOR_ACTION_2)
5788 door2 = door_state & DOOR_ACTION_2;
5790 return (door1 | door2);
5793 if (!(door_state & DOOR_FORCE_REDRAW))
5795 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
5796 door_state &= ~DOOR_OPEN_1;
5797 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
5798 door_state &= ~DOOR_CLOSE_1;
5799 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
5800 door_state &= ~DOOR_OPEN_2;
5801 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
5802 door_state &= ~DOOR_CLOSE_2;
5805 door_delay_value = (door_state & DOOR_ACTION_1 ? door_1.step_delay :
5808 // door_delay_value *= 4; // !!! TEST ONLY !!!
5810 if (setup.quick_doors)
5812 stepsize = 20; /* must be chosen to always draw last frame */
5813 door_delay_value = 0;
5816 if (global.autoplay_leveldir)
5818 door_state |= DOOR_NO_DELAY;
5819 door_state &= ~DOOR_CLOSE_ALL;
5823 if (game_status == GAME_MODE_EDITOR)
5824 door_state |= DOOR_NO_DELAY;
5827 if (door_state & DOOR_ACTION)
5830 struct GraphicInfo *g1_left = &graphic_info[IMG_DOOR_1_WING_LEFT];
5831 struct GraphicInfo *g1_right = &graphic_info[IMG_DOOR_1_WING_RIGHT];
5832 struct GraphicInfo *g2_left = &graphic_info[IMG_DOOR_2_WING_LEFT];
5833 struct GraphicInfo *g2_right = &graphic_info[IMG_DOOR_2_WING_RIGHT];
5834 int door_1_left_width = g1_left->width;
5835 int door_1_left_height = g1_left->height;
5836 int door_1_right_width = g1_right->width;
5837 int door_1_right_height = g1_right->height;
5838 int door_2_left_width = g2_left->width;
5839 int door_2_left_height = g2_left->height;
5840 int door_2_right_width = g2_right->width;
5841 int door_2_right_height = g2_right->height;
5842 int door_1_width = MAX(door_1_left_width, door_1_right_width);
5843 int door_1_height = MAX(door_1_left_height, door_1_right_height);
5844 int door_2_width = MAX(door_2_left_width, door_2_right_width);
5845 int door_2_height = MAX(door_2_left_height, door_2_right_height);
5847 boolean handle_door_1 = (door_state & DOOR_ACTION_1);
5848 boolean handle_door_2 = (door_state & DOOR_ACTION_2);
5849 boolean door_1_done = (!handle_door_1);
5850 boolean door_2_done = (!handle_door_2);
5851 boolean door_1_vertical = (door_1.anim_mode & ANIM_VERTICAL);
5852 boolean door_2_vertical = (door_2.anim_mode & ANIM_VERTICAL);
5855 int door_size_1 = (door_1_vertical ? door_1_height : door_1_width);
5856 int door_size_2 = (door_2_vertical ? door_2_height : door_2_width);
5858 int door_size_1 = (door_1_vertical ? DYSIZE : DXSIZE);
5859 int door_size_2 = (door_2_vertical ? VYSIZE : VXSIZE);
5862 int door_size_1 = (door_1_vertical ? door_1.height : door_1.width);
5863 int door_size_2 = (door_2_vertical ? door_2.height : door_2.width);
5865 int max_door_size_1 = (door_1_vertical ? DYSIZE : DXSIZE);
5866 int max_door_size_2 = (door_2_vertical ? VYSIZE : VXSIZE);
5867 // int door_size = (handle_door_1 ? door_size_1 : door_size_2);
5868 int door_size = (handle_door_2 ? door_size_2 : door_size_1);
5869 int max_door_size = (handle_door_1 ? max_door_size_1 : max_door_size_2);
5870 int door_skip = max_door_size - door_size;
5871 int end = door_size;
5872 int start = ((door_state & DOOR_NO_DELAY) ? end : 0);
5875 if (!(door_state & DOOR_NO_DELAY) && !setup.quick_doors)
5877 /* opening door sound has priority over simultaneously closing door */
5878 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
5879 PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
5880 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
5881 PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
5884 for (k = start; k <= end && !(door_1_done && door_2_done); k += stepsize)
5888 Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
5889 GC gc = bitmap->stored_clip_gc;
5892 if (door_state & DOOR_ACTION_1 &&
5893 x * door_1.step_offset <= door_size_1)
5895 int a = MIN(x * door_1.step_offset, end);
5896 int p = (door_state & DOOR_OPEN_1 ? end - a : a);
5900 int i = p + door_skip;
5904 struct GraphicInfo *g_left = &graphic_info[IMG_DOOR_1_WING_LEFT];
5905 struct GraphicInfo *g_right = &graphic_info[IMG_DOOR_1_WING_RIGHT];
5906 Bitmap *bm_left = g_left->bitmap;
5907 Bitmap *bm_right = g_right->bitmap;
5908 GC gc_left = bm_left->stored_clip_gc;
5909 GC gc_right = bm_right->stored_clip_gc;
5912 int classic_dxsize = 100;
5913 int classic_dysize = 280;
5914 boolean classic_door_1_size = (DXSIZE == classic_dxsize &&
5915 DYSIZE == classic_dysize);
5917 if (door_1.anim_mode & ANIM_STATIC_PANEL)
5919 BlitBitmap(bitmap_db_door, drawto,
5920 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1,
5921 DXSIZE, DYSIZE, DX, DY);
5925 BlitBitmap(bitmap_db_door, drawto,
5926 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + p / 2,
5927 DXSIZE, DYSIZE - p / 2, DX, DY);
5930 // printf("::: p == %d\n", p);
5931 ClearRectangle(drawto, DX, DY + DYSIZE - p / 2, DXSIZE, p / 2);
5935 if (door_1.anim_mode & ANIM_HORIZONTAL && x <= DXSIZE)
5938 int src1_x = g_right->src_x;
5939 int src1_y = g_right->src_y;
5940 int src2_x = g_left->src_x + g_left->width - i;
5941 int src2_y = g_left->src_y;
5942 int dst1_x = DX + DXSIZE - i;
5947 int height = DYSIZE;
5949 SetClipOrigin(bm_right, gc_right, dst1_x - src1_x, dst1_y - src1_y);
5950 BlitBitmapMasked(bm_right, drawto, src1_x, src1_y, width, height,
5953 SetClipOrigin(bm_left, gc_left, dst2_x - src2_x, dst2_y - src2_y);
5954 BlitBitmapMasked(bm_left, drawto, src2_x, src2_y, width, height,
5957 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
5958 int src2_x = DXSIZE - i, src2_y = DOOR_GFX_PAGEY1;
5959 int dst1_x = DX + DXSIZE - i, dst1_y = DY;
5960 int dst2_x = DX, dst2_y = DY;
5961 int width = i, height = DYSIZE;
5963 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
5964 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
5967 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
5968 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
5972 else if (door_1.anim_mode & ANIM_VERTICAL && x <= DYSIZE)
5975 int src1_x = g_right->src_x;
5976 int src1_y = g_right->src_y;
5977 int src2_x = g_left->src_x;
5978 int src2_y = g_left->src_y + g_left->height - i;
5980 int dst1_y = DY + DYSIZE - i;
5986 SetClipOrigin(bm_right, gc_right, dst1_x - src1_x, dst1_y - src1_y);
5987 BlitBitmapMasked(bm_right, drawto, src1_x, src1_y, width, height,
5990 SetClipOrigin(bm_left, gc_left, dst2_x - src2_x, dst2_y - src2_y);
5991 BlitBitmapMasked(bm_left, drawto, src2_x, src2_y, width, height,
5994 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
5995 int src2_x = 0, src2_y = DOOR_GFX_PAGEY1 + DYSIZE - i;
5996 int dst1_x = DX, dst1_y = DY + DYSIZE - i;
5997 int dst2_x = DX, dst2_y = DY;
5998 int width = DXSIZE, height = i;
6000 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
6001 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
6004 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
6005 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
6009 else if (classic_door_1_size && x <= DXSIZE) /* ANIM_DEFAULT */
6011 int j = (door_1.anim_mode == ANIM_DEFAULT ? (DXSIZE - i) / 3 : 0);
6014 int src1_x = g_right->src_x;
6015 int src1_y = g_right->src_y;
6016 int src2_x = g_left->src_x + g_left->width - i;
6017 int src2_y = g_left->src_y;
6018 int dst1_x = DX + DXSIZE - i;
6023 int height1 = 63, height2 = DYSIZE / 2 - height1;
6024 int ypos1 = 0, ypos2 = height2;
6025 int ypos3 = DYSIZE / 2, ypos4 = DYSIZE - height2;
6027 SetClipOrigin(bm_right, gc_right,
6028 dst1_x - src1_x, dst1_y - src1_y + j);
6029 BlitBitmapMasked(bm_right, drawto,
6030 src1_x, src1_y + ypos1, width, height2,
6031 dst1_x, dst1_y + ypos1 + j);
6032 BlitBitmapMasked(bm_right, drawto,
6033 src1_x, src1_y + ypos3, width, height1,
6034 dst1_x, dst1_y + ypos3 + j);
6035 SetClipOrigin(bm_left, gc_left,
6036 dst2_x - src2_x, dst2_y - src2_y - j);
6037 BlitBitmapMasked(bm_left, drawto,
6038 src2_x, src2_y + ypos1 + j, width, height2 - j,
6039 dst2_x, dst2_y + ypos1);
6040 BlitBitmapMasked(bm_left, drawto,
6041 src2_x, src2_y + ypos3, width, height1,
6042 dst2_x, dst2_y + ypos3 - j);
6044 SetClipOrigin(bm_left, gc_left,
6045 dst2_x - src2_x, dst2_y - src2_y - j);
6046 BlitBitmapMasked(bm_left, drawto,
6047 src2_x, src2_y + ypos2, width, height1,
6048 dst2_x, dst2_y + ypos2 - j);
6049 BlitBitmapMasked(bm_left, drawto,
6050 src2_x, src2_y + ypos4, width, height2,
6051 dst2_x, dst2_y + ypos4 - j);
6052 SetClipOrigin(bm_right, gc_right,
6053 dst1_x - src1_x, dst1_y - src1_y + j);
6054 BlitBitmapMasked(bm_right, drawto,
6055 src1_x, src1_y + ypos2, width, height1,
6056 dst1_x, dst1_y + ypos2 + j);
6057 BlitBitmapMasked(bm_right, drawto,
6058 src1_x, src1_y + ypos4, width, height2 - j,
6059 dst1_x, dst1_y + ypos4 + j);
6062 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
6063 int src2_x = DXSIZE - i, src2_y = DOOR_GFX_PAGEY1;
6064 int dst1_x = DX + DXSIZE - i, dst1_y = DY;
6065 int dst2_x = DX, dst2_y = DY;
6066 int width = i, height = DYSIZE;
6067 int ypos1 = 63, ypos2 = 77, ypos3 = 140, ypos4 = 203;
6069 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y + j);
6070 BlitBitmapMasked(bitmap, drawto,
6071 src1_x, src1_y, width, ypos2,
6072 dst1_x, dst1_y + j);
6073 BlitBitmapMasked(bitmap, drawto,
6074 src1_x, src1_y + ypos3, width, ypos1,
6075 dst1_x, dst1_y + ypos3 + j);
6076 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y - j);
6077 BlitBitmapMasked(bitmap, drawto,
6078 src2_x, src2_y + j, width, ypos2 - j,
6080 BlitBitmapMasked(bitmap, drawto,
6081 src2_x, src2_y + ypos3, width, ypos1,
6082 dst2_x, dst2_y + ypos3 - j);
6084 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y - j);
6085 BlitBitmapMasked(bitmap, drawto,
6086 src2_x, src2_y + ypos2, width, ypos1,
6087 dst2_x, dst2_y + ypos2 - j);
6088 BlitBitmapMasked(bitmap, drawto,
6089 src2_x, src2_y + ypos4, width, ypos2,
6090 dst2_x, dst2_y + ypos4 - j);
6091 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y + j);
6092 BlitBitmapMasked(bitmap, drawto,
6093 src1_x, src1_y + ypos2, width, ypos1,
6094 dst1_x, dst1_y + ypos2 + j);
6095 BlitBitmapMasked(bitmap, drawto,
6096 src1_x, src1_y + ypos4, width, ypos2 - j,
6097 dst1_x, dst1_y + ypos4 + j);
6100 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
6101 BlitBitmapMasked(bitmap, drawto,
6102 DXSIZE, DOOR_GFX_PAGEY1, i, 77,
6103 DX + DXSIZE - i, DY + j);
6104 BlitBitmapMasked(bitmap, drawto,
6105 DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
6106 DX + DXSIZE - i, DY + 140 + j);
6107 SetClipOrigin(bitmap, gc, DX - DXSIZE + i,
6108 DY - (DOOR_GFX_PAGEY1 + j));
6109 BlitBitmapMasked(bitmap, drawto,
6110 DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
6112 BlitBitmapMasked(bitmap, drawto,
6113 DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
6116 BlitBitmapMasked(bitmap, drawto,
6117 DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
6119 BlitBitmapMasked(bitmap, drawto,
6120 DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
6122 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
6123 BlitBitmapMasked(bitmap, drawto,
6124 DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
6125 DX + DXSIZE - i, DY + 77 + j);
6126 BlitBitmapMasked(bitmap, drawto,
6127 DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
6128 DX + DXSIZE - i, DY + 203 + j);
6133 redraw_mask |= REDRAW_DOOR_1;
6134 door_1_done = (a == end);
6137 if (door_state & DOOR_ACTION_2 &&
6138 x * door_2.step_offset <= door_size_2)
6140 int a = MIN(x * door_2.step_offset, door_size);
6141 int p = (door_state & DOOR_OPEN_2 ? door_size - a : a);
6142 int i = p + door_skip;
6145 struct GraphicInfo *g_left = &graphic_info[IMG_DOOR_2_WING_LEFT];
6146 struct GraphicInfo *g_right = &graphic_info[IMG_DOOR_2_WING_RIGHT];
6147 Bitmap *bm_left = g_left->bitmap;
6148 Bitmap *bm_right = g_right->bitmap;
6149 GC gc_left = bm_left->stored_clip_gc;
6150 GC gc_right = bm_right->stored_clip_gc;
6153 int classic_vxsize = 100;
6154 int classic_vysize = 100;
6155 boolean classic_door_2_size = (VXSIZE == classic_vxsize &&
6156 VYSIZE == classic_vysize);
6158 if (door_2.anim_mode & ANIM_STATIC_PANEL)
6160 BlitBitmap(bitmap_db_door, drawto,
6161 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2,
6162 VXSIZE, VYSIZE, VX, VY);
6164 else if (x <= VYSIZE)
6166 BlitBitmap(bitmap_db_door, drawto,
6167 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + p / 2,
6168 VXSIZE, VYSIZE - p / 2, VX, VY);
6170 ClearRectangle(drawto, VX, VY + VYSIZE - p / 2, VXSIZE, p / 2);
6173 if (door_2.anim_mode & ANIM_HORIZONTAL && x <= VXSIZE)
6176 int src1_x = g_right->src_x;
6177 int src1_y = g_right->src_y;
6178 int src2_x = g_left->src_x + g_left->width - i;
6179 int src2_y = g_left->src_y;
6180 int dst1_x = VX + VXSIZE - i;
6185 int height = VYSIZE;
6187 SetClipOrigin(bm_right, gc_right, dst1_x - src1_x, dst1_y - src1_y);
6188 BlitBitmapMasked(bm_right, drawto, src1_x, src1_y, width, height,
6191 SetClipOrigin(bm_left, gc_left, dst2_x - src2_x, dst2_y - src2_y);
6192 BlitBitmapMasked(bm_left, drawto, src2_x, src2_y, width, height,
6195 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
6196 int src2_x = VXSIZE - i, src2_y = DOOR_GFX_PAGEY2;
6197 int dst1_x = VX + VXSIZE - i, dst1_y = VY;
6198 int dst2_x = VX, dst2_y = VY;
6199 int width = i, height = VYSIZE;
6201 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
6202 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
6205 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
6206 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
6210 else if (door_2.anim_mode & ANIM_VERTICAL && x <= VYSIZE)
6213 int src1_x = g_right->src_x;
6214 int src1_y = g_right->src_y;
6215 int src2_x = g_left->src_x;
6216 int src2_y = g_left->src_y + g_left->height - i;
6218 int dst1_y = VY + VYSIZE - i;
6224 SetClipOrigin(bm_right, gc_right, dst1_x - src1_x, dst1_y - src1_y);
6225 BlitBitmapMasked(bm_right, drawto, src1_x, src1_y, width, height,
6228 SetClipOrigin(bm_left, gc_left, dst2_x - src2_x, dst2_y - src2_y);
6229 BlitBitmapMasked(bm_left, drawto, src2_x, src2_y, width, height,
6232 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
6233 int src2_x = 0, src2_y = DOOR_GFX_PAGEY2 + VYSIZE - i;
6234 int dst1_x = VX, dst1_y = VY + VYSIZE - i;
6235 int dst2_x = VX, dst2_y = VY;
6236 int width = VXSIZE, height = i;
6238 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
6239 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
6242 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
6243 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
6247 else if (classic_door_2_size && x <= VXSIZE) /* ANIM_DEFAULT */
6249 int j = (door_2.anim_mode == ANIM_DEFAULT ? (VXSIZE - i) / 3 : 0);
6252 int src1_x = g_right->src_x;
6253 int src1_y = g_right->src_y;
6254 int src2_x = g_left->src_x + g_left->width - i;
6255 int src2_y = g_left->src_y;
6256 int dst1_x = VX + VXSIZE - i;
6261 int height = VYSIZE / 2;
6262 int ypos1 = 0, ypos2 = VYSIZE / 2;
6264 SetClipOrigin(bm_right, gc_right,
6265 dst1_x - src1_x, dst1_y - src1_y + j);
6266 BlitBitmapMasked(bm_right, drawto,
6267 src1_x, src1_y + ypos1, width, height,
6268 dst1_x, dst1_y + ypos1 + j);
6269 SetClipOrigin(bm_left, gc_left,
6270 dst2_x - src2_x, dst2_y - src2_y - j);
6271 BlitBitmapMasked(bm_left, drawto,
6272 src2_x, src2_y + ypos1 + j, width, height - j,
6273 dst2_x, dst2_y + ypos1);
6275 SetClipOrigin(bm_left, gc_left,
6276 dst2_x - src2_x, dst2_y - src2_y - j);
6277 BlitBitmapMasked(bm_left, drawto,
6278 src2_x, src2_y + ypos2, width, height,
6279 dst2_x, dst2_y + ypos2 - j);
6280 SetClipOrigin(bm_right, gc_right,
6281 dst1_x - src1_x, dst1_y - src1_y + j);
6282 BlitBitmapMasked(bm_right, drawto,
6283 src1_x, src1_y + ypos2, width, height - j,
6284 dst1_x, dst1_y + ypos2 + j);
6286 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
6287 int src2_x = VXSIZE - i, src2_y = DOOR_GFX_PAGEY2;
6288 int dst1_x = VX + VXSIZE - i, dst1_y = VY;
6289 int dst2_x = VX, dst2_y = VY;
6290 int width = i, height = VYSIZE;
6291 int ypos = VYSIZE / 2;
6293 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y + j);
6294 BlitBitmapMasked(bitmap, drawto,
6295 src1_x, src1_y, width, ypos,
6296 dst1_x, dst1_y + j);
6297 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src1_y - j);
6298 BlitBitmapMasked(bitmap, drawto,
6299 src2_x, src2_y + j, width, ypos - j,
6302 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src1_y - j);
6303 BlitBitmapMasked(bitmap, drawto,
6304 src2_x, src2_y + ypos, width, ypos,
6305 dst2_x, dst2_y + ypos - j);
6306 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y + j);
6307 BlitBitmapMasked(bitmap, drawto,
6308 src1_x, src1_y + ypos, width, ypos - j,
6309 dst1_x, dst1_y + ypos + j);
6312 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
6313 BlitBitmapMasked(bitmap, drawto,
6314 VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
6315 VX + VXSIZE - i, VY + j);
6316 SetClipOrigin(bitmap, gc,
6317 VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
6318 BlitBitmapMasked(bitmap, drawto,
6319 VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
6322 BlitBitmapMasked(bitmap, drawto,
6323 VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
6324 i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
6325 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
6326 BlitBitmapMasked(bitmap, drawto,
6327 VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
6329 VX + VXSIZE - i, VY + VYSIZE / 2 + j);
6334 redraw_mask |= REDRAW_DOOR_2;
6335 door_2_done = (a == VXSIZE);
6338 if (!(door_state & DOOR_NO_DELAY))
6342 if (game_status == GAME_MODE_MAIN)
6345 WaitUntilDelayReached(&door_delay, door_delay_value);
6350 if (door_state & DOOR_ACTION_1)
6351 door1 = door_state & DOOR_ACTION_1;
6352 if (door_state & DOOR_ACTION_2)
6353 door2 = door_state & DOOR_ACTION_2;
6355 return (door1 | door2);
6360 void DrawSpecialEditorDoor()
6363 struct GraphicInfo *gfx1 = &graphic_info[IMG_DOOR_2_TOP_BORDER_CORRECTION];
6364 int top_border_width = gfx1->width;
6365 int top_border_height = gfx1->height;
6366 int outer_border = viewport.door_2[GAME_MODE_EDITOR].border_size;
6367 int ex = EX - outer_border;
6368 int ey = EY - outer_border;
6369 int vy = VY - outer_border;
6370 int exsize = EXSIZE + 2 * outer_border;
6372 CloseDoor(DOOR_CLOSE_2);
6374 /* draw bigger level editor toolbox window */
6375 BlitBitmap(gfx1->bitmap, drawto, gfx1->src_x, gfx1->src_y,
6376 top_border_width, top_border_height, ex, ey - top_border_height);
6377 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto, ex, vy,
6378 exsize, EYSIZE - VYSIZE + outer_border, ex, ey);
6380 /* draw bigger level editor toolbox window */
6381 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
6382 DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
6384 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
6385 EX - 6, VY - 4, EXSIZE + 12, EYSIZE - VYSIZE + 4,
6389 redraw_mask |= REDRAW_ALL;
6392 void UndrawSpecialEditorDoor()
6395 struct GraphicInfo *gfx1 = &graphic_info[IMG_DOOR_2_TOP_BORDER_CORRECTION];
6396 int top_border_width = gfx1->width;
6397 int top_border_height = gfx1->height;
6398 int outer_border = viewport.door_2[GAME_MODE_EDITOR].border_size;
6399 int ex = EX - outer_border;
6400 int ey = EY - outer_border;
6401 int ey_top = ey - top_border_height;
6402 int exsize = EXSIZE + 2 * outer_border;
6403 int eysize = EYSIZE + 2 * outer_border;
6405 /* draw normal tape recorder window */
6406 if (graphic_info[IMG_GLOBAL_BORDER].bitmap)
6408 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
6409 ex, ey_top, top_border_width, top_border_height,
6411 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
6412 ex, ey, exsize, eysize, ex, ey);
6416 // if screen background is set to "[NONE]", clear editor toolbox window
6417 ClearRectangle(drawto, ex, ey_top, top_border_width, top_border_height);
6418 ClearRectangle(drawto, ex, ey, exsize, eysize);
6421 /* draw normal tape recorder window */
6422 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
6423 EX - 6, EY - 12, EXSIZE + 12, EYSIZE - VYSIZE + 12,
6427 redraw_mask |= REDRAW_ALL;
6431 /* ---------- new tool button stuff ---------------------------------------- */
6438 struct TextPosInfo *pos;
6441 } toolbutton_info[NUM_TOOL_BUTTONS] =
6444 IMG_REQUEST_BUTTON_GFX_YES, &request.button.yes,
6445 TOOL_CTRL_ID_YES, "yes"
6448 IMG_REQUEST_BUTTON_GFX_NO, &request.button.no,
6449 TOOL_CTRL_ID_NO, "no"
6452 IMG_REQUEST_BUTTON_GFX_CONFIRM, &request.button.confirm,
6453 TOOL_CTRL_ID_CONFIRM, "confirm"
6456 IMG_REQUEST_BUTTON_GFX_PLAYER_1, &request.button.player_1,
6457 TOOL_CTRL_ID_PLAYER_1, "player 1"
6460 IMG_REQUEST_BUTTON_GFX_PLAYER_2, &request.button.player_2,
6461 TOOL_CTRL_ID_PLAYER_2, "player 2"
6464 IMG_REQUEST_BUTTON_GFX_PLAYER_3, &request.button.player_3,
6465 TOOL_CTRL_ID_PLAYER_3, "player 3"
6468 IMG_REQUEST_BUTTON_GFX_PLAYER_4, &request.button.player_4,
6469 TOOL_CTRL_ID_PLAYER_4, "player 4"
6473 void CreateToolButtons()
6477 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
6479 struct GraphicInfo *gfx = &graphic_info[toolbutton_info[i].graphic];
6480 struct TextPosInfo *pos = toolbutton_info[i].pos;
6481 struct GadgetInfo *gi;
6482 Bitmap *deco_bitmap = None;
6483 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
6484 unsigned int event_mask = GD_EVENT_RELEASED;
6487 int gd_x = gfx->src_x;
6488 int gd_y = gfx->src_y;
6489 int gd_xp = gfx->src_x + gfx->pressed_xoffset;
6490 int gd_yp = gfx->src_y + gfx->pressed_yoffset;
6493 if (global.use_envelope_request)
6494 setRequestPosition(&dx, &dy, TRUE);
6496 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
6498 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
6500 getSizedGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr), 0,
6501 pos->size, &deco_bitmap, &deco_x, &deco_y);
6502 deco_xpos = (gfx->width - pos->size) / 2;
6503 deco_ypos = (gfx->height - pos->size) / 2;
6506 gi = CreateGadget(GDI_CUSTOM_ID, id,
6507 GDI_INFO_TEXT, toolbutton_info[i].infotext,
6510 GDI_WIDTH, gfx->width,
6511 GDI_HEIGHT, gfx->height,
6512 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
6513 GDI_STATE, GD_BUTTON_UNPRESSED,
6514 GDI_DESIGN_UNPRESSED, gfx->bitmap, gd_x, gd_y,
6515 GDI_DESIGN_PRESSED, gfx->bitmap, gd_xp, gd_yp,
6516 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
6517 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
6518 GDI_DECORATION_SIZE, pos->size, pos->size,
6519 GDI_DECORATION_SHIFTING, 1, 1,
6520 GDI_DIRECT_DRAW, FALSE,
6521 GDI_EVENT_MASK, event_mask,
6522 GDI_CALLBACK_ACTION, HandleToolButtons,
6526 Error(ERR_EXIT, "cannot create gadget");
6528 tool_gadget[id] = gi;
6534 /* graphic position values for tool buttons */
6535 #define TOOL_BUTTON_YES_XPOS 2
6536 #define TOOL_BUTTON_YES_YPOS 250
6537 #define TOOL_BUTTON_YES_GFX_YPOS 0
6538 #define TOOL_BUTTON_YES_XSIZE 46
6539 #define TOOL_BUTTON_YES_YSIZE 28
6540 #define TOOL_BUTTON_NO_XPOS 52
6541 #define TOOL_BUTTON_NO_YPOS TOOL_BUTTON_YES_YPOS
6542 #define TOOL_BUTTON_NO_GFX_YPOS TOOL_BUTTON_YES_GFX_YPOS
6543 #define TOOL_BUTTON_NO_XSIZE TOOL_BUTTON_YES_XSIZE
6544 #define TOOL_BUTTON_NO_YSIZE TOOL_BUTTON_YES_YSIZE
6545 #define TOOL_BUTTON_CONFIRM_XPOS TOOL_BUTTON_YES_XPOS
6546 #define TOOL_BUTTON_CONFIRM_YPOS TOOL_BUTTON_YES_YPOS
6547 #define TOOL_BUTTON_CONFIRM_GFX_YPOS 30
6548 #define TOOL_BUTTON_CONFIRM_XSIZE 96
6549 #define TOOL_BUTTON_CONFIRM_YSIZE TOOL_BUTTON_YES_YSIZE
6550 #define TOOL_BUTTON_PLAYER_XSIZE 30
6551 #define TOOL_BUTTON_PLAYER_YSIZE 30
6552 #define TOOL_BUTTON_PLAYER_GFX_XPOS 5
6553 #define TOOL_BUTTON_PLAYER_GFX_YPOS 185
6554 #define TOOL_BUTTON_PLAYER_XPOS (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
6555 #define TOOL_BUTTON_PLAYER_YPOS (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
6556 #define TOOL_BUTTON_PLAYER1_XPOS (TOOL_BUTTON_PLAYER_XPOS \
6557 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
6558 #define TOOL_BUTTON_PLAYER2_XPOS (TOOL_BUTTON_PLAYER_XPOS \
6559 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
6560 #define TOOL_BUTTON_PLAYER3_XPOS (TOOL_BUTTON_PLAYER_XPOS \
6561 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
6562 #define TOOL_BUTTON_PLAYER4_XPOS (TOOL_BUTTON_PLAYER_XPOS \
6563 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
6564 #define TOOL_BUTTON_PLAYER1_YPOS (TOOL_BUTTON_PLAYER_YPOS \
6565 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
6566 #define TOOL_BUTTON_PLAYER2_YPOS (TOOL_BUTTON_PLAYER_YPOS \
6567 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
6568 #define TOOL_BUTTON_PLAYER3_YPOS (TOOL_BUTTON_PLAYER_YPOS \
6569 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
6570 #define TOOL_BUTTON_PLAYER4_YPOS (TOOL_BUTTON_PLAYER_YPOS \
6571 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
6580 } toolbutton_info[NUM_TOOL_BUTTONS] =
6583 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_GFX_YPOS,
6584 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_YPOS,
6585 TOOL_BUTTON_YES_XSIZE, TOOL_BUTTON_YES_YSIZE,
6590 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_GFX_YPOS,
6591 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_YPOS,
6592 TOOL_BUTTON_NO_XSIZE, TOOL_BUTTON_NO_YSIZE,
6597 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_GFX_YPOS,
6598 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_YPOS,
6599 TOOL_BUTTON_CONFIRM_XSIZE, TOOL_BUTTON_CONFIRM_YSIZE,
6600 TOOL_CTRL_ID_CONFIRM,
6604 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
6605 TOOL_BUTTON_PLAYER1_XPOS, TOOL_BUTTON_PLAYER1_YPOS,
6606 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
6607 TOOL_CTRL_ID_PLAYER_1,
6611 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
6612 TOOL_BUTTON_PLAYER2_XPOS, TOOL_BUTTON_PLAYER2_YPOS,
6613 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
6614 TOOL_CTRL_ID_PLAYER_2,
6618 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
6619 TOOL_BUTTON_PLAYER3_XPOS, TOOL_BUTTON_PLAYER3_YPOS,
6620 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
6621 TOOL_CTRL_ID_PLAYER_3,
6625 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
6626 TOOL_BUTTON_PLAYER4_XPOS, TOOL_BUTTON_PLAYER4_YPOS,
6627 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
6628 TOOL_CTRL_ID_PLAYER_4,
6633 void CreateToolButtons()
6637 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
6639 Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
6640 Bitmap *deco_bitmap = None;
6641 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
6642 struct GadgetInfo *gi;
6643 unsigned int event_mask;
6644 int gd_xoffset, gd_yoffset;
6645 int gd_x1, gd_x2, gd_y;
6648 event_mask = GD_EVENT_RELEASED;
6650 gd_xoffset = toolbutton_info[i].xpos;
6651 gd_yoffset = toolbutton_info[i].ypos;
6652 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
6653 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
6654 gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
6656 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
6658 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
6660 getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr),
6661 &deco_bitmap, &deco_x, &deco_y);
6662 deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
6663 deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
6666 gi = CreateGadget(GDI_CUSTOM_ID, id,
6667 GDI_INFO_TEXT, toolbutton_info[i].infotext,
6668 GDI_X, DX + toolbutton_info[i].x,
6669 GDI_Y, DY + toolbutton_info[i].y,
6670 GDI_WIDTH, toolbutton_info[i].width,
6671 GDI_HEIGHT, toolbutton_info[i].height,
6672 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
6673 GDI_STATE, GD_BUTTON_UNPRESSED,
6674 GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
6675 GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
6676 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
6677 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
6678 GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
6679 GDI_DECORATION_SHIFTING, 1, 1,
6680 GDI_DIRECT_DRAW, FALSE,
6681 GDI_EVENT_MASK, event_mask,
6682 GDI_CALLBACK_ACTION, HandleToolButtons,
6686 Error(ERR_EXIT, "cannot create gadget");
6688 tool_gadget[id] = gi;
6694 void FreeToolButtons()
6698 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
6699 FreeGadget(tool_gadget[i]);
6702 static void UnmapToolButtons()
6706 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
6707 UnmapGadget(tool_gadget[i]);
6710 static void HandleToolButtons(struct GadgetInfo *gi)
6712 request_gadget_id = gi->custom_id;
6715 static struct Mapping_EM_to_RND_object
6718 boolean is_rnd_to_em_mapping; /* unique mapping EM <-> RND */
6719 boolean is_backside; /* backside of moving element */
6725 em_object_mapping_list[] =
6728 Xblank, TRUE, FALSE,
6732 Yacid_splash_eB, FALSE, FALSE,
6733 EL_ACID_SPLASH_RIGHT, -1, -1
6736 Yacid_splash_wB, FALSE, FALSE,
6737 EL_ACID_SPLASH_LEFT, -1, -1
6740 #ifdef EM_ENGINE_BAD_ROLL
6742 Xstone_force_e, FALSE, FALSE,
6743 EL_ROCK, -1, MV_BIT_RIGHT
6746 Xstone_force_w, FALSE, FALSE,
6747 EL_ROCK, -1, MV_BIT_LEFT
6750 Xnut_force_e, FALSE, FALSE,
6751 EL_NUT, -1, MV_BIT_RIGHT
6754 Xnut_force_w, FALSE, FALSE,
6755 EL_NUT, -1, MV_BIT_LEFT
6758 Xspring_force_e, FALSE, FALSE,
6759 EL_SPRING, -1, MV_BIT_RIGHT
6762 Xspring_force_w, FALSE, FALSE,
6763 EL_SPRING, -1, MV_BIT_LEFT
6766 Xemerald_force_e, FALSE, FALSE,
6767 EL_EMERALD, -1, MV_BIT_RIGHT
6770 Xemerald_force_w, FALSE, FALSE,
6771 EL_EMERALD, -1, MV_BIT_LEFT
6774 Xdiamond_force_e, FALSE, FALSE,
6775 EL_DIAMOND, -1, MV_BIT_RIGHT
6778 Xdiamond_force_w, FALSE, FALSE,
6779 EL_DIAMOND, -1, MV_BIT_LEFT
6782 Xbomb_force_e, FALSE, FALSE,
6783 EL_BOMB, -1, MV_BIT_RIGHT
6786 Xbomb_force_w, FALSE, FALSE,
6787 EL_BOMB, -1, MV_BIT_LEFT
6789 #endif /* EM_ENGINE_BAD_ROLL */
6792 Xstone, TRUE, FALSE,
6796 Xstone_pause, FALSE, FALSE,
6800 Xstone_fall, FALSE, FALSE,
6804 Ystone_s, FALSE, FALSE,
6805 EL_ROCK, ACTION_FALLING, -1
6808 Ystone_sB, FALSE, TRUE,
6809 EL_ROCK, ACTION_FALLING, -1
6812 Ystone_e, FALSE, FALSE,
6813 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
6816 Ystone_eB, FALSE, TRUE,
6817 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
6820 Ystone_w, FALSE, FALSE,
6821 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
6824 Ystone_wB, FALSE, TRUE,
6825 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
6832 Xnut_pause, FALSE, FALSE,
6836 Xnut_fall, FALSE, FALSE,
6840 Ynut_s, FALSE, FALSE,
6841 EL_NUT, ACTION_FALLING, -1
6844 Ynut_sB, FALSE, TRUE,
6845 EL_NUT, ACTION_FALLING, -1
6848 Ynut_e, FALSE, FALSE,
6849 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
6852 Ynut_eB, FALSE, TRUE,
6853 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
6856 Ynut_w, FALSE, FALSE,
6857 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
6860 Ynut_wB, FALSE, TRUE,
6861 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
6864 Xbug_n, TRUE, FALSE,
6868 Xbug_e, TRUE, FALSE,
6869 EL_BUG_RIGHT, -1, -1
6872 Xbug_s, TRUE, FALSE,
6876 Xbug_w, TRUE, FALSE,
6880 Xbug_gon, FALSE, FALSE,
6884 Xbug_goe, FALSE, FALSE,
6885 EL_BUG_RIGHT, -1, -1
6888 Xbug_gos, FALSE, FALSE,
6892 Xbug_gow, FALSE, FALSE,
6896 Ybug_n, FALSE, FALSE,
6897 EL_BUG, ACTION_MOVING, MV_BIT_UP
6900 Ybug_nB, FALSE, TRUE,
6901 EL_BUG, ACTION_MOVING, MV_BIT_UP
6904 Ybug_e, FALSE, FALSE,
6905 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
6908 Ybug_eB, FALSE, TRUE,
6909 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
6912 Ybug_s, FALSE, FALSE,
6913 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
6916 Ybug_sB, FALSE, TRUE,
6917 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
6920 Ybug_w, FALSE, FALSE,
6921 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
6924 Ybug_wB, FALSE, TRUE,
6925 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
6928 Ybug_w_n, FALSE, FALSE,
6929 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
6932 Ybug_n_e, FALSE, FALSE,
6933 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
6936 Ybug_e_s, FALSE, FALSE,
6937 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
6940 Ybug_s_w, FALSE, FALSE,
6941 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
6944 Ybug_e_n, FALSE, FALSE,
6945 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
6948 Ybug_s_e, FALSE, FALSE,
6949 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
6952 Ybug_w_s, FALSE, FALSE,
6953 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
6956 Ybug_n_w, FALSE, FALSE,
6957 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
6960 Ybug_stone, FALSE, FALSE,
6961 EL_BUG, ACTION_SMASHED_BY_ROCK, -1
6964 Ybug_spring, FALSE, FALSE,
6965 EL_BUG, ACTION_SMASHED_BY_SPRING, -1
6968 Xtank_n, TRUE, FALSE,
6969 EL_SPACESHIP_UP, -1, -1
6972 Xtank_e, TRUE, FALSE,
6973 EL_SPACESHIP_RIGHT, -1, -1
6976 Xtank_s, TRUE, FALSE,
6977 EL_SPACESHIP_DOWN, -1, -1
6980 Xtank_w, TRUE, FALSE,
6981 EL_SPACESHIP_LEFT, -1, -1
6984 Xtank_gon, FALSE, FALSE,
6985 EL_SPACESHIP_UP, -1, -1
6988 Xtank_goe, FALSE, FALSE,
6989 EL_SPACESHIP_RIGHT, -1, -1
6992 Xtank_gos, FALSE, FALSE,
6993 EL_SPACESHIP_DOWN, -1, -1
6996 Xtank_gow, FALSE, FALSE,
6997 EL_SPACESHIP_LEFT, -1, -1
7000 Ytank_n, FALSE, FALSE,
7001 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
7004 Ytank_nB, FALSE, TRUE,
7005 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
7008 Ytank_e, FALSE, FALSE,
7009 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
7012 Ytank_eB, FALSE, TRUE,
7013 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
7016 Ytank_s, FALSE, FALSE,
7017 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
7020 Ytank_sB, FALSE, TRUE,
7021 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
7024 Ytank_w, FALSE, FALSE,
7025 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
7028 Ytank_wB, FALSE, TRUE,
7029 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
7032 Ytank_w_n, FALSE, FALSE,
7033 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
7036 Ytank_n_e, FALSE, FALSE,
7037 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
7040 Ytank_e_s, FALSE, FALSE,
7041 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
7044 Ytank_s_w, FALSE, FALSE,
7045 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
7048 Ytank_e_n, FALSE, FALSE,
7049 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
7052 Ytank_s_e, FALSE, FALSE,
7053 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
7056 Ytank_w_s, FALSE, FALSE,
7057 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
7060 Ytank_n_w, FALSE, FALSE,
7061 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
7064 Ytank_stone, FALSE, FALSE,
7065 EL_SPACESHIP, ACTION_SMASHED_BY_ROCK, -1
7068 Ytank_spring, FALSE, FALSE,
7069 EL_SPACESHIP, ACTION_SMASHED_BY_SPRING, -1
7072 Xandroid, TRUE, FALSE,
7073 EL_EMC_ANDROID, ACTION_ACTIVE, -1
7076 Xandroid_1_n, FALSE, FALSE,
7077 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
7080 Xandroid_2_n, FALSE, FALSE,
7081 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
7084 Xandroid_1_e, FALSE, FALSE,
7085 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
7088 Xandroid_2_e, FALSE, FALSE,
7089 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
7092 Xandroid_1_w, FALSE, FALSE,
7093 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
7096 Xandroid_2_w, FALSE, FALSE,
7097 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
7100 Xandroid_1_s, FALSE, FALSE,
7101 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
7104 Xandroid_2_s, FALSE, FALSE,
7105 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
7108 Yandroid_n, FALSE, FALSE,
7109 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
7112 Yandroid_nB, FALSE, TRUE,
7113 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
7116 Yandroid_ne, FALSE, FALSE,
7117 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPRIGHT
7120 Yandroid_neB, FALSE, TRUE,
7121 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPRIGHT
7124 Yandroid_e, FALSE, FALSE,
7125 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
7128 Yandroid_eB, FALSE, TRUE,
7129 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
7132 Yandroid_se, FALSE, FALSE,
7133 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNRIGHT
7136 Yandroid_seB, FALSE, TRUE,
7137 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNRIGHT
7140 Yandroid_s, FALSE, FALSE,
7141 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
7144 Yandroid_sB, FALSE, TRUE,
7145 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
7148 Yandroid_sw, FALSE, FALSE,
7149 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNLEFT
7152 Yandroid_swB, FALSE, TRUE,
7153 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNLEFT
7156 Yandroid_w, FALSE, FALSE,
7157 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
7160 Yandroid_wB, FALSE, TRUE,
7161 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
7164 Yandroid_nw, FALSE, FALSE,
7165 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPLEFT
7168 Yandroid_nwB, FALSE, TRUE,
7169 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPLEFT
7172 Xspring, TRUE, FALSE,
7176 Xspring_pause, FALSE, FALSE,
7180 Xspring_e, FALSE, FALSE,
7184 Xspring_w, FALSE, FALSE,
7188 Xspring_fall, FALSE, FALSE,
7192 Yspring_s, FALSE, FALSE,
7193 EL_SPRING, ACTION_FALLING, -1
7196 Yspring_sB, FALSE, TRUE,
7197 EL_SPRING, ACTION_FALLING, -1
7200 Yspring_e, FALSE, FALSE,
7201 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
7204 Yspring_eB, FALSE, TRUE,
7205 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
7208 Yspring_w, FALSE, FALSE,
7209 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
7212 Yspring_wB, FALSE, TRUE,
7213 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
7216 Yspring_kill_e, FALSE, FALSE,
7217 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
7220 Yspring_kill_eB, FALSE, TRUE,
7221 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
7224 Yspring_kill_w, FALSE, FALSE,
7225 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
7228 Yspring_kill_wB, FALSE, TRUE,
7229 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
7232 Xeater_n, TRUE, FALSE,
7233 EL_YAMYAM_UP, -1, -1
7236 Xeater_e, TRUE, FALSE,
7237 EL_YAMYAM_RIGHT, -1, -1
7240 Xeater_w, TRUE, FALSE,
7241 EL_YAMYAM_LEFT, -1, -1
7244 Xeater_s, TRUE, FALSE,
7245 EL_YAMYAM_DOWN, -1, -1
7248 Yeater_n, FALSE, FALSE,
7249 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
7252 Yeater_nB, FALSE, TRUE,
7253 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
7256 Yeater_e, FALSE, FALSE,
7257 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
7260 Yeater_eB, FALSE, TRUE,
7261 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
7264 Yeater_s, FALSE, FALSE,
7265 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
7268 Yeater_sB, FALSE, TRUE,
7269 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
7272 Yeater_w, FALSE, FALSE,
7273 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
7276 Yeater_wB, FALSE, TRUE,
7277 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
7280 Yeater_stone, FALSE, FALSE,
7281 EL_YAMYAM, ACTION_SMASHED_BY_ROCK, -1
7284 Yeater_spring, FALSE, FALSE,
7285 EL_YAMYAM, ACTION_SMASHED_BY_SPRING, -1
7288 Xalien, TRUE, FALSE,
7292 Xalien_pause, FALSE, FALSE,
7296 Yalien_n, FALSE, FALSE,
7297 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
7300 Yalien_nB, FALSE, TRUE,
7301 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
7304 Yalien_e, FALSE, FALSE,
7305 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
7308 Yalien_eB, FALSE, TRUE,
7309 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
7312 Yalien_s, FALSE, FALSE,
7313 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
7316 Yalien_sB, FALSE, TRUE,
7317 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
7320 Yalien_w, FALSE, FALSE,
7321 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
7324 Yalien_wB, FALSE, TRUE,
7325 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
7328 Yalien_stone, FALSE, FALSE,
7329 EL_ROBOT, ACTION_SMASHED_BY_ROCK, -1
7332 Yalien_spring, FALSE, FALSE,
7333 EL_ROBOT, ACTION_SMASHED_BY_SPRING, -1
7336 Xemerald, TRUE, FALSE,
7340 Xemerald_pause, FALSE, FALSE,
7344 Xemerald_fall, FALSE, FALSE,
7348 Xemerald_shine, FALSE, FALSE,
7349 EL_EMERALD, ACTION_TWINKLING, -1
7352 Yemerald_s, FALSE, FALSE,
7353 EL_EMERALD, ACTION_FALLING, -1
7356 Yemerald_sB, FALSE, TRUE,
7357 EL_EMERALD, ACTION_FALLING, -1
7360 Yemerald_e, FALSE, FALSE,
7361 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
7364 Yemerald_eB, FALSE, TRUE,
7365 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
7368 Yemerald_w, FALSE, FALSE,
7369 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
7372 Yemerald_wB, FALSE, TRUE,
7373 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
7376 Yemerald_eat, FALSE, FALSE,
7377 EL_EMERALD, ACTION_COLLECTING, -1
7380 Yemerald_stone, FALSE, FALSE,
7381 EL_NUT, ACTION_BREAKING, -1
7384 Xdiamond, TRUE, FALSE,
7388 Xdiamond_pause, FALSE, FALSE,
7392 Xdiamond_fall, FALSE, FALSE,
7396 Xdiamond_shine, FALSE, FALSE,
7397 EL_DIAMOND, ACTION_TWINKLING, -1
7400 Ydiamond_s, FALSE, FALSE,
7401 EL_DIAMOND, ACTION_FALLING, -1
7404 Ydiamond_sB, FALSE, TRUE,
7405 EL_DIAMOND, ACTION_FALLING, -1
7408 Ydiamond_e, FALSE, FALSE,
7409 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
7412 Ydiamond_eB, FALSE, TRUE,
7413 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
7416 Ydiamond_w, FALSE, FALSE,
7417 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
7420 Ydiamond_wB, FALSE, TRUE,
7421 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
7424 Ydiamond_eat, FALSE, FALSE,
7425 EL_DIAMOND, ACTION_COLLECTING, -1
7428 Ydiamond_stone, FALSE, FALSE,
7429 EL_DIAMOND, ACTION_SMASHED_BY_ROCK, -1
7432 Xdrip_fall, TRUE, FALSE,
7433 EL_AMOEBA_DROP, -1, -1
7436 Xdrip_stretch, FALSE, FALSE,
7437 EL_AMOEBA_DROP, ACTION_FALLING, -1
7440 Xdrip_stretchB, FALSE, TRUE,
7441 EL_AMOEBA_DROP, ACTION_FALLING, -1
7444 Xdrip_eat, FALSE, FALSE,
7445 EL_AMOEBA_DROP, ACTION_GROWING, -1
7448 Ydrip_s1, FALSE, FALSE,
7449 EL_AMOEBA_DROP, ACTION_FALLING, -1
7452 Ydrip_s1B, FALSE, TRUE,
7453 EL_AMOEBA_DROP, ACTION_FALLING, -1
7456 Ydrip_s2, FALSE, FALSE,
7457 EL_AMOEBA_DROP, ACTION_FALLING, -1
7460 Ydrip_s2B, FALSE, TRUE,
7461 EL_AMOEBA_DROP, ACTION_FALLING, -1
7468 Xbomb_pause, FALSE, FALSE,
7472 Xbomb_fall, FALSE, FALSE,
7476 Ybomb_s, FALSE, FALSE,
7477 EL_BOMB, ACTION_FALLING, -1
7480 Ybomb_sB, FALSE, TRUE,
7481 EL_BOMB, ACTION_FALLING, -1
7484 Ybomb_e, FALSE, FALSE,
7485 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
7488 Ybomb_eB, FALSE, TRUE,
7489 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
7492 Ybomb_w, FALSE, FALSE,
7493 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
7496 Ybomb_wB, FALSE, TRUE,
7497 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
7500 Ybomb_eat, FALSE, FALSE,
7501 EL_BOMB, ACTION_ACTIVATING, -1
7504 Xballoon, TRUE, FALSE,
7508 Yballoon_n, FALSE, FALSE,
7509 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
7512 Yballoon_nB, FALSE, TRUE,
7513 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
7516 Yballoon_e, FALSE, FALSE,
7517 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
7520 Yballoon_eB, FALSE, TRUE,
7521 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
7524 Yballoon_s, FALSE, FALSE,
7525 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
7528 Yballoon_sB, FALSE, TRUE,
7529 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
7532 Yballoon_w, FALSE, FALSE,
7533 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
7536 Yballoon_wB, FALSE, TRUE,
7537 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
7540 Xgrass, TRUE, FALSE,
7541 EL_EMC_GRASS, -1, -1
7544 Ygrass_nB, FALSE, FALSE,
7545 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_UP
7548 Ygrass_eB, FALSE, FALSE,
7549 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_RIGHT
7552 Ygrass_sB, FALSE, FALSE,
7553 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_DOWN
7556 Ygrass_wB, FALSE, FALSE,
7557 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_LEFT
7564 Ydirt_nB, FALSE, FALSE,
7565 EL_SAND, ACTION_DIGGING, MV_BIT_UP
7568 Ydirt_eB, FALSE, FALSE,
7569 EL_SAND, ACTION_DIGGING, MV_BIT_RIGHT
7572 Ydirt_sB, FALSE, FALSE,
7573 EL_SAND, ACTION_DIGGING, MV_BIT_DOWN
7576 Ydirt_wB, FALSE, FALSE,
7577 EL_SAND, ACTION_DIGGING, MV_BIT_LEFT
7580 Xacid_ne, TRUE, FALSE,
7581 EL_ACID_POOL_TOPRIGHT, -1, -1
7584 Xacid_se, TRUE, FALSE,
7585 EL_ACID_POOL_BOTTOMRIGHT, -1, -1
7588 Xacid_s, TRUE, FALSE,
7589 EL_ACID_POOL_BOTTOM, -1, -1
7592 Xacid_sw, TRUE, FALSE,
7593 EL_ACID_POOL_BOTTOMLEFT, -1, -1
7596 Xacid_nw, TRUE, FALSE,
7597 EL_ACID_POOL_TOPLEFT, -1, -1
7600 Xacid_1, TRUE, FALSE,
7604 Xacid_2, FALSE, FALSE,
7608 Xacid_3, FALSE, FALSE,
7612 Xacid_4, FALSE, FALSE,
7616 Xacid_5, FALSE, FALSE,
7620 Xacid_6, FALSE, FALSE,
7624 Xacid_7, FALSE, FALSE,
7628 Xacid_8, FALSE, FALSE,
7632 Xball_1, TRUE, FALSE,
7633 EL_EMC_MAGIC_BALL, -1, -1
7636 Xball_1B, FALSE, FALSE,
7637 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
7640 Xball_2, FALSE, FALSE,
7641 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
7644 Xball_2B, FALSE, FALSE,
7645 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
7648 Yball_eat, FALSE, FALSE,
7649 EL_EMC_MAGIC_BALL, ACTION_DROPPING, -1
7652 Ykey_1_eat, FALSE, FALSE,
7653 EL_EM_KEY_1, ACTION_COLLECTING, -1
7656 Ykey_2_eat, FALSE, FALSE,
7657 EL_EM_KEY_2, ACTION_COLLECTING, -1
7660 Ykey_3_eat, FALSE, FALSE,
7661 EL_EM_KEY_3, ACTION_COLLECTING, -1
7664 Ykey_4_eat, FALSE, FALSE,
7665 EL_EM_KEY_4, ACTION_COLLECTING, -1
7668 Ykey_5_eat, FALSE, FALSE,
7669 EL_EMC_KEY_5, ACTION_COLLECTING, -1
7672 Ykey_6_eat, FALSE, FALSE,
7673 EL_EMC_KEY_6, ACTION_COLLECTING, -1
7676 Ykey_7_eat, FALSE, FALSE,
7677 EL_EMC_KEY_7, ACTION_COLLECTING, -1
7680 Ykey_8_eat, FALSE, FALSE,
7681 EL_EMC_KEY_8, ACTION_COLLECTING, -1
7684 Ylenses_eat, FALSE, FALSE,
7685 EL_EMC_LENSES, ACTION_COLLECTING, -1
7688 Ymagnify_eat, FALSE, FALSE,
7689 EL_EMC_MAGNIFIER, ACTION_COLLECTING, -1
7692 Ygrass_eat, FALSE, FALSE,
7693 EL_EMC_GRASS, ACTION_SNAPPING, -1
7696 Ydirt_eat, FALSE, FALSE,
7697 EL_SAND, ACTION_SNAPPING, -1
7700 Xgrow_ns, TRUE, FALSE,
7701 EL_EXPANDABLE_WALL_VERTICAL, -1, -1
7704 Ygrow_ns_eat, FALSE, FALSE,
7705 EL_EXPANDABLE_WALL_VERTICAL, ACTION_GROWING, -1
7708 Xgrow_ew, TRUE, FALSE,
7709 EL_EXPANDABLE_WALL_HORIZONTAL, -1, -1
7712 Ygrow_ew_eat, FALSE, FALSE,
7713 EL_EXPANDABLE_WALL_HORIZONTAL, ACTION_GROWING, -1
7716 Xwonderwall, TRUE, FALSE,
7717 EL_MAGIC_WALL, -1, -1
7720 XwonderwallB, FALSE, FALSE,
7721 EL_MAGIC_WALL, ACTION_ACTIVE, -1
7724 Xamoeba_1, TRUE, FALSE,
7725 EL_AMOEBA_DRY, ACTION_OTHER, -1
7728 Xamoeba_2, FALSE, FALSE,
7729 EL_AMOEBA_DRY, ACTION_OTHER, -1
7732 Xamoeba_3, FALSE, FALSE,
7733 EL_AMOEBA_DRY, ACTION_OTHER, -1
7736 Xamoeba_4, FALSE, FALSE,
7737 EL_AMOEBA_DRY, ACTION_OTHER, -1
7740 Xamoeba_5, TRUE, FALSE,
7741 EL_AMOEBA_WET, ACTION_OTHER, -1
7744 Xamoeba_6, FALSE, FALSE,
7745 EL_AMOEBA_WET, ACTION_OTHER, -1
7748 Xamoeba_7, FALSE, FALSE,
7749 EL_AMOEBA_WET, ACTION_OTHER, -1
7752 Xamoeba_8, FALSE, FALSE,
7753 EL_AMOEBA_WET, ACTION_OTHER, -1
7756 Xdoor_1, TRUE, FALSE,
7757 EL_EM_GATE_1, -1, -1
7760 Xdoor_2, TRUE, FALSE,
7761 EL_EM_GATE_2, -1, -1
7764 Xdoor_3, TRUE, FALSE,
7765 EL_EM_GATE_3, -1, -1
7768 Xdoor_4, TRUE, FALSE,
7769 EL_EM_GATE_4, -1, -1
7772 Xdoor_5, TRUE, FALSE,
7773 EL_EMC_GATE_5, -1, -1
7776 Xdoor_6, TRUE, FALSE,
7777 EL_EMC_GATE_6, -1, -1
7780 Xdoor_7, TRUE, FALSE,
7781 EL_EMC_GATE_7, -1, -1
7784 Xdoor_8, TRUE, FALSE,
7785 EL_EMC_GATE_8, -1, -1
7788 Xkey_1, TRUE, FALSE,
7792 Xkey_2, TRUE, FALSE,
7796 Xkey_3, TRUE, FALSE,
7800 Xkey_4, TRUE, FALSE,
7804 Xkey_5, TRUE, FALSE,
7805 EL_EMC_KEY_5, -1, -1
7808 Xkey_6, TRUE, FALSE,
7809 EL_EMC_KEY_6, -1, -1
7812 Xkey_7, TRUE, FALSE,
7813 EL_EMC_KEY_7, -1, -1
7816 Xkey_8, TRUE, FALSE,
7817 EL_EMC_KEY_8, -1, -1
7820 Xwind_n, TRUE, FALSE,
7821 EL_BALLOON_SWITCH_UP, -1, -1
7824 Xwind_e, TRUE, FALSE,
7825 EL_BALLOON_SWITCH_RIGHT, -1, -1
7828 Xwind_s, TRUE, FALSE,
7829 EL_BALLOON_SWITCH_DOWN, -1, -1
7832 Xwind_w, TRUE, FALSE,
7833 EL_BALLOON_SWITCH_LEFT, -1, -1
7836 Xwind_nesw, TRUE, FALSE,
7837 EL_BALLOON_SWITCH_ANY, -1, -1
7840 Xwind_stop, TRUE, FALSE,
7841 EL_BALLOON_SWITCH_NONE, -1, -1
7845 EL_EM_EXIT_CLOSED, -1, -1
7848 Xexit_1, TRUE, FALSE,
7849 EL_EM_EXIT_OPEN, -1, -1
7852 Xexit_2, FALSE, FALSE,
7853 EL_EM_EXIT_OPEN, -1, -1
7856 Xexit_3, FALSE, FALSE,
7857 EL_EM_EXIT_OPEN, -1, -1
7860 Xdynamite, TRUE, FALSE,
7861 EL_EM_DYNAMITE, -1, -1
7864 Ydynamite_eat, FALSE, FALSE,
7865 EL_EM_DYNAMITE, ACTION_COLLECTING, -1
7868 Xdynamite_1, TRUE, FALSE,
7869 EL_EM_DYNAMITE_ACTIVE, -1, -1
7872 Xdynamite_2, FALSE, FALSE,
7873 EL_EM_DYNAMITE_ACTIVE, -1, -1
7876 Xdynamite_3, FALSE, FALSE,
7877 EL_EM_DYNAMITE_ACTIVE, -1, -1
7880 Xdynamite_4, FALSE, FALSE,
7881 EL_EM_DYNAMITE_ACTIVE, -1, -1
7884 Xbumper, TRUE, FALSE,
7885 EL_EMC_SPRING_BUMPER, -1, -1
7888 XbumperB, FALSE, FALSE,
7889 EL_EMC_SPRING_BUMPER, ACTION_ACTIVE, -1
7892 Xwheel, TRUE, FALSE,
7893 EL_ROBOT_WHEEL, -1, -1
7896 XwheelB, FALSE, FALSE,
7897 EL_ROBOT_WHEEL, ACTION_ACTIVE, -1
7900 Xswitch, TRUE, FALSE,
7901 EL_EMC_MAGIC_BALL_SWITCH, -1, -1
7904 XswitchB, FALSE, FALSE,
7905 EL_EMC_MAGIC_BALL_SWITCH, ACTION_ACTIVE, -1
7909 EL_QUICKSAND_EMPTY, -1, -1
7912 Xsand_stone, TRUE, FALSE,
7913 EL_QUICKSAND_FULL, -1, -1
7916 Xsand_stonein_1, FALSE, TRUE,
7917 EL_ROCK, ACTION_FILLING, -1
7920 Xsand_stonein_2, FALSE, TRUE,
7921 EL_ROCK, ACTION_FILLING, -1
7924 Xsand_stonein_3, FALSE, TRUE,
7925 EL_ROCK, ACTION_FILLING, -1
7928 Xsand_stonein_4, FALSE, TRUE,
7929 EL_ROCK, ACTION_FILLING, -1
7933 Xsand_stonesand_1, FALSE, FALSE,
7934 EL_QUICKSAND_EMPTYING, -1, -1
7937 Xsand_stonesand_2, FALSE, FALSE,
7938 EL_QUICKSAND_EMPTYING, -1, -1
7941 Xsand_stonesand_3, FALSE, FALSE,
7942 EL_QUICKSAND_EMPTYING, -1, -1
7945 Xsand_stonesand_4, FALSE, FALSE,
7946 EL_QUICKSAND_EMPTYING, -1, -1
7949 Xsand_stonesand_quickout_1, FALSE, FALSE,
7950 EL_QUICKSAND_EMPTYING, -1, -1
7953 Xsand_stonesand_quickout_2, FALSE, FALSE,
7954 EL_QUICKSAND_EMPTYING, -1, -1
7958 Xsand_stonesand_1, FALSE, FALSE,
7959 EL_QUICKSAND_FULL, -1, -1
7962 Xsand_stonesand_2, FALSE, FALSE,
7963 EL_QUICKSAND_FULL, -1, -1
7966 Xsand_stonesand_3, FALSE, FALSE,
7967 EL_QUICKSAND_FULL, -1, -1
7970 Xsand_stonesand_4, FALSE, FALSE,
7971 EL_QUICKSAND_FULL, -1, -1
7975 Xsand_stoneout_1, FALSE, FALSE,
7976 EL_ROCK, ACTION_EMPTYING, -1
7979 Xsand_stoneout_2, FALSE, FALSE,
7980 EL_ROCK, ACTION_EMPTYING, -1
7984 Xsand_sandstone_1, FALSE, FALSE,
7985 EL_QUICKSAND_FILLING, -1, -1
7988 Xsand_sandstone_2, FALSE, FALSE,
7989 EL_QUICKSAND_FILLING, -1, -1
7992 Xsand_sandstone_3, FALSE, FALSE,
7993 EL_QUICKSAND_FILLING, -1, -1
7996 Xsand_sandstone_4, FALSE, FALSE,
7997 EL_QUICKSAND_FILLING, -1, -1
8001 Xsand_sandstone_1, FALSE, FALSE,
8002 EL_QUICKSAND_FULL, -1, -1
8005 Xsand_sandstone_2, FALSE, FALSE,
8006 EL_QUICKSAND_FULL, -1, -1
8009 Xsand_sandstone_3, FALSE, FALSE,
8010 EL_QUICKSAND_FULL, -1, -1
8013 Xsand_sandstone_4, FALSE, FALSE,
8014 EL_QUICKSAND_FULL, -1, -1
8018 Xplant, TRUE, FALSE,
8019 EL_EMC_PLANT, -1, -1
8022 Yplant, FALSE, FALSE,
8023 EL_EMC_PLANT, -1, -1
8026 Xlenses, TRUE, FALSE,
8027 EL_EMC_LENSES, -1, -1
8030 Xmagnify, TRUE, FALSE,
8031 EL_EMC_MAGNIFIER, -1, -1
8034 Xdripper, TRUE, FALSE,
8035 EL_EMC_DRIPPER, -1, -1
8038 XdripperB, FALSE, FALSE,
8039 EL_EMC_DRIPPER, ACTION_ACTIVE, -1
8042 Xfake_blank, TRUE, FALSE,
8043 EL_INVISIBLE_WALL, -1, -1
8046 Xfake_blankB, FALSE, FALSE,
8047 EL_INVISIBLE_WALL, ACTION_ACTIVE, -1
8050 Xfake_grass, TRUE, FALSE,
8051 EL_EMC_FAKE_GRASS, -1, -1
8054 Xfake_grassB, FALSE, FALSE,
8055 EL_EMC_FAKE_GRASS, ACTION_ACTIVE, -1
8058 Xfake_door_1, TRUE, FALSE,
8059 EL_EM_GATE_1_GRAY, -1, -1
8062 Xfake_door_2, TRUE, FALSE,
8063 EL_EM_GATE_2_GRAY, -1, -1
8066 Xfake_door_3, TRUE, FALSE,
8067 EL_EM_GATE_3_GRAY, -1, -1
8070 Xfake_door_4, TRUE, FALSE,
8071 EL_EM_GATE_4_GRAY, -1, -1
8074 Xfake_door_5, TRUE, FALSE,
8075 EL_EMC_GATE_5_GRAY, -1, -1
8078 Xfake_door_6, TRUE, FALSE,
8079 EL_EMC_GATE_6_GRAY, -1, -1
8082 Xfake_door_7, TRUE, FALSE,
8083 EL_EMC_GATE_7_GRAY, -1, -1
8086 Xfake_door_8, TRUE, FALSE,
8087 EL_EMC_GATE_8_GRAY, -1, -1
8090 Xfake_acid_1, TRUE, FALSE,
8091 EL_EMC_FAKE_ACID, -1, -1
8094 Xfake_acid_2, FALSE, FALSE,
8095 EL_EMC_FAKE_ACID, -1, -1
8098 Xfake_acid_3, FALSE, FALSE,
8099 EL_EMC_FAKE_ACID, -1, -1
8102 Xfake_acid_4, FALSE, FALSE,
8103 EL_EMC_FAKE_ACID, -1, -1
8106 Xfake_acid_5, FALSE, FALSE,
8107 EL_EMC_FAKE_ACID, -1, -1
8110 Xfake_acid_6, FALSE, FALSE,
8111 EL_EMC_FAKE_ACID, -1, -1
8114 Xfake_acid_7, FALSE, FALSE,
8115 EL_EMC_FAKE_ACID, -1, -1
8118 Xfake_acid_8, FALSE, FALSE,
8119 EL_EMC_FAKE_ACID, -1, -1
8122 Xsteel_1, TRUE, FALSE,
8123 EL_STEELWALL, -1, -1
8126 Xsteel_2, TRUE, FALSE,
8127 EL_EMC_STEELWALL_2, -1, -1
8130 Xsteel_3, TRUE, FALSE,
8131 EL_EMC_STEELWALL_3, -1, -1
8134 Xsteel_4, TRUE, FALSE,
8135 EL_EMC_STEELWALL_4, -1, -1
8138 Xwall_1, TRUE, FALSE,
8142 Xwall_2, TRUE, FALSE,
8143 EL_EMC_WALL_14, -1, -1
8146 Xwall_3, TRUE, FALSE,
8147 EL_EMC_WALL_15, -1, -1
8150 Xwall_4, TRUE, FALSE,
8151 EL_EMC_WALL_16, -1, -1
8154 Xround_wall_1, TRUE, FALSE,
8155 EL_WALL_SLIPPERY, -1, -1
8158 Xround_wall_2, TRUE, FALSE,
8159 EL_EMC_WALL_SLIPPERY_2, -1, -1
8162 Xround_wall_3, TRUE, FALSE,
8163 EL_EMC_WALL_SLIPPERY_3, -1, -1
8166 Xround_wall_4, TRUE, FALSE,
8167 EL_EMC_WALL_SLIPPERY_4, -1, -1
8170 Xdecor_1, TRUE, FALSE,
8171 EL_EMC_WALL_8, -1, -1
8174 Xdecor_2, TRUE, FALSE,
8175 EL_EMC_WALL_6, -1, -1
8178 Xdecor_3, TRUE, FALSE,
8179 EL_EMC_WALL_4, -1, -1
8182 Xdecor_4, TRUE, FALSE,
8183 EL_EMC_WALL_7, -1, -1
8186 Xdecor_5, TRUE, FALSE,
8187 EL_EMC_WALL_5, -1, -1
8190 Xdecor_6, TRUE, FALSE,
8191 EL_EMC_WALL_9, -1, -1
8194 Xdecor_7, TRUE, FALSE,
8195 EL_EMC_WALL_10, -1, -1
8198 Xdecor_8, TRUE, FALSE,
8199 EL_EMC_WALL_1, -1, -1
8202 Xdecor_9, TRUE, FALSE,
8203 EL_EMC_WALL_2, -1, -1
8206 Xdecor_10, TRUE, FALSE,
8207 EL_EMC_WALL_3, -1, -1
8210 Xdecor_11, TRUE, FALSE,
8211 EL_EMC_WALL_11, -1, -1
8214 Xdecor_12, TRUE, FALSE,
8215 EL_EMC_WALL_12, -1, -1
8218 Xalpha_0, TRUE, FALSE,
8219 EL_CHAR('0'), -1, -1
8222 Xalpha_1, TRUE, FALSE,
8223 EL_CHAR('1'), -1, -1
8226 Xalpha_2, TRUE, FALSE,
8227 EL_CHAR('2'), -1, -1
8230 Xalpha_3, TRUE, FALSE,
8231 EL_CHAR('3'), -1, -1
8234 Xalpha_4, TRUE, FALSE,
8235 EL_CHAR('4'), -1, -1
8238 Xalpha_5, TRUE, FALSE,
8239 EL_CHAR('5'), -1, -1
8242 Xalpha_6, TRUE, FALSE,
8243 EL_CHAR('6'), -1, -1
8246 Xalpha_7, TRUE, FALSE,
8247 EL_CHAR('7'), -1, -1
8250 Xalpha_8, TRUE, FALSE,
8251 EL_CHAR('8'), -1, -1
8254 Xalpha_9, TRUE, FALSE,
8255 EL_CHAR('9'), -1, -1
8258 Xalpha_excla, TRUE, FALSE,
8259 EL_CHAR('!'), -1, -1
8262 Xalpha_quote, TRUE, FALSE,
8263 EL_CHAR('"'), -1, -1
8266 Xalpha_comma, TRUE, FALSE,
8267 EL_CHAR(','), -1, -1
8270 Xalpha_minus, TRUE, FALSE,
8271 EL_CHAR('-'), -1, -1
8274 Xalpha_perio, TRUE, FALSE,
8275 EL_CHAR('.'), -1, -1
8278 Xalpha_colon, TRUE, FALSE,
8279 EL_CHAR(':'), -1, -1
8282 Xalpha_quest, TRUE, FALSE,
8283 EL_CHAR('?'), -1, -1
8286 Xalpha_a, TRUE, FALSE,
8287 EL_CHAR('A'), -1, -1
8290 Xalpha_b, TRUE, FALSE,
8291 EL_CHAR('B'), -1, -1
8294 Xalpha_c, TRUE, FALSE,
8295 EL_CHAR('C'), -1, -1
8298 Xalpha_d, TRUE, FALSE,
8299 EL_CHAR('D'), -1, -1
8302 Xalpha_e, TRUE, FALSE,
8303 EL_CHAR('E'), -1, -1
8306 Xalpha_f, TRUE, FALSE,
8307 EL_CHAR('F'), -1, -1
8310 Xalpha_g, TRUE, FALSE,
8311 EL_CHAR('G'), -1, -1
8314 Xalpha_h, TRUE, FALSE,
8315 EL_CHAR('H'), -1, -1
8318 Xalpha_i, TRUE, FALSE,
8319 EL_CHAR('I'), -1, -1
8322 Xalpha_j, TRUE, FALSE,
8323 EL_CHAR('J'), -1, -1
8326 Xalpha_k, TRUE, FALSE,
8327 EL_CHAR('K'), -1, -1
8330 Xalpha_l, TRUE, FALSE,
8331 EL_CHAR('L'), -1, -1
8334 Xalpha_m, TRUE, FALSE,
8335 EL_CHAR('M'), -1, -1
8338 Xalpha_n, TRUE, FALSE,
8339 EL_CHAR('N'), -1, -1
8342 Xalpha_o, TRUE, FALSE,
8343 EL_CHAR('O'), -1, -1
8346 Xalpha_p, TRUE, FALSE,
8347 EL_CHAR('P'), -1, -1
8350 Xalpha_q, TRUE, FALSE,
8351 EL_CHAR('Q'), -1, -1
8354 Xalpha_r, TRUE, FALSE,
8355 EL_CHAR('R'), -1, -1
8358 Xalpha_s, TRUE, FALSE,
8359 EL_CHAR('S'), -1, -1
8362 Xalpha_t, TRUE, FALSE,
8363 EL_CHAR('T'), -1, -1
8366 Xalpha_u, TRUE, FALSE,
8367 EL_CHAR('U'), -1, -1
8370 Xalpha_v, TRUE, FALSE,
8371 EL_CHAR('V'), -1, -1
8374 Xalpha_w, TRUE, FALSE,
8375 EL_CHAR('W'), -1, -1
8378 Xalpha_x, TRUE, FALSE,
8379 EL_CHAR('X'), -1, -1
8382 Xalpha_y, TRUE, FALSE,
8383 EL_CHAR('Y'), -1, -1
8386 Xalpha_z, TRUE, FALSE,
8387 EL_CHAR('Z'), -1, -1
8390 Xalpha_arrow_e, TRUE, FALSE,
8391 EL_CHAR('>'), -1, -1
8394 Xalpha_arrow_w, TRUE, FALSE,
8395 EL_CHAR('<'), -1, -1
8398 Xalpha_copyr, TRUE, FALSE,
8399 EL_CHAR('©'), -1, -1
8403 Xboom_bug, FALSE, FALSE,
8404 EL_BUG, ACTION_EXPLODING, -1
8407 Xboom_bomb, FALSE, FALSE,
8408 EL_BOMB, ACTION_EXPLODING, -1
8411 Xboom_android, FALSE, FALSE,
8412 EL_EMC_ANDROID, ACTION_OTHER, -1
8415 Xboom_1, FALSE, FALSE,
8416 EL_DEFAULT, ACTION_EXPLODING, -1
8419 Xboom_2, FALSE, FALSE,
8420 EL_DEFAULT, ACTION_EXPLODING, -1
8423 Znormal, FALSE, FALSE,
8427 Zdynamite, FALSE, FALSE,
8431 Zplayer, FALSE, FALSE,
8435 ZBORDER, FALSE, FALSE,
8445 static struct Mapping_EM_to_RND_player
8454 em_player_mapping_list[] =
8458 EL_PLAYER_1, ACTION_MOVING, MV_BIT_UP,
8462 EL_PLAYER_1, ACTION_MOVING, MV_BIT_RIGHT,
8466 EL_PLAYER_1, ACTION_MOVING, MV_BIT_DOWN,
8470 EL_PLAYER_1, ACTION_MOVING, MV_BIT_LEFT,
8474 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_UP,
8478 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_RIGHT,
8482 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_DOWN,
8486 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_LEFT,
8490 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_UP,
8494 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_RIGHT,
8498 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_DOWN,
8502 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_LEFT,
8506 EL_PLAYER_2, ACTION_MOVING, MV_BIT_UP,
8510 EL_PLAYER_2, ACTION_MOVING, MV_BIT_RIGHT,
8514 EL_PLAYER_2, ACTION_MOVING, MV_BIT_DOWN,
8518 EL_PLAYER_2, ACTION_MOVING, MV_BIT_LEFT,
8522 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_UP,
8526 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_RIGHT,
8530 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_DOWN,
8534 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_LEFT,
8538 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_UP,
8542 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_RIGHT,
8546 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_DOWN,
8550 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_LEFT,
8554 EL_PLAYER_1, ACTION_DEFAULT, -1,
8558 EL_PLAYER_2, ACTION_DEFAULT, -1,
8562 EL_PLAYER_3, ACTION_MOVING, MV_BIT_UP,
8566 EL_PLAYER_3, ACTION_MOVING, MV_BIT_RIGHT,
8570 EL_PLAYER_3, ACTION_MOVING, MV_BIT_DOWN,
8574 EL_PLAYER_3, ACTION_MOVING, MV_BIT_LEFT,
8578 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_UP,
8582 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_RIGHT,
8586 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_DOWN,
8590 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_LEFT,
8594 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_UP,
8598 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_RIGHT,
8602 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_DOWN,
8606 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_LEFT,
8610 EL_PLAYER_4, ACTION_MOVING, MV_BIT_UP,
8614 EL_PLAYER_4, ACTION_MOVING, MV_BIT_RIGHT,
8618 EL_PLAYER_4, ACTION_MOVING, MV_BIT_DOWN,
8622 EL_PLAYER_4, ACTION_MOVING, MV_BIT_LEFT,
8626 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_UP,
8630 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_RIGHT,
8634 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_DOWN,
8638 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_LEFT,
8642 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_UP,
8646 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_RIGHT,
8650 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_DOWN,
8654 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_LEFT,
8658 EL_PLAYER_3, ACTION_DEFAULT, -1,
8662 EL_PLAYER_4, ACTION_DEFAULT, -1,
8671 int map_element_RND_to_EM(int element_rnd)
8673 static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
8674 static boolean mapping_initialized = FALSE;
8676 if (!mapping_initialized)
8680 /* return "Xalpha_quest" for all undefined elements in mapping array */
8681 for (i = 0; i < NUM_FILE_ELEMENTS; i++)
8682 mapping_RND_to_EM[i] = Xalpha_quest;
8684 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
8685 if (em_object_mapping_list[i].is_rnd_to_em_mapping)
8686 mapping_RND_to_EM[em_object_mapping_list[i].element_rnd] =
8687 em_object_mapping_list[i].element_em;
8689 mapping_initialized = TRUE;
8692 if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
8693 return mapping_RND_to_EM[element_rnd];
8695 Error(ERR_WARN, "invalid RND level element %d", element_rnd);
8700 int map_element_EM_to_RND(int element_em)
8702 static unsigned short mapping_EM_to_RND[TILE_MAX];
8703 static boolean mapping_initialized = FALSE;
8705 if (!mapping_initialized)
8709 /* return "EL_UNKNOWN" for all undefined elements in mapping array */
8710 for (i = 0; i < TILE_MAX; i++)
8711 mapping_EM_to_RND[i] = EL_UNKNOWN;
8713 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
8714 mapping_EM_to_RND[em_object_mapping_list[i].element_em] =
8715 em_object_mapping_list[i].element_rnd;
8717 mapping_initialized = TRUE;
8720 if (element_em >= 0 && element_em < TILE_MAX)
8721 return mapping_EM_to_RND[element_em];
8723 Error(ERR_WARN, "invalid EM level element %d", element_em);
8728 void map_android_clone_elements_RND_to_EM(struct LevelInfo *level)
8730 struct LevelInfo_EM *level_em = level->native_em_level;
8731 struct LEVEL *lev = level_em->lev;
8734 for (i = 0; i < TILE_MAX; i++)
8735 lev->android_array[i] = Xblank;
8737 for (i = 0; i < level->num_android_clone_elements; i++)
8739 int element_rnd = level->android_clone_element[i];
8740 int element_em = map_element_RND_to_EM(element_rnd);
8742 for (j = 0; em_object_mapping_list[j].element_em != -1; j++)
8743 if (em_object_mapping_list[j].element_rnd == element_rnd)
8744 lev->android_array[em_object_mapping_list[j].element_em] = element_em;
8748 void map_android_clone_elements_EM_to_RND(struct LevelInfo *level)
8750 struct LevelInfo_EM *level_em = level->native_em_level;
8751 struct LEVEL *lev = level_em->lev;
8754 level->num_android_clone_elements = 0;
8756 for (i = 0; i < TILE_MAX; i++)
8758 int element_em = lev->android_array[i];
8760 boolean element_found = FALSE;
8762 if (element_em == Xblank)
8765 element_rnd = map_element_EM_to_RND(element_em);
8767 for (j = 0; j < level->num_android_clone_elements; j++)
8768 if (level->android_clone_element[j] == element_rnd)
8769 element_found = TRUE;
8773 level->android_clone_element[level->num_android_clone_elements++] =
8776 if (level->num_android_clone_elements == MAX_ANDROID_ELEMENTS)
8781 if (level->num_android_clone_elements == 0)
8783 level->num_android_clone_elements = 1;
8784 level->android_clone_element[0] = EL_EMPTY;
8788 int map_direction_RND_to_EM(int direction)
8790 return (direction == MV_UP ? 0 :
8791 direction == MV_RIGHT ? 1 :
8792 direction == MV_DOWN ? 2 :
8793 direction == MV_LEFT ? 3 :
8797 int map_direction_EM_to_RND(int direction)
8799 return (direction == 0 ? MV_UP :
8800 direction == 1 ? MV_RIGHT :
8801 direction == 2 ? MV_DOWN :
8802 direction == 3 ? MV_LEFT :
8806 int map_element_RND_to_SP(int element_rnd)
8808 int element_sp = 0x20; /* map unknown elements to yellow "hardware" */
8810 if (element_rnd >= EL_SP_START &&
8811 element_rnd <= EL_SP_END)
8812 element_sp = element_rnd - EL_SP_START;
8813 else if (element_rnd == EL_EMPTY_SPACE)
8815 else if (element_rnd == EL_INVISIBLE_WALL)
8821 int map_element_SP_to_RND(int element_sp)
8823 int element_rnd = EL_UNKNOWN;
8825 if (element_sp >= 0x00 &&
8827 element_rnd = EL_SP_START + element_sp;
8828 else if (element_sp == 0x28)
8829 element_rnd = EL_INVISIBLE_WALL;
8834 int map_action_SP_to_RND(int action_sp)
8838 case actActive: return ACTION_ACTIVE;
8839 case actImpact: return ACTION_IMPACT;
8840 case actExploding: return ACTION_EXPLODING;
8841 case actDigging: return ACTION_DIGGING;
8842 case actSnapping: return ACTION_SNAPPING;
8843 case actCollecting: return ACTION_COLLECTING;
8844 case actPassing: return ACTION_PASSING;
8845 case actPushing: return ACTION_PUSHING;
8846 case actDropping: return ACTION_DROPPING;
8848 default: return ACTION_DEFAULT;
8852 int get_next_element(int element)
8856 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
8857 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
8858 case EL_QUICKSAND_FAST_FILLING: return EL_QUICKSAND_FAST_FULL;
8859 case EL_QUICKSAND_FAST_EMPTYING: return EL_QUICKSAND_FAST_EMPTY;
8860 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
8861 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
8862 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
8863 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
8864 case EL_DC_MAGIC_WALL_FILLING: return EL_DC_MAGIC_WALL_FULL;
8865 case EL_DC_MAGIC_WALL_EMPTYING: return EL_DC_MAGIC_WALL_ACTIVE;
8866 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
8868 default: return element;
8873 int el_act_dir2img(int element, int action, int direction)
8875 element = GFX_ELEMENT(element);
8877 if (direction == MV_NONE)
8878 return element_info[element].graphic[action];
8880 direction = MV_DIR_TO_BIT(direction);
8882 return element_info[element].direction_graphic[action][direction];
8885 int el_act_dir2img(int element, int action, int direction)
8887 element = GFX_ELEMENT(element);
8888 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
8890 /* direction_graphic[][] == graphic[] for undefined direction graphics */
8891 return element_info[element].direction_graphic[action][direction];
8896 static int el_act_dir2crm(int element, int action, int direction)
8898 element = GFX_ELEMENT(element);
8900 if (direction == MV_NONE)
8901 return element_info[element].crumbled[action];
8903 direction = MV_DIR_TO_BIT(direction);
8905 return element_info[element].direction_crumbled[action][direction];
8908 static int el_act_dir2crm(int element, int action, int direction)
8910 element = GFX_ELEMENT(element);
8911 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
8913 /* direction_graphic[][] == graphic[] for undefined direction graphics */
8914 return element_info[element].direction_crumbled[action][direction];
8918 int el_act2img(int element, int action)
8920 element = GFX_ELEMENT(element);
8922 return element_info[element].graphic[action];
8925 int el_act2crm(int element, int action)
8927 element = GFX_ELEMENT(element);
8929 return element_info[element].crumbled[action];
8932 int el_dir2img(int element, int direction)
8934 element = GFX_ELEMENT(element);
8936 return el_act_dir2img(element, ACTION_DEFAULT, direction);
8939 int el2baseimg(int element)
8941 return element_info[element].graphic[ACTION_DEFAULT];
8944 int el2img(int element)
8946 element = GFX_ELEMENT(element);
8948 return element_info[element].graphic[ACTION_DEFAULT];
8951 int el2edimg(int element)
8953 element = GFX_ELEMENT(element);
8955 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
8958 int el2preimg(int element)
8960 element = GFX_ELEMENT(element);
8962 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
8965 int el2panelimg(int element)
8967 element = GFX_ELEMENT(element);
8969 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PANEL];
8972 int font2baseimg(int font_nr)
8974 return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
8977 int getBeltNrFromBeltElement(int element)
8979 return (element < EL_CONVEYOR_BELT_2_LEFT ? 0 :
8980 element < EL_CONVEYOR_BELT_3_LEFT ? 1 :
8981 element < EL_CONVEYOR_BELT_4_LEFT ? 2 : 3);
8984 int getBeltNrFromBeltActiveElement(int element)
8986 return (element < EL_CONVEYOR_BELT_2_LEFT_ACTIVE ? 0 :
8987 element < EL_CONVEYOR_BELT_3_LEFT_ACTIVE ? 1 :
8988 element < EL_CONVEYOR_BELT_4_LEFT_ACTIVE ? 2 : 3);
8991 int getBeltNrFromBeltSwitchElement(int element)
8993 return (element < EL_CONVEYOR_BELT_2_SWITCH_LEFT ? 0 :
8994 element < EL_CONVEYOR_BELT_3_SWITCH_LEFT ? 1 :
8995 element < EL_CONVEYOR_BELT_4_SWITCH_LEFT ? 2 : 3);
8998 int getBeltDirNrFromBeltElement(int element)
9000 static int belt_base_element[4] =
9002 EL_CONVEYOR_BELT_1_LEFT,
9003 EL_CONVEYOR_BELT_2_LEFT,
9004 EL_CONVEYOR_BELT_3_LEFT,
9005 EL_CONVEYOR_BELT_4_LEFT
9008 int belt_nr = getBeltNrFromBeltElement(element);
9009 int belt_dir_nr = element - belt_base_element[belt_nr];
9011 return (belt_dir_nr % 3);
9014 int getBeltDirNrFromBeltSwitchElement(int element)
9016 static int belt_base_element[4] =
9018 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
9019 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
9020 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
9021 EL_CONVEYOR_BELT_4_SWITCH_LEFT
9024 int belt_nr = getBeltNrFromBeltSwitchElement(element);
9025 int belt_dir_nr = element - belt_base_element[belt_nr];
9027 return (belt_dir_nr % 3);
9030 int getBeltDirFromBeltElement(int element)
9032 static int belt_move_dir[3] =
9039 int belt_dir_nr = getBeltDirNrFromBeltElement(element);
9041 return belt_move_dir[belt_dir_nr];
9044 int getBeltDirFromBeltSwitchElement(int element)
9046 static int belt_move_dir[3] =
9053 int belt_dir_nr = getBeltDirNrFromBeltSwitchElement(element);
9055 return belt_move_dir[belt_dir_nr];
9058 int getBeltElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
9060 static int belt_base_element[4] =
9062 EL_CONVEYOR_BELT_1_LEFT,
9063 EL_CONVEYOR_BELT_2_LEFT,
9064 EL_CONVEYOR_BELT_3_LEFT,
9065 EL_CONVEYOR_BELT_4_LEFT
9068 return belt_base_element[belt_nr] + belt_dir_nr;
9071 int getBeltElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
9073 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
9075 return getBeltElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
9078 int getBeltSwitchElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
9080 static int belt_base_element[4] =
9082 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
9083 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
9084 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
9085 EL_CONVEYOR_BELT_4_SWITCH_LEFT
9088 return belt_base_element[belt_nr] + belt_dir_nr;
9091 int getBeltSwitchElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
9093 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
9095 return getBeltSwitchElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
9099 boolean getTeamMode_EM()
9101 return game.team_mode;
9104 int getNumActivePlayers_EM()
9107 int num_players = 0;
9111 return (setup.team_mode ? MAX_PLAYERS : 1);
9113 for (i = 0; i < MAX_PLAYERS; i++)
9114 if (tape.player_participates[i])
9117 return (num_players > 1 ? MAX_PLAYERS : 1);
9121 int num_players = 0;
9124 /* when recording game, activate all connected players */
9128 for (i = 0; i < MAX_PLAYERS; i++)
9129 if (tape.player_participates[i])
9137 int getGameFrameDelay_EM(int native_em_game_frame_delay)
9139 int game_frame_delay_value;
9141 game_frame_delay_value =
9142 (tape.playing && tape.fast_forward ? FfwdFrameDelay :
9143 GameFrameDelay == GAME_FRAME_DELAY ? native_em_game_frame_delay :
9146 if (tape.playing && tape.warp_forward && !tape.pausing)
9147 game_frame_delay_value = 0;
9149 return game_frame_delay_value;
9152 unsigned int InitRND(int seed)
9154 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
9155 return InitEngineRandom_EM(seed);
9156 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
9157 return InitEngineRandom_SP(seed);
9159 return InitEngineRandom_RND(seed);
9163 static struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
9164 static struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
9167 inline static int get_effective_element_EM(int tile, int frame_em)
9169 int element = object_mapping[tile].element_rnd;
9170 int action = object_mapping[tile].action;
9171 boolean is_backside = object_mapping[tile].is_backside;
9172 boolean action_removing = (action == ACTION_DIGGING ||
9173 action == ACTION_SNAPPING ||
9174 action == ACTION_COLLECTING);
9180 case Yacid_splash_eB:
9181 case Yacid_splash_wB:
9182 return (frame_em > 5 ? EL_EMPTY : element);
9186 case Ydiamond_stone:
9187 // if (!game.use_native_emc_graphics_engine)
9195 else /* frame_em == 7 */
9199 case Yacid_splash_eB:
9200 case Yacid_splash_wB:
9203 case Yemerald_stone:
9206 case Ydiamond_stone:
9210 case Xdrip_stretchB:
9229 case Xsand_stonein_1:
9230 case Xsand_stonein_2:
9231 case Xsand_stonein_3:
9232 case Xsand_stonein_4:
9236 return (is_backside || action_removing ? EL_EMPTY : element);
9241 inline static boolean check_linear_animation_EM(int tile)
9245 case Xsand_stonesand_1:
9246 case Xsand_stonesand_quickout_1:
9247 case Xsand_sandstone_1:
9248 case Xsand_stonein_1:
9249 case Xsand_stoneout_1:
9269 case Yacid_splash_eB:
9270 case Yacid_splash_wB:
9271 case Yemerald_stone:
9279 inline static void set_crumbled_graphics_EM(struct GraphicInfo_EM *g_em,
9280 boolean has_crumbled_graphics,
9281 int crumbled, int sync_frame)
9283 /* if element can be crumbled, but certain action graphics are just empty
9284 space (like instantly snapping sand to empty space in 1 frame), do not
9285 treat these empty space graphics as crumbled graphics in EMC engine */
9286 if (crumbled == IMG_EMPTY_SPACE)
9287 has_crumbled_graphics = FALSE;
9289 if (has_crumbled_graphics)
9291 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
9292 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
9293 g_crumbled->anim_delay,
9294 g_crumbled->anim_mode,
9295 g_crumbled->anim_start_frame,
9298 getGraphicSource(crumbled, frame_crumbled, &g_em->crumbled_bitmap,
9299 &g_em->crumbled_src_x, &g_em->crumbled_src_y);
9301 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
9303 g_em->has_crumbled_graphics = TRUE;
9307 g_em->crumbled_bitmap = NULL;
9308 g_em->crumbled_src_x = 0;
9309 g_em->crumbled_src_y = 0;
9310 g_em->crumbled_border_size = 0;
9312 g_em->has_crumbled_graphics = FALSE;
9316 void ResetGfxAnimation_EM(int x, int y, int tile)
9321 void SetGfxAnimation_EM(struct GraphicInfo_EM *g_em,
9322 int tile, int frame_em, int x, int y)
9324 int action = object_mapping[tile].action;
9326 int direction = object_mapping[tile].direction;
9327 int effective_element = get_effective_element_EM(tile, frame_em);
9328 int graphic = (direction == MV_NONE ?
9329 el_act2img(effective_element, action) :
9330 el_act_dir2img(effective_element, action, direction));
9331 struct GraphicInfo *g = &graphic_info[graphic];
9334 boolean action_removing = (action == ACTION_DIGGING ||
9335 action == ACTION_SNAPPING ||
9336 action == ACTION_COLLECTING);
9337 boolean action_moving = (action == ACTION_FALLING ||
9338 action == ACTION_MOVING ||
9339 action == ACTION_PUSHING ||
9340 action == ACTION_EATING ||
9341 action == ACTION_FILLING ||
9342 action == ACTION_EMPTYING);
9343 boolean action_falling = (action == ACTION_FALLING ||
9344 action == ACTION_FILLING ||
9345 action == ACTION_EMPTYING);
9347 /* special case: graphic uses "2nd movement tile" and has defined
9348 7 frames for movement animation (or less) => use default graphic
9349 for last (8th) frame which ends the movement animation */
9350 if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
9352 action = ACTION_DEFAULT; /* (keep action_* unchanged for now) */
9353 graphic = (direction == MV_NONE ?
9354 el_act2img(effective_element, action) :
9355 el_act_dir2img(effective_element, action, direction));
9357 g = &graphic_info[graphic];
9361 if (tile == Xsand_stonesand_1 ||
9362 tile == Xsand_stonesand_2 ||
9363 tile == Xsand_stonesand_3 ||
9364 tile == Xsand_stonesand_4)
9365 printf("::: 1: quicksand frame %d [%d]\n", GfxFrame[x][y], tile);
9369 if ((action_removing || check_linear_animation_EM(tile)) && frame_em == 0)
9373 // printf("::: resetting... [%d]\n", tile);
9376 if (action_removing || check_linear_animation_EM(tile))
9378 GfxFrame[x][y] = frame_em;
9380 // printf("::: resetting... [%d]\n", tile);
9383 else if (action_moving)
9385 boolean is_backside = object_mapping[tile].is_backside;
9389 int direction = object_mapping[tile].direction;
9390 int move_dir = (action_falling ? MV_DOWN : direction);
9395 /* !!! TEST !!! NEW !!! DOES NOT WORK RIGHT YET !!! */
9396 if (g->double_movement && frame_em == 0)
9400 // printf("::: resetting... [%d]\n", tile);
9404 if (move_dir == MV_LEFT)
9405 GfxFrame[x - 1][y] = GfxFrame[x][y];
9406 else if (move_dir == MV_RIGHT)
9407 GfxFrame[x + 1][y] = GfxFrame[x][y];
9408 else if (move_dir == MV_UP)
9409 GfxFrame[x][y - 1] = GfxFrame[x][y];
9410 else if (move_dir == MV_DOWN)
9411 GfxFrame[x][y + 1] = GfxFrame[x][y];
9418 /* special case: animation for Xsand_stonesand_quickout_1/2 twice as fast */
9419 if (tile == Xsand_stonesand_quickout_1 ||
9420 tile == Xsand_stonesand_quickout_2)
9425 if (tile == Xsand_stonesand_1 ||
9426 tile == Xsand_stonesand_2 ||
9427 tile == Xsand_stonesand_3 ||
9428 tile == Xsand_stonesand_4)
9429 printf("::: 2: quicksand frame %d [%d]\n", GfxFrame[x][y], tile);
9433 if (graphic_info[graphic].anim_global_sync)
9434 sync_frame = FrameCounter;
9435 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
9436 sync_frame = GfxFrame[x][y];
9438 sync_frame = 0; /* playfield border (pseudo steel) */
9440 SetRandomAnimationValue(x, y);
9442 int frame = getAnimationFrame(g->anim_frames,
9445 g->anim_start_frame,
9448 g_em->unique_identifier =
9449 (graphic << 16) | ((frame % 8) << 12) | (g_em->width << 6) | g_em->height;
9453 void getGraphicSourceObjectExt_EM(struct GraphicInfo_EM *g_em,
9454 int tile, int frame_em, int x, int y)
9456 int action = object_mapping[tile].action;
9457 int direction = object_mapping[tile].direction;
9458 boolean is_backside = object_mapping[tile].is_backside;
9459 int effective_element = get_effective_element_EM(tile, frame_em);
9461 int effective_action = action;
9463 int effective_action = (frame_em < 7 ? action : ACTION_DEFAULT);
9465 int graphic = (direction == MV_NONE ?
9466 el_act2img(effective_element, effective_action) :
9467 el_act_dir2img(effective_element, effective_action,
9469 int crumbled = (direction == MV_NONE ?
9470 el_act2crm(effective_element, effective_action) :
9471 el_act_dir2crm(effective_element, effective_action,
9473 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
9474 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
9475 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
9476 struct GraphicInfo *g = &graphic_info[graphic];
9478 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
9482 /* special case: graphic uses "2nd movement tile" and has defined
9483 7 frames for movement animation (or less) => use default graphic
9484 for last (8th) frame which ends the movement animation */
9485 if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
9487 effective_action = ACTION_DEFAULT;
9488 graphic = (direction == MV_NONE ?
9489 el_act2img(effective_element, effective_action) :
9490 el_act_dir2img(effective_element, effective_action,
9492 crumbled = (direction == MV_NONE ?
9493 el_act2crm(effective_element, effective_action) :
9494 el_act_dir2crm(effective_element, effective_action,
9497 g = &graphic_info[graphic];
9507 if (frame_em == 0) /* reset animation frame for certain elements */
9509 if (check_linear_animation_EM(tile))
9514 if (graphic_info[graphic].anim_global_sync)
9515 sync_frame = FrameCounter;
9516 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
9517 sync_frame = GfxFrame[x][y];
9519 sync_frame = 0; /* playfield border (pseudo steel) */
9521 SetRandomAnimationValue(x, y);
9526 int xxx_sync_frame = (i == Xdrip_stretch ? 7 :
9527 i == Xdrip_stretchB ? 7 :
9528 i == Ydrip_s2 ? j + 8 :
9529 i == Ydrip_s2B ? j + 8 :
9538 i == Xfake_acid_1 ? 0 :
9539 i == Xfake_acid_2 ? 10 :
9540 i == Xfake_acid_3 ? 20 :
9541 i == Xfake_acid_4 ? 30 :
9542 i == Xfake_acid_5 ? 40 :
9543 i == Xfake_acid_6 ? 50 :
9544 i == Xfake_acid_7 ? 60 :
9545 i == Xfake_acid_8 ? 70 :
9547 i == Xball_2B ? j + 8 :
9548 i == Yball_eat ? j + 1 :
9549 i == Ykey_1_eat ? j + 1 :
9550 i == Ykey_2_eat ? j + 1 :
9551 i == Ykey_3_eat ? j + 1 :
9552 i == Ykey_4_eat ? j + 1 :
9553 i == Ykey_5_eat ? j + 1 :
9554 i == Ykey_6_eat ? j + 1 :
9555 i == Ykey_7_eat ? j + 1 :
9556 i == Ykey_8_eat ? j + 1 :
9557 i == Ylenses_eat ? j + 1 :
9558 i == Ymagnify_eat ? j + 1 :
9559 i == Ygrass_eat ? j + 1 :
9560 i == Ydirt_eat ? j + 1 :
9561 i == Xamoeba_1 ? 0 :
9562 i == Xamoeba_2 ? 1 :
9563 i == Xamoeba_3 ? 2 :
9564 i == Xamoeba_4 ? 3 :
9565 i == Xamoeba_5 ? 0 :
9566 i == Xamoeba_6 ? 1 :
9567 i == Xamoeba_7 ? 2 :
9568 i == Xamoeba_8 ? 3 :
9569 i == Xexit_2 ? j + 8 :
9570 i == Xexit_3 ? j + 16 :
9571 i == Xdynamite_1 ? 0 :
9572 i == Xdynamite_2 ? 8 :
9573 i == Xdynamite_3 ? 16 :
9574 i == Xdynamite_4 ? 24 :
9575 i == Xsand_stonein_1 ? j + 1 :
9576 i == Xsand_stonein_2 ? j + 9 :
9577 i == Xsand_stonein_3 ? j + 17 :
9578 i == Xsand_stonein_4 ? j + 25 :
9579 i == Xsand_stoneout_1 && j == 0 ? 0 :
9580 i == Xsand_stoneout_1 && j == 1 ? 0 :
9581 i == Xsand_stoneout_1 && j == 2 ? 1 :
9582 i == Xsand_stoneout_1 && j == 3 ? 2 :
9583 i == Xsand_stoneout_1 && j == 4 ? 2 :
9584 i == Xsand_stoneout_1 && j == 5 ? 3 :
9585 i == Xsand_stoneout_1 && j == 6 ? 4 :
9586 i == Xsand_stoneout_1 && j == 7 ? 4 :
9587 i == Xsand_stoneout_2 && j == 0 ? 5 :
9588 i == Xsand_stoneout_2 && j == 1 ? 6 :
9589 i == Xsand_stoneout_2 && j == 2 ? 7 :
9590 i == Xsand_stoneout_2 && j == 3 ? 8 :
9591 i == Xsand_stoneout_2 && j == 4 ? 9 :
9592 i == Xsand_stoneout_2 && j == 5 ? 11 :
9593 i == Xsand_stoneout_2 && j == 6 ? 13 :
9594 i == Xsand_stoneout_2 && j == 7 ? 15 :
9595 i == Xboom_bug && j == 1 ? 2 :
9596 i == Xboom_bug && j == 2 ? 2 :
9597 i == Xboom_bug && j == 3 ? 4 :
9598 i == Xboom_bug && j == 4 ? 4 :
9599 i == Xboom_bug && j == 5 ? 2 :
9600 i == Xboom_bug && j == 6 ? 2 :
9601 i == Xboom_bug && j == 7 ? 0 :
9602 i == Xboom_bomb && j == 1 ? 2 :
9603 i == Xboom_bomb && j == 2 ? 2 :
9604 i == Xboom_bomb && j == 3 ? 4 :
9605 i == Xboom_bomb && j == 4 ? 4 :
9606 i == Xboom_bomb && j == 5 ? 2 :
9607 i == Xboom_bomb && j == 6 ? 2 :
9608 i == Xboom_bomb && j == 7 ? 0 :
9609 i == Xboom_android && j == 7 ? 6 :
9610 i == Xboom_1 && j == 1 ? 2 :
9611 i == Xboom_1 && j == 2 ? 2 :
9612 i == Xboom_1 && j == 3 ? 4 :
9613 i == Xboom_1 && j == 4 ? 4 :
9614 i == Xboom_1 && j == 5 ? 6 :
9615 i == Xboom_1 && j == 6 ? 6 :
9616 i == Xboom_1 && j == 7 ? 8 :
9617 i == Xboom_2 && j == 0 ? 8 :
9618 i == Xboom_2 && j == 1 ? 8 :
9619 i == Xboom_2 && j == 2 ? 10 :
9620 i == Xboom_2 && j == 3 ? 10 :
9621 i == Xboom_2 && j == 4 ? 10 :
9622 i == Xboom_2 && j == 5 ? 12 :
9623 i == Xboom_2 && j == 6 ? 12 :
9624 i == Xboom_2 && j == 7 ? 12 :
9626 special_animation && j == 4 ? 3 :
9627 effective_action != action ? 0 :
9633 int xxx_effective_action;
9634 int xxx_has_action_graphics;
9637 int element = object_mapping[i].element_rnd;
9638 int action = object_mapping[i].action;
9639 int direction = object_mapping[i].direction;
9640 boolean is_backside = object_mapping[i].is_backside;
9642 boolean action_removing = (action == ACTION_DIGGING ||
9643 action == ACTION_SNAPPING ||
9644 action == ACTION_COLLECTING);
9646 boolean action_exploding = ((action == ACTION_EXPLODING ||
9647 action == ACTION_SMASHED_BY_ROCK ||
9648 action == ACTION_SMASHED_BY_SPRING) &&
9649 element != EL_DIAMOND);
9650 boolean action_active = (action == ACTION_ACTIVE);
9651 boolean action_other = (action == ACTION_OTHER);
9655 int effective_element = get_effective_element_EM(i, j);
9657 int effective_element = (j > 5 && i == Yacid_splash_eB ? EL_EMPTY :
9658 j > 5 && i == Yacid_splash_wB ? EL_EMPTY :
9660 i == Xdrip_stretch ? element :
9661 i == Xdrip_stretchB ? element :
9662 i == Ydrip_s1 ? element :
9663 i == Ydrip_s1B ? element :
9664 i == Xball_1B ? element :
9665 i == Xball_2 ? element :
9666 i == Xball_2B ? element :
9667 i == Yball_eat ? element :
9668 i == Ykey_1_eat ? element :
9669 i == Ykey_2_eat ? element :
9670 i == Ykey_3_eat ? element :
9671 i == Ykey_4_eat ? element :
9672 i == Ykey_5_eat ? element :
9673 i == Ykey_6_eat ? element :
9674 i == Ykey_7_eat ? element :
9675 i == Ykey_8_eat ? element :
9676 i == Ylenses_eat ? element :
9677 i == Ymagnify_eat ? element :
9678 i == Ygrass_eat ? element :
9679 i == Ydirt_eat ? element :
9680 i == Yemerald_stone ? EL_EMERALD :
9681 i == Ydiamond_stone ? EL_ROCK :
9682 i == Xsand_stonein_1 ? element :
9683 i == Xsand_stonein_2 ? element :
9684 i == Xsand_stonein_3 ? element :
9685 i == Xsand_stonein_4 ? element :
9686 is_backside ? EL_EMPTY :
9687 action_removing ? EL_EMPTY :
9690 int effective_action = (j < 7 ? action :
9691 i == Xdrip_stretch ? action :
9692 i == Xdrip_stretchB ? action :
9693 i == Ydrip_s1 ? action :
9694 i == Ydrip_s1B ? action :
9695 i == Xball_1B ? action :
9696 i == Xball_2 ? action :
9697 i == Xball_2B ? action :
9698 i == Yball_eat ? action :
9699 i == Ykey_1_eat ? action :
9700 i == Ykey_2_eat ? action :
9701 i == Ykey_3_eat ? action :
9702 i == Ykey_4_eat ? action :
9703 i == Ykey_5_eat ? action :
9704 i == Ykey_6_eat ? action :
9705 i == Ykey_7_eat ? action :
9706 i == Ykey_8_eat ? action :
9707 i == Ylenses_eat ? action :
9708 i == Ymagnify_eat ? action :
9709 i == Ygrass_eat ? action :
9710 i == Ydirt_eat ? action :
9711 i == Xsand_stonein_1 ? action :
9712 i == Xsand_stonein_2 ? action :
9713 i == Xsand_stonein_3 ? action :
9714 i == Xsand_stonein_4 ? action :
9715 i == Xsand_stoneout_1 ? action :
9716 i == Xsand_stoneout_2 ? action :
9717 i == Xboom_android ? ACTION_EXPLODING :
9718 action_exploding ? ACTION_EXPLODING :
9719 action_active ? action :
9720 action_other ? action :
9722 int graphic = (el_act_dir2img(effective_element, effective_action,
9724 int crumbled = (el_act_dir2crm(effective_element, effective_action,
9726 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
9727 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
9728 boolean has_action_graphics = (graphic != base_graphic);
9729 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
9730 struct GraphicInfo *g = &graphic_info[graphic];
9732 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
9734 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
9737 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
9738 boolean special_animation = (action != ACTION_DEFAULT &&
9739 g->anim_frames == 3 &&
9740 g->anim_delay == 2 &&
9741 g->anim_mode & ANIM_LINEAR);
9742 xxx_sync_frame = (i == Xdrip_stretch ? 7 :
9743 i == Xdrip_stretchB ? 7 :
9744 i == Ydrip_s2 ? j + 8 :
9745 i == Ydrip_s2B ? j + 8 :
9754 i == Xfake_acid_1 ? 0 :
9755 i == Xfake_acid_2 ? 10 :
9756 i == Xfake_acid_3 ? 20 :
9757 i == Xfake_acid_4 ? 30 :
9758 i == Xfake_acid_5 ? 40 :
9759 i == Xfake_acid_6 ? 50 :
9760 i == Xfake_acid_7 ? 60 :
9761 i == Xfake_acid_8 ? 70 :
9763 i == Xball_2B ? j + 8 :
9764 i == Yball_eat ? j + 1 :
9765 i == Ykey_1_eat ? j + 1 :
9766 i == Ykey_2_eat ? j + 1 :
9767 i == Ykey_3_eat ? j + 1 :
9768 i == Ykey_4_eat ? j + 1 :
9769 i == Ykey_5_eat ? j + 1 :
9770 i == Ykey_6_eat ? j + 1 :
9771 i == Ykey_7_eat ? j + 1 :
9772 i == Ykey_8_eat ? j + 1 :
9773 i == Ylenses_eat ? j + 1 :
9774 i == Ymagnify_eat ? j + 1 :
9775 i == Ygrass_eat ? j + 1 :
9776 i == Ydirt_eat ? j + 1 :
9777 i == Xamoeba_1 ? 0 :
9778 i == Xamoeba_2 ? 1 :
9779 i == Xamoeba_3 ? 2 :
9780 i == Xamoeba_4 ? 3 :
9781 i == Xamoeba_5 ? 0 :
9782 i == Xamoeba_6 ? 1 :
9783 i == Xamoeba_7 ? 2 :
9784 i == Xamoeba_8 ? 3 :
9785 i == Xexit_2 ? j + 8 :
9786 i == Xexit_3 ? j + 16 :
9787 i == Xdynamite_1 ? 0 :
9788 i == Xdynamite_2 ? 8 :
9789 i == Xdynamite_3 ? 16 :
9790 i == Xdynamite_4 ? 24 :
9791 i == Xsand_stonein_1 ? j + 1 :
9792 i == Xsand_stonein_2 ? j + 9 :
9793 i == Xsand_stonein_3 ? j + 17 :
9794 i == Xsand_stonein_4 ? j + 25 :
9795 i == Xsand_stoneout_1 && j == 0 ? 0 :
9796 i == Xsand_stoneout_1 && j == 1 ? 0 :
9797 i == Xsand_stoneout_1 && j == 2 ? 1 :
9798 i == Xsand_stoneout_1 && j == 3 ? 2 :
9799 i == Xsand_stoneout_1 && j == 4 ? 2 :
9800 i == Xsand_stoneout_1 && j == 5 ? 3 :
9801 i == Xsand_stoneout_1 && j == 6 ? 4 :
9802 i == Xsand_stoneout_1 && j == 7 ? 4 :
9803 i == Xsand_stoneout_2 && j == 0 ? 5 :
9804 i == Xsand_stoneout_2 && j == 1 ? 6 :
9805 i == Xsand_stoneout_2 && j == 2 ? 7 :
9806 i == Xsand_stoneout_2 && j == 3 ? 8 :
9807 i == Xsand_stoneout_2 && j == 4 ? 9 :
9808 i == Xsand_stoneout_2 && j == 5 ? 11 :
9809 i == Xsand_stoneout_2 && j == 6 ? 13 :
9810 i == Xsand_stoneout_2 && j == 7 ? 15 :
9811 i == Xboom_bug && j == 1 ? 2 :
9812 i == Xboom_bug && j == 2 ? 2 :
9813 i == Xboom_bug && j == 3 ? 4 :
9814 i == Xboom_bug && j == 4 ? 4 :
9815 i == Xboom_bug && j == 5 ? 2 :
9816 i == Xboom_bug && j == 6 ? 2 :
9817 i == Xboom_bug && j == 7 ? 0 :
9818 i == Xboom_bomb && j == 1 ? 2 :
9819 i == Xboom_bomb && j == 2 ? 2 :
9820 i == Xboom_bomb && j == 3 ? 4 :
9821 i == Xboom_bomb && j == 4 ? 4 :
9822 i == Xboom_bomb && j == 5 ? 2 :
9823 i == Xboom_bomb && j == 6 ? 2 :
9824 i == Xboom_bomb && j == 7 ? 0 :
9825 i == Xboom_android && j == 7 ? 6 :
9826 i == Xboom_1 && j == 1 ? 2 :
9827 i == Xboom_1 && j == 2 ? 2 :
9828 i == Xboom_1 && j == 3 ? 4 :
9829 i == Xboom_1 && j == 4 ? 4 :
9830 i == Xboom_1 && j == 5 ? 6 :
9831 i == Xboom_1 && j == 6 ? 6 :
9832 i == Xboom_1 && j == 7 ? 8 :
9833 i == Xboom_2 && j == 0 ? 8 :
9834 i == Xboom_2 && j == 1 ? 8 :
9835 i == Xboom_2 && j == 2 ? 10 :
9836 i == Xboom_2 && j == 3 ? 10 :
9837 i == Xboom_2 && j == 4 ? 10 :
9838 i == Xboom_2 && j == 5 ? 12 :
9839 i == Xboom_2 && j == 6 ? 12 :
9840 i == Xboom_2 && j == 7 ? 12 :
9841 special_animation && j == 4 ? 3 :
9842 effective_action != action ? 0 :
9845 xxx_effective_action = effective_action;
9846 xxx_has_action_graphics = has_action_graphics;
9851 int frame = getAnimationFrame(g->anim_frames,
9854 g->anim_start_frame,
9868 int old_src_x = g_em->src_x;
9869 int old_src_y = g_em->src_y;
9873 getGraphicSourceExt(graphic, frame, &g_em->bitmap, &g_em->src_x, &g_em->src_y,
9874 g->double_movement && is_backside);
9876 getGraphicSourceExt(graphic, frame, &g_em->bitmap,
9877 &g_em->src_x, &g_em->src_y, FALSE);
9882 if (tile == Ydiamond_stone)
9883 printf("::: stone smashing diamond... %d: %d, %d, %d, %d, %d -> %d [%d, %d, %d, %d, %d, %d] [%d]\n",
9888 g->anim_start_frame,
9891 g_em->src_x, g_em->src_y,
9892 g_em->src_offset_x, g_em->src_offset_y,
9893 g_em->dst_offset_x, g_em->dst_offset_y,
9905 if (graphic == IMG_BUG_MOVING_RIGHT)
9906 printf("::: %d, %d, %d: %d, %d [%d, %d -> %d, %d]\n", graphic, x, y,
9907 g->double_movement, is_backside,
9908 old_src_x, old_src_y, g_em->src_x, g_em->src_y);
9916 g_em->src_offset_x = 0;
9917 g_em->src_offset_y = 0;
9918 g_em->dst_offset_x = 0;
9919 g_em->dst_offset_y = 0;
9920 g_em->width = TILEX;
9921 g_em->height = TILEY;
9923 g_em->preserve_background = FALSE;
9926 /* (updating the "crumbled" graphic definitions is probably not really needed,
9927 as animations for crumbled graphics can't be longer than one EMC cycle) */
9929 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
9934 g_em->crumbled_bitmap = NULL;
9935 g_em->crumbled_src_x = 0;
9936 g_em->crumbled_src_y = 0;
9938 g_em->has_crumbled_graphics = FALSE;
9940 if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
9942 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
9943 g_crumbled->anim_delay,
9944 g_crumbled->anim_mode,
9945 g_crumbled->anim_start_frame,
9948 getGraphicSource(crumbled, frame_crumbled, &g_em->crumbled_bitmap,
9949 &g_em->crumbled_src_x, &g_em->crumbled_src_y);
9951 g_em->has_crumbled_graphics = TRUE;
9957 int effective_action = xxx_effective_action;
9958 int has_action_graphics = xxx_has_action_graphics;
9960 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
9961 effective_action == ACTION_MOVING ||
9962 effective_action == ACTION_PUSHING ||
9963 effective_action == ACTION_EATING)) ||
9964 (!has_action_graphics && (effective_action == ACTION_FILLING ||
9965 effective_action == ACTION_EMPTYING)))
9968 (effective_action == ACTION_FALLING ||
9969 effective_action == ACTION_FILLING ||
9970 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
9971 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
9972 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
9973 int num_steps = (i == Ydrip_s1 ? 16 :
9974 i == Ydrip_s1B ? 16 :
9975 i == Ydrip_s2 ? 16 :
9976 i == Ydrip_s2B ? 16 :
9977 i == Xsand_stonein_1 ? 32 :
9978 i == Xsand_stonein_2 ? 32 :
9979 i == Xsand_stonein_3 ? 32 :
9980 i == Xsand_stonein_4 ? 32 :
9981 i == Xsand_stoneout_1 ? 16 :
9982 i == Xsand_stoneout_2 ? 16 : 8);
9983 int cx = ABS(dx) * (TILEX / num_steps);
9984 int cy = ABS(dy) * (TILEY / num_steps);
9985 int step_frame = (i == Ydrip_s2 ? j + 8 :
9986 i == Ydrip_s2B ? j + 8 :
9987 i == Xsand_stonein_2 ? j + 8 :
9988 i == Xsand_stonein_3 ? j + 16 :
9989 i == Xsand_stonein_4 ? j + 24 :
9990 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
9991 int step = (is_backside ? step_frame : num_steps - step_frame);
9993 if (is_backside) /* tile where movement starts */
9995 if (dx < 0 || dy < 0)
9997 g_em->src_offset_x = cx * step;
9998 g_em->src_offset_y = cy * step;
10002 g_em->dst_offset_x = cx * step;
10003 g_em->dst_offset_y = cy * step;
10006 else /* tile where movement ends */
10008 if (dx < 0 || dy < 0)
10010 g_em->dst_offset_x = cx * step;
10011 g_em->dst_offset_y = cy * step;
10015 g_em->src_offset_x = cx * step;
10016 g_em->src_offset_y = cy * step;
10020 g_em->width = TILEX - cx * step;
10021 g_em->height = TILEY - cy * step;
10024 /* create unique graphic identifier to decide if tile must be redrawn */
10025 /* bit 31 - 16 (16 bit): EM style graphic
10026 bit 15 - 12 ( 4 bit): EM style frame
10027 bit 11 - 6 ( 6 bit): graphic width
10028 bit 5 - 0 ( 6 bit): graphic height */
10029 g_em->unique_identifier =
10030 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
10036 void getGraphicSourcePlayerExt_EM(struct GraphicInfo_EM *g_em,
10037 int player_nr, int anim, int frame_em)
10039 int element = player_mapping[player_nr][anim].element_rnd;
10040 int action = player_mapping[player_nr][anim].action;
10041 int direction = player_mapping[player_nr][anim].direction;
10042 int graphic = (direction == MV_NONE ?
10043 el_act2img(element, action) :
10044 el_act_dir2img(element, action, direction));
10045 struct GraphicInfo *g = &graphic_info[graphic];
10048 InitPlayerGfxAnimation(&stored_player[player_nr], action, direction);
10050 stored_player[player_nr].StepFrame = frame_em;
10052 sync_frame = stored_player[player_nr].Frame;
10054 int frame = getAnimationFrame(g->anim_frames,
10057 g->anim_start_frame,
10060 getGraphicSourceExt(graphic, frame, &g_em->bitmap,
10061 &g_em->src_x, &g_em->src_y, FALSE);
10064 printf("::: %d: %d, %d [%d]\n",
10066 stored_player[player_nr].Frame,
10067 stored_player[player_nr].StepFrame,
10072 void InitGraphicInfo_EM(void)
10075 struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
10076 struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
10081 int num_em_gfx_errors = 0;
10083 if (graphic_info_em_object[0][0].bitmap == NULL)
10085 /* EM graphics not yet initialized in em_open_all() */
10090 printf("::: [4 errors can be ignored (1 x 'bomb', 3 x 'em_dynamite']\n");
10093 /* always start with reliable default values */
10094 for (i = 0; i < TILE_MAX; i++)
10096 object_mapping[i].element_rnd = EL_UNKNOWN;
10097 object_mapping[i].is_backside = FALSE;
10098 object_mapping[i].action = ACTION_DEFAULT;
10099 object_mapping[i].direction = MV_NONE;
10102 /* always start with reliable default values */
10103 for (p = 0; p < MAX_PLAYERS; p++)
10105 for (i = 0; i < SPR_MAX; i++)
10107 player_mapping[p][i].element_rnd = EL_UNKNOWN;
10108 player_mapping[p][i].action = ACTION_DEFAULT;
10109 player_mapping[p][i].direction = MV_NONE;
10113 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
10115 int e = em_object_mapping_list[i].element_em;
10117 object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd;
10118 object_mapping[e].is_backside = em_object_mapping_list[i].is_backside;
10120 if (em_object_mapping_list[i].action != -1)
10121 object_mapping[e].action = em_object_mapping_list[i].action;
10123 if (em_object_mapping_list[i].direction != -1)
10124 object_mapping[e].direction =
10125 MV_DIR_FROM_BIT(em_object_mapping_list[i].direction);
10128 for (i = 0; em_player_mapping_list[i].action_em != -1; i++)
10130 int a = em_player_mapping_list[i].action_em;
10131 int p = em_player_mapping_list[i].player_nr;
10133 player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd;
10135 if (em_player_mapping_list[i].action != -1)
10136 player_mapping[p][a].action = em_player_mapping_list[i].action;
10138 if (em_player_mapping_list[i].direction != -1)
10139 player_mapping[p][a].direction =
10140 MV_DIR_FROM_BIT(em_player_mapping_list[i].direction);
10143 for (i = 0; i < TILE_MAX; i++)
10145 int element = object_mapping[i].element_rnd;
10146 int action = object_mapping[i].action;
10147 int direction = object_mapping[i].direction;
10148 boolean is_backside = object_mapping[i].is_backside;
10150 boolean action_removing = (action == ACTION_DIGGING ||
10151 action == ACTION_SNAPPING ||
10152 action == ACTION_COLLECTING);
10154 boolean action_exploding = ((action == ACTION_EXPLODING ||
10155 action == ACTION_SMASHED_BY_ROCK ||
10156 action == ACTION_SMASHED_BY_SPRING) &&
10157 element != EL_DIAMOND);
10158 boolean action_active = (action == ACTION_ACTIVE);
10159 boolean action_other = (action == ACTION_OTHER);
10161 for (j = 0; j < 8; j++)
10164 int effective_element = get_effective_element_EM(i, j);
10166 int effective_element = (j > 5 && i == Yacid_splash_eB ? EL_EMPTY :
10167 j > 5 && i == Yacid_splash_wB ? EL_EMPTY :
10169 i == Xdrip_stretch ? element :
10170 i == Xdrip_stretchB ? element :
10171 i == Ydrip_s1 ? element :
10172 i == Ydrip_s1B ? element :
10173 i == Xball_1B ? element :
10174 i == Xball_2 ? element :
10175 i == Xball_2B ? element :
10176 i == Yball_eat ? element :
10177 i == Ykey_1_eat ? element :
10178 i == Ykey_2_eat ? element :
10179 i == Ykey_3_eat ? element :
10180 i == Ykey_4_eat ? element :
10181 i == Ykey_5_eat ? element :
10182 i == Ykey_6_eat ? element :
10183 i == Ykey_7_eat ? element :
10184 i == Ykey_8_eat ? element :
10185 i == Ylenses_eat ? element :
10186 i == Ymagnify_eat ? element :
10187 i == Ygrass_eat ? element :
10188 i == Ydirt_eat ? element :
10189 i == Yemerald_stone ? EL_EMERALD :
10190 i == Ydiamond_stone ? EL_ROCK :
10191 i == Xsand_stonein_1 ? element :
10192 i == Xsand_stonein_2 ? element :
10193 i == Xsand_stonein_3 ? element :
10194 i == Xsand_stonein_4 ? element :
10195 is_backside ? EL_EMPTY :
10196 action_removing ? EL_EMPTY :
10199 int effective_action = (j < 7 ? action :
10200 i == Xdrip_stretch ? action :
10201 i == Xdrip_stretchB ? action :
10202 i == Ydrip_s1 ? action :
10203 i == Ydrip_s1B ? action :
10204 i == Xball_1B ? action :
10205 i == Xball_2 ? action :
10206 i == Xball_2B ? action :
10207 i == Yball_eat ? action :
10208 i == Ykey_1_eat ? action :
10209 i == Ykey_2_eat ? action :
10210 i == Ykey_3_eat ? action :
10211 i == Ykey_4_eat ? action :
10212 i == Ykey_5_eat ? action :
10213 i == Ykey_6_eat ? action :
10214 i == Ykey_7_eat ? action :
10215 i == Ykey_8_eat ? action :
10216 i == Ylenses_eat ? action :
10217 i == Ymagnify_eat ? action :
10218 i == Ygrass_eat ? action :
10219 i == Ydirt_eat ? action :
10220 i == Xsand_stonein_1 ? action :
10221 i == Xsand_stonein_2 ? action :
10222 i == Xsand_stonein_3 ? action :
10223 i == Xsand_stonein_4 ? action :
10224 i == Xsand_stoneout_1 ? action :
10225 i == Xsand_stoneout_2 ? action :
10226 i == Xboom_android ? ACTION_EXPLODING :
10227 action_exploding ? ACTION_EXPLODING :
10228 action_active ? action :
10229 action_other ? action :
10231 int graphic = (el_act_dir2img(effective_element, effective_action,
10233 int crumbled = (el_act_dir2crm(effective_element, effective_action,
10235 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
10236 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
10237 boolean has_action_graphics = (graphic != base_graphic);
10238 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
10239 struct GraphicInfo *g = &graphic_info[graphic];
10241 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
10243 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
10244 Bitmap *src_bitmap;
10246 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
10247 boolean special_animation = (action != ACTION_DEFAULT &&
10248 g->anim_frames == 3 &&
10249 g->anim_delay == 2 &&
10250 g->anim_mode & ANIM_LINEAR);
10251 int sync_frame = (i == Xdrip_stretch ? 7 :
10252 i == Xdrip_stretchB ? 7 :
10253 i == Ydrip_s2 ? j + 8 :
10254 i == Ydrip_s2B ? j + 8 :
10256 i == Xacid_2 ? 10 :
10257 i == Xacid_3 ? 20 :
10258 i == Xacid_4 ? 30 :
10259 i == Xacid_5 ? 40 :
10260 i == Xacid_6 ? 50 :
10261 i == Xacid_7 ? 60 :
10262 i == Xacid_8 ? 70 :
10263 i == Xfake_acid_1 ? 0 :
10264 i == Xfake_acid_2 ? 10 :
10265 i == Xfake_acid_3 ? 20 :
10266 i == Xfake_acid_4 ? 30 :
10267 i == Xfake_acid_5 ? 40 :
10268 i == Xfake_acid_6 ? 50 :
10269 i == Xfake_acid_7 ? 60 :
10270 i == Xfake_acid_8 ? 70 :
10272 i == Xball_2B ? j + 8 :
10273 i == Yball_eat ? j + 1 :
10274 i == Ykey_1_eat ? j + 1 :
10275 i == Ykey_2_eat ? j + 1 :
10276 i == Ykey_3_eat ? j + 1 :
10277 i == Ykey_4_eat ? j + 1 :
10278 i == Ykey_5_eat ? j + 1 :
10279 i == Ykey_6_eat ? j + 1 :
10280 i == Ykey_7_eat ? j + 1 :
10281 i == Ykey_8_eat ? j + 1 :
10282 i == Ylenses_eat ? j + 1 :
10283 i == Ymagnify_eat ? j + 1 :
10284 i == Ygrass_eat ? j + 1 :
10285 i == Ydirt_eat ? j + 1 :
10286 i == Xamoeba_1 ? 0 :
10287 i == Xamoeba_2 ? 1 :
10288 i == Xamoeba_3 ? 2 :
10289 i == Xamoeba_4 ? 3 :
10290 i == Xamoeba_5 ? 0 :
10291 i == Xamoeba_6 ? 1 :
10292 i == Xamoeba_7 ? 2 :
10293 i == Xamoeba_8 ? 3 :
10294 i == Xexit_2 ? j + 8 :
10295 i == Xexit_3 ? j + 16 :
10296 i == Xdynamite_1 ? 0 :
10297 i == Xdynamite_2 ? 8 :
10298 i == Xdynamite_3 ? 16 :
10299 i == Xdynamite_4 ? 24 :
10300 i == Xsand_stonein_1 ? j + 1 :
10301 i == Xsand_stonein_2 ? j + 9 :
10302 i == Xsand_stonein_3 ? j + 17 :
10303 i == Xsand_stonein_4 ? j + 25 :
10304 i == Xsand_stoneout_1 && j == 0 ? 0 :
10305 i == Xsand_stoneout_1 && j == 1 ? 0 :
10306 i == Xsand_stoneout_1 && j == 2 ? 1 :
10307 i == Xsand_stoneout_1 && j == 3 ? 2 :
10308 i == Xsand_stoneout_1 && j == 4 ? 2 :
10309 i == Xsand_stoneout_1 && j == 5 ? 3 :
10310 i == Xsand_stoneout_1 && j == 6 ? 4 :
10311 i == Xsand_stoneout_1 && j == 7 ? 4 :
10312 i == Xsand_stoneout_2 && j == 0 ? 5 :
10313 i == Xsand_stoneout_2 && j == 1 ? 6 :
10314 i == Xsand_stoneout_2 && j == 2 ? 7 :
10315 i == Xsand_stoneout_2 && j == 3 ? 8 :
10316 i == Xsand_stoneout_2 && j == 4 ? 9 :
10317 i == Xsand_stoneout_2 && j == 5 ? 11 :
10318 i == Xsand_stoneout_2 && j == 6 ? 13 :
10319 i == Xsand_stoneout_2 && j == 7 ? 15 :
10320 i == Xboom_bug && j == 1 ? 2 :
10321 i == Xboom_bug && j == 2 ? 2 :
10322 i == Xboom_bug && j == 3 ? 4 :
10323 i == Xboom_bug && j == 4 ? 4 :
10324 i == Xboom_bug && j == 5 ? 2 :
10325 i == Xboom_bug && j == 6 ? 2 :
10326 i == Xboom_bug && j == 7 ? 0 :
10327 i == Xboom_bomb && j == 1 ? 2 :
10328 i == Xboom_bomb && j == 2 ? 2 :
10329 i == Xboom_bomb && j == 3 ? 4 :
10330 i == Xboom_bomb && j == 4 ? 4 :
10331 i == Xboom_bomb && j == 5 ? 2 :
10332 i == Xboom_bomb && j == 6 ? 2 :
10333 i == Xboom_bomb && j == 7 ? 0 :
10334 i == Xboom_android && j == 7 ? 6 :
10335 i == Xboom_1 && j == 1 ? 2 :
10336 i == Xboom_1 && j == 2 ? 2 :
10337 i == Xboom_1 && j == 3 ? 4 :
10338 i == Xboom_1 && j == 4 ? 4 :
10339 i == Xboom_1 && j == 5 ? 6 :
10340 i == Xboom_1 && j == 6 ? 6 :
10341 i == Xboom_1 && j == 7 ? 8 :
10342 i == Xboom_2 && j == 0 ? 8 :
10343 i == Xboom_2 && j == 1 ? 8 :
10344 i == Xboom_2 && j == 2 ? 10 :
10345 i == Xboom_2 && j == 3 ? 10 :
10346 i == Xboom_2 && j == 4 ? 10 :
10347 i == Xboom_2 && j == 5 ? 12 :
10348 i == Xboom_2 && j == 6 ? 12 :
10349 i == Xboom_2 && j == 7 ? 12 :
10350 special_animation && j == 4 ? 3 :
10351 effective_action != action ? 0 :
10355 Bitmap *debug_bitmap = g_em->bitmap;
10356 int debug_src_x = g_em->src_x;
10357 int debug_src_y = g_em->src_y;
10360 int frame = getAnimationFrame(g->anim_frames,
10363 g->anim_start_frame,
10366 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y,
10367 g->double_movement && is_backside);
10369 g_em->bitmap = src_bitmap;
10370 g_em->src_x = src_x;
10371 g_em->src_y = src_y;
10372 g_em->src_offset_x = 0;
10373 g_em->src_offset_y = 0;
10374 g_em->dst_offset_x = 0;
10375 g_em->dst_offset_y = 0;
10376 g_em->width = TILEX;
10377 g_em->height = TILEY;
10379 g_em->preserve_background = FALSE;
10382 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
10387 g_em->crumbled_bitmap = NULL;
10388 g_em->crumbled_src_x = 0;
10389 g_em->crumbled_src_y = 0;
10390 g_em->crumbled_border_size = 0;
10392 g_em->has_crumbled_graphics = FALSE;
10395 if (has_crumbled_graphics && crumbled == IMG_EMPTY_SPACE)
10396 printf("::: empty crumbled: %d [%s], %d, %d\n",
10397 effective_element, element_info[effective_element].token_name,
10398 effective_action, direction);
10401 /* if element can be crumbled, but certain action graphics are just empty
10402 space (like instantly snapping sand to empty space in 1 frame), do not
10403 treat these empty space graphics as crumbled graphics in EMC engine */
10404 if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
10406 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
10407 g_crumbled->anim_delay,
10408 g_crumbled->anim_mode,
10409 g_crumbled->anim_start_frame,
10412 getGraphicSource(crumbled, frame_crumbled, &src_bitmap, &src_x, &src_y);
10414 g_em->has_crumbled_graphics = TRUE;
10415 g_em->crumbled_bitmap = src_bitmap;
10416 g_em->crumbled_src_x = src_x;
10417 g_em->crumbled_src_y = src_y;
10418 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
10422 if (g_em == &graphic_info_em_object[207][0])
10423 printf("... %d, %d [%d, %d, %d, %d] [%d, %d, %d, %d, %d, %d => %d]\n",
10424 graphic_info_em_object[207][0].crumbled_src_x,
10425 graphic_info_em_object[207][0].crumbled_src_y,
10427 crumbled, frame, src_x, src_y,
10432 g->anim_start_frame,
10434 gfx.anim_random_frame,
10439 printf("::: EMC tile %d is crumbled\n", i);
10445 if (element == EL_ROCK &&
10446 effective_action == ACTION_FILLING)
10447 printf("::: has_action_graphics == %d\n", has_action_graphics);
10450 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
10451 effective_action == ACTION_MOVING ||
10452 effective_action == ACTION_PUSHING ||
10453 effective_action == ACTION_EATING)) ||
10454 (!has_action_graphics && (effective_action == ACTION_FILLING ||
10455 effective_action == ACTION_EMPTYING)))
10458 (effective_action == ACTION_FALLING ||
10459 effective_action == ACTION_FILLING ||
10460 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
10461 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
10462 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
10463 int num_steps = (i == Ydrip_s1 ? 16 :
10464 i == Ydrip_s1B ? 16 :
10465 i == Ydrip_s2 ? 16 :
10466 i == Ydrip_s2B ? 16 :
10467 i == Xsand_stonein_1 ? 32 :
10468 i == Xsand_stonein_2 ? 32 :
10469 i == Xsand_stonein_3 ? 32 :
10470 i == Xsand_stonein_4 ? 32 :
10471 i == Xsand_stoneout_1 ? 16 :
10472 i == Xsand_stoneout_2 ? 16 : 8);
10473 int cx = ABS(dx) * (TILEX / num_steps);
10474 int cy = ABS(dy) * (TILEY / num_steps);
10475 int step_frame = (i == Ydrip_s2 ? j + 8 :
10476 i == Ydrip_s2B ? j + 8 :
10477 i == Xsand_stonein_2 ? j + 8 :
10478 i == Xsand_stonein_3 ? j + 16 :
10479 i == Xsand_stonein_4 ? j + 24 :
10480 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
10481 int step = (is_backside ? step_frame : num_steps - step_frame);
10483 if (is_backside) /* tile where movement starts */
10485 if (dx < 0 || dy < 0)
10487 g_em->src_offset_x = cx * step;
10488 g_em->src_offset_y = cy * step;
10492 g_em->dst_offset_x = cx * step;
10493 g_em->dst_offset_y = cy * step;
10496 else /* tile where movement ends */
10498 if (dx < 0 || dy < 0)
10500 g_em->dst_offset_x = cx * step;
10501 g_em->dst_offset_y = cy * step;
10505 g_em->src_offset_x = cx * step;
10506 g_em->src_offset_y = cy * step;
10510 g_em->width = TILEX - cx * step;
10511 g_em->height = TILEY - cy * step;
10514 /* create unique graphic identifier to decide if tile must be redrawn */
10515 /* bit 31 - 16 (16 bit): EM style graphic
10516 bit 15 - 12 ( 4 bit): EM style frame
10517 bit 11 - 6 ( 6 bit): graphic width
10518 bit 5 - 0 ( 6 bit): graphic height */
10519 g_em->unique_identifier =
10520 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
10524 /* skip check for EMC elements not contained in original EMC artwork */
10525 if (element == EL_EMC_FAKE_ACID)
10528 if (g_em->bitmap != debug_bitmap ||
10529 g_em->src_x != debug_src_x ||
10530 g_em->src_y != debug_src_y ||
10531 g_em->src_offset_x != 0 ||
10532 g_em->src_offset_y != 0 ||
10533 g_em->dst_offset_x != 0 ||
10534 g_em->dst_offset_y != 0 ||
10535 g_em->width != TILEX ||
10536 g_em->height != TILEY)
10538 static int last_i = -1;
10546 printf("::: EMC GFX ERROR for element %d -> %d ('%s', '%s', %d)",
10547 i, element, element_info[element].token_name,
10548 element_action_info[effective_action].suffix, direction);
10550 if (element != effective_element)
10551 printf(" [%d ('%s')]",
10553 element_info[effective_element].token_name);
10557 if (g_em->bitmap != debug_bitmap)
10558 printf(" %d (%d): different bitmap! (0x%08x != 0x%08x)\n",
10559 j, is_backside, (int)(g_em->bitmap), (int)(debug_bitmap));
10561 if (g_em->src_x != debug_src_x ||
10562 g_em->src_y != debug_src_y)
10563 printf(" frame %d (%c): %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
10564 j, (is_backside ? 'B' : 'F'),
10565 g_em->src_x, g_em->src_y,
10566 g_em->src_x / 32, g_em->src_y / 32,
10567 debug_src_x, debug_src_y,
10568 debug_src_x / 32, debug_src_y / 32);
10570 if (g_em->src_offset_x != 0 ||
10571 g_em->src_offset_y != 0 ||
10572 g_em->dst_offset_x != 0 ||
10573 g_em->dst_offset_y != 0)
10574 printf(" %d (%d): offsets %d,%d and %d,%d should be all 0\n",
10576 g_em->src_offset_x, g_em->src_offset_y,
10577 g_em->dst_offset_x, g_em->dst_offset_y);
10579 if (g_em->width != TILEX ||
10580 g_em->height != TILEY)
10581 printf(" %d (%d): size %d,%d should be %d,%d\n",
10583 g_em->width, g_em->height, TILEX, TILEY);
10585 num_em_gfx_errors++;
10592 for (i = 0; i < TILE_MAX; i++)
10594 for (j = 0; j < 8; j++)
10596 int element = object_mapping[i].element_rnd;
10597 int action = object_mapping[i].action;
10598 int direction = object_mapping[i].direction;
10599 boolean is_backside = object_mapping[i].is_backside;
10600 int graphic_action = el_act_dir2img(element, action, direction);
10601 int graphic_default = el_act_dir2img(element, ACTION_DEFAULT, direction);
10603 if ((action == ACTION_SMASHED_BY_ROCK ||
10604 action == ACTION_SMASHED_BY_SPRING ||
10605 action == ACTION_EATING) &&
10606 graphic_action == graphic_default)
10608 int e = (action == ACTION_SMASHED_BY_ROCK ? Ystone_s :
10609 action == ACTION_SMASHED_BY_SPRING ? Yspring_s :
10610 direction == MV_LEFT ? (is_backside? Yspring_wB: Yspring_w) :
10611 direction == MV_RIGHT ? (is_backside? Yspring_eB: Yspring_e) :
10614 /* no separate animation for "smashed by rock" -- use rock instead */
10615 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
10616 struct GraphicInfo_EM *g_xx = &graphic_info_em_object[e][7 - j];
10618 g_em->bitmap = g_xx->bitmap;
10619 g_em->src_x = g_xx->src_x;
10620 g_em->src_y = g_xx->src_y;
10621 g_em->src_offset_x = g_xx->src_offset_x;
10622 g_em->src_offset_y = g_xx->src_offset_y;
10623 g_em->dst_offset_x = g_xx->dst_offset_x;
10624 g_em->dst_offset_y = g_xx->dst_offset_y;
10625 g_em->width = g_xx->width;
10626 g_em->height = g_xx->height;
10627 g_em->unique_identifier = g_xx->unique_identifier;
10630 g_em->preserve_background = TRUE;
10635 for (p = 0; p < MAX_PLAYERS; p++)
10637 for (i = 0; i < SPR_MAX; i++)
10639 int element = player_mapping[p][i].element_rnd;
10640 int action = player_mapping[p][i].action;
10641 int direction = player_mapping[p][i].direction;
10643 for (j = 0; j < 8; j++)
10645 int effective_element = element;
10646 int effective_action = action;
10647 int graphic = (direction == MV_NONE ?
10648 el_act2img(effective_element, effective_action) :
10649 el_act_dir2img(effective_element, effective_action,
10651 struct GraphicInfo *g = &graphic_info[graphic];
10652 struct GraphicInfo_EM *g_em = &graphic_info_em_player[p][i][7 - j];
10653 Bitmap *src_bitmap;
10655 int sync_frame = j;
10658 Bitmap *debug_bitmap = g_em->bitmap;
10659 int debug_src_x = g_em->src_x;
10660 int debug_src_y = g_em->src_y;
10663 int frame = getAnimationFrame(g->anim_frames,
10666 g->anim_start_frame,
10669 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
10671 g_em->bitmap = src_bitmap;
10672 g_em->src_x = src_x;
10673 g_em->src_y = src_y;
10674 g_em->src_offset_x = 0;
10675 g_em->src_offset_y = 0;
10676 g_em->dst_offset_x = 0;
10677 g_em->dst_offset_y = 0;
10678 g_em->width = TILEX;
10679 g_em->height = TILEY;
10683 /* skip check for EMC elements not contained in original EMC artwork */
10684 if (element == EL_PLAYER_3 ||
10685 element == EL_PLAYER_4)
10688 if (g_em->bitmap != debug_bitmap ||
10689 g_em->src_x != debug_src_x ||
10690 g_em->src_y != debug_src_y)
10692 static int last_i = -1;
10700 printf("::: EMC GFX ERROR for p/a %d/%d -> %d ('%s', '%s', %d)",
10701 p, i, element, element_info[element].token_name,
10702 element_action_info[effective_action].suffix, direction);
10704 if (element != effective_element)
10705 printf(" [%d ('%s')]",
10707 element_info[effective_element].token_name);
10711 if (g_em->bitmap != debug_bitmap)
10712 printf(" %d: different bitmap! (0x%08x != 0x%08x)\n",
10713 j, (int)(g_em->bitmap), (int)(debug_bitmap));
10715 if (g_em->src_x != debug_src_x ||
10716 g_em->src_y != debug_src_y)
10717 printf(" frame %d: %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
10719 g_em->src_x, g_em->src_y,
10720 g_em->src_x / 32, g_em->src_y / 32,
10721 debug_src_x, debug_src_y,
10722 debug_src_x / 32, debug_src_y / 32);
10724 num_em_gfx_errors++;
10734 printf("::: [%d errors found]\n", num_em_gfx_errors);
10740 void CheckSingleStepMode_EM(byte action[MAX_PLAYERS], int frame,
10741 boolean any_player_moving,
10742 boolean player_is_dropping)
10744 if (tape.single_step && tape.recording && !tape.pausing)
10747 boolean active_players = FALSE;
10750 for (i = 0; i < MAX_PLAYERS; i++)
10751 if (action[i] != JOY_NO_ACTION)
10752 active_players = TRUE;
10756 if (frame == 0 && !player_is_dropping)
10757 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
10761 void CheckSingleStepMode_SP(boolean murphy_is_waiting,
10762 boolean murphy_is_dropping)
10765 printf("::: waiting: %d, dropping: %d\n",
10766 murphy_is_waiting, murphy_is_dropping);
10769 if (tape.single_step && tape.recording && !tape.pausing)
10771 // if (murphy_is_waiting || murphy_is_dropping)
10772 if (murphy_is_waiting)
10775 printf("::: murphy is waiting -> pause mode\n");
10778 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
10783 void getGraphicSource_SP(struct GraphicInfo_SP *g_sp,
10784 int graphic, int sync_frame, int x, int y)
10786 int frame = getGraphicAnimationFrame(graphic, sync_frame);
10788 getGraphicSource(graphic, frame, &g_sp->bitmap, &g_sp->src_x, &g_sp->src_y);
10791 boolean isNextAnimationFrame_SP(int graphic, int sync_frame)
10793 return (IS_NEXT_FRAME(sync_frame, graphic));
10796 int getGraphicInfo_Delay(int graphic)
10798 return graphic_info[graphic].anim_delay;
10801 void PlayMenuSoundExt(int sound)
10803 if (sound == SND_UNDEFINED)
10806 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
10807 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
10810 if (IS_LOOP_SOUND(sound))
10811 PlaySoundLoop(sound);
10816 void PlayMenuSound()
10818 PlayMenuSoundExt(menu.sound[game_status]);
10821 void PlayMenuSoundStereo(int sound, int stereo_position)
10823 if (sound == SND_UNDEFINED)
10826 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
10827 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
10830 if (IS_LOOP_SOUND(sound))
10831 PlaySoundExt(sound, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_LOOP);
10833 PlaySoundStereo(sound, stereo_position);
10836 void PlayMenuSoundIfLoopExt(int sound)
10838 if (sound == SND_UNDEFINED)
10841 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
10842 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
10845 if (IS_LOOP_SOUND(sound))
10846 PlaySoundLoop(sound);
10849 void PlayMenuSoundIfLoop()
10851 PlayMenuSoundIfLoopExt(menu.sound[game_status]);
10854 void PlayMenuMusicExt(int music)
10856 if (music == MUS_UNDEFINED)
10859 if (!setup.sound_music)
10865 void PlayMenuMusic()
10867 PlayMenuMusicExt(menu.music[game_status]);
10870 void PlaySoundActivating()
10873 PlaySound(SND_MENU_ITEM_ACTIVATING);
10877 void PlaySoundSelecting()
10880 PlaySound(SND_MENU_ITEM_SELECTING);
10884 void ToggleFullscreenOrChangeWindowScalingIfNeeded()
10886 boolean change_fullscreen = (setup.fullscreen !=
10887 video.fullscreen_enabled);
10888 boolean change_fullscreen_mode = (video.fullscreen_enabled &&
10889 !strEqual(setup.fullscreen_mode,
10890 video.fullscreen_mode_current));
10891 boolean change_window_scaling_percent = (!video.fullscreen_enabled &&
10892 setup.window_scaling_percent !=
10893 video.window_scaling_percent);
10895 if (change_window_scaling_percent && video.fullscreen_enabled)
10898 if (!change_window_scaling_percent && !video.fullscreen_available)
10901 #if defined(TARGET_SDL2)
10902 if (change_window_scaling_percent)
10904 SDLSetWindowScaling(setup.window_scaling_percent);
10908 else if (change_fullscreen)
10910 SDLSetWindowFullscreen(setup.fullscreen);
10912 /* set setup value according to successfully changed fullscreen mode */
10913 setup.fullscreen = video.fullscreen_enabled;
10919 if (change_fullscreen ||
10920 change_fullscreen_mode ||
10921 change_window_scaling_percent)
10923 Bitmap *tmp_backbuffer = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
10925 /* save backbuffer content which gets lost when toggling fullscreen mode */
10926 BlitBitmap(backbuffer, tmp_backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
10928 if (change_fullscreen_mode)
10930 /* keep fullscreen, but change fullscreen mode (screen resolution) */
10931 video.fullscreen_enabled = FALSE; /* force new fullscreen mode */
10934 if (change_window_scaling_percent)
10936 /* keep window mode, but change window scaling */
10937 video.fullscreen_enabled = TRUE; /* force new window scaling */
10940 /* toggle fullscreen */
10941 ChangeVideoModeIfNeeded(setup.fullscreen);
10943 /* set setup value according to successfully changed fullscreen mode */
10944 setup.fullscreen = video.fullscreen_enabled;
10946 /* restore backbuffer content from temporary backbuffer backup bitmap */
10947 BlitBitmap(tmp_backbuffer, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
10949 FreeBitmap(tmp_backbuffer);
10952 /* update visible window/screen */
10953 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
10955 redraw_mask = REDRAW_ALL;
10960 void ChangeViewportPropertiesIfNeeded()
10963 int *door_1_x = &DX;
10964 int *door_1_y = &DY;
10965 int *door_2_x = (game_status == GAME_MODE_EDITOR ? &EX : &VX);
10966 int *door_2_y = (game_status == GAME_MODE_EDITOR ? &EY : &VY);
10968 int gfx_game_mode = (game_status == GAME_MODE_PLAYING ||
10969 game_status == GAME_MODE_EDITOR ? game_status :
10971 int gfx_game_mode2 = (game_status == GAME_MODE_EDITOR ? GAME_MODE_DEFAULT :
10973 struct RectWithBorder *vp_playfield = &viewport.playfield[gfx_game_mode];
10974 struct RectWithBorder *vp_door_1 = &viewport.door_1[gfx_game_mode];
10975 struct RectWithBorder *vp_door_2 = &viewport.door_2[gfx_game_mode2];
10976 struct RectWithBorder *vp_door_3 = &viewport.door_2[GAME_MODE_EDITOR];
10977 int border_size = vp_playfield->border_size;
10978 int new_sx = vp_playfield->x + border_size;
10979 int new_sy = vp_playfield->y + border_size;
10980 int new_sxsize = vp_playfield->width - 2 * border_size;
10981 int new_sysize = vp_playfield->height - 2 * border_size;
10982 int new_real_sx = vp_playfield->x;
10983 int new_real_sy = vp_playfield->y;
10984 int new_full_sxsize = vp_playfield->width;
10985 int new_full_sysize = vp_playfield->height;
10986 int new_dx = vp_door_1->x;
10987 int new_dy = vp_door_1->y;
10988 int new_dxsize = vp_door_1->width;
10989 int new_dysize = vp_door_1->height;
10990 int new_vx = vp_door_2->x;
10991 int new_vy = vp_door_2->y;
10992 int new_vxsize = vp_door_2->width;
10993 int new_vysize = vp_door_2->height;
10994 int new_ex = vp_door_3->x;
10995 int new_ey = vp_door_3->y;
10996 int new_exsize = vp_door_3->width;
10997 int new_eysize = vp_door_3->height;
10999 int new_tilesize_var = TILESIZE / (setup.small_game_graphics ? 2 : 1);
11000 int tilesize = (gfx_game_mode == GAME_MODE_PLAYING ? new_tilesize_var :
11001 gfx_game_mode == GAME_MODE_EDITOR ? MINI_TILESIZE : TILESIZE);
11002 int new_scr_fieldx = new_sxsize / tilesize;
11003 int new_scr_fieldy = new_sysize / tilesize;
11004 int new_scr_fieldx_buffers = new_sxsize / new_tilesize_var;
11005 int new_scr_fieldy_buffers = new_sysize / new_tilesize_var;
11007 int new_scr_fieldx = (vp_playfield->width - 2 * border_size) / TILESIZE;
11008 int new_scr_fieldy = (vp_playfield->height - 2 * border_size) / TILESIZE;
11010 boolean init_gfx_buffers = FALSE;
11011 boolean init_video_buffer = FALSE;
11012 boolean init_gadgets_and_toons = FALSE;
11015 /* !!! TEST ONLY !!! */
11016 // InitGfxBuffers();
11020 if (viewport.window.width != WIN_XSIZE ||
11021 viewport.window.height != WIN_YSIZE)
11023 WIN_XSIZE = viewport.window.width;
11024 WIN_YSIZE = viewport.window.height;
11027 init_video_buffer = TRUE;
11028 init_gfx_buffers = TRUE;
11030 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
11034 SetDrawDeactivationMask(REDRAW_NONE);
11035 SetDrawBackgroundMask(REDRAW_FIELD);
11037 // RedrawBackground();
11041 // printf("::: video: init_video_buffer, init_gfx_buffers\n");
11044 if (new_scr_fieldx != SCR_FIELDX ||
11045 new_scr_fieldy != SCR_FIELDY)
11047 /* this always toggles between MAIN and GAME when using small tile size */
11049 SCR_FIELDX = new_scr_fieldx;
11050 SCR_FIELDY = new_scr_fieldy;
11052 // printf("::: new_scr_fieldx != SCR_FIELDX ...\n");
11056 if (new_tilesize_var != TILESIZE_VAR &&
11057 gfx_game_mode == GAME_MODE_PLAYING)
11059 /* doing this outside GAME_MODE_PLAYING would give wrong playfield size */
11061 TILESIZE_VAR = new_tilesize_var;
11063 init_gfx_buffers = TRUE;
11065 // printf("::: tilesize: init_gfx_buffers\n");
11069 if (new_sx != SX ||
11077 new_sxsize != SXSIZE ||
11078 new_sysize != SYSIZE ||
11079 new_dxsize != DXSIZE ||
11080 new_dysize != DYSIZE ||
11081 new_vxsize != VXSIZE ||
11082 new_vysize != VYSIZE ||
11083 new_exsize != EXSIZE ||
11084 new_eysize != EYSIZE ||
11085 new_real_sx != REAL_SX ||
11086 new_real_sy != REAL_SY ||
11087 new_full_sxsize != FULL_SXSIZE ||
11088 new_full_sysize != FULL_SYSIZE ||
11089 new_tilesize_var != TILESIZE_VAR
11092 vp_door_1->x != *door_1_x ||
11093 vp_door_1->y != *door_1_y ||
11094 vp_door_2->x != *door_2_x ||
11095 vp_door_2->y != *door_2_y
11107 SXSIZE = new_sxsize;
11108 SYSIZE = new_sysize;
11109 DXSIZE = new_dxsize;
11110 DYSIZE = new_dysize;
11111 VXSIZE = new_vxsize;
11112 VYSIZE = new_vysize;
11113 EXSIZE = new_exsize;
11114 EYSIZE = new_eysize;
11115 REAL_SX = new_real_sx;
11116 REAL_SY = new_real_sy;
11117 FULL_SXSIZE = new_full_sxsize;
11118 FULL_SYSIZE = new_full_sysize;
11119 TILESIZE_VAR = new_tilesize_var;
11122 printf("::: %d, %d, %d [%d]\n",
11123 SCR_FIELDX, SCR_FIELDY, TILESIZE_VAR,
11124 setup.small_game_graphics);
11128 *door_1_x = vp_door_1->x;
11129 *door_1_y = vp_door_1->y;
11130 *door_2_x = vp_door_2->x;
11131 *door_2_y = vp_door_2->y;
11135 init_gfx_buffers = TRUE;
11137 // printf("::: viewports: init_gfx_buffers\n");
11142 if (gfx_game_mode == GAME_MODE_MAIN)
11145 init_gadgets_and_toons = TRUE;
11147 // printf("::: viewports: init_gadgets_and_toons\n");
11155 if (init_gfx_buffers)
11157 // printf("::: init_gfx_buffers\n");
11159 SCR_FIELDX = new_scr_fieldx_buffers;
11160 SCR_FIELDY = new_scr_fieldy_buffers;
11164 SCR_FIELDX = new_scr_fieldx;
11165 SCR_FIELDY = new_scr_fieldy;
11168 if (init_video_buffer)
11170 // printf("::: init_video_buffer\n");
11172 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
11174 SetDrawDeactivationMask(REDRAW_NONE);
11175 SetDrawBackgroundMask(REDRAW_FIELD);
11178 if (init_gadgets_and_toons)
11180 // printf("::: init_gadgets_and_toons\n");
11187 printf("::: %d, %d / %d, %d [%d]\n", VX, VY, EX, EY, game_status);