1 /***********************************************************
2 * Rocks'n'Diamonds -- McDuffin Strikes Back! *
3 *----------------------------------------------------------*
4 * (c) 1995-2006 Artsoft Entertainment *
6 * Detmolder Strasse 189 *
9 * e-mail: info@artsoft.org *
10 *----------------------------------------------------------*
12 ***********************************************************/
14 #include "libgame/libgame.h"
25 /* select level set with EMC X11 graphics before activating EM GFX debugging */
26 #define DEBUG_EM_GFX 0
28 /* tool button identifiers */
29 #define TOOL_CTRL_ID_YES 0
30 #define TOOL_CTRL_ID_NO 1
31 #define TOOL_CTRL_ID_CONFIRM 2
32 #define TOOL_CTRL_ID_PLAYER_1 3
33 #define TOOL_CTRL_ID_PLAYER_2 4
34 #define TOOL_CTRL_ID_PLAYER_3 5
35 #define TOOL_CTRL_ID_PLAYER_4 6
37 #define NUM_TOOL_BUTTONS 7
39 /* forward declaration for internal use */
40 static void UnmapToolButtons();
41 static void HandleToolButtons(struct GadgetInfo *);
42 static int el_act_dir2crm(int, int, int);
43 static int el_act2crm(int, int);
45 static struct GadgetInfo *tool_gadget[NUM_TOOL_BUTTONS];
46 static int request_gadget_id = -1;
48 static char *print_if_not_empty(int element)
50 static char *s = NULL;
51 char *token_name = element_info[element].token_name;
56 s = checked_malloc(strlen(token_name) + 10 + 1);
58 if (element != EL_EMPTY)
59 sprintf(s, "%d\t['%s']", element, token_name);
61 sprintf(s, "%d", element);
66 void DumpTile(int x, int y)
71 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
78 printf("Field Info: SCREEN(%d, %d), LEVEL(%d, %d)\n", sx, sy, x, y);
81 if (!IN_LEV_FIELD(x, y))
83 printf("(not in level field)\n");
89 printf(" Feld: %d\t['%s']\n", Feld[x][y],
90 element_info[Feld[x][y]].token_name);
91 printf(" Back: %s\n", print_if_not_empty(Back[x][y]));
92 printf(" Store: %s\n", print_if_not_empty(Store[x][y]));
93 printf(" Store2: %s\n", print_if_not_empty(Store2[x][y]));
94 printf(" StorePlayer: %s\n", print_if_not_empty(StorePlayer[x][y]));
95 printf(" MovPos: %d\n", MovPos[x][y]);
96 printf(" MovDir: %d\n", MovDir[x][y]);
97 printf(" MovDelay: %d\n", MovDelay[x][y]);
98 printf(" ChangeDelay: %d\n", ChangeDelay[x][y]);
99 printf(" CustomValue: %d\n", CustomValue[x][y]);
100 printf(" GfxElement: %d\n", GfxElement[x][y]);
101 printf(" GfxAction: %d\n", GfxAction[x][y]);
102 printf(" GfxFrame: %d\n", GfxFrame[x][y]);
106 void SetDrawtoField(int mode)
108 if (mode == DRAW_BUFFERED && setup.soft_scrolling)
119 drawto_field = fieldbuffer;
121 else /* DRAW_DIRECT, DRAW_BACKBUFFER */
127 BX2 = SCR_FIELDX - 1;
128 BY2 = SCR_FIELDY - 1;
132 drawto_field = (mode == DRAW_DIRECT ? window : backbuffer);
136 void RedrawPlayfield(boolean force_redraw, int x, int y, int width, int height)
138 if (game_status == GAME_MODE_PLAYING &&
139 level.game_engine_type == GAME_ENGINE_TYPE_EM)
141 /* currently there is no partial redraw -- always redraw whole playfield */
142 RedrawPlayfield_EM(TRUE);
144 /* blit playfield from scroll buffer to normal back buffer for fading in */
145 BlitScreenToBitmap_EM(backbuffer);
147 else if (game_status == GAME_MODE_PLAYING && !game.envelope_active)
153 width = gfx.sxsize + 2 * TILEX;
154 height = gfx.sysize + 2 * TILEY;
157 if (force_redraw || setup.direct_draw)
160 int x1 = (x - SX) / TILEX, y1 = (y - SY) / TILEY;
161 int x2 = (x - SX + width) / TILEX, y2 = (y - SY + height) / TILEY;
163 if (setup.direct_draw)
164 SetDrawtoField(DRAW_BACKBUFFER);
166 for (xx = BX1; xx <= BX2; xx++)
167 for (yy = BY1; yy <= BY2; yy++)
168 if (xx >= x1 && xx <= x2 && yy >= y1 && yy <= y2)
169 DrawScreenField(xx, yy);
172 if (setup.direct_draw)
173 SetDrawtoField(DRAW_DIRECT);
176 if (setup.soft_scrolling)
178 int fx = FX, fy = FY;
180 fx += (ScreenMovDir & (MV_LEFT|MV_RIGHT) ? ScreenGfxPos : 0);
181 fy += (ScreenMovDir & (MV_UP|MV_DOWN) ? ScreenGfxPos : 0);
183 BlitBitmap(fieldbuffer, backbuffer, fx,fy, SXSIZE,SYSIZE, SX,SY);
195 BlitBitmap(drawto, window, x, y, width, height, x, y);
198 void DrawMaskedBorder_Rect(int x, int y, int width, int height)
200 Bitmap *bitmap = graphic_info[IMG_GLOBAL_BORDER].bitmap;
202 SetClipOrigin(bitmap, bitmap->stored_clip_gc, 0, 0);
203 BlitBitmapMasked(bitmap, backbuffer, x, y, width, height, x, y);
206 void DrawMaskedBorder_FIELD()
208 if (global.border_status >= GAME_MODE_TITLE &&
209 global.border_status <= GAME_MODE_PLAYING &&
210 border.draw_masked[global.border_status])
211 DrawMaskedBorder_Rect(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
214 void DrawMaskedBorder_DOOR_1()
216 if (border.draw_masked[GFX_SPECIAL_ARG_DOOR] &&
217 (global.border_status != GAME_MODE_EDITOR ||
218 border.draw_masked[GFX_SPECIAL_ARG_EDITOR]))
219 DrawMaskedBorder_Rect(DX, DY, DXSIZE, DYSIZE);
222 void DrawMaskedBorder_DOOR_2()
224 if (border.draw_masked[GFX_SPECIAL_ARG_DOOR] &&
225 global.border_status != GAME_MODE_EDITOR)
226 DrawMaskedBorder_Rect(VX, VY, VXSIZE, VYSIZE);
229 void DrawMaskedBorder_DOOR_3()
231 /* currently not available */
234 void DrawMaskedBorder_ALL()
236 DrawMaskedBorder_FIELD();
237 DrawMaskedBorder_DOOR_1();
238 DrawMaskedBorder_DOOR_2();
239 DrawMaskedBorder_DOOR_3();
242 void DrawMaskedBorder(int redraw_mask)
244 /* do not draw masked screen borders when displaying title screens */
245 if (effectiveGameStatus() == GAME_MODE_TITLE)
248 if (redraw_mask & REDRAW_ALL)
249 DrawMaskedBorder_ALL();
252 if (redraw_mask & REDRAW_FIELD)
253 DrawMaskedBorder_FIELD();
254 if (redraw_mask & REDRAW_DOOR_1)
255 DrawMaskedBorder_DOOR_1();
256 if (redraw_mask & REDRAW_DOOR_2)
257 DrawMaskedBorder_DOOR_2();
258 if (redraw_mask & REDRAW_DOOR_3)
259 DrawMaskedBorder_DOOR_3();
266 DrawBuffer *buffer = (drawto_field == window ? backbuffer : drawto_field);
268 if (setup.direct_draw && game_status == GAME_MODE_PLAYING)
269 redraw_mask &= ~REDRAW_MAIN;
271 if (redraw_mask & REDRAW_TILES && redraw_tiles > REDRAWTILES_THRESHOLD)
272 redraw_mask |= REDRAW_FIELD;
274 if (redraw_mask & REDRAW_FIELD)
275 redraw_mask &= ~REDRAW_TILES;
277 if (redraw_mask == REDRAW_NONE)
280 if (redraw_mask & REDRAW_TILES &&
281 game_status == GAME_MODE_PLAYING &&
282 border.draw_masked[GAME_MODE_PLAYING])
283 redraw_mask |= REDRAW_FIELD;
285 if (global.fps_slowdown && game_status == GAME_MODE_PLAYING)
287 static boolean last_frame_skipped = FALSE;
288 boolean skip_even_when_not_scrolling = TRUE;
289 boolean just_scrolling = (ScreenMovDir != 0);
290 boolean verbose = FALSE;
292 if (global.fps_slowdown_factor > 1 &&
293 (FrameCounter % global.fps_slowdown_factor) &&
294 (just_scrolling || skip_even_when_not_scrolling))
296 redraw_mask &= ~REDRAW_MAIN;
298 last_frame_skipped = TRUE;
301 printf("FRAME SKIPPED\n");
305 if (last_frame_skipped)
306 redraw_mask |= REDRAW_FIELD;
308 last_frame_skipped = FALSE;
311 printf("frame not skipped\n");
315 /* synchronize X11 graphics at this point; if we would synchronize the
316 display immediately after the buffer switching (after the XFlush),
317 this could mean that we have to wait for the graphics to complete,
318 although we could go on doing calculations for the next frame */
322 /* prevent drawing masked border to backbuffer when using playfield buffer */
323 if (game_status != GAME_MODE_PLAYING ||
324 redraw_mask & REDRAW_FROM_BACKBUFFER ||
325 buffer == backbuffer)
326 DrawMaskedBorder(redraw_mask);
328 DrawMaskedBorder(redraw_mask & REDRAW_DOORS);
330 if (redraw_mask & REDRAW_ALL)
332 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
334 redraw_mask = REDRAW_NONE;
337 if (redraw_mask & REDRAW_FIELD)
339 if (game_status != GAME_MODE_PLAYING ||
340 redraw_mask & REDRAW_FROM_BACKBUFFER)
342 BlitBitmap(backbuffer, window,
343 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE, REAL_SX, REAL_SY);
347 int fx = FX, fy = FY;
349 if (setup.soft_scrolling)
351 fx += (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
352 fy += (ScreenMovDir & (MV_UP | MV_DOWN) ? ScreenGfxPos : 0);
355 if (setup.soft_scrolling ||
356 ABS(ScreenMovPos) + ScrollStepSize == TILEX ||
357 ABS(ScreenMovPos) == ScrollStepSize ||
358 redraw_tiles > REDRAWTILES_THRESHOLD)
360 if (border.draw_masked[GAME_MODE_PLAYING])
362 if (buffer != backbuffer)
364 /* copy playfield buffer to backbuffer to add masked border */
365 BlitBitmap(buffer, backbuffer, fx, fy, SXSIZE, SYSIZE, SX, SY);
366 DrawMaskedBorder(REDRAW_FIELD);
369 BlitBitmap(backbuffer, window,
370 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
375 BlitBitmap(buffer, window, fx, fy, SXSIZE, SYSIZE, SX, SY);
380 printf("redrawing all (ScreenGfxPos == %d) because %s\n",
382 (setup.soft_scrolling ?
383 "setup.soft_scrolling" :
384 ABS(ScreenGfxPos) + ScrollStepSize == TILEX ?
385 "ABS(ScreenGfxPos) + ScrollStepSize == TILEX" :
386 ABS(ScreenGfxPos) == ScrollStepSize ?
387 "ABS(ScreenGfxPos) == ScrollStepSize" :
388 "redraw_tiles > REDRAWTILES_THRESHOLD"));
394 redraw_mask &= ~REDRAW_MAIN;
397 if (redraw_mask & REDRAW_DOORS)
399 if (redraw_mask & REDRAW_DOOR_1)
400 BlitBitmap(backbuffer, window, DX, DY, DXSIZE, DYSIZE, DX, DY);
402 if (redraw_mask & REDRAW_DOOR_2)
403 BlitBitmap(backbuffer, window, VX, VY, VXSIZE, VYSIZE, VX, VY);
405 if (redraw_mask & REDRAW_DOOR_3)
406 BlitBitmap(backbuffer, window, EX, EY, EXSIZE, EYSIZE, EX, EY);
408 redraw_mask &= ~REDRAW_DOORS;
411 if (redraw_mask & REDRAW_MICROLEVEL)
413 BlitBitmap(backbuffer, window, SX, SY + 10 * TILEY, SXSIZE, 7 * TILEY,
414 SX, SY + 10 * TILEY);
416 redraw_mask &= ~REDRAW_MICROLEVEL;
419 if (redraw_mask & REDRAW_TILES)
421 for (x = 0; x < SCR_FIELDX; x++)
422 for (y = 0 ; y < SCR_FIELDY; y++)
423 if (redraw[redraw_x1 + x][redraw_y1 + y])
424 BlitBitmap(buffer, window,
425 FX + x * TILEX, FY + y * TILEY, TILEX, TILEY,
426 SX + x * TILEX, SY + y * TILEY);
429 if (redraw_mask & REDRAW_FPS) /* display frames per second */
434 sprintf(info1, " (only every %d. frame)", global.fps_slowdown_factor);
435 if (!global.fps_slowdown)
438 sprintf(text, "%.1f fps%s", global.frames_per_second, info1);
439 DrawTextExt(window, SX, SY, text, FONT_TEXT_2, BLIT_OPAQUE);
444 for (x = 0; x < MAX_BUF_XSIZE; x++)
445 for (y = 0; y < MAX_BUF_YSIZE; y++)
448 redraw_mask = REDRAW_NONE;
451 static void FadeCrossSaveBackbuffer()
453 BlitBitmap(backbuffer, bitmap_db_cross, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
456 static void FadeExt(int fade_mask, int fade_mode, int fade_type)
458 static int fade_type_skip = FADE_TYPE_NONE;
459 void (*draw_border_function)(void) = NULL;
460 Bitmap *bitmap = (fade_mode & FADE_TYPE_TRANSFORM ? bitmap_db_cross : NULL);
461 int x, y, width, height;
462 int fade_delay, post_delay;
464 if (fade_type == FADE_TYPE_FADE_OUT)
466 if (fade_type_skip != FADE_TYPE_NONE)
469 printf("::: skipping %d ... [%d] (X)\n", fade_mode, fade_type_skip);
472 /* skip all fade operations until specified fade operation */
473 if (fade_type & fade_type_skip)
474 fade_type_skip = FADE_TYPE_NONE;
479 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
480 FadeCrossSaveBackbuffer();
485 redraw_mask |= fade_mask;
487 if (fade_type == FADE_TYPE_SKIP)
490 printf("::: will skip %d ... [%d]\n", fade_mode, fade_type_skip);
493 fade_type_skip = fade_mode;
498 if (fade_type_skip != FADE_TYPE_NONE)
501 printf("::: skipping %d ... [%d]\n", fade_mode, fade_type_skip);
504 /* skip all fade operations until specified fade operation */
505 if (fade_type & fade_type_skip)
506 fade_type_skip = FADE_TYPE_NONE;
512 if (global.autoplay_leveldir)
514 // fading.fade_mode = FADE_MODE_NONE;
521 if (fading.fade_mode == FADE_MODE_NONE)
529 /* !!! what abount fade_mask == REDRAW_FIELD | REDRAW_ALL ??? !!! */
532 printf("::: NOW FADING %d ... [%d]\n", fade_mode, fade_type);
535 if (fade_mask & REDRAW_FIELD)
540 height = FULL_SYSIZE;
542 fade_delay = fading.fade_delay;
543 post_delay = (fade_mode == FADE_MODE_FADE_OUT ? fading.post_delay : 0);
545 if (border.draw_masked_when_fading)
546 draw_border_function = DrawMaskedBorder_FIELD; /* update when fading */
548 DrawMaskedBorder_FIELD(); /* draw once */
550 else /* REDRAW_ALL */
557 fade_delay = fading.fade_delay;
558 post_delay = (fade_mode == FADE_MODE_FADE_OUT ? fading.post_delay : 0);
562 if (!setup.fade_screens || fade_delay == 0)
564 if (!setup.fade_screens || fade_delay == 0 || fading.anim_mode == ANIM_NONE)
567 if (fade_mode == FADE_MODE_FADE_OUT)
568 ClearRectangle(backbuffer, x, y, width, height);
575 FadeRectangle(bitmap, x, y, width, height, fade_mode, fade_delay, post_delay,
576 draw_border_function);
578 redraw_mask &= ~fade_mask;
581 void FadeIn(int fade_mask)
584 global.border_status = game_status;
588 // printf("::: now fading in...\n");
590 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
591 FadeExt(fade_mask, fading.fade_mode, FADE_TYPE_FADE_IN);
593 FadeExt(fade_mask, FADE_MODE_FADE_IN, FADE_TYPE_FADE_IN);
596 if (fading.fade_mode == FADE_MODE_CROSSFADE)
597 FadeExt(fade_mask, FADE_MODE_CROSSFADE);
599 FadeExt(fade_mask, FADE_MODE_FADE_IN);
601 FadeExt(fade_mask, FADE_MODE_FADE_IN);
606 void FadeOut(int fade_mask)
609 // printf("::: fading.fade_mode == %d\n", fading.fade_mode);
612 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
613 FadeExt(fade_mask, fading.fade_mode, FADE_TYPE_FADE_OUT);
615 FadeExt(fade_mask, FADE_MODE_FADE_OUT, FADE_TYPE_FADE_OUT);
617 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
618 FadeCrossSaveBackbuffer();
620 FadeExt(fade_mask, FADE_MODE_FADE_OUT, FADE_TYPE_FADE_OUT);
625 if (fading.fade_mode == FADE_MODE_CROSSFADE)
626 FadeCrossSaveBackbuffer();
628 FadeExt(fade_mask, FADE_MODE_FADE_OUT);
630 FadeExt(fade_mask, FADE_MODE_FADE_OUT);
635 global.border_status = game_status;
640 void FadeCross(int fade_mask)
642 FadeExt(fade_mask, FADE_MODE_CROSSFADE);
646 static void FadeSetLeaveNext(struct TitleFadingInfo fading_leave, boolean set)
648 static struct TitleFadingInfo fading_leave_stored;
651 fading_leave_stored = fading_leave;
653 fading = fading_leave_stored;
656 void FadeSetEnterMenu()
658 fading = menu.enter_menu;
661 printf("::: storing enter_menu\n");
664 FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
667 void FadeSetLeaveMenu()
669 fading = menu.leave_menu;
672 printf("::: storing leave_menu\n");
675 FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
678 void FadeSetEnterScreen()
680 fading = menu.enter_screen[game_status];
683 printf("::: storing leave_screen[%d]\n", game_status);
686 FadeSetLeaveNext(menu.leave_screen[game_status], TRUE); /* store */
689 void FadeSetNextScreen()
691 fading = menu.next_screen;
694 printf("::: storing next_screen\n");
697 // (do not overwrite fade mode set by FadeSetEnterScreen)
698 // FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
701 void FadeSetLeaveScreen()
704 printf("::: recalling last stored value\n");
707 FadeSetLeaveNext(menu.leave_screen[game_status], FALSE); /* recall */
710 void FadeSetFromType(int type)
712 if (type & TYPE_ENTER_SCREEN)
713 FadeSetEnterScreen();
714 else if (type & TYPE_ENTER)
716 else if (type & TYPE_LEAVE)
720 void FadeSetDisabled()
722 static struct TitleFadingInfo fading_none = { FADE_MODE_NONE, -1, -1, -1 };
724 fading = fading_none;
727 void FadeSkipNextFadeIn()
729 FadeExt(0, FADE_MODE_SKIP_FADE_IN, FADE_TYPE_SKIP);
732 void FadeSkipNextFadeOut()
734 FadeExt(0, FADE_MODE_SKIP_FADE_OUT, FADE_TYPE_SKIP);
737 void SetWindowBackgroundImageIfDefined(int graphic)
739 if (graphic_info[graphic].bitmap)
740 SetWindowBackgroundBitmap(graphic_info[graphic].bitmap);
743 void SetMainBackgroundImageIfDefined(int graphic)
745 if (graphic_info[graphic].bitmap)
746 SetMainBackgroundBitmap(graphic_info[graphic].bitmap);
749 void SetDoorBackgroundImageIfDefined(int graphic)
751 if (graphic_info[graphic].bitmap)
752 SetDoorBackgroundBitmap(graphic_info[graphic].bitmap);
755 void SetWindowBackgroundImage(int graphic)
757 SetWindowBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
758 graphic_info[graphic].bitmap ?
759 graphic_info[graphic].bitmap :
760 graphic_info[IMG_BACKGROUND].bitmap);
763 void SetMainBackgroundImage(int graphic)
765 SetMainBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
766 graphic_info[graphic].bitmap ?
767 graphic_info[graphic].bitmap :
768 graphic_info[IMG_BACKGROUND].bitmap);
771 void SetDoorBackgroundImage(int graphic)
773 SetDoorBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
774 graphic_info[graphic].bitmap ?
775 graphic_info[graphic].bitmap :
776 graphic_info[IMG_BACKGROUND].bitmap);
779 void SetPanelBackground()
781 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, bitmap_db_panel,
782 DOOR_GFX_PAGEX5, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE, 0, 0);
784 SetDoorBackgroundBitmap(bitmap_db_panel);
787 void DrawBackground(int x, int y, int width, int height)
789 /* !!! "drawto" might still point to playfield buffer here (see below) !!! */
790 /* (when entering hall of fame after playing) */
792 ClearRectangleOnBackground(drawto, x, y, width, height);
794 ClearRectangleOnBackground(backbuffer, x, y, width, height);
797 redraw_mask |= REDRAW_FIELD;
800 void DrawBackgroundForFont(int x, int y, int width, int height, int font_nr)
802 struct FontBitmapInfo *font = getFontBitmapInfo(font_nr);
804 if (font->bitmap == NULL)
807 DrawBackground(x, y, width, height);
810 void DrawBackgroundForGraphic(int x, int y, int width, int height, int graphic)
812 struct GraphicInfo *g = &graphic_info[graphic];
814 if (g->bitmap == NULL)
817 DrawBackground(x, y, width, height);
822 /* !!! "drawto" might still point to playfield buffer here (see above) !!! */
823 /* (when entering hall of fame after playing) */
824 DrawBackground(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
826 /* !!! maybe this should be done before clearing the background !!! */
827 if (setup.soft_scrolling && game_status == GAME_MODE_PLAYING)
829 ClearRectangle(fieldbuffer, 0, 0, FXSIZE, FYSIZE);
830 SetDrawtoField(DRAW_BUFFERED);
833 SetDrawtoField(DRAW_BACKBUFFER);
835 if (setup.direct_draw && game_status == GAME_MODE_PLAYING)
837 ClearRectangle(window, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
838 SetDrawtoField(DRAW_DIRECT);
842 void MarkTileDirty(int x, int y)
844 int xx = redraw_x1 + x;
845 int yy = redraw_y1 + y;
850 redraw[xx][yy] = TRUE;
851 redraw_mask |= REDRAW_TILES;
854 void SetBorderElement()
858 BorderElement = EL_EMPTY;
860 for (y = 0; y < lev_fieldy && BorderElement == EL_EMPTY; y++)
862 for (x = 0; x < lev_fieldx; x++)
864 if (!IS_INDESTRUCTIBLE(Feld[x][y]))
865 BorderElement = EL_STEELWALL;
867 if (y != 0 && y != lev_fieldy - 1 && x != lev_fieldx - 1)
873 void FloodFillLevel(int from_x, int from_y, int fill_element,
874 short field[MAX_LEV_FIELDX][MAX_LEV_FIELDY],
875 int max_fieldx, int max_fieldy)
879 static int check[4][2] = { { -1, 0 }, { 0, -1 }, { 1, 0 }, { 0, 1 } };
880 static int safety = 0;
882 /* check if starting field still has the desired content */
883 if (field[from_x][from_y] == fill_element)
888 if (safety > max_fieldx * max_fieldy)
889 Error(ERR_EXIT, "Something went wrong in 'FloodFill()'. Please debug.");
891 old_element = field[from_x][from_y];
892 field[from_x][from_y] = fill_element;
894 for (i = 0; i < 4; i++)
896 x = from_x + check[i][0];
897 y = from_y + check[i][1];
899 if (IN_FIELD(x, y, max_fieldx, max_fieldy) && field[x][y] == old_element)
900 FloodFillLevel(x, y, fill_element, field, max_fieldx, max_fieldy);
906 void SetRandomAnimationValue(int x, int y)
908 gfx.anim_random_frame = GfxRandom[x][y];
911 inline int getGraphicAnimationFrame(int graphic, int sync_frame)
913 /* animation synchronized with global frame counter, not move position */
914 if (graphic_info[graphic].anim_global_sync || sync_frame < 0)
915 sync_frame = FrameCounter;
917 return getAnimationFrame(graphic_info[graphic].anim_frames,
918 graphic_info[graphic].anim_delay,
919 graphic_info[graphic].anim_mode,
920 graphic_info[graphic].anim_start_frame,
924 void getSizedGraphicSource(int graphic, int frame, int tilesize_raw,
925 Bitmap **bitmap, int *x, int *y)
929 int width_mult, width_div;
930 int height_mult, height_div;
934 { 15, 16, 2, 3 }, /* 1 x 1 */
935 { 7, 8, 2, 3 }, /* 2 x 2 */
936 { 3, 4, 2, 3 }, /* 4 x 4 */
937 { 1, 2, 2, 3 }, /* 8 x 8 */
938 { 0, 1, 2, 3 }, /* 16 x 16 */
939 { 0, 1, 0, 1 }, /* 32 x 32 */
941 struct GraphicInfo *g = &graphic_info[graphic];
942 Bitmap *src_bitmap = g->bitmap;
943 int tilesize = MIN(MAX(1, tilesize_raw), TILESIZE);
944 int offset_calc_pos = log_2(tilesize);
945 int width_mult = offset_calc[offset_calc_pos].width_mult;
946 int width_div = offset_calc[offset_calc_pos].width_div;
947 int height_mult = offset_calc[offset_calc_pos].height_mult;
948 int height_div = offset_calc[offset_calc_pos].height_div;
949 int startx = src_bitmap->width * width_mult / width_div;
950 int starty = src_bitmap->height * height_mult / height_div;
951 int src_x = g->src_x * tilesize / TILESIZE;
952 int src_y = g->src_y * tilesize / TILESIZE;
953 int width = g->width * tilesize / TILESIZE;
954 int height = g->height * tilesize / TILESIZE;
955 int offset_x = g->offset_x * tilesize / TILESIZE;
956 int offset_y = g->offset_y * tilesize / TILESIZE;
958 if (g->offset_y == 0) /* frames are ordered horizontally */
960 int max_width = g->anim_frames_per_line * width;
961 int pos = (src_y / height) * max_width + src_x + frame * offset_x;
963 src_x = pos % max_width;
964 src_y = src_y % height + pos / max_width * height;
966 else if (g->offset_x == 0) /* frames are ordered vertically */
968 int max_height = g->anim_frames_per_line * height;
969 int pos = (src_x / width) * max_height + src_y + frame * offset_y;
971 src_x = src_x % width + pos / max_height * width;
972 src_y = pos % max_height;
974 else /* frames are ordered diagonally */
976 src_x = src_x + frame * offset_x;
977 src_y = src_y + frame * offset_y;
980 *bitmap = src_bitmap;
985 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
988 getSizedGraphicSource(graphic, 0, MINI_TILESIZE, bitmap, x, y);
990 struct GraphicInfo *g = &graphic_info[graphic];
992 int mini_starty = g->bitmap->height * 2 / 3;
995 *x = mini_startx + g->src_x / 2;
996 *y = mini_starty + g->src_y / 2;
1000 inline void getGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
1001 int *x, int *y, boolean get_backside)
1003 struct GraphicInfo *g = &graphic_info[graphic];
1004 int src_x = g->src_x + (get_backside ? g->offset2_x : 0);
1005 int src_y = g->src_y + (get_backside ? g->offset2_y : 0);
1007 *bitmap = g->bitmap;
1009 if (g->offset_y == 0) /* frames are ordered horizontally */
1011 int max_width = g->anim_frames_per_line * g->width;
1012 int pos = (src_y / g->height) * max_width + src_x + frame * g->offset_x;
1014 *x = pos % max_width;
1015 *y = src_y % g->height + pos / max_width * g->height;
1017 else if (g->offset_x == 0) /* frames are ordered vertically */
1019 int max_height = g->anim_frames_per_line * g->height;
1020 int pos = (src_x / g->width) * max_height + src_y + frame * g->offset_y;
1022 *x = src_x % g->width + pos / max_height * g->width;
1023 *y = pos % max_height;
1025 else /* frames are ordered diagonally */
1027 *x = src_x + frame * g->offset_x;
1028 *y = src_y + frame * g->offset_y;
1032 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
1034 getGraphicSourceExt(graphic, frame, bitmap, x, y, FALSE);
1037 void DrawGraphic(int x, int y, int graphic, int frame)
1040 if (!IN_SCR_FIELD(x, y))
1042 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
1043 printf("DrawGraphic(): This should never happen!\n");
1048 DrawGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic, frame);
1049 MarkTileDirty(x, y);
1052 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
1058 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1059 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
1062 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
1065 if (!IN_SCR_FIELD(x, y))
1067 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
1068 printf("DrawGraphicThruMask(): This should never happen!\n");
1073 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y *TILEY, graphic,
1075 MarkTileDirty(x, y);
1078 void DrawGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y, int graphic,
1084 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1086 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1087 dst_x - src_x, dst_y - src_y);
1088 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dst_x, dst_y);
1091 void DrawSizedGraphic(int x, int y, int graphic, int frame, int tilesize)
1093 DrawSizedGraphicExt(drawto, SX + x * tilesize, SY + y * tilesize, graphic,
1095 MarkTileDirty(x / tilesize, y / tilesize);
1098 void DrawSizedGraphicExt(DrawBuffer *d, int x, int y, int graphic, int frame,
1104 getSizedGraphicSource(graphic, frame, tilesize, &src_bitmap, &src_x, &src_y);
1105 BlitBitmap(src_bitmap, d, src_x, src_y, tilesize, tilesize, x, y);
1108 void DrawMiniGraphic(int x, int y, int graphic)
1110 DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
1111 MarkTileDirty(x / 2, y / 2);
1114 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
1119 getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1120 BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
1123 inline static void DrawGraphicShiftedNormal(int x, int y, int dx, int dy,
1124 int graphic, int frame,
1125 int cut_mode, int mask_mode)
1130 int width = TILEX, height = TILEY;
1133 if (dx || dy) /* shifted graphic */
1135 if (x < BX1) /* object enters playfield from the left */
1142 else if (x > BX2) /* object enters playfield from the right */
1148 else if (x==BX1 && dx < 0) /* object leaves playfield to the left */
1154 else if (x==BX2 && dx > 0) /* object leaves playfield to the right */
1156 else if (dx) /* general horizontal movement */
1157 MarkTileDirty(x + SIGN(dx), y);
1159 if (y < BY1) /* object enters playfield from the top */
1161 if (cut_mode==CUT_BELOW) /* object completely above top border */
1169 else if (y > BY2) /* object enters playfield from the bottom */
1175 else if (y==BY1 && dy < 0) /* object leaves playfield to the top */
1181 else if (dy > 0 && cut_mode == CUT_ABOVE)
1183 if (y == BY2) /* object completely above bottom border */
1189 MarkTileDirty(x, y + 1);
1190 } /* object leaves playfield to the bottom */
1191 else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
1193 else if (dy) /* general vertical movement */
1194 MarkTileDirty(x, y + SIGN(dy));
1198 if (!IN_SCR_FIELD(x, y))
1200 printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
1201 printf("DrawGraphicShifted(): This should never happen!\n");
1206 if (width > 0 && height > 0)
1208 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1213 dst_x = FX + x * TILEX + dx;
1214 dst_y = FY + y * TILEY + dy;
1216 if (mask_mode == USE_MASKING)
1218 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1219 dst_x - src_x, dst_y - src_y);
1220 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1224 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1227 MarkTileDirty(x, y);
1231 inline static void DrawGraphicShiftedDouble(int x, int y, int dx, int dy,
1232 int graphic, int frame,
1233 int cut_mode, int mask_mode)
1238 int width = TILEX, height = TILEY;
1241 int x2 = x + SIGN(dx);
1242 int y2 = y + SIGN(dy);
1243 int anim_frames = graphic_info[graphic].anim_frames;
1244 int sync_frame = (dx ? ABS(dx) : ABS(dy)) * anim_frames / TILESIZE;
1245 boolean draw_start_tile = (cut_mode != CUT_ABOVE); /* only for falling! */
1246 boolean draw_end_tile = (cut_mode != CUT_BELOW); /* only for falling! */
1248 /* re-calculate animation frame for two-tile movement animation */
1249 frame = getGraphicAnimationFrame(graphic, sync_frame);
1251 /* check if movement start graphic inside screen area and should be drawn */
1252 if (draw_start_tile && IN_SCR_FIELD(x1, y1))
1254 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, TRUE);
1256 dst_x = FX + x1 * TILEX;
1257 dst_y = FY + y1 * TILEY;
1259 if (mask_mode == USE_MASKING)
1261 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1262 dst_x - src_x, dst_y - src_y);
1263 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1267 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1270 MarkTileDirty(x1, y1);
1273 /* check if movement end graphic inside screen area and should be drawn */
1274 if (draw_end_tile && IN_SCR_FIELD(x2, y2))
1276 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
1278 dst_x = FX + x2 * TILEX;
1279 dst_y = FY + y2 * TILEY;
1281 if (mask_mode == USE_MASKING)
1283 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1284 dst_x - src_x, dst_y - src_y);
1285 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1289 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1292 MarkTileDirty(x2, y2);
1296 static void DrawGraphicShifted(int x, int y, int dx, int dy,
1297 int graphic, int frame,
1298 int cut_mode, int mask_mode)
1302 DrawGraphic(x, y, graphic, frame);
1307 if (graphic_info[graphic].double_movement) /* EM style movement images */
1308 DrawGraphicShiftedDouble(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1310 DrawGraphicShiftedNormal(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1313 void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
1314 int frame, int cut_mode)
1316 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, USE_MASKING);
1319 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
1320 int cut_mode, int mask_mode)
1322 int lx = LEVELX(x), ly = LEVELY(y);
1326 if (IN_LEV_FIELD(lx, ly))
1328 SetRandomAnimationValue(lx, ly);
1330 graphic = el_act_dir2img(element, GfxAction[lx][ly], GfxDir[lx][ly]);
1331 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1333 /* do not use double (EM style) movement graphic when not moving */
1334 if (graphic_info[graphic].double_movement && !dx && !dy)
1336 graphic = el_act_dir2img(element, ACTION_DEFAULT, GfxDir[lx][ly]);
1337 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1340 else /* border element */
1342 graphic = el2img(element);
1343 frame = getGraphicAnimationFrame(graphic, -1);
1346 if (element == EL_EXPANDABLE_WALL)
1348 boolean left_stopped = FALSE, right_stopped = FALSE;
1350 if (!IN_LEV_FIELD(lx - 1, ly) || IS_WALL(Feld[lx - 1][ly]))
1351 left_stopped = TRUE;
1352 if (!IN_LEV_FIELD(lx + 1, ly) || IS_WALL(Feld[lx + 1][ly]))
1353 right_stopped = TRUE;
1355 if (left_stopped && right_stopped)
1357 else if (left_stopped)
1359 graphic = IMG_EXPANDABLE_WALL_GROWING_RIGHT;
1360 frame = graphic_info[graphic].anim_frames - 1;
1362 else if (right_stopped)
1364 graphic = IMG_EXPANDABLE_WALL_GROWING_LEFT;
1365 frame = graphic_info[graphic].anim_frames - 1;
1370 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
1371 else if (mask_mode == USE_MASKING)
1372 DrawGraphicThruMask(x, y, graphic, frame);
1374 DrawGraphic(x, y, graphic, frame);
1377 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
1378 int cut_mode, int mask_mode)
1380 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1381 DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
1382 cut_mode, mask_mode);
1385 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
1388 DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1391 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
1394 DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1397 void DrawLevelElementThruMask(int x, int y, int element)
1399 DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1402 void DrawLevelFieldThruMask(int x, int y)
1404 DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
1407 static void DrawLevelFieldCrumbledSandExt(int x, int y, int graphic, int frame)
1411 int sx = SCREENX(x), sy = SCREENY(y);
1413 int width, height, cx, cy, i;
1414 int crumbled_border_size = graphic_info[graphic].border_size;
1415 static int xy[4][2] =
1423 if (!IN_LEV_FIELD(x, y))
1426 element = TILE_GFX_ELEMENT(x, y);
1428 /* crumble field itself */
1429 if (GFX_CRUMBLED(element) && !IS_MOVING(x, y))
1431 if (!IN_SCR_FIELD(sx, sy))
1434 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1436 for (i = 0; i < 4; i++)
1438 int xx = x + xy[i][0];
1439 int yy = y + xy[i][1];
1441 element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1444 /* check if neighbour field is of same type */
1445 if (GFX_CRUMBLED(element) && !IS_MOVING(xx, yy))
1448 if (i == 1 || i == 2)
1450 width = crumbled_border_size;
1452 cx = (i == 2 ? TILEX - crumbled_border_size : 0);
1458 height = crumbled_border_size;
1460 cy = (i == 3 ? TILEY - crumbled_border_size : 0);
1463 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1464 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
1467 MarkTileDirty(sx, sy);
1469 else /* crumble neighbour fields */
1471 for (i = 0; i < 4; i++)
1473 int xx = x + xy[i][0];
1474 int yy = y + xy[i][1];
1475 int sxx = sx + xy[i][0];
1476 int syy = sy + xy[i][1];
1478 if (!IN_LEV_FIELD(xx, yy) ||
1479 !IN_SCR_FIELD(sxx, syy) ||
1483 if (Feld[xx][yy] == EL_ELEMENT_SNAPPING)
1486 element = TILE_GFX_ELEMENT(xx, yy);
1488 if (!GFX_CRUMBLED(element))
1491 graphic = el_act2crm(element, ACTION_DEFAULT);
1492 crumbled_border_size = graphic_info[graphic].border_size;
1494 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1496 if (i == 1 || i == 2)
1498 width = crumbled_border_size;
1500 cx = (i == 1 ? TILEX - crumbled_border_size : 0);
1506 height = crumbled_border_size;
1508 cy = (i == 0 ? TILEY - crumbled_border_size : 0);
1511 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1512 width, height, FX + sxx * TILEX + cx, FY + syy * TILEY + cy);
1514 MarkTileDirty(sxx, syy);
1519 void DrawLevelFieldCrumbledSand(int x, int y)
1523 if (!IN_LEV_FIELD(x, y))
1527 /* !!! CHECK THIS !!! */
1530 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
1531 GFX_CRUMBLED(GfxElement[x][y]))
1534 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
1535 GfxElement[x][y] != EL_UNDEFINED &&
1536 GFX_CRUMBLED(GfxElement[x][y]))
1538 DrawLevelFieldCrumbledSandDigging(x, y, GfxDir[x][y], GfxFrame[x][y]);
1545 graphic = el_act2crm(TILE_GFX_ELEMENT(x, y), ACTION_DEFAULT);
1547 graphic = el_act2crm(Feld[x][y], ACTION_DEFAULT);
1550 DrawLevelFieldCrumbledSandExt(x, y, graphic, 0);
1553 void DrawLevelFieldCrumbledSandDigging(int x, int y, int direction,
1556 int graphic1 = el_act_dir2img(GfxElement[x][y], ACTION_DIGGING, direction);
1557 int graphic2 = el_act_dir2crm(GfxElement[x][y], ACTION_DIGGING, direction);
1558 int frame1 = getGraphicAnimationFrame(graphic1, step_frame);
1559 int frame2 = getGraphicAnimationFrame(graphic2, step_frame);
1560 int sx = SCREENX(x), sy = SCREENY(y);
1562 DrawGraphic(sx, sy, graphic1, frame1);
1563 DrawLevelFieldCrumbledSandExt(x, y, graphic2, frame2);
1566 void DrawLevelFieldCrumbledSandNeighbours(int x, int y)
1568 int sx = SCREENX(x), sy = SCREENY(y);
1569 static int xy[4][2] =
1578 for (i = 0; i < 4; i++)
1580 int xx = x + xy[i][0];
1581 int yy = y + xy[i][1];
1582 int sxx = sx + xy[i][0];
1583 int syy = sy + xy[i][1];
1585 if (!IN_LEV_FIELD(xx, yy) ||
1586 !IN_SCR_FIELD(sxx, syy) ||
1587 !GFX_CRUMBLED(Feld[xx][yy]) ||
1591 DrawLevelField(xx, yy);
1595 static int getBorderElement(int x, int y)
1599 { EL_STEELWALL_TOPLEFT, EL_INVISIBLE_STEELWALL_TOPLEFT },
1600 { EL_STEELWALL_TOPRIGHT, EL_INVISIBLE_STEELWALL_TOPRIGHT },
1601 { EL_STEELWALL_BOTTOMLEFT, EL_INVISIBLE_STEELWALL_BOTTOMLEFT },
1602 { EL_STEELWALL_BOTTOMRIGHT, EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
1603 { EL_STEELWALL_VERTICAL, EL_INVISIBLE_STEELWALL_VERTICAL },
1604 { EL_STEELWALL_HORIZONTAL, EL_INVISIBLE_STEELWALL_HORIZONTAL },
1605 { EL_STEELWALL, EL_INVISIBLE_STEELWALL }
1607 int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
1608 int steel_position = (x == -1 && y == -1 ? 0 :
1609 x == lev_fieldx && y == -1 ? 1 :
1610 x == -1 && y == lev_fieldy ? 2 :
1611 x == lev_fieldx && y == lev_fieldy ? 3 :
1612 x == -1 || x == lev_fieldx ? 4 :
1613 y == -1 || y == lev_fieldy ? 5 : 6);
1615 return border[steel_position][steel_type];
1618 void DrawScreenElement(int x, int y, int element)
1620 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
1621 DrawLevelFieldCrumbledSand(LEVELX(x), LEVELY(y));
1624 void DrawLevelElement(int x, int y, int element)
1626 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1627 DrawScreenElement(SCREENX(x), SCREENY(y), element);
1630 void DrawScreenField(int x, int y)
1632 int lx = LEVELX(x), ly = LEVELY(y);
1633 int element, content;
1635 if (!IN_LEV_FIELD(lx, ly))
1637 if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
1640 element = getBorderElement(lx, ly);
1642 DrawScreenElement(x, y, element);
1646 element = Feld[lx][ly];
1647 content = Store[lx][ly];
1649 if (IS_MOVING(lx, ly))
1651 int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
1652 boolean cut_mode = NO_CUTTING;
1654 if (element == EL_QUICKSAND_EMPTYING ||
1655 element == EL_QUICKSAND_FAST_EMPTYING ||
1656 element == EL_MAGIC_WALL_EMPTYING ||
1657 element == EL_BD_MAGIC_WALL_EMPTYING ||
1658 element == EL_DC_MAGIC_WALL_EMPTYING ||
1659 element == EL_AMOEBA_DROPPING)
1660 cut_mode = CUT_ABOVE;
1661 else if (element == EL_QUICKSAND_FILLING ||
1662 element == EL_QUICKSAND_FAST_FILLING ||
1663 element == EL_MAGIC_WALL_FILLING ||
1664 element == EL_BD_MAGIC_WALL_FILLING ||
1665 element == EL_DC_MAGIC_WALL_FILLING)
1666 cut_mode = CUT_BELOW;
1668 if (cut_mode == CUT_ABOVE)
1669 DrawScreenElementShifted(x, y, 0, 0, element, NO_CUTTING);
1671 DrawScreenElement(x, y, EL_EMPTY);
1674 DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
1675 else if (cut_mode == NO_CUTTING)
1676 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
1678 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
1680 if (content == EL_ACID)
1682 int dir = MovDir[lx][ly];
1683 int newlx = lx + (dir == MV_LEFT ? -1 : dir == MV_RIGHT ? +1 : 0);
1684 int newly = ly + (dir == MV_UP ? -1 : dir == MV_DOWN ? +1 : 0);
1686 DrawLevelElementThruMask(newlx, newly, EL_ACID);
1689 else if (IS_BLOCKED(lx, ly))
1694 boolean cut_mode = NO_CUTTING;
1695 int element_old, content_old;
1697 Blocked2Moving(lx, ly, &oldx, &oldy);
1700 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
1701 MovDir[oldx][oldy] == MV_RIGHT);
1703 element_old = Feld[oldx][oldy];
1704 content_old = Store[oldx][oldy];
1706 if (element_old == EL_QUICKSAND_EMPTYING ||
1707 element_old == EL_QUICKSAND_FAST_EMPTYING ||
1708 element_old == EL_MAGIC_WALL_EMPTYING ||
1709 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
1710 element_old == EL_DC_MAGIC_WALL_EMPTYING ||
1711 element_old == EL_AMOEBA_DROPPING)
1712 cut_mode = CUT_ABOVE;
1714 DrawScreenElement(x, y, EL_EMPTY);
1717 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
1719 else if (cut_mode == NO_CUTTING)
1720 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
1723 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
1726 else if (IS_DRAWABLE(element))
1727 DrawScreenElement(x, y, element);
1729 DrawScreenElement(x, y, EL_EMPTY);
1732 void DrawLevelField(int x, int y)
1734 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1735 DrawScreenField(SCREENX(x), SCREENY(y));
1736 else if (IS_MOVING(x, y))
1740 Moving2Blocked(x, y, &newx, &newy);
1741 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
1742 DrawScreenField(SCREENX(newx), SCREENY(newy));
1744 else if (IS_BLOCKED(x, y))
1748 Blocked2Moving(x, y, &oldx, &oldy);
1749 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
1750 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
1754 void DrawMiniElement(int x, int y, int element)
1758 graphic = el2edimg(element);
1759 DrawMiniGraphic(x, y, graphic);
1762 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
1764 int x = sx + scroll_x, y = sy + scroll_y;
1766 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
1767 DrawMiniElement(sx, sy, EL_EMPTY);
1768 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
1769 DrawMiniElement(sx, sy, Feld[x][y]);
1771 DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
1774 void DrawEnvelopeBackground(int envelope_nr, int startx, int starty,
1775 int x, int y, int xsize, int ysize, int font_nr)
1777 int font_width = getFontWidth(font_nr);
1778 int font_height = getFontHeight(font_nr);
1779 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1782 int dst_x = SX + startx + x * font_width;
1783 int dst_y = SY + starty + y * font_height;
1784 int width = graphic_info[graphic].width;
1785 int height = graphic_info[graphic].height;
1786 int inner_width = MAX(width - 2 * font_width, font_width);
1787 int inner_height = MAX(height - 2 * font_height, font_height);
1788 int inner_sx = (width >= 3 * font_width ? font_width : 0);
1789 int inner_sy = (height >= 3 * font_height ? font_height : 0);
1790 boolean draw_masked = graphic_info[graphic].draw_masked;
1792 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1794 if (src_bitmap == NULL || width < font_width || height < font_height)
1796 ClearRectangle(drawto, dst_x, dst_y, font_width, font_height);
1800 src_x += (x == 0 ? 0 : x == xsize - 1 ? width - font_width :
1801 inner_sx + (x - 1) * font_width % inner_width);
1802 src_y += (y == 0 ? 0 : y == ysize - 1 ? height - font_height :
1803 inner_sy + (y - 1) * font_height % inner_height);
1807 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1808 dst_x - src_x, dst_y - src_y);
1809 BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1813 BlitBitmap(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1817 void AnimateEnvelope(int envelope_nr, int anim_mode, int action)
1819 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1820 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1821 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
1822 boolean ffwd_delay = (tape.playing && tape.fast_forward);
1823 boolean no_delay = (tape.warp_forward);
1824 unsigned long anim_delay = 0;
1825 int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
1826 int anim_delay_value = (no_delay ? 0 : frame_delay_value);
1827 int font_nr = FONT_ENVELOPE_1 + envelope_nr;
1828 int font_width = getFontWidth(font_nr);
1829 int font_height = getFontHeight(font_nr);
1830 int max_xsize = level.envelope[envelope_nr].xsize;
1831 int max_ysize = level.envelope[envelope_nr].ysize;
1832 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
1833 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
1834 int xend = max_xsize;
1835 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
1836 int xstep = (xstart < xend ? 1 : 0);
1837 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
1840 for (x = xstart, y = ystart; x <= xend && y <= yend; x += xstep, y += ystep)
1842 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
1843 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
1844 int sx = (SXSIZE - xsize * font_width) / 2;
1845 int sy = (SYSIZE - ysize * font_height) / 2;
1848 SetDrawtoField(DRAW_BUFFERED);
1850 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
1852 SetDrawtoField(DRAW_BACKBUFFER);
1854 for (yy = 0; yy < ysize; yy++) for (xx = 0; xx < xsize; xx++)
1855 DrawEnvelopeBackground(envelope_nr, sx,sy, xx,yy, xsize, ysize, font_nr);
1858 DrawTextBuffer(SX + sx + font_width, SY + sy + font_height,
1859 level.envelope[envelope_nr].text, font_nr, max_xsize,
1860 xsize - 2, ysize - 2, mask_mode,
1861 level.envelope[envelope_nr].autowrap,
1862 level.envelope[envelope_nr].centered, FALSE);
1864 DrawTextToTextArea(SX + sx + font_width, SY + sy + font_height,
1865 level.envelope[envelope_nr].text, font_nr, max_xsize,
1866 xsize - 2, ysize - 2, mask_mode);
1869 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
1872 WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
1876 void ShowEnvelope(int envelope_nr)
1878 int element = EL_ENVELOPE_1 + envelope_nr;
1879 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1880 int sound_opening = element_info[element].sound[ACTION_OPENING];
1881 int sound_closing = element_info[element].sound[ACTION_CLOSING];
1882 boolean ffwd_delay = (tape.playing && tape.fast_forward);
1883 boolean no_delay = (tape.warp_forward);
1884 int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
1885 int wait_delay_value = (no_delay ? 0 : normal_delay_value);
1886 int anim_mode = graphic_info[graphic].anim_mode;
1887 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
1888 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
1890 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
1892 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
1894 if (anim_mode == ANIM_DEFAULT)
1895 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_OPENING);
1897 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_OPENING);
1900 Delay(wait_delay_value);
1902 WaitForEventToContinue();
1904 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
1906 if (anim_mode != ANIM_NONE)
1907 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_CLOSING);
1909 if (anim_mode == ANIM_DEFAULT)
1910 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_CLOSING);
1912 game.envelope_active = FALSE;
1914 SetDrawtoField(DRAW_BUFFERED);
1916 redraw_mask |= REDRAW_FIELD;
1920 void DrawPreviewElement(int dst_x, int dst_y, int element, int tilesize)
1924 int graphic = el2preimg(element);
1926 getSizedGraphicSource(graphic, 0, tilesize, &src_bitmap, &src_x, &src_y);
1927 BlitBitmap(src_bitmap, drawto, src_x, src_y, tilesize, tilesize, dst_x,dst_y);
1934 SetDrawBackgroundMask(REDRAW_NONE);
1937 for (x = BX1; x <= BX2; x++)
1938 for (y = BY1; y <= BY2; y++)
1939 DrawScreenField(x, y);
1941 redraw_mask |= REDRAW_FIELD;
1944 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
1948 for (x = 0; x < size_x; x++)
1949 for (y = 0; y < size_y; y++)
1950 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
1952 redraw_mask |= REDRAW_FIELD;
1955 static void DrawPreviewLevelExt(int from_x, int from_y)
1957 boolean show_level_border = (BorderElement != EL_EMPTY);
1958 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
1959 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
1960 int tile_size = preview.tile_size;
1961 int preview_width = preview.xsize * tile_size;
1962 int preview_height = preview.ysize * tile_size;
1963 int real_preview_xsize = MIN(level_xsize, preview.xsize);
1964 int real_preview_ysize = MIN(level_ysize, preview.ysize);
1965 int dst_x = SX + ALIGNED_XPOS(preview.x, preview_width, preview.align);
1966 int dst_y = SY + ALIGNED_YPOS(preview.y, preview_height, preview.valign);
1969 DrawBackground(dst_x, dst_y, preview_width, preview_height);
1971 dst_x += (preview_width - real_preview_xsize * tile_size) / 2;
1972 dst_y += (preview_height - real_preview_ysize * tile_size) / 2;
1974 for (x = 0; x < real_preview_xsize; x++)
1976 for (y = 0; y < real_preview_ysize; y++)
1978 int lx = from_x + x + (show_level_border ? -1 : 0);
1979 int ly = from_y + y + (show_level_border ? -1 : 0);
1980 int element = (IN_LEV_FIELD(lx, ly) ? level.field[lx][ly] :
1981 getBorderElement(lx, ly));
1983 DrawPreviewElement(dst_x + x * tile_size, dst_y + y * tile_size,
1984 element, tile_size);
1988 redraw_mask |= REDRAW_MICROLEVEL;
1991 #define MICROLABEL_EMPTY 0
1992 #define MICROLABEL_LEVEL_NAME 1
1993 #define MICROLABEL_LEVEL_AUTHOR_HEAD 2
1994 #define MICROLABEL_LEVEL_AUTHOR 3
1995 #define MICROLABEL_IMPORTED_FROM_HEAD 4
1996 #define MICROLABEL_IMPORTED_FROM 5
1997 #define MICROLABEL_IMPORTED_BY_HEAD 6
1998 #define MICROLABEL_IMPORTED_BY 7
2000 static int getMaxTextLength(struct TextPosInfo *pos, int font_nr)
2002 int max_text_width = SXSIZE;
2003 int font_width = getFontWidth(font_nr);
2005 if (pos->align == ALIGN_CENTER)
2006 max_text_width = (pos->x < SXSIZE / 2 ? pos->x * 2 : (SXSIZE - pos->x) * 2);
2007 else if (pos->align == ALIGN_RIGHT)
2008 max_text_width = pos->x;
2010 max_text_width = SXSIZE - pos->x;
2012 return max_text_width / font_width;
2015 static void DrawPreviewLevelLabelExt(int mode)
2017 struct TextPosInfo *pos = &menu.main.text.level_info_2;
2018 char label_text[MAX_OUTPUT_LINESIZE + 1];
2019 int max_len_label_text;
2021 int font_nr = pos->font;
2024 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
2025 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
2026 mode == MICROLABEL_IMPORTED_BY_HEAD)
2027 font_nr = pos->font_alt;
2029 int font_nr = FONT_TEXT_2;
2032 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
2033 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
2034 mode == MICROLABEL_IMPORTED_BY_HEAD)
2035 font_nr = FONT_TEXT_3;
2039 max_len_label_text = getMaxTextLength(pos, font_nr);
2041 max_len_label_text = SXSIZE / getFontWidth(font_nr);
2045 if (pos->size != -1)
2046 max_len_label_text = pos->size;
2049 for (i = 0; i < max_len_label_text; i++)
2050 label_text[i] = ' ';
2051 label_text[max_len_label_text] = '\0';
2053 if (strlen(label_text) > 0)
2056 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2058 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
2059 int lypos = MICROLABEL2_YPOS;
2061 DrawText(lxpos, lypos, label_text, font_nr);
2066 (mode == MICROLABEL_LEVEL_NAME ? level.name :
2067 mode == MICROLABEL_LEVEL_AUTHOR_HEAD ? "created by" :
2068 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
2069 mode == MICROLABEL_IMPORTED_FROM_HEAD ? "imported from" :
2070 mode == MICROLABEL_IMPORTED_FROM ? leveldir_current->imported_from :
2071 mode == MICROLABEL_IMPORTED_BY_HEAD ? "imported by" :
2072 mode == MICROLABEL_IMPORTED_BY ? leveldir_current->imported_by :""),
2073 max_len_label_text);
2074 label_text[max_len_label_text] = '\0';
2076 if (strlen(label_text) > 0)
2079 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2081 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
2082 int lypos = MICROLABEL2_YPOS;
2084 DrawText(lxpos, lypos, label_text, font_nr);
2088 redraw_mask |= REDRAW_MICROLEVEL;
2091 void DrawPreviewLevel(boolean restart)
2093 static unsigned long scroll_delay = 0;
2094 static unsigned long label_delay = 0;
2095 static int from_x, from_y, scroll_direction;
2096 static int label_state, label_counter;
2097 unsigned long scroll_delay_value = preview.step_delay;
2098 boolean show_level_border = (BorderElement != EL_EMPTY);
2099 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
2100 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
2101 int last_game_status = game_status; /* save current game status */
2104 /* force PREVIEW font on preview level */
2105 game_status = GAME_MODE_PSEUDO_PREVIEW;
2113 if (preview.anim_mode == ANIM_CENTERED)
2115 if (level_xsize > preview.xsize)
2116 from_x = (level_xsize - preview.xsize) / 2;
2117 if (level_ysize > preview.ysize)
2118 from_y = (level_ysize - preview.ysize) / 2;
2121 from_x += preview.xoffset;
2122 from_y += preview.yoffset;
2124 scroll_direction = MV_RIGHT;
2128 DrawPreviewLevelExt(from_x, from_y);
2129 DrawPreviewLevelLabelExt(label_state);
2131 /* initialize delay counters */
2132 DelayReached(&scroll_delay, 0);
2133 DelayReached(&label_delay, 0);
2135 if (leveldir_current->name)
2137 struct TextPosInfo *pos = &menu.main.text.level_info_1;
2138 char label_text[MAX_OUTPUT_LINESIZE + 1];
2140 int font_nr = pos->font;
2142 int font_nr = FONT_TEXT_1;
2145 int max_len_label_text = getMaxTextLength(pos, font_nr);
2147 int max_len_label_text = SXSIZE / getFontWidth(font_nr);
2155 if (pos->size != -1)
2156 max_len_label_text = pos->size;
2159 strncpy(label_text, leveldir_current->name, max_len_label_text);
2160 label_text[max_len_label_text] = '\0';
2163 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2165 lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
2166 lypos = SY + MICROLABEL1_YPOS;
2168 DrawText(lxpos, lypos, label_text, font_nr);
2172 game_status = last_game_status; /* restore current game status */
2177 /* scroll preview level, if needed */
2178 if (preview.anim_mode != ANIM_NONE &&
2179 (level_xsize > preview.xsize || level_ysize > preview.ysize) &&
2180 DelayReached(&scroll_delay, scroll_delay_value))
2182 switch (scroll_direction)
2187 from_x -= preview.step_offset;
2188 from_x = (from_x < 0 ? 0 : from_x);
2191 scroll_direction = MV_UP;
2195 if (from_x < level_xsize - preview.xsize)
2197 from_x += preview.step_offset;
2198 from_x = (from_x > level_xsize - preview.xsize ?
2199 level_xsize - preview.xsize : from_x);
2202 scroll_direction = MV_DOWN;
2208 from_y -= preview.step_offset;
2209 from_y = (from_y < 0 ? 0 : from_y);
2212 scroll_direction = MV_RIGHT;
2216 if (from_y < level_ysize - preview.ysize)
2218 from_y += preview.step_offset;
2219 from_y = (from_y > level_ysize - preview.ysize ?
2220 level_ysize - preview.ysize : from_y);
2223 scroll_direction = MV_LEFT;
2230 DrawPreviewLevelExt(from_x, from_y);
2233 /* !!! THIS ALL SUCKS -- SHOULD BE CLEANLY REWRITTEN !!! */
2234 /* redraw micro level label, if needed */
2235 if (!strEqual(level.name, NAMELESS_LEVEL_NAME) &&
2236 !strEqual(level.author, ANONYMOUS_NAME) &&
2237 !strEqual(level.author, leveldir_current->name) &&
2238 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
2240 int max_label_counter = 23;
2242 if (leveldir_current->imported_from != NULL &&
2243 strlen(leveldir_current->imported_from) > 0)
2244 max_label_counter += 14;
2245 if (leveldir_current->imported_by != NULL &&
2246 strlen(leveldir_current->imported_by) > 0)
2247 max_label_counter += 14;
2249 label_counter = (label_counter + 1) % max_label_counter;
2250 label_state = (label_counter >= 0 && label_counter <= 7 ?
2251 MICROLABEL_LEVEL_NAME :
2252 label_counter >= 9 && label_counter <= 12 ?
2253 MICROLABEL_LEVEL_AUTHOR_HEAD :
2254 label_counter >= 14 && label_counter <= 21 ?
2255 MICROLABEL_LEVEL_AUTHOR :
2256 label_counter >= 23 && label_counter <= 26 ?
2257 MICROLABEL_IMPORTED_FROM_HEAD :
2258 label_counter >= 28 && label_counter <= 35 ?
2259 MICROLABEL_IMPORTED_FROM :
2260 label_counter >= 37 && label_counter <= 40 ?
2261 MICROLABEL_IMPORTED_BY_HEAD :
2262 label_counter >= 42 && label_counter <= 49 ?
2263 MICROLABEL_IMPORTED_BY : MICROLABEL_EMPTY);
2265 if (leveldir_current->imported_from == NULL &&
2266 (label_state == MICROLABEL_IMPORTED_FROM_HEAD ||
2267 label_state == MICROLABEL_IMPORTED_FROM))
2268 label_state = (label_state == MICROLABEL_IMPORTED_FROM_HEAD ?
2269 MICROLABEL_IMPORTED_BY_HEAD : MICROLABEL_IMPORTED_BY);
2271 DrawPreviewLevelLabelExt(label_state);
2274 game_status = last_game_status; /* restore current game status */
2277 inline void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
2278 int graphic, int sync_frame, int mask_mode)
2280 int frame = getGraphicAnimationFrame(graphic, sync_frame);
2282 if (mask_mode == USE_MASKING)
2283 DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
2285 DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
2288 inline void DrawGraphicAnimation(int x, int y, int graphic)
2290 int lx = LEVELX(x), ly = LEVELY(y);
2292 if (!IN_SCR_FIELD(x, y))
2295 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
2296 graphic, GfxFrame[lx][ly], NO_MASKING);
2297 MarkTileDirty(x, y);
2300 void DrawLevelGraphicAnimation(int x, int y, int graphic)
2302 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
2305 void DrawLevelElementAnimation(int x, int y, int element)
2307 int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
2309 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
2312 inline void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
2314 int sx = SCREENX(x), sy = SCREENY(y);
2316 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
2319 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
2322 DrawGraphicAnimation(sx, sy, graphic);
2325 if (GFX_CRUMBLED(TILE_GFX_ELEMENT(x, y)))
2326 DrawLevelFieldCrumbledSand(x, y);
2328 if (GFX_CRUMBLED(Feld[x][y]))
2329 DrawLevelFieldCrumbledSand(x, y);
2333 void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
2335 int sx = SCREENX(x), sy = SCREENY(y);
2338 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
2341 graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
2343 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
2346 DrawGraphicAnimation(sx, sy, graphic);
2348 if (GFX_CRUMBLED(element))
2349 DrawLevelFieldCrumbledSand(x, y);
2352 static int getPlayerGraphic(struct PlayerInfo *player, int move_dir)
2354 if (player->use_murphy)
2356 /* this works only because currently only one player can be "murphy" ... */
2357 static int last_horizontal_dir = MV_LEFT;
2358 int graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir);
2360 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
2361 last_horizontal_dir = move_dir;
2363 if (graphic == IMG_SP_MURPHY) /* undefined => use special graphic */
2365 int direction = (player->is_snapping ? move_dir : last_horizontal_dir);
2367 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
2373 return el_act_dir2img(player->artwork_element, player->GfxAction,move_dir);
2376 static boolean equalGraphics(int graphic1, int graphic2)
2378 struct GraphicInfo *g1 = &graphic_info[graphic1];
2379 struct GraphicInfo *g2 = &graphic_info[graphic2];
2381 return (g1->bitmap == g2->bitmap &&
2382 g1->src_x == g2->src_x &&
2383 g1->src_y == g2->src_y &&
2384 g1->anim_frames == g2->anim_frames &&
2385 g1->anim_delay == g2->anim_delay &&
2386 g1->anim_mode == g2->anim_mode);
2389 void DrawAllPlayers()
2393 for (i = 0; i < MAX_PLAYERS; i++)
2394 if (stored_player[i].active)
2395 DrawPlayer(&stored_player[i]);
2398 void DrawPlayerField(int x, int y)
2400 if (!IS_PLAYER(x, y))
2403 DrawPlayer(PLAYERINFO(x, y));
2406 void DrawPlayer(struct PlayerInfo *player)
2408 int jx = player->jx;
2409 int jy = player->jy;
2410 int move_dir = player->MovDir;
2411 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? +1 : 0);
2412 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? +1 : 0);
2413 int last_jx = (player->is_moving ? jx - dx : jx);
2414 int last_jy = (player->is_moving ? jy - dy : jy);
2415 int next_jx = jx + dx;
2416 int next_jy = jy + dy;
2417 boolean player_is_moving = (player->MovPos ? TRUE : FALSE);
2418 boolean player_is_opaque = FALSE;
2419 int sx = SCREENX(jx), sy = SCREENY(jy);
2420 int sxx = 0, syy = 0;
2421 int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
2423 int action = ACTION_DEFAULT;
2424 int last_player_graphic = getPlayerGraphic(player, move_dir);
2425 int last_player_frame = player->Frame;
2428 /* GfxElement[][] is set to the element the player is digging or collecting;
2429 remove also for off-screen player if the player is not moving anymore */
2430 if (IN_LEV_FIELD(jx, jy) && !player_is_moving)
2431 GfxElement[jx][jy] = EL_UNDEFINED;
2433 if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
2437 if (!IN_LEV_FIELD(jx, jy))
2439 printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
2440 printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
2441 printf("DrawPlayerField(): This should never happen!\n");
2446 if (element == EL_EXPLOSION)
2449 action = (player->is_pushing ? ACTION_PUSHING :
2450 player->is_digging ? ACTION_DIGGING :
2451 player->is_collecting ? ACTION_COLLECTING :
2452 player->is_moving ? ACTION_MOVING :
2453 player->is_snapping ? ACTION_SNAPPING :
2454 player->is_dropping ? ACTION_DROPPING :
2455 player->is_waiting ? player->action_waiting : ACTION_DEFAULT);
2457 if (player->is_waiting)
2458 move_dir = player->dir_waiting;
2460 InitPlayerGfxAnimation(player, action, move_dir);
2462 /* ----------------------------------------------------------------------- */
2463 /* draw things in the field the player is leaving, if needed */
2464 /* ----------------------------------------------------------------------- */
2466 if (player->is_moving)
2468 if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
2470 DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
2472 if (last_element == EL_DYNAMITE_ACTIVE ||
2473 last_element == EL_EM_DYNAMITE_ACTIVE ||
2474 last_element == EL_SP_DISK_RED_ACTIVE)
2475 DrawDynamite(last_jx, last_jy);
2477 DrawLevelFieldThruMask(last_jx, last_jy);
2479 else if (last_element == EL_DYNAMITE_ACTIVE ||
2480 last_element == EL_EM_DYNAMITE_ACTIVE ||
2481 last_element == EL_SP_DISK_RED_ACTIVE)
2482 DrawDynamite(last_jx, last_jy);
2484 /* !!! this is not enough to prevent flickering of players which are
2485 moving next to each others without a free tile between them -- this
2486 can only be solved by drawing all players layer by layer (first the
2487 background, then the foreground etc.) !!! => TODO */
2488 else if (!IS_PLAYER(last_jx, last_jy))
2489 DrawLevelField(last_jx, last_jy);
2492 DrawLevelField(last_jx, last_jy);
2495 if (player->is_pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
2496 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
2499 if (!IN_SCR_FIELD(sx, sy))
2502 if (setup.direct_draw)
2503 SetDrawtoField(DRAW_BUFFERED);
2505 /* ----------------------------------------------------------------------- */
2506 /* draw things behind the player, if needed */
2507 /* ----------------------------------------------------------------------- */
2510 DrawLevelElement(jx, jy, Back[jx][jy]);
2511 else if (IS_ACTIVE_BOMB(element))
2512 DrawLevelElement(jx, jy, EL_EMPTY);
2515 if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
2517 int old_element = GfxElement[jx][jy];
2518 int old_graphic = el_act_dir2img(old_element, action, move_dir);
2519 int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
2521 if (GFX_CRUMBLED(old_element))
2522 DrawLevelFieldCrumbledSandDigging(jx, jy, move_dir, player->StepFrame);
2524 DrawGraphic(sx, sy, old_graphic, frame);
2526 if (graphic_info[old_graphic].anim_mode & ANIM_OPAQUE_PLAYER)
2527 player_is_opaque = TRUE;
2531 GfxElement[jx][jy] = EL_UNDEFINED;
2533 /* make sure that pushed elements are drawn with correct frame rate */
2535 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
2537 if (player->is_pushing && player->is_moving && !IS_ANIM_MODE_CE(graphic))
2538 GfxFrame[jx][jy] = player->StepFrame;
2540 if (player->is_pushing && player->is_moving)
2541 GfxFrame[jx][jy] = player->StepFrame;
2544 DrawLevelField(jx, jy);
2548 /* ----------------------------------------------------------------------- */
2549 /* draw player himself */
2550 /* ----------------------------------------------------------------------- */
2552 graphic = getPlayerGraphic(player, move_dir);
2554 /* in the case of changed player action or direction, prevent the current
2555 animation frame from being restarted for identical animations */
2556 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
2557 player->Frame = last_player_frame;
2559 frame = getGraphicAnimationFrame(graphic, player->Frame);
2563 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
2564 sxx = player->GfxPos;
2566 syy = player->GfxPos;
2569 if (!setup.soft_scrolling && ScreenMovPos)
2572 if (player_is_opaque)
2573 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
2575 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
2577 if (SHIELD_ON(player))
2579 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
2580 IMG_SHIELD_NORMAL_ACTIVE);
2581 int frame = getGraphicAnimationFrame(graphic, -1);
2583 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
2586 /* ----------------------------------------------------------------------- */
2587 /* draw things the player is pushing, if needed */
2588 /* ----------------------------------------------------------------------- */
2591 printf("::: %d, %d [%d, %d] [%d]\n",
2592 player->is_pushing, player_is_moving, player->GfxAction,
2593 player->is_moving, player_is_moving);
2597 if (player->is_pushing && player->is_moving)
2599 int px = SCREENX(jx), py = SCREENY(jy);
2600 int pxx = (TILEX - ABS(sxx)) * dx;
2601 int pyy = (TILEY - ABS(syy)) * dy;
2602 int gfx_frame = GfxFrame[jx][jy];
2608 if (!IS_MOVING(jx, jy)) /* push movement already finished */
2610 element = Feld[next_jx][next_jy];
2611 gfx_frame = GfxFrame[next_jx][next_jy];
2614 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
2617 sync_frame = (IS_ANIM_MODE_CE(graphic) ? gfx_frame : player->StepFrame);
2618 frame = getGraphicAnimationFrame(graphic, sync_frame);
2620 frame = getGraphicAnimationFrame(graphic, player->StepFrame);
2623 /* draw background element under pushed element (like the Sokoban field) */
2624 if (Back[next_jx][next_jy])
2625 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
2627 /* masked drawing is needed for EMC style (double) movement graphics */
2628 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
2632 /* ----------------------------------------------------------------------- */
2633 /* draw things in front of player (active dynamite or dynabombs) */
2634 /* ----------------------------------------------------------------------- */
2636 if (IS_ACTIVE_BOMB(element))
2638 graphic = el2img(element);
2639 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
2641 if (game.emulation == EMU_SUPAPLEX)
2642 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
2644 DrawGraphicThruMask(sx, sy, graphic, frame);
2647 if (player_is_moving && last_element == EL_EXPLOSION)
2649 int element = (GfxElement[last_jx][last_jy] != EL_UNDEFINED ?
2650 GfxElement[last_jx][last_jy] : EL_EMPTY);
2651 int graphic = el_act2img(element, ACTION_EXPLODING);
2652 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
2653 int phase = ExplodePhase[last_jx][last_jy] - 1;
2654 int frame = getGraphicAnimationFrame(graphic, phase - delay);
2657 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
2660 /* ----------------------------------------------------------------------- */
2661 /* draw elements the player is just walking/passing through/under */
2662 /* ----------------------------------------------------------------------- */
2664 if (player_is_moving)
2666 /* handle the field the player is leaving ... */
2667 if (IS_ACCESSIBLE_INSIDE(last_element))
2668 DrawLevelField(last_jx, last_jy);
2669 else if (IS_ACCESSIBLE_UNDER(last_element))
2670 DrawLevelFieldThruMask(last_jx, last_jy);
2673 /* do not redraw accessible elements if the player is just pushing them */
2674 if (!player_is_moving || !player->is_pushing)
2676 /* ... and the field the player is entering */
2677 if (IS_ACCESSIBLE_INSIDE(element))
2678 DrawLevelField(jx, jy);
2679 else if (IS_ACCESSIBLE_UNDER(element))
2680 DrawLevelFieldThruMask(jx, jy);
2683 if (setup.direct_draw)
2685 int dst_x = SX + SCREENX(MIN(jx, last_jx)) * TILEX;
2686 int dst_y = SY + SCREENY(MIN(jy, last_jy)) * TILEY;
2687 int x_size = TILEX * (1 + ABS(jx - last_jx));
2688 int y_size = TILEY * (1 + ABS(jy - last_jy));
2690 BlitBitmap(drawto_field, window,
2691 dst_x, dst_y, x_size, y_size, dst_x, dst_y);
2692 SetDrawtoField(DRAW_DIRECT);
2695 MarkTileDirty(sx, sy);
2698 /* ------------------------------------------------------------------------- */
2700 void WaitForEventToContinue()
2702 boolean still_wait = TRUE;
2704 /* simulate releasing mouse button over last gadget, if still pressed */
2706 HandleGadgets(-1, -1, 0);
2708 button_status = MB_RELEASED;
2724 case EVENT_BUTTONPRESS:
2725 case EVENT_KEYPRESS:
2729 case EVENT_KEYRELEASE:
2730 ClearPlayerAction();
2734 HandleOtherEvents(&event);
2738 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2745 /* don't eat all CPU time */
2750 #define MAX_REQUEST_LINES 13
2751 #define MAX_REQUEST_LINE_FONT1_LEN 7
2752 #define MAX_REQUEST_LINE_FONT2_LEN 10
2754 boolean Request(char *text, unsigned int req_state)
2756 int mx, my, ty, result = -1;
2757 unsigned int old_door_state;
2758 int last_game_status = game_status; /* save current game status */
2759 int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
2760 int font_nr = FONT_TEXT_2;
2761 int max_word_len = 0;
2764 for (text_ptr = text; *text_ptr; text_ptr++)
2766 max_word_len = (*text_ptr != ' ' ? max_word_len + 1 : 0);
2768 if (max_word_len > MAX_REQUEST_LINE_FONT1_LEN)
2770 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
2772 font_nr = FONT_TEXT_1;
2774 font_nr = FONT_LEVEL_NUMBER;
2781 if (game_status == GAME_MODE_PLAYING &&
2782 level.game_engine_type == GAME_ENGINE_TYPE_EM)
2783 BlitScreenToBitmap_EM(backbuffer);
2785 /* disable deactivated drawing when quick-loading level tape recording */
2786 if (tape.playing && tape.deactivate_display)
2787 TapeDeactivateDisplayOff(TRUE);
2789 SetMouseCursor(CURSOR_DEFAULT);
2791 #if defined(NETWORK_AVALIABLE)
2792 /* pause network game while waiting for request to answer */
2793 if (options.network &&
2794 game_status == GAME_MODE_PLAYING &&
2795 req_state & REQUEST_WAIT_FOR_INPUT)
2796 SendToServer_PausePlaying();
2799 old_door_state = GetDoorState();
2801 /* simulate releasing mouse button over last gadget, if still pressed */
2803 HandleGadgets(-1, -1, 0);
2807 if (old_door_state & DOOR_OPEN_1)
2809 CloseDoor(DOOR_CLOSE_1);
2811 /* save old door content */
2812 BlitBitmap(bitmap_db_door, bitmap_db_door,
2813 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
2814 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
2818 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
2821 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2823 /* clear door drawing field */
2824 DrawBackground(DX, DY, DXSIZE, DYSIZE);
2826 /* force DOOR font inside door area */
2827 game_status = GAME_MODE_PSEUDO_DOOR;
2829 /* write text for request */
2830 for (ty = 0; ty < MAX_REQUEST_LINES; ty++)
2832 char text_line[max_request_line_len + 1];
2838 for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
2841 if (!tc || tc == ' ')
2852 strncpy(text_line, text, tl);
2855 DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
2856 DY + 8 + ty * (getFontHeight(font_nr) + 2),
2857 text_line, font_nr);
2859 text += tl + (tc == ' ' ? 1 : 0);
2862 game_status = last_game_status; /* restore current game status */
2864 if (req_state & REQ_ASK)
2866 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
2867 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
2869 else if (req_state & REQ_CONFIRM)
2871 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
2873 else if (req_state & REQ_PLAYER)
2875 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
2876 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
2877 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
2878 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
2881 /* copy request gadgets to door backbuffer */
2882 BlitBitmap(drawto, bitmap_db_door,
2883 DX, DY, DXSIZE, DYSIZE,
2884 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2886 OpenDoor(DOOR_OPEN_1);
2888 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
2890 if (game_status == GAME_MODE_PLAYING)
2892 SetPanelBackground();
2893 SetDrawBackgroundMask(REDRAW_DOOR_1);
2897 SetDrawBackgroundMask(REDRAW_FIELD);
2903 if (game_status != GAME_MODE_MAIN)
2906 button_status = MB_RELEASED;
2908 request_gadget_id = -1;
2910 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2922 case EVENT_BUTTONPRESS:
2923 case EVENT_BUTTONRELEASE:
2924 case EVENT_MOTIONNOTIFY:
2926 if (event.type == EVENT_MOTIONNOTIFY)
2928 if (!PointerInWindow(window))
2929 continue; /* window and pointer are on different screens */
2934 motion_status = TRUE;
2935 mx = ((MotionEvent *) &event)->x;
2936 my = ((MotionEvent *) &event)->y;
2940 motion_status = FALSE;
2941 mx = ((ButtonEvent *) &event)->x;
2942 my = ((ButtonEvent *) &event)->y;
2943 if (event.type == EVENT_BUTTONPRESS)
2944 button_status = ((ButtonEvent *) &event)->button;
2946 button_status = MB_RELEASED;
2949 /* this sets 'request_gadget_id' */
2950 HandleGadgets(mx, my, button_status);
2952 switch (request_gadget_id)
2954 case TOOL_CTRL_ID_YES:
2957 case TOOL_CTRL_ID_NO:
2960 case TOOL_CTRL_ID_CONFIRM:
2961 result = TRUE | FALSE;
2964 case TOOL_CTRL_ID_PLAYER_1:
2967 case TOOL_CTRL_ID_PLAYER_2:
2970 case TOOL_CTRL_ID_PLAYER_3:
2973 case TOOL_CTRL_ID_PLAYER_4:
2984 case EVENT_KEYPRESS:
2985 switch (GetEventKey((KeyEvent *)&event, TRUE))
2988 if (req_state & REQ_CONFIRM)
3004 if (req_state & REQ_PLAYER)
3008 case EVENT_KEYRELEASE:
3009 ClearPlayerAction();
3013 HandleOtherEvents(&event);
3017 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
3019 int joy = AnyJoystick();
3021 if (joy & JOY_BUTTON_1)
3023 else if (joy & JOY_BUTTON_2)
3029 if (game_status == GAME_MODE_PLAYING && local_player->LevelSolved_GameEnd)
3031 HandleGameActions();
3037 if (!PendingEvent()) /* delay only if no pending events */
3048 if (!PendingEvent()) /* delay only if no pending events */
3051 /* don't eat all CPU time */
3058 if (game_status != GAME_MODE_MAIN)
3063 if (!(req_state & REQ_STAY_OPEN))
3065 CloseDoor(DOOR_CLOSE_1);
3067 if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
3068 (req_state & REQ_REOPEN))
3069 OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
3074 if (game_status == GAME_MODE_PLAYING)
3076 SetPanelBackground();
3077 SetDrawBackgroundMask(REDRAW_DOOR_1);
3081 SetDrawBackgroundMask(REDRAW_FIELD);
3084 #if defined(NETWORK_AVALIABLE)
3085 /* continue network game after request */
3086 if (options.network &&
3087 game_status == GAME_MODE_PLAYING &&
3088 req_state & REQUEST_WAIT_FOR_INPUT)
3089 SendToServer_ContinuePlaying();
3092 /* restore deactivated drawing when quick-loading level tape recording */
3093 if (tape.playing && tape.deactivate_display)
3094 TapeDeactivateDisplayOn();
3099 unsigned int OpenDoor(unsigned int door_state)
3101 if (door_state & DOOR_COPY_BACK)
3103 if (door_state & DOOR_OPEN_1)
3104 BlitBitmap(bitmap_db_door, bitmap_db_door,
3105 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
3106 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
3108 if (door_state & DOOR_OPEN_2)
3109 BlitBitmap(bitmap_db_door, bitmap_db_door,
3110 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY2, VXSIZE, VYSIZE,
3111 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
3113 door_state &= ~DOOR_COPY_BACK;
3116 return MoveDoor(door_state);
3119 unsigned int CloseDoor(unsigned int door_state)
3121 unsigned int old_door_state = GetDoorState();
3123 if (!(door_state & DOOR_NO_COPY_BACK))
3125 if (old_door_state & DOOR_OPEN_1)
3126 BlitBitmap(backbuffer, bitmap_db_door,
3127 DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
3129 if (old_door_state & DOOR_OPEN_2)
3130 BlitBitmap(backbuffer, bitmap_db_door,
3131 VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
3133 door_state &= ~DOOR_NO_COPY_BACK;
3136 return MoveDoor(door_state);
3139 unsigned int GetDoorState()
3141 return MoveDoor(DOOR_GET_STATE);
3144 unsigned int SetDoorState(unsigned int door_state)
3146 return MoveDoor(door_state | DOOR_SET_STATE);
3149 unsigned int MoveDoor(unsigned int door_state)
3151 static int door1 = DOOR_OPEN_1;
3152 static int door2 = DOOR_CLOSE_2;
3153 unsigned long door_delay = 0;
3154 unsigned long door_delay_value;
3157 if (door_1.width < 0 || door_1.width > DXSIZE)
3158 door_1.width = DXSIZE;
3159 if (door_1.height < 0 || door_1.height > DYSIZE)
3160 door_1.height = DYSIZE;
3161 if (door_2.width < 0 || door_2.width > VXSIZE)
3162 door_2.width = VXSIZE;
3163 if (door_2.height < 0 || door_2.height > VYSIZE)
3164 door_2.height = VYSIZE;
3166 if (door_state == DOOR_GET_STATE)
3167 return (door1 | door2);
3169 if (door_state & DOOR_SET_STATE)
3171 if (door_state & DOOR_ACTION_1)
3172 door1 = door_state & DOOR_ACTION_1;
3173 if (door_state & DOOR_ACTION_2)
3174 door2 = door_state & DOOR_ACTION_2;
3176 return (door1 | door2);
3179 if (!(door_state & DOOR_FORCE_REDRAW))
3181 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
3182 door_state &= ~DOOR_OPEN_1;
3183 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
3184 door_state &= ~DOOR_CLOSE_1;
3185 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
3186 door_state &= ~DOOR_OPEN_2;
3187 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
3188 door_state &= ~DOOR_CLOSE_2;
3191 door_delay_value = (door_state & DOOR_ACTION_1 ? door_1.step_delay :
3194 if (setup.quick_doors)
3196 stepsize = 20; /* must be chosen to always draw last frame */
3197 door_delay_value = 0;
3200 if (global.autoplay_leveldir)
3202 door_state |= DOOR_NO_DELAY;
3203 door_state &= ~DOOR_CLOSE_ALL;
3206 if (door_state & DOOR_ACTION)
3208 boolean handle_door_1 = (door_state & DOOR_ACTION_1);
3209 boolean handle_door_2 = (door_state & DOOR_ACTION_2);
3210 boolean door_1_done = (!handle_door_1);
3211 boolean door_2_done = (!handle_door_2);
3212 boolean door_1_vertical = (door_1.anim_mode & ANIM_VERTICAL);
3213 boolean door_2_vertical = (door_2.anim_mode & ANIM_VERTICAL);
3214 int door_size_1 = (door_1_vertical ? door_1.height : door_1.width);
3215 int door_size_2 = (door_2_vertical ? door_2.height : door_2.width);
3216 int max_door_size_1 = (door_1_vertical ? DYSIZE : DXSIZE);
3217 int max_door_size_2 = (door_2_vertical ? VYSIZE : VXSIZE);
3218 int door_size = (handle_door_1 ? door_size_1 : door_size_2);
3219 int max_door_size = (handle_door_1 ? max_door_size_1 : max_door_size_2);
3220 int door_skip = max_door_size - door_size;
3221 int end = door_size;
3222 int start = ((door_state & DOOR_NO_DELAY) ? end : 0);
3225 if (!(door_state & DOOR_NO_DELAY) && !setup.quick_doors)
3227 /* opening door sound has priority over simultaneously closing door */
3228 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
3229 PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
3230 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
3231 PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
3234 for (k = start; k <= end && !(door_1_done && door_2_done); k += stepsize)
3237 Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
3238 GC gc = bitmap->stored_clip_gc;
3240 if (door_state & DOOR_ACTION_1)
3242 int a = MIN(x * door_1.step_offset, end);
3243 int p = (door_state & DOOR_OPEN_1 ? end - a : a);
3244 int i = p + door_skip;
3246 if (door_1.anim_mode & ANIM_STATIC_PANEL)
3248 BlitBitmap(bitmap_db_door, drawto,
3249 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1,
3250 DXSIZE, DYSIZE, DX, DY);
3254 BlitBitmap(bitmap_db_door, drawto,
3255 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + p / 2,
3256 DXSIZE, DYSIZE - p / 2, DX, DY);
3258 ClearRectangle(drawto, DX, DY + DYSIZE - p / 2, DXSIZE, p / 2);
3261 if (door_1.anim_mode & ANIM_HORIZONTAL && x <= DXSIZE)
3263 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
3264 int dst1_x = DX + DXSIZE - i, dst1_y = DY;
3265 int src2_x = DXSIZE - i, src2_y = DOOR_GFX_PAGEY1;
3266 int dst2_x = DX, dst2_y = DY;
3267 int width = i, height = DYSIZE;
3269 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3270 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3273 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3274 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3277 else if (door_1.anim_mode & ANIM_VERTICAL && x <= DYSIZE)
3279 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
3280 int dst1_x = DX, dst1_y = DY + DYSIZE - i;
3281 int src2_x = 0, src2_y = DOOR_GFX_PAGEY1 + DYSIZE - i;
3282 int dst2_x = DX, dst2_y = DY;
3283 int width = DXSIZE, height = i;
3285 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3286 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3289 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3290 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3293 else if (x <= DXSIZE) /* ANIM_DEFAULT */
3295 int j = (door_1.anim_mode == ANIM_DEFAULT ? (DXSIZE - i) / 3 : 0);
3297 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
3298 BlitBitmapMasked(bitmap, drawto,
3299 DXSIZE, DOOR_GFX_PAGEY1, i, 77,
3300 DX + DXSIZE - i, DY + j);
3301 BlitBitmapMasked(bitmap, drawto,
3302 DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
3303 DX + DXSIZE - i, DY + 140 + j);
3304 SetClipOrigin(bitmap, gc, DX - DXSIZE + i,
3305 DY - (DOOR_GFX_PAGEY1 + j));
3306 BlitBitmapMasked(bitmap, drawto,
3307 DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
3309 BlitBitmapMasked(bitmap, drawto,
3310 DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
3313 BlitBitmapMasked(bitmap, drawto,
3314 DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
3316 BlitBitmapMasked(bitmap, drawto,
3317 DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
3319 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
3320 BlitBitmapMasked(bitmap, drawto,
3321 DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
3322 DX + DXSIZE - i, DY + 77 + j);
3323 BlitBitmapMasked(bitmap, drawto,
3324 DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
3325 DX + DXSIZE - i, DY + 203 + j);
3328 redraw_mask |= REDRAW_DOOR_1;
3329 door_1_done = (a == end);
3332 if (door_state & DOOR_ACTION_2)
3334 int a = MIN(x * door_2.step_offset, door_size);
3335 int p = (door_state & DOOR_OPEN_2 ? door_size - a : a);
3336 int i = p + door_skip;
3338 if (door_2.anim_mode & ANIM_STATIC_PANEL)
3340 BlitBitmap(bitmap_db_door, drawto,
3341 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2,
3342 VXSIZE, VYSIZE, VX, VY);
3344 else if (x <= VYSIZE)
3346 BlitBitmap(bitmap_db_door, drawto,
3347 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + p / 2,
3348 VXSIZE, VYSIZE - p / 2, VX, VY);
3350 ClearRectangle(drawto, VX, VY + VYSIZE - p / 2, VXSIZE, p / 2);
3353 if (door_2.anim_mode & ANIM_HORIZONTAL && x <= VXSIZE)
3355 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
3356 int dst1_x = VX + VXSIZE - i, dst1_y = VY;
3357 int src2_x = VXSIZE - i, src2_y = DOOR_GFX_PAGEY2;
3358 int dst2_x = VX, dst2_y = VY;
3359 int width = i, height = VYSIZE;
3361 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3362 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3365 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3366 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3369 else if (door_2.anim_mode & ANIM_VERTICAL && x <= VYSIZE)
3371 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
3372 int dst1_x = VX, dst1_y = VY + VYSIZE - i;
3373 int src2_x = 0, src2_y = DOOR_GFX_PAGEY2 + VYSIZE - i;
3374 int dst2_x = VX, dst2_y = VY;
3375 int width = VXSIZE, height = i;
3377 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3378 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3381 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3382 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3385 else if (x <= VXSIZE) /* ANIM_DEFAULT */
3387 int j = (door_2.anim_mode == ANIM_DEFAULT ? (VXSIZE - i) / 3 : 0);
3389 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
3390 BlitBitmapMasked(bitmap, drawto,
3391 VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
3392 VX + VXSIZE - i, VY + j);
3393 SetClipOrigin(bitmap, gc,
3394 VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
3395 BlitBitmapMasked(bitmap, drawto,
3396 VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
3399 BlitBitmapMasked(bitmap, drawto,
3400 VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
3401 i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
3402 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
3403 BlitBitmapMasked(bitmap, drawto,
3404 VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
3406 VX + VXSIZE - i, VY + VYSIZE / 2 + j);
3409 redraw_mask |= REDRAW_DOOR_2;
3410 door_2_done = (a == VXSIZE);
3413 if (!(door_state & DOOR_NO_DELAY))
3417 if (game_status == GAME_MODE_MAIN)
3420 WaitUntilDelayReached(&door_delay, door_delay_value);
3425 if (door_state & DOOR_ACTION_1)
3426 door1 = door_state & DOOR_ACTION_1;
3427 if (door_state & DOOR_ACTION_2)
3428 door2 = door_state & DOOR_ACTION_2;
3430 return (door1 | door2);
3433 void DrawSpecialEditorDoor()
3435 /* draw bigger toolbox window */
3436 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
3437 DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
3439 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
3440 EX - 6, VY - 4, EXSIZE + 12, EYSIZE - VYSIZE + 4,
3443 redraw_mask |= REDRAW_ALL;
3446 void UndrawSpecialEditorDoor()
3448 /* draw normal tape recorder window */
3449 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
3450 EX - 6, EY - 12, EXSIZE + 12, EYSIZE - VYSIZE + 12,
3453 redraw_mask |= REDRAW_ALL;
3457 /* ---------- new tool button stuff ---------------------------------------- */
3459 /* graphic position values for tool buttons */
3460 #define TOOL_BUTTON_YES_XPOS 2
3461 #define TOOL_BUTTON_YES_YPOS 250
3462 #define TOOL_BUTTON_YES_GFX_YPOS 0
3463 #define TOOL_BUTTON_YES_XSIZE 46
3464 #define TOOL_BUTTON_YES_YSIZE 28
3465 #define TOOL_BUTTON_NO_XPOS 52
3466 #define TOOL_BUTTON_NO_YPOS TOOL_BUTTON_YES_YPOS
3467 #define TOOL_BUTTON_NO_GFX_YPOS TOOL_BUTTON_YES_GFX_YPOS
3468 #define TOOL_BUTTON_NO_XSIZE TOOL_BUTTON_YES_XSIZE
3469 #define TOOL_BUTTON_NO_YSIZE TOOL_BUTTON_YES_YSIZE
3470 #define TOOL_BUTTON_CONFIRM_XPOS TOOL_BUTTON_YES_XPOS
3471 #define TOOL_BUTTON_CONFIRM_YPOS TOOL_BUTTON_YES_YPOS
3472 #define TOOL_BUTTON_CONFIRM_GFX_YPOS 30
3473 #define TOOL_BUTTON_CONFIRM_XSIZE 96
3474 #define TOOL_BUTTON_CONFIRM_YSIZE TOOL_BUTTON_YES_YSIZE
3475 #define TOOL_BUTTON_PLAYER_XSIZE 30
3476 #define TOOL_BUTTON_PLAYER_YSIZE 30
3477 #define TOOL_BUTTON_PLAYER_GFX_XPOS 5
3478 #define TOOL_BUTTON_PLAYER_GFX_YPOS 185
3479 #define TOOL_BUTTON_PLAYER_XPOS (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
3480 #define TOOL_BUTTON_PLAYER_YPOS (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
3481 #define TOOL_BUTTON_PLAYER1_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3482 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
3483 #define TOOL_BUTTON_PLAYER2_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3484 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
3485 #define TOOL_BUTTON_PLAYER3_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3486 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
3487 #define TOOL_BUTTON_PLAYER4_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3488 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
3489 #define TOOL_BUTTON_PLAYER1_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3490 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
3491 #define TOOL_BUTTON_PLAYER2_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3492 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
3493 #define TOOL_BUTTON_PLAYER3_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3494 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
3495 #define TOOL_BUTTON_PLAYER4_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3496 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
3505 } toolbutton_info[NUM_TOOL_BUTTONS] =
3508 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_GFX_YPOS,
3509 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_YPOS,
3510 TOOL_BUTTON_YES_XSIZE, TOOL_BUTTON_YES_YSIZE,
3515 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_GFX_YPOS,
3516 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_YPOS,
3517 TOOL_BUTTON_NO_XSIZE, TOOL_BUTTON_NO_YSIZE,
3522 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_GFX_YPOS,
3523 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_YPOS,
3524 TOOL_BUTTON_CONFIRM_XSIZE, TOOL_BUTTON_CONFIRM_YSIZE,
3525 TOOL_CTRL_ID_CONFIRM,
3529 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3530 TOOL_BUTTON_PLAYER1_XPOS, TOOL_BUTTON_PLAYER1_YPOS,
3531 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3532 TOOL_CTRL_ID_PLAYER_1,
3536 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3537 TOOL_BUTTON_PLAYER2_XPOS, TOOL_BUTTON_PLAYER2_YPOS,
3538 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3539 TOOL_CTRL_ID_PLAYER_2,
3543 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3544 TOOL_BUTTON_PLAYER3_XPOS, TOOL_BUTTON_PLAYER3_YPOS,
3545 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3546 TOOL_CTRL_ID_PLAYER_3,
3550 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3551 TOOL_BUTTON_PLAYER4_XPOS, TOOL_BUTTON_PLAYER4_YPOS,
3552 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3553 TOOL_CTRL_ID_PLAYER_4,
3558 void CreateToolButtons()
3562 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3564 Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
3565 Bitmap *deco_bitmap = None;
3566 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
3567 struct GadgetInfo *gi;
3568 unsigned long event_mask;
3569 int gd_xoffset, gd_yoffset;
3570 int gd_x1, gd_x2, gd_y;
3573 event_mask = GD_EVENT_RELEASED;
3575 gd_xoffset = toolbutton_info[i].xpos;
3576 gd_yoffset = toolbutton_info[i].ypos;
3577 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
3578 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
3579 gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
3581 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
3583 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
3585 getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr),
3586 &deco_bitmap, &deco_x, &deco_y);
3587 deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
3588 deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
3591 gi = CreateGadget(GDI_CUSTOM_ID, id,
3592 GDI_INFO_TEXT, toolbutton_info[i].infotext,
3593 GDI_X, DX + toolbutton_info[i].x,
3594 GDI_Y, DY + toolbutton_info[i].y,
3595 GDI_WIDTH, toolbutton_info[i].width,
3596 GDI_HEIGHT, toolbutton_info[i].height,
3597 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
3598 GDI_STATE, GD_BUTTON_UNPRESSED,
3599 GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
3600 GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
3601 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
3602 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
3603 GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
3604 GDI_DECORATION_SHIFTING, 1, 1,
3605 GDI_DIRECT_DRAW, FALSE,
3606 GDI_EVENT_MASK, event_mask,
3607 GDI_CALLBACK_ACTION, HandleToolButtons,
3611 Error(ERR_EXIT, "cannot create gadget");
3613 tool_gadget[id] = gi;
3617 void FreeToolButtons()
3621 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3622 FreeGadget(tool_gadget[i]);
3625 static void UnmapToolButtons()
3629 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3630 UnmapGadget(tool_gadget[i]);
3633 static void HandleToolButtons(struct GadgetInfo *gi)
3635 request_gadget_id = gi->custom_id;
3638 static struct Mapping_EM_to_RND_object
3641 boolean is_rnd_to_em_mapping; /* unique mapping EM <-> RND */
3642 boolean is_backside; /* backside of moving element */
3648 em_object_mapping_list[] =
3651 Xblank, TRUE, FALSE,
3655 Yacid_splash_eB, FALSE, FALSE,
3656 EL_ACID_SPLASH_RIGHT, -1, -1
3659 Yacid_splash_wB, FALSE, FALSE,
3660 EL_ACID_SPLASH_LEFT, -1, -1
3663 #ifdef EM_ENGINE_BAD_ROLL
3665 Xstone_force_e, FALSE, FALSE,
3666 EL_ROCK, -1, MV_BIT_RIGHT
3669 Xstone_force_w, FALSE, FALSE,
3670 EL_ROCK, -1, MV_BIT_LEFT
3673 Xnut_force_e, FALSE, FALSE,
3674 EL_NUT, -1, MV_BIT_RIGHT
3677 Xnut_force_w, FALSE, FALSE,
3678 EL_NUT, -1, MV_BIT_LEFT
3681 Xspring_force_e, FALSE, FALSE,
3682 EL_SPRING, -1, MV_BIT_RIGHT
3685 Xspring_force_w, FALSE, FALSE,
3686 EL_SPRING, -1, MV_BIT_LEFT
3689 Xemerald_force_e, FALSE, FALSE,
3690 EL_EMERALD, -1, MV_BIT_RIGHT
3693 Xemerald_force_w, FALSE, FALSE,
3694 EL_EMERALD, -1, MV_BIT_LEFT
3697 Xdiamond_force_e, FALSE, FALSE,
3698 EL_DIAMOND, -1, MV_BIT_RIGHT
3701 Xdiamond_force_w, FALSE, FALSE,
3702 EL_DIAMOND, -1, MV_BIT_LEFT
3705 Xbomb_force_e, FALSE, FALSE,
3706 EL_BOMB, -1, MV_BIT_RIGHT
3709 Xbomb_force_w, FALSE, FALSE,
3710 EL_BOMB, -1, MV_BIT_LEFT
3712 #endif /* EM_ENGINE_BAD_ROLL */
3715 Xstone, TRUE, FALSE,
3719 Xstone_pause, FALSE, FALSE,
3723 Xstone_fall, FALSE, FALSE,
3727 Ystone_s, FALSE, FALSE,
3728 EL_ROCK, ACTION_FALLING, -1
3731 Ystone_sB, FALSE, TRUE,
3732 EL_ROCK, ACTION_FALLING, -1
3735 Ystone_e, FALSE, FALSE,
3736 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
3739 Ystone_eB, FALSE, TRUE,
3740 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
3743 Ystone_w, FALSE, FALSE,
3744 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
3747 Ystone_wB, FALSE, TRUE,
3748 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
3755 Xnut_pause, FALSE, FALSE,
3759 Xnut_fall, FALSE, FALSE,
3763 Ynut_s, FALSE, FALSE,
3764 EL_NUT, ACTION_FALLING, -1
3767 Ynut_sB, FALSE, TRUE,
3768 EL_NUT, ACTION_FALLING, -1
3771 Ynut_e, FALSE, FALSE,
3772 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
3775 Ynut_eB, FALSE, TRUE,
3776 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
3779 Ynut_w, FALSE, FALSE,
3780 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
3783 Ynut_wB, FALSE, TRUE,
3784 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
3787 Xbug_n, TRUE, FALSE,
3791 Xbug_e, TRUE, FALSE,
3792 EL_BUG_RIGHT, -1, -1
3795 Xbug_s, TRUE, FALSE,
3799 Xbug_w, TRUE, FALSE,
3803 Xbug_gon, FALSE, FALSE,
3807 Xbug_goe, FALSE, FALSE,
3808 EL_BUG_RIGHT, -1, -1
3811 Xbug_gos, FALSE, FALSE,
3815 Xbug_gow, FALSE, FALSE,
3819 Ybug_n, FALSE, FALSE,
3820 EL_BUG, ACTION_MOVING, MV_BIT_UP
3823 Ybug_nB, FALSE, TRUE,
3824 EL_BUG, ACTION_MOVING, MV_BIT_UP
3827 Ybug_e, FALSE, FALSE,
3828 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
3831 Ybug_eB, FALSE, TRUE,
3832 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
3835 Ybug_s, FALSE, FALSE,
3836 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
3839 Ybug_sB, FALSE, TRUE,
3840 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
3843 Ybug_w, FALSE, FALSE,
3844 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
3847 Ybug_wB, FALSE, TRUE,
3848 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
3851 Ybug_w_n, FALSE, FALSE,
3852 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
3855 Ybug_n_e, FALSE, FALSE,
3856 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
3859 Ybug_e_s, FALSE, FALSE,
3860 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
3863 Ybug_s_w, FALSE, FALSE,
3864 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
3867 Ybug_e_n, FALSE, FALSE,
3868 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
3871 Ybug_s_e, FALSE, FALSE,
3872 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
3875 Ybug_w_s, FALSE, FALSE,
3876 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
3879 Ybug_n_w, FALSE, FALSE,
3880 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
3883 Ybug_stone, FALSE, FALSE,
3884 EL_BUG, ACTION_SMASHED_BY_ROCK, -1
3887 Ybug_spring, FALSE, FALSE,
3888 EL_BUG, ACTION_SMASHED_BY_SPRING, -1
3891 Xtank_n, TRUE, FALSE,
3892 EL_SPACESHIP_UP, -1, -1
3895 Xtank_e, TRUE, FALSE,
3896 EL_SPACESHIP_RIGHT, -1, -1
3899 Xtank_s, TRUE, FALSE,
3900 EL_SPACESHIP_DOWN, -1, -1
3903 Xtank_w, TRUE, FALSE,
3904 EL_SPACESHIP_LEFT, -1, -1
3907 Xtank_gon, FALSE, FALSE,
3908 EL_SPACESHIP_UP, -1, -1
3911 Xtank_goe, FALSE, FALSE,
3912 EL_SPACESHIP_RIGHT, -1, -1
3915 Xtank_gos, FALSE, FALSE,
3916 EL_SPACESHIP_DOWN, -1, -1
3919 Xtank_gow, FALSE, FALSE,
3920 EL_SPACESHIP_LEFT, -1, -1
3923 Ytank_n, FALSE, FALSE,
3924 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
3927 Ytank_nB, FALSE, TRUE,
3928 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
3931 Ytank_e, FALSE, FALSE,
3932 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
3935 Ytank_eB, FALSE, TRUE,
3936 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
3939 Ytank_s, FALSE, FALSE,
3940 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
3943 Ytank_sB, FALSE, TRUE,
3944 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
3947 Ytank_w, FALSE, FALSE,
3948 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
3951 Ytank_wB, FALSE, TRUE,
3952 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
3955 Ytank_w_n, FALSE, FALSE,
3956 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
3959 Ytank_n_e, FALSE, FALSE,
3960 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
3963 Ytank_e_s, FALSE, FALSE,
3964 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
3967 Ytank_s_w, FALSE, FALSE,
3968 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
3971 Ytank_e_n, FALSE, FALSE,
3972 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
3975 Ytank_s_e, FALSE, FALSE,
3976 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
3979 Ytank_w_s, FALSE, FALSE,
3980 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
3983 Ytank_n_w, FALSE, FALSE,
3984 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
3987 Ytank_stone, FALSE, FALSE,
3988 EL_SPACESHIP, ACTION_SMASHED_BY_ROCK, -1
3991 Ytank_spring, FALSE, FALSE,
3992 EL_SPACESHIP, ACTION_SMASHED_BY_SPRING, -1
3995 Xandroid, TRUE, FALSE,
3996 EL_EMC_ANDROID, ACTION_ACTIVE, -1
3999 Xandroid_1_n, FALSE, FALSE,
4000 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
4003 Xandroid_2_n, FALSE, FALSE,
4004 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
4007 Xandroid_1_e, FALSE, FALSE,
4008 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
4011 Xandroid_2_e, FALSE, FALSE,
4012 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
4015 Xandroid_1_w, FALSE, FALSE,
4016 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
4019 Xandroid_2_w, FALSE, FALSE,
4020 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
4023 Xandroid_1_s, FALSE, FALSE,
4024 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
4027 Xandroid_2_s, FALSE, FALSE,
4028 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
4031 Yandroid_n, FALSE, FALSE,
4032 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
4035 Yandroid_nB, FALSE, TRUE,
4036 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
4039 Yandroid_ne, FALSE, FALSE,
4040 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPRIGHT
4043 Yandroid_neB, FALSE, TRUE,
4044 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPRIGHT
4047 Yandroid_e, FALSE, FALSE,
4048 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
4051 Yandroid_eB, FALSE, TRUE,
4052 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
4055 Yandroid_se, FALSE, FALSE,
4056 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNRIGHT
4059 Yandroid_seB, FALSE, TRUE,
4060 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNRIGHT
4063 Yandroid_s, FALSE, FALSE,
4064 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
4067 Yandroid_sB, FALSE, TRUE,
4068 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
4071 Yandroid_sw, FALSE, FALSE,
4072 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNLEFT
4075 Yandroid_swB, FALSE, TRUE,
4076 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNLEFT
4079 Yandroid_w, FALSE, FALSE,
4080 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
4083 Yandroid_wB, FALSE, TRUE,
4084 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
4087 Yandroid_nw, FALSE, FALSE,
4088 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPLEFT
4091 Yandroid_nwB, FALSE, TRUE,
4092 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPLEFT
4095 Xspring, TRUE, FALSE,
4099 Xspring_pause, FALSE, FALSE,
4103 Xspring_e, FALSE, FALSE,
4107 Xspring_w, FALSE, FALSE,
4111 Xspring_fall, FALSE, FALSE,
4115 Yspring_s, FALSE, FALSE,
4116 EL_SPRING, ACTION_FALLING, -1
4119 Yspring_sB, FALSE, TRUE,
4120 EL_SPRING, ACTION_FALLING, -1
4123 Yspring_e, FALSE, FALSE,
4124 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
4127 Yspring_eB, FALSE, TRUE,
4128 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
4131 Yspring_w, FALSE, FALSE,
4132 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
4135 Yspring_wB, FALSE, TRUE,
4136 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
4139 Yspring_kill_e, FALSE, FALSE,
4140 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
4143 Yspring_kill_eB, FALSE, TRUE,
4144 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
4147 Yspring_kill_w, FALSE, FALSE,
4148 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
4151 Yspring_kill_wB, FALSE, TRUE,
4152 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
4155 Xeater_n, TRUE, FALSE,
4156 EL_YAMYAM_UP, -1, -1
4159 Xeater_e, TRUE, FALSE,
4160 EL_YAMYAM_RIGHT, -1, -1
4163 Xeater_w, TRUE, FALSE,
4164 EL_YAMYAM_LEFT, -1, -1
4167 Xeater_s, TRUE, FALSE,
4168 EL_YAMYAM_DOWN, -1, -1
4171 Yeater_n, FALSE, FALSE,
4172 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
4175 Yeater_nB, FALSE, TRUE,
4176 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
4179 Yeater_e, FALSE, FALSE,
4180 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
4183 Yeater_eB, FALSE, TRUE,
4184 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
4187 Yeater_s, FALSE, FALSE,
4188 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
4191 Yeater_sB, FALSE, TRUE,
4192 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
4195 Yeater_w, FALSE, FALSE,
4196 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
4199 Yeater_wB, FALSE, TRUE,
4200 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
4203 Yeater_stone, FALSE, FALSE,
4204 EL_YAMYAM, ACTION_SMASHED_BY_ROCK, -1
4207 Yeater_spring, FALSE, FALSE,
4208 EL_YAMYAM, ACTION_SMASHED_BY_SPRING, -1
4211 Xalien, TRUE, FALSE,
4215 Xalien_pause, FALSE, FALSE,
4219 Yalien_n, FALSE, FALSE,
4220 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
4223 Yalien_nB, FALSE, TRUE,
4224 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
4227 Yalien_e, FALSE, FALSE,
4228 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
4231 Yalien_eB, FALSE, TRUE,
4232 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
4235 Yalien_s, FALSE, FALSE,
4236 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
4239 Yalien_sB, FALSE, TRUE,
4240 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
4243 Yalien_w, FALSE, FALSE,
4244 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
4247 Yalien_wB, FALSE, TRUE,
4248 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
4251 Yalien_stone, FALSE, FALSE,
4252 EL_ROBOT, ACTION_SMASHED_BY_ROCK, -1
4255 Yalien_spring, FALSE, FALSE,
4256 EL_ROBOT, ACTION_SMASHED_BY_SPRING, -1
4259 Xemerald, TRUE, FALSE,
4263 Xemerald_pause, FALSE, FALSE,
4267 Xemerald_fall, FALSE, FALSE,
4271 Xemerald_shine, FALSE, FALSE,
4272 EL_EMERALD, ACTION_TWINKLING, -1
4275 Yemerald_s, FALSE, FALSE,
4276 EL_EMERALD, ACTION_FALLING, -1
4279 Yemerald_sB, FALSE, TRUE,
4280 EL_EMERALD, ACTION_FALLING, -1
4283 Yemerald_e, FALSE, FALSE,
4284 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
4287 Yemerald_eB, FALSE, TRUE,
4288 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
4291 Yemerald_w, FALSE, FALSE,
4292 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
4295 Yemerald_wB, FALSE, TRUE,
4296 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
4299 Yemerald_eat, FALSE, FALSE,
4300 EL_EMERALD, ACTION_COLLECTING, -1
4303 Yemerald_stone, FALSE, FALSE,
4304 EL_NUT, ACTION_BREAKING, -1
4307 Xdiamond, TRUE, FALSE,
4311 Xdiamond_pause, FALSE, FALSE,
4315 Xdiamond_fall, FALSE, FALSE,
4319 Xdiamond_shine, FALSE, FALSE,
4320 EL_DIAMOND, ACTION_TWINKLING, -1
4323 Ydiamond_s, FALSE, FALSE,
4324 EL_DIAMOND, ACTION_FALLING, -1
4327 Ydiamond_sB, FALSE, TRUE,
4328 EL_DIAMOND, ACTION_FALLING, -1
4331 Ydiamond_e, FALSE, FALSE,
4332 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
4335 Ydiamond_eB, FALSE, TRUE,
4336 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
4339 Ydiamond_w, FALSE, FALSE,
4340 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
4343 Ydiamond_wB, FALSE, TRUE,
4344 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
4347 Ydiamond_eat, FALSE, FALSE,
4348 EL_DIAMOND, ACTION_COLLECTING, -1
4351 Ydiamond_stone, FALSE, FALSE,
4352 EL_DIAMOND, ACTION_SMASHED_BY_ROCK, -1
4355 Xdrip_fall, TRUE, FALSE,
4356 EL_AMOEBA_DROP, -1, -1
4359 Xdrip_stretch, FALSE, FALSE,
4360 EL_AMOEBA_DROP, ACTION_FALLING, -1
4363 Xdrip_stretchB, FALSE, TRUE,
4364 EL_AMOEBA_DROP, ACTION_FALLING, -1
4367 Xdrip_eat, FALSE, FALSE,
4368 EL_AMOEBA_DROP, ACTION_GROWING, -1
4371 Ydrip_s1, FALSE, FALSE,
4372 EL_AMOEBA_DROP, ACTION_FALLING, -1
4375 Ydrip_s1B, FALSE, TRUE,
4376 EL_AMOEBA_DROP, ACTION_FALLING, -1
4379 Ydrip_s2, FALSE, FALSE,
4380 EL_AMOEBA_DROP, ACTION_FALLING, -1
4383 Ydrip_s2B, FALSE, TRUE,
4384 EL_AMOEBA_DROP, ACTION_FALLING, -1
4391 Xbomb_pause, FALSE, FALSE,
4395 Xbomb_fall, FALSE, FALSE,
4399 Ybomb_s, FALSE, FALSE,
4400 EL_BOMB, ACTION_FALLING, -1
4403 Ybomb_sB, FALSE, TRUE,
4404 EL_BOMB, ACTION_FALLING, -1
4407 Ybomb_e, FALSE, FALSE,
4408 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
4411 Ybomb_eB, FALSE, TRUE,
4412 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
4415 Ybomb_w, FALSE, FALSE,
4416 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
4419 Ybomb_wB, FALSE, TRUE,
4420 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
4423 Ybomb_eat, FALSE, FALSE,
4424 EL_BOMB, ACTION_ACTIVATING, -1
4427 Xballoon, TRUE, FALSE,
4431 Yballoon_n, FALSE, FALSE,
4432 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
4435 Yballoon_nB, FALSE, TRUE,
4436 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
4439 Yballoon_e, FALSE, FALSE,
4440 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
4443 Yballoon_eB, FALSE, TRUE,
4444 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
4447 Yballoon_s, FALSE, FALSE,
4448 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
4451 Yballoon_sB, FALSE, TRUE,
4452 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
4455 Yballoon_w, FALSE, FALSE,
4456 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
4459 Yballoon_wB, FALSE, TRUE,
4460 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
4463 Xgrass, TRUE, FALSE,
4464 EL_EMC_GRASS, -1, -1
4467 Ygrass_nB, FALSE, FALSE,
4468 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_UP
4471 Ygrass_eB, FALSE, FALSE,
4472 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_RIGHT
4475 Ygrass_sB, FALSE, FALSE,
4476 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_DOWN
4479 Ygrass_wB, FALSE, FALSE,
4480 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_LEFT
4487 Ydirt_nB, FALSE, FALSE,
4488 EL_SAND, ACTION_DIGGING, MV_BIT_UP
4491 Ydirt_eB, FALSE, FALSE,
4492 EL_SAND, ACTION_DIGGING, MV_BIT_RIGHT
4495 Ydirt_sB, FALSE, FALSE,
4496 EL_SAND, ACTION_DIGGING, MV_BIT_DOWN
4499 Ydirt_wB, FALSE, FALSE,
4500 EL_SAND, ACTION_DIGGING, MV_BIT_LEFT
4503 Xacid_ne, TRUE, FALSE,
4504 EL_ACID_POOL_TOPRIGHT, -1, -1
4507 Xacid_se, TRUE, FALSE,
4508 EL_ACID_POOL_BOTTOMRIGHT, -1, -1
4511 Xacid_s, TRUE, FALSE,
4512 EL_ACID_POOL_BOTTOM, -1, -1
4515 Xacid_sw, TRUE, FALSE,
4516 EL_ACID_POOL_BOTTOMLEFT, -1, -1
4519 Xacid_nw, TRUE, FALSE,
4520 EL_ACID_POOL_TOPLEFT, -1, -1
4523 Xacid_1, TRUE, FALSE,
4527 Xacid_2, FALSE, FALSE,
4531 Xacid_3, FALSE, FALSE,
4535 Xacid_4, FALSE, FALSE,
4539 Xacid_5, FALSE, FALSE,
4543 Xacid_6, FALSE, FALSE,
4547 Xacid_7, FALSE, FALSE,
4551 Xacid_8, FALSE, FALSE,
4555 Xball_1, TRUE, FALSE,
4556 EL_EMC_MAGIC_BALL, -1, -1
4559 Xball_1B, FALSE, FALSE,
4560 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4563 Xball_2, FALSE, FALSE,
4564 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4567 Xball_2B, FALSE, FALSE,
4568 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4571 Yball_eat, FALSE, FALSE,
4572 EL_EMC_MAGIC_BALL, ACTION_DROPPING, -1
4575 Ykey_1_eat, FALSE, FALSE,
4576 EL_EM_KEY_1, ACTION_COLLECTING, -1
4579 Ykey_2_eat, FALSE, FALSE,
4580 EL_EM_KEY_2, ACTION_COLLECTING, -1
4583 Ykey_3_eat, FALSE, FALSE,
4584 EL_EM_KEY_3, ACTION_COLLECTING, -1
4587 Ykey_4_eat, FALSE, FALSE,
4588 EL_EM_KEY_4, ACTION_COLLECTING, -1
4591 Ykey_5_eat, FALSE, FALSE,
4592 EL_EMC_KEY_5, ACTION_COLLECTING, -1
4595 Ykey_6_eat, FALSE, FALSE,
4596 EL_EMC_KEY_6, ACTION_COLLECTING, -1
4599 Ykey_7_eat, FALSE, FALSE,
4600 EL_EMC_KEY_7, ACTION_COLLECTING, -1
4603 Ykey_8_eat, FALSE, FALSE,
4604 EL_EMC_KEY_8, ACTION_COLLECTING, -1
4607 Ylenses_eat, FALSE, FALSE,
4608 EL_EMC_LENSES, ACTION_COLLECTING, -1
4611 Ymagnify_eat, FALSE, FALSE,
4612 EL_EMC_MAGNIFIER, ACTION_COLLECTING, -1
4615 Ygrass_eat, FALSE, FALSE,
4616 EL_EMC_GRASS, ACTION_SNAPPING, -1
4619 Ydirt_eat, FALSE, FALSE,
4620 EL_SAND, ACTION_SNAPPING, -1
4623 Xgrow_ns, TRUE, FALSE,
4624 EL_EXPANDABLE_WALL_VERTICAL, -1, -1
4627 Ygrow_ns_eat, FALSE, FALSE,
4628 EL_EXPANDABLE_WALL_VERTICAL, ACTION_GROWING, -1
4631 Xgrow_ew, TRUE, FALSE,
4632 EL_EXPANDABLE_WALL_HORIZONTAL, -1, -1
4635 Ygrow_ew_eat, FALSE, FALSE,
4636 EL_EXPANDABLE_WALL_HORIZONTAL, ACTION_GROWING, -1
4639 Xwonderwall, TRUE, FALSE,
4640 EL_MAGIC_WALL, -1, -1
4643 XwonderwallB, FALSE, FALSE,
4644 EL_MAGIC_WALL, ACTION_ACTIVE, -1
4647 Xamoeba_1, TRUE, FALSE,
4648 EL_AMOEBA_DRY, ACTION_OTHER, -1
4651 Xamoeba_2, FALSE, FALSE,
4652 EL_AMOEBA_DRY, ACTION_OTHER, -1
4655 Xamoeba_3, FALSE, FALSE,
4656 EL_AMOEBA_DRY, ACTION_OTHER, -1
4659 Xamoeba_4, FALSE, FALSE,
4660 EL_AMOEBA_DRY, ACTION_OTHER, -1
4663 Xamoeba_5, TRUE, FALSE,
4664 EL_AMOEBA_WET, ACTION_OTHER, -1
4667 Xamoeba_6, FALSE, FALSE,
4668 EL_AMOEBA_WET, ACTION_OTHER, -1
4671 Xamoeba_7, FALSE, FALSE,
4672 EL_AMOEBA_WET, ACTION_OTHER, -1
4675 Xamoeba_8, FALSE, FALSE,
4676 EL_AMOEBA_WET, ACTION_OTHER, -1
4679 Xdoor_1, TRUE, FALSE,
4680 EL_EM_GATE_1, -1, -1
4683 Xdoor_2, TRUE, FALSE,
4684 EL_EM_GATE_2, -1, -1
4687 Xdoor_3, TRUE, FALSE,
4688 EL_EM_GATE_3, -1, -1
4691 Xdoor_4, TRUE, FALSE,
4692 EL_EM_GATE_4, -1, -1
4695 Xdoor_5, TRUE, FALSE,
4696 EL_EMC_GATE_5, -1, -1
4699 Xdoor_6, TRUE, FALSE,
4700 EL_EMC_GATE_6, -1, -1
4703 Xdoor_7, TRUE, FALSE,
4704 EL_EMC_GATE_7, -1, -1
4707 Xdoor_8, TRUE, FALSE,
4708 EL_EMC_GATE_8, -1, -1
4711 Xkey_1, TRUE, FALSE,
4715 Xkey_2, TRUE, FALSE,
4719 Xkey_3, TRUE, FALSE,
4723 Xkey_4, TRUE, FALSE,
4727 Xkey_5, TRUE, FALSE,
4728 EL_EMC_KEY_5, -1, -1
4731 Xkey_6, TRUE, FALSE,
4732 EL_EMC_KEY_6, -1, -1
4735 Xkey_7, TRUE, FALSE,
4736 EL_EMC_KEY_7, -1, -1
4739 Xkey_8, TRUE, FALSE,
4740 EL_EMC_KEY_8, -1, -1
4743 Xwind_n, TRUE, FALSE,
4744 EL_BALLOON_SWITCH_UP, -1, -1
4747 Xwind_e, TRUE, FALSE,
4748 EL_BALLOON_SWITCH_RIGHT, -1, -1
4751 Xwind_s, TRUE, FALSE,
4752 EL_BALLOON_SWITCH_DOWN, -1, -1
4755 Xwind_w, TRUE, FALSE,
4756 EL_BALLOON_SWITCH_LEFT, -1, -1
4759 Xwind_nesw, TRUE, FALSE,
4760 EL_BALLOON_SWITCH_ANY, -1, -1
4763 Xwind_stop, TRUE, FALSE,
4764 EL_BALLOON_SWITCH_NONE, -1, -1
4768 EL_EM_EXIT_CLOSED, -1, -1
4771 Xexit_1, TRUE, FALSE,
4772 EL_EM_EXIT_OPEN, -1, -1
4775 Xexit_2, FALSE, FALSE,
4776 EL_EM_EXIT_OPEN, -1, -1
4779 Xexit_3, FALSE, FALSE,
4780 EL_EM_EXIT_OPEN, -1, -1
4783 Xdynamite, TRUE, FALSE,
4784 EL_EM_DYNAMITE, -1, -1
4787 Ydynamite_eat, FALSE, FALSE,
4788 EL_EM_DYNAMITE, ACTION_COLLECTING, -1
4791 Xdynamite_1, TRUE, FALSE,
4792 EL_EM_DYNAMITE_ACTIVE, -1, -1
4795 Xdynamite_2, FALSE, FALSE,
4796 EL_EM_DYNAMITE_ACTIVE, -1, -1
4799 Xdynamite_3, FALSE, FALSE,
4800 EL_EM_DYNAMITE_ACTIVE, -1, -1
4803 Xdynamite_4, FALSE, FALSE,
4804 EL_EM_DYNAMITE_ACTIVE, -1, -1
4807 Xbumper, TRUE, FALSE,
4808 EL_EMC_SPRING_BUMPER, -1, -1
4811 XbumperB, FALSE, FALSE,
4812 EL_EMC_SPRING_BUMPER, ACTION_ACTIVE, -1
4815 Xwheel, TRUE, FALSE,
4816 EL_ROBOT_WHEEL, -1, -1
4819 XwheelB, FALSE, FALSE,
4820 EL_ROBOT_WHEEL, ACTION_ACTIVE, -1
4823 Xswitch, TRUE, FALSE,
4824 EL_EMC_MAGIC_BALL_SWITCH, -1, -1
4827 XswitchB, FALSE, FALSE,
4828 EL_EMC_MAGIC_BALL_SWITCH, ACTION_ACTIVE, -1
4832 EL_QUICKSAND_EMPTY, -1, -1
4835 Xsand_stone, TRUE, FALSE,
4836 EL_QUICKSAND_FULL, -1, -1
4839 Xsand_stonein_1, FALSE, TRUE,
4840 EL_ROCK, ACTION_FILLING, -1
4843 Xsand_stonein_2, FALSE, TRUE,
4844 EL_ROCK, ACTION_FILLING, -1
4847 Xsand_stonein_3, FALSE, TRUE,
4848 EL_ROCK, ACTION_FILLING, -1
4851 Xsand_stonein_4, FALSE, TRUE,
4852 EL_ROCK, ACTION_FILLING, -1
4855 Xsand_stonesand_1, FALSE, FALSE,
4856 EL_QUICKSAND_FULL, -1, -1
4859 Xsand_stonesand_2, FALSE, FALSE,
4860 EL_QUICKSAND_FULL, -1, -1
4863 Xsand_stonesand_3, FALSE, FALSE,
4864 EL_QUICKSAND_FULL, -1, -1
4867 Xsand_stonesand_4, FALSE, FALSE,
4868 EL_QUICKSAND_FULL, -1, -1
4871 Xsand_stoneout_1, FALSE, FALSE,
4872 EL_ROCK, ACTION_EMPTYING, -1
4875 Xsand_stoneout_2, FALSE, FALSE,
4876 EL_ROCK, ACTION_EMPTYING, -1
4879 Xsand_sandstone_1, FALSE, FALSE,
4880 EL_QUICKSAND_FULL, -1, -1
4883 Xsand_sandstone_2, FALSE, FALSE,
4884 EL_QUICKSAND_FULL, -1, -1
4887 Xsand_sandstone_3, FALSE, FALSE,
4888 EL_QUICKSAND_FULL, -1, -1
4891 Xsand_sandstone_4, FALSE, FALSE,
4892 EL_QUICKSAND_FULL, -1, -1
4895 Xplant, TRUE, FALSE,
4896 EL_EMC_PLANT, -1, -1
4899 Yplant, FALSE, FALSE,
4900 EL_EMC_PLANT, -1, -1
4903 Xlenses, TRUE, FALSE,
4904 EL_EMC_LENSES, -1, -1
4907 Xmagnify, TRUE, FALSE,
4908 EL_EMC_MAGNIFIER, -1, -1
4911 Xdripper, TRUE, FALSE,
4912 EL_EMC_DRIPPER, -1, -1
4915 XdripperB, FALSE, FALSE,
4916 EL_EMC_DRIPPER, ACTION_ACTIVE, -1
4919 Xfake_blank, TRUE, FALSE,
4920 EL_INVISIBLE_WALL, -1, -1
4923 Xfake_blankB, FALSE, FALSE,
4924 EL_INVISIBLE_WALL, ACTION_ACTIVE, -1
4927 Xfake_grass, TRUE, FALSE,
4928 EL_EMC_FAKE_GRASS, -1, -1
4931 Xfake_grassB, FALSE, FALSE,
4932 EL_EMC_FAKE_GRASS, ACTION_ACTIVE, -1
4935 Xfake_door_1, TRUE, FALSE,
4936 EL_EM_GATE_1_GRAY, -1, -1
4939 Xfake_door_2, TRUE, FALSE,
4940 EL_EM_GATE_2_GRAY, -1, -1
4943 Xfake_door_3, TRUE, FALSE,
4944 EL_EM_GATE_3_GRAY, -1, -1
4947 Xfake_door_4, TRUE, FALSE,
4948 EL_EM_GATE_4_GRAY, -1, -1
4951 Xfake_door_5, TRUE, FALSE,
4952 EL_EMC_GATE_5_GRAY, -1, -1
4955 Xfake_door_6, TRUE, FALSE,
4956 EL_EMC_GATE_6_GRAY, -1, -1
4959 Xfake_door_7, TRUE, FALSE,
4960 EL_EMC_GATE_7_GRAY, -1, -1
4963 Xfake_door_8, TRUE, FALSE,
4964 EL_EMC_GATE_8_GRAY, -1, -1
4967 Xfake_acid_1, TRUE, FALSE,
4968 EL_EMC_FAKE_ACID, -1, -1
4971 Xfake_acid_2, FALSE, FALSE,
4972 EL_EMC_FAKE_ACID, -1, -1
4975 Xfake_acid_3, FALSE, FALSE,
4976 EL_EMC_FAKE_ACID, -1, -1
4979 Xfake_acid_4, FALSE, FALSE,
4980 EL_EMC_FAKE_ACID, -1, -1
4983 Xfake_acid_5, FALSE, FALSE,
4984 EL_EMC_FAKE_ACID, -1, -1
4987 Xfake_acid_6, FALSE, FALSE,
4988 EL_EMC_FAKE_ACID, -1, -1
4991 Xfake_acid_7, FALSE, FALSE,
4992 EL_EMC_FAKE_ACID, -1, -1
4995 Xfake_acid_8, FALSE, FALSE,
4996 EL_EMC_FAKE_ACID, -1, -1
4999 Xsteel_1, TRUE, FALSE,
5000 EL_STEELWALL, -1, -1
5003 Xsteel_2, TRUE, FALSE,
5004 EL_EMC_STEELWALL_2, -1, -1
5007 Xsteel_3, TRUE, FALSE,
5008 EL_EMC_STEELWALL_3, -1, -1
5011 Xsteel_4, TRUE, FALSE,
5012 EL_EMC_STEELWALL_4, -1, -1
5015 Xwall_1, TRUE, FALSE,
5019 Xwall_2, TRUE, FALSE,
5020 EL_EMC_WALL_14, -1, -1
5023 Xwall_3, TRUE, FALSE,
5024 EL_EMC_WALL_15, -1, -1
5027 Xwall_4, TRUE, FALSE,
5028 EL_EMC_WALL_16, -1, -1
5031 Xround_wall_1, TRUE, FALSE,
5032 EL_WALL_SLIPPERY, -1, -1
5035 Xround_wall_2, TRUE, FALSE,
5036 EL_EMC_WALL_SLIPPERY_2, -1, -1
5039 Xround_wall_3, TRUE, FALSE,
5040 EL_EMC_WALL_SLIPPERY_3, -1, -1
5043 Xround_wall_4, TRUE, FALSE,
5044 EL_EMC_WALL_SLIPPERY_4, -1, -1
5047 Xdecor_1, TRUE, FALSE,
5048 EL_EMC_WALL_8, -1, -1
5051 Xdecor_2, TRUE, FALSE,
5052 EL_EMC_WALL_6, -1, -1
5055 Xdecor_3, TRUE, FALSE,
5056 EL_EMC_WALL_4, -1, -1
5059 Xdecor_4, TRUE, FALSE,
5060 EL_EMC_WALL_7, -1, -1
5063 Xdecor_5, TRUE, FALSE,
5064 EL_EMC_WALL_5, -1, -1
5067 Xdecor_6, TRUE, FALSE,
5068 EL_EMC_WALL_9, -1, -1
5071 Xdecor_7, TRUE, FALSE,
5072 EL_EMC_WALL_10, -1, -1
5075 Xdecor_8, TRUE, FALSE,
5076 EL_EMC_WALL_1, -1, -1
5079 Xdecor_9, TRUE, FALSE,
5080 EL_EMC_WALL_2, -1, -1
5083 Xdecor_10, TRUE, FALSE,
5084 EL_EMC_WALL_3, -1, -1
5087 Xdecor_11, TRUE, FALSE,
5088 EL_EMC_WALL_11, -1, -1
5091 Xdecor_12, TRUE, FALSE,
5092 EL_EMC_WALL_12, -1, -1
5095 Xalpha_0, TRUE, FALSE,
5096 EL_CHAR('0'), -1, -1
5099 Xalpha_1, TRUE, FALSE,
5100 EL_CHAR('1'), -1, -1
5103 Xalpha_2, TRUE, FALSE,
5104 EL_CHAR('2'), -1, -1
5107 Xalpha_3, TRUE, FALSE,
5108 EL_CHAR('3'), -1, -1
5111 Xalpha_4, TRUE, FALSE,
5112 EL_CHAR('4'), -1, -1
5115 Xalpha_5, TRUE, FALSE,
5116 EL_CHAR('5'), -1, -1
5119 Xalpha_6, TRUE, FALSE,
5120 EL_CHAR('6'), -1, -1
5123 Xalpha_7, TRUE, FALSE,
5124 EL_CHAR('7'), -1, -1
5127 Xalpha_8, TRUE, FALSE,
5128 EL_CHAR('8'), -1, -1
5131 Xalpha_9, TRUE, FALSE,
5132 EL_CHAR('9'), -1, -1
5135 Xalpha_excla, TRUE, FALSE,
5136 EL_CHAR('!'), -1, -1
5139 Xalpha_quote, TRUE, FALSE,
5140 EL_CHAR('"'), -1, -1
5143 Xalpha_comma, TRUE, FALSE,
5144 EL_CHAR(','), -1, -1
5147 Xalpha_minus, TRUE, FALSE,
5148 EL_CHAR('-'), -1, -1
5151 Xalpha_perio, TRUE, FALSE,
5152 EL_CHAR('.'), -1, -1
5155 Xalpha_colon, TRUE, FALSE,
5156 EL_CHAR(':'), -1, -1
5159 Xalpha_quest, TRUE, FALSE,
5160 EL_CHAR('?'), -1, -1
5163 Xalpha_a, TRUE, FALSE,
5164 EL_CHAR('A'), -1, -1
5167 Xalpha_b, TRUE, FALSE,
5168 EL_CHAR('B'), -1, -1
5171 Xalpha_c, TRUE, FALSE,
5172 EL_CHAR('C'), -1, -1
5175 Xalpha_d, TRUE, FALSE,
5176 EL_CHAR('D'), -1, -1
5179 Xalpha_e, TRUE, FALSE,
5180 EL_CHAR('E'), -1, -1
5183 Xalpha_f, TRUE, FALSE,
5184 EL_CHAR('F'), -1, -1
5187 Xalpha_g, TRUE, FALSE,
5188 EL_CHAR('G'), -1, -1
5191 Xalpha_h, TRUE, FALSE,
5192 EL_CHAR('H'), -1, -1
5195 Xalpha_i, TRUE, FALSE,
5196 EL_CHAR('I'), -1, -1
5199 Xalpha_j, TRUE, FALSE,
5200 EL_CHAR('J'), -1, -1
5203 Xalpha_k, TRUE, FALSE,
5204 EL_CHAR('K'), -1, -1
5207 Xalpha_l, TRUE, FALSE,
5208 EL_CHAR('L'), -1, -1
5211 Xalpha_m, TRUE, FALSE,
5212 EL_CHAR('M'), -1, -1
5215 Xalpha_n, TRUE, FALSE,
5216 EL_CHAR('N'), -1, -1
5219 Xalpha_o, TRUE, FALSE,
5220 EL_CHAR('O'), -1, -1
5223 Xalpha_p, TRUE, FALSE,
5224 EL_CHAR('P'), -1, -1
5227 Xalpha_q, TRUE, FALSE,
5228 EL_CHAR('Q'), -1, -1
5231 Xalpha_r, TRUE, FALSE,
5232 EL_CHAR('R'), -1, -1
5235 Xalpha_s, TRUE, FALSE,
5236 EL_CHAR('S'), -1, -1
5239 Xalpha_t, TRUE, FALSE,
5240 EL_CHAR('T'), -1, -1
5243 Xalpha_u, TRUE, FALSE,
5244 EL_CHAR('U'), -1, -1
5247 Xalpha_v, TRUE, FALSE,
5248 EL_CHAR('V'), -1, -1
5251 Xalpha_w, TRUE, FALSE,
5252 EL_CHAR('W'), -1, -1
5255 Xalpha_x, TRUE, FALSE,
5256 EL_CHAR('X'), -1, -1
5259 Xalpha_y, TRUE, FALSE,
5260 EL_CHAR('Y'), -1, -1
5263 Xalpha_z, TRUE, FALSE,
5264 EL_CHAR('Z'), -1, -1
5267 Xalpha_arrow_e, TRUE, FALSE,
5268 EL_CHAR('>'), -1, -1
5271 Xalpha_arrow_w, TRUE, FALSE,
5272 EL_CHAR('<'), -1, -1
5275 Xalpha_copyr, TRUE, FALSE,
5276 EL_CHAR('©'), -1, -1
5280 Xboom_bug, FALSE, FALSE,
5281 EL_BUG, ACTION_EXPLODING, -1
5284 Xboom_bomb, FALSE, FALSE,
5285 EL_BOMB, ACTION_EXPLODING, -1
5288 Xboom_android, FALSE, FALSE,
5289 EL_EMC_ANDROID, ACTION_OTHER, -1
5292 Xboom_1, FALSE, FALSE,
5293 EL_DEFAULT, ACTION_EXPLODING, -1
5296 Xboom_2, FALSE, FALSE,
5297 EL_DEFAULT, ACTION_EXPLODING, -1
5300 Znormal, FALSE, FALSE,
5304 Zdynamite, FALSE, FALSE,
5308 Zplayer, FALSE, FALSE,
5312 ZBORDER, FALSE, FALSE,
5322 static struct Mapping_EM_to_RND_player
5331 em_player_mapping_list[] =
5335 EL_PLAYER_1, ACTION_MOVING, MV_BIT_UP,
5339 EL_PLAYER_1, ACTION_MOVING, MV_BIT_RIGHT,
5343 EL_PLAYER_1, ACTION_MOVING, MV_BIT_DOWN,
5347 EL_PLAYER_1, ACTION_MOVING, MV_BIT_LEFT,
5351 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_UP,
5355 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_RIGHT,
5359 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_DOWN,
5363 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_LEFT,
5367 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_UP,
5371 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_RIGHT,
5375 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_DOWN,
5379 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_LEFT,
5383 EL_PLAYER_2, ACTION_MOVING, MV_BIT_UP,
5387 EL_PLAYER_2, ACTION_MOVING, MV_BIT_RIGHT,
5391 EL_PLAYER_2, ACTION_MOVING, MV_BIT_DOWN,
5395 EL_PLAYER_2, ACTION_MOVING, MV_BIT_LEFT,
5399 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_UP,
5403 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_RIGHT,
5407 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_DOWN,
5411 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_LEFT,
5415 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_UP,
5419 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_RIGHT,
5423 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_DOWN,
5427 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_LEFT,
5431 EL_PLAYER_1, ACTION_DEFAULT, -1,
5435 EL_PLAYER_2, ACTION_DEFAULT, -1,
5439 EL_PLAYER_3, ACTION_MOVING, MV_BIT_UP,
5443 EL_PLAYER_3, ACTION_MOVING, MV_BIT_RIGHT,
5447 EL_PLAYER_3, ACTION_MOVING, MV_BIT_DOWN,
5451 EL_PLAYER_3, ACTION_MOVING, MV_BIT_LEFT,
5455 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_UP,
5459 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_RIGHT,
5463 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_DOWN,
5467 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_LEFT,
5471 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_UP,
5475 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_RIGHT,
5479 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_DOWN,
5483 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_LEFT,
5487 EL_PLAYER_4, ACTION_MOVING, MV_BIT_UP,
5491 EL_PLAYER_4, ACTION_MOVING, MV_BIT_RIGHT,
5495 EL_PLAYER_4, ACTION_MOVING, MV_BIT_DOWN,
5499 EL_PLAYER_4, ACTION_MOVING, MV_BIT_LEFT,
5503 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_UP,
5507 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_RIGHT,
5511 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_DOWN,
5515 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_LEFT,
5519 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_UP,
5523 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_RIGHT,
5527 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_DOWN,
5531 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_LEFT,
5535 EL_PLAYER_3, ACTION_DEFAULT, -1,
5539 EL_PLAYER_4, ACTION_DEFAULT, -1,
5548 int map_element_RND_to_EM(int element_rnd)
5550 static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
5551 static boolean mapping_initialized = FALSE;
5553 if (!mapping_initialized)
5557 /* return "Xalpha_quest" for all undefined elements in mapping array */
5558 for (i = 0; i < NUM_FILE_ELEMENTS; i++)
5559 mapping_RND_to_EM[i] = Xalpha_quest;
5561 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5562 if (em_object_mapping_list[i].is_rnd_to_em_mapping)
5563 mapping_RND_to_EM[em_object_mapping_list[i].element_rnd] =
5564 em_object_mapping_list[i].element_em;
5566 mapping_initialized = TRUE;
5569 if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
5570 return mapping_RND_to_EM[element_rnd];
5572 Error(ERR_WARN, "invalid RND level element %d", element_rnd);
5577 int map_element_EM_to_RND(int element_em)
5579 static unsigned short mapping_EM_to_RND[TILE_MAX];
5580 static boolean mapping_initialized = FALSE;
5582 if (!mapping_initialized)
5586 /* return "EL_UNKNOWN" for all undefined elements in mapping array */
5587 for (i = 0; i < TILE_MAX; i++)
5588 mapping_EM_to_RND[i] = EL_UNKNOWN;
5590 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5591 mapping_EM_to_RND[em_object_mapping_list[i].element_em] =
5592 em_object_mapping_list[i].element_rnd;
5594 mapping_initialized = TRUE;
5597 if (element_em >= 0 && element_em < TILE_MAX)
5598 return mapping_EM_to_RND[element_em];
5600 Error(ERR_WARN, "invalid EM level element %d", element_em);
5605 void map_android_clone_elements_RND_to_EM(struct LevelInfo *level)
5607 struct LevelInfo_EM *level_em = level->native_em_level;
5608 struct LEVEL *lev = level_em->lev;
5611 for (i = 0; i < TILE_MAX; i++)
5612 lev->android_array[i] = Xblank;
5614 for (i = 0; i < level->num_android_clone_elements; i++)
5616 int element_rnd = level->android_clone_element[i];
5617 int element_em = map_element_RND_to_EM(element_rnd);
5619 for (j = 0; em_object_mapping_list[j].element_em != -1; j++)
5620 if (em_object_mapping_list[j].element_rnd == element_rnd)
5621 lev->android_array[em_object_mapping_list[j].element_em] = element_em;
5625 void map_android_clone_elements_EM_to_RND(struct LevelInfo *level)
5627 struct LevelInfo_EM *level_em = level->native_em_level;
5628 struct LEVEL *lev = level_em->lev;
5631 level->num_android_clone_elements = 0;
5633 for (i = 0; i < TILE_MAX; i++)
5635 int element_em = lev->android_array[i];
5637 boolean element_found = FALSE;
5639 if (element_em == Xblank)
5642 element_rnd = map_element_EM_to_RND(element_em);
5644 for (j = 0; j < level->num_android_clone_elements; j++)
5645 if (level->android_clone_element[j] == element_rnd)
5646 element_found = TRUE;
5650 level->android_clone_element[level->num_android_clone_elements++] =
5653 if (level->num_android_clone_elements == MAX_ANDROID_ELEMENTS)
5658 if (level->num_android_clone_elements == 0)
5660 level->num_android_clone_elements = 1;
5661 level->android_clone_element[0] = EL_EMPTY;
5665 int map_direction_RND_to_EM(int direction)
5667 return (direction == MV_UP ? 0 :
5668 direction == MV_RIGHT ? 1 :
5669 direction == MV_DOWN ? 2 :
5670 direction == MV_LEFT ? 3 :
5674 int map_direction_EM_to_RND(int direction)
5676 return (direction == 0 ? MV_UP :
5677 direction == 1 ? MV_RIGHT :
5678 direction == 2 ? MV_DOWN :
5679 direction == 3 ? MV_LEFT :
5683 int get_next_element(int element)
5687 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
5688 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
5689 case EL_QUICKSAND_FAST_FILLING: return EL_QUICKSAND_FAST_FULL;
5690 case EL_QUICKSAND_FAST_EMPTYING: return EL_QUICKSAND_FAST_EMPTY;
5691 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
5692 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
5693 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
5694 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
5695 case EL_DC_MAGIC_WALL_FILLING: return EL_DC_MAGIC_WALL_FULL;
5696 case EL_DC_MAGIC_WALL_EMPTYING: return EL_DC_MAGIC_WALL_ACTIVE;
5697 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
5699 default: return element;
5704 int el_act_dir2img(int element, int action, int direction)
5706 element = GFX_ELEMENT(element);
5708 if (direction == MV_NONE)
5709 return element_info[element].graphic[action];
5711 direction = MV_DIR_TO_BIT(direction);
5713 return element_info[element].direction_graphic[action][direction];
5716 int el_act_dir2img(int element, int action, int direction)
5718 element = GFX_ELEMENT(element);
5719 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
5721 /* direction_graphic[][] == graphic[] for undefined direction graphics */
5722 return element_info[element].direction_graphic[action][direction];
5727 static int el_act_dir2crm(int element, int action, int direction)
5729 element = GFX_ELEMENT(element);
5731 if (direction == MV_NONE)
5732 return element_info[element].crumbled[action];
5734 direction = MV_DIR_TO_BIT(direction);
5736 return element_info[element].direction_crumbled[action][direction];
5739 static int el_act_dir2crm(int element, int action, int direction)
5741 element = GFX_ELEMENT(element);
5742 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
5744 /* direction_graphic[][] == graphic[] for undefined direction graphics */
5745 return element_info[element].direction_crumbled[action][direction];
5749 int el_act2img(int element, int action)
5751 element = GFX_ELEMENT(element);
5753 return element_info[element].graphic[action];
5756 int el_act2crm(int element, int action)
5758 element = GFX_ELEMENT(element);
5760 return element_info[element].crumbled[action];
5763 int el_dir2img(int element, int direction)
5765 element = GFX_ELEMENT(element);
5767 return el_act_dir2img(element, ACTION_DEFAULT, direction);
5770 int el2baseimg(int element)
5772 return element_info[element].graphic[ACTION_DEFAULT];
5775 int el2img(int element)
5777 element = GFX_ELEMENT(element);
5779 return element_info[element].graphic[ACTION_DEFAULT];
5782 int el2edimg(int element)
5784 element = GFX_ELEMENT(element);
5786 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
5789 int el2preimg(int element)
5791 element = GFX_ELEMENT(element);
5793 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
5796 int el2panelimg(int element)
5798 element = GFX_ELEMENT(element);
5800 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PANEL];
5803 int font2baseimg(int font_nr)
5805 return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
5808 int getBeltNrFromBeltElement(int element)
5810 return (element < EL_CONVEYOR_BELT_2_LEFT ? 0 :
5811 element < EL_CONVEYOR_BELT_3_LEFT ? 1 :
5812 element < EL_CONVEYOR_BELT_4_LEFT ? 2 : 3);
5815 int getBeltNrFromBeltActiveElement(int element)
5817 return (element < EL_CONVEYOR_BELT_2_LEFT_ACTIVE ? 0 :
5818 element < EL_CONVEYOR_BELT_3_LEFT_ACTIVE ? 1 :
5819 element < EL_CONVEYOR_BELT_4_LEFT_ACTIVE ? 2 : 3);
5822 int getBeltNrFromBeltSwitchElement(int element)
5824 return (element < EL_CONVEYOR_BELT_2_SWITCH_LEFT ? 0 :
5825 element < EL_CONVEYOR_BELT_3_SWITCH_LEFT ? 1 :
5826 element < EL_CONVEYOR_BELT_4_SWITCH_LEFT ? 2 : 3);
5829 int getBeltDirNrFromBeltElement(int element)
5831 static int belt_base_element[4] =
5833 EL_CONVEYOR_BELT_1_LEFT,
5834 EL_CONVEYOR_BELT_2_LEFT,
5835 EL_CONVEYOR_BELT_3_LEFT,
5836 EL_CONVEYOR_BELT_4_LEFT
5839 int belt_nr = getBeltNrFromBeltElement(element);
5840 int belt_dir_nr = element - belt_base_element[belt_nr];
5842 return (belt_dir_nr % 3);
5845 int getBeltDirNrFromBeltSwitchElement(int element)
5847 static int belt_base_element[4] =
5849 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
5850 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
5851 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
5852 EL_CONVEYOR_BELT_4_SWITCH_LEFT
5855 int belt_nr = getBeltNrFromBeltSwitchElement(element);
5856 int belt_dir_nr = element - belt_base_element[belt_nr];
5858 return (belt_dir_nr % 3);
5861 int getBeltDirFromBeltElement(int element)
5863 static int belt_move_dir[3] =
5870 int belt_dir_nr = getBeltDirNrFromBeltElement(element);
5872 return belt_move_dir[belt_dir_nr];
5875 int getBeltDirFromBeltSwitchElement(int element)
5877 static int belt_move_dir[3] =
5884 int belt_dir_nr = getBeltDirNrFromBeltSwitchElement(element);
5886 return belt_move_dir[belt_dir_nr];
5889 int getBeltElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
5891 static int belt_base_element[4] =
5893 EL_CONVEYOR_BELT_1_LEFT,
5894 EL_CONVEYOR_BELT_2_LEFT,
5895 EL_CONVEYOR_BELT_3_LEFT,
5896 EL_CONVEYOR_BELT_4_LEFT
5899 return belt_base_element[belt_nr] + belt_dir_nr;
5902 int getBeltElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
5904 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
5906 return getBeltElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
5909 int getBeltSwitchElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
5911 static int belt_base_element[4] =
5913 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
5914 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
5915 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
5916 EL_CONVEYOR_BELT_4_SWITCH_LEFT
5919 return belt_base_element[belt_nr] + belt_dir_nr;
5922 int getBeltSwitchElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
5924 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
5926 return getBeltSwitchElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
5929 int getNumActivePlayers_EM()
5931 int num_players = 0;
5937 for (i = 0; i < MAX_PLAYERS; i++)
5938 if (tape.player_participates[i])
5944 int getGameFrameDelay_EM(int native_em_game_frame_delay)
5946 int game_frame_delay_value;
5948 game_frame_delay_value =
5949 (tape.playing && tape.fast_forward ? FfwdFrameDelay :
5950 GameFrameDelay == GAME_FRAME_DELAY ? native_em_game_frame_delay :
5953 if (tape.playing && tape.warp_forward && !tape.pausing)
5954 game_frame_delay_value = 0;
5956 return game_frame_delay_value;
5959 unsigned int InitRND(long seed)
5961 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
5962 return InitEngineRandom_EM(seed);
5964 return InitEngineRandom_RND(seed);
5968 static struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
5969 static struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
5972 void ResetGfxAnimation_EM(int x, int y, int tile)
5977 void SetGfxAnimation_EM(int tile, int frame_em, int x, int y)
5980 int element = object_mapping[tile].element_rnd;
5982 int action = object_mapping[tile].action;
5983 int direction = object_mapping[tile].direction;
5984 boolean is_backside = object_mapping[tile].is_backside;
5985 boolean action_removing = (action == ACTION_DIGGING ||
5986 action == ACTION_SNAPPING ||
5987 action == ACTION_COLLECTING);
5990 printf("::: SET: %d, %d: '%s'\n", x, y, EL_NAME(element));
5994 if (action_removing)
5997 printf("::: %d, %d: action_removing [%s]\n", x, y, EL_NAME(element));
6000 GfxFrame[x][y] = 7 - frame_em;
6002 else if (action == ACTION_FALLING ||
6003 action == ACTION_MOVING ||
6004 action == ACTION_PUSHING ||
6005 action == ACTION_EATING ||
6006 action == ACTION_FILLING ||
6007 action == ACTION_EMPTYING)
6010 (action == ACTION_FALLING ||
6011 action == ACTION_FILLING ||
6012 action == ACTION_EMPTYING ? MV_DOWN : direction);
6018 if (move_dir == MV_LEFT)
6019 GfxFrame[x - 1][y] = GfxFrame[x][y];
6020 else if (move_dir == MV_RIGHT)
6021 GfxFrame[x + 1][y] = GfxFrame[x][y];
6022 else if (move_dir == MV_UP)
6023 GfxFrame[x][y - 1] = GfxFrame[x][y];
6024 else if (move_dir == MV_DOWN)
6025 GfxFrame[x][y + 1] = GfxFrame[x][y];
6029 printf("::: %d, %d: %s, %d, %d [%d]\n", x, y, EL_NAME(element), is_backside,
6030 move_dir, GfxFrame[x][y]);
6036 GfxFrame[x][y] = 7 - frame_em;
6040 void getGraphicSourceObjectExt_EM(int tile, int frame_em,
6041 Bitmap **src_bitmap, int *src_x, int *src_y,
6044 int element = object_mapping[tile].element_rnd;
6045 int action = object_mapping[tile].action;
6046 int direction = object_mapping[tile].direction;
6047 boolean is_backside = object_mapping[tile].is_backside;
6048 boolean action_removing = (action == ACTION_DIGGING ||
6049 action == ACTION_SNAPPING ||
6050 action == ACTION_COLLECTING);
6051 int effective_element = (frame_em > 0 ? element :
6052 is_backside ? EL_EMPTY :
6053 action_removing ? EL_EMPTY :
6055 int graphic = (direction == MV_NONE ?
6056 el_act2img(effective_element, action) :
6057 el_act_dir2img(effective_element, action, direction));
6058 struct GraphicInfo *g = &graphic_info[graphic];
6062 printf("::: GET: %d, %d: '%s'\n", x, y, EL_NAME(element));
6066 if (GfxFrame[x][y] < 8)
6067 printf("::: %d, %d: %d [%s]\n", x, y, GfxFrame[x][y], EL_NAME(element));
6071 if (graphic_info[graphic].anim_global_sync)
6072 sync_frame = FrameCounter;
6073 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
6074 sync_frame = GfxFrame[x][y];
6076 sync_frame = 0; /* steel border */
6078 if (graphic_info[graphic].anim_global_sync)
6079 sync_frame = FrameCounter;
6081 sync_frame = 7 - frame_em;
6084 SetRandomAnimationValue(x, y);
6086 int frame = getAnimationFrame(g->anim_frames,
6089 g->anim_start_frame,
6092 getGraphicSourceExt(graphic, frame, src_bitmap, src_x, src_y, FALSE);
6095 void getGraphicSourcePlayerExt_EM(int player_nr, int anim, int frame_em,
6096 Bitmap **src_bitmap, int *src_x, int *src_y)
6098 int element = player_mapping[player_nr][anim].element_rnd;
6099 int action = player_mapping[player_nr][anim].action;
6100 int direction = player_mapping[player_nr][anim].direction;
6101 int graphic = (direction == MV_NONE ?
6102 el_act2img(element, action) :
6103 el_act_dir2img(element, action, direction));
6104 struct GraphicInfo *g = &graphic_info[graphic];
6107 InitPlayerGfxAnimation(&stored_player[player_nr], action, direction);
6109 stored_player[player_nr].StepFrame = 7 - frame_em;
6111 sync_frame = stored_player[player_nr].Frame;
6114 printf("::: %d: %d, %d [%d]\n",
6116 stored_player[player_nr].Frame,
6117 stored_player[player_nr].StepFrame,
6121 int frame = getAnimationFrame(g->anim_frames,
6124 g->anim_start_frame,
6127 getGraphicSourceExt(graphic, frame, src_bitmap, src_x, src_y, FALSE);
6130 void InitGraphicInfo_EM(void)
6133 struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
6134 struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
6139 int num_em_gfx_errors = 0;
6141 if (graphic_info_em_object[0][0].bitmap == NULL)
6143 /* EM graphics not yet initialized in em_open_all() */
6148 printf("::: [4 errors can be ignored (1 x 'bomb', 3 x 'em_dynamite']\n");
6151 /* always start with reliable default values */
6152 for (i = 0; i < TILE_MAX; i++)
6154 object_mapping[i].element_rnd = EL_UNKNOWN;
6155 object_mapping[i].is_backside = FALSE;
6156 object_mapping[i].action = ACTION_DEFAULT;
6157 object_mapping[i].direction = MV_NONE;
6160 /* always start with reliable default values */
6161 for (p = 0; p < MAX_PLAYERS; p++)
6163 for (i = 0; i < SPR_MAX; i++)
6165 player_mapping[p][i].element_rnd = EL_UNKNOWN;
6166 player_mapping[p][i].action = ACTION_DEFAULT;
6167 player_mapping[p][i].direction = MV_NONE;
6171 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
6173 int e = em_object_mapping_list[i].element_em;
6175 object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd;
6176 object_mapping[e].is_backside = em_object_mapping_list[i].is_backside;
6178 if (em_object_mapping_list[i].action != -1)
6179 object_mapping[e].action = em_object_mapping_list[i].action;
6181 if (em_object_mapping_list[i].direction != -1)
6182 object_mapping[e].direction =
6183 MV_DIR_FROM_BIT(em_object_mapping_list[i].direction);
6186 for (i = 0; em_player_mapping_list[i].action_em != -1; i++)
6188 int a = em_player_mapping_list[i].action_em;
6189 int p = em_player_mapping_list[i].player_nr;
6191 player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd;
6193 if (em_player_mapping_list[i].action != -1)
6194 player_mapping[p][a].action = em_player_mapping_list[i].action;
6196 if (em_player_mapping_list[i].direction != -1)
6197 player_mapping[p][a].direction =
6198 MV_DIR_FROM_BIT(em_player_mapping_list[i].direction);
6201 for (i = 0; i < TILE_MAX; i++)
6203 int element = object_mapping[i].element_rnd;
6204 int action = object_mapping[i].action;
6205 int direction = object_mapping[i].direction;
6206 boolean is_backside = object_mapping[i].is_backside;
6207 boolean action_removing = (action == ACTION_DIGGING ||
6208 action == ACTION_SNAPPING ||
6209 action == ACTION_COLLECTING);
6210 boolean action_exploding = ((action == ACTION_EXPLODING ||
6211 action == ACTION_SMASHED_BY_ROCK ||
6212 action == ACTION_SMASHED_BY_SPRING) &&
6213 element != EL_DIAMOND);
6214 boolean action_active = (action == ACTION_ACTIVE);
6215 boolean action_other = (action == ACTION_OTHER);
6217 for (j = 0; j < 8; j++)
6219 int effective_element = (j > 5 && i == Yacid_splash_eB ? EL_EMPTY :
6220 j > 5 && i == Yacid_splash_wB ? EL_EMPTY :
6222 i == Xdrip_stretch ? element :
6223 i == Xdrip_stretchB ? element :
6224 i == Ydrip_s1 ? element :
6225 i == Ydrip_s1B ? element :
6226 i == Xball_1B ? element :
6227 i == Xball_2 ? element :
6228 i == Xball_2B ? element :
6229 i == Yball_eat ? element :
6230 i == Ykey_1_eat ? element :
6231 i == Ykey_2_eat ? element :
6232 i == Ykey_3_eat ? element :
6233 i == Ykey_4_eat ? element :
6234 i == Ykey_5_eat ? element :
6235 i == Ykey_6_eat ? element :
6236 i == Ykey_7_eat ? element :
6237 i == Ykey_8_eat ? element :
6238 i == Ylenses_eat ? element :
6239 i == Ymagnify_eat ? element :
6240 i == Ygrass_eat ? element :
6241 i == Ydirt_eat ? element :
6242 i == Yemerald_stone ? EL_EMERALD :
6243 i == Ydiamond_stone ? EL_ROCK :
6244 i == Xsand_stonein_1 ? element :
6245 i == Xsand_stonein_2 ? element :
6246 i == Xsand_stonein_3 ? element :
6247 i == Xsand_stonein_4 ? element :
6248 is_backside ? EL_EMPTY :
6249 action_removing ? EL_EMPTY :
6251 int effective_action = (j < 7 ? action :
6252 i == Xdrip_stretch ? action :
6253 i == Xdrip_stretchB ? action :
6254 i == Ydrip_s1 ? action :
6255 i == Ydrip_s1B ? action :
6256 i == Xball_1B ? action :
6257 i == Xball_2 ? action :
6258 i == Xball_2B ? action :
6259 i == Yball_eat ? action :
6260 i == Ykey_1_eat ? action :
6261 i == Ykey_2_eat ? action :
6262 i == Ykey_3_eat ? action :
6263 i == Ykey_4_eat ? action :
6264 i == Ykey_5_eat ? action :
6265 i == Ykey_6_eat ? action :
6266 i == Ykey_7_eat ? action :
6267 i == Ykey_8_eat ? action :
6268 i == Ylenses_eat ? action :
6269 i == Ymagnify_eat ? action :
6270 i == Ygrass_eat ? action :
6271 i == Ydirt_eat ? action :
6272 i == Xsand_stonein_1 ? action :
6273 i == Xsand_stonein_2 ? action :
6274 i == Xsand_stonein_3 ? action :
6275 i == Xsand_stonein_4 ? action :
6276 i == Xsand_stoneout_1 ? action :
6277 i == Xsand_stoneout_2 ? action :
6278 i == Xboom_android ? ACTION_EXPLODING :
6279 action_exploding ? ACTION_EXPLODING :
6280 action_active ? action :
6281 action_other ? action :
6283 int graphic = (el_act_dir2img(effective_element, effective_action,
6285 int crumbled = (el_act_dir2crm(effective_element, effective_action,
6287 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
6288 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
6289 boolean has_action_graphics = (graphic != base_graphic);
6290 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
6291 struct GraphicInfo *g = &graphic_info[graphic];
6292 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
6295 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
6296 boolean special_animation = (action != ACTION_DEFAULT &&
6297 g->anim_frames == 3 &&
6298 g->anim_delay == 2 &&
6299 g->anim_mode & ANIM_LINEAR);
6300 int sync_frame = (i == Xdrip_stretch ? 7 :
6301 i == Xdrip_stretchB ? 7 :
6302 i == Ydrip_s2 ? j + 8 :
6303 i == Ydrip_s2B ? j + 8 :
6312 i == Xfake_acid_1 ? 0 :
6313 i == Xfake_acid_2 ? 10 :
6314 i == Xfake_acid_3 ? 20 :
6315 i == Xfake_acid_4 ? 30 :
6316 i == Xfake_acid_5 ? 40 :
6317 i == Xfake_acid_6 ? 50 :
6318 i == Xfake_acid_7 ? 60 :
6319 i == Xfake_acid_8 ? 70 :
6321 i == Xball_2B ? j + 8 :
6322 i == Yball_eat ? j + 1 :
6323 i == Ykey_1_eat ? j + 1 :
6324 i == Ykey_2_eat ? j + 1 :
6325 i == Ykey_3_eat ? j + 1 :
6326 i == Ykey_4_eat ? j + 1 :
6327 i == Ykey_5_eat ? j + 1 :
6328 i == Ykey_6_eat ? j + 1 :
6329 i == Ykey_7_eat ? j + 1 :
6330 i == Ykey_8_eat ? j + 1 :
6331 i == Ylenses_eat ? j + 1 :
6332 i == Ymagnify_eat ? j + 1 :
6333 i == Ygrass_eat ? j + 1 :
6334 i == Ydirt_eat ? j + 1 :
6335 i == Xamoeba_1 ? 0 :
6336 i == Xamoeba_2 ? 1 :
6337 i == Xamoeba_3 ? 2 :
6338 i == Xamoeba_4 ? 3 :
6339 i == Xamoeba_5 ? 0 :
6340 i == Xamoeba_6 ? 1 :
6341 i == Xamoeba_7 ? 2 :
6342 i == Xamoeba_8 ? 3 :
6343 i == Xexit_2 ? j + 8 :
6344 i == Xexit_3 ? j + 16 :
6345 i == Xdynamite_1 ? 0 :
6346 i == Xdynamite_2 ? 8 :
6347 i == Xdynamite_3 ? 16 :
6348 i == Xdynamite_4 ? 24 :
6349 i == Xsand_stonein_1 ? j + 1 :
6350 i == Xsand_stonein_2 ? j + 9 :
6351 i == Xsand_stonein_3 ? j + 17 :
6352 i == Xsand_stonein_4 ? j + 25 :
6353 i == Xsand_stoneout_1 && j == 0 ? 0 :
6354 i == Xsand_stoneout_1 && j == 1 ? 0 :
6355 i == Xsand_stoneout_1 && j == 2 ? 1 :
6356 i == Xsand_stoneout_1 && j == 3 ? 2 :
6357 i == Xsand_stoneout_1 && j == 4 ? 2 :
6358 i == Xsand_stoneout_1 && j == 5 ? 3 :
6359 i == Xsand_stoneout_1 && j == 6 ? 4 :
6360 i == Xsand_stoneout_1 && j == 7 ? 4 :
6361 i == Xsand_stoneout_2 && j == 0 ? 5 :
6362 i == Xsand_stoneout_2 && j == 1 ? 6 :
6363 i == Xsand_stoneout_2 && j == 2 ? 7 :
6364 i == Xsand_stoneout_2 && j == 3 ? 8 :
6365 i == Xsand_stoneout_2 && j == 4 ? 9 :
6366 i == Xsand_stoneout_2 && j == 5 ? 11 :
6367 i == Xsand_stoneout_2 && j == 6 ? 13 :
6368 i == Xsand_stoneout_2 && j == 7 ? 15 :
6369 i == Xboom_bug && j == 1 ? 2 :
6370 i == Xboom_bug && j == 2 ? 2 :
6371 i == Xboom_bug && j == 3 ? 4 :
6372 i == Xboom_bug && j == 4 ? 4 :
6373 i == Xboom_bug && j == 5 ? 2 :
6374 i == Xboom_bug && j == 6 ? 2 :
6375 i == Xboom_bug && j == 7 ? 0 :
6376 i == Xboom_bomb && j == 1 ? 2 :
6377 i == Xboom_bomb && j == 2 ? 2 :
6378 i == Xboom_bomb && j == 3 ? 4 :
6379 i == Xboom_bomb && j == 4 ? 4 :
6380 i == Xboom_bomb && j == 5 ? 2 :
6381 i == Xboom_bomb && j == 6 ? 2 :
6382 i == Xboom_bomb && j == 7 ? 0 :
6383 i == Xboom_android && j == 7 ? 6 :
6384 i == Xboom_1 && j == 1 ? 2 :
6385 i == Xboom_1 && j == 2 ? 2 :
6386 i == Xboom_1 && j == 3 ? 4 :
6387 i == Xboom_1 && j == 4 ? 4 :
6388 i == Xboom_1 && j == 5 ? 6 :
6389 i == Xboom_1 && j == 6 ? 6 :
6390 i == Xboom_1 && j == 7 ? 8 :
6391 i == Xboom_2 && j == 0 ? 8 :
6392 i == Xboom_2 && j == 1 ? 8 :
6393 i == Xboom_2 && j == 2 ? 10 :
6394 i == Xboom_2 && j == 3 ? 10 :
6395 i == Xboom_2 && j == 4 ? 10 :
6396 i == Xboom_2 && j == 5 ? 12 :
6397 i == Xboom_2 && j == 6 ? 12 :
6398 i == Xboom_2 && j == 7 ? 12 :
6399 special_animation && j == 4 ? 3 :
6400 effective_action != action ? 0 :
6404 Bitmap *debug_bitmap = g_em->bitmap;
6405 int debug_src_x = g_em->src_x;
6406 int debug_src_y = g_em->src_y;
6409 int frame = getAnimationFrame(g->anim_frames,
6412 g->anim_start_frame,
6415 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y,
6416 g->double_movement && is_backside);
6418 g_em->bitmap = src_bitmap;
6419 g_em->src_x = src_x;
6420 g_em->src_y = src_y;
6421 g_em->src_offset_x = 0;
6422 g_em->src_offset_y = 0;
6423 g_em->dst_offset_x = 0;
6424 g_em->dst_offset_y = 0;
6425 g_em->width = TILEX;
6426 g_em->height = TILEY;
6428 g_em->crumbled_bitmap = NULL;
6429 g_em->crumbled_src_x = 0;
6430 g_em->crumbled_src_y = 0;
6431 g_em->crumbled_border_size = 0;
6433 g_em->has_crumbled_graphics = FALSE;
6434 g_em->preserve_background = FALSE;
6437 if (has_crumbled_graphics && crumbled == IMG_EMPTY_SPACE)
6438 printf("::: empty crumbled: %d [%s], %d, %d\n",
6439 effective_element, element_info[effective_element].token_name,
6440 effective_action, direction);
6443 /* if element can be crumbled, but certain action graphics are just empty
6444 space (like snapping sand with the original R'n'D graphics), do not
6445 treat these empty space graphics as crumbled graphics in EMC engine */
6446 if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
6448 getGraphicSource(crumbled, frame, &src_bitmap, &src_x, &src_y);
6450 g_em->has_crumbled_graphics = TRUE;
6451 g_em->crumbled_bitmap = src_bitmap;
6452 g_em->crumbled_src_x = src_x;
6453 g_em->crumbled_src_y = src_y;
6454 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
6458 if (element == EL_ROCK &&
6459 effective_action == ACTION_FILLING)
6460 printf("::: has_action_graphics == %d\n", has_action_graphics);
6463 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
6464 effective_action == ACTION_MOVING ||
6465 effective_action == ACTION_PUSHING ||
6466 effective_action == ACTION_EATING)) ||
6467 (!has_action_graphics && (effective_action == ACTION_FILLING ||
6468 effective_action == ACTION_EMPTYING)))
6471 (effective_action == ACTION_FALLING ||
6472 effective_action == ACTION_FILLING ||
6473 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
6474 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
6475 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
6476 int num_steps = (i == Ydrip_s1 ? 16 :
6477 i == Ydrip_s1B ? 16 :
6478 i == Ydrip_s2 ? 16 :
6479 i == Ydrip_s2B ? 16 :
6480 i == Xsand_stonein_1 ? 32 :
6481 i == Xsand_stonein_2 ? 32 :
6482 i == Xsand_stonein_3 ? 32 :
6483 i == Xsand_stonein_4 ? 32 :
6484 i == Xsand_stoneout_1 ? 16 :
6485 i == Xsand_stoneout_2 ? 16 : 8);
6486 int cx = ABS(dx) * (TILEX / num_steps);
6487 int cy = ABS(dy) * (TILEY / num_steps);
6488 int step_frame = (i == Ydrip_s2 ? j + 8 :
6489 i == Ydrip_s2B ? j + 8 :
6490 i == Xsand_stonein_2 ? j + 8 :
6491 i == Xsand_stonein_3 ? j + 16 :
6492 i == Xsand_stonein_4 ? j + 24 :
6493 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
6494 int step = (is_backside ? step_frame : num_steps - step_frame);
6496 if (is_backside) /* tile where movement starts */
6498 if (dx < 0 || dy < 0)
6500 g_em->src_offset_x = cx * step;
6501 g_em->src_offset_y = cy * step;
6505 g_em->dst_offset_x = cx * step;
6506 g_em->dst_offset_y = cy * step;
6509 else /* tile where movement ends */
6511 if (dx < 0 || dy < 0)
6513 g_em->dst_offset_x = cx * step;
6514 g_em->dst_offset_y = cy * step;
6518 g_em->src_offset_x = cx * step;
6519 g_em->src_offset_y = cy * step;
6523 g_em->width = TILEX - cx * step;
6524 g_em->height = TILEY - cy * step;
6527 /* create unique graphic identifier to decide if tile must be redrawn */
6528 /* bit 31 - 16 (16 bit): EM style graphic
6529 bit 15 - 12 ( 4 bit): EM style frame
6530 bit 11 - 6 ( 6 bit): graphic width
6531 bit 5 - 0 ( 6 bit): graphic height */
6532 g_em->unique_identifier =
6533 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
6537 /* skip check for EMC elements not contained in original EMC artwork */
6538 if (element == EL_EMC_FAKE_ACID)
6541 if (g_em->bitmap != debug_bitmap ||
6542 g_em->src_x != debug_src_x ||
6543 g_em->src_y != debug_src_y ||
6544 g_em->src_offset_x != 0 ||
6545 g_em->src_offset_y != 0 ||
6546 g_em->dst_offset_x != 0 ||
6547 g_em->dst_offset_y != 0 ||
6548 g_em->width != TILEX ||
6549 g_em->height != TILEY)
6551 static int last_i = -1;
6559 printf("::: EMC GFX ERROR for element %d -> %d ('%s', '%s', %d)",
6560 i, element, element_info[element].token_name,
6561 element_action_info[effective_action].suffix, direction);
6563 if (element != effective_element)
6564 printf(" [%d ('%s')]",
6566 element_info[effective_element].token_name);
6570 if (g_em->bitmap != debug_bitmap)
6571 printf(" %d (%d): different bitmap! (0x%08x != 0x%08x)\n",
6572 j, is_backside, (int)(g_em->bitmap), (int)(debug_bitmap));
6574 if (g_em->src_x != debug_src_x ||
6575 g_em->src_y != debug_src_y)
6576 printf(" frame %d (%c): %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
6577 j, (is_backside ? 'B' : 'F'),
6578 g_em->src_x, g_em->src_y,
6579 g_em->src_x / 32, g_em->src_y / 32,
6580 debug_src_x, debug_src_y,
6581 debug_src_x / 32, debug_src_y / 32);
6583 if (g_em->src_offset_x != 0 ||
6584 g_em->src_offset_y != 0 ||
6585 g_em->dst_offset_x != 0 ||
6586 g_em->dst_offset_y != 0)
6587 printf(" %d (%d): offsets %d,%d and %d,%d should be all 0\n",
6589 g_em->src_offset_x, g_em->src_offset_y,
6590 g_em->dst_offset_x, g_em->dst_offset_y);
6592 if (g_em->width != TILEX ||
6593 g_em->height != TILEY)
6594 printf(" %d (%d): size %d,%d should be %d,%d\n",
6596 g_em->width, g_em->height, TILEX, TILEY);
6598 num_em_gfx_errors++;
6605 for (i = 0; i < TILE_MAX; i++)
6607 for (j = 0; j < 8; j++)
6609 int element = object_mapping[i].element_rnd;
6610 int action = object_mapping[i].action;
6611 int direction = object_mapping[i].direction;
6612 boolean is_backside = object_mapping[i].is_backside;
6613 int graphic_action = el_act_dir2img(element, action, direction);
6614 int graphic_default = el_act_dir2img(element, ACTION_DEFAULT, direction);
6616 if ((action == ACTION_SMASHED_BY_ROCK ||
6617 action == ACTION_SMASHED_BY_SPRING ||
6618 action == ACTION_EATING) &&
6619 graphic_action == graphic_default)
6621 int e = (action == ACTION_SMASHED_BY_ROCK ? Ystone_s :
6622 action == ACTION_SMASHED_BY_SPRING ? Yspring_s :
6623 direction == MV_LEFT ? (is_backside? Yspring_wB: Yspring_w) :
6624 direction == MV_RIGHT ? (is_backside? Yspring_eB: Yspring_e) :
6627 /* no separate animation for "smashed by rock" -- use rock instead */
6628 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
6629 struct GraphicInfo_EM *g_xx = &graphic_info_em_object[e][7 - j];
6631 g_em->bitmap = g_xx->bitmap;
6632 g_em->src_x = g_xx->src_x;
6633 g_em->src_y = g_xx->src_y;
6634 g_em->src_offset_x = g_xx->src_offset_x;
6635 g_em->src_offset_y = g_xx->src_offset_y;
6636 g_em->dst_offset_x = g_xx->dst_offset_x;
6637 g_em->dst_offset_y = g_xx->dst_offset_y;
6638 g_em->width = g_xx->width;
6639 g_em->height = g_xx->height;
6640 g_em->unique_identifier = g_xx->unique_identifier;
6643 g_em->preserve_background = TRUE;
6648 for (p = 0; p < MAX_PLAYERS; p++)
6650 for (i = 0; i < SPR_MAX; i++)
6652 int element = player_mapping[p][i].element_rnd;
6653 int action = player_mapping[p][i].action;
6654 int direction = player_mapping[p][i].direction;
6656 for (j = 0; j < 8; j++)
6658 int effective_element = element;
6659 int effective_action = action;
6660 int graphic = (direction == MV_NONE ?
6661 el_act2img(effective_element, effective_action) :
6662 el_act_dir2img(effective_element, effective_action,
6664 struct GraphicInfo *g = &graphic_info[graphic];
6665 struct GraphicInfo_EM *g_em = &graphic_info_em_player[p][i][7 - j];
6671 Bitmap *debug_bitmap = g_em->bitmap;
6672 int debug_src_x = g_em->src_x;
6673 int debug_src_y = g_em->src_y;
6676 int frame = getAnimationFrame(g->anim_frames,
6679 g->anim_start_frame,
6682 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
6684 g_em->bitmap = src_bitmap;
6685 g_em->src_x = src_x;
6686 g_em->src_y = src_y;
6687 g_em->src_offset_x = 0;
6688 g_em->src_offset_y = 0;
6689 g_em->dst_offset_x = 0;
6690 g_em->dst_offset_y = 0;
6691 g_em->width = TILEX;
6692 g_em->height = TILEY;
6696 /* skip check for EMC elements not contained in original EMC artwork */
6697 if (element == EL_PLAYER_3 ||
6698 element == EL_PLAYER_4)
6701 if (g_em->bitmap != debug_bitmap ||
6702 g_em->src_x != debug_src_x ||
6703 g_em->src_y != debug_src_y)
6705 static int last_i = -1;
6713 printf("::: EMC GFX ERROR for p/a %d/%d -> %d ('%s', '%s', %d)",
6714 p, i, element, element_info[element].token_name,
6715 element_action_info[effective_action].suffix, direction);
6717 if (element != effective_element)
6718 printf(" [%d ('%s')]",
6720 element_info[effective_element].token_name);
6724 if (g_em->bitmap != debug_bitmap)
6725 printf(" %d: different bitmap! (0x%08x != 0x%08x)\n",
6726 j, (int)(g_em->bitmap), (int)(debug_bitmap));
6728 if (g_em->src_x != debug_src_x ||
6729 g_em->src_y != debug_src_y)
6730 printf(" frame %d: %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
6732 g_em->src_x, g_em->src_y,
6733 g_em->src_x / 32, g_em->src_y / 32,
6734 debug_src_x, debug_src_y,
6735 debug_src_x / 32, debug_src_y / 32);
6737 num_em_gfx_errors++;
6747 printf("::: [%d errors found]\n", num_em_gfx_errors);
6753 void PlayMenuSoundExt(int sound)
6755 if (sound == SND_UNDEFINED)
6758 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
6759 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
6762 if (IS_LOOP_SOUND(sound))
6763 PlaySoundLoop(sound);
6768 void PlayMenuSound()
6770 PlayMenuSoundExt(menu.sound[game_status]);
6773 void PlayMenuSoundStereo(int sound, int stereo_position)
6775 if (sound == SND_UNDEFINED)
6778 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
6779 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
6782 if (IS_LOOP_SOUND(sound))
6783 PlaySoundExt(sound, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_LOOP);
6785 PlaySoundStereo(sound, stereo_position);
6788 void PlayMenuSoundIfLoopExt(int sound)
6790 if (sound == SND_UNDEFINED)
6793 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
6794 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
6797 if (IS_LOOP_SOUND(sound))
6798 PlaySoundLoop(sound);
6801 void PlayMenuSoundIfLoop()
6803 PlayMenuSoundIfLoopExt(menu.sound[game_status]);
6806 void PlayMenuMusicExt(int music)
6808 if (music == MUS_UNDEFINED)
6811 if (!setup.sound_music)
6817 void PlayMenuMusic()
6819 PlayMenuMusicExt(menu.music[game_status]);
6822 void PlaySoundActivating()
6825 PlaySound(SND_MENU_ITEM_ACTIVATING);
6829 void PlaySoundSelecting()
6832 PlaySound(SND_MENU_ITEM_SELECTING);
6836 void ToggleFullscreenIfNeeded()
6838 boolean change_fullscreen = (setup.fullscreen !=
6839 video.fullscreen_enabled);
6840 boolean change_fullscreen_mode = (video.fullscreen_enabled &&
6841 !strEqual(setup.fullscreen_mode,
6842 video.fullscreen_mode_current));
6844 if (!video.fullscreen_available)
6848 if (change_fullscreen || change_fullscreen_mode)
6850 if (setup.fullscreen != video.fullscreen_enabled ||
6851 setup.fullscreen_mode != video.fullscreen_mode_current)
6854 Bitmap *tmp_backbuffer = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
6856 /* save backbuffer content which gets lost when toggling fullscreen mode */
6857 BlitBitmap(backbuffer, tmp_backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
6860 if (change_fullscreen_mode)
6862 if (setup.fullscreen && video.fullscreen_enabled)
6865 /* keep fullscreen, but change fullscreen mode (screen resolution) */
6867 /* (this is now set in sdl.c) */
6869 video.fullscreen_mode_current = setup.fullscreen_mode;
6871 video.fullscreen_enabled = FALSE; /* force new fullscreen mode */
6874 /* toggle fullscreen */
6875 ChangeVideoModeIfNeeded(setup.fullscreen);
6877 setup.fullscreen = video.fullscreen_enabled;
6879 /* restore backbuffer content from temporary backbuffer backup bitmap */
6880 BlitBitmap(tmp_backbuffer, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
6882 FreeBitmap(tmp_backbuffer);
6885 /* update visible window/screen */
6886 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
6888 redraw_mask = REDRAW_ALL;