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 /* never draw masked screen borders on borderless screens */
245 if (effectiveGameStatus() == GAME_MODE_LOADING ||
246 effectiveGameStatus() == GAME_MODE_TITLE)
249 if (redraw_mask & REDRAW_ALL)
250 DrawMaskedBorder_ALL();
253 if (redraw_mask & REDRAW_FIELD)
254 DrawMaskedBorder_FIELD();
255 if (redraw_mask & REDRAW_DOOR_1)
256 DrawMaskedBorder_DOOR_1();
257 if (redraw_mask & REDRAW_DOOR_2)
258 DrawMaskedBorder_DOOR_2();
259 if (redraw_mask & REDRAW_DOOR_3)
260 DrawMaskedBorder_DOOR_3();
267 DrawBuffer *buffer = (drawto_field == window ? backbuffer : drawto_field);
269 if (setup.direct_draw && game_status == GAME_MODE_PLAYING)
270 redraw_mask &= ~REDRAW_MAIN;
272 if (redraw_mask & REDRAW_TILES && redraw_tiles > REDRAWTILES_THRESHOLD)
273 redraw_mask |= REDRAW_FIELD;
275 if (redraw_mask & REDRAW_FIELD)
276 redraw_mask &= ~REDRAW_TILES;
278 if (redraw_mask == REDRAW_NONE)
281 if (redraw_mask & REDRAW_TILES &&
282 game_status == GAME_MODE_PLAYING &&
283 border.draw_masked[GAME_MODE_PLAYING])
284 redraw_mask |= REDRAW_FIELD;
286 if (global.fps_slowdown && game_status == GAME_MODE_PLAYING)
288 static boolean last_frame_skipped = FALSE;
289 boolean skip_even_when_not_scrolling = TRUE;
290 boolean just_scrolling = (ScreenMovDir != 0);
291 boolean verbose = FALSE;
293 if (global.fps_slowdown_factor > 1 &&
294 (FrameCounter % global.fps_slowdown_factor) &&
295 (just_scrolling || skip_even_when_not_scrolling))
297 redraw_mask &= ~REDRAW_MAIN;
299 last_frame_skipped = TRUE;
302 printf("FRAME SKIPPED\n");
306 if (last_frame_skipped)
307 redraw_mask |= REDRAW_FIELD;
309 last_frame_skipped = FALSE;
312 printf("frame not skipped\n");
316 /* synchronize X11 graphics at this point; if we would synchronize the
317 display immediately after the buffer switching (after the XFlush),
318 this could mean that we have to wait for the graphics to complete,
319 although we could go on doing calculations for the next frame */
323 /* prevent drawing masked border to backbuffer when using playfield buffer */
324 if (game_status != GAME_MODE_PLAYING ||
325 redraw_mask & REDRAW_FROM_BACKBUFFER ||
326 buffer == backbuffer)
327 DrawMaskedBorder(redraw_mask);
329 DrawMaskedBorder(redraw_mask & REDRAW_DOORS);
331 if (redraw_mask & REDRAW_ALL)
333 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
335 redraw_mask = REDRAW_NONE;
338 if (redraw_mask & REDRAW_FIELD)
340 if (game_status != GAME_MODE_PLAYING ||
341 redraw_mask & REDRAW_FROM_BACKBUFFER)
343 BlitBitmap(backbuffer, window,
344 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE, REAL_SX, REAL_SY);
348 int fx = FX, fy = FY;
350 if (setup.soft_scrolling)
352 fx += (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
353 fy += (ScreenMovDir & (MV_UP | MV_DOWN) ? ScreenGfxPos : 0);
356 if (setup.soft_scrolling ||
357 ABS(ScreenMovPos) + ScrollStepSize == TILEX ||
358 ABS(ScreenMovPos) == ScrollStepSize ||
359 redraw_tiles > REDRAWTILES_THRESHOLD)
361 if (border.draw_masked[GAME_MODE_PLAYING])
363 if (buffer != backbuffer)
365 /* copy playfield buffer to backbuffer to add masked border */
366 BlitBitmap(buffer, backbuffer, fx, fy, SXSIZE, SYSIZE, SX, SY);
367 DrawMaskedBorder(REDRAW_FIELD);
370 BlitBitmap(backbuffer, window,
371 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
376 BlitBitmap(buffer, window, fx, fy, SXSIZE, SYSIZE, SX, SY);
381 printf("redrawing all (ScreenGfxPos == %d) because %s\n",
383 (setup.soft_scrolling ?
384 "setup.soft_scrolling" :
385 ABS(ScreenGfxPos) + ScrollStepSize == TILEX ?
386 "ABS(ScreenGfxPos) + ScrollStepSize == TILEX" :
387 ABS(ScreenGfxPos) == ScrollStepSize ?
388 "ABS(ScreenGfxPos) == ScrollStepSize" :
389 "redraw_tiles > REDRAWTILES_THRESHOLD"));
395 redraw_mask &= ~REDRAW_MAIN;
398 if (redraw_mask & REDRAW_DOORS)
400 if (redraw_mask & REDRAW_DOOR_1)
401 BlitBitmap(backbuffer, window, DX, DY, DXSIZE, DYSIZE, DX, DY);
403 if (redraw_mask & REDRAW_DOOR_2)
404 BlitBitmap(backbuffer, window, VX, VY, VXSIZE, VYSIZE, VX, VY);
406 if (redraw_mask & REDRAW_DOOR_3)
407 BlitBitmap(backbuffer, window, EX, EY, EXSIZE, EYSIZE, EX, EY);
409 redraw_mask &= ~REDRAW_DOORS;
412 if (redraw_mask & REDRAW_MICROLEVEL)
414 BlitBitmap(backbuffer, window, SX, SY + 10 * TILEY, SXSIZE, 7 * TILEY,
415 SX, SY + 10 * TILEY);
417 redraw_mask &= ~REDRAW_MICROLEVEL;
420 if (redraw_mask & REDRAW_TILES)
422 for (x = 0; x < SCR_FIELDX; x++)
423 for (y = 0 ; y < SCR_FIELDY; y++)
424 if (redraw[redraw_x1 + x][redraw_y1 + y])
425 BlitBitmap(buffer, window,
426 FX + x * TILEX, FY + y * TILEY, TILEX, TILEY,
427 SX + x * TILEX, SY + y * TILEY);
430 if (redraw_mask & REDRAW_FPS) /* display frames per second */
435 sprintf(info1, " (only every %d. frame)", global.fps_slowdown_factor);
436 if (!global.fps_slowdown)
439 sprintf(text, "%.1f fps%s", global.frames_per_second, info1);
440 DrawTextExt(window, SX, SY, text, FONT_TEXT_2, BLIT_OPAQUE);
445 for (x = 0; x < MAX_BUF_XSIZE; x++)
446 for (y = 0; y < MAX_BUF_YSIZE; y++)
449 redraw_mask = REDRAW_NONE;
452 static void FadeCrossSaveBackbuffer()
454 BlitBitmap(backbuffer, bitmap_db_cross, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
457 static void FadeExt(int fade_mask, int fade_mode, int fade_type)
459 static int fade_type_skip = FADE_TYPE_NONE;
460 void (*draw_border_function)(void) = NULL;
461 Bitmap *bitmap = (fade_mode & FADE_TYPE_TRANSFORM ? bitmap_db_cross : NULL);
462 int x, y, width, height;
463 int fade_delay, post_delay;
465 if (fade_type == FADE_TYPE_FADE_OUT)
467 if (fade_type_skip != FADE_TYPE_NONE)
470 printf("::: skipping %d ... [%d] (X)\n", fade_mode, fade_type_skip);
473 /* skip all fade operations until specified fade operation */
474 if (fade_type & fade_type_skip)
475 fade_type_skip = FADE_TYPE_NONE;
480 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
482 FadeCrossSaveBackbuffer();
488 redraw_mask |= fade_mask;
490 if (fade_type == FADE_TYPE_SKIP)
493 printf("::: will skip %d ... [%d]\n", fade_mode, fade_type_skip);
496 fade_type_skip = fade_mode;
501 if (fade_type_skip != FADE_TYPE_NONE)
504 printf("::: skipping %d ... [%d]\n", fade_mode, fade_type_skip);
507 /* skip all fade operations until specified fade operation */
508 if (fade_type & fade_type_skip)
509 fade_type_skip = FADE_TYPE_NONE;
515 if (global.autoplay_leveldir)
517 // fading.fade_mode = FADE_MODE_NONE;
524 if (fading.fade_mode == FADE_MODE_NONE)
532 /* !!! what abount fade_mask == REDRAW_FIELD | REDRAW_ALL ??? !!! */
535 printf("::: NOW FADING %d ... [%d]\n", fade_mode, fade_type);
538 if (fade_mask & REDRAW_FIELD)
543 height = FULL_SYSIZE;
545 fade_delay = fading.fade_delay;
546 post_delay = (fade_mode == FADE_MODE_FADE_OUT ? fading.post_delay : 0);
548 if (border.draw_masked_when_fading)
549 draw_border_function = DrawMaskedBorder_FIELD; /* update when fading */
551 DrawMaskedBorder_FIELD(); /* draw once */
553 else /* REDRAW_ALL */
560 fade_delay = fading.fade_delay;
561 post_delay = (fade_mode == FADE_MODE_FADE_OUT ? fading.post_delay : 0);
565 if (!setup.fade_screens || fade_delay == 0)
567 if (!setup.fade_screens || fade_delay == 0 || fading.anim_mode == ANIM_NONE)
570 if (fade_mode == FADE_MODE_FADE_OUT)
571 ClearRectangle(backbuffer, x, y, width, height);
578 FadeRectangle(bitmap, x, y, width, height, fade_mode, fade_delay, post_delay,
579 draw_border_function);
581 redraw_mask &= ~fade_mask;
584 void FadeIn(int fade_mask)
587 global.border_status = game_status;
591 // printf("::: now fading in...\n");
593 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
594 FadeExt(fade_mask, fading.fade_mode, FADE_TYPE_FADE_IN);
596 FadeExt(fade_mask, FADE_MODE_FADE_IN, FADE_TYPE_FADE_IN);
599 if (fading.fade_mode == FADE_MODE_CROSSFADE)
600 FadeExt(fade_mask, FADE_MODE_CROSSFADE);
602 FadeExt(fade_mask, FADE_MODE_FADE_IN);
604 FadeExt(fade_mask, FADE_MODE_FADE_IN);
609 void FadeOut(int fade_mask)
612 // printf("::: fading.fade_mode == %d\n", fading.fade_mode);
615 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
616 FadeExt(fade_mask, fading.fade_mode, FADE_TYPE_FADE_OUT);
618 FadeExt(fade_mask, FADE_MODE_FADE_OUT, FADE_TYPE_FADE_OUT);
620 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
621 FadeCrossSaveBackbuffer();
623 FadeExt(fade_mask, FADE_MODE_FADE_OUT, FADE_TYPE_FADE_OUT);
628 if (fading.fade_mode == FADE_MODE_CROSSFADE)
629 FadeCrossSaveBackbuffer();
631 FadeExt(fade_mask, FADE_MODE_FADE_OUT);
633 FadeExt(fade_mask, FADE_MODE_FADE_OUT);
638 global.border_status = game_status;
643 void FadeCross(int fade_mask)
645 FadeExt(fade_mask, FADE_MODE_CROSSFADE);
649 static void FadeSetLeaveNext(struct TitleFadingInfo fading_leave, boolean set)
651 static struct TitleFadingInfo fading_leave_stored;
654 fading_leave_stored = fading_leave;
656 fading = fading_leave_stored;
659 void FadeSetEnterMenu()
661 fading = menu.enter_menu;
664 printf("::: storing enter_menu\n");
667 FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
670 void FadeSetLeaveMenu()
672 fading = menu.leave_menu;
675 printf("::: storing leave_menu\n");
678 FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
681 void FadeSetEnterScreen()
683 fading = menu.enter_screen[game_status];
686 printf("::: storing leave_screen[%d]\n", game_status);
689 FadeSetLeaveNext(menu.leave_screen[game_status], TRUE); /* store */
692 void FadeSetNextScreen()
694 fading = menu.next_screen;
697 printf("::: storing next_screen\n");
700 // (do not overwrite fade mode set by FadeSetEnterScreen)
701 // FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
704 void FadeSetLeaveScreen()
707 printf("::: recalling last stored value\n");
710 FadeSetLeaveNext(menu.leave_screen[game_status], FALSE); /* recall */
713 void FadeSetFromType(int type)
715 if (type & TYPE_ENTER_SCREEN)
716 FadeSetEnterScreen();
717 else if (type & TYPE_ENTER)
719 else if (type & TYPE_LEAVE)
723 void FadeSetDisabled()
725 static struct TitleFadingInfo fading_none = { FADE_MODE_NONE, -1, -1, -1 };
727 fading = fading_none;
730 void FadeSkipNextFadeIn()
732 FadeExt(0, FADE_MODE_SKIP_FADE_IN, FADE_TYPE_SKIP);
735 void FadeSkipNextFadeOut()
737 FadeExt(0, FADE_MODE_SKIP_FADE_OUT, FADE_TYPE_SKIP);
740 void SetWindowBackgroundImageIfDefined(int graphic)
742 if (graphic_info[graphic].bitmap)
743 SetWindowBackgroundBitmap(graphic_info[graphic].bitmap);
746 void SetMainBackgroundImageIfDefined(int graphic)
748 if (graphic_info[graphic].bitmap)
749 SetMainBackgroundBitmap(graphic_info[graphic].bitmap);
752 void SetDoorBackgroundImageIfDefined(int graphic)
754 if (graphic_info[graphic].bitmap)
755 SetDoorBackgroundBitmap(graphic_info[graphic].bitmap);
758 void SetWindowBackgroundImage(int graphic)
760 SetWindowBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
761 graphic_info[graphic].bitmap ?
762 graphic_info[graphic].bitmap :
763 graphic_info[IMG_BACKGROUND].bitmap);
766 void SetMainBackgroundImage(int graphic)
768 SetMainBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
769 graphic_info[graphic].bitmap ?
770 graphic_info[graphic].bitmap :
771 graphic_info[IMG_BACKGROUND].bitmap);
774 void SetDoorBackgroundImage(int graphic)
776 SetDoorBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
777 graphic_info[graphic].bitmap ?
778 graphic_info[graphic].bitmap :
779 graphic_info[IMG_BACKGROUND].bitmap);
782 void SetPanelBackground()
784 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, bitmap_db_panel,
785 DOOR_GFX_PAGEX5, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE, 0, 0);
787 SetDoorBackgroundBitmap(bitmap_db_panel);
790 void DrawBackground(int x, int y, int width, int height)
792 /* !!! "drawto" might still point to playfield buffer here (see below) !!! */
793 /* (when entering hall of fame after playing) */
795 ClearRectangleOnBackground(drawto, x, y, width, height);
797 ClearRectangleOnBackground(backbuffer, x, y, width, height);
800 redraw_mask |= REDRAW_FIELD;
803 void DrawBackgroundForFont(int x, int y, int width, int height, int font_nr)
805 struct FontBitmapInfo *font = getFontBitmapInfo(font_nr);
807 if (font->bitmap == NULL)
810 DrawBackground(x, y, width, height);
813 void DrawBackgroundForGraphic(int x, int y, int width, int height, int graphic)
815 struct GraphicInfo *g = &graphic_info[graphic];
817 if (g->bitmap == NULL)
820 DrawBackground(x, y, width, height);
825 /* !!! "drawto" might still point to playfield buffer here (see above) !!! */
826 /* (when entering hall of fame after playing) */
827 DrawBackground(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
829 /* !!! maybe this should be done before clearing the background !!! */
830 if (setup.soft_scrolling && game_status == GAME_MODE_PLAYING)
832 ClearRectangle(fieldbuffer, 0, 0, FXSIZE, FYSIZE);
833 SetDrawtoField(DRAW_BUFFERED);
836 SetDrawtoField(DRAW_BACKBUFFER);
838 if (setup.direct_draw && game_status == GAME_MODE_PLAYING)
840 ClearRectangle(window, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
841 SetDrawtoField(DRAW_DIRECT);
845 void MarkTileDirty(int x, int y)
847 int xx = redraw_x1 + x;
848 int yy = redraw_y1 + y;
853 redraw[xx][yy] = TRUE;
854 redraw_mask |= REDRAW_TILES;
857 void SetBorderElement()
861 BorderElement = EL_EMPTY;
863 for (y = 0; y < lev_fieldy && BorderElement == EL_EMPTY; y++)
865 for (x = 0; x < lev_fieldx; x++)
867 if (!IS_INDESTRUCTIBLE(Feld[x][y]))
868 BorderElement = EL_STEELWALL;
870 if (y != 0 && y != lev_fieldy - 1 && x != lev_fieldx - 1)
876 void FloodFillLevel(int from_x, int from_y, int fill_element,
877 short field[MAX_LEV_FIELDX][MAX_LEV_FIELDY],
878 int max_fieldx, int max_fieldy)
882 static int check[4][2] = { { -1, 0 }, { 0, -1 }, { 1, 0 }, { 0, 1 } };
883 static int safety = 0;
885 /* check if starting field still has the desired content */
886 if (field[from_x][from_y] == fill_element)
891 if (safety > max_fieldx * max_fieldy)
892 Error(ERR_EXIT, "Something went wrong in 'FloodFill()'. Please debug.");
894 old_element = field[from_x][from_y];
895 field[from_x][from_y] = fill_element;
897 for (i = 0; i < 4; i++)
899 x = from_x + check[i][0];
900 y = from_y + check[i][1];
902 if (IN_FIELD(x, y, max_fieldx, max_fieldy) && field[x][y] == old_element)
903 FloodFillLevel(x, y, fill_element, field, max_fieldx, max_fieldy);
909 void SetRandomAnimationValue(int x, int y)
911 gfx.anim_random_frame = GfxRandom[x][y];
914 inline int getGraphicAnimationFrame(int graphic, int sync_frame)
916 /* animation synchronized with global frame counter, not move position */
917 if (graphic_info[graphic].anim_global_sync || sync_frame < 0)
918 sync_frame = FrameCounter;
920 return getAnimationFrame(graphic_info[graphic].anim_frames,
921 graphic_info[graphic].anim_delay,
922 graphic_info[graphic].anim_mode,
923 graphic_info[graphic].anim_start_frame,
927 void getSizedGraphicSource(int graphic, int frame, int tilesize_raw,
928 Bitmap **bitmap, int *x, int *y)
932 int width_mult, width_div;
933 int height_mult, height_div;
937 { 15, 16, 2, 3 }, /* 1 x 1 */
938 { 7, 8, 2, 3 }, /* 2 x 2 */
939 { 3, 4, 2, 3 }, /* 4 x 4 */
940 { 1, 2, 2, 3 }, /* 8 x 8 */
941 { 0, 1, 2, 3 }, /* 16 x 16 */
942 { 0, 1, 0, 1 }, /* 32 x 32 */
944 struct GraphicInfo *g = &graphic_info[graphic];
945 Bitmap *src_bitmap = g->bitmap;
946 int tilesize = MIN(MAX(1, tilesize_raw), TILESIZE);
947 int offset_calc_pos = log_2(tilesize);
948 int width_mult = offset_calc[offset_calc_pos].width_mult;
949 int width_div = offset_calc[offset_calc_pos].width_div;
950 int height_mult = offset_calc[offset_calc_pos].height_mult;
951 int height_div = offset_calc[offset_calc_pos].height_div;
952 int startx = src_bitmap->width * width_mult / width_div;
953 int starty = src_bitmap->height * height_mult / height_div;
954 int src_x = g->src_x * tilesize / TILESIZE;
955 int src_y = g->src_y * tilesize / TILESIZE;
956 int width = g->width * tilesize / TILESIZE;
957 int height = g->height * tilesize / TILESIZE;
958 int offset_x = g->offset_x * tilesize / TILESIZE;
959 int offset_y = g->offset_y * tilesize / TILESIZE;
961 if (g->offset_y == 0) /* frames are ordered horizontally */
963 int max_width = g->anim_frames_per_line * width;
964 int pos = (src_y / height) * max_width + src_x + frame * offset_x;
966 src_x = pos % max_width;
967 src_y = src_y % height + pos / max_width * height;
969 else if (g->offset_x == 0) /* frames are ordered vertically */
971 int max_height = g->anim_frames_per_line * height;
972 int pos = (src_x / width) * max_height + src_y + frame * offset_y;
974 src_x = src_x % width + pos / max_height * width;
975 src_y = pos % max_height;
977 else /* frames are ordered diagonally */
979 src_x = src_x + frame * offset_x;
980 src_y = src_y + frame * offset_y;
983 *bitmap = src_bitmap;
988 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
991 getSizedGraphicSource(graphic, 0, MINI_TILESIZE, bitmap, x, y);
993 struct GraphicInfo *g = &graphic_info[graphic];
995 int mini_starty = g->bitmap->height * 2 / 3;
998 *x = mini_startx + g->src_x / 2;
999 *y = mini_starty + g->src_y / 2;
1003 inline void getGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
1004 int *x, int *y, boolean get_backside)
1006 struct GraphicInfo *g = &graphic_info[graphic];
1007 int src_x = g->src_x + (get_backside ? g->offset2_x : 0);
1008 int src_y = g->src_y + (get_backside ? g->offset2_y : 0);
1010 *bitmap = g->bitmap;
1012 if (g->offset_y == 0) /* frames are ordered horizontally */
1014 int max_width = g->anim_frames_per_line * g->width;
1015 int pos = (src_y / g->height) * max_width + src_x + frame * g->offset_x;
1017 *x = pos % max_width;
1018 *y = src_y % g->height + pos / max_width * g->height;
1020 else if (g->offset_x == 0) /* frames are ordered vertically */
1022 int max_height = g->anim_frames_per_line * g->height;
1023 int pos = (src_x / g->width) * max_height + src_y + frame * g->offset_y;
1025 *x = src_x % g->width + pos / max_height * g->width;
1026 *y = pos % max_height;
1028 else /* frames are ordered diagonally */
1030 *x = src_x + frame * g->offset_x;
1031 *y = src_y + frame * g->offset_y;
1035 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
1037 getGraphicSourceExt(graphic, frame, bitmap, x, y, FALSE);
1040 void DrawGraphic(int x, int y, int graphic, int frame)
1043 if (!IN_SCR_FIELD(x, y))
1045 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
1046 printf("DrawGraphic(): This should never happen!\n");
1051 DrawGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic, frame);
1052 MarkTileDirty(x, y);
1055 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
1061 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1062 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
1065 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
1068 if (!IN_SCR_FIELD(x, y))
1070 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
1071 printf("DrawGraphicThruMask(): This should never happen!\n");
1076 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y *TILEY, graphic,
1078 MarkTileDirty(x, y);
1081 void DrawGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y, int graphic,
1087 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1089 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1090 dst_x - src_x, dst_y - src_y);
1091 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dst_x, dst_y);
1094 void DrawSizedGraphic(int x, int y, int graphic, int frame, int tilesize)
1096 DrawSizedGraphicExt(drawto, SX + x * tilesize, SY + y * tilesize, graphic,
1098 MarkTileDirty(x / tilesize, y / tilesize);
1101 void DrawSizedGraphicExt(DrawBuffer *d, int x, int y, int graphic, int frame,
1107 getSizedGraphicSource(graphic, frame, tilesize, &src_bitmap, &src_x, &src_y);
1108 BlitBitmap(src_bitmap, d, src_x, src_y, tilesize, tilesize, x, y);
1111 void DrawMiniGraphic(int x, int y, int graphic)
1113 DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
1114 MarkTileDirty(x / 2, y / 2);
1117 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
1122 getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1123 BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
1126 inline static void DrawGraphicShiftedNormal(int x, int y, int dx, int dy,
1127 int graphic, int frame,
1128 int cut_mode, int mask_mode)
1133 int width = TILEX, height = TILEY;
1136 if (dx || dy) /* shifted graphic */
1138 if (x < BX1) /* object enters playfield from the left */
1145 else if (x > BX2) /* object enters playfield from the right */
1151 else if (x==BX1 && dx < 0) /* object leaves playfield to the left */
1157 else if (x==BX2 && dx > 0) /* object leaves playfield to the right */
1159 else if (dx) /* general horizontal movement */
1160 MarkTileDirty(x + SIGN(dx), y);
1162 if (y < BY1) /* object enters playfield from the top */
1164 if (cut_mode==CUT_BELOW) /* object completely above top border */
1172 else if (y > BY2) /* object enters playfield from the bottom */
1178 else if (y==BY1 && dy < 0) /* object leaves playfield to the top */
1184 else if (dy > 0 && cut_mode == CUT_ABOVE)
1186 if (y == BY2) /* object completely above bottom border */
1192 MarkTileDirty(x, y + 1);
1193 } /* object leaves playfield to the bottom */
1194 else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
1196 else if (dy) /* general vertical movement */
1197 MarkTileDirty(x, y + SIGN(dy));
1201 if (!IN_SCR_FIELD(x, y))
1203 printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
1204 printf("DrawGraphicShifted(): This should never happen!\n");
1209 if (width > 0 && height > 0)
1211 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1216 dst_x = FX + x * TILEX + dx;
1217 dst_y = FY + y * TILEY + dy;
1219 if (mask_mode == USE_MASKING)
1221 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1222 dst_x - src_x, dst_y - src_y);
1223 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1227 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1230 MarkTileDirty(x, y);
1234 inline static void DrawGraphicShiftedDouble(int x, int y, int dx, int dy,
1235 int graphic, int frame,
1236 int cut_mode, int mask_mode)
1241 int width = TILEX, height = TILEY;
1244 int x2 = x + SIGN(dx);
1245 int y2 = y + SIGN(dy);
1246 int anim_frames = graphic_info[graphic].anim_frames;
1247 int sync_frame = (dx ? ABS(dx) : ABS(dy)) * anim_frames / TILESIZE;
1248 boolean draw_start_tile = (cut_mode != CUT_ABOVE); /* only for falling! */
1249 boolean draw_end_tile = (cut_mode != CUT_BELOW); /* only for falling! */
1251 /* re-calculate animation frame for two-tile movement animation */
1252 frame = getGraphicAnimationFrame(graphic, sync_frame);
1254 /* check if movement start graphic inside screen area and should be drawn */
1255 if (draw_start_tile && IN_SCR_FIELD(x1, y1))
1257 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, TRUE);
1259 dst_x = FX + x1 * TILEX;
1260 dst_y = FY + y1 * TILEY;
1262 if (mask_mode == USE_MASKING)
1264 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1265 dst_x - src_x, dst_y - src_y);
1266 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1270 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1273 MarkTileDirty(x1, y1);
1276 /* check if movement end graphic inside screen area and should be drawn */
1277 if (draw_end_tile && IN_SCR_FIELD(x2, y2))
1279 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
1281 dst_x = FX + x2 * TILEX;
1282 dst_y = FY + y2 * TILEY;
1284 if (mask_mode == USE_MASKING)
1286 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1287 dst_x - src_x, dst_y - src_y);
1288 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1292 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1295 MarkTileDirty(x2, y2);
1299 static void DrawGraphicShifted(int x, int y, int dx, int dy,
1300 int graphic, int frame,
1301 int cut_mode, int mask_mode)
1305 DrawGraphic(x, y, graphic, frame);
1310 if (graphic_info[graphic].double_movement) /* EM style movement images */
1311 DrawGraphicShiftedDouble(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1313 DrawGraphicShiftedNormal(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1316 void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
1317 int frame, int cut_mode)
1319 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, USE_MASKING);
1322 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
1323 int cut_mode, int mask_mode)
1325 int lx = LEVELX(x), ly = LEVELY(y);
1329 if (IN_LEV_FIELD(lx, ly))
1331 SetRandomAnimationValue(lx, ly);
1333 graphic = el_act_dir2img(element, GfxAction[lx][ly], GfxDir[lx][ly]);
1334 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1336 /* do not use double (EM style) movement graphic when not moving */
1337 if (graphic_info[graphic].double_movement && !dx && !dy)
1339 graphic = el_act_dir2img(element, ACTION_DEFAULT, GfxDir[lx][ly]);
1340 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1343 else /* border element */
1345 graphic = el2img(element);
1346 frame = getGraphicAnimationFrame(graphic, -1);
1349 if (element == EL_EXPANDABLE_WALL)
1351 boolean left_stopped = FALSE, right_stopped = FALSE;
1353 if (!IN_LEV_FIELD(lx - 1, ly) || IS_WALL(Feld[lx - 1][ly]))
1354 left_stopped = TRUE;
1355 if (!IN_LEV_FIELD(lx + 1, ly) || IS_WALL(Feld[lx + 1][ly]))
1356 right_stopped = TRUE;
1358 if (left_stopped && right_stopped)
1360 else if (left_stopped)
1362 graphic = IMG_EXPANDABLE_WALL_GROWING_RIGHT;
1363 frame = graphic_info[graphic].anim_frames - 1;
1365 else if (right_stopped)
1367 graphic = IMG_EXPANDABLE_WALL_GROWING_LEFT;
1368 frame = graphic_info[graphic].anim_frames - 1;
1373 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
1374 else if (mask_mode == USE_MASKING)
1375 DrawGraphicThruMask(x, y, graphic, frame);
1377 DrawGraphic(x, y, graphic, frame);
1380 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
1381 int cut_mode, int mask_mode)
1383 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1384 DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
1385 cut_mode, mask_mode);
1388 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
1391 DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1394 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
1397 DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1400 void DrawLevelElementThruMask(int x, int y, int element)
1402 DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1405 void DrawLevelFieldThruMask(int x, int y)
1407 DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
1410 static void DrawLevelFieldCrumbledSandExt(int x, int y, int graphic, int frame)
1414 int sx = SCREENX(x), sy = SCREENY(y);
1416 int width, height, cx, cy, i;
1417 int crumbled_border_size = graphic_info[graphic].border_size;
1418 static int xy[4][2] =
1426 if (!IN_LEV_FIELD(x, y))
1429 element = TILE_GFX_ELEMENT(x, y);
1431 /* crumble field itself */
1432 if (GFX_CRUMBLED(element) && !IS_MOVING(x, y))
1434 if (!IN_SCR_FIELD(sx, sy))
1437 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1439 for (i = 0; i < 4; i++)
1441 int xx = x + xy[i][0];
1442 int yy = y + xy[i][1];
1444 element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1447 /* check if neighbour field is of same type */
1448 if (GFX_CRUMBLED(element) && !IS_MOVING(xx, yy))
1451 if (i == 1 || i == 2)
1453 width = crumbled_border_size;
1455 cx = (i == 2 ? TILEX - crumbled_border_size : 0);
1461 height = crumbled_border_size;
1463 cy = (i == 3 ? TILEY - crumbled_border_size : 0);
1466 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1467 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
1470 MarkTileDirty(sx, sy);
1472 else /* crumble neighbour fields */
1474 for (i = 0; i < 4; i++)
1476 int xx = x + xy[i][0];
1477 int yy = y + xy[i][1];
1478 int sxx = sx + xy[i][0];
1479 int syy = sy + xy[i][1];
1481 if (!IN_LEV_FIELD(xx, yy) ||
1482 !IN_SCR_FIELD(sxx, syy) ||
1486 if (Feld[xx][yy] == EL_ELEMENT_SNAPPING)
1489 element = TILE_GFX_ELEMENT(xx, yy);
1491 if (!GFX_CRUMBLED(element))
1494 graphic = el_act2crm(element, ACTION_DEFAULT);
1495 crumbled_border_size = graphic_info[graphic].border_size;
1497 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1499 if (i == 1 || i == 2)
1501 width = crumbled_border_size;
1503 cx = (i == 1 ? TILEX - crumbled_border_size : 0);
1509 height = crumbled_border_size;
1511 cy = (i == 0 ? TILEY - crumbled_border_size : 0);
1514 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1515 width, height, FX + sxx * TILEX + cx, FY + syy * TILEY + cy);
1517 MarkTileDirty(sxx, syy);
1522 void DrawLevelFieldCrumbledSand(int x, int y)
1526 if (!IN_LEV_FIELD(x, y))
1530 /* !!! CHECK THIS !!! */
1533 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
1534 GFX_CRUMBLED(GfxElement[x][y]))
1537 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
1538 GfxElement[x][y] != EL_UNDEFINED &&
1539 GFX_CRUMBLED(GfxElement[x][y]))
1541 DrawLevelFieldCrumbledSandDigging(x, y, GfxDir[x][y], GfxFrame[x][y]);
1548 graphic = el_act2crm(TILE_GFX_ELEMENT(x, y), ACTION_DEFAULT);
1550 graphic = el_act2crm(Feld[x][y], ACTION_DEFAULT);
1553 DrawLevelFieldCrumbledSandExt(x, y, graphic, 0);
1556 void DrawLevelFieldCrumbledSandDigging(int x, int y, int direction,
1559 int graphic1 = el_act_dir2img(GfxElement[x][y], ACTION_DIGGING, direction);
1560 int graphic2 = el_act_dir2crm(GfxElement[x][y], ACTION_DIGGING, direction);
1561 int frame1 = getGraphicAnimationFrame(graphic1, step_frame);
1562 int frame2 = getGraphicAnimationFrame(graphic2, step_frame);
1563 int sx = SCREENX(x), sy = SCREENY(y);
1565 DrawGraphic(sx, sy, graphic1, frame1);
1566 DrawLevelFieldCrumbledSandExt(x, y, graphic2, frame2);
1569 void DrawLevelFieldCrumbledSandNeighbours(int x, int y)
1571 int sx = SCREENX(x), sy = SCREENY(y);
1572 static int xy[4][2] =
1581 for (i = 0; i < 4; i++)
1583 int xx = x + xy[i][0];
1584 int yy = y + xy[i][1];
1585 int sxx = sx + xy[i][0];
1586 int syy = sy + xy[i][1];
1588 if (!IN_LEV_FIELD(xx, yy) ||
1589 !IN_SCR_FIELD(sxx, syy) ||
1590 !GFX_CRUMBLED(Feld[xx][yy]) ||
1594 DrawLevelField(xx, yy);
1598 static int getBorderElement(int x, int y)
1602 { EL_STEELWALL_TOPLEFT, EL_INVISIBLE_STEELWALL_TOPLEFT },
1603 { EL_STEELWALL_TOPRIGHT, EL_INVISIBLE_STEELWALL_TOPRIGHT },
1604 { EL_STEELWALL_BOTTOMLEFT, EL_INVISIBLE_STEELWALL_BOTTOMLEFT },
1605 { EL_STEELWALL_BOTTOMRIGHT, EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
1606 { EL_STEELWALL_VERTICAL, EL_INVISIBLE_STEELWALL_VERTICAL },
1607 { EL_STEELWALL_HORIZONTAL, EL_INVISIBLE_STEELWALL_HORIZONTAL },
1608 { EL_STEELWALL, EL_INVISIBLE_STEELWALL }
1610 int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
1611 int steel_position = (x == -1 && y == -1 ? 0 :
1612 x == lev_fieldx && y == -1 ? 1 :
1613 x == -1 && y == lev_fieldy ? 2 :
1614 x == lev_fieldx && y == lev_fieldy ? 3 :
1615 x == -1 || x == lev_fieldx ? 4 :
1616 y == -1 || y == lev_fieldy ? 5 : 6);
1618 return border[steel_position][steel_type];
1621 void DrawScreenElement(int x, int y, int element)
1623 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
1624 DrawLevelFieldCrumbledSand(LEVELX(x), LEVELY(y));
1627 void DrawLevelElement(int x, int y, int element)
1629 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1630 DrawScreenElement(SCREENX(x), SCREENY(y), element);
1633 void DrawScreenField(int x, int y)
1635 int lx = LEVELX(x), ly = LEVELY(y);
1636 int element, content;
1638 if (!IN_LEV_FIELD(lx, ly))
1640 if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
1643 element = getBorderElement(lx, ly);
1645 DrawScreenElement(x, y, element);
1649 element = Feld[lx][ly];
1650 content = Store[lx][ly];
1652 if (IS_MOVING(lx, ly))
1654 int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
1655 boolean cut_mode = NO_CUTTING;
1657 if (element == EL_QUICKSAND_EMPTYING ||
1658 element == EL_QUICKSAND_FAST_EMPTYING ||
1659 element == EL_MAGIC_WALL_EMPTYING ||
1660 element == EL_BD_MAGIC_WALL_EMPTYING ||
1661 element == EL_DC_MAGIC_WALL_EMPTYING ||
1662 element == EL_AMOEBA_DROPPING)
1663 cut_mode = CUT_ABOVE;
1664 else if (element == EL_QUICKSAND_FILLING ||
1665 element == EL_QUICKSAND_FAST_FILLING ||
1666 element == EL_MAGIC_WALL_FILLING ||
1667 element == EL_BD_MAGIC_WALL_FILLING ||
1668 element == EL_DC_MAGIC_WALL_FILLING)
1669 cut_mode = CUT_BELOW;
1671 if (cut_mode == CUT_ABOVE)
1672 DrawScreenElementShifted(x, y, 0, 0, element, NO_CUTTING);
1674 DrawScreenElement(x, y, EL_EMPTY);
1677 DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
1678 else if (cut_mode == NO_CUTTING)
1679 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
1681 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
1683 if (content == EL_ACID)
1685 int dir = MovDir[lx][ly];
1686 int newlx = lx + (dir == MV_LEFT ? -1 : dir == MV_RIGHT ? +1 : 0);
1687 int newly = ly + (dir == MV_UP ? -1 : dir == MV_DOWN ? +1 : 0);
1689 DrawLevelElementThruMask(newlx, newly, EL_ACID);
1692 else if (IS_BLOCKED(lx, ly))
1697 boolean cut_mode = NO_CUTTING;
1698 int element_old, content_old;
1700 Blocked2Moving(lx, ly, &oldx, &oldy);
1703 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
1704 MovDir[oldx][oldy] == MV_RIGHT);
1706 element_old = Feld[oldx][oldy];
1707 content_old = Store[oldx][oldy];
1709 if (element_old == EL_QUICKSAND_EMPTYING ||
1710 element_old == EL_QUICKSAND_FAST_EMPTYING ||
1711 element_old == EL_MAGIC_WALL_EMPTYING ||
1712 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
1713 element_old == EL_DC_MAGIC_WALL_EMPTYING ||
1714 element_old == EL_AMOEBA_DROPPING)
1715 cut_mode = CUT_ABOVE;
1717 DrawScreenElement(x, y, EL_EMPTY);
1720 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
1722 else if (cut_mode == NO_CUTTING)
1723 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
1726 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
1729 else if (IS_DRAWABLE(element))
1730 DrawScreenElement(x, y, element);
1732 DrawScreenElement(x, y, EL_EMPTY);
1735 void DrawLevelField(int x, int y)
1737 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1738 DrawScreenField(SCREENX(x), SCREENY(y));
1739 else if (IS_MOVING(x, y))
1743 Moving2Blocked(x, y, &newx, &newy);
1744 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
1745 DrawScreenField(SCREENX(newx), SCREENY(newy));
1747 else if (IS_BLOCKED(x, y))
1751 Blocked2Moving(x, y, &oldx, &oldy);
1752 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
1753 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
1757 void DrawMiniElement(int x, int y, int element)
1761 graphic = el2edimg(element);
1762 DrawMiniGraphic(x, y, graphic);
1765 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
1767 int x = sx + scroll_x, y = sy + scroll_y;
1769 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
1770 DrawMiniElement(sx, sy, EL_EMPTY);
1771 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
1772 DrawMiniElement(sx, sy, Feld[x][y]);
1774 DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
1777 void DrawEnvelopeBackground(int envelope_nr, int startx, int starty,
1778 int x, int y, int xsize, int ysize, int font_nr)
1780 int font_width = getFontWidth(font_nr);
1781 int font_height = getFontHeight(font_nr);
1782 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1785 int dst_x = SX + startx + x * font_width;
1786 int dst_y = SY + starty + y * font_height;
1787 int width = graphic_info[graphic].width;
1788 int height = graphic_info[graphic].height;
1789 int inner_width = MAX(width - 2 * font_width, font_width);
1790 int inner_height = MAX(height - 2 * font_height, font_height);
1791 int inner_sx = (width >= 3 * font_width ? font_width : 0);
1792 int inner_sy = (height >= 3 * font_height ? font_height : 0);
1793 boolean draw_masked = graphic_info[graphic].draw_masked;
1795 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1797 if (src_bitmap == NULL || width < font_width || height < font_height)
1799 ClearRectangle(drawto, dst_x, dst_y, font_width, font_height);
1803 src_x += (x == 0 ? 0 : x == xsize - 1 ? width - font_width :
1804 inner_sx + (x - 1) * font_width % inner_width);
1805 src_y += (y == 0 ? 0 : y == ysize - 1 ? height - font_height :
1806 inner_sy + (y - 1) * font_height % inner_height);
1810 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1811 dst_x - src_x, dst_y - src_y);
1812 BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1816 BlitBitmap(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1820 void AnimateEnvelope(int envelope_nr, int anim_mode, int action)
1822 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1823 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1824 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
1825 boolean ffwd_delay = (tape.playing && tape.fast_forward);
1826 boolean no_delay = (tape.warp_forward);
1827 unsigned long anim_delay = 0;
1828 int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
1829 int anim_delay_value = (no_delay ? 0 : frame_delay_value);
1830 int font_nr = FONT_ENVELOPE_1 + envelope_nr;
1831 int font_width = getFontWidth(font_nr);
1832 int font_height = getFontHeight(font_nr);
1833 int max_xsize = level.envelope[envelope_nr].xsize;
1834 int max_ysize = level.envelope[envelope_nr].ysize;
1835 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
1836 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
1837 int xend = max_xsize;
1838 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
1839 int xstep = (xstart < xend ? 1 : 0);
1840 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
1843 for (x = xstart, y = ystart; x <= xend && y <= yend; x += xstep, y += ystep)
1845 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
1846 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
1847 int sx = (SXSIZE - xsize * font_width) / 2;
1848 int sy = (SYSIZE - ysize * font_height) / 2;
1851 SetDrawtoField(DRAW_BUFFERED);
1853 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
1855 SetDrawtoField(DRAW_BACKBUFFER);
1857 for (yy = 0; yy < ysize; yy++) for (xx = 0; xx < xsize; xx++)
1858 DrawEnvelopeBackground(envelope_nr, sx,sy, xx,yy, xsize, ysize, font_nr);
1861 DrawTextBuffer(SX + sx + font_width, SY + sy + font_height,
1862 level.envelope[envelope_nr].text, font_nr, max_xsize,
1863 xsize - 2, ysize - 2, mask_mode,
1864 level.envelope[envelope_nr].autowrap,
1865 level.envelope[envelope_nr].centered, FALSE);
1867 DrawTextToTextArea(SX + sx + font_width, SY + sy + font_height,
1868 level.envelope[envelope_nr].text, font_nr, max_xsize,
1869 xsize - 2, ysize - 2, mask_mode);
1872 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
1875 WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
1879 void ShowEnvelope(int envelope_nr)
1881 int element = EL_ENVELOPE_1 + envelope_nr;
1882 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1883 int sound_opening = element_info[element].sound[ACTION_OPENING];
1884 int sound_closing = element_info[element].sound[ACTION_CLOSING];
1885 boolean ffwd_delay = (tape.playing && tape.fast_forward);
1886 boolean no_delay = (tape.warp_forward);
1887 int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
1888 int wait_delay_value = (no_delay ? 0 : normal_delay_value);
1889 int anim_mode = graphic_info[graphic].anim_mode;
1890 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
1891 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
1893 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
1895 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
1897 if (anim_mode == ANIM_DEFAULT)
1898 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_OPENING);
1900 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_OPENING);
1903 Delay(wait_delay_value);
1905 WaitForEventToContinue();
1907 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
1909 if (anim_mode != ANIM_NONE)
1910 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_CLOSING);
1912 if (anim_mode == ANIM_DEFAULT)
1913 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_CLOSING);
1915 game.envelope_active = FALSE;
1917 SetDrawtoField(DRAW_BUFFERED);
1919 redraw_mask |= REDRAW_FIELD;
1923 void DrawPreviewElement(int dst_x, int dst_y, int element, int tilesize)
1927 int graphic = el2preimg(element);
1929 getSizedGraphicSource(graphic, 0, tilesize, &src_bitmap, &src_x, &src_y);
1930 BlitBitmap(src_bitmap, drawto, src_x, src_y, tilesize, tilesize, dst_x,dst_y);
1937 SetDrawBackgroundMask(REDRAW_NONE);
1940 for (x = BX1; x <= BX2; x++)
1941 for (y = BY1; y <= BY2; y++)
1942 DrawScreenField(x, y);
1944 redraw_mask |= REDRAW_FIELD;
1947 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
1951 for (x = 0; x < size_x; x++)
1952 for (y = 0; y < size_y; y++)
1953 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
1955 redraw_mask |= REDRAW_FIELD;
1958 static void DrawPreviewLevelExt(int from_x, int from_y)
1960 boolean show_level_border = (BorderElement != EL_EMPTY);
1961 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
1962 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
1963 int tile_size = preview.tile_size;
1964 int preview_width = preview.xsize * tile_size;
1965 int preview_height = preview.ysize * tile_size;
1966 int real_preview_xsize = MIN(level_xsize, preview.xsize);
1967 int real_preview_ysize = MIN(level_ysize, preview.ysize);
1968 int dst_x = SX + ALIGNED_XPOS(preview.x, preview_width, preview.align);
1969 int dst_y = SY + ALIGNED_YPOS(preview.y, preview_height, preview.valign);
1972 DrawBackground(dst_x, dst_y, preview_width, preview_height);
1974 dst_x += (preview_width - real_preview_xsize * tile_size) / 2;
1975 dst_y += (preview_height - real_preview_ysize * tile_size) / 2;
1977 for (x = 0; x < real_preview_xsize; x++)
1979 for (y = 0; y < real_preview_ysize; y++)
1981 int lx = from_x + x + (show_level_border ? -1 : 0);
1982 int ly = from_y + y + (show_level_border ? -1 : 0);
1983 int element = (IN_LEV_FIELD(lx, ly) ? level.field[lx][ly] :
1984 getBorderElement(lx, ly));
1986 DrawPreviewElement(dst_x + x * tile_size, dst_y + y * tile_size,
1987 element, tile_size);
1991 redraw_mask |= REDRAW_MICROLEVEL;
1994 #define MICROLABEL_EMPTY 0
1995 #define MICROLABEL_LEVEL_NAME 1
1996 #define MICROLABEL_LEVEL_AUTHOR_HEAD 2
1997 #define MICROLABEL_LEVEL_AUTHOR 3
1998 #define MICROLABEL_IMPORTED_FROM_HEAD 4
1999 #define MICROLABEL_IMPORTED_FROM 5
2000 #define MICROLABEL_IMPORTED_BY_HEAD 6
2001 #define MICROLABEL_IMPORTED_BY 7
2003 static int getMaxTextLength(struct TextPosInfo *pos, int font_nr)
2005 int max_text_width = SXSIZE;
2006 int font_width = getFontWidth(font_nr);
2008 if (pos->align == ALIGN_CENTER)
2009 max_text_width = (pos->x < SXSIZE / 2 ? pos->x * 2 : (SXSIZE - pos->x) * 2);
2010 else if (pos->align == ALIGN_RIGHT)
2011 max_text_width = pos->x;
2013 max_text_width = SXSIZE - pos->x;
2015 return max_text_width / font_width;
2018 static void DrawPreviewLevelLabelExt(int mode)
2020 struct TextPosInfo *pos = &menu.main.text.level_info_2;
2021 char label_text[MAX_OUTPUT_LINESIZE + 1];
2022 int max_len_label_text;
2024 int font_nr = pos->font;
2027 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
2028 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
2029 mode == MICROLABEL_IMPORTED_BY_HEAD)
2030 font_nr = pos->font_alt;
2032 int font_nr = FONT_TEXT_2;
2035 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
2036 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
2037 mode == MICROLABEL_IMPORTED_BY_HEAD)
2038 font_nr = FONT_TEXT_3;
2042 max_len_label_text = getMaxTextLength(pos, font_nr);
2044 max_len_label_text = SXSIZE / getFontWidth(font_nr);
2048 if (pos->size != -1)
2049 max_len_label_text = pos->size;
2052 for (i = 0; i < max_len_label_text; i++)
2053 label_text[i] = ' ';
2054 label_text[max_len_label_text] = '\0';
2056 if (strlen(label_text) > 0)
2059 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2061 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
2062 int lypos = MICROLABEL2_YPOS;
2064 DrawText(lxpos, lypos, label_text, font_nr);
2069 (mode == MICROLABEL_LEVEL_NAME ? level.name :
2070 mode == MICROLABEL_LEVEL_AUTHOR_HEAD ? "created by" :
2071 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
2072 mode == MICROLABEL_IMPORTED_FROM_HEAD ? "imported from" :
2073 mode == MICROLABEL_IMPORTED_FROM ? leveldir_current->imported_from :
2074 mode == MICROLABEL_IMPORTED_BY_HEAD ? "imported by" :
2075 mode == MICROLABEL_IMPORTED_BY ? leveldir_current->imported_by :""),
2076 max_len_label_text);
2077 label_text[max_len_label_text] = '\0';
2079 if (strlen(label_text) > 0)
2082 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2084 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
2085 int lypos = MICROLABEL2_YPOS;
2087 DrawText(lxpos, lypos, label_text, font_nr);
2091 redraw_mask |= REDRAW_MICROLEVEL;
2094 void DrawPreviewLevel(boolean restart)
2096 static unsigned long scroll_delay = 0;
2097 static unsigned long label_delay = 0;
2098 static int from_x, from_y, scroll_direction;
2099 static int label_state, label_counter;
2100 unsigned long scroll_delay_value = preview.step_delay;
2101 boolean show_level_border = (BorderElement != EL_EMPTY);
2102 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
2103 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
2104 int last_game_status = game_status; /* save current game status */
2107 /* force PREVIEW font on preview level */
2108 game_status = GAME_MODE_PSEUDO_PREVIEW;
2116 if (preview.anim_mode == ANIM_CENTERED)
2118 if (level_xsize > preview.xsize)
2119 from_x = (level_xsize - preview.xsize) / 2;
2120 if (level_ysize > preview.ysize)
2121 from_y = (level_ysize - preview.ysize) / 2;
2124 from_x += preview.xoffset;
2125 from_y += preview.yoffset;
2127 scroll_direction = MV_RIGHT;
2131 DrawPreviewLevelExt(from_x, from_y);
2132 DrawPreviewLevelLabelExt(label_state);
2134 /* initialize delay counters */
2135 DelayReached(&scroll_delay, 0);
2136 DelayReached(&label_delay, 0);
2138 if (leveldir_current->name)
2140 struct TextPosInfo *pos = &menu.main.text.level_info_1;
2141 char label_text[MAX_OUTPUT_LINESIZE + 1];
2143 int font_nr = pos->font;
2145 int font_nr = FONT_TEXT_1;
2148 int max_len_label_text = getMaxTextLength(pos, font_nr);
2150 int max_len_label_text = SXSIZE / getFontWidth(font_nr);
2158 if (pos->size != -1)
2159 max_len_label_text = pos->size;
2162 strncpy(label_text, leveldir_current->name, max_len_label_text);
2163 label_text[max_len_label_text] = '\0';
2166 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2168 lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
2169 lypos = SY + MICROLABEL1_YPOS;
2171 DrawText(lxpos, lypos, label_text, font_nr);
2175 game_status = last_game_status; /* restore current game status */
2180 /* scroll preview level, if needed */
2181 if (preview.anim_mode != ANIM_NONE &&
2182 (level_xsize > preview.xsize || level_ysize > preview.ysize) &&
2183 DelayReached(&scroll_delay, scroll_delay_value))
2185 switch (scroll_direction)
2190 from_x -= preview.step_offset;
2191 from_x = (from_x < 0 ? 0 : from_x);
2194 scroll_direction = MV_UP;
2198 if (from_x < level_xsize - preview.xsize)
2200 from_x += preview.step_offset;
2201 from_x = (from_x > level_xsize - preview.xsize ?
2202 level_xsize - preview.xsize : from_x);
2205 scroll_direction = MV_DOWN;
2211 from_y -= preview.step_offset;
2212 from_y = (from_y < 0 ? 0 : from_y);
2215 scroll_direction = MV_RIGHT;
2219 if (from_y < level_ysize - preview.ysize)
2221 from_y += preview.step_offset;
2222 from_y = (from_y > level_ysize - preview.ysize ?
2223 level_ysize - preview.ysize : from_y);
2226 scroll_direction = MV_LEFT;
2233 DrawPreviewLevelExt(from_x, from_y);
2236 /* !!! THIS ALL SUCKS -- SHOULD BE CLEANLY REWRITTEN !!! */
2237 /* redraw micro level label, if needed */
2238 if (!strEqual(level.name, NAMELESS_LEVEL_NAME) &&
2239 !strEqual(level.author, ANONYMOUS_NAME) &&
2240 !strEqual(level.author, leveldir_current->name) &&
2241 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
2243 int max_label_counter = 23;
2245 if (leveldir_current->imported_from != NULL &&
2246 strlen(leveldir_current->imported_from) > 0)
2247 max_label_counter += 14;
2248 if (leveldir_current->imported_by != NULL &&
2249 strlen(leveldir_current->imported_by) > 0)
2250 max_label_counter += 14;
2252 label_counter = (label_counter + 1) % max_label_counter;
2253 label_state = (label_counter >= 0 && label_counter <= 7 ?
2254 MICROLABEL_LEVEL_NAME :
2255 label_counter >= 9 && label_counter <= 12 ?
2256 MICROLABEL_LEVEL_AUTHOR_HEAD :
2257 label_counter >= 14 && label_counter <= 21 ?
2258 MICROLABEL_LEVEL_AUTHOR :
2259 label_counter >= 23 && label_counter <= 26 ?
2260 MICROLABEL_IMPORTED_FROM_HEAD :
2261 label_counter >= 28 && label_counter <= 35 ?
2262 MICROLABEL_IMPORTED_FROM :
2263 label_counter >= 37 && label_counter <= 40 ?
2264 MICROLABEL_IMPORTED_BY_HEAD :
2265 label_counter >= 42 && label_counter <= 49 ?
2266 MICROLABEL_IMPORTED_BY : MICROLABEL_EMPTY);
2268 if (leveldir_current->imported_from == NULL &&
2269 (label_state == MICROLABEL_IMPORTED_FROM_HEAD ||
2270 label_state == MICROLABEL_IMPORTED_FROM))
2271 label_state = (label_state == MICROLABEL_IMPORTED_FROM_HEAD ?
2272 MICROLABEL_IMPORTED_BY_HEAD : MICROLABEL_IMPORTED_BY);
2274 DrawPreviewLevelLabelExt(label_state);
2277 game_status = last_game_status; /* restore current game status */
2280 inline void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
2281 int graphic, int sync_frame, int mask_mode)
2283 int frame = getGraphicAnimationFrame(graphic, sync_frame);
2285 if (mask_mode == USE_MASKING)
2286 DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
2288 DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
2291 inline void DrawGraphicAnimation(int x, int y, int graphic)
2293 int lx = LEVELX(x), ly = LEVELY(y);
2295 if (!IN_SCR_FIELD(x, y))
2298 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
2299 graphic, GfxFrame[lx][ly], NO_MASKING);
2300 MarkTileDirty(x, y);
2303 void DrawLevelGraphicAnimation(int x, int y, int graphic)
2305 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
2308 void DrawLevelElementAnimation(int x, int y, int element)
2310 int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
2312 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
2315 inline void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
2317 int sx = SCREENX(x), sy = SCREENY(y);
2319 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
2322 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
2325 DrawGraphicAnimation(sx, sy, graphic);
2328 if (GFX_CRUMBLED(TILE_GFX_ELEMENT(x, y)))
2329 DrawLevelFieldCrumbledSand(x, y);
2331 if (GFX_CRUMBLED(Feld[x][y]))
2332 DrawLevelFieldCrumbledSand(x, y);
2336 void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
2338 int sx = SCREENX(x), sy = SCREENY(y);
2341 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
2344 graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
2346 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
2349 DrawGraphicAnimation(sx, sy, graphic);
2351 if (GFX_CRUMBLED(element))
2352 DrawLevelFieldCrumbledSand(x, y);
2355 static int getPlayerGraphic(struct PlayerInfo *player, int move_dir)
2357 if (player->use_murphy)
2359 /* this works only because currently only one player can be "murphy" ... */
2360 static int last_horizontal_dir = MV_LEFT;
2361 int graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir);
2363 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
2364 last_horizontal_dir = move_dir;
2366 if (graphic == IMG_SP_MURPHY) /* undefined => use special graphic */
2368 int direction = (player->is_snapping ? move_dir : last_horizontal_dir);
2370 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
2376 return el_act_dir2img(player->artwork_element, player->GfxAction,move_dir);
2379 static boolean equalGraphics(int graphic1, int graphic2)
2381 struct GraphicInfo *g1 = &graphic_info[graphic1];
2382 struct GraphicInfo *g2 = &graphic_info[graphic2];
2384 return (g1->bitmap == g2->bitmap &&
2385 g1->src_x == g2->src_x &&
2386 g1->src_y == g2->src_y &&
2387 g1->anim_frames == g2->anim_frames &&
2388 g1->anim_delay == g2->anim_delay &&
2389 g1->anim_mode == g2->anim_mode);
2392 void DrawAllPlayers()
2396 for (i = 0; i < MAX_PLAYERS; i++)
2397 if (stored_player[i].active)
2398 DrawPlayer(&stored_player[i]);
2401 void DrawPlayerField(int x, int y)
2403 if (!IS_PLAYER(x, y))
2406 DrawPlayer(PLAYERINFO(x, y));
2409 void DrawPlayer(struct PlayerInfo *player)
2411 int jx = player->jx;
2412 int jy = player->jy;
2413 int move_dir = player->MovDir;
2414 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? +1 : 0);
2415 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? +1 : 0);
2416 int last_jx = (player->is_moving ? jx - dx : jx);
2417 int last_jy = (player->is_moving ? jy - dy : jy);
2418 int next_jx = jx + dx;
2419 int next_jy = jy + dy;
2420 boolean player_is_moving = (player->MovPos ? TRUE : FALSE);
2421 boolean player_is_opaque = FALSE;
2422 int sx = SCREENX(jx), sy = SCREENY(jy);
2423 int sxx = 0, syy = 0;
2424 int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
2426 int action = ACTION_DEFAULT;
2427 int last_player_graphic = getPlayerGraphic(player, move_dir);
2428 int last_player_frame = player->Frame;
2431 /* GfxElement[][] is set to the element the player is digging or collecting;
2432 remove also for off-screen player if the player is not moving anymore */
2433 if (IN_LEV_FIELD(jx, jy) && !player_is_moving)
2434 GfxElement[jx][jy] = EL_UNDEFINED;
2436 if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
2440 if (!IN_LEV_FIELD(jx, jy))
2442 printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
2443 printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
2444 printf("DrawPlayerField(): This should never happen!\n");
2449 if (element == EL_EXPLOSION)
2452 action = (player->is_pushing ? ACTION_PUSHING :
2453 player->is_digging ? ACTION_DIGGING :
2454 player->is_collecting ? ACTION_COLLECTING :
2455 player->is_moving ? ACTION_MOVING :
2456 player->is_snapping ? ACTION_SNAPPING :
2457 player->is_dropping ? ACTION_DROPPING :
2458 player->is_waiting ? player->action_waiting : ACTION_DEFAULT);
2460 if (player->is_waiting)
2461 move_dir = player->dir_waiting;
2463 InitPlayerGfxAnimation(player, action, move_dir);
2465 /* ----------------------------------------------------------------------- */
2466 /* draw things in the field the player is leaving, if needed */
2467 /* ----------------------------------------------------------------------- */
2469 if (player->is_moving)
2471 if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
2473 DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
2475 if (last_element == EL_DYNAMITE_ACTIVE ||
2476 last_element == EL_EM_DYNAMITE_ACTIVE ||
2477 last_element == EL_SP_DISK_RED_ACTIVE)
2478 DrawDynamite(last_jx, last_jy);
2480 DrawLevelFieldThruMask(last_jx, last_jy);
2482 else if (last_element == EL_DYNAMITE_ACTIVE ||
2483 last_element == EL_EM_DYNAMITE_ACTIVE ||
2484 last_element == EL_SP_DISK_RED_ACTIVE)
2485 DrawDynamite(last_jx, last_jy);
2487 /* !!! this is not enough to prevent flickering of players which are
2488 moving next to each others without a free tile between them -- this
2489 can only be solved by drawing all players layer by layer (first the
2490 background, then the foreground etc.) !!! => TODO */
2491 else if (!IS_PLAYER(last_jx, last_jy))
2492 DrawLevelField(last_jx, last_jy);
2495 DrawLevelField(last_jx, last_jy);
2498 if (player->is_pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
2499 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
2502 if (!IN_SCR_FIELD(sx, sy))
2505 if (setup.direct_draw)
2506 SetDrawtoField(DRAW_BUFFERED);
2508 /* ----------------------------------------------------------------------- */
2509 /* draw things behind the player, if needed */
2510 /* ----------------------------------------------------------------------- */
2513 DrawLevelElement(jx, jy, Back[jx][jy]);
2514 else if (IS_ACTIVE_BOMB(element))
2515 DrawLevelElement(jx, jy, EL_EMPTY);
2518 if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
2520 int old_element = GfxElement[jx][jy];
2521 int old_graphic = el_act_dir2img(old_element, action, move_dir);
2522 int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
2524 if (GFX_CRUMBLED(old_element))
2525 DrawLevelFieldCrumbledSandDigging(jx, jy, move_dir, player->StepFrame);
2527 DrawGraphic(sx, sy, old_graphic, frame);
2529 if (graphic_info[old_graphic].anim_mode & ANIM_OPAQUE_PLAYER)
2530 player_is_opaque = TRUE;
2534 GfxElement[jx][jy] = EL_UNDEFINED;
2536 /* make sure that pushed elements are drawn with correct frame rate */
2538 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
2540 if (player->is_pushing && player->is_moving && !IS_ANIM_MODE_CE(graphic))
2541 GfxFrame[jx][jy] = player->StepFrame;
2543 if (player->is_pushing && player->is_moving)
2544 GfxFrame[jx][jy] = player->StepFrame;
2547 DrawLevelField(jx, jy);
2551 /* ----------------------------------------------------------------------- */
2552 /* draw player himself */
2553 /* ----------------------------------------------------------------------- */
2555 graphic = getPlayerGraphic(player, move_dir);
2557 /* in the case of changed player action or direction, prevent the current
2558 animation frame from being restarted for identical animations */
2559 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
2560 player->Frame = last_player_frame;
2562 frame = getGraphicAnimationFrame(graphic, player->Frame);
2566 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
2567 sxx = player->GfxPos;
2569 syy = player->GfxPos;
2572 if (!setup.soft_scrolling && ScreenMovPos)
2575 if (player_is_opaque)
2576 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
2578 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
2580 if (SHIELD_ON(player))
2582 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
2583 IMG_SHIELD_NORMAL_ACTIVE);
2584 int frame = getGraphicAnimationFrame(graphic, -1);
2586 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
2589 /* ----------------------------------------------------------------------- */
2590 /* draw things the player is pushing, if needed */
2591 /* ----------------------------------------------------------------------- */
2594 printf("::: %d, %d [%d, %d] [%d]\n",
2595 player->is_pushing, player_is_moving, player->GfxAction,
2596 player->is_moving, player_is_moving);
2600 if (player->is_pushing && player->is_moving)
2602 int px = SCREENX(jx), py = SCREENY(jy);
2603 int pxx = (TILEX - ABS(sxx)) * dx;
2604 int pyy = (TILEY - ABS(syy)) * dy;
2605 int gfx_frame = GfxFrame[jx][jy];
2611 if (!IS_MOVING(jx, jy)) /* push movement already finished */
2613 element = Feld[next_jx][next_jy];
2614 gfx_frame = GfxFrame[next_jx][next_jy];
2617 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
2620 sync_frame = (IS_ANIM_MODE_CE(graphic) ? gfx_frame : player->StepFrame);
2621 frame = getGraphicAnimationFrame(graphic, sync_frame);
2623 frame = getGraphicAnimationFrame(graphic, player->StepFrame);
2626 /* draw background element under pushed element (like the Sokoban field) */
2627 if (Back[next_jx][next_jy])
2628 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
2630 /* masked drawing is needed for EMC style (double) movement graphics */
2631 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
2635 /* ----------------------------------------------------------------------- */
2636 /* draw things in front of player (active dynamite or dynabombs) */
2637 /* ----------------------------------------------------------------------- */
2639 if (IS_ACTIVE_BOMB(element))
2641 graphic = el2img(element);
2642 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
2644 if (game.emulation == EMU_SUPAPLEX)
2645 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
2647 DrawGraphicThruMask(sx, sy, graphic, frame);
2650 if (player_is_moving && last_element == EL_EXPLOSION)
2652 int element = (GfxElement[last_jx][last_jy] != EL_UNDEFINED ?
2653 GfxElement[last_jx][last_jy] : EL_EMPTY);
2654 int graphic = el_act2img(element, ACTION_EXPLODING);
2655 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
2656 int phase = ExplodePhase[last_jx][last_jy] - 1;
2657 int frame = getGraphicAnimationFrame(graphic, phase - delay);
2660 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
2663 /* ----------------------------------------------------------------------- */
2664 /* draw elements the player is just walking/passing through/under */
2665 /* ----------------------------------------------------------------------- */
2667 if (player_is_moving)
2669 /* handle the field the player is leaving ... */
2670 if (IS_ACCESSIBLE_INSIDE(last_element))
2671 DrawLevelField(last_jx, last_jy);
2672 else if (IS_ACCESSIBLE_UNDER(last_element))
2673 DrawLevelFieldThruMask(last_jx, last_jy);
2676 /* do not redraw accessible elements if the player is just pushing them */
2677 if (!player_is_moving || !player->is_pushing)
2679 /* ... and the field the player is entering */
2680 if (IS_ACCESSIBLE_INSIDE(element))
2681 DrawLevelField(jx, jy);
2682 else if (IS_ACCESSIBLE_UNDER(element))
2683 DrawLevelFieldThruMask(jx, jy);
2686 if (setup.direct_draw)
2688 int dst_x = SX + SCREENX(MIN(jx, last_jx)) * TILEX;
2689 int dst_y = SY + SCREENY(MIN(jy, last_jy)) * TILEY;
2690 int x_size = TILEX * (1 + ABS(jx - last_jx));
2691 int y_size = TILEY * (1 + ABS(jy - last_jy));
2693 BlitBitmap(drawto_field, window,
2694 dst_x, dst_y, x_size, y_size, dst_x, dst_y);
2695 SetDrawtoField(DRAW_DIRECT);
2698 MarkTileDirty(sx, sy);
2701 /* ------------------------------------------------------------------------- */
2703 void WaitForEventToContinue()
2705 boolean still_wait = TRUE;
2707 /* simulate releasing mouse button over last gadget, if still pressed */
2709 HandleGadgets(-1, -1, 0);
2711 button_status = MB_RELEASED;
2727 case EVENT_BUTTONPRESS:
2728 case EVENT_KEYPRESS:
2732 case EVENT_KEYRELEASE:
2733 ClearPlayerAction();
2737 HandleOtherEvents(&event);
2741 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2748 /* don't eat all CPU time */
2753 #define MAX_REQUEST_LINES 13
2754 #define MAX_REQUEST_LINE_FONT1_LEN 7
2755 #define MAX_REQUEST_LINE_FONT2_LEN 10
2757 boolean Request(char *text, unsigned int req_state)
2759 int mx, my, ty, result = -1;
2760 unsigned int old_door_state;
2761 int last_game_status = game_status; /* save current game status */
2762 int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
2763 int font_nr = FONT_TEXT_2;
2764 int max_word_len = 0;
2767 for (text_ptr = text; *text_ptr; text_ptr++)
2769 max_word_len = (*text_ptr != ' ' ? max_word_len + 1 : 0);
2771 if (max_word_len > MAX_REQUEST_LINE_FONT1_LEN)
2773 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
2775 font_nr = FONT_TEXT_1;
2777 font_nr = FONT_LEVEL_NUMBER;
2784 if (game_status == GAME_MODE_PLAYING &&
2785 level.game_engine_type == GAME_ENGINE_TYPE_EM)
2786 BlitScreenToBitmap_EM(backbuffer);
2788 /* disable deactivated drawing when quick-loading level tape recording */
2789 if (tape.playing && tape.deactivate_display)
2790 TapeDeactivateDisplayOff(TRUE);
2792 SetMouseCursor(CURSOR_DEFAULT);
2794 #if defined(NETWORK_AVALIABLE)
2795 /* pause network game while waiting for request to answer */
2796 if (options.network &&
2797 game_status == GAME_MODE_PLAYING &&
2798 req_state & REQUEST_WAIT_FOR_INPUT)
2799 SendToServer_PausePlaying();
2802 old_door_state = GetDoorState();
2804 /* simulate releasing mouse button over last gadget, if still pressed */
2806 HandleGadgets(-1, -1, 0);
2810 if (old_door_state & DOOR_OPEN_1)
2812 CloseDoor(DOOR_CLOSE_1);
2814 /* save old door content */
2815 BlitBitmap(bitmap_db_door, bitmap_db_door,
2816 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
2817 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
2821 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
2824 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2826 /* clear door drawing field */
2827 DrawBackground(DX, DY, DXSIZE, DYSIZE);
2829 /* force DOOR font inside door area */
2830 game_status = GAME_MODE_PSEUDO_DOOR;
2832 /* write text for request */
2833 for (ty = 0; ty < MAX_REQUEST_LINES; ty++)
2835 char text_line[max_request_line_len + 1];
2841 for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
2844 if (!tc || tc == ' ')
2855 strncpy(text_line, text, tl);
2858 DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
2859 DY + 8 + ty * (getFontHeight(font_nr) + 2),
2860 text_line, font_nr);
2862 text += tl + (tc == ' ' ? 1 : 0);
2865 game_status = last_game_status; /* restore current game status */
2867 if (req_state & REQ_ASK)
2869 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
2870 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
2872 else if (req_state & REQ_CONFIRM)
2874 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
2876 else if (req_state & REQ_PLAYER)
2878 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
2879 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
2880 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
2881 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
2884 /* copy request gadgets to door backbuffer */
2885 BlitBitmap(drawto, bitmap_db_door,
2886 DX, DY, DXSIZE, DYSIZE,
2887 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2889 OpenDoor(DOOR_OPEN_1);
2891 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
2893 if (game_status == GAME_MODE_PLAYING)
2895 SetPanelBackground();
2896 SetDrawBackgroundMask(REDRAW_DOOR_1);
2900 SetDrawBackgroundMask(REDRAW_FIELD);
2906 if (game_status != GAME_MODE_MAIN)
2909 button_status = MB_RELEASED;
2911 request_gadget_id = -1;
2913 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2925 case EVENT_BUTTONPRESS:
2926 case EVENT_BUTTONRELEASE:
2927 case EVENT_MOTIONNOTIFY:
2929 if (event.type == EVENT_MOTIONNOTIFY)
2931 if (!PointerInWindow(window))
2932 continue; /* window and pointer are on different screens */
2937 motion_status = TRUE;
2938 mx = ((MotionEvent *) &event)->x;
2939 my = ((MotionEvent *) &event)->y;
2943 motion_status = FALSE;
2944 mx = ((ButtonEvent *) &event)->x;
2945 my = ((ButtonEvent *) &event)->y;
2946 if (event.type == EVENT_BUTTONPRESS)
2947 button_status = ((ButtonEvent *) &event)->button;
2949 button_status = MB_RELEASED;
2952 /* this sets 'request_gadget_id' */
2953 HandleGadgets(mx, my, button_status);
2955 switch (request_gadget_id)
2957 case TOOL_CTRL_ID_YES:
2960 case TOOL_CTRL_ID_NO:
2963 case TOOL_CTRL_ID_CONFIRM:
2964 result = TRUE | FALSE;
2967 case TOOL_CTRL_ID_PLAYER_1:
2970 case TOOL_CTRL_ID_PLAYER_2:
2973 case TOOL_CTRL_ID_PLAYER_3:
2976 case TOOL_CTRL_ID_PLAYER_4:
2987 case EVENT_KEYPRESS:
2988 switch (GetEventKey((KeyEvent *)&event, TRUE))
2991 if (req_state & REQ_CONFIRM)
3007 if (req_state & REQ_PLAYER)
3011 case EVENT_KEYRELEASE:
3012 ClearPlayerAction();
3016 HandleOtherEvents(&event);
3020 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
3022 int joy = AnyJoystick();
3024 if (joy & JOY_BUTTON_1)
3026 else if (joy & JOY_BUTTON_2)
3032 if (game_status == GAME_MODE_PLAYING && local_player->LevelSolved_GameEnd)
3034 HandleGameActions();
3040 if (!PendingEvent()) /* delay only if no pending events */
3051 if (!PendingEvent()) /* delay only if no pending events */
3054 /* don't eat all CPU time */
3061 if (game_status != GAME_MODE_MAIN)
3066 if (!(req_state & REQ_STAY_OPEN))
3068 CloseDoor(DOOR_CLOSE_1);
3070 if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
3071 (req_state & REQ_REOPEN))
3072 OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
3077 if (game_status == GAME_MODE_PLAYING)
3079 SetPanelBackground();
3080 SetDrawBackgroundMask(REDRAW_DOOR_1);
3084 SetDrawBackgroundMask(REDRAW_FIELD);
3087 #if defined(NETWORK_AVALIABLE)
3088 /* continue network game after request */
3089 if (options.network &&
3090 game_status == GAME_MODE_PLAYING &&
3091 req_state & REQUEST_WAIT_FOR_INPUT)
3092 SendToServer_ContinuePlaying();
3095 /* restore deactivated drawing when quick-loading level tape recording */
3096 if (tape.playing && tape.deactivate_display)
3097 TapeDeactivateDisplayOn();
3102 unsigned int OpenDoor(unsigned int door_state)
3104 if (door_state & DOOR_COPY_BACK)
3106 if (door_state & DOOR_OPEN_1)
3107 BlitBitmap(bitmap_db_door, bitmap_db_door,
3108 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
3109 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
3111 if (door_state & DOOR_OPEN_2)
3112 BlitBitmap(bitmap_db_door, bitmap_db_door,
3113 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY2, VXSIZE, VYSIZE,
3114 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
3116 door_state &= ~DOOR_COPY_BACK;
3119 return MoveDoor(door_state);
3122 unsigned int CloseDoor(unsigned int door_state)
3124 unsigned int old_door_state = GetDoorState();
3126 if (!(door_state & DOOR_NO_COPY_BACK))
3128 if (old_door_state & DOOR_OPEN_1)
3129 BlitBitmap(backbuffer, bitmap_db_door,
3130 DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
3132 if (old_door_state & DOOR_OPEN_2)
3133 BlitBitmap(backbuffer, bitmap_db_door,
3134 VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
3136 door_state &= ~DOOR_NO_COPY_BACK;
3139 return MoveDoor(door_state);
3142 unsigned int GetDoorState()
3144 return MoveDoor(DOOR_GET_STATE);
3147 unsigned int SetDoorState(unsigned int door_state)
3149 return MoveDoor(door_state | DOOR_SET_STATE);
3152 unsigned int MoveDoor(unsigned int door_state)
3154 static int door1 = DOOR_OPEN_1;
3155 static int door2 = DOOR_CLOSE_2;
3156 unsigned long door_delay = 0;
3157 unsigned long door_delay_value;
3160 if (door_1.width < 0 || door_1.width > DXSIZE)
3161 door_1.width = DXSIZE;
3162 if (door_1.height < 0 || door_1.height > DYSIZE)
3163 door_1.height = DYSIZE;
3164 if (door_2.width < 0 || door_2.width > VXSIZE)
3165 door_2.width = VXSIZE;
3166 if (door_2.height < 0 || door_2.height > VYSIZE)
3167 door_2.height = VYSIZE;
3169 if (door_state == DOOR_GET_STATE)
3170 return (door1 | door2);
3172 if (door_state & DOOR_SET_STATE)
3174 if (door_state & DOOR_ACTION_1)
3175 door1 = door_state & DOOR_ACTION_1;
3176 if (door_state & DOOR_ACTION_2)
3177 door2 = door_state & DOOR_ACTION_2;
3179 return (door1 | door2);
3182 if (!(door_state & DOOR_FORCE_REDRAW))
3184 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
3185 door_state &= ~DOOR_OPEN_1;
3186 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
3187 door_state &= ~DOOR_CLOSE_1;
3188 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
3189 door_state &= ~DOOR_OPEN_2;
3190 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
3191 door_state &= ~DOOR_CLOSE_2;
3194 door_delay_value = (door_state & DOOR_ACTION_1 ? door_1.step_delay :
3197 if (setup.quick_doors)
3199 stepsize = 20; /* must be chosen to always draw last frame */
3200 door_delay_value = 0;
3203 if (global.autoplay_leveldir)
3205 door_state |= DOOR_NO_DELAY;
3206 door_state &= ~DOOR_CLOSE_ALL;
3209 if (door_state & DOOR_ACTION)
3211 boolean handle_door_1 = (door_state & DOOR_ACTION_1);
3212 boolean handle_door_2 = (door_state & DOOR_ACTION_2);
3213 boolean door_1_done = (!handle_door_1);
3214 boolean door_2_done = (!handle_door_2);
3215 boolean door_1_vertical = (door_1.anim_mode & ANIM_VERTICAL);
3216 boolean door_2_vertical = (door_2.anim_mode & ANIM_VERTICAL);
3217 int door_size_1 = (door_1_vertical ? door_1.height : door_1.width);
3218 int door_size_2 = (door_2_vertical ? door_2.height : door_2.width);
3219 int max_door_size_1 = (door_1_vertical ? DYSIZE : DXSIZE);
3220 int max_door_size_2 = (door_2_vertical ? VYSIZE : VXSIZE);
3221 int door_size = (handle_door_1 ? door_size_1 : door_size_2);
3222 int max_door_size = (handle_door_1 ? max_door_size_1 : max_door_size_2);
3223 int door_skip = max_door_size - door_size;
3224 int end = door_size;
3225 int start = ((door_state & DOOR_NO_DELAY) ? end : 0);
3228 if (!(door_state & DOOR_NO_DELAY) && !setup.quick_doors)
3230 /* opening door sound has priority over simultaneously closing door */
3231 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
3232 PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
3233 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
3234 PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
3237 for (k = start; k <= end && !(door_1_done && door_2_done); k += stepsize)
3240 Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
3241 GC gc = bitmap->stored_clip_gc;
3243 if (door_state & DOOR_ACTION_1)
3245 int a = MIN(x * door_1.step_offset, end);
3246 int p = (door_state & DOOR_OPEN_1 ? end - a : a);
3247 int i = p + door_skip;
3249 if (door_1.anim_mode & ANIM_STATIC_PANEL)
3251 BlitBitmap(bitmap_db_door, drawto,
3252 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1,
3253 DXSIZE, DYSIZE, DX, DY);
3257 BlitBitmap(bitmap_db_door, drawto,
3258 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + p / 2,
3259 DXSIZE, DYSIZE - p / 2, DX, DY);
3261 ClearRectangle(drawto, DX, DY + DYSIZE - p / 2, DXSIZE, p / 2);
3264 if (door_1.anim_mode & ANIM_HORIZONTAL && x <= DXSIZE)
3266 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
3267 int dst1_x = DX + DXSIZE - i, dst1_y = DY;
3268 int src2_x = DXSIZE - i, src2_y = DOOR_GFX_PAGEY1;
3269 int dst2_x = DX, dst2_y = DY;
3270 int width = i, height = DYSIZE;
3272 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3273 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3276 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3277 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3280 else if (door_1.anim_mode & ANIM_VERTICAL && x <= DYSIZE)
3282 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
3283 int dst1_x = DX, dst1_y = DY + DYSIZE - i;
3284 int src2_x = 0, src2_y = DOOR_GFX_PAGEY1 + DYSIZE - i;
3285 int dst2_x = DX, dst2_y = DY;
3286 int width = DXSIZE, height = i;
3288 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3289 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3292 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3293 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3296 else if (x <= DXSIZE) /* ANIM_DEFAULT */
3298 int j = (door_1.anim_mode == ANIM_DEFAULT ? (DXSIZE - i) / 3 : 0);
3300 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
3301 BlitBitmapMasked(bitmap, drawto,
3302 DXSIZE, DOOR_GFX_PAGEY1, i, 77,
3303 DX + DXSIZE - i, DY + j);
3304 BlitBitmapMasked(bitmap, drawto,
3305 DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
3306 DX + DXSIZE - i, DY + 140 + j);
3307 SetClipOrigin(bitmap, gc, DX - DXSIZE + i,
3308 DY - (DOOR_GFX_PAGEY1 + j));
3309 BlitBitmapMasked(bitmap, drawto,
3310 DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
3312 BlitBitmapMasked(bitmap, drawto,
3313 DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
3316 BlitBitmapMasked(bitmap, drawto,
3317 DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
3319 BlitBitmapMasked(bitmap, drawto,
3320 DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
3322 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
3323 BlitBitmapMasked(bitmap, drawto,
3324 DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
3325 DX + DXSIZE - i, DY + 77 + j);
3326 BlitBitmapMasked(bitmap, drawto,
3327 DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
3328 DX + DXSIZE - i, DY + 203 + j);
3331 redraw_mask |= REDRAW_DOOR_1;
3332 door_1_done = (a == end);
3335 if (door_state & DOOR_ACTION_2)
3337 int a = MIN(x * door_2.step_offset, door_size);
3338 int p = (door_state & DOOR_OPEN_2 ? door_size - a : a);
3339 int i = p + door_skip;
3341 if (door_2.anim_mode & ANIM_STATIC_PANEL)
3343 BlitBitmap(bitmap_db_door, drawto,
3344 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2,
3345 VXSIZE, VYSIZE, VX, VY);
3347 else if (x <= VYSIZE)
3349 BlitBitmap(bitmap_db_door, drawto,
3350 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + p / 2,
3351 VXSIZE, VYSIZE - p / 2, VX, VY);
3353 ClearRectangle(drawto, VX, VY + VYSIZE - p / 2, VXSIZE, p / 2);
3356 if (door_2.anim_mode & ANIM_HORIZONTAL && x <= VXSIZE)
3358 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
3359 int dst1_x = VX + VXSIZE - i, dst1_y = VY;
3360 int src2_x = VXSIZE - i, src2_y = DOOR_GFX_PAGEY2;
3361 int dst2_x = VX, dst2_y = VY;
3362 int width = i, height = VYSIZE;
3364 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3365 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3368 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3369 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3372 else if (door_2.anim_mode & ANIM_VERTICAL && x <= VYSIZE)
3374 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
3375 int dst1_x = VX, dst1_y = VY + VYSIZE - i;
3376 int src2_x = 0, src2_y = DOOR_GFX_PAGEY2 + VYSIZE - i;
3377 int dst2_x = VX, dst2_y = VY;
3378 int width = VXSIZE, height = i;
3380 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3381 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3384 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3385 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3388 else if (x <= VXSIZE) /* ANIM_DEFAULT */
3390 int j = (door_2.anim_mode == ANIM_DEFAULT ? (VXSIZE - i) / 3 : 0);
3392 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
3393 BlitBitmapMasked(bitmap, drawto,
3394 VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
3395 VX + VXSIZE - i, VY + j);
3396 SetClipOrigin(bitmap, gc,
3397 VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
3398 BlitBitmapMasked(bitmap, drawto,
3399 VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
3402 BlitBitmapMasked(bitmap, drawto,
3403 VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
3404 i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
3405 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
3406 BlitBitmapMasked(bitmap, drawto,
3407 VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
3409 VX + VXSIZE - i, VY + VYSIZE / 2 + j);
3412 redraw_mask |= REDRAW_DOOR_2;
3413 door_2_done = (a == VXSIZE);
3416 if (!(door_state & DOOR_NO_DELAY))
3420 if (game_status == GAME_MODE_MAIN)
3423 WaitUntilDelayReached(&door_delay, door_delay_value);
3428 if (door_state & DOOR_ACTION_1)
3429 door1 = door_state & DOOR_ACTION_1;
3430 if (door_state & DOOR_ACTION_2)
3431 door2 = door_state & DOOR_ACTION_2;
3433 return (door1 | door2);
3436 void DrawSpecialEditorDoor()
3438 /* draw bigger toolbox window */
3439 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
3440 DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
3442 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
3443 EX - 6, VY - 4, EXSIZE + 12, EYSIZE - VYSIZE + 4,
3446 redraw_mask |= REDRAW_ALL;
3449 void UndrawSpecialEditorDoor()
3451 /* draw normal tape recorder window */
3452 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
3453 EX - 6, EY - 12, EXSIZE + 12, EYSIZE - VYSIZE + 12,
3456 redraw_mask |= REDRAW_ALL;
3460 /* ---------- new tool button stuff ---------------------------------------- */
3462 /* graphic position values for tool buttons */
3463 #define TOOL_BUTTON_YES_XPOS 2
3464 #define TOOL_BUTTON_YES_YPOS 250
3465 #define TOOL_BUTTON_YES_GFX_YPOS 0
3466 #define TOOL_BUTTON_YES_XSIZE 46
3467 #define TOOL_BUTTON_YES_YSIZE 28
3468 #define TOOL_BUTTON_NO_XPOS 52
3469 #define TOOL_BUTTON_NO_YPOS TOOL_BUTTON_YES_YPOS
3470 #define TOOL_BUTTON_NO_GFX_YPOS TOOL_BUTTON_YES_GFX_YPOS
3471 #define TOOL_BUTTON_NO_XSIZE TOOL_BUTTON_YES_XSIZE
3472 #define TOOL_BUTTON_NO_YSIZE TOOL_BUTTON_YES_YSIZE
3473 #define TOOL_BUTTON_CONFIRM_XPOS TOOL_BUTTON_YES_XPOS
3474 #define TOOL_BUTTON_CONFIRM_YPOS TOOL_BUTTON_YES_YPOS
3475 #define TOOL_BUTTON_CONFIRM_GFX_YPOS 30
3476 #define TOOL_BUTTON_CONFIRM_XSIZE 96
3477 #define TOOL_BUTTON_CONFIRM_YSIZE TOOL_BUTTON_YES_YSIZE
3478 #define TOOL_BUTTON_PLAYER_XSIZE 30
3479 #define TOOL_BUTTON_PLAYER_YSIZE 30
3480 #define TOOL_BUTTON_PLAYER_GFX_XPOS 5
3481 #define TOOL_BUTTON_PLAYER_GFX_YPOS 185
3482 #define TOOL_BUTTON_PLAYER_XPOS (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
3483 #define TOOL_BUTTON_PLAYER_YPOS (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
3484 #define TOOL_BUTTON_PLAYER1_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3485 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
3486 #define TOOL_BUTTON_PLAYER2_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3487 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
3488 #define TOOL_BUTTON_PLAYER3_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3489 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
3490 #define TOOL_BUTTON_PLAYER4_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3491 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
3492 #define TOOL_BUTTON_PLAYER1_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3493 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
3494 #define TOOL_BUTTON_PLAYER2_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3495 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
3496 #define TOOL_BUTTON_PLAYER3_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3497 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
3498 #define TOOL_BUTTON_PLAYER4_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3499 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
3508 } toolbutton_info[NUM_TOOL_BUTTONS] =
3511 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_GFX_YPOS,
3512 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_YPOS,
3513 TOOL_BUTTON_YES_XSIZE, TOOL_BUTTON_YES_YSIZE,
3518 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_GFX_YPOS,
3519 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_YPOS,
3520 TOOL_BUTTON_NO_XSIZE, TOOL_BUTTON_NO_YSIZE,
3525 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_GFX_YPOS,
3526 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_YPOS,
3527 TOOL_BUTTON_CONFIRM_XSIZE, TOOL_BUTTON_CONFIRM_YSIZE,
3528 TOOL_CTRL_ID_CONFIRM,
3532 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3533 TOOL_BUTTON_PLAYER1_XPOS, TOOL_BUTTON_PLAYER1_YPOS,
3534 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3535 TOOL_CTRL_ID_PLAYER_1,
3539 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3540 TOOL_BUTTON_PLAYER2_XPOS, TOOL_BUTTON_PLAYER2_YPOS,
3541 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3542 TOOL_CTRL_ID_PLAYER_2,
3546 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3547 TOOL_BUTTON_PLAYER3_XPOS, TOOL_BUTTON_PLAYER3_YPOS,
3548 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3549 TOOL_CTRL_ID_PLAYER_3,
3553 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3554 TOOL_BUTTON_PLAYER4_XPOS, TOOL_BUTTON_PLAYER4_YPOS,
3555 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3556 TOOL_CTRL_ID_PLAYER_4,
3561 void CreateToolButtons()
3565 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3567 Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
3568 Bitmap *deco_bitmap = None;
3569 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
3570 struct GadgetInfo *gi;
3571 unsigned long event_mask;
3572 int gd_xoffset, gd_yoffset;
3573 int gd_x1, gd_x2, gd_y;
3576 event_mask = GD_EVENT_RELEASED;
3578 gd_xoffset = toolbutton_info[i].xpos;
3579 gd_yoffset = toolbutton_info[i].ypos;
3580 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
3581 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
3582 gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
3584 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
3586 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
3588 getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr),
3589 &deco_bitmap, &deco_x, &deco_y);
3590 deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
3591 deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
3594 gi = CreateGadget(GDI_CUSTOM_ID, id,
3595 GDI_INFO_TEXT, toolbutton_info[i].infotext,
3596 GDI_X, DX + toolbutton_info[i].x,
3597 GDI_Y, DY + toolbutton_info[i].y,
3598 GDI_WIDTH, toolbutton_info[i].width,
3599 GDI_HEIGHT, toolbutton_info[i].height,
3600 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
3601 GDI_STATE, GD_BUTTON_UNPRESSED,
3602 GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
3603 GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
3604 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
3605 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
3606 GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
3607 GDI_DECORATION_SHIFTING, 1, 1,
3608 GDI_DIRECT_DRAW, FALSE,
3609 GDI_EVENT_MASK, event_mask,
3610 GDI_CALLBACK_ACTION, HandleToolButtons,
3614 Error(ERR_EXIT, "cannot create gadget");
3616 tool_gadget[id] = gi;
3620 void FreeToolButtons()
3624 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3625 FreeGadget(tool_gadget[i]);
3628 static void UnmapToolButtons()
3632 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3633 UnmapGadget(tool_gadget[i]);
3636 static void HandleToolButtons(struct GadgetInfo *gi)
3638 request_gadget_id = gi->custom_id;
3641 static struct Mapping_EM_to_RND_object
3644 boolean is_rnd_to_em_mapping; /* unique mapping EM <-> RND */
3645 boolean is_backside; /* backside of moving element */
3651 em_object_mapping_list[] =
3654 Xblank, TRUE, FALSE,
3658 Yacid_splash_eB, FALSE, FALSE,
3659 EL_ACID_SPLASH_RIGHT, -1, -1
3662 Yacid_splash_wB, FALSE, FALSE,
3663 EL_ACID_SPLASH_LEFT, -1, -1
3666 #ifdef EM_ENGINE_BAD_ROLL
3668 Xstone_force_e, FALSE, FALSE,
3669 EL_ROCK, -1, MV_BIT_RIGHT
3672 Xstone_force_w, FALSE, FALSE,
3673 EL_ROCK, -1, MV_BIT_LEFT
3676 Xnut_force_e, FALSE, FALSE,
3677 EL_NUT, -1, MV_BIT_RIGHT
3680 Xnut_force_w, FALSE, FALSE,
3681 EL_NUT, -1, MV_BIT_LEFT
3684 Xspring_force_e, FALSE, FALSE,
3685 EL_SPRING, -1, MV_BIT_RIGHT
3688 Xspring_force_w, FALSE, FALSE,
3689 EL_SPRING, -1, MV_BIT_LEFT
3692 Xemerald_force_e, FALSE, FALSE,
3693 EL_EMERALD, -1, MV_BIT_RIGHT
3696 Xemerald_force_w, FALSE, FALSE,
3697 EL_EMERALD, -1, MV_BIT_LEFT
3700 Xdiamond_force_e, FALSE, FALSE,
3701 EL_DIAMOND, -1, MV_BIT_RIGHT
3704 Xdiamond_force_w, FALSE, FALSE,
3705 EL_DIAMOND, -1, MV_BIT_LEFT
3708 Xbomb_force_e, FALSE, FALSE,
3709 EL_BOMB, -1, MV_BIT_RIGHT
3712 Xbomb_force_w, FALSE, FALSE,
3713 EL_BOMB, -1, MV_BIT_LEFT
3715 #endif /* EM_ENGINE_BAD_ROLL */
3718 Xstone, TRUE, FALSE,
3722 Xstone_pause, FALSE, FALSE,
3726 Xstone_fall, FALSE, FALSE,
3730 Ystone_s, FALSE, FALSE,
3731 EL_ROCK, ACTION_FALLING, -1
3734 Ystone_sB, FALSE, TRUE,
3735 EL_ROCK, ACTION_FALLING, -1
3738 Ystone_e, FALSE, FALSE,
3739 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
3742 Ystone_eB, FALSE, TRUE,
3743 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
3746 Ystone_w, FALSE, FALSE,
3747 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
3750 Ystone_wB, FALSE, TRUE,
3751 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
3758 Xnut_pause, FALSE, FALSE,
3762 Xnut_fall, FALSE, FALSE,
3766 Ynut_s, FALSE, FALSE,
3767 EL_NUT, ACTION_FALLING, -1
3770 Ynut_sB, FALSE, TRUE,
3771 EL_NUT, ACTION_FALLING, -1
3774 Ynut_e, FALSE, FALSE,
3775 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
3778 Ynut_eB, FALSE, TRUE,
3779 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
3782 Ynut_w, FALSE, FALSE,
3783 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
3786 Ynut_wB, FALSE, TRUE,
3787 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
3790 Xbug_n, TRUE, FALSE,
3794 Xbug_e, TRUE, FALSE,
3795 EL_BUG_RIGHT, -1, -1
3798 Xbug_s, TRUE, FALSE,
3802 Xbug_w, TRUE, FALSE,
3806 Xbug_gon, FALSE, FALSE,
3810 Xbug_goe, FALSE, FALSE,
3811 EL_BUG_RIGHT, -1, -1
3814 Xbug_gos, FALSE, FALSE,
3818 Xbug_gow, FALSE, FALSE,
3822 Ybug_n, FALSE, FALSE,
3823 EL_BUG, ACTION_MOVING, MV_BIT_UP
3826 Ybug_nB, FALSE, TRUE,
3827 EL_BUG, ACTION_MOVING, MV_BIT_UP
3830 Ybug_e, FALSE, FALSE,
3831 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
3834 Ybug_eB, FALSE, TRUE,
3835 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
3838 Ybug_s, FALSE, FALSE,
3839 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
3842 Ybug_sB, FALSE, TRUE,
3843 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
3846 Ybug_w, FALSE, FALSE,
3847 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
3850 Ybug_wB, FALSE, TRUE,
3851 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
3854 Ybug_w_n, FALSE, FALSE,
3855 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
3858 Ybug_n_e, FALSE, FALSE,
3859 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
3862 Ybug_e_s, FALSE, FALSE,
3863 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
3866 Ybug_s_w, FALSE, FALSE,
3867 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
3870 Ybug_e_n, FALSE, FALSE,
3871 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
3874 Ybug_s_e, FALSE, FALSE,
3875 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
3878 Ybug_w_s, FALSE, FALSE,
3879 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
3882 Ybug_n_w, FALSE, FALSE,
3883 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
3886 Ybug_stone, FALSE, FALSE,
3887 EL_BUG, ACTION_SMASHED_BY_ROCK, -1
3890 Ybug_spring, FALSE, FALSE,
3891 EL_BUG, ACTION_SMASHED_BY_SPRING, -1
3894 Xtank_n, TRUE, FALSE,
3895 EL_SPACESHIP_UP, -1, -1
3898 Xtank_e, TRUE, FALSE,
3899 EL_SPACESHIP_RIGHT, -1, -1
3902 Xtank_s, TRUE, FALSE,
3903 EL_SPACESHIP_DOWN, -1, -1
3906 Xtank_w, TRUE, FALSE,
3907 EL_SPACESHIP_LEFT, -1, -1
3910 Xtank_gon, FALSE, FALSE,
3911 EL_SPACESHIP_UP, -1, -1
3914 Xtank_goe, FALSE, FALSE,
3915 EL_SPACESHIP_RIGHT, -1, -1
3918 Xtank_gos, FALSE, FALSE,
3919 EL_SPACESHIP_DOWN, -1, -1
3922 Xtank_gow, FALSE, FALSE,
3923 EL_SPACESHIP_LEFT, -1, -1
3926 Ytank_n, FALSE, FALSE,
3927 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
3930 Ytank_nB, FALSE, TRUE,
3931 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
3934 Ytank_e, FALSE, FALSE,
3935 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
3938 Ytank_eB, FALSE, TRUE,
3939 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
3942 Ytank_s, FALSE, FALSE,
3943 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
3946 Ytank_sB, FALSE, TRUE,
3947 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
3950 Ytank_w, FALSE, FALSE,
3951 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
3954 Ytank_wB, FALSE, TRUE,
3955 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
3958 Ytank_w_n, FALSE, FALSE,
3959 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
3962 Ytank_n_e, FALSE, FALSE,
3963 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
3966 Ytank_e_s, FALSE, FALSE,
3967 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
3970 Ytank_s_w, FALSE, FALSE,
3971 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
3974 Ytank_e_n, FALSE, FALSE,
3975 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
3978 Ytank_s_e, FALSE, FALSE,
3979 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
3982 Ytank_w_s, FALSE, FALSE,
3983 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
3986 Ytank_n_w, FALSE, FALSE,
3987 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
3990 Ytank_stone, FALSE, FALSE,
3991 EL_SPACESHIP, ACTION_SMASHED_BY_ROCK, -1
3994 Ytank_spring, FALSE, FALSE,
3995 EL_SPACESHIP, ACTION_SMASHED_BY_SPRING, -1
3998 Xandroid, TRUE, FALSE,
3999 EL_EMC_ANDROID, ACTION_ACTIVE, -1
4002 Xandroid_1_n, FALSE, FALSE,
4003 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
4006 Xandroid_2_n, FALSE, FALSE,
4007 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
4010 Xandroid_1_e, FALSE, FALSE,
4011 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
4014 Xandroid_2_e, FALSE, FALSE,
4015 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
4018 Xandroid_1_w, FALSE, FALSE,
4019 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
4022 Xandroid_2_w, FALSE, FALSE,
4023 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
4026 Xandroid_1_s, FALSE, FALSE,
4027 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
4030 Xandroid_2_s, FALSE, FALSE,
4031 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
4034 Yandroid_n, FALSE, FALSE,
4035 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
4038 Yandroid_nB, FALSE, TRUE,
4039 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
4042 Yandroid_ne, FALSE, FALSE,
4043 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPRIGHT
4046 Yandroid_neB, FALSE, TRUE,
4047 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPRIGHT
4050 Yandroid_e, FALSE, FALSE,
4051 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
4054 Yandroid_eB, FALSE, TRUE,
4055 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
4058 Yandroid_se, FALSE, FALSE,
4059 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNRIGHT
4062 Yandroid_seB, FALSE, TRUE,
4063 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNRIGHT
4066 Yandroid_s, FALSE, FALSE,
4067 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
4070 Yandroid_sB, FALSE, TRUE,
4071 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
4074 Yandroid_sw, FALSE, FALSE,
4075 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNLEFT
4078 Yandroid_swB, FALSE, TRUE,
4079 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNLEFT
4082 Yandroid_w, FALSE, FALSE,
4083 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
4086 Yandroid_wB, FALSE, TRUE,
4087 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
4090 Yandroid_nw, FALSE, FALSE,
4091 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPLEFT
4094 Yandroid_nwB, FALSE, TRUE,
4095 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPLEFT
4098 Xspring, TRUE, FALSE,
4102 Xspring_pause, FALSE, FALSE,
4106 Xspring_e, FALSE, FALSE,
4110 Xspring_w, FALSE, FALSE,
4114 Xspring_fall, FALSE, FALSE,
4118 Yspring_s, FALSE, FALSE,
4119 EL_SPRING, ACTION_FALLING, -1
4122 Yspring_sB, FALSE, TRUE,
4123 EL_SPRING, ACTION_FALLING, -1
4126 Yspring_e, FALSE, FALSE,
4127 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
4130 Yspring_eB, FALSE, TRUE,
4131 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
4134 Yspring_w, FALSE, FALSE,
4135 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
4138 Yspring_wB, FALSE, TRUE,
4139 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
4142 Yspring_kill_e, FALSE, FALSE,
4143 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
4146 Yspring_kill_eB, FALSE, TRUE,
4147 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
4150 Yspring_kill_w, FALSE, FALSE,
4151 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
4154 Yspring_kill_wB, FALSE, TRUE,
4155 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
4158 Xeater_n, TRUE, FALSE,
4159 EL_YAMYAM_UP, -1, -1
4162 Xeater_e, TRUE, FALSE,
4163 EL_YAMYAM_RIGHT, -1, -1
4166 Xeater_w, TRUE, FALSE,
4167 EL_YAMYAM_LEFT, -1, -1
4170 Xeater_s, TRUE, FALSE,
4171 EL_YAMYAM_DOWN, -1, -1
4174 Yeater_n, FALSE, FALSE,
4175 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
4178 Yeater_nB, FALSE, TRUE,
4179 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
4182 Yeater_e, FALSE, FALSE,
4183 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
4186 Yeater_eB, FALSE, TRUE,
4187 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
4190 Yeater_s, FALSE, FALSE,
4191 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
4194 Yeater_sB, FALSE, TRUE,
4195 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
4198 Yeater_w, FALSE, FALSE,
4199 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
4202 Yeater_wB, FALSE, TRUE,
4203 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
4206 Yeater_stone, FALSE, FALSE,
4207 EL_YAMYAM, ACTION_SMASHED_BY_ROCK, -1
4210 Yeater_spring, FALSE, FALSE,
4211 EL_YAMYAM, ACTION_SMASHED_BY_SPRING, -1
4214 Xalien, TRUE, FALSE,
4218 Xalien_pause, FALSE, FALSE,
4222 Yalien_n, FALSE, FALSE,
4223 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
4226 Yalien_nB, FALSE, TRUE,
4227 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
4230 Yalien_e, FALSE, FALSE,
4231 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
4234 Yalien_eB, FALSE, TRUE,
4235 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
4238 Yalien_s, FALSE, FALSE,
4239 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
4242 Yalien_sB, FALSE, TRUE,
4243 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
4246 Yalien_w, FALSE, FALSE,
4247 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
4250 Yalien_wB, FALSE, TRUE,
4251 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
4254 Yalien_stone, FALSE, FALSE,
4255 EL_ROBOT, ACTION_SMASHED_BY_ROCK, -1
4258 Yalien_spring, FALSE, FALSE,
4259 EL_ROBOT, ACTION_SMASHED_BY_SPRING, -1
4262 Xemerald, TRUE, FALSE,
4266 Xemerald_pause, FALSE, FALSE,
4270 Xemerald_fall, FALSE, FALSE,
4274 Xemerald_shine, FALSE, FALSE,
4275 EL_EMERALD, ACTION_TWINKLING, -1
4278 Yemerald_s, FALSE, FALSE,
4279 EL_EMERALD, ACTION_FALLING, -1
4282 Yemerald_sB, FALSE, TRUE,
4283 EL_EMERALD, ACTION_FALLING, -1
4286 Yemerald_e, FALSE, FALSE,
4287 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
4290 Yemerald_eB, FALSE, TRUE,
4291 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
4294 Yemerald_w, FALSE, FALSE,
4295 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
4298 Yemerald_wB, FALSE, TRUE,
4299 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
4302 Yemerald_eat, FALSE, FALSE,
4303 EL_EMERALD, ACTION_COLLECTING, -1
4306 Yemerald_stone, FALSE, FALSE,
4307 EL_NUT, ACTION_BREAKING, -1
4310 Xdiamond, TRUE, FALSE,
4314 Xdiamond_pause, FALSE, FALSE,
4318 Xdiamond_fall, FALSE, FALSE,
4322 Xdiamond_shine, FALSE, FALSE,
4323 EL_DIAMOND, ACTION_TWINKLING, -1
4326 Ydiamond_s, FALSE, FALSE,
4327 EL_DIAMOND, ACTION_FALLING, -1
4330 Ydiamond_sB, FALSE, TRUE,
4331 EL_DIAMOND, ACTION_FALLING, -1
4334 Ydiamond_e, FALSE, FALSE,
4335 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
4338 Ydiamond_eB, FALSE, TRUE,
4339 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
4342 Ydiamond_w, FALSE, FALSE,
4343 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
4346 Ydiamond_wB, FALSE, TRUE,
4347 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
4350 Ydiamond_eat, FALSE, FALSE,
4351 EL_DIAMOND, ACTION_COLLECTING, -1
4354 Ydiamond_stone, FALSE, FALSE,
4355 EL_DIAMOND, ACTION_SMASHED_BY_ROCK, -1
4358 Xdrip_fall, TRUE, FALSE,
4359 EL_AMOEBA_DROP, -1, -1
4362 Xdrip_stretch, FALSE, FALSE,
4363 EL_AMOEBA_DROP, ACTION_FALLING, -1
4366 Xdrip_stretchB, FALSE, TRUE,
4367 EL_AMOEBA_DROP, ACTION_FALLING, -1
4370 Xdrip_eat, FALSE, FALSE,
4371 EL_AMOEBA_DROP, ACTION_GROWING, -1
4374 Ydrip_s1, FALSE, FALSE,
4375 EL_AMOEBA_DROP, ACTION_FALLING, -1
4378 Ydrip_s1B, FALSE, TRUE,
4379 EL_AMOEBA_DROP, ACTION_FALLING, -1
4382 Ydrip_s2, FALSE, FALSE,
4383 EL_AMOEBA_DROP, ACTION_FALLING, -1
4386 Ydrip_s2B, FALSE, TRUE,
4387 EL_AMOEBA_DROP, ACTION_FALLING, -1
4394 Xbomb_pause, FALSE, FALSE,
4398 Xbomb_fall, FALSE, FALSE,
4402 Ybomb_s, FALSE, FALSE,
4403 EL_BOMB, ACTION_FALLING, -1
4406 Ybomb_sB, FALSE, TRUE,
4407 EL_BOMB, ACTION_FALLING, -1
4410 Ybomb_e, FALSE, FALSE,
4411 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
4414 Ybomb_eB, FALSE, TRUE,
4415 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
4418 Ybomb_w, FALSE, FALSE,
4419 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
4422 Ybomb_wB, FALSE, TRUE,
4423 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
4426 Ybomb_eat, FALSE, FALSE,
4427 EL_BOMB, ACTION_ACTIVATING, -1
4430 Xballoon, TRUE, FALSE,
4434 Yballoon_n, FALSE, FALSE,
4435 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
4438 Yballoon_nB, FALSE, TRUE,
4439 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
4442 Yballoon_e, FALSE, FALSE,
4443 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
4446 Yballoon_eB, FALSE, TRUE,
4447 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
4450 Yballoon_s, FALSE, FALSE,
4451 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
4454 Yballoon_sB, FALSE, TRUE,
4455 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
4458 Yballoon_w, FALSE, FALSE,
4459 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
4462 Yballoon_wB, FALSE, TRUE,
4463 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
4466 Xgrass, TRUE, FALSE,
4467 EL_EMC_GRASS, -1, -1
4470 Ygrass_nB, FALSE, FALSE,
4471 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_UP
4474 Ygrass_eB, FALSE, FALSE,
4475 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_RIGHT
4478 Ygrass_sB, FALSE, FALSE,
4479 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_DOWN
4482 Ygrass_wB, FALSE, FALSE,
4483 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_LEFT
4490 Ydirt_nB, FALSE, FALSE,
4491 EL_SAND, ACTION_DIGGING, MV_BIT_UP
4494 Ydirt_eB, FALSE, FALSE,
4495 EL_SAND, ACTION_DIGGING, MV_BIT_RIGHT
4498 Ydirt_sB, FALSE, FALSE,
4499 EL_SAND, ACTION_DIGGING, MV_BIT_DOWN
4502 Ydirt_wB, FALSE, FALSE,
4503 EL_SAND, ACTION_DIGGING, MV_BIT_LEFT
4506 Xacid_ne, TRUE, FALSE,
4507 EL_ACID_POOL_TOPRIGHT, -1, -1
4510 Xacid_se, TRUE, FALSE,
4511 EL_ACID_POOL_BOTTOMRIGHT, -1, -1
4514 Xacid_s, TRUE, FALSE,
4515 EL_ACID_POOL_BOTTOM, -1, -1
4518 Xacid_sw, TRUE, FALSE,
4519 EL_ACID_POOL_BOTTOMLEFT, -1, -1
4522 Xacid_nw, TRUE, FALSE,
4523 EL_ACID_POOL_TOPLEFT, -1, -1
4526 Xacid_1, TRUE, FALSE,
4530 Xacid_2, FALSE, FALSE,
4534 Xacid_3, FALSE, FALSE,
4538 Xacid_4, FALSE, FALSE,
4542 Xacid_5, FALSE, FALSE,
4546 Xacid_6, FALSE, FALSE,
4550 Xacid_7, FALSE, FALSE,
4554 Xacid_8, FALSE, FALSE,
4558 Xball_1, TRUE, FALSE,
4559 EL_EMC_MAGIC_BALL, -1, -1
4562 Xball_1B, FALSE, FALSE,
4563 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4566 Xball_2, FALSE, FALSE,
4567 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4570 Xball_2B, FALSE, FALSE,
4571 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4574 Yball_eat, FALSE, FALSE,
4575 EL_EMC_MAGIC_BALL, ACTION_DROPPING, -1
4578 Ykey_1_eat, FALSE, FALSE,
4579 EL_EM_KEY_1, ACTION_COLLECTING, -1
4582 Ykey_2_eat, FALSE, FALSE,
4583 EL_EM_KEY_2, ACTION_COLLECTING, -1
4586 Ykey_3_eat, FALSE, FALSE,
4587 EL_EM_KEY_3, ACTION_COLLECTING, -1
4590 Ykey_4_eat, FALSE, FALSE,
4591 EL_EM_KEY_4, ACTION_COLLECTING, -1
4594 Ykey_5_eat, FALSE, FALSE,
4595 EL_EMC_KEY_5, ACTION_COLLECTING, -1
4598 Ykey_6_eat, FALSE, FALSE,
4599 EL_EMC_KEY_6, ACTION_COLLECTING, -1
4602 Ykey_7_eat, FALSE, FALSE,
4603 EL_EMC_KEY_7, ACTION_COLLECTING, -1
4606 Ykey_8_eat, FALSE, FALSE,
4607 EL_EMC_KEY_8, ACTION_COLLECTING, -1
4610 Ylenses_eat, FALSE, FALSE,
4611 EL_EMC_LENSES, ACTION_COLLECTING, -1
4614 Ymagnify_eat, FALSE, FALSE,
4615 EL_EMC_MAGNIFIER, ACTION_COLLECTING, -1
4618 Ygrass_eat, FALSE, FALSE,
4619 EL_EMC_GRASS, ACTION_SNAPPING, -1
4622 Ydirt_eat, FALSE, FALSE,
4623 EL_SAND, ACTION_SNAPPING, -1
4626 Xgrow_ns, TRUE, FALSE,
4627 EL_EXPANDABLE_WALL_VERTICAL, -1, -1
4630 Ygrow_ns_eat, FALSE, FALSE,
4631 EL_EXPANDABLE_WALL_VERTICAL, ACTION_GROWING, -1
4634 Xgrow_ew, TRUE, FALSE,
4635 EL_EXPANDABLE_WALL_HORIZONTAL, -1, -1
4638 Ygrow_ew_eat, FALSE, FALSE,
4639 EL_EXPANDABLE_WALL_HORIZONTAL, ACTION_GROWING, -1
4642 Xwonderwall, TRUE, FALSE,
4643 EL_MAGIC_WALL, -1, -1
4646 XwonderwallB, FALSE, FALSE,
4647 EL_MAGIC_WALL, ACTION_ACTIVE, -1
4650 Xamoeba_1, TRUE, FALSE,
4651 EL_AMOEBA_DRY, ACTION_OTHER, -1
4654 Xamoeba_2, FALSE, FALSE,
4655 EL_AMOEBA_DRY, ACTION_OTHER, -1
4658 Xamoeba_3, FALSE, FALSE,
4659 EL_AMOEBA_DRY, ACTION_OTHER, -1
4662 Xamoeba_4, FALSE, FALSE,
4663 EL_AMOEBA_DRY, ACTION_OTHER, -1
4666 Xamoeba_5, TRUE, FALSE,
4667 EL_AMOEBA_WET, ACTION_OTHER, -1
4670 Xamoeba_6, FALSE, FALSE,
4671 EL_AMOEBA_WET, ACTION_OTHER, -1
4674 Xamoeba_7, FALSE, FALSE,
4675 EL_AMOEBA_WET, ACTION_OTHER, -1
4678 Xamoeba_8, FALSE, FALSE,
4679 EL_AMOEBA_WET, ACTION_OTHER, -1
4682 Xdoor_1, TRUE, FALSE,
4683 EL_EM_GATE_1, -1, -1
4686 Xdoor_2, TRUE, FALSE,
4687 EL_EM_GATE_2, -1, -1
4690 Xdoor_3, TRUE, FALSE,
4691 EL_EM_GATE_3, -1, -1
4694 Xdoor_4, TRUE, FALSE,
4695 EL_EM_GATE_4, -1, -1
4698 Xdoor_5, TRUE, FALSE,
4699 EL_EMC_GATE_5, -1, -1
4702 Xdoor_6, TRUE, FALSE,
4703 EL_EMC_GATE_6, -1, -1
4706 Xdoor_7, TRUE, FALSE,
4707 EL_EMC_GATE_7, -1, -1
4710 Xdoor_8, TRUE, FALSE,
4711 EL_EMC_GATE_8, -1, -1
4714 Xkey_1, TRUE, FALSE,
4718 Xkey_2, TRUE, FALSE,
4722 Xkey_3, TRUE, FALSE,
4726 Xkey_4, TRUE, FALSE,
4730 Xkey_5, TRUE, FALSE,
4731 EL_EMC_KEY_5, -1, -1
4734 Xkey_6, TRUE, FALSE,
4735 EL_EMC_KEY_6, -1, -1
4738 Xkey_7, TRUE, FALSE,
4739 EL_EMC_KEY_7, -1, -1
4742 Xkey_8, TRUE, FALSE,
4743 EL_EMC_KEY_8, -1, -1
4746 Xwind_n, TRUE, FALSE,
4747 EL_BALLOON_SWITCH_UP, -1, -1
4750 Xwind_e, TRUE, FALSE,
4751 EL_BALLOON_SWITCH_RIGHT, -1, -1
4754 Xwind_s, TRUE, FALSE,
4755 EL_BALLOON_SWITCH_DOWN, -1, -1
4758 Xwind_w, TRUE, FALSE,
4759 EL_BALLOON_SWITCH_LEFT, -1, -1
4762 Xwind_nesw, TRUE, FALSE,
4763 EL_BALLOON_SWITCH_ANY, -1, -1
4766 Xwind_stop, TRUE, FALSE,
4767 EL_BALLOON_SWITCH_NONE, -1, -1
4771 EL_EM_EXIT_CLOSED, -1, -1
4774 Xexit_1, TRUE, FALSE,
4775 EL_EM_EXIT_OPEN, -1, -1
4778 Xexit_2, FALSE, FALSE,
4779 EL_EM_EXIT_OPEN, -1, -1
4782 Xexit_3, FALSE, FALSE,
4783 EL_EM_EXIT_OPEN, -1, -1
4786 Xdynamite, TRUE, FALSE,
4787 EL_EM_DYNAMITE, -1, -1
4790 Ydynamite_eat, FALSE, FALSE,
4791 EL_EM_DYNAMITE, ACTION_COLLECTING, -1
4794 Xdynamite_1, TRUE, FALSE,
4795 EL_EM_DYNAMITE_ACTIVE, -1, -1
4798 Xdynamite_2, FALSE, FALSE,
4799 EL_EM_DYNAMITE_ACTIVE, -1, -1
4802 Xdynamite_3, FALSE, FALSE,
4803 EL_EM_DYNAMITE_ACTIVE, -1, -1
4806 Xdynamite_4, FALSE, FALSE,
4807 EL_EM_DYNAMITE_ACTIVE, -1, -1
4810 Xbumper, TRUE, FALSE,
4811 EL_EMC_SPRING_BUMPER, -1, -1
4814 XbumperB, FALSE, FALSE,
4815 EL_EMC_SPRING_BUMPER, ACTION_ACTIVE, -1
4818 Xwheel, TRUE, FALSE,
4819 EL_ROBOT_WHEEL, -1, -1
4822 XwheelB, FALSE, FALSE,
4823 EL_ROBOT_WHEEL, ACTION_ACTIVE, -1
4826 Xswitch, TRUE, FALSE,
4827 EL_EMC_MAGIC_BALL_SWITCH, -1, -1
4830 XswitchB, FALSE, FALSE,
4831 EL_EMC_MAGIC_BALL_SWITCH, ACTION_ACTIVE, -1
4835 EL_QUICKSAND_EMPTY, -1, -1
4838 Xsand_stone, TRUE, FALSE,
4839 EL_QUICKSAND_FULL, -1, -1
4842 Xsand_stonein_1, FALSE, TRUE,
4843 EL_ROCK, ACTION_FILLING, -1
4846 Xsand_stonein_2, FALSE, TRUE,
4847 EL_ROCK, ACTION_FILLING, -1
4850 Xsand_stonein_3, FALSE, TRUE,
4851 EL_ROCK, ACTION_FILLING, -1
4854 Xsand_stonein_4, FALSE, TRUE,
4855 EL_ROCK, ACTION_FILLING, -1
4858 Xsand_stonesand_1, FALSE, FALSE,
4859 EL_QUICKSAND_FULL, -1, -1
4862 Xsand_stonesand_2, FALSE, FALSE,
4863 EL_QUICKSAND_FULL, -1, -1
4866 Xsand_stonesand_3, FALSE, FALSE,
4867 EL_QUICKSAND_FULL, -1, -1
4870 Xsand_stonesand_4, FALSE, FALSE,
4871 EL_QUICKSAND_FULL, -1, -1
4874 Xsand_stoneout_1, FALSE, FALSE,
4875 EL_ROCK, ACTION_EMPTYING, -1
4878 Xsand_stoneout_2, FALSE, FALSE,
4879 EL_ROCK, ACTION_EMPTYING, -1
4882 Xsand_sandstone_1, FALSE, FALSE,
4883 EL_QUICKSAND_FULL, -1, -1
4886 Xsand_sandstone_2, FALSE, FALSE,
4887 EL_QUICKSAND_FULL, -1, -1
4890 Xsand_sandstone_3, FALSE, FALSE,
4891 EL_QUICKSAND_FULL, -1, -1
4894 Xsand_sandstone_4, FALSE, FALSE,
4895 EL_QUICKSAND_FULL, -1, -1
4898 Xplant, TRUE, FALSE,
4899 EL_EMC_PLANT, -1, -1
4902 Yplant, FALSE, FALSE,
4903 EL_EMC_PLANT, -1, -1
4906 Xlenses, TRUE, FALSE,
4907 EL_EMC_LENSES, -1, -1
4910 Xmagnify, TRUE, FALSE,
4911 EL_EMC_MAGNIFIER, -1, -1
4914 Xdripper, TRUE, FALSE,
4915 EL_EMC_DRIPPER, -1, -1
4918 XdripperB, FALSE, FALSE,
4919 EL_EMC_DRIPPER, ACTION_ACTIVE, -1
4922 Xfake_blank, TRUE, FALSE,
4923 EL_INVISIBLE_WALL, -1, -1
4926 Xfake_blankB, FALSE, FALSE,
4927 EL_INVISIBLE_WALL, ACTION_ACTIVE, -1
4930 Xfake_grass, TRUE, FALSE,
4931 EL_EMC_FAKE_GRASS, -1, -1
4934 Xfake_grassB, FALSE, FALSE,
4935 EL_EMC_FAKE_GRASS, ACTION_ACTIVE, -1
4938 Xfake_door_1, TRUE, FALSE,
4939 EL_EM_GATE_1_GRAY, -1, -1
4942 Xfake_door_2, TRUE, FALSE,
4943 EL_EM_GATE_2_GRAY, -1, -1
4946 Xfake_door_3, TRUE, FALSE,
4947 EL_EM_GATE_3_GRAY, -1, -1
4950 Xfake_door_4, TRUE, FALSE,
4951 EL_EM_GATE_4_GRAY, -1, -1
4954 Xfake_door_5, TRUE, FALSE,
4955 EL_EMC_GATE_5_GRAY, -1, -1
4958 Xfake_door_6, TRUE, FALSE,
4959 EL_EMC_GATE_6_GRAY, -1, -1
4962 Xfake_door_7, TRUE, FALSE,
4963 EL_EMC_GATE_7_GRAY, -1, -1
4966 Xfake_door_8, TRUE, FALSE,
4967 EL_EMC_GATE_8_GRAY, -1, -1
4970 Xfake_acid_1, TRUE, FALSE,
4971 EL_EMC_FAKE_ACID, -1, -1
4974 Xfake_acid_2, FALSE, FALSE,
4975 EL_EMC_FAKE_ACID, -1, -1
4978 Xfake_acid_3, FALSE, FALSE,
4979 EL_EMC_FAKE_ACID, -1, -1
4982 Xfake_acid_4, FALSE, FALSE,
4983 EL_EMC_FAKE_ACID, -1, -1
4986 Xfake_acid_5, FALSE, FALSE,
4987 EL_EMC_FAKE_ACID, -1, -1
4990 Xfake_acid_6, FALSE, FALSE,
4991 EL_EMC_FAKE_ACID, -1, -1
4994 Xfake_acid_7, FALSE, FALSE,
4995 EL_EMC_FAKE_ACID, -1, -1
4998 Xfake_acid_8, FALSE, FALSE,
4999 EL_EMC_FAKE_ACID, -1, -1
5002 Xsteel_1, TRUE, FALSE,
5003 EL_STEELWALL, -1, -1
5006 Xsteel_2, TRUE, FALSE,
5007 EL_EMC_STEELWALL_2, -1, -1
5010 Xsteel_3, TRUE, FALSE,
5011 EL_EMC_STEELWALL_3, -1, -1
5014 Xsteel_4, TRUE, FALSE,
5015 EL_EMC_STEELWALL_4, -1, -1
5018 Xwall_1, TRUE, FALSE,
5022 Xwall_2, TRUE, FALSE,
5023 EL_EMC_WALL_14, -1, -1
5026 Xwall_3, TRUE, FALSE,
5027 EL_EMC_WALL_15, -1, -1
5030 Xwall_4, TRUE, FALSE,
5031 EL_EMC_WALL_16, -1, -1
5034 Xround_wall_1, TRUE, FALSE,
5035 EL_WALL_SLIPPERY, -1, -1
5038 Xround_wall_2, TRUE, FALSE,
5039 EL_EMC_WALL_SLIPPERY_2, -1, -1
5042 Xround_wall_3, TRUE, FALSE,
5043 EL_EMC_WALL_SLIPPERY_3, -1, -1
5046 Xround_wall_4, TRUE, FALSE,
5047 EL_EMC_WALL_SLIPPERY_4, -1, -1
5050 Xdecor_1, TRUE, FALSE,
5051 EL_EMC_WALL_8, -1, -1
5054 Xdecor_2, TRUE, FALSE,
5055 EL_EMC_WALL_6, -1, -1
5058 Xdecor_3, TRUE, FALSE,
5059 EL_EMC_WALL_4, -1, -1
5062 Xdecor_4, TRUE, FALSE,
5063 EL_EMC_WALL_7, -1, -1
5066 Xdecor_5, TRUE, FALSE,
5067 EL_EMC_WALL_5, -1, -1
5070 Xdecor_6, TRUE, FALSE,
5071 EL_EMC_WALL_9, -1, -1
5074 Xdecor_7, TRUE, FALSE,
5075 EL_EMC_WALL_10, -1, -1
5078 Xdecor_8, TRUE, FALSE,
5079 EL_EMC_WALL_1, -1, -1
5082 Xdecor_9, TRUE, FALSE,
5083 EL_EMC_WALL_2, -1, -1
5086 Xdecor_10, TRUE, FALSE,
5087 EL_EMC_WALL_3, -1, -1
5090 Xdecor_11, TRUE, FALSE,
5091 EL_EMC_WALL_11, -1, -1
5094 Xdecor_12, TRUE, FALSE,
5095 EL_EMC_WALL_12, -1, -1
5098 Xalpha_0, TRUE, FALSE,
5099 EL_CHAR('0'), -1, -1
5102 Xalpha_1, TRUE, FALSE,
5103 EL_CHAR('1'), -1, -1
5106 Xalpha_2, TRUE, FALSE,
5107 EL_CHAR('2'), -1, -1
5110 Xalpha_3, TRUE, FALSE,
5111 EL_CHAR('3'), -1, -1
5114 Xalpha_4, TRUE, FALSE,
5115 EL_CHAR('4'), -1, -1
5118 Xalpha_5, TRUE, FALSE,
5119 EL_CHAR('5'), -1, -1
5122 Xalpha_6, TRUE, FALSE,
5123 EL_CHAR('6'), -1, -1
5126 Xalpha_7, TRUE, FALSE,
5127 EL_CHAR('7'), -1, -1
5130 Xalpha_8, TRUE, FALSE,
5131 EL_CHAR('8'), -1, -1
5134 Xalpha_9, TRUE, FALSE,
5135 EL_CHAR('9'), -1, -1
5138 Xalpha_excla, TRUE, FALSE,
5139 EL_CHAR('!'), -1, -1
5142 Xalpha_quote, TRUE, FALSE,
5143 EL_CHAR('"'), -1, -1
5146 Xalpha_comma, TRUE, FALSE,
5147 EL_CHAR(','), -1, -1
5150 Xalpha_minus, TRUE, FALSE,
5151 EL_CHAR('-'), -1, -1
5154 Xalpha_perio, TRUE, FALSE,
5155 EL_CHAR('.'), -1, -1
5158 Xalpha_colon, TRUE, FALSE,
5159 EL_CHAR(':'), -1, -1
5162 Xalpha_quest, TRUE, FALSE,
5163 EL_CHAR('?'), -1, -1
5166 Xalpha_a, TRUE, FALSE,
5167 EL_CHAR('A'), -1, -1
5170 Xalpha_b, TRUE, FALSE,
5171 EL_CHAR('B'), -1, -1
5174 Xalpha_c, TRUE, FALSE,
5175 EL_CHAR('C'), -1, -1
5178 Xalpha_d, TRUE, FALSE,
5179 EL_CHAR('D'), -1, -1
5182 Xalpha_e, TRUE, FALSE,
5183 EL_CHAR('E'), -1, -1
5186 Xalpha_f, TRUE, FALSE,
5187 EL_CHAR('F'), -1, -1
5190 Xalpha_g, TRUE, FALSE,
5191 EL_CHAR('G'), -1, -1
5194 Xalpha_h, TRUE, FALSE,
5195 EL_CHAR('H'), -1, -1
5198 Xalpha_i, TRUE, FALSE,
5199 EL_CHAR('I'), -1, -1
5202 Xalpha_j, TRUE, FALSE,
5203 EL_CHAR('J'), -1, -1
5206 Xalpha_k, TRUE, FALSE,
5207 EL_CHAR('K'), -1, -1
5210 Xalpha_l, TRUE, FALSE,
5211 EL_CHAR('L'), -1, -1
5214 Xalpha_m, TRUE, FALSE,
5215 EL_CHAR('M'), -1, -1
5218 Xalpha_n, TRUE, FALSE,
5219 EL_CHAR('N'), -1, -1
5222 Xalpha_o, TRUE, FALSE,
5223 EL_CHAR('O'), -1, -1
5226 Xalpha_p, TRUE, FALSE,
5227 EL_CHAR('P'), -1, -1
5230 Xalpha_q, TRUE, FALSE,
5231 EL_CHAR('Q'), -1, -1
5234 Xalpha_r, TRUE, FALSE,
5235 EL_CHAR('R'), -1, -1
5238 Xalpha_s, TRUE, FALSE,
5239 EL_CHAR('S'), -1, -1
5242 Xalpha_t, TRUE, FALSE,
5243 EL_CHAR('T'), -1, -1
5246 Xalpha_u, TRUE, FALSE,
5247 EL_CHAR('U'), -1, -1
5250 Xalpha_v, TRUE, FALSE,
5251 EL_CHAR('V'), -1, -1
5254 Xalpha_w, TRUE, FALSE,
5255 EL_CHAR('W'), -1, -1
5258 Xalpha_x, TRUE, FALSE,
5259 EL_CHAR('X'), -1, -1
5262 Xalpha_y, TRUE, FALSE,
5263 EL_CHAR('Y'), -1, -1
5266 Xalpha_z, TRUE, FALSE,
5267 EL_CHAR('Z'), -1, -1
5270 Xalpha_arrow_e, TRUE, FALSE,
5271 EL_CHAR('>'), -1, -1
5274 Xalpha_arrow_w, TRUE, FALSE,
5275 EL_CHAR('<'), -1, -1
5278 Xalpha_copyr, TRUE, FALSE,
5279 EL_CHAR('©'), -1, -1
5283 Xboom_bug, FALSE, FALSE,
5284 EL_BUG, ACTION_EXPLODING, -1
5287 Xboom_bomb, FALSE, FALSE,
5288 EL_BOMB, ACTION_EXPLODING, -1
5291 Xboom_android, FALSE, FALSE,
5292 EL_EMC_ANDROID, ACTION_OTHER, -1
5295 Xboom_1, FALSE, FALSE,
5296 EL_DEFAULT, ACTION_EXPLODING, -1
5299 Xboom_2, FALSE, FALSE,
5300 EL_DEFAULT, ACTION_EXPLODING, -1
5303 Znormal, FALSE, FALSE,
5307 Zdynamite, FALSE, FALSE,
5311 Zplayer, FALSE, FALSE,
5315 ZBORDER, FALSE, FALSE,
5325 static struct Mapping_EM_to_RND_player
5334 em_player_mapping_list[] =
5338 EL_PLAYER_1, ACTION_MOVING, MV_BIT_UP,
5342 EL_PLAYER_1, ACTION_MOVING, MV_BIT_RIGHT,
5346 EL_PLAYER_1, ACTION_MOVING, MV_BIT_DOWN,
5350 EL_PLAYER_1, ACTION_MOVING, MV_BIT_LEFT,
5354 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_UP,
5358 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_RIGHT,
5362 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_DOWN,
5366 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_LEFT,
5370 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_UP,
5374 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_RIGHT,
5378 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_DOWN,
5382 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_LEFT,
5386 EL_PLAYER_2, ACTION_MOVING, MV_BIT_UP,
5390 EL_PLAYER_2, ACTION_MOVING, MV_BIT_RIGHT,
5394 EL_PLAYER_2, ACTION_MOVING, MV_BIT_DOWN,
5398 EL_PLAYER_2, ACTION_MOVING, MV_BIT_LEFT,
5402 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_UP,
5406 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_RIGHT,
5410 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_DOWN,
5414 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_LEFT,
5418 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_UP,
5422 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_RIGHT,
5426 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_DOWN,
5430 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_LEFT,
5434 EL_PLAYER_1, ACTION_DEFAULT, -1,
5438 EL_PLAYER_2, ACTION_DEFAULT, -1,
5442 EL_PLAYER_3, ACTION_MOVING, MV_BIT_UP,
5446 EL_PLAYER_3, ACTION_MOVING, MV_BIT_RIGHT,
5450 EL_PLAYER_3, ACTION_MOVING, MV_BIT_DOWN,
5454 EL_PLAYER_3, ACTION_MOVING, MV_BIT_LEFT,
5458 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_UP,
5462 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_RIGHT,
5466 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_DOWN,
5470 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_LEFT,
5474 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_UP,
5478 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_RIGHT,
5482 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_DOWN,
5486 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_LEFT,
5490 EL_PLAYER_4, ACTION_MOVING, MV_BIT_UP,
5494 EL_PLAYER_4, ACTION_MOVING, MV_BIT_RIGHT,
5498 EL_PLAYER_4, ACTION_MOVING, MV_BIT_DOWN,
5502 EL_PLAYER_4, ACTION_MOVING, MV_BIT_LEFT,
5506 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_UP,
5510 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_RIGHT,
5514 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_DOWN,
5518 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_LEFT,
5522 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_UP,
5526 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_RIGHT,
5530 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_DOWN,
5534 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_LEFT,
5538 EL_PLAYER_3, ACTION_DEFAULT, -1,
5542 EL_PLAYER_4, ACTION_DEFAULT, -1,
5551 int map_element_RND_to_EM(int element_rnd)
5553 static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
5554 static boolean mapping_initialized = FALSE;
5556 if (!mapping_initialized)
5560 /* return "Xalpha_quest" for all undefined elements in mapping array */
5561 for (i = 0; i < NUM_FILE_ELEMENTS; i++)
5562 mapping_RND_to_EM[i] = Xalpha_quest;
5564 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5565 if (em_object_mapping_list[i].is_rnd_to_em_mapping)
5566 mapping_RND_to_EM[em_object_mapping_list[i].element_rnd] =
5567 em_object_mapping_list[i].element_em;
5569 mapping_initialized = TRUE;
5572 if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
5573 return mapping_RND_to_EM[element_rnd];
5575 Error(ERR_WARN, "invalid RND level element %d", element_rnd);
5580 int map_element_EM_to_RND(int element_em)
5582 static unsigned short mapping_EM_to_RND[TILE_MAX];
5583 static boolean mapping_initialized = FALSE;
5585 if (!mapping_initialized)
5589 /* return "EL_UNKNOWN" for all undefined elements in mapping array */
5590 for (i = 0; i < TILE_MAX; i++)
5591 mapping_EM_to_RND[i] = EL_UNKNOWN;
5593 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5594 mapping_EM_to_RND[em_object_mapping_list[i].element_em] =
5595 em_object_mapping_list[i].element_rnd;
5597 mapping_initialized = TRUE;
5600 if (element_em >= 0 && element_em < TILE_MAX)
5601 return mapping_EM_to_RND[element_em];
5603 Error(ERR_WARN, "invalid EM level element %d", element_em);
5608 void map_android_clone_elements_RND_to_EM(struct LevelInfo *level)
5610 struct LevelInfo_EM *level_em = level->native_em_level;
5611 struct LEVEL *lev = level_em->lev;
5614 for (i = 0; i < TILE_MAX; i++)
5615 lev->android_array[i] = Xblank;
5617 for (i = 0; i < level->num_android_clone_elements; i++)
5619 int element_rnd = level->android_clone_element[i];
5620 int element_em = map_element_RND_to_EM(element_rnd);
5622 for (j = 0; em_object_mapping_list[j].element_em != -1; j++)
5623 if (em_object_mapping_list[j].element_rnd == element_rnd)
5624 lev->android_array[em_object_mapping_list[j].element_em] = element_em;
5628 void map_android_clone_elements_EM_to_RND(struct LevelInfo *level)
5630 struct LevelInfo_EM *level_em = level->native_em_level;
5631 struct LEVEL *lev = level_em->lev;
5634 level->num_android_clone_elements = 0;
5636 for (i = 0; i < TILE_MAX; i++)
5638 int element_em = lev->android_array[i];
5640 boolean element_found = FALSE;
5642 if (element_em == Xblank)
5645 element_rnd = map_element_EM_to_RND(element_em);
5647 for (j = 0; j < level->num_android_clone_elements; j++)
5648 if (level->android_clone_element[j] == element_rnd)
5649 element_found = TRUE;
5653 level->android_clone_element[level->num_android_clone_elements++] =
5656 if (level->num_android_clone_elements == MAX_ANDROID_ELEMENTS)
5661 if (level->num_android_clone_elements == 0)
5663 level->num_android_clone_elements = 1;
5664 level->android_clone_element[0] = EL_EMPTY;
5668 int map_direction_RND_to_EM(int direction)
5670 return (direction == MV_UP ? 0 :
5671 direction == MV_RIGHT ? 1 :
5672 direction == MV_DOWN ? 2 :
5673 direction == MV_LEFT ? 3 :
5677 int map_direction_EM_to_RND(int direction)
5679 return (direction == 0 ? MV_UP :
5680 direction == 1 ? MV_RIGHT :
5681 direction == 2 ? MV_DOWN :
5682 direction == 3 ? MV_LEFT :
5686 int get_next_element(int element)
5690 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
5691 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
5692 case EL_QUICKSAND_FAST_FILLING: return EL_QUICKSAND_FAST_FULL;
5693 case EL_QUICKSAND_FAST_EMPTYING: return EL_QUICKSAND_FAST_EMPTY;
5694 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
5695 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
5696 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
5697 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
5698 case EL_DC_MAGIC_WALL_FILLING: return EL_DC_MAGIC_WALL_FULL;
5699 case EL_DC_MAGIC_WALL_EMPTYING: return EL_DC_MAGIC_WALL_ACTIVE;
5700 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
5702 default: return element;
5707 int el_act_dir2img(int element, int action, int direction)
5709 element = GFX_ELEMENT(element);
5711 if (direction == MV_NONE)
5712 return element_info[element].graphic[action];
5714 direction = MV_DIR_TO_BIT(direction);
5716 return element_info[element].direction_graphic[action][direction];
5719 int el_act_dir2img(int element, int action, int direction)
5721 element = GFX_ELEMENT(element);
5722 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
5724 /* direction_graphic[][] == graphic[] for undefined direction graphics */
5725 return element_info[element].direction_graphic[action][direction];
5730 static int el_act_dir2crm(int element, int action, int direction)
5732 element = GFX_ELEMENT(element);
5734 if (direction == MV_NONE)
5735 return element_info[element].crumbled[action];
5737 direction = MV_DIR_TO_BIT(direction);
5739 return element_info[element].direction_crumbled[action][direction];
5742 static int el_act_dir2crm(int element, int action, int direction)
5744 element = GFX_ELEMENT(element);
5745 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
5747 /* direction_graphic[][] == graphic[] for undefined direction graphics */
5748 return element_info[element].direction_crumbled[action][direction];
5752 int el_act2img(int element, int action)
5754 element = GFX_ELEMENT(element);
5756 return element_info[element].graphic[action];
5759 int el_act2crm(int element, int action)
5761 element = GFX_ELEMENT(element);
5763 return element_info[element].crumbled[action];
5766 int el_dir2img(int element, int direction)
5768 element = GFX_ELEMENT(element);
5770 return el_act_dir2img(element, ACTION_DEFAULT, direction);
5773 int el2baseimg(int element)
5775 return element_info[element].graphic[ACTION_DEFAULT];
5778 int el2img(int element)
5780 element = GFX_ELEMENT(element);
5782 return element_info[element].graphic[ACTION_DEFAULT];
5785 int el2edimg(int element)
5787 element = GFX_ELEMENT(element);
5789 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
5792 int el2preimg(int element)
5794 element = GFX_ELEMENT(element);
5796 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
5799 int el2panelimg(int element)
5801 element = GFX_ELEMENT(element);
5803 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PANEL];
5806 int font2baseimg(int font_nr)
5808 return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
5811 int getBeltNrFromBeltElement(int element)
5813 return (element < EL_CONVEYOR_BELT_2_LEFT ? 0 :
5814 element < EL_CONVEYOR_BELT_3_LEFT ? 1 :
5815 element < EL_CONVEYOR_BELT_4_LEFT ? 2 : 3);
5818 int getBeltNrFromBeltActiveElement(int element)
5820 return (element < EL_CONVEYOR_BELT_2_LEFT_ACTIVE ? 0 :
5821 element < EL_CONVEYOR_BELT_3_LEFT_ACTIVE ? 1 :
5822 element < EL_CONVEYOR_BELT_4_LEFT_ACTIVE ? 2 : 3);
5825 int getBeltNrFromBeltSwitchElement(int element)
5827 return (element < EL_CONVEYOR_BELT_2_SWITCH_LEFT ? 0 :
5828 element < EL_CONVEYOR_BELT_3_SWITCH_LEFT ? 1 :
5829 element < EL_CONVEYOR_BELT_4_SWITCH_LEFT ? 2 : 3);
5832 int getBeltDirNrFromBeltElement(int element)
5834 static int belt_base_element[4] =
5836 EL_CONVEYOR_BELT_1_LEFT,
5837 EL_CONVEYOR_BELT_2_LEFT,
5838 EL_CONVEYOR_BELT_3_LEFT,
5839 EL_CONVEYOR_BELT_4_LEFT
5842 int belt_nr = getBeltNrFromBeltElement(element);
5843 int belt_dir_nr = element - belt_base_element[belt_nr];
5845 return (belt_dir_nr % 3);
5848 int getBeltDirNrFromBeltSwitchElement(int element)
5850 static int belt_base_element[4] =
5852 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
5853 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
5854 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
5855 EL_CONVEYOR_BELT_4_SWITCH_LEFT
5858 int belt_nr = getBeltNrFromBeltSwitchElement(element);
5859 int belt_dir_nr = element - belt_base_element[belt_nr];
5861 return (belt_dir_nr % 3);
5864 int getBeltDirFromBeltElement(int element)
5866 static int belt_move_dir[3] =
5873 int belt_dir_nr = getBeltDirNrFromBeltElement(element);
5875 return belt_move_dir[belt_dir_nr];
5878 int getBeltDirFromBeltSwitchElement(int element)
5880 static int belt_move_dir[3] =
5887 int belt_dir_nr = getBeltDirNrFromBeltSwitchElement(element);
5889 return belt_move_dir[belt_dir_nr];
5892 int getBeltElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
5894 static int belt_base_element[4] =
5896 EL_CONVEYOR_BELT_1_LEFT,
5897 EL_CONVEYOR_BELT_2_LEFT,
5898 EL_CONVEYOR_BELT_3_LEFT,
5899 EL_CONVEYOR_BELT_4_LEFT
5902 return belt_base_element[belt_nr] + belt_dir_nr;
5905 int getBeltElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
5907 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
5909 return getBeltElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
5912 int getBeltSwitchElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
5914 static int belt_base_element[4] =
5916 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
5917 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
5918 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
5919 EL_CONVEYOR_BELT_4_SWITCH_LEFT
5922 return belt_base_element[belt_nr] + belt_dir_nr;
5925 int getBeltSwitchElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
5927 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
5929 return getBeltSwitchElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
5932 int getNumActivePlayers_EM()
5934 int num_players = 0;
5940 for (i = 0; i < MAX_PLAYERS; i++)
5941 if (tape.player_participates[i])
5947 int getGameFrameDelay_EM(int native_em_game_frame_delay)
5949 int game_frame_delay_value;
5951 game_frame_delay_value =
5952 (tape.playing && tape.fast_forward ? FfwdFrameDelay :
5953 GameFrameDelay == GAME_FRAME_DELAY ? native_em_game_frame_delay :
5956 if (tape.playing && tape.warp_forward && !tape.pausing)
5957 game_frame_delay_value = 0;
5959 return game_frame_delay_value;
5962 unsigned int InitRND(long seed)
5964 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
5965 return InitEngineRandom_EM(seed);
5967 return InitEngineRandom_RND(seed);
5971 static struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
5972 static struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
5975 void ResetGfxAnimation_EM(int x, int y, int tile)
5980 void SetGfxAnimation_EM(int tile, int frame_em, int x, int y)
5983 int element = object_mapping[tile].element_rnd;
5985 int action = object_mapping[tile].action;
5986 int direction = object_mapping[tile].direction;
5987 boolean is_backside = object_mapping[tile].is_backside;
5988 boolean action_removing = (action == ACTION_DIGGING ||
5989 action == ACTION_SNAPPING ||
5990 action == ACTION_COLLECTING);
5993 printf("::: SET: %d, %d: '%s'\n", x, y, EL_NAME(element));
5997 if (action_removing)
6000 printf("::: %d, %d: action_removing [%s]\n", x, y, EL_NAME(element));
6003 GfxFrame[x][y] = 7 - frame_em;
6005 else if (action == ACTION_FALLING ||
6006 action == ACTION_MOVING ||
6007 action == ACTION_PUSHING ||
6008 action == ACTION_EATING ||
6009 action == ACTION_FILLING ||
6010 action == ACTION_EMPTYING)
6013 (action == ACTION_FALLING ||
6014 action == ACTION_FILLING ||
6015 action == ACTION_EMPTYING ? MV_DOWN : direction);
6021 if (move_dir == MV_LEFT)
6022 GfxFrame[x - 1][y] = GfxFrame[x][y];
6023 else if (move_dir == MV_RIGHT)
6024 GfxFrame[x + 1][y] = GfxFrame[x][y];
6025 else if (move_dir == MV_UP)
6026 GfxFrame[x][y - 1] = GfxFrame[x][y];
6027 else if (move_dir == MV_DOWN)
6028 GfxFrame[x][y + 1] = GfxFrame[x][y];
6032 printf("::: %d, %d: %s, %d, %d [%d]\n", x, y, EL_NAME(element), is_backside,
6033 move_dir, GfxFrame[x][y]);
6039 GfxFrame[x][y] = 7 - frame_em;
6043 void getGraphicSourceObjectExt_EM(int tile, int frame_em,
6044 Bitmap **src_bitmap, int *src_x, int *src_y,
6047 int element = object_mapping[tile].element_rnd;
6048 int action = object_mapping[tile].action;
6049 int direction = object_mapping[tile].direction;
6050 boolean is_backside = object_mapping[tile].is_backside;
6051 boolean action_removing = (action == ACTION_DIGGING ||
6052 action == ACTION_SNAPPING ||
6053 action == ACTION_COLLECTING);
6054 int effective_element = (frame_em > 0 ? element :
6055 is_backside ? EL_EMPTY :
6056 action_removing ? EL_EMPTY :
6058 int graphic = (direction == MV_NONE ?
6059 el_act2img(effective_element, action) :
6060 el_act_dir2img(effective_element, action, direction));
6061 struct GraphicInfo *g = &graphic_info[graphic];
6065 printf("::: GET: %d, %d: '%s'\n", x, y, EL_NAME(element));
6069 if (GfxFrame[x][y] < 8)
6070 printf("::: %d, %d: %d [%s]\n", x, y, GfxFrame[x][y], EL_NAME(element));
6074 if (graphic_info[graphic].anim_global_sync)
6075 sync_frame = FrameCounter;
6076 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
6077 sync_frame = GfxFrame[x][y];
6079 sync_frame = 0; /* steel border */
6081 if (graphic_info[graphic].anim_global_sync)
6082 sync_frame = FrameCounter;
6084 sync_frame = 7 - frame_em;
6087 SetRandomAnimationValue(x, y);
6089 int frame = getAnimationFrame(g->anim_frames,
6092 g->anim_start_frame,
6095 getGraphicSourceExt(graphic, frame, src_bitmap, src_x, src_y, FALSE);
6098 void getGraphicSourcePlayerExt_EM(int player_nr, int anim, int frame_em,
6099 Bitmap **src_bitmap, int *src_x, int *src_y)
6101 int element = player_mapping[player_nr][anim].element_rnd;
6102 int action = player_mapping[player_nr][anim].action;
6103 int direction = player_mapping[player_nr][anim].direction;
6104 int graphic = (direction == MV_NONE ?
6105 el_act2img(element, action) :
6106 el_act_dir2img(element, action, direction));
6107 struct GraphicInfo *g = &graphic_info[graphic];
6110 InitPlayerGfxAnimation(&stored_player[player_nr], action, direction);
6112 stored_player[player_nr].StepFrame = 7 - frame_em;
6114 sync_frame = stored_player[player_nr].Frame;
6117 printf("::: %d: %d, %d [%d]\n",
6119 stored_player[player_nr].Frame,
6120 stored_player[player_nr].StepFrame,
6124 int frame = getAnimationFrame(g->anim_frames,
6127 g->anim_start_frame,
6130 getGraphicSourceExt(graphic, frame, src_bitmap, src_x, src_y, FALSE);
6133 void InitGraphicInfo_EM(void)
6136 struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
6137 struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
6142 int num_em_gfx_errors = 0;
6144 if (graphic_info_em_object[0][0].bitmap == NULL)
6146 /* EM graphics not yet initialized in em_open_all() */
6151 printf("::: [4 errors can be ignored (1 x 'bomb', 3 x 'em_dynamite']\n");
6154 /* always start with reliable default values */
6155 for (i = 0; i < TILE_MAX; i++)
6157 object_mapping[i].element_rnd = EL_UNKNOWN;
6158 object_mapping[i].is_backside = FALSE;
6159 object_mapping[i].action = ACTION_DEFAULT;
6160 object_mapping[i].direction = MV_NONE;
6163 /* always start with reliable default values */
6164 for (p = 0; p < MAX_PLAYERS; p++)
6166 for (i = 0; i < SPR_MAX; i++)
6168 player_mapping[p][i].element_rnd = EL_UNKNOWN;
6169 player_mapping[p][i].action = ACTION_DEFAULT;
6170 player_mapping[p][i].direction = MV_NONE;
6174 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
6176 int e = em_object_mapping_list[i].element_em;
6178 object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd;
6179 object_mapping[e].is_backside = em_object_mapping_list[i].is_backside;
6181 if (em_object_mapping_list[i].action != -1)
6182 object_mapping[e].action = em_object_mapping_list[i].action;
6184 if (em_object_mapping_list[i].direction != -1)
6185 object_mapping[e].direction =
6186 MV_DIR_FROM_BIT(em_object_mapping_list[i].direction);
6189 for (i = 0; em_player_mapping_list[i].action_em != -1; i++)
6191 int a = em_player_mapping_list[i].action_em;
6192 int p = em_player_mapping_list[i].player_nr;
6194 player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd;
6196 if (em_player_mapping_list[i].action != -1)
6197 player_mapping[p][a].action = em_player_mapping_list[i].action;
6199 if (em_player_mapping_list[i].direction != -1)
6200 player_mapping[p][a].direction =
6201 MV_DIR_FROM_BIT(em_player_mapping_list[i].direction);
6204 for (i = 0; i < TILE_MAX; i++)
6206 int element = object_mapping[i].element_rnd;
6207 int action = object_mapping[i].action;
6208 int direction = object_mapping[i].direction;
6209 boolean is_backside = object_mapping[i].is_backside;
6210 boolean action_removing = (action == ACTION_DIGGING ||
6211 action == ACTION_SNAPPING ||
6212 action == ACTION_COLLECTING);
6213 boolean action_exploding = ((action == ACTION_EXPLODING ||
6214 action == ACTION_SMASHED_BY_ROCK ||
6215 action == ACTION_SMASHED_BY_SPRING) &&
6216 element != EL_DIAMOND);
6217 boolean action_active = (action == ACTION_ACTIVE);
6218 boolean action_other = (action == ACTION_OTHER);
6220 for (j = 0; j < 8; j++)
6222 int effective_element = (j > 5 && i == Yacid_splash_eB ? EL_EMPTY :
6223 j > 5 && i == Yacid_splash_wB ? EL_EMPTY :
6225 i == Xdrip_stretch ? element :
6226 i == Xdrip_stretchB ? element :
6227 i == Ydrip_s1 ? element :
6228 i == Ydrip_s1B ? element :
6229 i == Xball_1B ? element :
6230 i == Xball_2 ? element :
6231 i == Xball_2B ? element :
6232 i == Yball_eat ? element :
6233 i == Ykey_1_eat ? element :
6234 i == Ykey_2_eat ? element :
6235 i == Ykey_3_eat ? element :
6236 i == Ykey_4_eat ? element :
6237 i == Ykey_5_eat ? element :
6238 i == Ykey_6_eat ? element :
6239 i == Ykey_7_eat ? element :
6240 i == Ykey_8_eat ? element :
6241 i == Ylenses_eat ? element :
6242 i == Ymagnify_eat ? element :
6243 i == Ygrass_eat ? element :
6244 i == Ydirt_eat ? element :
6245 i == Yemerald_stone ? EL_EMERALD :
6246 i == Ydiamond_stone ? EL_ROCK :
6247 i == Xsand_stonein_1 ? element :
6248 i == Xsand_stonein_2 ? element :
6249 i == Xsand_stonein_3 ? element :
6250 i == Xsand_stonein_4 ? element :
6251 is_backside ? EL_EMPTY :
6252 action_removing ? EL_EMPTY :
6254 int effective_action = (j < 7 ? action :
6255 i == Xdrip_stretch ? action :
6256 i == Xdrip_stretchB ? action :
6257 i == Ydrip_s1 ? action :
6258 i == Ydrip_s1B ? action :
6259 i == Xball_1B ? action :
6260 i == Xball_2 ? action :
6261 i == Xball_2B ? action :
6262 i == Yball_eat ? action :
6263 i == Ykey_1_eat ? action :
6264 i == Ykey_2_eat ? action :
6265 i == Ykey_3_eat ? action :
6266 i == Ykey_4_eat ? action :
6267 i == Ykey_5_eat ? action :
6268 i == Ykey_6_eat ? action :
6269 i == Ykey_7_eat ? action :
6270 i == Ykey_8_eat ? action :
6271 i == Ylenses_eat ? action :
6272 i == Ymagnify_eat ? action :
6273 i == Ygrass_eat ? action :
6274 i == Ydirt_eat ? action :
6275 i == Xsand_stonein_1 ? action :
6276 i == Xsand_stonein_2 ? action :
6277 i == Xsand_stonein_3 ? action :
6278 i == Xsand_stonein_4 ? action :
6279 i == Xsand_stoneout_1 ? action :
6280 i == Xsand_stoneout_2 ? action :
6281 i == Xboom_android ? ACTION_EXPLODING :
6282 action_exploding ? ACTION_EXPLODING :
6283 action_active ? action :
6284 action_other ? action :
6286 int graphic = (el_act_dir2img(effective_element, effective_action,
6288 int crumbled = (el_act_dir2crm(effective_element, effective_action,
6290 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
6291 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
6292 boolean has_action_graphics = (graphic != base_graphic);
6293 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
6294 struct GraphicInfo *g = &graphic_info[graphic];
6295 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
6298 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
6299 boolean special_animation = (action != ACTION_DEFAULT &&
6300 g->anim_frames == 3 &&
6301 g->anim_delay == 2 &&
6302 g->anim_mode & ANIM_LINEAR);
6303 int sync_frame = (i == Xdrip_stretch ? 7 :
6304 i == Xdrip_stretchB ? 7 :
6305 i == Ydrip_s2 ? j + 8 :
6306 i == Ydrip_s2B ? j + 8 :
6315 i == Xfake_acid_1 ? 0 :
6316 i == Xfake_acid_2 ? 10 :
6317 i == Xfake_acid_3 ? 20 :
6318 i == Xfake_acid_4 ? 30 :
6319 i == Xfake_acid_5 ? 40 :
6320 i == Xfake_acid_6 ? 50 :
6321 i == Xfake_acid_7 ? 60 :
6322 i == Xfake_acid_8 ? 70 :
6324 i == Xball_2B ? j + 8 :
6325 i == Yball_eat ? j + 1 :
6326 i == Ykey_1_eat ? j + 1 :
6327 i == Ykey_2_eat ? j + 1 :
6328 i == Ykey_3_eat ? j + 1 :
6329 i == Ykey_4_eat ? j + 1 :
6330 i == Ykey_5_eat ? j + 1 :
6331 i == Ykey_6_eat ? j + 1 :
6332 i == Ykey_7_eat ? j + 1 :
6333 i == Ykey_8_eat ? j + 1 :
6334 i == Ylenses_eat ? j + 1 :
6335 i == Ymagnify_eat ? j + 1 :
6336 i == Ygrass_eat ? j + 1 :
6337 i == Ydirt_eat ? j + 1 :
6338 i == Xamoeba_1 ? 0 :
6339 i == Xamoeba_2 ? 1 :
6340 i == Xamoeba_3 ? 2 :
6341 i == Xamoeba_4 ? 3 :
6342 i == Xamoeba_5 ? 0 :
6343 i == Xamoeba_6 ? 1 :
6344 i == Xamoeba_7 ? 2 :
6345 i == Xamoeba_8 ? 3 :
6346 i == Xexit_2 ? j + 8 :
6347 i == Xexit_3 ? j + 16 :
6348 i == Xdynamite_1 ? 0 :
6349 i == Xdynamite_2 ? 8 :
6350 i == Xdynamite_3 ? 16 :
6351 i == Xdynamite_4 ? 24 :
6352 i == Xsand_stonein_1 ? j + 1 :
6353 i == Xsand_stonein_2 ? j + 9 :
6354 i == Xsand_stonein_3 ? j + 17 :
6355 i == Xsand_stonein_4 ? j + 25 :
6356 i == Xsand_stoneout_1 && j == 0 ? 0 :
6357 i == Xsand_stoneout_1 && j == 1 ? 0 :
6358 i == Xsand_stoneout_1 && j == 2 ? 1 :
6359 i == Xsand_stoneout_1 && j == 3 ? 2 :
6360 i == Xsand_stoneout_1 && j == 4 ? 2 :
6361 i == Xsand_stoneout_1 && j == 5 ? 3 :
6362 i == Xsand_stoneout_1 && j == 6 ? 4 :
6363 i == Xsand_stoneout_1 && j == 7 ? 4 :
6364 i == Xsand_stoneout_2 && j == 0 ? 5 :
6365 i == Xsand_stoneout_2 && j == 1 ? 6 :
6366 i == Xsand_stoneout_2 && j == 2 ? 7 :
6367 i == Xsand_stoneout_2 && j == 3 ? 8 :
6368 i == Xsand_stoneout_2 && j == 4 ? 9 :
6369 i == Xsand_stoneout_2 && j == 5 ? 11 :
6370 i == Xsand_stoneout_2 && j == 6 ? 13 :
6371 i == Xsand_stoneout_2 && j == 7 ? 15 :
6372 i == Xboom_bug && j == 1 ? 2 :
6373 i == Xboom_bug && j == 2 ? 2 :
6374 i == Xboom_bug && j == 3 ? 4 :
6375 i == Xboom_bug && j == 4 ? 4 :
6376 i == Xboom_bug && j == 5 ? 2 :
6377 i == Xboom_bug && j == 6 ? 2 :
6378 i == Xboom_bug && j == 7 ? 0 :
6379 i == Xboom_bomb && j == 1 ? 2 :
6380 i == Xboom_bomb && j == 2 ? 2 :
6381 i == Xboom_bomb && j == 3 ? 4 :
6382 i == Xboom_bomb && j == 4 ? 4 :
6383 i == Xboom_bomb && j == 5 ? 2 :
6384 i == Xboom_bomb && j == 6 ? 2 :
6385 i == Xboom_bomb && j == 7 ? 0 :
6386 i == Xboom_android && j == 7 ? 6 :
6387 i == Xboom_1 && j == 1 ? 2 :
6388 i == Xboom_1 && j == 2 ? 2 :
6389 i == Xboom_1 && j == 3 ? 4 :
6390 i == Xboom_1 && j == 4 ? 4 :
6391 i == Xboom_1 && j == 5 ? 6 :
6392 i == Xboom_1 && j == 6 ? 6 :
6393 i == Xboom_1 && j == 7 ? 8 :
6394 i == Xboom_2 && j == 0 ? 8 :
6395 i == Xboom_2 && j == 1 ? 8 :
6396 i == Xboom_2 && j == 2 ? 10 :
6397 i == Xboom_2 && j == 3 ? 10 :
6398 i == Xboom_2 && j == 4 ? 10 :
6399 i == Xboom_2 && j == 5 ? 12 :
6400 i == Xboom_2 && j == 6 ? 12 :
6401 i == Xboom_2 && j == 7 ? 12 :
6402 special_animation && j == 4 ? 3 :
6403 effective_action != action ? 0 :
6407 Bitmap *debug_bitmap = g_em->bitmap;
6408 int debug_src_x = g_em->src_x;
6409 int debug_src_y = g_em->src_y;
6412 int frame = getAnimationFrame(g->anim_frames,
6415 g->anim_start_frame,
6418 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y,
6419 g->double_movement && is_backside);
6421 g_em->bitmap = src_bitmap;
6422 g_em->src_x = src_x;
6423 g_em->src_y = src_y;
6424 g_em->src_offset_x = 0;
6425 g_em->src_offset_y = 0;
6426 g_em->dst_offset_x = 0;
6427 g_em->dst_offset_y = 0;
6428 g_em->width = TILEX;
6429 g_em->height = TILEY;
6431 g_em->crumbled_bitmap = NULL;
6432 g_em->crumbled_src_x = 0;
6433 g_em->crumbled_src_y = 0;
6434 g_em->crumbled_border_size = 0;
6436 g_em->has_crumbled_graphics = FALSE;
6437 g_em->preserve_background = FALSE;
6440 if (has_crumbled_graphics && crumbled == IMG_EMPTY_SPACE)
6441 printf("::: empty crumbled: %d [%s], %d, %d\n",
6442 effective_element, element_info[effective_element].token_name,
6443 effective_action, direction);
6446 /* if element can be crumbled, but certain action graphics are just empty
6447 space (like snapping sand with the original R'n'D graphics), do not
6448 treat these empty space graphics as crumbled graphics in EMC engine */
6449 if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
6451 getGraphicSource(crumbled, frame, &src_bitmap, &src_x, &src_y);
6453 g_em->has_crumbled_graphics = TRUE;
6454 g_em->crumbled_bitmap = src_bitmap;
6455 g_em->crumbled_src_x = src_x;
6456 g_em->crumbled_src_y = src_y;
6457 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
6461 if (element == EL_ROCK &&
6462 effective_action == ACTION_FILLING)
6463 printf("::: has_action_graphics == %d\n", has_action_graphics);
6466 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
6467 effective_action == ACTION_MOVING ||
6468 effective_action == ACTION_PUSHING ||
6469 effective_action == ACTION_EATING)) ||
6470 (!has_action_graphics && (effective_action == ACTION_FILLING ||
6471 effective_action == ACTION_EMPTYING)))
6474 (effective_action == ACTION_FALLING ||
6475 effective_action == ACTION_FILLING ||
6476 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
6477 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
6478 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
6479 int num_steps = (i == Ydrip_s1 ? 16 :
6480 i == Ydrip_s1B ? 16 :
6481 i == Ydrip_s2 ? 16 :
6482 i == Ydrip_s2B ? 16 :
6483 i == Xsand_stonein_1 ? 32 :
6484 i == Xsand_stonein_2 ? 32 :
6485 i == Xsand_stonein_3 ? 32 :
6486 i == Xsand_stonein_4 ? 32 :
6487 i == Xsand_stoneout_1 ? 16 :
6488 i == Xsand_stoneout_2 ? 16 : 8);
6489 int cx = ABS(dx) * (TILEX / num_steps);
6490 int cy = ABS(dy) * (TILEY / num_steps);
6491 int step_frame = (i == Ydrip_s2 ? j + 8 :
6492 i == Ydrip_s2B ? j + 8 :
6493 i == Xsand_stonein_2 ? j + 8 :
6494 i == Xsand_stonein_3 ? j + 16 :
6495 i == Xsand_stonein_4 ? j + 24 :
6496 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
6497 int step = (is_backside ? step_frame : num_steps - step_frame);
6499 if (is_backside) /* tile where movement starts */
6501 if (dx < 0 || dy < 0)
6503 g_em->src_offset_x = cx * step;
6504 g_em->src_offset_y = cy * step;
6508 g_em->dst_offset_x = cx * step;
6509 g_em->dst_offset_y = cy * step;
6512 else /* tile where movement ends */
6514 if (dx < 0 || dy < 0)
6516 g_em->dst_offset_x = cx * step;
6517 g_em->dst_offset_y = cy * step;
6521 g_em->src_offset_x = cx * step;
6522 g_em->src_offset_y = cy * step;
6526 g_em->width = TILEX - cx * step;
6527 g_em->height = TILEY - cy * step;
6530 /* create unique graphic identifier to decide if tile must be redrawn */
6531 /* bit 31 - 16 (16 bit): EM style graphic
6532 bit 15 - 12 ( 4 bit): EM style frame
6533 bit 11 - 6 ( 6 bit): graphic width
6534 bit 5 - 0 ( 6 bit): graphic height */
6535 g_em->unique_identifier =
6536 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
6540 /* skip check for EMC elements not contained in original EMC artwork */
6541 if (element == EL_EMC_FAKE_ACID)
6544 if (g_em->bitmap != debug_bitmap ||
6545 g_em->src_x != debug_src_x ||
6546 g_em->src_y != debug_src_y ||
6547 g_em->src_offset_x != 0 ||
6548 g_em->src_offset_y != 0 ||
6549 g_em->dst_offset_x != 0 ||
6550 g_em->dst_offset_y != 0 ||
6551 g_em->width != TILEX ||
6552 g_em->height != TILEY)
6554 static int last_i = -1;
6562 printf("::: EMC GFX ERROR for element %d -> %d ('%s', '%s', %d)",
6563 i, element, element_info[element].token_name,
6564 element_action_info[effective_action].suffix, direction);
6566 if (element != effective_element)
6567 printf(" [%d ('%s')]",
6569 element_info[effective_element].token_name);
6573 if (g_em->bitmap != debug_bitmap)
6574 printf(" %d (%d): different bitmap! (0x%08x != 0x%08x)\n",
6575 j, is_backside, (int)(g_em->bitmap), (int)(debug_bitmap));
6577 if (g_em->src_x != debug_src_x ||
6578 g_em->src_y != debug_src_y)
6579 printf(" frame %d (%c): %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
6580 j, (is_backside ? 'B' : 'F'),
6581 g_em->src_x, g_em->src_y,
6582 g_em->src_x / 32, g_em->src_y / 32,
6583 debug_src_x, debug_src_y,
6584 debug_src_x / 32, debug_src_y / 32);
6586 if (g_em->src_offset_x != 0 ||
6587 g_em->src_offset_y != 0 ||
6588 g_em->dst_offset_x != 0 ||
6589 g_em->dst_offset_y != 0)
6590 printf(" %d (%d): offsets %d,%d and %d,%d should be all 0\n",
6592 g_em->src_offset_x, g_em->src_offset_y,
6593 g_em->dst_offset_x, g_em->dst_offset_y);
6595 if (g_em->width != TILEX ||
6596 g_em->height != TILEY)
6597 printf(" %d (%d): size %d,%d should be %d,%d\n",
6599 g_em->width, g_em->height, TILEX, TILEY);
6601 num_em_gfx_errors++;
6608 for (i = 0; i < TILE_MAX; i++)
6610 for (j = 0; j < 8; j++)
6612 int element = object_mapping[i].element_rnd;
6613 int action = object_mapping[i].action;
6614 int direction = object_mapping[i].direction;
6615 boolean is_backside = object_mapping[i].is_backside;
6616 int graphic_action = el_act_dir2img(element, action, direction);
6617 int graphic_default = el_act_dir2img(element, ACTION_DEFAULT, direction);
6619 if ((action == ACTION_SMASHED_BY_ROCK ||
6620 action == ACTION_SMASHED_BY_SPRING ||
6621 action == ACTION_EATING) &&
6622 graphic_action == graphic_default)
6624 int e = (action == ACTION_SMASHED_BY_ROCK ? Ystone_s :
6625 action == ACTION_SMASHED_BY_SPRING ? Yspring_s :
6626 direction == MV_LEFT ? (is_backside? Yspring_wB: Yspring_w) :
6627 direction == MV_RIGHT ? (is_backside? Yspring_eB: Yspring_e) :
6630 /* no separate animation for "smashed by rock" -- use rock instead */
6631 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
6632 struct GraphicInfo_EM *g_xx = &graphic_info_em_object[e][7 - j];
6634 g_em->bitmap = g_xx->bitmap;
6635 g_em->src_x = g_xx->src_x;
6636 g_em->src_y = g_xx->src_y;
6637 g_em->src_offset_x = g_xx->src_offset_x;
6638 g_em->src_offset_y = g_xx->src_offset_y;
6639 g_em->dst_offset_x = g_xx->dst_offset_x;
6640 g_em->dst_offset_y = g_xx->dst_offset_y;
6641 g_em->width = g_xx->width;
6642 g_em->height = g_xx->height;
6643 g_em->unique_identifier = g_xx->unique_identifier;
6646 g_em->preserve_background = TRUE;
6651 for (p = 0; p < MAX_PLAYERS; p++)
6653 for (i = 0; i < SPR_MAX; i++)
6655 int element = player_mapping[p][i].element_rnd;
6656 int action = player_mapping[p][i].action;
6657 int direction = player_mapping[p][i].direction;
6659 for (j = 0; j < 8; j++)
6661 int effective_element = element;
6662 int effective_action = action;
6663 int graphic = (direction == MV_NONE ?
6664 el_act2img(effective_element, effective_action) :
6665 el_act_dir2img(effective_element, effective_action,
6667 struct GraphicInfo *g = &graphic_info[graphic];
6668 struct GraphicInfo_EM *g_em = &graphic_info_em_player[p][i][7 - j];
6674 Bitmap *debug_bitmap = g_em->bitmap;
6675 int debug_src_x = g_em->src_x;
6676 int debug_src_y = g_em->src_y;
6679 int frame = getAnimationFrame(g->anim_frames,
6682 g->anim_start_frame,
6685 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
6687 g_em->bitmap = src_bitmap;
6688 g_em->src_x = src_x;
6689 g_em->src_y = src_y;
6690 g_em->src_offset_x = 0;
6691 g_em->src_offset_y = 0;
6692 g_em->dst_offset_x = 0;
6693 g_em->dst_offset_y = 0;
6694 g_em->width = TILEX;
6695 g_em->height = TILEY;
6699 /* skip check for EMC elements not contained in original EMC artwork */
6700 if (element == EL_PLAYER_3 ||
6701 element == EL_PLAYER_4)
6704 if (g_em->bitmap != debug_bitmap ||
6705 g_em->src_x != debug_src_x ||
6706 g_em->src_y != debug_src_y)
6708 static int last_i = -1;
6716 printf("::: EMC GFX ERROR for p/a %d/%d -> %d ('%s', '%s', %d)",
6717 p, i, element, element_info[element].token_name,
6718 element_action_info[effective_action].suffix, direction);
6720 if (element != effective_element)
6721 printf(" [%d ('%s')]",
6723 element_info[effective_element].token_name);
6727 if (g_em->bitmap != debug_bitmap)
6728 printf(" %d: different bitmap! (0x%08x != 0x%08x)\n",
6729 j, (int)(g_em->bitmap), (int)(debug_bitmap));
6731 if (g_em->src_x != debug_src_x ||
6732 g_em->src_y != debug_src_y)
6733 printf(" frame %d: %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
6735 g_em->src_x, g_em->src_y,
6736 g_em->src_x / 32, g_em->src_y / 32,
6737 debug_src_x, debug_src_y,
6738 debug_src_x / 32, debug_src_y / 32);
6740 num_em_gfx_errors++;
6750 printf("::: [%d errors found]\n", num_em_gfx_errors);
6756 void PlayMenuSoundExt(int sound)
6758 if (sound == SND_UNDEFINED)
6761 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
6762 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
6765 if (IS_LOOP_SOUND(sound))
6766 PlaySoundLoop(sound);
6771 void PlayMenuSound()
6773 PlayMenuSoundExt(menu.sound[game_status]);
6776 void PlayMenuSoundStereo(int sound, int stereo_position)
6778 if (sound == SND_UNDEFINED)
6781 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
6782 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
6785 if (IS_LOOP_SOUND(sound))
6786 PlaySoundExt(sound, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_LOOP);
6788 PlaySoundStereo(sound, stereo_position);
6791 void PlayMenuSoundIfLoopExt(int sound)
6793 if (sound == SND_UNDEFINED)
6796 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
6797 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
6800 if (IS_LOOP_SOUND(sound))
6801 PlaySoundLoop(sound);
6804 void PlayMenuSoundIfLoop()
6806 PlayMenuSoundIfLoopExt(menu.sound[game_status]);
6809 void PlayMenuMusicExt(int music)
6811 if (music == MUS_UNDEFINED)
6814 if (!setup.sound_music)
6820 void PlayMenuMusic()
6822 PlayMenuMusicExt(menu.music[game_status]);
6825 void PlaySoundActivating()
6828 PlaySound(SND_MENU_ITEM_ACTIVATING);
6832 void PlaySoundSelecting()
6835 PlaySound(SND_MENU_ITEM_SELECTING);
6839 void ToggleFullscreenIfNeeded()
6841 boolean change_fullscreen = (setup.fullscreen !=
6842 video.fullscreen_enabled);
6843 boolean change_fullscreen_mode = (video.fullscreen_enabled &&
6844 !strEqual(setup.fullscreen_mode,
6845 video.fullscreen_mode_current));
6847 if (!video.fullscreen_available)
6851 if (change_fullscreen || change_fullscreen_mode)
6853 if (setup.fullscreen != video.fullscreen_enabled ||
6854 setup.fullscreen_mode != video.fullscreen_mode_current)
6857 Bitmap *tmp_backbuffer = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
6859 /* save backbuffer content which gets lost when toggling fullscreen mode */
6860 BlitBitmap(backbuffer, tmp_backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
6863 if (change_fullscreen_mode)
6865 if (setup.fullscreen && video.fullscreen_enabled)
6868 /* keep fullscreen, but change fullscreen mode (screen resolution) */
6870 /* (this is now set in sdl.c) */
6872 video.fullscreen_mode_current = setup.fullscreen_mode;
6874 video.fullscreen_enabled = FALSE; /* force new fullscreen mode */
6877 /* toggle fullscreen */
6878 ChangeVideoModeIfNeeded(setup.fullscreen);
6880 setup.fullscreen = video.fullscreen_enabled;
6882 /* restore backbuffer content from temporary backbuffer backup bitmap */
6883 BlitBitmap(tmp_backbuffer, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
6885 FreeBitmap(tmp_backbuffer);
6888 /* update visible window/screen */
6889 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
6891 redraw_mask = REDRAW_ALL;