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"
25 /* select level set with EMC X11 graphics before activating EM GFX debugging */
26 #define DEBUG_EM_GFX 0
28 /* tool button identifiers */
29 #define TOOL_CTRL_ID_YES 0
30 #define TOOL_CTRL_ID_NO 1
31 #define TOOL_CTRL_ID_CONFIRM 2
32 #define TOOL_CTRL_ID_PLAYER_1 3
33 #define TOOL_CTRL_ID_PLAYER_2 4
34 #define TOOL_CTRL_ID_PLAYER_3 5
35 #define TOOL_CTRL_ID_PLAYER_4 6
37 #define NUM_TOOL_BUTTONS 7
39 /* forward declaration for internal use */
40 static void UnmapToolButtons();
41 static void HandleToolButtons(struct GadgetInfo *);
42 static int el_act_dir2crm(int, int, int);
43 static int el_act2crm(int, int);
45 static struct GadgetInfo *tool_gadget[NUM_TOOL_BUTTONS];
46 static int request_gadget_id = -1;
48 static char *print_if_not_empty(int element)
50 static char *s = NULL;
51 char *token_name = element_info[element].token_name;
56 s = checked_malloc(strlen(token_name) + 10 + 1);
58 if (element != EL_EMPTY)
59 sprintf(s, "%d\t['%s']", element, token_name);
61 sprintf(s, "%d", element);
66 void DumpTile(int x, int y)
71 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
78 printf("Field Info: SCREEN(%d, %d), LEVEL(%d, %d)\n", sx, sy, x, y);
81 if (!IN_LEV_FIELD(x, y))
83 printf("(not in level field)\n");
89 printf(" Feld: %d\t['%s']\n", Feld[x][y],
90 element_info[Feld[x][y]].token_name);
91 printf(" Back: %s\n", print_if_not_empty(Back[x][y]));
92 printf(" Store: %s\n", print_if_not_empty(Store[x][y]));
93 printf(" Store2: %s\n", print_if_not_empty(Store2[x][y]));
94 printf(" StorePlayer: %s\n", print_if_not_empty(StorePlayer[x][y]));
95 printf(" MovPos: %d\n", MovPos[x][y]);
96 printf(" MovDir: %d\n", MovDir[x][y]);
97 printf(" MovDelay: %d\n", MovDelay[x][y]);
98 printf(" ChangeDelay: %d\n", ChangeDelay[x][y]);
99 printf(" CustomValue: %d\n", CustomValue[x][y]);
100 printf(" GfxElement: %d\n", GfxElement[x][y]);
101 printf(" GfxAction: %d\n", GfxAction[x][y]);
102 printf(" GfxFrame: %d\n", GfxFrame[x][y]);
106 void SetDrawtoField(int mode)
108 if (mode == DRAW_BUFFERED && setup.soft_scrolling)
119 drawto_field = fieldbuffer;
121 else /* DRAW_DIRECT, DRAW_BACKBUFFER */
127 BX2 = SCR_FIELDX - 1;
128 BY2 = SCR_FIELDY - 1;
132 drawto_field = (mode == DRAW_DIRECT ? window : backbuffer);
136 void RedrawPlayfield(boolean force_redraw, int x, int y, int width, int height)
138 if (game_status == GAME_MODE_PLAYING &&
139 level.game_engine_type == GAME_ENGINE_TYPE_EM)
141 /* currently there is no partial redraw -- always redraw whole playfield */
142 RedrawPlayfield_EM(TRUE);
144 /* blit playfield from scroll buffer to normal back buffer for fading in */
145 BlitScreenToBitmap_EM(backbuffer);
147 else if (game_status == GAME_MODE_PLAYING && !game.envelope_active)
153 width = gfx.sxsize + 2 * TILEX;
154 height = gfx.sysize + 2 * TILEY;
157 if (force_redraw || setup.direct_draw)
160 int x1 = (x - SX) / TILEX, y1 = (y - SY) / TILEY;
161 int x2 = (x - SX + width) / TILEX, y2 = (y - SY + height) / TILEY;
163 if (setup.direct_draw)
164 SetDrawtoField(DRAW_BACKBUFFER);
166 for (xx = BX1; xx <= BX2; xx++)
167 for (yy = BY1; yy <= BY2; yy++)
168 if (xx >= x1 && xx <= x2 && yy >= y1 && yy <= y2)
169 DrawScreenField(xx, yy);
172 if (setup.direct_draw)
173 SetDrawtoField(DRAW_DIRECT);
176 if (setup.soft_scrolling)
178 int fx = FX, fy = FY;
180 fx += (ScreenMovDir & (MV_LEFT|MV_RIGHT) ? ScreenGfxPos : 0);
181 fy += (ScreenMovDir & (MV_UP|MV_DOWN) ? ScreenGfxPos : 0);
183 BlitBitmap(fieldbuffer, backbuffer, fx,fy, SXSIZE,SYSIZE, SX,SY);
195 BlitBitmap(drawto, window, x, y, width, height, x, y);
198 void DrawMaskedBorder_Rect(int x, int y, int width, int height)
200 Bitmap *bitmap = graphic_info[IMG_GLOBAL_BORDER].bitmap;
202 SetClipOrigin(bitmap, bitmap->stored_clip_gc, 0, 0);
203 BlitBitmapMasked(bitmap, backbuffer, x, y, width, height, x, y);
206 void DrawMaskedBorder_FIELD()
208 if (global.border_status >= GAME_MODE_TITLE &&
209 global.border_status <= GAME_MODE_PLAYING &&
210 border.draw_masked[global.border_status])
211 DrawMaskedBorder_Rect(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
214 void DrawMaskedBorder_DOOR_1()
216 if (border.draw_masked[GFX_SPECIAL_ARG_DOOR] &&
217 (global.border_status != GAME_MODE_EDITOR ||
218 border.draw_masked[GFX_SPECIAL_ARG_EDITOR]))
219 DrawMaskedBorder_Rect(DX, DY, DXSIZE, DYSIZE);
222 void DrawMaskedBorder_DOOR_2()
224 if (border.draw_masked[GFX_SPECIAL_ARG_DOOR] &&
225 global.border_status != GAME_MODE_EDITOR)
226 DrawMaskedBorder_Rect(VX, VY, VXSIZE, VYSIZE);
229 void DrawMaskedBorder_DOOR_3()
231 /* currently not available */
234 void DrawMaskedBorder_ALL()
236 DrawMaskedBorder_FIELD();
237 DrawMaskedBorder_DOOR_1();
238 DrawMaskedBorder_DOOR_2();
239 DrawMaskedBorder_DOOR_3();
242 void DrawMaskedBorder(int redraw_mask)
244 /* do not draw masked screen borders when displaying title screens */
245 if (effectiveGameStatus() == GAME_MODE_TITLE)
248 if (redraw_mask & REDRAW_ALL)
249 DrawMaskedBorder_ALL();
252 if (redraw_mask & REDRAW_FIELD)
253 DrawMaskedBorder_FIELD();
254 if (redraw_mask & REDRAW_DOOR_1)
255 DrawMaskedBorder_DOOR_1();
256 if (redraw_mask & REDRAW_DOOR_2)
257 DrawMaskedBorder_DOOR_2();
258 if (redraw_mask & REDRAW_DOOR_3)
259 DrawMaskedBorder_DOOR_3();
266 DrawBuffer *buffer = (drawto_field == window ? backbuffer : drawto_field);
268 if (setup.direct_draw && game_status == GAME_MODE_PLAYING)
269 redraw_mask &= ~REDRAW_MAIN;
271 if (redraw_mask & REDRAW_TILES && redraw_tiles > REDRAWTILES_THRESHOLD)
272 redraw_mask |= REDRAW_FIELD;
274 if (redraw_mask & REDRAW_FIELD)
275 redraw_mask &= ~REDRAW_TILES;
277 if (redraw_mask == REDRAW_NONE)
280 if (redraw_mask & REDRAW_TILES &&
281 game_status == GAME_MODE_PLAYING &&
282 border.draw_masked[GAME_MODE_PLAYING])
283 redraw_mask |= REDRAW_FIELD;
285 if (global.fps_slowdown && game_status == GAME_MODE_PLAYING)
287 static boolean last_frame_skipped = FALSE;
288 boolean skip_even_when_not_scrolling = TRUE;
289 boolean just_scrolling = (ScreenMovDir != 0);
290 boolean verbose = FALSE;
292 if (global.fps_slowdown_factor > 1 &&
293 (FrameCounter % global.fps_slowdown_factor) &&
294 (just_scrolling || skip_even_when_not_scrolling))
296 redraw_mask &= ~REDRAW_MAIN;
298 last_frame_skipped = TRUE;
301 printf("FRAME SKIPPED\n");
305 if (last_frame_skipped)
306 redraw_mask |= REDRAW_FIELD;
308 last_frame_skipped = FALSE;
311 printf("frame not skipped\n");
315 /* synchronize X11 graphics at this point; if we would synchronize the
316 display immediately after the buffer switching (after the XFlush),
317 this could mean that we have to wait for the graphics to complete,
318 although we could go on doing calculations for the next frame */
322 /* prevent drawing masked border to backbuffer when using playfield buffer */
323 if (game_status != GAME_MODE_PLAYING ||
324 redraw_mask & REDRAW_FROM_BACKBUFFER ||
325 buffer == backbuffer)
326 DrawMaskedBorder(redraw_mask);
328 DrawMaskedBorder(redraw_mask & REDRAW_DOORS);
330 if (redraw_mask & REDRAW_ALL)
332 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
334 redraw_mask = REDRAW_NONE;
337 if (redraw_mask & REDRAW_FIELD)
339 if (game_status != GAME_MODE_PLAYING ||
340 redraw_mask & REDRAW_FROM_BACKBUFFER)
342 BlitBitmap(backbuffer, window,
343 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE, REAL_SX, REAL_SY);
347 int fx = FX, fy = FY;
349 if (setup.soft_scrolling)
351 fx += (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
352 fy += (ScreenMovDir & (MV_UP | MV_DOWN) ? ScreenGfxPos : 0);
355 if (setup.soft_scrolling ||
356 ABS(ScreenMovPos) + ScrollStepSize == TILEX ||
357 ABS(ScreenMovPos) == ScrollStepSize ||
358 redraw_tiles > REDRAWTILES_THRESHOLD)
360 if (border.draw_masked[GAME_MODE_PLAYING])
362 if (buffer != backbuffer)
364 /* copy playfield buffer to backbuffer to add masked border */
365 BlitBitmap(buffer, backbuffer, fx, fy, SXSIZE, SYSIZE, SX, SY);
366 DrawMaskedBorder(REDRAW_FIELD);
369 BlitBitmap(backbuffer, window,
370 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
375 BlitBitmap(buffer, window, fx, fy, SXSIZE, SYSIZE, SX, SY);
380 printf("redrawing all (ScreenGfxPos == %d) because %s\n",
382 (setup.soft_scrolling ?
383 "setup.soft_scrolling" :
384 ABS(ScreenGfxPos) + ScrollStepSize == TILEX ?
385 "ABS(ScreenGfxPos) + ScrollStepSize == TILEX" :
386 ABS(ScreenGfxPos) == ScrollStepSize ?
387 "ABS(ScreenGfxPos) == ScrollStepSize" :
388 "redraw_tiles > REDRAWTILES_THRESHOLD"));
394 redraw_mask &= ~REDRAW_MAIN;
397 if (redraw_mask & REDRAW_DOORS)
399 if (redraw_mask & REDRAW_DOOR_1)
400 BlitBitmap(backbuffer, window, DX, DY, DXSIZE, DYSIZE, DX, DY);
402 if (redraw_mask & REDRAW_DOOR_2)
403 BlitBitmap(backbuffer, window, VX, VY, VXSIZE, VYSIZE, VX, VY);
405 if (redraw_mask & REDRAW_DOOR_3)
406 BlitBitmap(backbuffer, window, EX, EY, EXSIZE, EYSIZE, EX, EY);
408 redraw_mask &= ~REDRAW_DOORS;
411 if (redraw_mask & REDRAW_MICROLEVEL)
413 BlitBitmap(backbuffer, window, SX, SY + 10 * TILEY, SXSIZE, 7 * TILEY,
414 SX, SY + 10 * TILEY);
416 redraw_mask &= ~REDRAW_MICROLEVEL;
419 if (redraw_mask & REDRAW_TILES)
421 for (x = 0; x < SCR_FIELDX; x++)
422 for (y = 0 ; y < SCR_FIELDY; y++)
423 if (redraw[redraw_x1 + x][redraw_y1 + y])
424 BlitBitmap(buffer, window,
425 FX + x * TILEX, FY + y * TILEY, TILEX, TILEY,
426 SX + x * TILEX, SY + y * TILEY);
429 if (redraw_mask & REDRAW_FPS) /* display frames per second */
434 sprintf(info1, " (only every %d. frame)", global.fps_slowdown_factor);
435 if (!global.fps_slowdown)
438 sprintf(text, "%.1f fps%s", global.frames_per_second, info1);
439 DrawTextExt(window, SX, SY, text, FONT_TEXT_2, BLIT_OPAQUE);
444 for (x = 0; x < MAX_BUF_XSIZE; x++)
445 for (y = 0; y < MAX_BUF_YSIZE; y++)
448 redraw_mask = REDRAW_NONE;
454 long fading_delay = 300;
456 if (setup.fading && (redraw_mask & REDRAW_FIELD))
463 ClearRectangle(window, REAL_SX,REAL_SY,FULL_SXSIZE,FULL_SYSIZE);
466 for (i = 0; i < 2 * FULL_SYSIZE; i++)
468 for (y = 0; y < FULL_SYSIZE; y++)
470 BlitBitmap(backbuffer, window,
471 REAL_SX,REAL_SY+i, FULL_SXSIZE,1, REAL_SX,REAL_SY+i);
479 for (i = 1; i < FULL_SYSIZE; i+=2)
480 BlitBitmap(backbuffer, window,
481 REAL_SX,REAL_SY+i, FULL_SXSIZE,1, REAL_SX,REAL_SY+i);
487 SetClipOrigin(clip_gc[PIX_FADEMASK], 0, 0);
488 BlitBitmapMasked(backbuffer, window,
489 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
494 SetClipOrigin(clip_gc[PIX_FADEMASK], -1, -1);
495 BlitBitmapMasked(backbuffer, window,
496 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
501 SetClipOrigin(clip_gc[PIX_FADEMASK], 0, -1);
502 BlitBitmapMasked(backbuffer, window,
503 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
508 SetClipOrigin(clip_gc[PIX_FADEMASK], -1, 0);
509 BlitBitmapMasked(backbuffer, window,
510 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
515 redraw_mask &= ~REDRAW_MAIN;
522 void FadeExt(int fade_mask, int fade_mode)
524 static int fade_mode_skip = FADE_MODE_NONE;
525 void (*draw_border_function)(void) = NULL;
527 Bitmap *bitmap = (fade_mode != FADE_MODE_FADE_IN ? bitmap_db_cross : NULL);
529 Bitmap *bitmap = (fade_mode & FADE_TYPE_TRANSFORM ? bitmap_db_cross : NULL);
531 int x, y, width, height;
532 int fade_delay, post_delay;
534 redraw_mask |= fade_mask;
536 if (fade_mode & FADE_TYPE_SKIP)
539 printf("::: will skip %d ... [%d]\n", fade_mode, fade_mode_skip);
542 fade_mode_skip = fade_mode;
547 if (fade_mode_skip & FADE_TYPE_SKIP)
550 printf("::: skipping %d ... [%d]\n", fade_mode, fade_mode_skip);
553 /* skip all fade operations until specified fade operation */
554 if (fade_mode & fade_mode_skip)
555 fade_mode_skip = FADE_MODE_NONE;
561 if (global.autoplay_leveldir)
563 // fading.fade_mode = FADE_MODE_NONE;
570 if (fading.fade_mode == FADE_MODE_NONE)
578 if (fade_mask & REDRAW_FIELD)
583 height = FULL_SYSIZE;
585 fade_delay = fading.fade_delay;
586 post_delay = (fade_mode == FADE_MODE_FADE_OUT ? fading.post_delay : 0);
588 if (border.draw_masked_when_fading)
589 draw_border_function = DrawMaskedBorder_FIELD; /* update when fading */
591 DrawMaskedBorder_FIELD(); /* draw once */
593 else /* REDRAW_ALL */
600 fade_delay = fading.fade_delay;
601 post_delay = (fade_mode == FADE_MODE_FADE_OUT ? fading.post_delay : 0);
605 if (!setup.fade_screens || fade_delay == 0)
607 if (!setup.fade_screens || fade_delay == 0 || fading.anim_mode == ANIM_NONE)
610 if (fade_mode == FADE_MODE_FADE_OUT)
611 ClearRectangle(backbuffer, x, y, width, height);
618 FadeRectangle(bitmap, x, y, width, height, fade_mode, fade_delay, post_delay,
619 draw_border_function);
621 redraw_mask &= ~fade_mask;
624 void FadeIn(int fade_mask)
627 global.border_status = game_status;
631 global.fading_status = game_status;
633 if (global.fading_type == TYPE_ENTER_MENU)
634 fading = menu.enter_menu;
635 else if (global.fading_type == TYPE_LEAVE_MENU)
636 fading = menu.leave_menu;
637 else if (global.fading_type == TYPE_ENTER_SCREEN)
638 fading = menu.enter_screen[global.fading_status];
639 else if (global.fading_type == TYPE_LEAVE_SCREEN)
640 fading = menu.leave_screen[global.fading_status];
642 printf("::: FadeIn: %s [0x%08x] [%d]\n",
643 global.fading_type == TYPE_ENTER_MENU ? "enter_menu" :
644 global.fading_type == TYPE_LEAVE_MENU ? "leave_menu" :
645 global.fading_type == TYPE_ENTER_SCREEN ? "enter_screen" :
646 global.fading_type == TYPE_LEAVE_SCREEN ? "leave_screen" : "(?)",
648 global.fading_status);
652 // printf("::: now fading in...\n");
654 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
655 FadeExt(fade_mask, fading.fade_mode);
657 FadeExt(fade_mask, FADE_MODE_FADE_IN);
660 if (fading.fade_mode == FADE_MODE_CROSSFADE)
661 FadeExt(fade_mask, FADE_MODE_CROSSFADE);
663 FadeExt(fade_mask, FADE_MODE_FADE_IN);
665 FadeExt(fade_mask, FADE_MODE_FADE_IN);
670 void FadeOut(int fade_mask)
673 if (global.fading_type == TYPE_ENTER_MENU)
674 fading = menu.enter_menu;
675 else if (global.fading_type == TYPE_LEAVE_MENU)
676 fading = menu.leave_menu;
677 else if (global.fading_type == TYPE_ENTER_SCREEN)
678 fading = menu.enter_screen[global.fading_status];
679 else if (global.fading_type == TYPE_LEAVE_SCREEN)
680 fading = menu.leave_screen[global.fading_status];
682 printf("::: FadeOut: %s [0x%08x] [%d]\n",
683 global.fading_type == TYPE_ENTER_MENU ? "enter_menu" :
684 global.fading_type == TYPE_LEAVE_MENU ? "leave_menu" :
685 global.fading_type == TYPE_ENTER_SCREEN ? "enter_screen" :
686 global.fading_type == TYPE_LEAVE_SCREEN ? "leave_screen" : "(?)",
688 global.fading_status);
692 // printf("::: fading.fade_mode == %d\n", fading.fade_mode);
694 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
695 FadeCrossSaveBackbuffer();
697 FadeExt(fade_mask, FADE_MODE_FADE_OUT);
700 if (fading.fade_mode == FADE_MODE_CROSSFADE)
701 FadeCrossSaveBackbuffer();
703 FadeExt(fade_mask, FADE_MODE_FADE_OUT);
705 FadeExt(fade_mask, FADE_MODE_FADE_OUT);
710 global.border_status = game_status;
714 void FadeCross(int fade_mask)
716 FadeExt(fade_mask, FADE_MODE_CROSSFADE);
719 void FadeCrossSaveBackbuffer()
721 BlitBitmap(backbuffer, bitmap_db_cross, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
725 void FadeSetEnterMenu()
727 global.fading_type = TYPE_ENTER_MENU;
730 void FadeSetLeaveMenu()
732 global.fading_type = TYPE_LEAVE_MENU;
735 void FadeSetEnterScreen()
737 global.fading_type = TYPE_ENTER_SCREEN;
740 void FadeSetLeaveScreen()
742 // global.fading_type = TYPE_LEAVE_SCREEN;
744 global.fading_type = (global.fading_type == TYPE_ENTER_SCREEN ?
745 TYPE_LEAVE_SCREEN : TYPE_LEAVE_MENU);
750 static void FadeSetLeaveNext(struct TitleFadingInfo fading_leave, boolean set)
752 static struct TitleFadingInfo fading_leave_stored;
755 fading_leave_stored = fading_leave;
757 fading = fading_leave_stored;
760 void FadeSetEnterMenu()
762 fading = menu.enter_menu;
765 printf("::: storing enter_menu\n");
768 FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
771 void FadeSetLeaveMenu()
773 fading = menu.leave_menu;
776 printf("::: storing leave_menu\n");
779 FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
782 void FadeSetEnterScreen()
784 fading = menu.enter_screen[game_status];
787 printf("::: storing leave_screen[%d]\n", game_status);
791 printf("::: - %d, %d / %d, %d\n",
792 menu.enter_screen[game_status].fade_mode,
793 menu.enter_screen[game_status].fade_delay,
794 menu.leave_screen[game_status].fade_mode,
795 menu.leave_screen[game_status].fade_delay);
798 FadeSetLeaveNext(menu.leave_screen[game_status], TRUE); /* store */
801 void FadeSetLeaveScreen()
804 printf("::: recalling last stored value\n");
807 FadeSetLeaveNext(menu.leave_screen[game_status], FALSE); /* recall */
812 void FadeSetFromType(int type)
814 if (type & TYPE_ENTER_SCREEN)
815 FadeSetEnterScreen();
816 else if (type & TYPE_ENTER)
818 else if (type & TYPE_LEAVE)
822 void FadeSetDisabled()
824 static struct TitleFadingInfo fading_none = { FADE_MODE_NONE, -1, -1, -1 };
826 fading = fading_none;
829 void FadeSkipNextFadeIn()
831 FadeExt(0, FADE_MODE_SKIP_FADE_IN);
834 void FadeSkipNextFadeOut()
836 FadeExt(0, FADE_MODE_SKIP_FADE_OUT);
839 void SetWindowBackgroundImageIfDefined(int graphic)
841 if (graphic_info[graphic].bitmap)
842 SetWindowBackgroundBitmap(graphic_info[graphic].bitmap);
845 void SetMainBackgroundImageIfDefined(int graphic)
847 if (graphic_info[graphic].bitmap)
848 SetMainBackgroundBitmap(graphic_info[graphic].bitmap);
851 void SetDoorBackgroundImageIfDefined(int graphic)
853 if (graphic_info[graphic].bitmap)
854 SetDoorBackgroundBitmap(graphic_info[graphic].bitmap);
857 void SetWindowBackgroundImage(int graphic)
859 SetWindowBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
860 graphic_info[graphic].bitmap ?
861 graphic_info[graphic].bitmap :
862 graphic_info[IMG_BACKGROUND].bitmap);
865 void SetMainBackgroundImage(int graphic)
867 SetMainBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
868 graphic_info[graphic].bitmap ?
869 graphic_info[graphic].bitmap :
870 graphic_info[IMG_BACKGROUND].bitmap);
873 void SetDoorBackgroundImage(int graphic)
875 SetDoorBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
876 graphic_info[graphic].bitmap ?
877 graphic_info[graphic].bitmap :
878 graphic_info[IMG_BACKGROUND].bitmap);
881 void SetPanelBackground()
883 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, bitmap_db_panel,
884 DOOR_GFX_PAGEX5, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE, 0, 0);
886 SetDoorBackgroundBitmap(bitmap_db_panel);
889 void DrawBackground(int x, int y, int width, int height)
891 /* !!! "drawto" might still point to playfield buffer here (see below) !!! */
892 /* (when entering hall of fame after playing) */
894 ClearRectangleOnBackground(drawto, x, y, width, height);
896 ClearRectangleOnBackground(backbuffer, x, y, width, height);
899 redraw_mask |= REDRAW_FIELD;
902 void DrawBackgroundForFont(int x, int y, int width, int height, int font_nr)
904 struct FontBitmapInfo *font = getFontBitmapInfo(font_nr);
906 if (font->bitmap == NULL)
909 DrawBackground(x, y, width, height);
912 void DrawBackgroundForGraphic(int x, int y, int width, int height, int graphic)
914 struct GraphicInfo *g = &graphic_info[graphic];
916 if (g->bitmap == NULL)
919 DrawBackground(x, y, width, height);
924 /* !!! "drawto" might still point to playfield buffer here (see above) !!! */
925 /* (when entering hall of fame after playing) */
926 DrawBackground(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
928 /* !!! maybe this should be done before clearing the background !!! */
929 if (setup.soft_scrolling && game_status == GAME_MODE_PLAYING)
931 ClearRectangle(fieldbuffer, 0, 0, FXSIZE, FYSIZE);
932 SetDrawtoField(DRAW_BUFFERED);
935 SetDrawtoField(DRAW_BACKBUFFER);
937 if (setup.direct_draw && game_status == GAME_MODE_PLAYING)
939 ClearRectangle(window, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
940 SetDrawtoField(DRAW_DIRECT);
944 void MarkTileDirty(int x, int y)
946 int xx = redraw_x1 + x;
947 int yy = redraw_y1 + y;
952 redraw[xx][yy] = TRUE;
953 redraw_mask |= REDRAW_TILES;
956 void SetBorderElement()
960 BorderElement = EL_EMPTY;
962 for (y = 0; y < lev_fieldy && BorderElement == EL_EMPTY; y++)
964 for (x = 0; x < lev_fieldx; x++)
966 if (!IS_INDESTRUCTIBLE(Feld[x][y]))
967 BorderElement = EL_STEELWALL;
969 if (y != 0 && y != lev_fieldy - 1 && x != lev_fieldx - 1)
975 void FloodFillLevel(int from_x, int from_y, int fill_element,
976 short field[MAX_LEV_FIELDX][MAX_LEV_FIELDY],
977 int max_fieldx, int max_fieldy)
981 static int check[4][2] = { { -1, 0 }, { 0, -1 }, { 1, 0 }, { 0, 1 } };
982 static int safety = 0;
984 /* check if starting field still has the desired content */
985 if (field[from_x][from_y] == fill_element)
990 if (safety > max_fieldx * max_fieldy)
991 Error(ERR_EXIT, "Something went wrong in 'FloodFill()'. Please debug.");
993 old_element = field[from_x][from_y];
994 field[from_x][from_y] = fill_element;
996 for (i = 0; i < 4; i++)
998 x = from_x + check[i][0];
999 y = from_y + check[i][1];
1001 if (IN_FIELD(x, y, max_fieldx, max_fieldy) && field[x][y] == old_element)
1002 FloodFillLevel(x, y, fill_element, field, max_fieldx, max_fieldy);
1008 void SetRandomAnimationValue(int x, int y)
1010 gfx.anim_random_frame = GfxRandom[x][y];
1013 inline int getGraphicAnimationFrame(int graphic, int sync_frame)
1015 /* animation synchronized with global frame counter, not move position */
1016 if (graphic_info[graphic].anim_global_sync || sync_frame < 0)
1017 sync_frame = FrameCounter;
1019 return getAnimationFrame(graphic_info[graphic].anim_frames,
1020 graphic_info[graphic].anim_delay,
1021 graphic_info[graphic].anim_mode,
1022 graphic_info[graphic].anim_start_frame,
1026 void getSizedGraphicSource(int graphic, int frame, int tilesize_raw,
1027 Bitmap **bitmap, int *x, int *y)
1031 int width_mult, width_div;
1032 int height_mult, height_div;
1036 { 15, 16, 2, 3 }, /* 1 x 1 */
1037 { 7, 8, 2, 3 }, /* 2 x 2 */
1038 { 3, 4, 2, 3 }, /* 4 x 4 */
1039 { 1, 2, 2, 3 }, /* 8 x 8 */
1040 { 0, 1, 2, 3 }, /* 16 x 16 */
1041 { 0, 1, 0, 1 }, /* 32 x 32 */
1043 struct GraphicInfo *g = &graphic_info[graphic];
1044 Bitmap *src_bitmap = g->bitmap;
1045 int tilesize = MIN(MAX(1, tilesize_raw), TILESIZE);
1046 int offset_calc_pos = log_2(tilesize);
1047 int width_mult = offset_calc[offset_calc_pos].width_mult;
1048 int width_div = offset_calc[offset_calc_pos].width_div;
1049 int height_mult = offset_calc[offset_calc_pos].height_mult;
1050 int height_div = offset_calc[offset_calc_pos].height_div;
1051 int startx = src_bitmap->width * width_mult / width_div;
1052 int starty = src_bitmap->height * height_mult / height_div;
1053 int src_x = g->src_x * tilesize / TILESIZE;
1054 int src_y = g->src_y * tilesize / TILESIZE;
1055 int width = g->width * tilesize / TILESIZE;
1056 int height = g->height * tilesize / TILESIZE;
1057 int offset_x = g->offset_x * tilesize / TILESIZE;
1058 int offset_y = g->offset_y * tilesize / TILESIZE;
1060 if (g->offset_y == 0) /* frames are ordered horizontally */
1062 int max_width = g->anim_frames_per_line * width;
1063 int pos = (src_y / height) * max_width + src_x + frame * offset_x;
1065 src_x = pos % max_width;
1066 src_y = src_y % height + pos / max_width * height;
1068 else if (g->offset_x == 0) /* frames are ordered vertically */
1070 int max_height = g->anim_frames_per_line * height;
1071 int pos = (src_x / width) * max_height + src_y + frame * offset_y;
1073 src_x = src_x % width + pos / max_height * width;
1074 src_y = pos % max_height;
1076 else /* frames are ordered diagonally */
1078 src_x = src_x + frame * offset_x;
1079 src_y = src_y + frame * offset_y;
1082 *bitmap = src_bitmap;
1083 *x = startx + src_x;
1084 *y = starty + src_y;
1087 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
1090 getSizedGraphicSource(graphic, 0, MINI_TILESIZE, bitmap, x, y);
1092 struct GraphicInfo *g = &graphic_info[graphic];
1093 int mini_startx = 0;
1094 int mini_starty = g->bitmap->height * 2 / 3;
1096 *bitmap = g->bitmap;
1097 *x = mini_startx + g->src_x / 2;
1098 *y = mini_starty + g->src_y / 2;
1102 inline void getGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
1103 int *x, int *y, boolean get_backside)
1105 struct GraphicInfo *g = &graphic_info[graphic];
1106 int src_x = g->src_x + (get_backside ? g->offset2_x : 0);
1107 int src_y = g->src_y + (get_backside ? g->offset2_y : 0);
1109 *bitmap = g->bitmap;
1111 if (g->offset_y == 0) /* frames are ordered horizontally */
1113 int max_width = g->anim_frames_per_line * g->width;
1114 int pos = (src_y / g->height) * max_width + src_x + frame * g->offset_x;
1116 *x = pos % max_width;
1117 *y = src_y % g->height + pos / max_width * g->height;
1119 else if (g->offset_x == 0) /* frames are ordered vertically */
1121 int max_height = g->anim_frames_per_line * g->height;
1122 int pos = (src_x / g->width) * max_height + src_y + frame * g->offset_y;
1124 *x = src_x % g->width + pos / max_height * g->width;
1125 *y = pos % max_height;
1127 else /* frames are ordered diagonally */
1129 *x = src_x + frame * g->offset_x;
1130 *y = src_y + frame * g->offset_y;
1134 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
1136 getGraphicSourceExt(graphic, frame, bitmap, x, y, FALSE);
1139 void DrawGraphic(int x, int y, int graphic, int frame)
1142 if (!IN_SCR_FIELD(x, y))
1144 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
1145 printf("DrawGraphic(): This should never happen!\n");
1150 DrawGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic, frame);
1151 MarkTileDirty(x, y);
1154 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
1160 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1161 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
1164 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
1167 if (!IN_SCR_FIELD(x, y))
1169 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
1170 printf("DrawGraphicThruMask(): This should never happen!\n");
1175 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y *TILEY, graphic,
1177 MarkTileDirty(x, y);
1180 void DrawGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y, int graphic,
1186 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1188 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1189 dst_x - src_x, dst_y - src_y);
1190 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dst_x, dst_y);
1193 void DrawSizedGraphic(int x, int y, int graphic, int frame, int tilesize)
1195 DrawSizedGraphicExt(drawto, SX + x * tilesize, SY + y * tilesize, graphic,
1197 MarkTileDirty(x / tilesize, y / tilesize);
1200 void DrawSizedGraphicExt(DrawBuffer *d, int x, int y, int graphic, int frame,
1206 getSizedGraphicSource(graphic, frame, tilesize, &src_bitmap, &src_x, &src_y);
1207 BlitBitmap(src_bitmap, d, src_x, src_y, tilesize, tilesize, x, y);
1210 void DrawMiniGraphic(int x, int y, int graphic)
1212 DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
1213 MarkTileDirty(x / 2, y / 2);
1216 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
1221 getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1222 BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
1225 inline static void DrawGraphicShiftedNormal(int x, int y, int dx, int dy,
1226 int graphic, int frame,
1227 int cut_mode, int mask_mode)
1232 int width = TILEX, height = TILEY;
1235 if (dx || dy) /* shifted graphic */
1237 if (x < BX1) /* object enters playfield from the left */
1244 else if (x > BX2) /* object enters playfield from the right */
1250 else if (x==BX1 && dx < 0) /* object leaves playfield to the left */
1256 else if (x==BX2 && dx > 0) /* object leaves playfield to the right */
1258 else if (dx) /* general horizontal movement */
1259 MarkTileDirty(x + SIGN(dx), y);
1261 if (y < BY1) /* object enters playfield from the top */
1263 if (cut_mode==CUT_BELOW) /* object completely above top border */
1271 else if (y > BY2) /* object enters playfield from the bottom */
1277 else if (y==BY1 && dy < 0) /* object leaves playfield to the top */
1283 else if (dy > 0 && cut_mode == CUT_ABOVE)
1285 if (y == BY2) /* object completely above bottom border */
1291 MarkTileDirty(x, y + 1);
1292 } /* object leaves playfield to the bottom */
1293 else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
1295 else if (dy) /* general vertical movement */
1296 MarkTileDirty(x, y + SIGN(dy));
1300 if (!IN_SCR_FIELD(x, y))
1302 printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
1303 printf("DrawGraphicShifted(): This should never happen!\n");
1308 if (width > 0 && height > 0)
1310 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1315 dst_x = FX + x * TILEX + dx;
1316 dst_y = FY + y * TILEY + dy;
1318 if (mask_mode == USE_MASKING)
1320 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1321 dst_x - src_x, dst_y - src_y);
1322 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1326 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1329 MarkTileDirty(x, y);
1333 inline static void DrawGraphicShiftedDouble(int x, int y, int dx, int dy,
1334 int graphic, int frame,
1335 int cut_mode, int mask_mode)
1340 int width = TILEX, height = TILEY;
1343 int x2 = x + SIGN(dx);
1344 int y2 = y + SIGN(dy);
1345 int anim_frames = graphic_info[graphic].anim_frames;
1346 int sync_frame = (dx ? ABS(dx) : ABS(dy)) * anim_frames / TILESIZE;
1347 boolean draw_start_tile = (cut_mode != CUT_ABOVE); /* only for falling! */
1348 boolean draw_end_tile = (cut_mode != CUT_BELOW); /* only for falling! */
1350 /* re-calculate animation frame for two-tile movement animation */
1351 frame = getGraphicAnimationFrame(graphic, sync_frame);
1353 /* check if movement start graphic inside screen area and should be drawn */
1354 if (draw_start_tile && IN_SCR_FIELD(x1, y1))
1356 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, TRUE);
1358 dst_x = FX + x1 * TILEX;
1359 dst_y = FY + y1 * TILEY;
1361 if (mask_mode == USE_MASKING)
1363 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1364 dst_x - src_x, dst_y - src_y);
1365 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1369 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1372 MarkTileDirty(x1, y1);
1375 /* check if movement end graphic inside screen area and should be drawn */
1376 if (draw_end_tile && IN_SCR_FIELD(x2, y2))
1378 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
1380 dst_x = FX + x2 * TILEX;
1381 dst_y = FY + y2 * TILEY;
1383 if (mask_mode == USE_MASKING)
1385 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1386 dst_x - src_x, dst_y - src_y);
1387 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1391 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1394 MarkTileDirty(x2, y2);
1398 static void DrawGraphicShifted(int x, int y, int dx, int dy,
1399 int graphic, int frame,
1400 int cut_mode, int mask_mode)
1404 DrawGraphic(x, y, graphic, frame);
1409 if (graphic_info[graphic].double_movement) /* EM style movement images */
1410 DrawGraphicShiftedDouble(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1412 DrawGraphicShiftedNormal(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1415 void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
1416 int frame, int cut_mode)
1418 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, USE_MASKING);
1421 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
1422 int cut_mode, int mask_mode)
1424 int lx = LEVELX(x), ly = LEVELY(y);
1428 if (IN_LEV_FIELD(lx, ly))
1430 SetRandomAnimationValue(lx, ly);
1432 graphic = el_act_dir2img(element, GfxAction[lx][ly], GfxDir[lx][ly]);
1433 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1435 /* do not use double (EM style) movement graphic when not moving */
1436 if (graphic_info[graphic].double_movement && !dx && !dy)
1438 graphic = el_act_dir2img(element, ACTION_DEFAULT, GfxDir[lx][ly]);
1439 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1442 else /* border element */
1444 graphic = el2img(element);
1445 frame = getGraphicAnimationFrame(graphic, -1);
1448 if (element == EL_EXPANDABLE_WALL)
1450 boolean left_stopped = FALSE, right_stopped = FALSE;
1452 if (!IN_LEV_FIELD(lx - 1, ly) || IS_WALL(Feld[lx - 1][ly]))
1453 left_stopped = TRUE;
1454 if (!IN_LEV_FIELD(lx + 1, ly) || IS_WALL(Feld[lx + 1][ly]))
1455 right_stopped = TRUE;
1457 if (left_stopped && right_stopped)
1459 else if (left_stopped)
1461 graphic = IMG_EXPANDABLE_WALL_GROWING_RIGHT;
1462 frame = graphic_info[graphic].anim_frames - 1;
1464 else if (right_stopped)
1466 graphic = IMG_EXPANDABLE_WALL_GROWING_LEFT;
1467 frame = graphic_info[graphic].anim_frames - 1;
1472 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
1473 else if (mask_mode == USE_MASKING)
1474 DrawGraphicThruMask(x, y, graphic, frame);
1476 DrawGraphic(x, y, graphic, frame);
1479 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
1480 int cut_mode, int mask_mode)
1482 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1483 DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
1484 cut_mode, mask_mode);
1487 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
1490 DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1493 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
1496 DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1499 void DrawLevelElementThruMask(int x, int y, int element)
1501 DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1504 void DrawLevelFieldThruMask(int x, int y)
1506 DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
1509 static void DrawLevelFieldCrumbledSandExt(int x, int y, int graphic, int frame)
1513 int sx = SCREENX(x), sy = SCREENY(y);
1515 int width, height, cx, cy, i;
1516 int crumbled_border_size = graphic_info[graphic].border_size;
1517 static int xy[4][2] =
1525 if (!IN_LEV_FIELD(x, y))
1528 element = TILE_GFX_ELEMENT(x, y);
1530 /* crumble field itself */
1531 if (GFX_CRUMBLED(element) && !IS_MOVING(x, y))
1533 if (!IN_SCR_FIELD(sx, sy))
1536 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1538 for (i = 0; i < 4; i++)
1540 int xx = x + xy[i][0];
1541 int yy = y + xy[i][1];
1543 element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1546 /* check if neighbour field is of same type */
1547 if (GFX_CRUMBLED(element) && !IS_MOVING(xx, yy))
1550 if (i == 1 || i == 2)
1552 width = crumbled_border_size;
1554 cx = (i == 2 ? TILEX - crumbled_border_size : 0);
1560 height = crumbled_border_size;
1562 cy = (i == 3 ? TILEY - crumbled_border_size : 0);
1565 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1566 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
1569 MarkTileDirty(sx, sy);
1571 else /* crumble neighbour fields */
1573 for (i = 0; i < 4; i++)
1575 int xx = x + xy[i][0];
1576 int yy = y + xy[i][1];
1577 int sxx = sx + xy[i][0];
1578 int syy = sy + xy[i][1];
1580 if (!IN_LEV_FIELD(xx, yy) ||
1581 !IN_SCR_FIELD(sxx, syy) ||
1585 if (Feld[xx][yy] == EL_ELEMENT_SNAPPING)
1588 element = TILE_GFX_ELEMENT(xx, yy);
1590 if (!GFX_CRUMBLED(element))
1593 graphic = el_act2crm(element, ACTION_DEFAULT);
1594 crumbled_border_size = graphic_info[graphic].border_size;
1596 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1598 if (i == 1 || i == 2)
1600 width = crumbled_border_size;
1602 cx = (i == 1 ? TILEX - crumbled_border_size : 0);
1608 height = crumbled_border_size;
1610 cy = (i == 0 ? TILEY - crumbled_border_size : 0);
1613 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1614 width, height, FX + sxx * TILEX + cx, FY + syy * TILEY + cy);
1616 MarkTileDirty(sxx, syy);
1621 void DrawLevelFieldCrumbledSand(int x, int y)
1625 if (!IN_LEV_FIELD(x, y))
1629 /* !!! CHECK THIS !!! */
1632 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
1633 GFX_CRUMBLED(GfxElement[x][y]))
1636 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
1637 GfxElement[x][y] != EL_UNDEFINED &&
1638 GFX_CRUMBLED(GfxElement[x][y]))
1640 DrawLevelFieldCrumbledSandDigging(x, y, GfxDir[x][y], GfxFrame[x][y]);
1647 graphic = el_act2crm(TILE_GFX_ELEMENT(x, y), ACTION_DEFAULT);
1649 graphic = el_act2crm(Feld[x][y], ACTION_DEFAULT);
1652 DrawLevelFieldCrumbledSandExt(x, y, graphic, 0);
1655 void DrawLevelFieldCrumbledSandDigging(int x, int y, int direction,
1658 int graphic1 = el_act_dir2img(GfxElement[x][y], ACTION_DIGGING, direction);
1659 int graphic2 = el_act_dir2crm(GfxElement[x][y], ACTION_DIGGING, direction);
1660 int frame1 = getGraphicAnimationFrame(graphic1, step_frame);
1661 int frame2 = getGraphicAnimationFrame(graphic2, step_frame);
1662 int sx = SCREENX(x), sy = SCREENY(y);
1664 DrawGraphic(sx, sy, graphic1, frame1);
1665 DrawLevelFieldCrumbledSandExt(x, y, graphic2, frame2);
1668 void DrawLevelFieldCrumbledSandNeighbours(int x, int y)
1670 int sx = SCREENX(x), sy = SCREENY(y);
1671 static int xy[4][2] =
1680 for (i = 0; i < 4; i++)
1682 int xx = x + xy[i][0];
1683 int yy = y + xy[i][1];
1684 int sxx = sx + xy[i][0];
1685 int syy = sy + xy[i][1];
1687 if (!IN_LEV_FIELD(xx, yy) ||
1688 !IN_SCR_FIELD(sxx, syy) ||
1689 !GFX_CRUMBLED(Feld[xx][yy]) ||
1693 DrawLevelField(xx, yy);
1697 static int getBorderElement(int x, int y)
1701 { EL_STEELWALL_TOPLEFT, EL_INVISIBLE_STEELWALL_TOPLEFT },
1702 { EL_STEELWALL_TOPRIGHT, EL_INVISIBLE_STEELWALL_TOPRIGHT },
1703 { EL_STEELWALL_BOTTOMLEFT, EL_INVISIBLE_STEELWALL_BOTTOMLEFT },
1704 { EL_STEELWALL_BOTTOMRIGHT, EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
1705 { EL_STEELWALL_VERTICAL, EL_INVISIBLE_STEELWALL_VERTICAL },
1706 { EL_STEELWALL_HORIZONTAL, EL_INVISIBLE_STEELWALL_HORIZONTAL },
1707 { EL_STEELWALL, EL_INVISIBLE_STEELWALL }
1709 int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
1710 int steel_position = (x == -1 && y == -1 ? 0 :
1711 x == lev_fieldx && y == -1 ? 1 :
1712 x == -1 && y == lev_fieldy ? 2 :
1713 x == lev_fieldx && y == lev_fieldy ? 3 :
1714 x == -1 || x == lev_fieldx ? 4 :
1715 y == -1 || y == lev_fieldy ? 5 : 6);
1717 return border[steel_position][steel_type];
1720 void DrawScreenElement(int x, int y, int element)
1722 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
1723 DrawLevelFieldCrumbledSand(LEVELX(x), LEVELY(y));
1726 void DrawLevelElement(int x, int y, int element)
1728 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1729 DrawScreenElement(SCREENX(x), SCREENY(y), element);
1732 void DrawScreenField(int x, int y)
1734 int lx = LEVELX(x), ly = LEVELY(y);
1735 int element, content;
1737 if (!IN_LEV_FIELD(lx, ly))
1739 if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
1742 element = getBorderElement(lx, ly);
1744 DrawScreenElement(x, y, element);
1748 element = Feld[lx][ly];
1749 content = Store[lx][ly];
1751 if (IS_MOVING(lx, ly))
1753 int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
1754 boolean cut_mode = NO_CUTTING;
1756 if (element == EL_QUICKSAND_EMPTYING ||
1757 element == EL_QUICKSAND_FAST_EMPTYING ||
1758 element == EL_MAGIC_WALL_EMPTYING ||
1759 element == EL_BD_MAGIC_WALL_EMPTYING ||
1760 element == EL_DC_MAGIC_WALL_EMPTYING ||
1761 element == EL_AMOEBA_DROPPING)
1762 cut_mode = CUT_ABOVE;
1763 else if (element == EL_QUICKSAND_FILLING ||
1764 element == EL_QUICKSAND_FAST_FILLING ||
1765 element == EL_MAGIC_WALL_FILLING ||
1766 element == EL_BD_MAGIC_WALL_FILLING ||
1767 element == EL_DC_MAGIC_WALL_FILLING)
1768 cut_mode = CUT_BELOW;
1770 if (cut_mode == CUT_ABOVE)
1771 DrawScreenElementShifted(x, y, 0, 0, element, NO_CUTTING);
1773 DrawScreenElement(x, y, EL_EMPTY);
1776 DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
1777 else if (cut_mode == NO_CUTTING)
1778 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
1780 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
1782 if (content == EL_ACID)
1784 int dir = MovDir[lx][ly];
1785 int newlx = lx + (dir == MV_LEFT ? -1 : dir == MV_RIGHT ? +1 : 0);
1786 int newly = ly + (dir == MV_UP ? -1 : dir == MV_DOWN ? +1 : 0);
1788 DrawLevelElementThruMask(newlx, newly, EL_ACID);
1791 else if (IS_BLOCKED(lx, ly))
1796 boolean cut_mode = NO_CUTTING;
1797 int element_old, content_old;
1799 Blocked2Moving(lx, ly, &oldx, &oldy);
1802 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
1803 MovDir[oldx][oldy] == MV_RIGHT);
1805 element_old = Feld[oldx][oldy];
1806 content_old = Store[oldx][oldy];
1808 if (element_old == EL_QUICKSAND_EMPTYING ||
1809 element_old == EL_QUICKSAND_FAST_EMPTYING ||
1810 element_old == EL_MAGIC_WALL_EMPTYING ||
1811 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
1812 element_old == EL_DC_MAGIC_WALL_EMPTYING ||
1813 element_old == EL_AMOEBA_DROPPING)
1814 cut_mode = CUT_ABOVE;
1816 DrawScreenElement(x, y, EL_EMPTY);
1819 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
1821 else if (cut_mode == NO_CUTTING)
1822 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
1825 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
1828 else if (IS_DRAWABLE(element))
1829 DrawScreenElement(x, y, element);
1831 DrawScreenElement(x, y, EL_EMPTY);
1834 void DrawLevelField(int x, int y)
1836 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1837 DrawScreenField(SCREENX(x), SCREENY(y));
1838 else if (IS_MOVING(x, y))
1842 Moving2Blocked(x, y, &newx, &newy);
1843 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
1844 DrawScreenField(SCREENX(newx), SCREENY(newy));
1846 else if (IS_BLOCKED(x, y))
1850 Blocked2Moving(x, y, &oldx, &oldy);
1851 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
1852 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
1856 void DrawMiniElement(int x, int y, int element)
1860 graphic = el2edimg(element);
1861 DrawMiniGraphic(x, y, graphic);
1864 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
1866 int x = sx + scroll_x, y = sy + scroll_y;
1868 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
1869 DrawMiniElement(sx, sy, EL_EMPTY);
1870 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
1871 DrawMiniElement(sx, sy, Feld[x][y]);
1873 DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
1876 void DrawEnvelopeBackground(int envelope_nr, int startx, int starty,
1877 int x, int y, int xsize, int ysize, int font_nr)
1879 int font_width = getFontWidth(font_nr);
1880 int font_height = getFontHeight(font_nr);
1881 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1884 int dst_x = SX + startx + x * font_width;
1885 int dst_y = SY + starty + y * font_height;
1886 int width = graphic_info[graphic].width;
1887 int height = graphic_info[graphic].height;
1888 int inner_width = MAX(width - 2 * font_width, font_width);
1889 int inner_height = MAX(height - 2 * font_height, font_height);
1890 int inner_sx = (width >= 3 * font_width ? font_width : 0);
1891 int inner_sy = (height >= 3 * font_height ? font_height : 0);
1892 boolean draw_masked = graphic_info[graphic].draw_masked;
1894 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1896 if (src_bitmap == NULL || width < font_width || height < font_height)
1898 ClearRectangle(drawto, dst_x, dst_y, font_width, font_height);
1902 src_x += (x == 0 ? 0 : x == xsize - 1 ? width - font_width :
1903 inner_sx + (x - 1) * font_width % inner_width);
1904 src_y += (y == 0 ? 0 : y == ysize - 1 ? height - font_height :
1905 inner_sy + (y - 1) * font_height % inner_height);
1909 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1910 dst_x - src_x, dst_y - src_y);
1911 BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1915 BlitBitmap(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1919 void AnimateEnvelope(int envelope_nr, int anim_mode, int action)
1921 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1922 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1923 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
1924 boolean ffwd_delay = (tape.playing && tape.fast_forward);
1925 boolean no_delay = (tape.warp_forward);
1926 unsigned long anim_delay = 0;
1927 int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
1928 int anim_delay_value = (no_delay ? 0 : frame_delay_value);
1929 int font_nr = FONT_ENVELOPE_1 + envelope_nr;
1930 int font_width = getFontWidth(font_nr);
1931 int font_height = getFontHeight(font_nr);
1932 int max_xsize = level.envelope[envelope_nr].xsize;
1933 int max_ysize = level.envelope[envelope_nr].ysize;
1934 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
1935 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
1936 int xend = max_xsize;
1937 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
1938 int xstep = (xstart < xend ? 1 : 0);
1939 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
1942 for (x = xstart, y = ystart; x <= xend && y <= yend; x += xstep, y += ystep)
1944 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
1945 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
1946 int sx = (SXSIZE - xsize * font_width) / 2;
1947 int sy = (SYSIZE - ysize * font_height) / 2;
1950 SetDrawtoField(DRAW_BUFFERED);
1952 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
1954 SetDrawtoField(DRAW_BACKBUFFER);
1956 for (yy = 0; yy < ysize; yy++) for (xx = 0; xx < xsize; xx++)
1957 DrawEnvelopeBackground(envelope_nr, sx,sy, xx,yy, xsize, ysize, font_nr);
1960 DrawTextBuffer(SX + sx + font_width, SY + sy + font_height,
1961 level.envelope[envelope_nr].text, font_nr, max_xsize,
1962 xsize - 2, ysize - 2, mask_mode,
1963 level.envelope[envelope_nr].autowrap,
1964 level.envelope[envelope_nr].centered, FALSE);
1966 DrawTextToTextArea(SX + sx + font_width, SY + sy + font_height,
1967 level.envelope[envelope_nr].text, font_nr, max_xsize,
1968 xsize - 2, ysize - 2, mask_mode);
1971 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
1974 WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
1978 void ShowEnvelope(int envelope_nr)
1980 int element = EL_ENVELOPE_1 + envelope_nr;
1981 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1982 int sound_opening = element_info[element].sound[ACTION_OPENING];
1983 int sound_closing = element_info[element].sound[ACTION_CLOSING];
1984 boolean ffwd_delay = (tape.playing && tape.fast_forward);
1985 boolean no_delay = (tape.warp_forward);
1986 int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
1987 int wait_delay_value = (no_delay ? 0 : normal_delay_value);
1988 int anim_mode = graphic_info[graphic].anim_mode;
1989 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
1990 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
1992 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
1994 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
1996 if (anim_mode == ANIM_DEFAULT)
1997 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_OPENING);
1999 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_OPENING);
2002 Delay(wait_delay_value);
2004 WaitForEventToContinue();
2006 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
2008 if (anim_mode != ANIM_NONE)
2009 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_CLOSING);
2011 if (anim_mode == ANIM_DEFAULT)
2012 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_CLOSING);
2014 game.envelope_active = FALSE;
2016 SetDrawtoField(DRAW_BUFFERED);
2018 redraw_mask |= REDRAW_FIELD;
2022 void DrawPreviewElement(int dst_x, int dst_y, int element, int tilesize)
2026 int graphic = el2preimg(element);
2028 getSizedGraphicSource(graphic, 0, tilesize, &src_bitmap, &src_x, &src_y);
2029 BlitBitmap(src_bitmap, drawto, src_x, src_y, tilesize, tilesize, dst_x,dst_y);
2036 SetDrawBackgroundMask(REDRAW_NONE);
2039 for (x = BX1; x <= BX2; x++)
2040 for (y = BY1; y <= BY2; y++)
2041 DrawScreenField(x, y);
2043 redraw_mask |= REDRAW_FIELD;
2046 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
2050 for (x = 0; x < size_x; x++)
2051 for (y = 0; y < size_y; y++)
2052 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
2054 redraw_mask |= REDRAW_FIELD;
2057 static void DrawPreviewLevelExt(int from_x, int from_y)
2059 boolean show_level_border = (BorderElement != EL_EMPTY);
2060 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
2061 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
2062 int tile_size = preview.tile_size;
2063 int preview_width = preview.xsize * tile_size;
2064 int preview_height = preview.ysize * tile_size;
2065 int real_preview_xsize = MIN(level_xsize, preview.xsize);
2066 int real_preview_ysize = MIN(level_ysize, preview.ysize);
2067 int dst_x = SX + ALIGNED_XPOS(preview.x, preview_width, preview.align);
2068 int dst_y = SY + ALIGNED_YPOS(preview.y, preview_height, preview.valign);
2071 DrawBackground(dst_x, dst_y, preview_width, preview_height);
2073 dst_x += (preview_width - real_preview_xsize * tile_size) / 2;
2074 dst_y += (preview_height - real_preview_ysize * tile_size) / 2;
2076 for (x = 0; x < real_preview_xsize; x++)
2078 for (y = 0; y < real_preview_ysize; y++)
2080 int lx = from_x + x + (show_level_border ? -1 : 0);
2081 int ly = from_y + y + (show_level_border ? -1 : 0);
2082 int element = (IN_LEV_FIELD(lx, ly) ? level.field[lx][ly] :
2083 getBorderElement(lx, ly));
2085 DrawPreviewElement(dst_x + x * tile_size, dst_y + y * tile_size,
2086 element, tile_size);
2090 redraw_mask |= REDRAW_MICROLEVEL;
2093 #define MICROLABEL_EMPTY 0
2094 #define MICROLABEL_LEVEL_NAME 1
2095 #define MICROLABEL_LEVEL_AUTHOR_HEAD 2
2096 #define MICROLABEL_LEVEL_AUTHOR 3
2097 #define MICROLABEL_IMPORTED_FROM_HEAD 4
2098 #define MICROLABEL_IMPORTED_FROM 5
2099 #define MICROLABEL_IMPORTED_BY_HEAD 6
2100 #define MICROLABEL_IMPORTED_BY 7
2102 static int getMaxTextLength(struct TextPosInfo *pos, int font_nr)
2104 int max_text_width = SXSIZE;
2105 int font_width = getFontWidth(font_nr);
2107 if (pos->align == ALIGN_CENTER)
2108 max_text_width = (pos->x < SXSIZE / 2 ? pos->x * 2 : (SXSIZE - pos->x) * 2);
2109 else if (pos->align == ALIGN_RIGHT)
2110 max_text_width = pos->x;
2112 max_text_width = SXSIZE - pos->x;
2114 return max_text_width / font_width;
2117 static void DrawPreviewLevelLabelExt(int mode)
2119 struct TextPosInfo *pos = &menu.main.text.level_info_2;
2120 char label_text[MAX_OUTPUT_LINESIZE + 1];
2121 int max_len_label_text;
2123 int font_nr = pos->font;
2126 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
2127 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
2128 mode == MICROLABEL_IMPORTED_BY_HEAD)
2129 font_nr = pos->font_alt;
2131 int font_nr = FONT_TEXT_2;
2134 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
2135 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
2136 mode == MICROLABEL_IMPORTED_BY_HEAD)
2137 font_nr = FONT_TEXT_3;
2141 max_len_label_text = getMaxTextLength(pos, font_nr);
2143 max_len_label_text = SXSIZE / getFontWidth(font_nr);
2147 if (pos->size != -1)
2148 max_len_label_text = pos->size;
2151 for (i = 0; i < max_len_label_text; i++)
2152 label_text[i] = ' ';
2153 label_text[max_len_label_text] = '\0';
2155 if (strlen(label_text) > 0)
2158 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2160 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
2161 int lypos = MICROLABEL2_YPOS;
2163 DrawText(lxpos, lypos, label_text, font_nr);
2168 (mode == MICROLABEL_LEVEL_NAME ? level.name :
2169 mode == MICROLABEL_LEVEL_AUTHOR_HEAD ? "created by" :
2170 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
2171 mode == MICROLABEL_IMPORTED_FROM_HEAD ? "imported from" :
2172 mode == MICROLABEL_IMPORTED_FROM ? leveldir_current->imported_from :
2173 mode == MICROLABEL_IMPORTED_BY_HEAD ? "imported by" :
2174 mode == MICROLABEL_IMPORTED_BY ? leveldir_current->imported_by :""),
2175 max_len_label_text);
2176 label_text[max_len_label_text] = '\0';
2178 if (strlen(label_text) > 0)
2181 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2183 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
2184 int lypos = MICROLABEL2_YPOS;
2186 DrawText(lxpos, lypos, label_text, font_nr);
2190 redraw_mask |= REDRAW_MICROLEVEL;
2193 void DrawPreviewLevel(boolean restart)
2195 static unsigned long scroll_delay = 0;
2196 static unsigned long label_delay = 0;
2197 static int from_x, from_y, scroll_direction;
2198 static int label_state, label_counter;
2199 unsigned long scroll_delay_value = preview.step_delay;
2200 boolean show_level_border = (BorderElement != EL_EMPTY);
2201 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
2202 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
2203 int last_game_status = game_status; /* save current game status */
2206 /* force PREVIEW font on preview level */
2207 game_status = GAME_MODE_PSEUDO_PREVIEW;
2215 if (preview.anim_mode == ANIM_CENTERED)
2217 if (level_xsize > preview.xsize)
2218 from_x = (level_xsize - preview.xsize) / 2;
2219 if (level_ysize > preview.ysize)
2220 from_y = (level_ysize - preview.ysize) / 2;
2223 from_x += preview.xoffset;
2224 from_y += preview.yoffset;
2226 scroll_direction = MV_RIGHT;
2230 DrawPreviewLevelExt(from_x, from_y);
2231 DrawPreviewLevelLabelExt(label_state);
2233 /* initialize delay counters */
2234 DelayReached(&scroll_delay, 0);
2235 DelayReached(&label_delay, 0);
2237 if (leveldir_current->name)
2239 struct TextPosInfo *pos = &menu.main.text.level_info_1;
2240 char label_text[MAX_OUTPUT_LINESIZE + 1];
2242 int font_nr = pos->font;
2244 int font_nr = FONT_TEXT_1;
2247 int max_len_label_text = getMaxTextLength(pos, font_nr);
2249 int max_len_label_text = SXSIZE / getFontWidth(font_nr);
2257 if (pos->size != -1)
2258 max_len_label_text = pos->size;
2261 strncpy(label_text, leveldir_current->name, max_len_label_text);
2262 label_text[max_len_label_text] = '\0';
2265 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2267 lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
2268 lypos = SY + MICROLABEL1_YPOS;
2270 DrawText(lxpos, lypos, label_text, font_nr);
2274 game_status = last_game_status; /* restore current game status */
2279 /* scroll preview level, if needed */
2280 if (preview.anim_mode != ANIM_NONE &&
2281 (level_xsize > preview.xsize || level_ysize > preview.ysize) &&
2282 DelayReached(&scroll_delay, scroll_delay_value))
2284 switch (scroll_direction)
2289 from_x -= preview.step_offset;
2290 from_x = (from_x < 0 ? 0 : from_x);
2293 scroll_direction = MV_UP;
2297 if (from_x < level_xsize - preview.xsize)
2299 from_x += preview.step_offset;
2300 from_x = (from_x > level_xsize - preview.xsize ?
2301 level_xsize - preview.xsize : from_x);
2304 scroll_direction = MV_DOWN;
2310 from_y -= preview.step_offset;
2311 from_y = (from_y < 0 ? 0 : from_y);
2314 scroll_direction = MV_RIGHT;
2318 if (from_y < level_ysize - preview.ysize)
2320 from_y += preview.step_offset;
2321 from_y = (from_y > level_ysize - preview.ysize ?
2322 level_ysize - preview.ysize : from_y);
2325 scroll_direction = MV_LEFT;
2332 DrawPreviewLevelExt(from_x, from_y);
2335 /* !!! THIS ALL SUCKS -- SHOULD BE CLEANLY REWRITTEN !!! */
2336 /* redraw micro level label, if needed */
2337 if (!strEqual(level.name, NAMELESS_LEVEL_NAME) &&
2338 !strEqual(level.author, ANONYMOUS_NAME) &&
2339 !strEqual(level.author, leveldir_current->name) &&
2340 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
2342 int max_label_counter = 23;
2344 if (leveldir_current->imported_from != NULL &&
2345 strlen(leveldir_current->imported_from) > 0)
2346 max_label_counter += 14;
2347 if (leveldir_current->imported_by != NULL &&
2348 strlen(leveldir_current->imported_by) > 0)
2349 max_label_counter += 14;
2351 label_counter = (label_counter + 1) % max_label_counter;
2352 label_state = (label_counter >= 0 && label_counter <= 7 ?
2353 MICROLABEL_LEVEL_NAME :
2354 label_counter >= 9 && label_counter <= 12 ?
2355 MICROLABEL_LEVEL_AUTHOR_HEAD :
2356 label_counter >= 14 && label_counter <= 21 ?
2357 MICROLABEL_LEVEL_AUTHOR :
2358 label_counter >= 23 && label_counter <= 26 ?
2359 MICROLABEL_IMPORTED_FROM_HEAD :
2360 label_counter >= 28 && label_counter <= 35 ?
2361 MICROLABEL_IMPORTED_FROM :
2362 label_counter >= 37 && label_counter <= 40 ?
2363 MICROLABEL_IMPORTED_BY_HEAD :
2364 label_counter >= 42 && label_counter <= 49 ?
2365 MICROLABEL_IMPORTED_BY : MICROLABEL_EMPTY);
2367 if (leveldir_current->imported_from == NULL &&
2368 (label_state == MICROLABEL_IMPORTED_FROM_HEAD ||
2369 label_state == MICROLABEL_IMPORTED_FROM))
2370 label_state = (label_state == MICROLABEL_IMPORTED_FROM_HEAD ?
2371 MICROLABEL_IMPORTED_BY_HEAD : MICROLABEL_IMPORTED_BY);
2373 DrawPreviewLevelLabelExt(label_state);
2376 game_status = last_game_status; /* restore current game status */
2379 inline void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
2380 int graphic, int sync_frame, int mask_mode)
2382 int frame = getGraphicAnimationFrame(graphic, sync_frame);
2384 if (mask_mode == USE_MASKING)
2385 DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
2387 DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
2390 inline void DrawGraphicAnimation(int x, int y, int graphic)
2392 int lx = LEVELX(x), ly = LEVELY(y);
2394 if (!IN_SCR_FIELD(x, y))
2397 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
2398 graphic, GfxFrame[lx][ly], NO_MASKING);
2399 MarkTileDirty(x, y);
2402 void DrawLevelGraphicAnimation(int x, int y, int graphic)
2404 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
2407 void DrawLevelElementAnimation(int x, int y, int element)
2409 int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
2411 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
2414 inline void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
2416 int sx = SCREENX(x), sy = SCREENY(y);
2418 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
2421 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
2424 DrawGraphicAnimation(sx, sy, graphic);
2427 if (GFX_CRUMBLED(TILE_GFX_ELEMENT(x, y)))
2428 DrawLevelFieldCrumbledSand(x, y);
2430 if (GFX_CRUMBLED(Feld[x][y]))
2431 DrawLevelFieldCrumbledSand(x, y);
2435 void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
2437 int sx = SCREENX(x), sy = SCREENY(y);
2440 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
2443 graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
2445 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
2448 DrawGraphicAnimation(sx, sy, graphic);
2450 if (GFX_CRUMBLED(element))
2451 DrawLevelFieldCrumbledSand(x, y);
2454 static int getPlayerGraphic(struct PlayerInfo *player, int move_dir)
2456 if (player->use_murphy)
2458 /* this works only because currently only one player can be "murphy" ... */
2459 static int last_horizontal_dir = MV_LEFT;
2460 int graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir);
2462 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
2463 last_horizontal_dir = move_dir;
2465 if (graphic == IMG_SP_MURPHY) /* undefined => use special graphic */
2467 int direction = (player->is_snapping ? move_dir : last_horizontal_dir);
2469 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
2475 return el_act_dir2img(player->artwork_element, player->GfxAction,move_dir);
2478 static boolean equalGraphics(int graphic1, int graphic2)
2480 struct GraphicInfo *g1 = &graphic_info[graphic1];
2481 struct GraphicInfo *g2 = &graphic_info[graphic2];
2483 return (g1->bitmap == g2->bitmap &&
2484 g1->src_x == g2->src_x &&
2485 g1->src_y == g2->src_y &&
2486 g1->anim_frames == g2->anim_frames &&
2487 g1->anim_delay == g2->anim_delay &&
2488 g1->anim_mode == g2->anim_mode);
2491 void DrawAllPlayers()
2495 for (i = 0; i < MAX_PLAYERS; i++)
2496 if (stored_player[i].active)
2497 DrawPlayer(&stored_player[i]);
2500 void DrawPlayerField(int x, int y)
2502 if (!IS_PLAYER(x, y))
2505 DrawPlayer(PLAYERINFO(x, y));
2508 void DrawPlayer(struct PlayerInfo *player)
2510 int jx = player->jx;
2511 int jy = player->jy;
2512 int move_dir = player->MovDir;
2513 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? +1 : 0);
2514 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? +1 : 0);
2515 int last_jx = (player->is_moving ? jx - dx : jx);
2516 int last_jy = (player->is_moving ? jy - dy : jy);
2517 int next_jx = jx + dx;
2518 int next_jy = jy + dy;
2519 boolean player_is_moving = (player->MovPos ? TRUE : FALSE);
2520 boolean player_is_opaque = FALSE;
2521 int sx = SCREENX(jx), sy = SCREENY(jy);
2522 int sxx = 0, syy = 0;
2523 int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
2525 int action = ACTION_DEFAULT;
2526 int last_player_graphic = getPlayerGraphic(player, move_dir);
2527 int last_player_frame = player->Frame;
2530 /* GfxElement[][] is set to the element the player is digging or collecting;
2531 remove also for off-screen player if the player is not moving anymore */
2532 if (IN_LEV_FIELD(jx, jy) && !player_is_moving)
2533 GfxElement[jx][jy] = EL_UNDEFINED;
2535 if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
2539 if (!IN_LEV_FIELD(jx, jy))
2541 printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
2542 printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
2543 printf("DrawPlayerField(): This should never happen!\n");
2548 if (element == EL_EXPLOSION)
2551 action = (player->is_pushing ? ACTION_PUSHING :
2552 player->is_digging ? ACTION_DIGGING :
2553 player->is_collecting ? ACTION_COLLECTING :
2554 player->is_moving ? ACTION_MOVING :
2555 player->is_snapping ? ACTION_SNAPPING :
2556 player->is_dropping ? ACTION_DROPPING :
2557 player->is_waiting ? player->action_waiting : ACTION_DEFAULT);
2559 if (player->is_waiting)
2560 move_dir = player->dir_waiting;
2562 InitPlayerGfxAnimation(player, action, move_dir);
2564 /* ----------------------------------------------------------------------- */
2565 /* draw things in the field the player is leaving, if needed */
2566 /* ----------------------------------------------------------------------- */
2568 if (player->is_moving)
2570 if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
2572 DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
2574 if (last_element == EL_DYNAMITE_ACTIVE ||
2575 last_element == EL_EM_DYNAMITE_ACTIVE ||
2576 last_element == EL_SP_DISK_RED_ACTIVE)
2577 DrawDynamite(last_jx, last_jy);
2579 DrawLevelFieldThruMask(last_jx, last_jy);
2581 else if (last_element == EL_DYNAMITE_ACTIVE ||
2582 last_element == EL_EM_DYNAMITE_ACTIVE ||
2583 last_element == EL_SP_DISK_RED_ACTIVE)
2584 DrawDynamite(last_jx, last_jy);
2586 /* !!! this is not enough to prevent flickering of players which are
2587 moving next to each others without a free tile between them -- this
2588 can only be solved by drawing all players layer by layer (first the
2589 background, then the foreground etc.) !!! => TODO */
2590 else if (!IS_PLAYER(last_jx, last_jy))
2591 DrawLevelField(last_jx, last_jy);
2594 DrawLevelField(last_jx, last_jy);
2597 if (player->is_pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
2598 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
2601 if (!IN_SCR_FIELD(sx, sy))
2604 if (setup.direct_draw)
2605 SetDrawtoField(DRAW_BUFFERED);
2607 /* ----------------------------------------------------------------------- */
2608 /* draw things behind the player, if needed */
2609 /* ----------------------------------------------------------------------- */
2612 DrawLevelElement(jx, jy, Back[jx][jy]);
2613 else if (IS_ACTIVE_BOMB(element))
2614 DrawLevelElement(jx, jy, EL_EMPTY);
2617 if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
2619 int old_element = GfxElement[jx][jy];
2620 int old_graphic = el_act_dir2img(old_element, action, move_dir);
2621 int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
2623 if (GFX_CRUMBLED(old_element))
2624 DrawLevelFieldCrumbledSandDigging(jx, jy, move_dir, player->StepFrame);
2626 DrawGraphic(sx, sy, old_graphic, frame);
2628 if (graphic_info[old_graphic].anim_mode & ANIM_OPAQUE_PLAYER)
2629 player_is_opaque = TRUE;
2633 GfxElement[jx][jy] = EL_UNDEFINED;
2635 /* make sure that pushed elements are drawn with correct frame rate */
2637 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
2639 if (player->is_pushing && player->is_moving && !IS_ANIM_MODE_CE(graphic))
2640 GfxFrame[jx][jy] = player->StepFrame;
2642 if (player->is_pushing && player->is_moving)
2643 GfxFrame[jx][jy] = player->StepFrame;
2646 DrawLevelField(jx, jy);
2650 /* ----------------------------------------------------------------------- */
2651 /* draw player himself */
2652 /* ----------------------------------------------------------------------- */
2654 graphic = getPlayerGraphic(player, move_dir);
2656 /* in the case of changed player action or direction, prevent the current
2657 animation frame from being restarted for identical animations */
2658 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
2659 player->Frame = last_player_frame;
2661 frame = getGraphicAnimationFrame(graphic, player->Frame);
2665 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
2666 sxx = player->GfxPos;
2668 syy = player->GfxPos;
2671 if (!setup.soft_scrolling && ScreenMovPos)
2674 if (player_is_opaque)
2675 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
2677 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
2679 if (SHIELD_ON(player))
2681 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
2682 IMG_SHIELD_NORMAL_ACTIVE);
2683 int frame = getGraphicAnimationFrame(graphic, -1);
2685 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
2688 /* ----------------------------------------------------------------------- */
2689 /* draw things the player is pushing, if needed */
2690 /* ----------------------------------------------------------------------- */
2693 printf("::: %d, %d [%d, %d] [%d]\n",
2694 player->is_pushing, player_is_moving, player->GfxAction,
2695 player->is_moving, player_is_moving);
2699 if (player->is_pushing && player->is_moving)
2701 int px = SCREENX(jx), py = SCREENY(jy);
2702 int pxx = (TILEX - ABS(sxx)) * dx;
2703 int pyy = (TILEY - ABS(syy)) * dy;
2704 int gfx_frame = GfxFrame[jx][jy];
2710 if (!IS_MOVING(jx, jy)) /* push movement already finished */
2712 element = Feld[next_jx][next_jy];
2713 gfx_frame = GfxFrame[next_jx][next_jy];
2716 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
2719 sync_frame = (IS_ANIM_MODE_CE(graphic) ? gfx_frame : player->StepFrame);
2720 frame = getGraphicAnimationFrame(graphic, sync_frame);
2722 frame = getGraphicAnimationFrame(graphic, player->StepFrame);
2725 /* draw background element under pushed element (like the Sokoban field) */
2726 if (Back[next_jx][next_jy])
2727 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
2729 /* masked drawing is needed for EMC style (double) movement graphics */
2730 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
2734 /* ----------------------------------------------------------------------- */
2735 /* draw things in front of player (active dynamite or dynabombs) */
2736 /* ----------------------------------------------------------------------- */
2738 if (IS_ACTIVE_BOMB(element))
2740 graphic = el2img(element);
2741 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
2743 if (game.emulation == EMU_SUPAPLEX)
2744 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
2746 DrawGraphicThruMask(sx, sy, graphic, frame);
2749 if (player_is_moving && last_element == EL_EXPLOSION)
2751 int element = (GfxElement[last_jx][last_jy] != EL_UNDEFINED ?
2752 GfxElement[last_jx][last_jy] : EL_EMPTY);
2753 int graphic = el_act2img(element, ACTION_EXPLODING);
2754 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
2755 int phase = ExplodePhase[last_jx][last_jy] - 1;
2756 int frame = getGraphicAnimationFrame(graphic, phase - delay);
2759 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
2762 /* ----------------------------------------------------------------------- */
2763 /* draw elements the player is just walking/passing through/under */
2764 /* ----------------------------------------------------------------------- */
2766 if (player_is_moving)
2768 /* handle the field the player is leaving ... */
2769 if (IS_ACCESSIBLE_INSIDE(last_element))
2770 DrawLevelField(last_jx, last_jy);
2771 else if (IS_ACCESSIBLE_UNDER(last_element))
2772 DrawLevelFieldThruMask(last_jx, last_jy);
2775 /* do not redraw accessible elements if the player is just pushing them */
2776 if (!player_is_moving || !player->is_pushing)
2778 /* ... and the field the player is entering */
2779 if (IS_ACCESSIBLE_INSIDE(element))
2780 DrawLevelField(jx, jy);
2781 else if (IS_ACCESSIBLE_UNDER(element))
2782 DrawLevelFieldThruMask(jx, jy);
2785 if (setup.direct_draw)
2787 int dst_x = SX + SCREENX(MIN(jx, last_jx)) * TILEX;
2788 int dst_y = SY + SCREENY(MIN(jy, last_jy)) * TILEY;
2789 int x_size = TILEX * (1 + ABS(jx - last_jx));
2790 int y_size = TILEY * (1 + ABS(jy - last_jy));
2792 BlitBitmap(drawto_field, window,
2793 dst_x, dst_y, x_size, y_size, dst_x, dst_y);
2794 SetDrawtoField(DRAW_DIRECT);
2797 MarkTileDirty(sx, sy);
2800 /* ------------------------------------------------------------------------- */
2802 void WaitForEventToContinue()
2804 boolean still_wait = TRUE;
2806 /* simulate releasing mouse button over last gadget, if still pressed */
2808 HandleGadgets(-1, -1, 0);
2810 button_status = MB_RELEASED;
2826 case EVENT_BUTTONPRESS:
2827 case EVENT_KEYPRESS:
2831 case EVENT_KEYRELEASE:
2832 ClearPlayerAction();
2836 HandleOtherEvents(&event);
2840 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2847 /* don't eat all CPU time */
2852 #define MAX_REQUEST_LINES 13
2853 #define MAX_REQUEST_LINE_FONT1_LEN 7
2854 #define MAX_REQUEST_LINE_FONT2_LEN 10
2856 boolean Request(char *text, unsigned int req_state)
2858 int mx, my, ty, result = -1;
2859 unsigned int old_door_state;
2860 int last_game_status = game_status; /* save current game status */
2861 int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
2862 int font_nr = FONT_TEXT_2;
2863 int max_word_len = 0;
2866 for (text_ptr = text; *text_ptr; text_ptr++)
2868 max_word_len = (*text_ptr != ' ' ? max_word_len + 1 : 0);
2870 if (max_word_len > MAX_REQUEST_LINE_FONT1_LEN)
2872 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
2874 font_nr = FONT_TEXT_1;
2876 font_nr = FONT_LEVEL_NUMBER;
2883 if (game_status == GAME_MODE_PLAYING &&
2884 level.game_engine_type == GAME_ENGINE_TYPE_EM)
2885 BlitScreenToBitmap_EM(backbuffer);
2887 /* disable deactivated drawing when quick-loading level tape recording */
2888 if (tape.playing && tape.deactivate_display)
2889 TapeDeactivateDisplayOff(TRUE);
2891 SetMouseCursor(CURSOR_DEFAULT);
2893 #if defined(NETWORK_AVALIABLE)
2894 /* pause network game while waiting for request to answer */
2895 if (options.network &&
2896 game_status == GAME_MODE_PLAYING &&
2897 req_state & REQUEST_WAIT_FOR_INPUT)
2898 SendToServer_PausePlaying();
2901 old_door_state = GetDoorState();
2903 /* simulate releasing mouse button over last gadget, if still pressed */
2905 HandleGadgets(-1, -1, 0);
2909 if (old_door_state & DOOR_OPEN_1)
2911 CloseDoor(DOOR_CLOSE_1);
2913 /* save old door content */
2914 BlitBitmap(bitmap_db_door, bitmap_db_door,
2915 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
2916 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
2920 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
2923 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2925 /* clear door drawing field */
2926 DrawBackground(DX, DY, DXSIZE, DYSIZE);
2928 /* force DOOR font inside door area */
2929 game_status = GAME_MODE_PSEUDO_DOOR;
2931 /* write text for request */
2932 for (ty = 0; ty < MAX_REQUEST_LINES; ty++)
2934 char text_line[max_request_line_len + 1];
2940 for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
2943 if (!tc || tc == ' ')
2954 strncpy(text_line, text, tl);
2957 DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
2958 DY + 8 + ty * (getFontHeight(font_nr) + 2),
2959 text_line, font_nr);
2961 text += tl + (tc == ' ' ? 1 : 0);
2964 game_status = last_game_status; /* restore current game status */
2966 if (req_state & REQ_ASK)
2968 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
2969 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
2971 else if (req_state & REQ_CONFIRM)
2973 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
2975 else if (req_state & REQ_PLAYER)
2977 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
2978 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
2979 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
2980 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
2983 /* copy request gadgets to door backbuffer */
2984 BlitBitmap(drawto, bitmap_db_door,
2985 DX, DY, DXSIZE, DYSIZE,
2986 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2988 OpenDoor(DOOR_OPEN_1);
2990 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
2992 if (game_status == GAME_MODE_PLAYING)
2994 SetPanelBackground();
2995 SetDrawBackgroundMask(REDRAW_DOOR_1);
2999 SetDrawBackgroundMask(REDRAW_FIELD);
3005 if (game_status != GAME_MODE_MAIN)
3008 button_status = MB_RELEASED;
3010 request_gadget_id = -1;
3012 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3024 case EVENT_BUTTONPRESS:
3025 case EVENT_BUTTONRELEASE:
3026 case EVENT_MOTIONNOTIFY:
3028 if (event.type == EVENT_MOTIONNOTIFY)
3030 if (!PointerInWindow(window))
3031 continue; /* window and pointer are on different screens */
3036 motion_status = TRUE;
3037 mx = ((MotionEvent *) &event)->x;
3038 my = ((MotionEvent *) &event)->y;
3042 motion_status = FALSE;
3043 mx = ((ButtonEvent *) &event)->x;
3044 my = ((ButtonEvent *) &event)->y;
3045 if (event.type == EVENT_BUTTONPRESS)
3046 button_status = ((ButtonEvent *) &event)->button;
3048 button_status = MB_RELEASED;
3051 /* this sets 'request_gadget_id' */
3052 HandleGadgets(mx, my, button_status);
3054 switch (request_gadget_id)
3056 case TOOL_CTRL_ID_YES:
3059 case TOOL_CTRL_ID_NO:
3062 case TOOL_CTRL_ID_CONFIRM:
3063 result = TRUE | FALSE;
3066 case TOOL_CTRL_ID_PLAYER_1:
3069 case TOOL_CTRL_ID_PLAYER_2:
3072 case TOOL_CTRL_ID_PLAYER_3:
3075 case TOOL_CTRL_ID_PLAYER_4:
3086 case EVENT_KEYPRESS:
3087 switch (GetEventKey((KeyEvent *)&event, TRUE))
3090 if (req_state & REQ_CONFIRM)
3106 if (req_state & REQ_PLAYER)
3110 case EVENT_KEYRELEASE:
3111 ClearPlayerAction();
3115 HandleOtherEvents(&event);
3119 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
3121 int joy = AnyJoystick();
3123 if (joy & JOY_BUTTON_1)
3125 else if (joy & JOY_BUTTON_2)
3131 if (game_status == GAME_MODE_PLAYING && local_player->LevelSolved_GameEnd)
3133 HandleGameActions();
3139 if (!PendingEvent()) /* delay only if no pending events */
3150 if (!PendingEvent()) /* delay only if no pending events */
3153 /* don't eat all CPU time */
3160 if (game_status != GAME_MODE_MAIN)
3165 if (!(req_state & REQ_STAY_OPEN))
3167 CloseDoor(DOOR_CLOSE_1);
3169 if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
3170 (req_state & REQ_REOPEN))
3171 OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
3176 if (game_status == GAME_MODE_PLAYING)
3178 SetPanelBackground();
3179 SetDrawBackgroundMask(REDRAW_DOOR_1);
3183 SetDrawBackgroundMask(REDRAW_FIELD);
3186 #if defined(NETWORK_AVALIABLE)
3187 /* continue network game after request */
3188 if (options.network &&
3189 game_status == GAME_MODE_PLAYING &&
3190 req_state & REQUEST_WAIT_FOR_INPUT)
3191 SendToServer_ContinuePlaying();
3194 /* restore deactivated drawing when quick-loading level tape recording */
3195 if (tape.playing && tape.deactivate_display)
3196 TapeDeactivateDisplayOn();
3201 unsigned int OpenDoor(unsigned int door_state)
3203 if (door_state & DOOR_COPY_BACK)
3205 if (door_state & DOOR_OPEN_1)
3206 BlitBitmap(bitmap_db_door, bitmap_db_door,
3207 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
3208 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
3210 if (door_state & DOOR_OPEN_2)
3211 BlitBitmap(bitmap_db_door, bitmap_db_door,
3212 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY2, VXSIZE, VYSIZE,
3213 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
3215 door_state &= ~DOOR_COPY_BACK;
3218 return MoveDoor(door_state);
3221 unsigned int CloseDoor(unsigned int door_state)
3223 unsigned int old_door_state = GetDoorState();
3225 if (!(door_state & DOOR_NO_COPY_BACK))
3227 if (old_door_state & DOOR_OPEN_1)
3228 BlitBitmap(backbuffer, bitmap_db_door,
3229 DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
3231 if (old_door_state & DOOR_OPEN_2)
3232 BlitBitmap(backbuffer, bitmap_db_door,
3233 VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
3235 door_state &= ~DOOR_NO_COPY_BACK;
3238 return MoveDoor(door_state);
3241 unsigned int GetDoorState()
3243 return MoveDoor(DOOR_GET_STATE);
3246 unsigned int SetDoorState(unsigned int door_state)
3248 return MoveDoor(door_state | DOOR_SET_STATE);
3251 unsigned int MoveDoor(unsigned int door_state)
3253 static int door1 = DOOR_OPEN_1;
3254 static int door2 = DOOR_CLOSE_2;
3255 unsigned long door_delay = 0;
3256 unsigned long door_delay_value;
3259 if (door_1.width < 0 || door_1.width > DXSIZE)
3260 door_1.width = DXSIZE;
3261 if (door_1.height < 0 || door_1.height > DYSIZE)
3262 door_1.height = DYSIZE;
3263 if (door_2.width < 0 || door_2.width > VXSIZE)
3264 door_2.width = VXSIZE;
3265 if (door_2.height < 0 || door_2.height > VYSIZE)
3266 door_2.height = VYSIZE;
3268 if (door_state == DOOR_GET_STATE)
3269 return (door1 | door2);
3271 if (door_state & DOOR_SET_STATE)
3273 if (door_state & DOOR_ACTION_1)
3274 door1 = door_state & DOOR_ACTION_1;
3275 if (door_state & DOOR_ACTION_2)
3276 door2 = door_state & DOOR_ACTION_2;
3278 return (door1 | door2);
3281 if (!(door_state & DOOR_FORCE_REDRAW))
3283 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
3284 door_state &= ~DOOR_OPEN_1;
3285 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
3286 door_state &= ~DOOR_CLOSE_1;
3287 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
3288 door_state &= ~DOOR_OPEN_2;
3289 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
3290 door_state &= ~DOOR_CLOSE_2;
3293 door_delay_value = (door_state & DOOR_ACTION_1 ? door_1.step_delay :
3296 if (setup.quick_doors)
3298 stepsize = 20; /* must be chosen to always draw last frame */
3299 door_delay_value = 0;
3302 if (global.autoplay_leveldir)
3304 door_state |= DOOR_NO_DELAY;
3305 door_state &= ~DOOR_CLOSE_ALL;
3308 if (door_state & DOOR_ACTION)
3310 boolean handle_door_1 = (door_state & DOOR_ACTION_1);
3311 boolean handle_door_2 = (door_state & DOOR_ACTION_2);
3312 boolean door_1_done = (!handle_door_1);
3313 boolean door_2_done = (!handle_door_2);
3314 boolean door_1_vertical = (door_1.anim_mode & ANIM_VERTICAL);
3315 boolean door_2_vertical = (door_2.anim_mode & ANIM_VERTICAL);
3316 int door_size_1 = (door_1_vertical ? door_1.height : door_1.width);
3317 int door_size_2 = (door_2_vertical ? door_2.height : door_2.width);
3318 int max_door_size_1 = (door_1_vertical ? DYSIZE : DXSIZE);
3319 int max_door_size_2 = (door_2_vertical ? VYSIZE : VXSIZE);
3320 int door_size = (handle_door_1 ? door_size_1 : door_size_2);
3321 int max_door_size = (handle_door_1 ? max_door_size_1 : max_door_size_2);
3322 int door_skip = max_door_size - door_size;
3323 int end = door_size;
3324 int start = ((door_state & DOOR_NO_DELAY) ? end : 0);
3327 if (!(door_state & DOOR_NO_DELAY) && !setup.quick_doors)
3329 /* opening door sound has priority over simultaneously closing door */
3330 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
3331 PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
3332 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
3333 PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
3336 for (k = start; k <= end && !(door_1_done && door_2_done); k += stepsize)
3339 Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
3340 GC gc = bitmap->stored_clip_gc;
3342 if (door_state & DOOR_ACTION_1)
3344 int a = MIN(x * door_1.step_offset, end);
3345 int p = (door_state & DOOR_OPEN_1 ? end - a : a);
3346 int i = p + door_skip;
3348 if (door_1.anim_mode & ANIM_STATIC_PANEL)
3350 BlitBitmap(bitmap_db_door, drawto,
3351 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1,
3352 DXSIZE, DYSIZE, DX, DY);
3356 BlitBitmap(bitmap_db_door, drawto,
3357 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + p / 2,
3358 DXSIZE, DYSIZE - p / 2, DX, DY);
3360 ClearRectangle(drawto, DX, DY + DYSIZE - p / 2, DXSIZE, p / 2);
3363 if (door_1.anim_mode & ANIM_HORIZONTAL && x <= DXSIZE)
3365 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
3366 int dst1_x = DX + DXSIZE - i, dst1_y = DY;
3367 int src2_x = DXSIZE - i, src2_y = DOOR_GFX_PAGEY1;
3368 int dst2_x = DX, dst2_y = DY;
3369 int width = i, height = DYSIZE;
3371 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3372 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3375 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3376 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3379 else if (door_1.anim_mode & ANIM_VERTICAL && x <= DYSIZE)
3381 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
3382 int dst1_x = DX, dst1_y = DY + DYSIZE - i;
3383 int src2_x = 0, src2_y = DOOR_GFX_PAGEY1 + DYSIZE - i;
3384 int dst2_x = DX, dst2_y = DY;
3385 int width = DXSIZE, height = i;
3387 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3388 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3391 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3392 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3395 else if (x <= DXSIZE) /* ANIM_DEFAULT */
3397 int j = (door_1.anim_mode == ANIM_DEFAULT ? (DXSIZE - i) / 3 : 0);
3399 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
3400 BlitBitmapMasked(bitmap, drawto,
3401 DXSIZE, DOOR_GFX_PAGEY1, i, 77,
3402 DX + DXSIZE - i, DY + j);
3403 BlitBitmapMasked(bitmap, drawto,
3404 DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
3405 DX + DXSIZE - i, DY + 140 + j);
3406 SetClipOrigin(bitmap, gc, DX - DXSIZE + i,
3407 DY - (DOOR_GFX_PAGEY1 + j));
3408 BlitBitmapMasked(bitmap, drawto,
3409 DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
3411 BlitBitmapMasked(bitmap, drawto,
3412 DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
3415 BlitBitmapMasked(bitmap, drawto,
3416 DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
3418 BlitBitmapMasked(bitmap, drawto,
3419 DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
3421 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
3422 BlitBitmapMasked(bitmap, drawto,
3423 DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
3424 DX + DXSIZE - i, DY + 77 + j);
3425 BlitBitmapMasked(bitmap, drawto,
3426 DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
3427 DX + DXSIZE - i, DY + 203 + j);
3430 redraw_mask |= REDRAW_DOOR_1;
3431 door_1_done = (a == end);
3434 if (door_state & DOOR_ACTION_2)
3436 int a = MIN(x * door_2.step_offset, door_size);
3437 int p = (door_state & DOOR_OPEN_2 ? door_size - a : a);
3438 int i = p + door_skip;
3440 if (door_2.anim_mode & ANIM_STATIC_PANEL)
3442 BlitBitmap(bitmap_db_door, drawto,
3443 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2,
3444 VXSIZE, VYSIZE, VX, VY);
3446 else if (x <= VYSIZE)
3448 BlitBitmap(bitmap_db_door, drawto,
3449 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + p / 2,
3450 VXSIZE, VYSIZE - p / 2, VX, VY);
3452 ClearRectangle(drawto, VX, VY + VYSIZE - p / 2, VXSIZE, p / 2);
3455 if (door_2.anim_mode & ANIM_HORIZONTAL && x <= VXSIZE)
3457 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
3458 int dst1_x = VX + VXSIZE - i, dst1_y = VY;
3459 int src2_x = VXSIZE - i, src2_y = DOOR_GFX_PAGEY2;
3460 int dst2_x = VX, dst2_y = VY;
3461 int width = i, height = VYSIZE;
3463 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3464 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3467 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3468 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3471 else if (door_2.anim_mode & ANIM_VERTICAL && x <= VYSIZE)
3473 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
3474 int dst1_x = VX, dst1_y = VY + VYSIZE - i;
3475 int src2_x = 0, src2_y = DOOR_GFX_PAGEY2 + VYSIZE - i;
3476 int dst2_x = VX, dst2_y = VY;
3477 int width = VXSIZE, height = i;
3479 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3480 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3483 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3484 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3487 else if (x <= VXSIZE) /* ANIM_DEFAULT */
3489 int j = (door_2.anim_mode == ANIM_DEFAULT ? (VXSIZE - i) / 3 : 0);
3491 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
3492 BlitBitmapMasked(bitmap, drawto,
3493 VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
3494 VX + VXSIZE - i, VY + j);
3495 SetClipOrigin(bitmap, gc,
3496 VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
3497 BlitBitmapMasked(bitmap, drawto,
3498 VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
3501 BlitBitmapMasked(bitmap, drawto,
3502 VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
3503 i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
3504 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
3505 BlitBitmapMasked(bitmap, drawto,
3506 VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
3508 VX + VXSIZE - i, VY + VYSIZE / 2 + j);
3511 redraw_mask |= REDRAW_DOOR_2;
3512 door_2_done = (a == VXSIZE);
3515 if (!(door_state & DOOR_NO_DELAY))
3519 if (game_status == GAME_MODE_MAIN)
3522 WaitUntilDelayReached(&door_delay, door_delay_value);
3527 if (door_state & DOOR_ACTION_1)
3528 door1 = door_state & DOOR_ACTION_1;
3529 if (door_state & DOOR_ACTION_2)
3530 door2 = door_state & DOOR_ACTION_2;
3532 return (door1 | door2);
3535 void DrawSpecialEditorDoor()
3537 /* draw bigger toolbox window */
3538 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
3539 DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
3541 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
3542 EX - 6, VY - 4, EXSIZE + 12, EYSIZE - VYSIZE + 4,
3545 redraw_mask |= REDRAW_ALL;
3548 void UndrawSpecialEditorDoor()
3550 /* draw normal tape recorder window */
3551 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
3552 EX - 6, EY - 12, EXSIZE + 12, EYSIZE - VYSIZE + 12,
3555 redraw_mask |= REDRAW_ALL;
3559 /* ---------- new tool button stuff ---------------------------------------- */
3561 /* graphic position values for tool buttons */
3562 #define TOOL_BUTTON_YES_XPOS 2
3563 #define TOOL_BUTTON_YES_YPOS 250
3564 #define TOOL_BUTTON_YES_GFX_YPOS 0
3565 #define TOOL_BUTTON_YES_XSIZE 46
3566 #define TOOL_BUTTON_YES_YSIZE 28
3567 #define TOOL_BUTTON_NO_XPOS 52
3568 #define TOOL_BUTTON_NO_YPOS TOOL_BUTTON_YES_YPOS
3569 #define TOOL_BUTTON_NO_GFX_YPOS TOOL_BUTTON_YES_GFX_YPOS
3570 #define TOOL_BUTTON_NO_XSIZE TOOL_BUTTON_YES_XSIZE
3571 #define TOOL_BUTTON_NO_YSIZE TOOL_BUTTON_YES_YSIZE
3572 #define TOOL_BUTTON_CONFIRM_XPOS TOOL_BUTTON_YES_XPOS
3573 #define TOOL_BUTTON_CONFIRM_YPOS TOOL_BUTTON_YES_YPOS
3574 #define TOOL_BUTTON_CONFIRM_GFX_YPOS 30
3575 #define TOOL_BUTTON_CONFIRM_XSIZE 96
3576 #define TOOL_BUTTON_CONFIRM_YSIZE TOOL_BUTTON_YES_YSIZE
3577 #define TOOL_BUTTON_PLAYER_XSIZE 30
3578 #define TOOL_BUTTON_PLAYER_YSIZE 30
3579 #define TOOL_BUTTON_PLAYER_GFX_XPOS 5
3580 #define TOOL_BUTTON_PLAYER_GFX_YPOS 185
3581 #define TOOL_BUTTON_PLAYER_XPOS (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
3582 #define TOOL_BUTTON_PLAYER_YPOS (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
3583 #define TOOL_BUTTON_PLAYER1_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3584 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
3585 #define TOOL_BUTTON_PLAYER2_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3586 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
3587 #define TOOL_BUTTON_PLAYER3_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3588 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
3589 #define TOOL_BUTTON_PLAYER4_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3590 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
3591 #define TOOL_BUTTON_PLAYER1_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3592 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
3593 #define TOOL_BUTTON_PLAYER2_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3594 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
3595 #define TOOL_BUTTON_PLAYER3_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3596 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
3597 #define TOOL_BUTTON_PLAYER4_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3598 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
3607 } toolbutton_info[NUM_TOOL_BUTTONS] =
3610 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_GFX_YPOS,
3611 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_YPOS,
3612 TOOL_BUTTON_YES_XSIZE, TOOL_BUTTON_YES_YSIZE,
3617 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_GFX_YPOS,
3618 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_YPOS,
3619 TOOL_BUTTON_NO_XSIZE, TOOL_BUTTON_NO_YSIZE,
3624 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_GFX_YPOS,
3625 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_YPOS,
3626 TOOL_BUTTON_CONFIRM_XSIZE, TOOL_BUTTON_CONFIRM_YSIZE,
3627 TOOL_CTRL_ID_CONFIRM,
3631 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3632 TOOL_BUTTON_PLAYER1_XPOS, TOOL_BUTTON_PLAYER1_YPOS,
3633 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3634 TOOL_CTRL_ID_PLAYER_1,
3638 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3639 TOOL_BUTTON_PLAYER2_XPOS, TOOL_BUTTON_PLAYER2_YPOS,
3640 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3641 TOOL_CTRL_ID_PLAYER_2,
3645 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3646 TOOL_BUTTON_PLAYER3_XPOS, TOOL_BUTTON_PLAYER3_YPOS,
3647 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3648 TOOL_CTRL_ID_PLAYER_3,
3652 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3653 TOOL_BUTTON_PLAYER4_XPOS, TOOL_BUTTON_PLAYER4_YPOS,
3654 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3655 TOOL_CTRL_ID_PLAYER_4,
3660 void CreateToolButtons()
3664 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3666 Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
3667 Bitmap *deco_bitmap = None;
3668 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
3669 struct GadgetInfo *gi;
3670 unsigned long event_mask;
3671 int gd_xoffset, gd_yoffset;
3672 int gd_x1, gd_x2, gd_y;
3675 event_mask = GD_EVENT_RELEASED;
3677 gd_xoffset = toolbutton_info[i].xpos;
3678 gd_yoffset = toolbutton_info[i].ypos;
3679 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
3680 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
3681 gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
3683 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
3685 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
3687 getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr),
3688 &deco_bitmap, &deco_x, &deco_y);
3689 deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
3690 deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
3693 gi = CreateGadget(GDI_CUSTOM_ID, id,
3694 GDI_INFO_TEXT, toolbutton_info[i].infotext,
3695 GDI_X, DX + toolbutton_info[i].x,
3696 GDI_Y, DY + toolbutton_info[i].y,
3697 GDI_WIDTH, toolbutton_info[i].width,
3698 GDI_HEIGHT, toolbutton_info[i].height,
3699 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
3700 GDI_STATE, GD_BUTTON_UNPRESSED,
3701 GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
3702 GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
3703 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
3704 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
3705 GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
3706 GDI_DECORATION_SHIFTING, 1, 1,
3707 GDI_DIRECT_DRAW, FALSE,
3708 GDI_EVENT_MASK, event_mask,
3709 GDI_CALLBACK_ACTION, HandleToolButtons,
3713 Error(ERR_EXIT, "cannot create gadget");
3715 tool_gadget[id] = gi;
3719 void FreeToolButtons()
3723 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3724 FreeGadget(tool_gadget[i]);
3727 static void UnmapToolButtons()
3731 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3732 UnmapGadget(tool_gadget[i]);
3735 static void HandleToolButtons(struct GadgetInfo *gi)
3737 request_gadget_id = gi->custom_id;
3740 static struct Mapping_EM_to_RND_object
3743 boolean is_rnd_to_em_mapping; /* unique mapping EM <-> RND */
3744 boolean is_backside; /* backside of moving element */
3750 em_object_mapping_list[] =
3753 Xblank, TRUE, FALSE,
3757 Yacid_splash_eB, FALSE, FALSE,
3758 EL_ACID_SPLASH_RIGHT, -1, -1
3761 Yacid_splash_wB, FALSE, FALSE,
3762 EL_ACID_SPLASH_LEFT, -1, -1
3765 #ifdef EM_ENGINE_BAD_ROLL
3767 Xstone_force_e, FALSE, FALSE,
3768 EL_ROCK, -1, MV_BIT_RIGHT
3771 Xstone_force_w, FALSE, FALSE,
3772 EL_ROCK, -1, MV_BIT_LEFT
3775 Xnut_force_e, FALSE, FALSE,
3776 EL_NUT, -1, MV_BIT_RIGHT
3779 Xnut_force_w, FALSE, FALSE,
3780 EL_NUT, -1, MV_BIT_LEFT
3783 Xspring_force_e, FALSE, FALSE,
3784 EL_SPRING, -1, MV_BIT_RIGHT
3787 Xspring_force_w, FALSE, FALSE,
3788 EL_SPRING, -1, MV_BIT_LEFT
3791 Xemerald_force_e, FALSE, FALSE,
3792 EL_EMERALD, -1, MV_BIT_RIGHT
3795 Xemerald_force_w, FALSE, FALSE,
3796 EL_EMERALD, -1, MV_BIT_LEFT
3799 Xdiamond_force_e, FALSE, FALSE,
3800 EL_DIAMOND, -1, MV_BIT_RIGHT
3803 Xdiamond_force_w, FALSE, FALSE,
3804 EL_DIAMOND, -1, MV_BIT_LEFT
3807 Xbomb_force_e, FALSE, FALSE,
3808 EL_BOMB, -1, MV_BIT_RIGHT
3811 Xbomb_force_w, FALSE, FALSE,
3812 EL_BOMB, -1, MV_BIT_LEFT
3814 #endif /* EM_ENGINE_BAD_ROLL */
3817 Xstone, TRUE, FALSE,
3821 Xstone_pause, FALSE, FALSE,
3825 Xstone_fall, FALSE, FALSE,
3829 Ystone_s, FALSE, FALSE,
3830 EL_ROCK, ACTION_FALLING, -1
3833 Ystone_sB, FALSE, TRUE,
3834 EL_ROCK, ACTION_FALLING, -1
3837 Ystone_e, FALSE, FALSE,
3838 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
3841 Ystone_eB, FALSE, TRUE,
3842 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
3845 Ystone_w, FALSE, FALSE,
3846 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
3849 Ystone_wB, FALSE, TRUE,
3850 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
3857 Xnut_pause, FALSE, FALSE,
3861 Xnut_fall, FALSE, FALSE,
3865 Ynut_s, FALSE, FALSE,
3866 EL_NUT, ACTION_FALLING, -1
3869 Ynut_sB, FALSE, TRUE,
3870 EL_NUT, ACTION_FALLING, -1
3873 Ynut_e, FALSE, FALSE,
3874 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
3877 Ynut_eB, FALSE, TRUE,
3878 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
3881 Ynut_w, FALSE, FALSE,
3882 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
3885 Ynut_wB, FALSE, TRUE,
3886 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
3889 Xbug_n, TRUE, FALSE,
3893 Xbug_e, TRUE, FALSE,
3894 EL_BUG_RIGHT, -1, -1
3897 Xbug_s, TRUE, FALSE,
3901 Xbug_w, TRUE, FALSE,
3905 Xbug_gon, FALSE, FALSE,
3909 Xbug_goe, FALSE, FALSE,
3910 EL_BUG_RIGHT, -1, -1
3913 Xbug_gos, FALSE, FALSE,
3917 Xbug_gow, FALSE, FALSE,
3921 Ybug_n, FALSE, FALSE,
3922 EL_BUG, ACTION_MOVING, MV_BIT_UP
3925 Ybug_nB, FALSE, TRUE,
3926 EL_BUG, ACTION_MOVING, MV_BIT_UP
3929 Ybug_e, FALSE, FALSE,
3930 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
3933 Ybug_eB, FALSE, TRUE,
3934 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
3937 Ybug_s, FALSE, FALSE,
3938 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
3941 Ybug_sB, FALSE, TRUE,
3942 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
3945 Ybug_w, FALSE, FALSE,
3946 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
3949 Ybug_wB, FALSE, TRUE,
3950 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
3953 Ybug_w_n, FALSE, FALSE,
3954 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
3957 Ybug_n_e, FALSE, FALSE,
3958 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
3961 Ybug_e_s, FALSE, FALSE,
3962 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
3965 Ybug_s_w, FALSE, FALSE,
3966 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
3969 Ybug_e_n, FALSE, FALSE,
3970 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
3973 Ybug_s_e, FALSE, FALSE,
3974 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
3977 Ybug_w_s, FALSE, FALSE,
3978 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
3981 Ybug_n_w, FALSE, FALSE,
3982 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
3985 Ybug_stone, FALSE, FALSE,
3986 EL_BUG, ACTION_SMASHED_BY_ROCK, -1
3989 Ybug_spring, FALSE, FALSE,
3990 EL_BUG, ACTION_SMASHED_BY_SPRING, -1
3993 Xtank_n, TRUE, FALSE,
3994 EL_SPACESHIP_UP, -1, -1
3997 Xtank_e, TRUE, FALSE,
3998 EL_SPACESHIP_RIGHT, -1, -1
4001 Xtank_s, TRUE, FALSE,
4002 EL_SPACESHIP_DOWN, -1, -1
4005 Xtank_w, TRUE, FALSE,
4006 EL_SPACESHIP_LEFT, -1, -1
4009 Xtank_gon, FALSE, FALSE,
4010 EL_SPACESHIP_UP, -1, -1
4013 Xtank_goe, FALSE, FALSE,
4014 EL_SPACESHIP_RIGHT, -1, -1
4017 Xtank_gos, FALSE, FALSE,
4018 EL_SPACESHIP_DOWN, -1, -1
4021 Xtank_gow, FALSE, FALSE,
4022 EL_SPACESHIP_LEFT, -1, -1
4025 Ytank_n, FALSE, FALSE,
4026 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
4029 Ytank_nB, FALSE, TRUE,
4030 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
4033 Ytank_e, FALSE, FALSE,
4034 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
4037 Ytank_eB, FALSE, TRUE,
4038 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
4041 Ytank_s, FALSE, FALSE,
4042 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
4045 Ytank_sB, FALSE, TRUE,
4046 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
4049 Ytank_w, FALSE, FALSE,
4050 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
4053 Ytank_wB, FALSE, TRUE,
4054 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
4057 Ytank_w_n, FALSE, FALSE,
4058 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
4061 Ytank_n_e, FALSE, FALSE,
4062 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
4065 Ytank_e_s, FALSE, FALSE,
4066 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
4069 Ytank_s_w, FALSE, FALSE,
4070 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
4073 Ytank_e_n, FALSE, FALSE,
4074 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
4077 Ytank_s_e, FALSE, FALSE,
4078 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
4081 Ytank_w_s, FALSE, FALSE,
4082 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
4085 Ytank_n_w, FALSE, FALSE,
4086 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
4089 Ytank_stone, FALSE, FALSE,
4090 EL_SPACESHIP, ACTION_SMASHED_BY_ROCK, -1
4093 Ytank_spring, FALSE, FALSE,
4094 EL_SPACESHIP, ACTION_SMASHED_BY_SPRING, -1
4097 Xandroid, TRUE, FALSE,
4098 EL_EMC_ANDROID, ACTION_ACTIVE, -1
4101 Xandroid_1_n, FALSE, FALSE,
4102 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
4105 Xandroid_2_n, FALSE, FALSE,
4106 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
4109 Xandroid_1_e, FALSE, FALSE,
4110 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
4113 Xandroid_2_e, FALSE, FALSE,
4114 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
4117 Xandroid_1_w, FALSE, FALSE,
4118 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
4121 Xandroid_2_w, FALSE, FALSE,
4122 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
4125 Xandroid_1_s, FALSE, FALSE,
4126 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
4129 Xandroid_2_s, FALSE, FALSE,
4130 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
4133 Yandroid_n, FALSE, FALSE,
4134 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
4137 Yandroid_nB, FALSE, TRUE,
4138 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
4141 Yandroid_ne, FALSE, FALSE,
4142 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPRIGHT
4145 Yandroid_neB, FALSE, TRUE,
4146 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPRIGHT
4149 Yandroid_e, FALSE, FALSE,
4150 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
4153 Yandroid_eB, FALSE, TRUE,
4154 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
4157 Yandroid_se, FALSE, FALSE,
4158 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNRIGHT
4161 Yandroid_seB, FALSE, TRUE,
4162 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNRIGHT
4165 Yandroid_s, FALSE, FALSE,
4166 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
4169 Yandroid_sB, FALSE, TRUE,
4170 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
4173 Yandroid_sw, FALSE, FALSE,
4174 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNLEFT
4177 Yandroid_swB, FALSE, TRUE,
4178 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNLEFT
4181 Yandroid_w, FALSE, FALSE,
4182 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
4185 Yandroid_wB, FALSE, TRUE,
4186 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
4189 Yandroid_nw, FALSE, FALSE,
4190 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPLEFT
4193 Yandroid_nwB, FALSE, TRUE,
4194 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPLEFT
4197 Xspring, TRUE, FALSE,
4201 Xspring_pause, FALSE, FALSE,
4205 Xspring_e, FALSE, FALSE,
4209 Xspring_w, FALSE, FALSE,
4213 Xspring_fall, FALSE, FALSE,
4217 Yspring_s, FALSE, FALSE,
4218 EL_SPRING, ACTION_FALLING, -1
4221 Yspring_sB, FALSE, TRUE,
4222 EL_SPRING, ACTION_FALLING, -1
4225 Yspring_e, FALSE, FALSE,
4226 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
4229 Yspring_eB, FALSE, TRUE,
4230 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
4233 Yspring_w, FALSE, FALSE,
4234 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
4237 Yspring_wB, FALSE, TRUE,
4238 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
4241 Yspring_kill_e, FALSE, FALSE,
4242 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
4245 Yspring_kill_eB, FALSE, TRUE,
4246 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
4249 Yspring_kill_w, FALSE, FALSE,
4250 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
4253 Yspring_kill_wB, FALSE, TRUE,
4254 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
4257 Xeater_n, TRUE, FALSE,
4258 EL_YAMYAM_UP, -1, -1
4261 Xeater_e, TRUE, FALSE,
4262 EL_YAMYAM_RIGHT, -1, -1
4265 Xeater_w, TRUE, FALSE,
4266 EL_YAMYAM_LEFT, -1, -1
4269 Xeater_s, TRUE, FALSE,
4270 EL_YAMYAM_DOWN, -1, -1
4273 Yeater_n, FALSE, FALSE,
4274 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
4277 Yeater_nB, FALSE, TRUE,
4278 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
4281 Yeater_e, FALSE, FALSE,
4282 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
4285 Yeater_eB, FALSE, TRUE,
4286 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
4289 Yeater_s, FALSE, FALSE,
4290 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
4293 Yeater_sB, FALSE, TRUE,
4294 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
4297 Yeater_w, FALSE, FALSE,
4298 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
4301 Yeater_wB, FALSE, TRUE,
4302 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
4305 Yeater_stone, FALSE, FALSE,
4306 EL_YAMYAM, ACTION_SMASHED_BY_ROCK, -1
4309 Yeater_spring, FALSE, FALSE,
4310 EL_YAMYAM, ACTION_SMASHED_BY_SPRING, -1
4313 Xalien, TRUE, FALSE,
4317 Xalien_pause, FALSE, FALSE,
4321 Yalien_n, FALSE, FALSE,
4322 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
4325 Yalien_nB, FALSE, TRUE,
4326 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
4329 Yalien_e, FALSE, FALSE,
4330 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
4333 Yalien_eB, FALSE, TRUE,
4334 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
4337 Yalien_s, FALSE, FALSE,
4338 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
4341 Yalien_sB, FALSE, TRUE,
4342 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
4345 Yalien_w, FALSE, FALSE,
4346 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
4349 Yalien_wB, FALSE, TRUE,
4350 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
4353 Yalien_stone, FALSE, FALSE,
4354 EL_ROBOT, ACTION_SMASHED_BY_ROCK, -1
4357 Yalien_spring, FALSE, FALSE,
4358 EL_ROBOT, ACTION_SMASHED_BY_SPRING, -1
4361 Xemerald, TRUE, FALSE,
4365 Xemerald_pause, FALSE, FALSE,
4369 Xemerald_fall, FALSE, FALSE,
4373 Xemerald_shine, FALSE, FALSE,
4374 EL_EMERALD, ACTION_TWINKLING, -1
4377 Yemerald_s, FALSE, FALSE,
4378 EL_EMERALD, ACTION_FALLING, -1
4381 Yemerald_sB, FALSE, TRUE,
4382 EL_EMERALD, ACTION_FALLING, -1
4385 Yemerald_e, FALSE, FALSE,
4386 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
4389 Yemerald_eB, FALSE, TRUE,
4390 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
4393 Yemerald_w, FALSE, FALSE,
4394 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
4397 Yemerald_wB, FALSE, TRUE,
4398 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
4401 Yemerald_eat, FALSE, FALSE,
4402 EL_EMERALD, ACTION_COLLECTING, -1
4405 Yemerald_stone, FALSE, FALSE,
4406 EL_NUT, ACTION_BREAKING, -1
4409 Xdiamond, TRUE, FALSE,
4413 Xdiamond_pause, FALSE, FALSE,
4417 Xdiamond_fall, FALSE, FALSE,
4421 Xdiamond_shine, FALSE, FALSE,
4422 EL_DIAMOND, ACTION_TWINKLING, -1
4425 Ydiamond_s, FALSE, FALSE,
4426 EL_DIAMOND, ACTION_FALLING, -1
4429 Ydiamond_sB, FALSE, TRUE,
4430 EL_DIAMOND, ACTION_FALLING, -1
4433 Ydiamond_e, FALSE, FALSE,
4434 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
4437 Ydiamond_eB, FALSE, TRUE,
4438 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
4441 Ydiamond_w, FALSE, FALSE,
4442 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
4445 Ydiamond_wB, FALSE, TRUE,
4446 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
4449 Ydiamond_eat, FALSE, FALSE,
4450 EL_DIAMOND, ACTION_COLLECTING, -1
4453 Ydiamond_stone, FALSE, FALSE,
4454 EL_DIAMOND, ACTION_SMASHED_BY_ROCK, -1
4457 Xdrip_fall, TRUE, FALSE,
4458 EL_AMOEBA_DROP, -1, -1
4461 Xdrip_stretch, FALSE, FALSE,
4462 EL_AMOEBA_DROP, ACTION_FALLING, -1
4465 Xdrip_stretchB, FALSE, TRUE,
4466 EL_AMOEBA_DROP, ACTION_FALLING, -1
4469 Xdrip_eat, FALSE, FALSE,
4470 EL_AMOEBA_DROP, ACTION_GROWING, -1
4473 Ydrip_s1, FALSE, FALSE,
4474 EL_AMOEBA_DROP, ACTION_FALLING, -1
4477 Ydrip_s1B, FALSE, TRUE,
4478 EL_AMOEBA_DROP, ACTION_FALLING, -1
4481 Ydrip_s2, FALSE, FALSE,
4482 EL_AMOEBA_DROP, ACTION_FALLING, -1
4485 Ydrip_s2B, FALSE, TRUE,
4486 EL_AMOEBA_DROP, ACTION_FALLING, -1
4493 Xbomb_pause, FALSE, FALSE,
4497 Xbomb_fall, FALSE, FALSE,
4501 Ybomb_s, FALSE, FALSE,
4502 EL_BOMB, ACTION_FALLING, -1
4505 Ybomb_sB, FALSE, TRUE,
4506 EL_BOMB, ACTION_FALLING, -1
4509 Ybomb_e, FALSE, FALSE,
4510 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
4513 Ybomb_eB, FALSE, TRUE,
4514 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
4517 Ybomb_w, FALSE, FALSE,
4518 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
4521 Ybomb_wB, FALSE, TRUE,
4522 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
4525 Ybomb_eat, FALSE, FALSE,
4526 EL_BOMB, ACTION_ACTIVATING, -1
4529 Xballoon, TRUE, FALSE,
4533 Yballoon_n, FALSE, FALSE,
4534 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
4537 Yballoon_nB, FALSE, TRUE,
4538 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
4541 Yballoon_e, FALSE, FALSE,
4542 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
4545 Yballoon_eB, FALSE, TRUE,
4546 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
4549 Yballoon_s, FALSE, FALSE,
4550 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
4553 Yballoon_sB, FALSE, TRUE,
4554 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
4557 Yballoon_w, FALSE, FALSE,
4558 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
4561 Yballoon_wB, FALSE, TRUE,
4562 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
4565 Xgrass, TRUE, FALSE,
4566 EL_EMC_GRASS, -1, -1
4569 Ygrass_nB, FALSE, FALSE,
4570 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_UP
4573 Ygrass_eB, FALSE, FALSE,
4574 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_RIGHT
4577 Ygrass_sB, FALSE, FALSE,
4578 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_DOWN
4581 Ygrass_wB, FALSE, FALSE,
4582 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_LEFT
4589 Ydirt_nB, FALSE, FALSE,
4590 EL_SAND, ACTION_DIGGING, MV_BIT_UP
4593 Ydirt_eB, FALSE, FALSE,
4594 EL_SAND, ACTION_DIGGING, MV_BIT_RIGHT
4597 Ydirt_sB, FALSE, FALSE,
4598 EL_SAND, ACTION_DIGGING, MV_BIT_DOWN
4601 Ydirt_wB, FALSE, FALSE,
4602 EL_SAND, ACTION_DIGGING, MV_BIT_LEFT
4605 Xacid_ne, TRUE, FALSE,
4606 EL_ACID_POOL_TOPRIGHT, -1, -1
4609 Xacid_se, TRUE, FALSE,
4610 EL_ACID_POOL_BOTTOMRIGHT, -1, -1
4613 Xacid_s, TRUE, FALSE,
4614 EL_ACID_POOL_BOTTOM, -1, -1
4617 Xacid_sw, TRUE, FALSE,
4618 EL_ACID_POOL_BOTTOMLEFT, -1, -1
4621 Xacid_nw, TRUE, FALSE,
4622 EL_ACID_POOL_TOPLEFT, -1, -1
4625 Xacid_1, TRUE, FALSE,
4629 Xacid_2, FALSE, FALSE,
4633 Xacid_3, FALSE, FALSE,
4637 Xacid_4, FALSE, FALSE,
4641 Xacid_5, FALSE, FALSE,
4645 Xacid_6, FALSE, FALSE,
4649 Xacid_7, FALSE, FALSE,
4653 Xacid_8, FALSE, FALSE,
4657 Xball_1, TRUE, FALSE,
4658 EL_EMC_MAGIC_BALL, -1, -1
4661 Xball_1B, FALSE, FALSE,
4662 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4665 Xball_2, FALSE, FALSE,
4666 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4669 Xball_2B, FALSE, FALSE,
4670 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4673 Yball_eat, FALSE, FALSE,
4674 EL_EMC_MAGIC_BALL, ACTION_DROPPING, -1
4677 Ykey_1_eat, FALSE, FALSE,
4678 EL_EM_KEY_1, ACTION_COLLECTING, -1
4681 Ykey_2_eat, FALSE, FALSE,
4682 EL_EM_KEY_2, ACTION_COLLECTING, -1
4685 Ykey_3_eat, FALSE, FALSE,
4686 EL_EM_KEY_3, ACTION_COLLECTING, -1
4689 Ykey_4_eat, FALSE, FALSE,
4690 EL_EM_KEY_4, ACTION_COLLECTING, -1
4693 Ykey_5_eat, FALSE, FALSE,
4694 EL_EMC_KEY_5, ACTION_COLLECTING, -1
4697 Ykey_6_eat, FALSE, FALSE,
4698 EL_EMC_KEY_6, ACTION_COLLECTING, -1
4701 Ykey_7_eat, FALSE, FALSE,
4702 EL_EMC_KEY_7, ACTION_COLLECTING, -1
4705 Ykey_8_eat, FALSE, FALSE,
4706 EL_EMC_KEY_8, ACTION_COLLECTING, -1
4709 Ylenses_eat, FALSE, FALSE,
4710 EL_EMC_LENSES, ACTION_COLLECTING, -1
4713 Ymagnify_eat, FALSE, FALSE,
4714 EL_EMC_MAGNIFIER, ACTION_COLLECTING, -1
4717 Ygrass_eat, FALSE, FALSE,
4718 EL_EMC_GRASS, ACTION_SNAPPING, -1
4721 Ydirt_eat, FALSE, FALSE,
4722 EL_SAND, ACTION_SNAPPING, -1
4725 Xgrow_ns, TRUE, FALSE,
4726 EL_EXPANDABLE_WALL_VERTICAL, -1, -1
4729 Ygrow_ns_eat, FALSE, FALSE,
4730 EL_EXPANDABLE_WALL_VERTICAL, ACTION_GROWING, -1
4733 Xgrow_ew, TRUE, FALSE,
4734 EL_EXPANDABLE_WALL_HORIZONTAL, -1, -1
4737 Ygrow_ew_eat, FALSE, FALSE,
4738 EL_EXPANDABLE_WALL_HORIZONTAL, ACTION_GROWING, -1
4741 Xwonderwall, TRUE, FALSE,
4742 EL_MAGIC_WALL, -1, -1
4745 XwonderwallB, FALSE, FALSE,
4746 EL_MAGIC_WALL, ACTION_ACTIVE, -1
4749 Xamoeba_1, TRUE, FALSE,
4750 EL_AMOEBA_DRY, ACTION_OTHER, -1
4753 Xamoeba_2, FALSE, FALSE,
4754 EL_AMOEBA_DRY, ACTION_OTHER, -1
4757 Xamoeba_3, FALSE, FALSE,
4758 EL_AMOEBA_DRY, ACTION_OTHER, -1
4761 Xamoeba_4, FALSE, FALSE,
4762 EL_AMOEBA_DRY, ACTION_OTHER, -1
4765 Xamoeba_5, TRUE, FALSE,
4766 EL_AMOEBA_WET, ACTION_OTHER, -1
4769 Xamoeba_6, FALSE, FALSE,
4770 EL_AMOEBA_WET, ACTION_OTHER, -1
4773 Xamoeba_7, FALSE, FALSE,
4774 EL_AMOEBA_WET, ACTION_OTHER, -1
4777 Xamoeba_8, FALSE, FALSE,
4778 EL_AMOEBA_WET, ACTION_OTHER, -1
4781 Xdoor_1, TRUE, FALSE,
4782 EL_EM_GATE_1, -1, -1
4785 Xdoor_2, TRUE, FALSE,
4786 EL_EM_GATE_2, -1, -1
4789 Xdoor_3, TRUE, FALSE,
4790 EL_EM_GATE_3, -1, -1
4793 Xdoor_4, TRUE, FALSE,
4794 EL_EM_GATE_4, -1, -1
4797 Xdoor_5, TRUE, FALSE,
4798 EL_EMC_GATE_5, -1, -1
4801 Xdoor_6, TRUE, FALSE,
4802 EL_EMC_GATE_6, -1, -1
4805 Xdoor_7, TRUE, FALSE,
4806 EL_EMC_GATE_7, -1, -1
4809 Xdoor_8, TRUE, FALSE,
4810 EL_EMC_GATE_8, -1, -1
4813 Xkey_1, TRUE, FALSE,
4817 Xkey_2, TRUE, FALSE,
4821 Xkey_3, TRUE, FALSE,
4825 Xkey_4, TRUE, FALSE,
4829 Xkey_5, TRUE, FALSE,
4830 EL_EMC_KEY_5, -1, -1
4833 Xkey_6, TRUE, FALSE,
4834 EL_EMC_KEY_6, -1, -1
4837 Xkey_7, TRUE, FALSE,
4838 EL_EMC_KEY_7, -1, -1
4841 Xkey_8, TRUE, FALSE,
4842 EL_EMC_KEY_8, -1, -1
4845 Xwind_n, TRUE, FALSE,
4846 EL_BALLOON_SWITCH_UP, -1, -1
4849 Xwind_e, TRUE, FALSE,
4850 EL_BALLOON_SWITCH_RIGHT, -1, -1
4853 Xwind_s, TRUE, FALSE,
4854 EL_BALLOON_SWITCH_DOWN, -1, -1
4857 Xwind_w, TRUE, FALSE,
4858 EL_BALLOON_SWITCH_LEFT, -1, -1
4861 Xwind_nesw, TRUE, FALSE,
4862 EL_BALLOON_SWITCH_ANY, -1, -1
4865 Xwind_stop, TRUE, FALSE,
4866 EL_BALLOON_SWITCH_NONE, -1, -1
4870 EL_EM_EXIT_CLOSED, -1, -1
4873 Xexit_1, TRUE, FALSE,
4874 EL_EM_EXIT_OPEN, -1, -1
4877 Xexit_2, FALSE, FALSE,
4878 EL_EM_EXIT_OPEN, -1, -1
4881 Xexit_3, FALSE, FALSE,
4882 EL_EM_EXIT_OPEN, -1, -1
4885 Xdynamite, TRUE, FALSE,
4886 EL_EM_DYNAMITE, -1, -1
4889 Ydynamite_eat, FALSE, FALSE,
4890 EL_EM_DYNAMITE, ACTION_COLLECTING, -1
4893 Xdynamite_1, TRUE, FALSE,
4894 EL_EM_DYNAMITE_ACTIVE, -1, -1
4897 Xdynamite_2, FALSE, FALSE,
4898 EL_EM_DYNAMITE_ACTIVE, -1, -1
4901 Xdynamite_3, FALSE, FALSE,
4902 EL_EM_DYNAMITE_ACTIVE, -1, -1
4905 Xdynamite_4, FALSE, FALSE,
4906 EL_EM_DYNAMITE_ACTIVE, -1, -1
4909 Xbumper, TRUE, FALSE,
4910 EL_EMC_SPRING_BUMPER, -1, -1
4913 XbumperB, FALSE, FALSE,
4914 EL_EMC_SPRING_BUMPER, ACTION_ACTIVE, -1
4917 Xwheel, TRUE, FALSE,
4918 EL_ROBOT_WHEEL, -1, -1
4921 XwheelB, FALSE, FALSE,
4922 EL_ROBOT_WHEEL, ACTION_ACTIVE, -1
4925 Xswitch, TRUE, FALSE,
4926 EL_EMC_MAGIC_BALL_SWITCH, -1, -1
4929 XswitchB, FALSE, FALSE,
4930 EL_EMC_MAGIC_BALL_SWITCH, ACTION_ACTIVE, -1
4934 EL_QUICKSAND_EMPTY, -1, -1
4937 Xsand_stone, TRUE, FALSE,
4938 EL_QUICKSAND_FULL, -1, -1
4941 Xsand_stonein_1, FALSE, TRUE,
4942 EL_ROCK, ACTION_FILLING, -1
4945 Xsand_stonein_2, FALSE, TRUE,
4946 EL_ROCK, ACTION_FILLING, -1
4949 Xsand_stonein_3, FALSE, TRUE,
4950 EL_ROCK, ACTION_FILLING, -1
4953 Xsand_stonein_4, FALSE, TRUE,
4954 EL_ROCK, ACTION_FILLING, -1
4957 Xsand_stonesand_1, FALSE, FALSE,
4958 EL_QUICKSAND_FULL, -1, -1
4961 Xsand_stonesand_2, FALSE, FALSE,
4962 EL_QUICKSAND_FULL, -1, -1
4965 Xsand_stonesand_3, FALSE, FALSE,
4966 EL_QUICKSAND_FULL, -1, -1
4969 Xsand_stonesand_4, FALSE, FALSE,
4970 EL_QUICKSAND_FULL, -1, -1
4973 Xsand_stoneout_1, FALSE, FALSE,
4974 EL_ROCK, ACTION_EMPTYING, -1
4977 Xsand_stoneout_2, FALSE, FALSE,
4978 EL_ROCK, ACTION_EMPTYING, -1
4981 Xsand_sandstone_1, FALSE, FALSE,
4982 EL_QUICKSAND_FULL, -1, -1
4985 Xsand_sandstone_2, FALSE, FALSE,
4986 EL_QUICKSAND_FULL, -1, -1
4989 Xsand_sandstone_3, FALSE, FALSE,
4990 EL_QUICKSAND_FULL, -1, -1
4993 Xsand_sandstone_4, FALSE, FALSE,
4994 EL_QUICKSAND_FULL, -1, -1
4997 Xplant, TRUE, FALSE,
4998 EL_EMC_PLANT, -1, -1
5001 Yplant, FALSE, FALSE,
5002 EL_EMC_PLANT, -1, -1
5005 Xlenses, TRUE, FALSE,
5006 EL_EMC_LENSES, -1, -1
5009 Xmagnify, TRUE, FALSE,
5010 EL_EMC_MAGNIFIER, -1, -1
5013 Xdripper, TRUE, FALSE,
5014 EL_EMC_DRIPPER, -1, -1
5017 XdripperB, FALSE, FALSE,
5018 EL_EMC_DRIPPER, ACTION_ACTIVE, -1
5021 Xfake_blank, TRUE, FALSE,
5022 EL_INVISIBLE_WALL, -1, -1
5025 Xfake_blankB, FALSE, FALSE,
5026 EL_INVISIBLE_WALL, ACTION_ACTIVE, -1
5029 Xfake_grass, TRUE, FALSE,
5030 EL_EMC_FAKE_GRASS, -1, -1
5033 Xfake_grassB, FALSE, FALSE,
5034 EL_EMC_FAKE_GRASS, ACTION_ACTIVE, -1
5037 Xfake_door_1, TRUE, FALSE,
5038 EL_EM_GATE_1_GRAY, -1, -1
5041 Xfake_door_2, TRUE, FALSE,
5042 EL_EM_GATE_2_GRAY, -1, -1
5045 Xfake_door_3, TRUE, FALSE,
5046 EL_EM_GATE_3_GRAY, -1, -1
5049 Xfake_door_4, TRUE, FALSE,
5050 EL_EM_GATE_4_GRAY, -1, -1
5053 Xfake_door_5, TRUE, FALSE,
5054 EL_EMC_GATE_5_GRAY, -1, -1
5057 Xfake_door_6, TRUE, FALSE,
5058 EL_EMC_GATE_6_GRAY, -1, -1
5061 Xfake_door_7, TRUE, FALSE,
5062 EL_EMC_GATE_7_GRAY, -1, -1
5065 Xfake_door_8, TRUE, FALSE,
5066 EL_EMC_GATE_8_GRAY, -1, -1
5069 Xfake_acid_1, TRUE, FALSE,
5070 EL_EMC_FAKE_ACID, -1, -1
5073 Xfake_acid_2, FALSE, FALSE,
5074 EL_EMC_FAKE_ACID, -1, -1
5077 Xfake_acid_3, FALSE, FALSE,
5078 EL_EMC_FAKE_ACID, -1, -1
5081 Xfake_acid_4, FALSE, FALSE,
5082 EL_EMC_FAKE_ACID, -1, -1
5085 Xfake_acid_5, FALSE, FALSE,
5086 EL_EMC_FAKE_ACID, -1, -1
5089 Xfake_acid_6, FALSE, FALSE,
5090 EL_EMC_FAKE_ACID, -1, -1
5093 Xfake_acid_7, FALSE, FALSE,
5094 EL_EMC_FAKE_ACID, -1, -1
5097 Xfake_acid_8, FALSE, FALSE,
5098 EL_EMC_FAKE_ACID, -1, -1
5101 Xsteel_1, TRUE, FALSE,
5102 EL_STEELWALL, -1, -1
5105 Xsteel_2, TRUE, FALSE,
5106 EL_EMC_STEELWALL_2, -1, -1
5109 Xsteel_3, TRUE, FALSE,
5110 EL_EMC_STEELWALL_3, -1, -1
5113 Xsteel_4, TRUE, FALSE,
5114 EL_EMC_STEELWALL_4, -1, -1
5117 Xwall_1, TRUE, FALSE,
5121 Xwall_2, TRUE, FALSE,
5122 EL_EMC_WALL_14, -1, -1
5125 Xwall_3, TRUE, FALSE,
5126 EL_EMC_WALL_15, -1, -1
5129 Xwall_4, TRUE, FALSE,
5130 EL_EMC_WALL_16, -1, -1
5133 Xround_wall_1, TRUE, FALSE,
5134 EL_WALL_SLIPPERY, -1, -1
5137 Xround_wall_2, TRUE, FALSE,
5138 EL_EMC_WALL_SLIPPERY_2, -1, -1
5141 Xround_wall_3, TRUE, FALSE,
5142 EL_EMC_WALL_SLIPPERY_3, -1, -1
5145 Xround_wall_4, TRUE, FALSE,
5146 EL_EMC_WALL_SLIPPERY_4, -1, -1
5149 Xdecor_1, TRUE, FALSE,
5150 EL_EMC_WALL_8, -1, -1
5153 Xdecor_2, TRUE, FALSE,
5154 EL_EMC_WALL_6, -1, -1
5157 Xdecor_3, TRUE, FALSE,
5158 EL_EMC_WALL_4, -1, -1
5161 Xdecor_4, TRUE, FALSE,
5162 EL_EMC_WALL_7, -1, -1
5165 Xdecor_5, TRUE, FALSE,
5166 EL_EMC_WALL_5, -1, -1
5169 Xdecor_6, TRUE, FALSE,
5170 EL_EMC_WALL_9, -1, -1
5173 Xdecor_7, TRUE, FALSE,
5174 EL_EMC_WALL_10, -1, -1
5177 Xdecor_8, TRUE, FALSE,
5178 EL_EMC_WALL_1, -1, -1
5181 Xdecor_9, TRUE, FALSE,
5182 EL_EMC_WALL_2, -1, -1
5185 Xdecor_10, TRUE, FALSE,
5186 EL_EMC_WALL_3, -1, -1
5189 Xdecor_11, TRUE, FALSE,
5190 EL_EMC_WALL_11, -1, -1
5193 Xdecor_12, TRUE, FALSE,
5194 EL_EMC_WALL_12, -1, -1
5197 Xalpha_0, TRUE, FALSE,
5198 EL_CHAR('0'), -1, -1
5201 Xalpha_1, TRUE, FALSE,
5202 EL_CHAR('1'), -1, -1
5205 Xalpha_2, TRUE, FALSE,
5206 EL_CHAR('2'), -1, -1
5209 Xalpha_3, TRUE, FALSE,
5210 EL_CHAR('3'), -1, -1
5213 Xalpha_4, TRUE, FALSE,
5214 EL_CHAR('4'), -1, -1
5217 Xalpha_5, TRUE, FALSE,
5218 EL_CHAR('5'), -1, -1
5221 Xalpha_6, TRUE, FALSE,
5222 EL_CHAR('6'), -1, -1
5225 Xalpha_7, TRUE, FALSE,
5226 EL_CHAR('7'), -1, -1
5229 Xalpha_8, TRUE, FALSE,
5230 EL_CHAR('8'), -1, -1
5233 Xalpha_9, TRUE, FALSE,
5234 EL_CHAR('9'), -1, -1
5237 Xalpha_excla, TRUE, FALSE,
5238 EL_CHAR('!'), -1, -1
5241 Xalpha_quote, TRUE, FALSE,
5242 EL_CHAR('"'), -1, -1
5245 Xalpha_comma, TRUE, FALSE,
5246 EL_CHAR(','), -1, -1
5249 Xalpha_minus, TRUE, FALSE,
5250 EL_CHAR('-'), -1, -1
5253 Xalpha_perio, TRUE, FALSE,
5254 EL_CHAR('.'), -1, -1
5257 Xalpha_colon, TRUE, FALSE,
5258 EL_CHAR(':'), -1, -1
5261 Xalpha_quest, TRUE, FALSE,
5262 EL_CHAR('?'), -1, -1
5265 Xalpha_a, TRUE, FALSE,
5266 EL_CHAR('A'), -1, -1
5269 Xalpha_b, TRUE, FALSE,
5270 EL_CHAR('B'), -1, -1
5273 Xalpha_c, TRUE, FALSE,
5274 EL_CHAR('C'), -1, -1
5277 Xalpha_d, TRUE, FALSE,
5278 EL_CHAR('D'), -1, -1
5281 Xalpha_e, TRUE, FALSE,
5282 EL_CHAR('E'), -1, -1
5285 Xalpha_f, TRUE, FALSE,
5286 EL_CHAR('F'), -1, -1
5289 Xalpha_g, TRUE, FALSE,
5290 EL_CHAR('G'), -1, -1
5293 Xalpha_h, TRUE, FALSE,
5294 EL_CHAR('H'), -1, -1
5297 Xalpha_i, TRUE, FALSE,
5298 EL_CHAR('I'), -1, -1
5301 Xalpha_j, TRUE, FALSE,
5302 EL_CHAR('J'), -1, -1
5305 Xalpha_k, TRUE, FALSE,
5306 EL_CHAR('K'), -1, -1
5309 Xalpha_l, TRUE, FALSE,
5310 EL_CHAR('L'), -1, -1
5313 Xalpha_m, TRUE, FALSE,
5314 EL_CHAR('M'), -1, -1
5317 Xalpha_n, TRUE, FALSE,
5318 EL_CHAR('N'), -1, -1
5321 Xalpha_o, TRUE, FALSE,
5322 EL_CHAR('O'), -1, -1
5325 Xalpha_p, TRUE, FALSE,
5326 EL_CHAR('P'), -1, -1
5329 Xalpha_q, TRUE, FALSE,
5330 EL_CHAR('Q'), -1, -1
5333 Xalpha_r, TRUE, FALSE,
5334 EL_CHAR('R'), -1, -1
5337 Xalpha_s, TRUE, FALSE,
5338 EL_CHAR('S'), -1, -1
5341 Xalpha_t, TRUE, FALSE,
5342 EL_CHAR('T'), -1, -1
5345 Xalpha_u, TRUE, FALSE,
5346 EL_CHAR('U'), -1, -1
5349 Xalpha_v, TRUE, FALSE,
5350 EL_CHAR('V'), -1, -1
5353 Xalpha_w, TRUE, FALSE,
5354 EL_CHAR('W'), -1, -1
5357 Xalpha_x, TRUE, FALSE,
5358 EL_CHAR('X'), -1, -1
5361 Xalpha_y, TRUE, FALSE,
5362 EL_CHAR('Y'), -1, -1
5365 Xalpha_z, TRUE, FALSE,
5366 EL_CHAR('Z'), -1, -1
5369 Xalpha_arrow_e, TRUE, FALSE,
5370 EL_CHAR('>'), -1, -1
5373 Xalpha_arrow_w, TRUE, FALSE,
5374 EL_CHAR('<'), -1, -1
5377 Xalpha_copyr, TRUE, FALSE,
5378 EL_CHAR('©'), -1, -1
5382 Xboom_bug, FALSE, FALSE,
5383 EL_BUG, ACTION_EXPLODING, -1
5386 Xboom_bomb, FALSE, FALSE,
5387 EL_BOMB, ACTION_EXPLODING, -1
5390 Xboom_android, FALSE, FALSE,
5391 EL_EMC_ANDROID, ACTION_OTHER, -1
5394 Xboom_1, FALSE, FALSE,
5395 EL_DEFAULT, ACTION_EXPLODING, -1
5398 Xboom_2, FALSE, FALSE,
5399 EL_DEFAULT, ACTION_EXPLODING, -1
5402 Znormal, FALSE, FALSE,
5406 Zdynamite, FALSE, FALSE,
5410 Zplayer, FALSE, FALSE,
5414 ZBORDER, FALSE, FALSE,
5424 static struct Mapping_EM_to_RND_player
5433 em_player_mapping_list[] =
5437 EL_PLAYER_1, ACTION_MOVING, MV_BIT_UP,
5441 EL_PLAYER_1, ACTION_MOVING, MV_BIT_RIGHT,
5445 EL_PLAYER_1, ACTION_MOVING, MV_BIT_DOWN,
5449 EL_PLAYER_1, ACTION_MOVING, MV_BIT_LEFT,
5453 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_UP,
5457 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_RIGHT,
5461 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_DOWN,
5465 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_LEFT,
5469 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_UP,
5473 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_RIGHT,
5477 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_DOWN,
5481 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_LEFT,
5485 EL_PLAYER_2, ACTION_MOVING, MV_BIT_UP,
5489 EL_PLAYER_2, ACTION_MOVING, MV_BIT_RIGHT,
5493 EL_PLAYER_2, ACTION_MOVING, MV_BIT_DOWN,
5497 EL_PLAYER_2, ACTION_MOVING, MV_BIT_LEFT,
5501 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_UP,
5505 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_RIGHT,
5509 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_DOWN,
5513 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_LEFT,
5517 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_UP,
5521 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_RIGHT,
5525 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_DOWN,
5529 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_LEFT,
5533 EL_PLAYER_1, ACTION_DEFAULT, -1,
5537 EL_PLAYER_2, ACTION_DEFAULT, -1,
5541 EL_PLAYER_3, ACTION_MOVING, MV_BIT_UP,
5545 EL_PLAYER_3, ACTION_MOVING, MV_BIT_RIGHT,
5549 EL_PLAYER_3, ACTION_MOVING, MV_BIT_DOWN,
5553 EL_PLAYER_3, ACTION_MOVING, MV_BIT_LEFT,
5557 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_UP,
5561 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_RIGHT,
5565 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_DOWN,
5569 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_LEFT,
5573 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_UP,
5577 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_RIGHT,
5581 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_DOWN,
5585 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_LEFT,
5589 EL_PLAYER_4, ACTION_MOVING, MV_BIT_UP,
5593 EL_PLAYER_4, ACTION_MOVING, MV_BIT_RIGHT,
5597 EL_PLAYER_4, ACTION_MOVING, MV_BIT_DOWN,
5601 EL_PLAYER_4, ACTION_MOVING, MV_BIT_LEFT,
5605 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_UP,
5609 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_RIGHT,
5613 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_DOWN,
5617 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_LEFT,
5621 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_UP,
5625 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_RIGHT,
5629 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_DOWN,
5633 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_LEFT,
5637 EL_PLAYER_3, ACTION_DEFAULT, -1,
5641 EL_PLAYER_4, ACTION_DEFAULT, -1,
5650 int map_element_RND_to_EM(int element_rnd)
5652 static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
5653 static boolean mapping_initialized = FALSE;
5655 if (!mapping_initialized)
5659 /* return "Xalpha_quest" for all undefined elements in mapping array */
5660 for (i = 0; i < NUM_FILE_ELEMENTS; i++)
5661 mapping_RND_to_EM[i] = Xalpha_quest;
5663 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5664 if (em_object_mapping_list[i].is_rnd_to_em_mapping)
5665 mapping_RND_to_EM[em_object_mapping_list[i].element_rnd] =
5666 em_object_mapping_list[i].element_em;
5668 mapping_initialized = TRUE;
5671 if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
5672 return mapping_RND_to_EM[element_rnd];
5674 Error(ERR_WARN, "invalid RND level element %d", element_rnd);
5679 int map_element_EM_to_RND(int element_em)
5681 static unsigned short mapping_EM_to_RND[TILE_MAX];
5682 static boolean mapping_initialized = FALSE;
5684 if (!mapping_initialized)
5688 /* return "EL_UNKNOWN" for all undefined elements in mapping array */
5689 for (i = 0; i < TILE_MAX; i++)
5690 mapping_EM_to_RND[i] = EL_UNKNOWN;
5692 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5693 mapping_EM_to_RND[em_object_mapping_list[i].element_em] =
5694 em_object_mapping_list[i].element_rnd;
5696 mapping_initialized = TRUE;
5699 if (element_em >= 0 && element_em < TILE_MAX)
5700 return mapping_EM_to_RND[element_em];
5702 Error(ERR_WARN, "invalid EM level element %d", element_em);
5707 void map_android_clone_elements_RND_to_EM(struct LevelInfo *level)
5709 struct LevelInfo_EM *level_em = level->native_em_level;
5710 struct LEVEL *lev = level_em->lev;
5713 for (i = 0; i < TILE_MAX; i++)
5714 lev->android_array[i] = Xblank;
5716 for (i = 0; i < level->num_android_clone_elements; i++)
5718 int element_rnd = level->android_clone_element[i];
5719 int element_em = map_element_RND_to_EM(element_rnd);
5721 for (j = 0; em_object_mapping_list[j].element_em != -1; j++)
5722 if (em_object_mapping_list[j].element_rnd == element_rnd)
5723 lev->android_array[em_object_mapping_list[j].element_em] = element_em;
5727 void map_android_clone_elements_EM_to_RND(struct LevelInfo *level)
5729 struct LevelInfo_EM *level_em = level->native_em_level;
5730 struct LEVEL *lev = level_em->lev;
5733 level->num_android_clone_elements = 0;
5735 for (i = 0; i < TILE_MAX; i++)
5737 int element_em = lev->android_array[i];
5739 boolean element_found = FALSE;
5741 if (element_em == Xblank)
5744 element_rnd = map_element_EM_to_RND(element_em);
5746 for (j = 0; j < level->num_android_clone_elements; j++)
5747 if (level->android_clone_element[j] == element_rnd)
5748 element_found = TRUE;
5752 level->android_clone_element[level->num_android_clone_elements++] =
5755 if (level->num_android_clone_elements == MAX_ANDROID_ELEMENTS)
5760 if (level->num_android_clone_elements == 0)
5762 level->num_android_clone_elements = 1;
5763 level->android_clone_element[0] = EL_EMPTY;
5767 int map_direction_RND_to_EM(int direction)
5769 return (direction == MV_UP ? 0 :
5770 direction == MV_RIGHT ? 1 :
5771 direction == MV_DOWN ? 2 :
5772 direction == MV_LEFT ? 3 :
5776 int map_direction_EM_to_RND(int direction)
5778 return (direction == 0 ? MV_UP :
5779 direction == 1 ? MV_RIGHT :
5780 direction == 2 ? MV_DOWN :
5781 direction == 3 ? MV_LEFT :
5785 int get_next_element(int element)
5789 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
5790 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
5791 case EL_QUICKSAND_FAST_FILLING: return EL_QUICKSAND_FAST_FULL;
5792 case EL_QUICKSAND_FAST_EMPTYING: return EL_QUICKSAND_FAST_EMPTY;
5793 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
5794 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
5795 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
5796 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
5797 case EL_DC_MAGIC_WALL_FILLING: return EL_DC_MAGIC_WALL_FULL;
5798 case EL_DC_MAGIC_WALL_EMPTYING: return EL_DC_MAGIC_WALL_ACTIVE;
5799 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
5801 default: return element;
5806 int el_act_dir2img(int element, int action, int direction)
5808 element = GFX_ELEMENT(element);
5810 if (direction == MV_NONE)
5811 return element_info[element].graphic[action];
5813 direction = MV_DIR_TO_BIT(direction);
5815 return element_info[element].direction_graphic[action][direction];
5818 int el_act_dir2img(int element, int action, int direction)
5820 element = GFX_ELEMENT(element);
5821 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
5823 /* direction_graphic[][] == graphic[] for undefined direction graphics */
5824 return element_info[element].direction_graphic[action][direction];
5829 static int el_act_dir2crm(int element, int action, int direction)
5831 element = GFX_ELEMENT(element);
5833 if (direction == MV_NONE)
5834 return element_info[element].crumbled[action];
5836 direction = MV_DIR_TO_BIT(direction);
5838 return element_info[element].direction_crumbled[action][direction];
5841 static int el_act_dir2crm(int element, int action, int direction)
5843 element = GFX_ELEMENT(element);
5844 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
5846 /* direction_graphic[][] == graphic[] for undefined direction graphics */
5847 return element_info[element].direction_crumbled[action][direction];
5851 int el_act2img(int element, int action)
5853 element = GFX_ELEMENT(element);
5855 return element_info[element].graphic[action];
5858 int el_act2crm(int element, int action)
5860 element = GFX_ELEMENT(element);
5862 return element_info[element].crumbled[action];
5865 int el_dir2img(int element, int direction)
5867 element = GFX_ELEMENT(element);
5869 return el_act_dir2img(element, ACTION_DEFAULT, direction);
5872 int el2baseimg(int element)
5874 return element_info[element].graphic[ACTION_DEFAULT];
5877 int el2img(int element)
5879 element = GFX_ELEMENT(element);
5881 return element_info[element].graphic[ACTION_DEFAULT];
5884 int el2edimg(int element)
5886 element = GFX_ELEMENT(element);
5888 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
5891 int el2preimg(int element)
5893 element = GFX_ELEMENT(element);
5895 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
5898 int el2panelimg(int element)
5900 element = GFX_ELEMENT(element);
5902 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PANEL];
5905 int font2baseimg(int font_nr)
5907 return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
5910 int getBeltNrFromBeltElement(int element)
5912 return (element < EL_CONVEYOR_BELT_2_LEFT ? 0 :
5913 element < EL_CONVEYOR_BELT_3_LEFT ? 1 :
5914 element < EL_CONVEYOR_BELT_4_LEFT ? 2 : 3);
5917 int getBeltNrFromBeltActiveElement(int element)
5919 return (element < EL_CONVEYOR_BELT_2_LEFT_ACTIVE ? 0 :
5920 element < EL_CONVEYOR_BELT_3_LEFT_ACTIVE ? 1 :
5921 element < EL_CONVEYOR_BELT_4_LEFT_ACTIVE ? 2 : 3);
5924 int getBeltNrFromBeltSwitchElement(int element)
5926 return (element < EL_CONVEYOR_BELT_2_SWITCH_LEFT ? 0 :
5927 element < EL_CONVEYOR_BELT_3_SWITCH_LEFT ? 1 :
5928 element < EL_CONVEYOR_BELT_4_SWITCH_LEFT ? 2 : 3);
5931 int getBeltDirNrFromBeltElement(int element)
5933 static int belt_base_element[4] =
5935 EL_CONVEYOR_BELT_1_LEFT,
5936 EL_CONVEYOR_BELT_2_LEFT,
5937 EL_CONVEYOR_BELT_3_LEFT,
5938 EL_CONVEYOR_BELT_4_LEFT
5941 int belt_nr = getBeltNrFromBeltElement(element);
5942 int belt_dir_nr = element - belt_base_element[belt_nr];
5944 return (belt_dir_nr % 3);
5947 int getBeltDirNrFromBeltSwitchElement(int element)
5949 static int belt_base_element[4] =
5951 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
5952 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
5953 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
5954 EL_CONVEYOR_BELT_4_SWITCH_LEFT
5957 int belt_nr = getBeltNrFromBeltSwitchElement(element);
5958 int belt_dir_nr = element - belt_base_element[belt_nr];
5960 return (belt_dir_nr % 3);
5963 int getBeltDirFromBeltElement(int element)
5965 static int belt_move_dir[3] =
5972 int belt_dir_nr = getBeltDirNrFromBeltElement(element);
5974 return belt_move_dir[belt_dir_nr];
5977 int getBeltDirFromBeltSwitchElement(int element)
5979 static int belt_move_dir[3] =
5986 int belt_dir_nr = getBeltDirNrFromBeltSwitchElement(element);
5988 return belt_move_dir[belt_dir_nr];
5991 int getBeltElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
5993 static int belt_base_element[4] =
5995 EL_CONVEYOR_BELT_1_LEFT,
5996 EL_CONVEYOR_BELT_2_LEFT,
5997 EL_CONVEYOR_BELT_3_LEFT,
5998 EL_CONVEYOR_BELT_4_LEFT
6001 return belt_base_element[belt_nr] + belt_dir_nr;
6004 int getBeltElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
6006 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
6008 return getBeltElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
6011 int getBeltSwitchElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
6013 static int belt_base_element[4] =
6015 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
6016 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
6017 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
6018 EL_CONVEYOR_BELT_4_SWITCH_LEFT
6021 return belt_base_element[belt_nr] + belt_dir_nr;
6024 int getBeltSwitchElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
6026 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
6028 return getBeltSwitchElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
6031 int getNumActivePlayers_EM()
6033 int num_players = 0;
6039 for (i = 0; i < MAX_PLAYERS; i++)
6040 if (tape.player_participates[i])
6046 int getGameFrameDelay_EM(int native_em_game_frame_delay)
6048 int game_frame_delay_value;
6050 game_frame_delay_value =
6051 (tape.playing && tape.fast_forward ? FfwdFrameDelay :
6052 GameFrameDelay == GAME_FRAME_DELAY ? native_em_game_frame_delay :
6055 if (tape.playing && tape.warp_forward && !tape.pausing)
6056 game_frame_delay_value = 0;
6058 return game_frame_delay_value;
6061 unsigned int InitRND(long seed)
6063 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
6064 return InitEngineRandom_EM(seed);
6066 return InitEngineRandom_RND(seed);
6070 static struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
6071 static struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
6074 void ResetGfxAnimation_EM(int x, int y, int tile)
6079 void getGraphicSourceObjectExt_EM(int tile, int frame_em,
6080 Bitmap **src_bitmap, int *src_x, int *src_y,
6083 int element = object_mapping[tile].element_rnd;
6084 int action = object_mapping[tile].action;
6085 int direction = object_mapping[tile].direction;
6086 boolean is_backside = object_mapping[tile].is_backside;
6087 boolean action_removing = (action == ACTION_DIGGING ||
6088 action == ACTION_SNAPPING ||
6089 action == ACTION_COLLECTING);
6090 int effective_element = (frame_em > 0 ? element :
6091 is_backside ? EL_EMPTY :
6092 action_removing ? EL_EMPTY :
6094 int graphic = (direction == MV_NONE ?
6095 el_act2img(effective_element, action) :
6096 el_act_dir2img(effective_element, action, direction));
6097 struct GraphicInfo *g = &graphic_info[graphic];
6100 if (graphic_info[graphic].anim_global_sync)
6101 sync_frame = FrameCounter;
6103 sync_frame = 7 - frame_em;
6105 SetRandomAnimationValue(x, y);
6107 int frame = getAnimationFrame(g->anim_frames,
6110 g->anim_start_frame,
6113 getGraphicSourceExt(graphic, frame, src_bitmap, src_x, src_y, FALSE);
6116 void getGraphicSourcePlayerExt_EM(int player_nr, int anim, int frame_em,
6117 Bitmap **src_bitmap, int *src_x, int *src_y)
6119 int element = player_mapping[player_nr][anim].element_rnd;
6120 int action = player_mapping[player_nr][anim].action;
6121 int direction = player_mapping[player_nr][anim].direction;
6122 int graphic = (direction == MV_NONE ?
6123 el_act2img(element, action) :
6124 el_act_dir2img(element, action, direction));
6125 struct GraphicInfo *g = &graphic_info[graphic];
6128 InitPlayerGfxAnimation(&stored_player[player_nr], action, direction);
6130 stored_player[player_nr].StepFrame = 7 - frame_em;
6132 sync_frame = stored_player[player_nr].Frame;
6135 printf("::: %d: %d, %d [%d]\n",
6137 stored_player[player_nr].Frame,
6138 stored_player[player_nr].StepFrame,
6142 int frame = getAnimationFrame(g->anim_frames,
6145 g->anim_start_frame,
6148 getGraphicSourceExt(graphic, frame, src_bitmap, src_x, src_y, FALSE);
6151 void InitGraphicInfo_EM(void)
6154 struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
6155 struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
6160 int num_em_gfx_errors = 0;
6162 if (graphic_info_em_object[0][0].bitmap == NULL)
6164 /* EM graphics not yet initialized in em_open_all() */
6169 printf("::: [4 errors can be ignored (1 x 'bomb', 3 x 'em_dynamite']\n");
6172 /* always start with reliable default values */
6173 for (i = 0; i < TILE_MAX; i++)
6175 object_mapping[i].element_rnd = EL_UNKNOWN;
6176 object_mapping[i].is_backside = FALSE;
6177 object_mapping[i].action = ACTION_DEFAULT;
6178 object_mapping[i].direction = MV_NONE;
6181 /* always start with reliable default values */
6182 for (p = 0; p < MAX_PLAYERS; p++)
6184 for (i = 0; i < SPR_MAX; i++)
6186 player_mapping[p][i].element_rnd = EL_UNKNOWN;
6187 player_mapping[p][i].action = ACTION_DEFAULT;
6188 player_mapping[p][i].direction = MV_NONE;
6192 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
6194 int e = em_object_mapping_list[i].element_em;
6196 object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd;
6197 object_mapping[e].is_backside = em_object_mapping_list[i].is_backside;
6199 if (em_object_mapping_list[i].action != -1)
6200 object_mapping[e].action = em_object_mapping_list[i].action;
6202 if (em_object_mapping_list[i].direction != -1)
6203 object_mapping[e].direction =
6204 MV_DIR_FROM_BIT(em_object_mapping_list[i].direction);
6207 for (i = 0; em_player_mapping_list[i].action_em != -1; i++)
6209 int a = em_player_mapping_list[i].action_em;
6210 int p = em_player_mapping_list[i].player_nr;
6212 player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd;
6214 if (em_player_mapping_list[i].action != -1)
6215 player_mapping[p][a].action = em_player_mapping_list[i].action;
6217 if (em_player_mapping_list[i].direction != -1)
6218 player_mapping[p][a].direction =
6219 MV_DIR_FROM_BIT(em_player_mapping_list[i].direction);
6222 for (i = 0; i < TILE_MAX; i++)
6224 int element = object_mapping[i].element_rnd;
6225 int action = object_mapping[i].action;
6226 int direction = object_mapping[i].direction;
6227 boolean is_backside = object_mapping[i].is_backside;
6228 boolean action_removing = (action == ACTION_DIGGING ||
6229 action == ACTION_SNAPPING ||
6230 action == ACTION_COLLECTING);
6231 boolean action_exploding = ((action == ACTION_EXPLODING ||
6232 action == ACTION_SMASHED_BY_ROCK ||
6233 action == ACTION_SMASHED_BY_SPRING) &&
6234 element != EL_DIAMOND);
6235 boolean action_active = (action == ACTION_ACTIVE);
6236 boolean action_other = (action == ACTION_OTHER);
6238 for (j = 0; j < 8; j++)
6240 int effective_element = (j > 5 && i == Yacid_splash_eB ? EL_EMPTY :
6241 j > 5 && i == Yacid_splash_wB ? EL_EMPTY :
6243 i == Xdrip_stretch ? element :
6244 i == Xdrip_stretchB ? element :
6245 i == Ydrip_s1 ? element :
6246 i == Ydrip_s1B ? element :
6247 i == Xball_1B ? element :
6248 i == Xball_2 ? element :
6249 i == Xball_2B ? element :
6250 i == Yball_eat ? element :
6251 i == Ykey_1_eat ? element :
6252 i == Ykey_2_eat ? element :
6253 i == Ykey_3_eat ? element :
6254 i == Ykey_4_eat ? element :
6255 i == Ykey_5_eat ? element :
6256 i == Ykey_6_eat ? element :
6257 i == Ykey_7_eat ? element :
6258 i == Ykey_8_eat ? element :
6259 i == Ylenses_eat ? element :
6260 i == Ymagnify_eat ? element :
6261 i == Ygrass_eat ? element :
6262 i == Ydirt_eat ? element :
6263 i == Yemerald_stone ? EL_EMERALD :
6264 i == Ydiamond_stone ? EL_ROCK :
6265 i == Xsand_stonein_1 ? element :
6266 i == Xsand_stonein_2 ? element :
6267 i == Xsand_stonein_3 ? element :
6268 i == Xsand_stonein_4 ? element :
6269 is_backside ? EL_EMPTY :
6270 action_removing ? EL_EMPTY :
6272 int effective_action = (j < 7 ? action :
6273 i == Xdrip_stretch ? action :
6274 i == Xdrip_stretchB ? action :
6275 i == Ydrip_s1 ? action :
6276 i == Ydrip_s1B ? action :
6277 i == Xball_1B ? action :
6278 i == Xball_2 ? action :
6279 i == Xball_2B ? action :
6280 i == Yball_eat ? action :
6281 i == Ykey_1_eat ? action :
6282 i == Ykey_2_eat ? action :
6283 i == Ykey_3_eat ? action :
6284 i == Ykey_4_eat ? action :
6285 i == Ykey_5_eat ? action :
6286 i == Ykey_6_eat ? action :
6287 i == Ykey_7_eat ? action :
6288 i == Ykey_8_eat ? action :
6289 i == Ylenses_eat ? action :
6290 i == Ymagnify_eat ? action :
6291 i == Ygrass_eat ? action :
6292 i == Ydirt_eat ? action :
6293 i == Xsand_stonein_1 ? action :
6294 i == Xsand_stonein_2 ? action :
6295 i == Xsand_stonein_3 ? action :
6296 i == Xsand_stonein_4 ? action :
6297 i == Xsand_stoneout_1 ? action :
6298 i == Xsand_stoneout_2 ? action :
6299 i == Xboom_android ? ACTION_EXPLODING :
6300 action_exploding ? ACTION_EXPLODING :
6301 action_active ? action :
6302 action_other ? action :
6304 int graphic = (el_act_dir2img(effective_element, effective_action,
6306 int crumbled = (el_act_dir2crm(effective_element, effective_action,
6308 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
6309 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
6310 boolean has_action_graphics = (graphic != base_graphic);
6311 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
6312 struct GraphicInfo *g = &graphic_info[graphic];
6313 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
6316 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
6317 boolean special_animation = (action != ACTION_DEFAULT &&
6318 g->anim_frames == 3 &&
6319 g->anim_delay == 2 &&
6320 g->anim_mode & ANIM_LINEAR);
6321 int sync_frame = (i == Xdrip_stretch ? 7 :
6322 i == Xdrip_stretchB ? 7 :
6323 i == Ydrip_s2 ? j + 8 :
6324 i == Ydrip_s2B ? j + 8 :
6333 i == Xfake_acid_1 ? 0 :
6334 i == Xfake_acid_2 ? 10 :
6335 i == Xfake_acid_3 ? 20 :
6336 i == Xfake_acid_4 ? 30 :
6337 i == Xfake_acid_5 ? 40 :
6338 i == Xfake_acid_6 ? 50 :
6339 i == Xfake_acid_7 ? 60 :
6340 i == Xfake_acid_8 ? 70 :
6342 i == Xball_2B ? j + 8 :
6343 i == Yball_eat ? j + 1 :
6344 i == Ykey_1_eat ? j + 1 :
6345 i == Ykey_2_eat ? j + 1 :
6346 i == Ykey_3_eat ? j + 1 :
6347 i == Ykey_4_eat ? j + 1 :
6348 i == Ykey_5_eat ? j + 1 :
6349 i == Ykey_6_eat ? j + 1 :
6350 i == Ykey_7_eat ? j + 1 :
6351 i == Ykey_8_eat ? j + 1 :
6352 i == Ylenses_eat ? j + 1 :
6353 i == Ymagnify_eat ? j + 1 :
6354 i == Ygrass_eat ? j + 1 :
6355 i == Ydirt_eat ? j + 1 :
6356 i == Xamoeba_1 ? 0 :
6357 i == Xamoeba_2 ? 1 :
6358 i == Xamoeba_3 ? 2 :
6359 i == Xamoeba_4 ? 3 :
6360 i == Xamoeba_5 ? 0 :
6361 i == Xamoeba_6 ? 1 :
6362 i == Xamoeba_7 ? 2 :
6363 i == Xamoeba_8 ? 3 :
6364 i == Xexit_2 ? j + 8 :
6365 i == Xexit_3 ? j + 16 :
6366 i == Xdynamite_1 ? 0 :
6367 i == Xdynamite_2 ? 8 :
6368 i == Xdynamite_3 ? 16 :
6369 i == Xdynamite_4 ? 24 :
6370 i == Xsand_stonein_1 ? j + 1 :
6371 i == Xsand_stonein_2 ? j + 9 :
6372 i == Xsand_stonein_3 ? j + 17 :
6373 i == Xsand_stonein_4 ? j + 25 :
6374 i == Xsand_stoneout_1 && j == 0 ? 0 :
6375 i == Xsand_stoneout_1 && j == 1 ? 0 :
6376 i == Xsand_stoneout_1 && j == 2 ? 1 :
6377 i == Xsand_stoneout_1 && j == 3 ? 2 :
6378 i == Xsand_stoneout_1 && j == 4 ? 2 :
6379 i == Xsand_stoneout_1 && j == 5 ? 3 :
6380 i == Xsand_stoneout_1 && j == 6 ? 4 :
6381 i == Xsand_stoneout_1 && j == 7 ? 4 :
6382 i == Xsand_stoneout_2 && j == 0 ? 5 :
6383 i == Xsand_stoneout_2 && j == 1 ? 6 :
6384 i == Xsand_stoneout_2 && j == 2 ? 7 :
6385 i == Xsand_stoneout_2 && j == 3 ? 8 :
6386 i == Xsand_stoneout_2 && j == 4 ? 9 :
6387 i == Xsand_stoneout_2 && j == 5 ? 11 :
6388 i == Xsand_stoneout_2 && j == 6 ? 13 :
6389 i == Xsand_stoneout_2 && j == 7 ? 15 :
6390 i == Xboom_bug && j == 1 ? 2 :
6391 i == Xboom_bug && j == 2 ? 2 :
6392 i == Xboom_bug && j == 3 ? 4 :
6393 i == Xboom_bug && j == 4 ? 4 :
6394 i == Xboom_bug && j == 5 ? 2 :
6395 i == Xboom_bug && j == 6 ? 2 :
6396 i == Xboom_bug && j == 7 ? 0 :
6397 i == Xboom_bomb && j == 1 ? 2 :
6398 i == Xboom_bomb && j == 2 ? 2 :
6399 i == Xboom_bomb && j == 3 ? 4 :
6400 i == Xboom_bomb && j == 4 ? 4 :
6401 i == Xboom_bomb && j == 5 ? 2 :
6402 i == Xboom_bomb && j == 6 ? 2 :
6403 i == Xboom_bomb && j == 7 ? 0 :
6404 i == Xboom_android && j == 7 ? 6 :
6405 i == Xboom_1 && j == 1 ? 2 :
6406 i == Xboom_1 && j == 2 ? 2 :
6407 i == Xboom_1 && j == 3 ? 4 :
6408 i == Xboom_1 && j == 4 ? 4 :
6409 i == Xboom_1 && j == 5 ? 6 :
6410 i == Xboom_1 && j == 6 ? 6 :
6411 i == Xboom_1 && j == 7 ? 8 :
6412 i == Xboom_2 && j == 0 ? 8 :
6413 i == Xboom_2 && j == 1 ? 8 :
6414 i == Xboom_2 && j == 2 ? 10 :
6415 i == Xboom_2 && j == 3 ? 10 :
6416 i == Xboom_2 && j == 4 ? 10 :
6417 i == Xboom_2 && j == 5 ? 12 :
6418 i == Xboom_2 && j == 6 ? 12 :
6419 i == Xboom_2 && j == 7 ? 12 :
6420 special_animation && j == 4 ? 3 :
6421 effective_action != action ? 0 :
6425 Bitmap *debug_bitmap = g_em->bitmap;
6426 int debug_src_x = g_em->src_x;
6427 int debug_src_y = g_em->src_y;
6430 int frame = getAnimationFrame(g->anim_frames,
6433 g->anim_start_frame,
6436 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y,
6437 g->double_movement && is_backside);
6439 g_em->bitmap = src_bitmap;
6440 g_em->src_x = src_x;
6441 g_em->src_y = src_y;
6442 g_em->src_offset_x = 0;
6443 g_em->src_offset_y = 0;
6444 g_em->dst_offset_x = 0;
6445 g_em->dst_offset_y = 0;
6446 g_em->width = TILEX;
6447 g_em->height = TILEY;
6449 g_em->crumbled_bitmap = NULL;
6450 g_em->crumbled_src_x = 0;
6451 g_em->crumbled_src_y = 0;
6452 g_em->crumbled_border_size = 0;
6454 g_em->has_crumbled_graphics = FALSE;
6455 g_em->preserve_background = FALSE;
6458 if (has_crumbled_graphics && crumbled == IMG_EMPTY_SPACE)
6459 printf("::: empty crumbled: %d [%s], %d, %d\n",
6460 effective_element, element_info[effective_element].token_name,
6461 effective_action, direction);
6464 /* if element can be crumbled, but certain action graphics are just empty
6465 space (like snapping sand with the original R'n'D graphics), do not
6466 treat these empty space graphics as crumbled graphics in EMC engine */
6467 if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
6469 getGraphicSource(crumbled, frame, &src_bitmap, &src_x, &src_y);
6471 g_em->has_crumbled_graphics = TRUE;
6472 g_em->crumbled_bitmap = src_bitmap;
6473 g_em->crumbled_src_x = src_x;
6474 g_em->crumbled_src_y = src_y;
6475 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
6479 if (element == EL_ROCK &&
6480 effective_action == ACTION_FILLING)
6481 printf("::: has_action_graphics == %d\n", has_action_graphics);
6484 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
6485 effective_action == ACTION_MOVING ||
6486 effective_action == ACTION_PUSHING ||
6487 effective_action == ACTION_EATING)) ||
6488 (!has_action_graphics && (effective_action == ACTION_FILLING ||
6489 effective_action == ACTION_EMPTYING)))
6492 (effective_action == ACTION_FALLING ||
6493 effective_action == ACTION_FILLING ||
6494 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
6495 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
6496 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
6497 int num_steps = (i == Ydrip_s1 ? 16 :
6498 i == Ydrip_s1B ? 16 :
6499 i == Ydrip_s2 ? 16 :
6500 i == Ydrip_s2B ? 16 :
6501 i == Xsand_stonein_1 ? 32 :
6502 i == Xsand_stonein_2 ? 32 :
6503 i == Xsand_stonein_3 ? 32 :
6504 i == Xsand_stonein_4 ? 32 :
6505 i == Xsand_stoneout_1 ? 16 :
6506 i == Xsand_stoneout_2 ? 16 : 8);
6507 int cx = ABS(dx) * (TILEX / num_steps);
6508 int cy = ABS(dy) * (TILEY / num_steps);
6509 int step_frame = (i == Ydrip_s2 ? j + 8 :
6510 i == Ydrip_s2B ? j + 8 :
6511 i == Xsand_stonein_2 ? j + 8 :
6512 i == Xsand_stonein_3 ? j + 16 :
6513 i == Xsand_stonein_4 ? j + 24 :
6514 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
6515 int step = (is_backside ? step_frame : num_steps - step_frame);
6517 if (is_backside) /* tile where movement starts */
6519 if (dx < 0 || dy < 0)
6521 g_em->src_offset_x = cx * step;
6522 g_em->src_offset_y = cy * step;
6526 g_em->dst_offset_x = cx * step;
6527 g_em->dst_offset_y = cy * step;
6530 else /* tile where movement ends */
6532 if (dx < 0 || dy < 0)
6534 g_em->dst_offset_x = cx * step;
6535 g_em->dst_offset_y = cy * step;
6539 g_em->src_offset_x = cx * step;
6540 g_em->src_offset_y = cy * step;
6544 g_em->width = TILEX - cx * step;
6545 g_em->height = TILEY - cy * step;
6548 /* create unique graphic identifier to decide if tile must be redrawn */
6549 /* bit 31 - 16 (16 bit): EM style graphic
6550 bit 15 - 12 ( 4 bit): EM style frame
6551 bit 11 - 6 ( 6 bit): graphic width
6552 bit 5 - 0 ( 6 bit): graphic height */
6553 g_em->unique_identifier =
6554 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
6558 /* skip check for EMC elements not contained in original EMC artwork */
6559 if (element == EL_EMC_FAKE_ACID)
6562 if (g_em->bitmap != debug_bitmap ||
6563 g_em->src_x != debug_src_x ||
6564 g_em->src_y != debug_src_y ||
6565 g_em->src_offset_x != 0 ||
6566 g_em->src_offset_y != 0 ||
6567 g_em->dst_offset_x != 0 ||
6568 g_em->dst_offset_y != 0 ||
6569 g_em->width != TILEX ||
6570 g_em->height != TILEY)
6572 static int last_i = -1;
6580 printf("::: EMC GFX ERROR for element %d -> %d ('%s', '%s', %d)",
6581 i, element, element_info[element].token_name,
6582 element_action_info[effective_action].suffix, direction);
6584 if (element != effective_element)
6585 printf(" [%d ('%s')]",
6587 element_info[effective_element].token_name);
6591 if (g_em->bitmap != debug_bitmap)
6592 printf(" %d (%d): different bitmap! (0x%08x != 0x%08x)\n",
6593 j, is_backside, (int)(g_em->bitmap), (int)(debug_bitmap));
6595 if (g_em->src_x != debug_src_x ||
6596 g_em->src_y != debug_src_y)
6597 printf(" frame %d (%c): %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
6598 j, (is_backside ? 'B' : 'F'),
6599 g_em->src_x, g_em->src_y,
6600 g_em->src_x / 32, g_em->src_y / 32,
6601 debug_src_x, debug_src_y,
6602 debug_src_x / 32, debug_src_y / 32);
6604 if (g_em->src_offset_x != 0 ||
6605 g_em->src_offset_y != 0 ||
6606 g_em->dst_offset_x != 0 ||
6607 g_em->dst_offset_y != 0)
6608 printf(" %d (%d): offsets %d,%d and %d,%d should be all 0\n",
6610 g_em->src_offset_x, g_em->src_offset_y,
6611 g_em->dst_offset_x, g_em->dst_offset_y);
6613 if (g_em->width != TILEX ||
6614 g_em->height != TILEY)
6615 printf(" %d (%d): size %d,%d should be %d,%d\n",
6617 g_em->width, g_em->height, TILEX, TILEY);
6619 num_em_gfx_errors++;
6626 for (i = 0; i < TILE_MAX; i++)
6628 for (j = 0; j < 8; j++)
6630 int element = object_mapping[i].element_rnd;
6631 int action = object_mapping[i].action;
6632 int direction = object_mapping[i].direction;
6633 boolean is_backside = object_mapping[i].is_backside;
6634 int graphic_action = el_act_dir2img(element, action, direction);
6635 int graphic_default = el_act_dir2img(element, ACTION_DEFAULT, direction);
6637 if ((action == ACTION_SMASHED_BY_ROCK ||
6638 action == ACTION_SMASHED_BY_SPRING ||
6639 action == ACTION_EATING) &&
6640 graphic_action == graphic_default)
6642 int e = (action == ACTION_SMASHED_BY_ROCK ? Ystone_s :
6643 action == ACTION_SMASHED_BY_SPRING ? Yspring_s :
6644 direction == MV_LEFT ? (is_backside? Yspring_wB: Yspring_w) :
6645 direction == MV_RIGHT ? (is_backside? Yspring_eB: Yspring_e) :
6648 /* no separate animation for "smashed by rock" -- use rock instead */
6649 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
6650 struct GraphicInfo_EM *g_xx = &graphic_info_em_object[e][7 - j];
6652 g_em->bitmap = g_xx->bitmap;
6653 g_em->src_x = g_xx->src_x;
6654 g_em->src_y = g_xx->src_y;
6655 g_em->src_offset_x = g_xx->src_offset_x;
6656 g_em->src_offset_y = g_xx->src_offset_y;
6657 g_em->dst_offset_x = g_xx->dst_offset_x;
6658 g_em->dst_offset_y = g_xx->dst_offset_y;
6659 g_em->width = g_xx->width;
6660 g_em->height = g_xx->height;
6661 g_em->unique_identifier = g_xx->unique_identifier;
6664 g_em->preserve_background = TRUE;
6669 for (p = 0; p < MAX_PLAYERS; p++)
6671 for (i = 0; i < SPR_MAX; i++)
6673 int element = player_mapping[p][i].element_rnd;
6674 int action = player_mapping[p][i].action;
6675 int direction = player_mapping[p][i].direction;
6677 for (j = 0; j < 8; j++)
6679 int effective_element = element;
6680 int effective_action = action;
6681 int graphic = (direction == MV_NONE ?
6682 el_act2img(effective_element, effective_action) :
6683 el_act_dir2img(effective_element, effective_action,
6685 struct GraphicInfo *g = &graphic_info[graphic];
6686 struct GraphicInfo_EM *g_em = &graphic_info_em_player[p][i][7 - j];
6692 Bitmap *debug_bitmap = g_em->bitmap;
6693 int debug_src_x = g_em->src_x;
6694 int debug_src_y = g_em->src_y;
6697 int frame = getAnimationFrame(g->anim_frames,
6700 g->anim_start_frame,
6703 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
6705 g_em->bitmap = src_bitmap;
6706 g_em->src_x = src_x;
6707 g_em->src_y = src_y;
6708 g_em->src_offset_x = 0;
6709 g_em->src_offset_y = 0;
6710 g_em->dst_offset_x = 0;
6711 g_em->dst_offset_y = 0;
6712 g_em->width = TILEX;
6713 g_em->height = TILEY;
6717 /* skip check for EMC elements not contained in original EMC artwork */
6718 if (element == EL_PLAYER_3 ||
6719 element == EL_PLAYER_4)
6722 if (g_em->bitmap != debug_bitmap ||
6723 g_em->src_x != debug_src_x ||
6724 g_em->src_y != debug_src_y)
6726 static int last_i = -1;
6734 printf("::: EMC GFX ERROR for p/a %d/%d -> %d ('%s', '%s', %d)",
6735 p, i, element, element_info[element].token_name,
6736 element_action_info[effective_action].suffix, direction);
6738 if (element != effective_element)
6739 printf(" [%d ('%s')]",
6741 element_info[effective_element].token_name);
6745 if (g_em->bitmap != debug_bitmap)
6746 printf(" %d: different bitmap! (0x%08x != 0x%08x)\n",
6747 j, (int)(g_em->bitmap), (int)(debug_bitmap));
6749 if (g_em->src_x != debug_src_x ||
6750 g_em->src_y != debug_src_y)
6751 printf(" frame %d: %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
6753 g_em->src_x, g_em->src_y,
6754 g_em->src_x / 32, g_em->src_y / 32,
6755 debug_src_x, debug_src_y,
6756 debug_src_x / 32, debug_src_y / 32);
6758 num_em_gfx_errors++;
6768 printf("::: [%d errors found]\n", num_em_gfx_errors);
6774 void PlayMenuSoundExt(int sound)
6776 if (sound == SND_UNDEFINED)
6779 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
6780 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
6783 if (IS_LOOP_SOUND(sound))
6784 PlaySoundLoop(sound);
6789 void PlayMenuSound()
6791 PlayMenuSoundExt(menu.sound[game_status]);
6794 void PlayMenuSoundStereo(int sound, int stereo_position)
6796 if (sound == SND_UNDEFINED)
6799 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
6800 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
6803 if (IS_LOOP_SOUND(sound))
6804 PlaySoundExt(sound, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_LOOP);
6806 PlaySoundStereo(sound, stereo_position);
6809 void PlayMenuSoundIfLoopExt(int sound)
6811 if (sound == SND_UNDEFINED)
6814 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
6815 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
6818 if (IS_LOOP_SOUND(sound))
6819 PlaySoundLoop(sound);
6822 void PlayMenuSoundIfLoop()
6824 PlayMenuSoundIfLoopExt(menu.sound[game_status]);
6827 void PlayMenuMusicExt(int music)
6829 if (music == MUS_UNDEFINED)
6832 if (!setup.sound_music)
6838 void PlayMenuMusic()
6840 PlayMenuMusicExt(menu.music[game_status]);
6843 void PlaySoundActivating()
6846 PlaySound(SND_MENU_ITEM_ACTIVATING);
6850 void PlaySoundSelecting()
6853 PlaySound(SND_MENU_ITEM_SELECTING);
6857 void ToggleFullscreenIfNeeded()
6859 boolean change_fullscreen = (setup.fullscreen !=
6860 video.fullscreen_enabled);
6861 boolean change_fullscreen_mode = (video.fullscreen_enabled &&
6862 !strEqual(setup.fullscreen_mode,
6863 video.fullscreen_mode_current));
6865 if (!video.fullscreen_available)
6869 if (change_fullscreen || change_fullscreen_mode)
6871 if (setup.fullscreen != video.fullscreen_enabled ||
6872 setup.fullscreen_mode != video.fullscreen_mode_current)
6875 Bitmap *tmp_backbuffer = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
6877 /* save backbuffer content which gets lost when toggling fullscreen mode */
6878 BlitBitmap(backbuffer, tmp_backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
6881 if (change_fullscreen_mode)
6883 if (setup.fullscreen && video.fullscreen_enabled)
6886 /* keep fullscreen, but change fullscreen mode (screen resolution) */
6888 /* (this is now set in sdl.c) */
6890 video.fullscreen_mode_current = setup.fullscreen_mode;
6892 video.fullscreen_enabled = FALSE; /* force new fullscreen mode */
6895 /* toggle fullscreen */
6896 ChangeVideoModeIfNeeded(setup.fullscreen);
6898 setup.fullscreen = video.fullscreen_enabled;
6900 /* restore backbuffer content from temporary backbuffer backup bitmap */
6901 BlitBitmap(tmp_backbuffer, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
6903 FreeBitmap(tmp_backbuffer);
6906 /* update visible window/screen */
6907 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
6909 redraw_mask = REDRAW_ALL;