1 /***********************************************************
2 * Rocks'n'Diamonds -- McDuffin Strikes Back! *
3 *----------------------------------------------------------*
4 * (c) 1995-2006 Artsoft Entertainment *
6 * Detmolder Strasse 189 *
9 * e-mail: info@artsoft.org *
10 *----------------------------------------------------------*
12 ***********************************************************/
14 #include "libgame/libgame.h"
25 /* select level set with EMC X11 graphics before activating EM GFX debugging */
26 #define DEBUG_EM_GFX 0
28 /* tool button identifiers */
29 #define TOOL_CTRL_ID_YES 0
30 #define TOOL_CTRL_ID_NO 1
31 #define TOOL_CTRL_ID_CONFIRM 2
32 #define TOOL_CTRL_ID_PLAYER_1 3
33 #define TOOL_CTRL_ID_PLAYER_2 4
34 #define TOOL_CTRL_ID_PLAYER_3 5
35 #define TOOL_CTRL_ID_PLAYER_4 6
37 #define NUM_TOOL_BUTTONS 7
39 /* forward declaration for internal use */
40 static void UnmapToolButtons();
41 static void HandleToolButtons(struct GadgetInfo *);
42 static int el_act_dir2crm(int, int, int);
43 static int el_act2crm(int, int);
45 static struct GadgetInfo *tool_gadget[NUM_TOOL_BUTTONS];
46 static int request_gadget_id = -1;
48 static char *print_if_not_empty(int element)
50 static char *s = NULL;
51 char *token_name = element_info[element].token_name;
56 s = checked_malloc(strlen(token_name) + 10 + 1);
58 if (element != EL_EMPTY)
59 sprintf(s, "%d\t['%s']", element, token_name);
61 sprintf(s, "%d", element);
66 void DumpTile(int x, int y)
71 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
78 printf("Field Info: SCREEN(%d, %d), LEVEL(%d, %d)\n", sx, sy, x, y);
81 if (!IN_LEV_FIELD(x, y))
83 printf("(not in level field)\n");
89 printf(" Feld: %d\t['%s']\n", Feld[x][y],
90 element_info[Feld[x][y]].token_name);
91 printf(" Back: %s\n", print_if_not_empty(Back[x][y]));
92 printf(" Store: %s\n", print_if_not_empty(Store[x][y]));
93 printf(" Store2: %s\n", print_if_not_empty(Store2[x][y]));
94 printf(" StorePlayer: %s\n", print_if_not_empty(StorePlayer[x][y]));
95 printf(" MovPos: %d\n", MovPos[x][y]);
96 printf(" MovDir: %d\n", MovDir[x][y]);
97 printf(" MovDelay: %d\n", MovDelay[x][y]);
98 printf(" ChangeDelay: %d\n", ChangeDelay[x][y]);
99 printf(" CustomValue: %d\n", CustomValue[x][y]);
100 printf(" GfxElement: %d\n", GfxElement[x][y]);
101 printf(" GfxAction: %d\n", GfxAction[x][y]);
102 printf(" GfxFrame: %d\n", GfxFrame[x][y]);
106 void SetDrawtoField(int mode)
108 if (mode == DRAW_BUFFERED && setup.soft_scrolling)
119 drawto_field = fieldbuffer;
121 else /* DRAW_DIRECT, DRAW_BACKBUFFER */
127 BX2 = SCR_FIELDX - 1;
128 BY2 = SCR_FIELDY - 1;
132 drawto_field = (mode == DRAW_DIRECT ? window : backbuffer);
136 void RedrawPlayfield(boolean force_redraw, int x, int y, int width, int height)
138 if (game_status == GAME_MODE_PLAYING &&
139 level.game_engine_type == GAME_ENGINE_TYPE_EM)
141 /* currently there is no partial redraw -- always redraw whole playfield */
142 RedrawPlayfield_EM(TRUE);
144 /* blit playfield from scroll buffer to normal back buffer for fading in */
145 BlitScreenToBitmap_EM(backbuffer);
147 else if (game_status == GAME_MODE_PLAYING && !game.envelope_active)
153 width = gfx.sxsize + 2 * TILEX;
154 height = gfx.sysize + 2 * TILEY;
157 if (force_redraw || setup.direct_draw)
160 int x1 = (x - SX) / TILEX, y1 = (y - SY) / TILEY;
161 int x2 = (x - SX + width) / TILEX, y2 = (y - SY + height) / TILEY;
163 if (setup.direct_draw)
164 SetDrawtoField(DRAW_BACKBUFFER);
166 for (xx = BX1; xx <= BX2; xx++)
167 for (yy = BY1; yy <= BY2; yy++)
168 if (xx >= x1 && xx <= x2 && yy >= y1 && yy <= y2)
169 DrawScreenField(xx, yy);
172 if (setup.direct_draw)
173 SetDrawtoField(DRAW_DIRECT);
176 if (setup.soft_scrolling)
178 int fx = FX, fy = FY;
180 fx += (ScreenMovDir & (MV_LEFT|MV_RIGHT) ? ScreenGfxPos : 0);
181 fy += (ScreenMovDir & (MV_UP|MV_DOWN) ? ScreenGfxPos : 0);
183 BlitBitmap(fieldbuffer, backbuffer, fx,fy, SXSIZE,SYSIZE, SX,SY);
195 BlitBitmap(drawto, window, x, y, width, height, x, y);
198 void DrawMaskedBorder_Rect(int x, int y, int width, int height)
200 Bitmap *bitmap = graphic_info[IMG_GLOBAL_BORDER].bitmap;
202 SetClipOrigin(bitmap, bitmap->stored_clip_gc, 0, 0);
203 BlitBitmapMasked(bitmap, backbuffer, x, y, width, height, x, y);
206 void DrawMaskedBorder_FIELD()
208 if (global.border_status >= GAME_MODE_TITLE &&
209 global.border_status <= GAME_MODE_PLAYING &&
210 border.draw_masked[global.border_status])
211 DrawMaskedBorder_Rect(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
214 void DrawMaskedBorder_DOOR_1()
216 if (border.draw_masked[GFX_SPECIAL_ARG_DOOR] &&
217 (global.border_status != GAME_MODE_EDITOR ||
218 border.draw_masked[GFX_SPECIAL_ARG_EDITOR]))
219 DrawMaskedBorder_Rect(DX, DY, DXSIZE, DYSIZE);
222 void DrawMaskedBorder_DOOR_2()
224 if (border.draw_masked[GFX_SPECIAL_ARG_DOOR] &&
225 global.border_status != GAME_MODE_EDITOR)
226 DrawMaskedBorder_Rect(VX, VY, VXSIZE, VYSIZE);
229 void DrawMaskedBorder_DOOR_3()
231 /* currently not available */
234 void DrawMaskedBorder_ALL()
236 DrawMaskedBorder_FIELD();
237 DrawMaskedBorder_DOOR_1();
238 DrawMaskedBorder_DOOR_2();
239 DrawMaskedBorder_DOOR_3();
242 void DrawMaskedBorder(int redraw_mask)
244 /* never draw masked screen borders on borderless screens */
245 if (effectiveGameStatus() == GAME_MODE_LOADING ||
246 effectiveGameStatus() == GAME_MODE_TITLE)
249 if (redraw_mask & REDRAW_ALL)
250 DrawMaskedBorder_ALL();
253 if (redraw_mask & REDRAW_FIELD)
254 DrawMaskedBorder_FIELD();
255 if (redraw_mask & REDRAW_DOOR_1)
256 DrawMaskedBorder_DOOR_1();
257 if (redraw_mask & REDRAW_DOOR_2)
258 DrawMaskedBorder_DOOR_2();
259 if (redraw_mask & REDRAW_DOOR_3)
260 DrawMaskedBorder_DOOR_3();
267 DrawBuffer *buffer = (drawto_field == window ? backbuffer : drawto_field);
269 if (setup.direct_draw && game_status == GAME_MODE_PLAYING)
270 redraw_mask &= ~REDRAW_MAIN;
272 if (redraw_mask & REDRAW_TILES && redraw_tiles > REDRAWTILES_THRESHOLD)
273 redraw_mask |= REDRAW_FIELD;
275 if (redraw_mask & REDRAW_FIELD)
276 redraw_mask &= ~REDRAW_TILES;
278 if (redraw_mask == REDRAW_NONE)
281 if (redraw_mask & REDRAW_TILES &&
282 game_status == GAME_MODE_PLAYING &&
283 border.draw_masked[GAME_MODE_PLAYING])
284 redraw_mask |= REDRAW_FIELD;
286 if (global.fps_slowdown && game_status == GAME_MODE_PLAYING)
288 static boolean last_frame_skipped = FALSE;
289 boolean skip_even_when_not_scrolling = TRUE;
290 boolean just_scrolling = (ScreenMovDir != 0);
291 boolean verbose = FALSE;
293 if (global.fps_slowdown_factor > 1 &&
294 (FrameCounter % global.fps_slowdown_factor) &&
295 (just_scrolling || skip_even_when_not_scrolling))
297 redraw_mask &= ~REDRAW_MAIN;
299 last_frame_skipped = TRUE;
302 printf("FRAME SKIPPED\n");
306 if (last_frame_skipped)
307 redraw_mask |= REDRAW_FIELD;
309 last_frame_skipped = FALSE;
312 printf("frame not skipped\n");
316 /* synchronize X11 graphics at this point; if we would synchronize the
317 display immediately after the buffer switching (after the XFlush),
318 this could mean that we have to wait for the graphics to complete,
319 although we could go on doing calculations for the next frame */
323 /* prevent drawing masked border to backbuffer when using playfield buffer */
324 if (game_status != GAME_MODE_PLAYING ||
325 redraw_mask & REDRAW_FROM_BACKBUFFER ||
326 buffer == backbuffer)
327 DrawMaskedBorder(redraw_mask);
329 DrawMaskedBorder(redraw_mask & REDRAW_DOORS);
331 if (redraw_mask & REDRAW_ALL)
333 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
335 redraw_mask = REDRAW_NONE;
338 if (redraw_mask & REDRAW_FIELD)
340 if (game_status != GAME_MODE_PLAYING ||
341 redraw_mask & REDRAW_FROM_BACKBUFFER)
343 BlitBitmap(backbuffer, window,
344 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE, REAL_SX, REAL_SY);
348 int fx = FX, fy = FY;
350 if (setup.soft_scrolling)
352 fx += (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
353 fy += (ScreenMovDir & (MV_UP | MV_DOWN) ? ScreenGfxPos : 0);
356 if (setup.soft_scrolling ||
357 ABS(ScreenMovPos) + ScrollStepSize == TILEX ||
358 ABS(ScreenMovPos) == ScrollStepSize ||
359 redraw_tiles > REDRAWTILES_THRESHOLD)
361 if (border.draw_masked[GAME_MODE_PLAYING])
363 if (buffer != backbuffer)
365 /* copy playfield buffer to backbuffer to add masked border */
366 BlitBitmap(buffer, backbuffer, fx, fy, SXSIZE, SYSIZE, SX, SY);
367 DrawMaskedBorder(REDRAW_FIELD);
370 BlitBitmap(backbuffer, window,
371 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
376 BlitBitmap(buffer, window, fx, fy, SXSIZE, SYSIZE, SX, SY);
381 printf("redrawing all (ScreenGfxPos == %d) because %s\n",
383 (setup.soft_scrolling ?
384 "setup.soft_scrolling" :
385 ABS(ScreenGfxPos) + ScrollStepSize == TILEX ?
386 "ABS(ScreenGfxPos) + ScrollStepSize == TILEX" :
387 ABS(ScreenGfxPos) == ScrollStepSize ?
388 "ABS(ScreenGfxPos) == ScrollStepSize" :
389 "redraw_tiles > REDRAWTILES_THRESHOLD"));
395 redraw_mask &= ~REDRAW_MAIN;
398 if (redraw_mask & REDRAW_DOORS)
400 if (redraw_mask & REDRAW_DOOR_1)
401 BlitBitmap(backbuffer, window, DX, DY, DXSIZE, DYSIZE, DX, DY);
403 if (redraw_mask & REDRAW_DOOR_2)
404 BlitBitmap(backbuffer, window, VX, VY, VXSIZE, VYSIZE, VX, VY);
406 if (redraw_mask & REDRAW_DOOR_3)
407 BlitBitmap(backbuffer, window, EX, EY, EXSIZE, EYSIZE, EX, EY);
409 redraw_mask &= ~REDRAW_DOORS;
412 if (redraw_mask & REDRAW_MICROLEVEL)
414 BlitBitmap(backbuffer, window, SX, SY + 10 * TILEY, SXSIZE, 7 * TILEY,
415 SX, SY + 10 * TILEY);
417 redraw_mask &= ~REDRAW_MICROLEVEL;
420 if (redraw_mask & REDRAW_TILES)
422 for (x = 0; x < SCR_FIELDX; x++)
423 for (y = 0 ; y < SCR_FIELDY; y++)
424 if (redraw[redraw_x1 + x][redraw_y1 + y])
425 BlitBitmap(buffer, window,
426 FX + x * TILEX, FY + y * TILEY, TILEX, TILEY,
427 SX + x * TILEX, SY + y * TILEY);
430 if (redraw_mask & REDRAW_FPS) /* display frames per second */
435 sprintf(info1, " (only every %d. frame)", global.fps_slowdown_factor);
436 if (!global.fps_slowdown)
439 sprintf(text, "%.1f fps%s", global.frames_per_second, info1);
440 DrawTextExt(window, SX, SY, text, FONT_TEXT_2, BLIT_OPAQUE);
445 for (x = 0; x < MAX_BUF_XSIZE; x++)
446 for (y = 0; y < MAX_BUF_YSIZE; y++)
449 redraw_mask = REDRAW_NONE;
452 static void FadeCrossSaveBackbuffer()
454 BlitBitmap(backbuffer, bitmap_db_cross, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
457 static void FadeExt(int fade_mask, int fade_mode, int fade_type)
459 static int fade_type_skip = FADE_TYPE_NONE;
460 void (*draw_border_function)(void) = NULL;
461 Bitmap *bitmap = (fade_mode & FADE_TYPE_TRANSFORM ? bitmap_db_cross : NULL);
462 int x, y, width, height;
463 int fade_delay, post_delay;
465 if (fade_type == FADE_TYPE_FADE_OUT)
467 if (fade_type_skip != FADE_TYPE_NONE)
470 printf("::: skipping %d ... [%d] (X)\n", fade_mode, fade_type_skip);
473 /* skip all fade operations until specified fade operation */
474 if (fade_type & fade_type_skip)
475 fade_type_skip = FADE_TYPE_NONE;
480 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
482 FadeCrossSaveBackbuffer();
488 redraw_mask |= fade_mask;
490 if (fade_type == FADE_TYPE_SKIP)
493 printf("::: will skip %d ... [%d]\n", fade_mode, fade_type_skip);
496 fade_type_skip = fade_mode;
501 if (fade_type_skip != FADE_TYPE_NONE)
504 printf("::: skipping %d ... [%d]\n", fade_mode, fade_type_skip);
507 /* skip all fade operations until specified fade operation */
508 if (fade_type & fade_type_skip)
509 fade_type_skip = FADE_TYPE_NONE;
515 if (global.autoplay_leveldir)
517 // fading.fade_mode = FADE_MODE_NONE;
524 if (fading.fade_mode == FADE_MODE_NONE)
532 /* !!! what abount fade_mask == REDRAW_FIELD | REDRAW_ALL ??? !!! */
535 printf("::: NOW FADING %d ... [%d]\n", fade_mode, fade_type);
539 if (fade_mask == REDRAW_NONE)
540 fade_mask = REDRAW_FIELD;
543 if (fade_mask & REDRAW_FIELD)
548 height = FULL_SYSIZE;
550 fade_delay = fading.fade_delay;
551 post_delay = (fade_mode == FADE_MODE_FADE_OUT ? fading.post_delay : 0);
553 if (border.draw_masked_when_fading)
554 draw_border_function = DrawMaskedBorder_FIELD; /* update when fading */
556 DrawMaskedBorder_FIELD(); /* draw once */
558 else /* REDRAW_ALL */
565 fade_delay = fading.fade_delay;
566 post_delay = (fade_mode == FADE_MODE_FADE_OUT ? fading.post_delay : 0);
570 if (!setup.fade_screens || fade_delay == 0)
572 if (!setup.fade_screens || fade_delay == 0 || fading.anim_mode == ANIM_NONE)
575 if (fade_mode == FADE_MODE_FADE_OUT)
576 ClearRectangle(backbuffer, x, y, width, height);
583 FadeRectangle(bitmap, x, y, width, height, fade_mode, fade_delay, post_delay,
584 draw_border_function);
586 redraw_mask &= ~fade_mask;
589 void FadeIn(int fade_mask)
592 global.border_status = game_status;
596 // printf("::: now fading in...\n");
598 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
599 FadeExt(fade_mask, fading.fade_mode, FADE_TYPE_FADE_IN);
601 FadeExt(fade_mask, FADE_MODE_FADE_IN, FADE_TYPE_FADE_IN);
604 if (fading.fade_mode == FADE_MODE_CROSSFADE)
605 FadeExt(fade_mask, FADE_MODE_CROSSFADE);
607 FadeExt(fade_mask, FADE_MODE_FADE_IN);
609 FadeExt(fade_mask, FADE_MODE_FADE_IN);
614 void FadeOut(int fade_mask)
617 // printf("::: fading.fade_mode == %d\n", fading.fade_mode);
620 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
621 FadeExt(fade_mask, fading.fade_mode, FADE_TYPE_FADE_OUT);
623 FadeExt(fade_mask, FADE_MODE_FADE_OUT, FADE_TYPE_FADE_OUT);
625 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
626 FadeCrossSaveBackbuffer();
628 FadeExt(fade_mask, FADE_MODE_FADE_OUT, FADE_TYPE_FADE_OUT);
633 if (fading.fade_mode == FADE_MODE_CROSSFADE)
634 FadeCrossSaveBackbuffer();
636 FadeExt(fade_mask, FADE_MODE_FADE_OUT);
638 FadeExt(fade_mask, FADE_MODE_FADE_OUT);
643 global.border_status = game_status;
648 void FadeCross(int fade_mask)
650 FadeExt(fade_mask, FADE_MODE_CROSSFADE);
654 static void FadeSetLeaveNext(struct TitleFadingInfo fading_leave, boolean set)
656 static struct TitleFadingInfo fading_leave_stored;
659 fading_leave_stored = fading_leave;
661 fading = fading_leave_stored;
664 void FadeSetEnterMenu()
666 fading = menu.enter_menu;
669 printf("::: storing enter_menu\n");
672 FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
675 void FadeSetLeaveMenu()
677 fading = menu.leave_menu;
680 printf("::: storing leave_menu\n");
683 FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
686 void FadeSetEnterScreen()
688 fading = menu.enter_screen[game_status];
691 printf("::: storing leave_screen[%d]\n", game_status);
694 FadeSetLeaveNext(menu.leave_screen[game_status], TRUE); /* store */
697 void FadeSetNextScreen()
699 fading = menu.next_screen;
702 printf("::: storing next_screen\n");
705 // (do not overwrite fade mode set by FadeSetEnterScreen)
706 // FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
709 void FadeSetLeaveScreen()
712 printf("::: recalling last stored value\n");
715 FadeSetLeaveNext(menu.leave_screen[game_status], FALSE); /* recall */
718 void FadeSetFromType(int type)
720 if (type & TYPE_ENTER_SCREEN)
721 FadeSetEnterScreen();
722 else if (type & TYPE_ENTER)
724 else if (type & TYPE_LEAVE)
728 void FadeSetDisabled()
730 static struct TitleFadingInfo fading_none = { FADE_MODE_NONE, -1, -1, -1 };
732 fading = fading_none;
735 void FadeSkipNextFadeIn()
737 FadeExt(0, FADE_MODE_SKIP_FADE_IN, FADE_TYPE_SKIP);
740 void FadeSkipNextFadeOut()
742 FadeExt(0, FADE_MODE_SKIP_FADE_OUT, FADE_TYPE_SKIP);
745 void SetWindowBackgroundImageIfDefined(int graphic)
747 if (graphic_info[graphic].bitmap)
748 SetWindowBackgroundBitmap(graphic_info[graphic].bitmap);
751 void SetMainBackgroundImageIfDefined(int graphic)
753 if (graphic_info[graphic].bitmap)
754 SetMainBackgroundBitmap(graphic_info[graphic].bitmap);
757 void SetDoorBackgroundImageIfDefined(int graphic)
759 if (graphic_info[graphic].bitmap)
760 SetDoorBackgroundBitmap(graphic_info[graphic].bitmap);
763 void SetWindowBackgroundImage(int graphic)
765 SetWindowBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
766 graphic_info[graphic].bitmap ?
767 graphic_info[graphic].bitmap :
768 graphic_info[IMG_BACKGROUND].bitmap);
771 void SetMainBackgroundImage(int graphic)
773 SetMainBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
774 graphic_info[graphic].bitmap ?
775 graphic_info[graphic].bitmap :
776 graphic_info[IMG_BACKGROUND].bitmap);
779 void SetDoorBackgroundImage(int graphic)
781 SetDoorBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
782 graphic_info[graphic].bitmap ?
783 graphic_info[graphic].bitmap :
784 graphic_info[IMG_BACKGROUND].bitmap);
787 void SetPanelBackground()
789 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, bitmap_db_panel,
790 DOOR_GFX_PAGEX5, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE, 0, 0);
792 SetDoorBackgroundBitmap(bitmap_db_panel);
795 void DrawBackground(int x, int y, int width, int height)
797 /* !!! "drawto" might still point to playfield buffer here (see below) !!! */
798 /* (when entering hall of fame after playing) */
800 ClearRectangleOnBackground(drawto, x, y, width, height);
802 ClearRectangleOnBackground(backbuffer, x, y, width, height);
805 redraw_mask |= REDRAW_FIELD;
808 void DrawBackgroundForFont(int x, int y, int width, int height, int font_nr)
810 struct FontBitmapInfo *font = getFontBitmapInfo(font_nr);
812 if (font->bitmap == NULL)
815 DrawBackground(x, y, width, height);
818 void DrawBackgroundForGraphic(int x, int y, int width, int height, int graphic)
820 struct GraphicInfo *g = &graphic_info[graphic];
822 if (g->bitmap == NULL)
825 DrawBackground(x, y, width, height);
830 /* !!! "drawto" might still point to playfield buffer here (see above) !!! */
831 /* (when entering hall of fame after playing) */
832 DrawBackground(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
834 /* !!! maybe this should be done before clearing the background !!! */
835 if (setup.soft_scrolling && game_status == GAME_MODE_PLAYING)
837 ClearRectangle(fieldbuffer, 0, 0, FXSIZE, FYSIZE);
838 SetDrawtoField(DRAW_BUFFERED);
841 SetDrawtoField(DRAW_BACKBUFFER);
843 if (setup.direct_draw && game_status == GAME_MODE_PLAYING)
845 ClearRectangle(window, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
846 SetDrawtoField(DRAW_DIRECT);
850 void MarkTileDirty(int x, int y)
852 int xx = redraw_x1 + x;
853 int yy = redraw_y1 + y;
858 redraw[xx][yy] = TRUE;
859 redraw_mask |= REDRAW_TILES;
862 void SetBorderElement()
866 BorderElement = EL_EMPTY;
868 for (y = 0; y < lev_fieldy && BorderElement == EL_EMPTY; y++)
870 for (x = 0; x < lev_fieldx; x++)
872 if (!IS_INDESTRUCTIBLE(Feld[x][y]))
873 BorderElement = EL_STEELWALL;
875 if (y != 0 && y != lev_fieldy - 1 && x != lev_fieldx - 1)
881 void FloodFillLevel(int from_x, int from_y, int fill_element,
882 short field[MAX_LEV_FIELDX][MAX_LEV_FIELDY],
883 int max_fieldx, int max_fieldy)
887 static int check[4][2] = { { -1, 0 }, { 0, -1 }, { 1, 0 }, { 0, 1 } };
888 static int safety = 0;
890 /* check if starting field still has the desired content */
891 if (field[from_x][from_y] == fill_element)
896 if (safety > max_fieldx * max_fieldy)
897 Error(ERR_EXIT, "Something went wrong in 'FloodFill()'. Please debug.");
899 old_element = field[from_x][from_y];
900 field[from_x][from_y] = fill_element;
902 for (i = 0; i < 4; i++)
904 x = from_x + check[i][0];
905 y = from_y + check[i][1];
907 if (IN_FIELD(x, y, max_fieldx, max_fieldy) && field[x][y] == old_element)
908 FloodFillLevel(x, y, fill_element, field, max_fieldx, max_fieldy);
914 void SetRandomAnimationValue(int x, int y)
916 gfx.anim_random_frame = GfxRandom[x][y];
919 inline int getGraphicAnimationFrame(int graphic, int sync_frame)
921 /* animation synchronized with global frame counter, not move position */
922 if (graphic_info[graphic].anim_global_sync || sync_frame < 0)
923 sync_frame = FrameCounter;
925 return getAnimationFrame(graphic_info[graphic].anim_frames,
926 graphic_info[graphic].anim_delay,
927 graphic_info[graphic].anim_mode,
928 graphic_info[graphic].anim_start_frame,
932 void getSizedGraphicSource(int graphic, int frame, int tilesize_raw,
933 Bitmap **bitmap, int *x, int *y)
937 int width_mult, width_div;
938 int height_mult, height_div;
942 { 15, 16, 2, 3 }, /* 1 x 1 */
943 { 7, 8, 2, 3 }, /* 2 x 2 */
944 { 3, 4, 2, 3 }, /* 4 x 4 */
945 { 1, 2, 2, 3 }, /* 8 x 8 */
946 { 0, 1, 2, 3 }, /* 16 x 16 */
947 { 0, 1, 0, 1 }, /* 32 x 32 */
949 struct GraphicInfo *g = &graphic_info[graphic];
950 Bitmap *src_bitmap = g->bitmap;
951 int tilesize = MIN(MAX(1, tilesize_raw), TILESIZE);
952 int offset_calc_pos = log_2(tilesize);
953 int width_mult = offset_calc[offset_calc_pos].width_mult;
954 int width_div = offset_calc[offset_calc_pos].width_div;
955 int height_mult = offset_calc[offset_calc_pos].height_mult;
956 int height_div = offset_calc[offset_calc_pos].height_div;
957 int startx = src_bitmap->width * width_mult / width_div;
958 int starty = src_bitmap->height * height_mult / height_div;
959 int src_x = g->src_x * tilesize / TILESIZE;
960 int src_y = g->src_y * tilesize / TILESIZE;
961 int width = g->width * tilesize / TILESIZE;
962 int height = g->height * tilesize / TILESIZE;
963 int offset_x = g->offset_x * tilesize / TILESIZE;
964 int offset_y = g->offset_y * tilesize / TILESIZE;
966 if (g->offset_y == 0) /* frames are ordered horizontally */
968 int max_width = g->anim_frames_per_line * width;
969 int pos = (src_y / height) * max_width + src_x + frame * offset_x;
971 src_x = pos % max_width;
972 src_y = src_y % height + pos / max_width * height;
974 else if (g->offset_x == 0) /* frames are ordered vertically */
976 int max_height = g->anim_frames_per_line * height;
977 int pos = (src_x / width) * max_height + src_y + frame * offset_y;
979 src_x = src_x % width + pos / max_height * width;
980 src_y = pos % max_height;
982 else /* frames are ordered diagonally */
984 src_x = src_x + frame * offset_x;
985 src_y = src_y + frame * offset_y;
988 *bitmap = src_bitmap;
993 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
996 getSizedGraphicSource(graphic, 0, MINI_TILESIZE, bitmap, x, y);
998 struct GraphicInfo *g = &graphic_info[graphic];
1000 int mini_starty = g->bitmap->height * 2 / 3;
1002 *bitmap = g->bitmap;
1003 *x = mini_startx + g->src_x / 2;
1004 *y = mini_starty + g->src_y / 2;
1008 inline void getGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
1009 int *x, int *y, boolean get_backside)
1011 struct GraphicInfo *g = &graphic_info[graphic];
1012 int src_x = g->src_x + (get_backside ? g->offset2_x : 0);
1013 int src_y = g->src_y + (get_backside ? g->offset2_y : 0);
1015 *bitmap = g->bitmap;
1017 if (g->offset_y == 0) /* frames are ordered horizontally */
1019 int max_width = g->anim_frames_per_line * g->width;
1020 int pos = (src_y / g->height) * max_width + src_x + frame * g->offset_x;
1022 *x = pos % max_width;
1023 *y = src_y % g->height + pos / max_width * g->height;
1025 else if (g->offset_x == 0) /* frames are ordered vertically */
1027 int max_height = g->anim_frames_per_line * g->height;
1028 int pos = (src_x / g->width) * max_height + src_y + frame * g->offset_y;
1030 *x = src_x % g->width + pos / max_height * g->width;
1031 *y = pos % max_height;
1033 else /* frames are ordered diagonally */
1035 *x = src_x + frame * g->offset_x;
1036 *y = src_y + frame * g->offset_y;
1040 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
1042 getGraphicSourceExt(graphic, frame, bitmap, x, y, FALSE);
1045 void DrawGraphic(int x, int y, int graphic, int frame)
1048 if (!IN_SCR_FIELD(x, y))
1050 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
1051 printf("DrawGraphic(): This should never happen!\n");
1056 DrawGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic, frame);
1057 MarkTileDirty(x, y);
1060 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
1066 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1067 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
1070 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
1073 if (!IN_SCR_FIELD(x, y))
1075 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
1076 printf("DrawGraphicThruMask(): This should never happen!\n");
1081 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y *TILEY, graphic,
1083 MarkTileDirty(x, y);
1086 void DrawGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y, int graphic,
1092 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1094 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1095 dst_x - src_x, dst_y - src_y);
1096 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dst_x, dst_y);
1099 void DrawSizedGraphic(int x, int y, int graphic, int frame, int tilesize)
1101 DrawSizedGraphicExt(drawto, SX + x * tilesize, SY + y * tilesize, graphic,
1103 MarkTileDirty(x / tilesize, y / tilesize);
1106 void DrawSizedGraphicExt(DrawBuffer *d, int x, int y, int graphic, int frame,
1112 getSizedGraphicSource(graphic, frame, tilesize, &src_bitmap, &src_x, &src_y);
1113 BlitBitmap(src_bitmap, d, src_x, src_y, tilesize, tilesize, x, y);
1116 void DrawMiniGraphic(int x, int y, int graphic)
1118 DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
1119 MarkTileDirty(x / 2, y / 2);
1122 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
1127 getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1128 BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
1131 inline static void DrawGraphicShiftedNormal(int x, int y, int dx, int dy,
1132 int graphic, int frame,
1133 int cut_mode, int mask_mode)
1138 int width = TILEX, height = TILEY;
1141 if (dx || dy) /* shifted graphic */
1143 if (x < BX1) /* object enters playfield from the left */
1150 else if (x > BX2) /* object enters playfield from the right */
1156 else if (x==BX1 && dx < 0) /* object leaves playfield to the left */
1162 else if (x==BX2 && dx > 0) /* object leaves playfield to the right */
1164 else if (dx) /* general horizontal movement */
1165 MarkTileDirty(x + SIGN(dx), y);
1167 if (y < BY1) /* object enters playfield from the top */
1169 if (cut_mode==CUT_BELOW) /* object completely above top border */
1177 else if (y > BY2) /* object enters playfield from the bottom */
1183 else if (y==BY1 && dy < 0) /* object leaves playfield to the top */
1189 else if (dy > 0 && cut_mode == CUT_ABOVE)
1191 if (y == BY2) /* object completely above bottom border */
1197 MarkTileDirty(x, y + 1);
1198 } /* object leaves playfield to the bottom */
1199 else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
1201 else if (dy) /* general vertical movement */
1202 MarkTileDirty(x, y + SIGN(dy));
1206 if (!IN_SCR_FIELD(x, y))
1208 printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
1209 printf("DrawGraphicShifted(): This should never happen!\n");
1214 if (width > 0 && height > 0)
1216 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1221 dst_x = FX + x * TILEX + dx;
1222 dst_y = FY + y * TILEY + dy;
1224 if (mask_mode == USE_MASKING)
1226 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1227 dst_x - src_x, dst_y - src_y);
1228 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1232 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1235 MarkTileDirty(x, y);
1239 inline static void DrawGraphicShiftedDouble(int x, int y, int dx, int dy,
1240 int graphic, int frame,
1241 int cut_mode, int mask_mode)
1246 int width = TILEX, height = TILEY;
1249 int x2 = x + SIGN(dx);
1250 int y2 = y + SIGN(dy);
1251 int anim_frames = graphic_info[graphic].anim_frames;
1252 int sync_frame = (dx ? ABS(dx) : ABS(dy)) * anim_frames / TILESIZE;
1253 boolean draw_start_tile = (cut_mode != CUT_ABOVE); /* only for falling! */
1254 boolean draw_end_tile = (cut_mode != CUT_BELOW); /* only for falling! */
1256 /* re-calculate animation frame for two-tile movement animation */
1257 frame = getGraphicAnimationFrame(graphic, sync_frame);
1259 /* check if movement start graphic inside screen area and should be drawn */
1260 if (draw_start_tile && IN_SCR_FIELD(x1, y1))
1262 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, TRUE);
1264 dst_x = FX + x1 * TILEX;
1265 dst_y = FY + y1 * TILEY;
1267 if (mask_mode == USE_MASKING)
1269 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1270 dst_x - src_x, dst_y - src_y);
1271 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1275 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1278 MarkTileDirty(x1, y1);
1281 /* check if movement end graphic inside screen area and should be drawn */
1282 if (draw_end_tile && IN_SCR_FIELD(x2, y2))
1284 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
1286 dst_x = FX + x2 * TILEX;
1287 dst_y = FY + y2 * TILEY;
1289 if (mask_mode == USE_MASKING)
1291 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1292 dst_x - src_x, dst_y - src_y);
1293 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1297 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1300 MarkTileDirty(x2, y2);
1304 static void DrawGraphicShifted(int x, int y, int dx, int dy,
1305 int graphic, int frame,
1306 int cut_mode, int mask_mode)
1310 DrawGraphic(x, y, graphic, frame);
1315 if (graphic_info[graphic].double_movement) /* EM style movement images */
1316 DrawGraphicShiftedDouble(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1318 DrawGraphicShiftedNormal(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1321 void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
1322 int frame, int cut_mode)
1324 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, USE_MASKING);
1327 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
1328 int cut_mode, int mask_mode)
1330 int lx = LEVELX(x), ly = LEVELY(y);
1334 if (IN_LEV_FIELD(lx, ly))
1336 SetRandomAnimationValue(lx, ly);
1338 graphic = el_act_dir2img(element, GfxAction[lx][ly], GfxDir[lx][ly]);
1339 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1341 /* do not use double (EM style) movement graphic when not moving */
1342 if (graphic_info[graphic].double_movement && !dx && !dy)
1344 graphic = el_act_dir2img(element, ACTION_DEFAULT, GfxDir[lx][ly]);
1345 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1348 else /* border element */
1350 graphic = el2img(element);
1351 frame = getGraphicAnimationFrame(graphic, -1);
1354 if (element == EL_EXPANDABLE_WALL)
1356 boolean left_stopped = FALSE, right_stopped = FALSE;
1358 if (!IN_LEV_FIELD(lx - 1, ly) || IS_WALL(Feld[lx - 1][ly]))
1359 left_stopped = TRUE;
1360 if (!IN_LEV_FIELD(lx + 1, ly) || IS_WALL(Feld[lx + 1][ly]))
1361 right_stopped = TRUE;
1363 if (left_stopped && right_stopped)
1365 else if (left_stopped)
1367 graphic = IMG_EXPANDABLE_WALL_GROWING_RIGHT;
1368 frame = graphic_info[graphic].anim_frames - 1;
1370 else if (right_stopped)
1372 graphic = IMG_EXPANDABLE_WALL_GROWING_LEFT;
1373 frame = graphic_info[graphic].anim_frames - 1;
1378 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
1379 else if (mask_mode == USE_MASKING)
1380 DrawGraphicThruMask(x, y, graphic, frame);
1382 DrawGraphic(x, y, graphic, frame);
1385 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
1386 int cut_mode, int mask_mode)
1388 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1389 DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
1390 cut_mode, mask_mode);
1393 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
1396 DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1399 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
1402 DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1405 void DrawLevelElementThruMask(int x, int y, int element)
1407 DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1410 void DrawLevelFieldThruMask(int x, int y)
1412 DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
1415 static void DrawLevelFieldCrumbledSandExt(int x, int y, int graphic, int frame)
1419 int sx = SCREENX(x), sy = SCREENY(y);
1421 int width, height, cx, cy, i;
1422 int crumbled_border_size = graphic_info[graphic].border_size;
1423 static int xy[4][2] =
1431 if (!IN_LEV_FIELD(x, y))
1434 element = TILE_GFX_ELEMENT(x, y);
1436 /* crumble field itself */
1437 if (GFX_CRUMBLED(element) && !IS_MOVING(x, y))
1439 if (!IN_SCR_FIELD(sx, sy))
1442 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1444 for (i = 0; i < 4; i++)
1446 int xx = x + xy[i][0];
1447 int yy = y + xy[i][1];
1449 element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1452 /* check if neighbour field is of same type */
1453 if (GFX_CRUMBLED(element) && !IS_MOVING(xx, yy))
1456 if (i == 1 || i == 2)
1458 width = crumbled_border_size;
1460 cx = (i == 2 ? TILEX - crumbled_border_size : 0);
1466 height = crumbled_border_size;
1468 cy = (i == 3 ? TILEY - crumbled_border_size : 0);
1471 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1472 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
1475 MarkTileDirty(sx, sy);
1477 else /* crumble neighbour fields */
1479 for (i = 0; i < 4; i++)
1481 int xx = x + xy[i][0];
1482 int yy = y + xy[i][1];
1483 int sxx = sx + xy[i][0];
1484 int syy = sy + xy[i][1];
1486 if (!IN_LEV_FIELD(xx, yy) ||
1487 !IN_SCR_FIELD(sxx, syy) ||
1491 if (Feld[xx][yy] == EL_ELEMENT_SNAPPING)
1494 element = TILE_GFX_ELEMENT(xx, yy);
1496 if (!GFX_CRUMBLED(element))
1499 graphic = el_act2crm(element, ACTION_DEFAULT);
1500 crumbled_border_size = graphic_info[graphic].border_size;
1502 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1504 if (i == 1 || i == 2)
1506 width = crumbled_border_size;
1508 cx = (i == 1 ? TILEX - crumbled_border_size : 0);
1514 height = crumbled_border_size;
1516 cy = (i == 0 ? TILEY - crumbled_border_size : 0);
1519 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1520 width, height, FX + sxx * TILEX + cx, FY + syy * TILEY + cy);
1522 MarkTileDirty(sxx, syy);
1527 void DrawLevelFieldCrumbledSand(int x, int y)
1531 if (!IN_LEV_FIELD(x, y))
1535 /* !!! CHECK THIS !!! */
1538 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
1539 GFX_CRUMBLED(GfxElement[x][y]))
1542 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
1543 GfxElement[x][y] != EL_UNDEFINED &&
1544 GFX_CRUMBLED(GfxElement[x][y]))
1546 DrawLevelFieldCrumbledSandDigging(x, y, GfxDir[x][y], GfxFrame[x][y]);
1553 graphic = el_act2crm(TILE_GFX_ELEMENT(x, y), ACTION_DEFAULT);
1555 graphic = el_act2crm(Feld[x][y], ACTION_DEFAULT);
1558 DrawLevelFieldCrumbledSandExt(x, y, graphic, 0);
1561 void DrawLevelFieldCrumbledSandDigging(int x, int y, int direction,
1564 int graphic1 = el_act_dir2img(GfxElement[x][y], ACTION_DIGGING, direction);
1565 int graphic2 = el_act_dir2crm(GfxElement[x][y], ACTION_DIGGING, direction);
1566 int frame1 = getGraphicAnimationFrame(graphic1, step_frame);
1567 int frame2 = getGraphicAnimationFrame(graphic2, step_frame);
1568 int sx = SCREENX(x), sy = SCREENY(y);
1570 DrawGraphic(sx, sy, graphic1, frame1);
1571 DrawLevelFieldCrumbledSandExt(x, y, graphic2, frame2);
1574 void DrawLevelFieldCrumbledSandNeighbours(int x, int y)
1576 int sx = SCREENX(x), sy = SCREENY(y);
1577 static int xy[4][2] =
1586 for (i = 0; i < 4; i++)
1588 int xx = x + xy[i][0];
1589 int yy = y + xy[i][1];
1590 int sxx = sx + xy[i][0];
1591 int syy = sy + xy[i][1];
1593 if (!IN_LEV_FIELD(xx, yy) ||
1594 !IN_SCR_FIELD(sxx, syy) ||
1595 !GFX_CRUMBLED(Feld[xx][yy]) ||
1599 DrawLevelField(xx, yy);
1603 static int getBorderElement(int x, int y)
1607 { EL_STEELWALL_TOPLEFT, EL_INVISIBLE_STEELWALL_TOPLEFT },
1608 { EL_STEELWALL_TOPRIGHT, EL_INVISIBLE_STEELWALL_TOPRIGHT },
1609 { EL_STEELWALL_BOTTOMLEFT, EL_INVISIBLE_STEELWALL_BOTTOMLEFT },
1610 { EL_STEELWALL_BOTTOMRIGHT, EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
1611 { EL_STEELWALL_VERTICAL, EL_INVISIBLE_STEELWALL_VERTICAL },
1612 { EL_STEELWALL_HORIZONTAL, EL_INVISIBLE_STEELWALL_HORIZONTAL },
1613 { EL_STEELWALL, EL_INVISIBLE_STEELWALL }
1615 int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
1616 int steel_position = (x == -1 && y == -1 ? 0 :
1617 x == lev_fieldx && y == -1 ? 1 :
1618 x == -1 && y == lev_fieldy ? 2 :
1619 x == lev_fieldx && y == lev_fieldy ? 3 :
1620 x == -1 || x == lev_fieldx ? 4 :
1621 y == -1 || y == lev_fieldy ? 5 : 6);
1623 return border[steel_position][steel_type];
1626 void DrawScreenElement(int x, int y, int element)
1628 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
1629 DrawLevelFieldCrumbledSand(LEVELX(x), LEVELY(y));
1632 void DrawLevelElement(int x, int y, int element)
1634 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1635 DrawScreenElement(SCREENX(x), SCREENY(y), element);
1638 void DrawScreenField(int x, int y)
1640 int lx = LEVELX(x), ly = LEVELY(y);
1641 int element, content;
1643 if (!IN_LEV_FIELD(lx, ly))
1645 if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
1648 element = getBorderElement(lx, ly);
1650 DrawScreenElement(x, y, element);
1654 element = Feld[lx][ly];
1655 content = Store[lx][ly];
1657 if (IS_MOVING(lx, ly))
1659 int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
1660 boolean cut_mode = NO_CUTTING;
1662 if (element == EL_QUICKSAND_EMPTYING ||
1663 element == EL_QUICKSAND_FAST_EMPTYING ||
1664 element == EL_MAGIC_WALL_EMPTYING ||
1665 element == EL_BD_MAGIC_WALL_EMPTYING ||
1666 element == EL_DC_MAGIC_WALL_EMPTYING ||
1667 element == EL_AMOEBA_DROPPING)
1668 cut_mode = CUT_ABOVE;
1669 else if (element == EL_QUICKSAND_FILLING ||
1670 element == EL_QUICKSAND_FAST_FILLING ||
1671 element == EL_MAGIC_WALL_FILLING ||
1672 element == EL_BD_MAGIC_WALL_FILLING ||
1673 element == EL_DC_MAGIC_WALL_FILLING)
1674 cut_mode = CUT_BELOW;
1676 if (cut_mode == CUT_ABOVE)
1677 DrawScreenElementShifted(x, y, 0, 0, element, NO_CUTTING);
1679 DrawScreenElement(x, y, EL_EMPTY);
1682 DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
1683 else if (cut_mode == NO_CUTTING)
1684 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
1686 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
1688 if (content == EL_ACID)
1690 int dir = MovDir[lx][ly];
1691 int newlx = lx + (dir == MV_LEFT ? -1 : dir == MV_RIGHT ? +1 : 0);
1692 int newly = ly + (dir == MV_UP ? -1 : dir == MV_DOWN ? +1 : 0);
1694 DrawLevelElementThruMask(newlx, newly, EL_ACID);
1697 else if (IS_BLOCKED(lx, ly))
1702 boolean cut_mode = NO_CUTTING;
1703 int element_old, content_old;
1705 Blocked2Moving(lx, ly, &oldx, &oldy);
1708 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
1709 MovDir[oldx][oldy] == MV_RIGHT);
1711 element_old = Feld[oldx][oldy];
1712 content_old = Store[oldx][oldy];
1714 if (element_old == EL_QUICKSAND_EMPTYING ||
1715 element_old == EL_QUICKSAND_FAST_EMPTYING ||
1716 element_old == EL_MAGIC_WALL_EMPTYING ||
1717 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
1718 element_old == EL_DC_MAGIC_WALL_EMPTYING ||
1719 element_old == EL_AMOEBA_DROPPING)
1720 cut_mode = CUT_ABOVE;
1722 DrawScreenElement(x, y, EL_EMPTY);
1725 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
1727 else if (cut_mode == NO_CUTTING)
1728 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
1731 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
1734 else if (IS_DRAWABLE(element))
1735 DrawScreenElement(x, y, element);
1737 DrawScreenElement(x, y, EL_EMPTY);
1740 void DrawLevelField(int x, int y)
1742 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1743 DrawScreenField(SCREENX(x), SCREENY(y));
1744 else if (IS_MOVING(x, y))
1748 Moving2Blocked(x, y, &newx, &newy);
1749 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
1750 DrawScreenField(SCREENX(newx), SCREENY(newy));
1752 else if (IS_BLOCKED(x, y))
1756 Blocked2Moving(x, y, &oldx, &oldy);
1757 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
1758 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
1762 void DrawMiniElement(int x, int y, int element)
1766 graphic = el2edimg(element);
1767 DrawMiniGraphic(x, y, graphic);
1770 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
1772 int x = sx + scroll_x, y = sy + scroll_y;
1774 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
1775 DrawMiniElement(sx, sy, EL_EMPTY);
1776 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
1777 DrawMiniElement(sx, sy, Feld[x][y]);
1779 DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
1782 void DrawEnvelopeBackground(int envelope_nr, int startx, int starty,
1783 int x, int y, int xsize, int ysize, int font_nr)
1785 int font_width = getFontWidth(font_nr);
1786 int font_height = getFontHeight(font_nr);
1787 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1790 int dst_x = SX + startx + x * font_width;
1791 int dst_y = SY + starty + y * font_height;
1792 int width = graphic_info[graphic].width;
1793 int height = graphic_info[graphic].height;
1794 int inner_width = MAX(width - 2 * font_width, font_width);
1795 int inner_height = MAX(height - 2 * font_height, font_height);
1796 int inner_sx = (width >= 3 * font_width ? font_width : 0);
1797 int inner_sy = (height >= 3 * font_height ? font_height : 0);
1798 boolean draw_masked = graphic_info[graphic].draw_masked;
1800 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1802 if (src_bitmap == NULL || width < font_width || height < font_height)
1804 ClearRectangle(drawto, dst_x, dst_y, font_width, font_height);
1808 src_x += (x == 0 ? 0 : x == xsize - 1 ? width - font_width :
1809 inner_sx + (x - 1) * font_width % inner_width);
1810 src_y += (y == 0 ? 0 : y == ysize - 1 ? height - font_height :
1811 inner_sy + (y - 1) * font_height % inner_height);
1815 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1816 dst_x - src_x, dst_y - src_y);
1817 BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1821 BlitBitmap(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1825 void AnimateEnvelope(int envelope_nr, int anim_mode, int action)
1827 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1828 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1829 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
1830 boolean ffwd_delay = (tape.playing && tape.fast_forward);
1831 boolean no_delay = (tape.warp_forward);
1832 unsigned long anim_delay = 0;
1833 int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
1834 int anim_delay_value = (no_delay ? 0 : frame_delay_value);
1835 int font_nr = FONT_ENVELOPE_1 + envelope_nr;
1836 int font_width = getFontWidth(font_nr);
1837 int font_height = getFontHeight(font_nr);
1838 int max_xsize = level.envelope[envelope_nr].xsize;
1839 int max_ysize = level.envelope[envelope_nr].ysize;
1840 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
1841 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
1842 int xend = max_xsize;
1843 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
1844 int xstep = (xstart < xend ? 1 : 0);
1845 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
1848 for (x = xstart, y = ystart; x <= xend && y <= yend; x += xstep, y += ystep)
1850 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
1851 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
1852 int sx = (SXSIZE - xsize * font_width) / 2;
1853 int sy = (SYSIZE - ysize * font_height) / 2;
1856 SetDrawtoField(DRAW_BUFFERED);
1858 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
1860 SetDrawtoField(DRAW_BACKBUFFER);
1862 for (yy = 0; yy < ysize; yy++) for (xx = 0; xx < xsize; xx++)
1863 DrawEnvelopeBackground(envelope_nr, sx,sy, xx,yy, xsize, ysize, font_nr);
1866 DrawTextBuffer(SX + sx + font_width, SY + sy + font_height,
1867 level.envelope[envelope_nr].text, font_nr, max_xsize,
1868 xsize - 2, ysize - 2, mask_mode,
1869 level.envelope[envelope_nr].autowrap,
1870 level.envelope[envelope_nr].centered, FALSE);
1872 DrawTextToTextArea(SX + sx + font_width, SY + sy + font_height,
1873 level.envelope[envelope_nr].text, font_nr, max_xsize,
1874 xsize - 2, ysize - 2, mask_mode);
1877 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
1880 WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
1884 void ShowEnvelope(int envelope_nr)
1886 int element = EL_ENVELOPE_1 + envelope_nr;
1887 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1888 int sound_opening = element_info[element].sound[ACTION_OPENING];
1889 int sound_closing = element_info[element].sound[ACTION_CLOSING];
1890 boolean ffwd_delay = (tape.playing && tape.fast_forward);
1891 boolean no_delay = (tape.warp_forward);
1892 int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
1893 int wait_delay_value = (no_delay ? 0 : normal_delay_value);
1894 int anim_mode = graphic_info[graphic].anim_mode;
1895 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
1896 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
1898 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
1900 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
1902 if (anim_mode == ANIM_DEFAULT)
1903 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_OPENING);
1905 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_OPENING);
1908 Delay(wait_delay_value);
1910 WaitForEventToContinue();
1912 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
1914 if (anim_mode != ANIM_NONE)
1915 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_CLOSING);
1917 if (anim_mode == ANIM_DEFAULT)
1918 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_CLOSING);
1920 game.envelope_active = FALSE;
1922 SetDrawtoField(DRAW_BUFFERED);
1924 redraw_mask |= REDRAW_FIELD;
1928 void DrawPreviewElement(int dst_x, int dst_y, int element, int tilesize)
1932 int graphic = el2preimg(element);
1934 getSizedGraphicSource(graphic, 0, tilesize, &src_bitmap, &src_x, &src_y);
1935 BlitBitmap(src_bitmap, drawto, src_x, src_y, tilesize, tilesize, dst_x,dst_y);
1942 SetDrawBackgroundMask(REDRAW_NONE);
1945 for (x = BX1; x <= BX2; x++)
1946 for (y = BY1; y <= BY2; y++)
1947 DrawScreenField(x, y);
1949 redraw_mask |= REDRAW_FIELD;
1952 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
1956 for (x = 0; x < size_x; x++)
1957 for (y = 0; y < size_y; y++)
1958 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
1960 redraw_mask |= REDRAW_FIELD;
1963 static void DrawPreviewLevelExt(int from_x, int from_y)
1965 boolean show_level_border = (BorderElement != EL_EMPTY);
1966 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
1967 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
1968 int tile_size = preview.tile_size;
1969 int preview_width = preview.xsize * tile_size;
1970 int preview_height = preview.ysize * tile_size;
1971 int real_preview_xsize = MIN(level_xsize, preview.xsize);
1972 int real_preview_ysize = MIN(level_ysize, preview.ysize);
1973 int dst_x = SX + ALIGNED_XPOS(preview.x, preview_width, preview.align);
1974 int dst_y = SY + ALIGNED_YPOS(preview.y, preview_height, preview.valign);
1977 DrawBackground(dst_x, dst_y, preview_width, preview_height);
1979 dst_x += (preview_width - real_preview_xsize * tile_size) / 2;
1980 dst_y += (preview_height - real_preview_ysize * tile_size) / 2;
1982 for (x = 0; x < real_preview_xsize; x++)
1984 for (y = 0; y < real_preview_ysize; y++)
1986 int lx = from_x + x + (show_level_border ? -1 : 0);
1987 int ly = from_y + y + (show_level_border ? -1 : 0);
1988 int element = (IN_LEV_FIELD(lx, ly) ? level.field[lx][ly] :
1989 getBorderElement(lx, ly));
1991 DrawPreviewElement(dst_x + x * tile_size, dst_y + y * tile_size,
1992 element, tile_size);
1996 redraw_mask |= REDRAW_MICROLEVEL;
1999 #define MICROLABEL_EMPTY 0
2000 #define MICROLABEL_LEVEL_NAME 1
2001 #define MICROLABEL_LEVEL_AUTHOR_HEAD 2
2002 #define MICROLABEL_LEVEL_AUTHOR 3
2003 #define MICROLABEL_IMPORTED_FROM_HEAD 4
2004 #define MICROLABEL_IMPORTED_FROM 5
2005 #define MICROLABEL_IMPORTED_BY_HEAD 6
2006 #define MICROLABEL_IMPORTED_BY 7
2008 static int getMaxTextLength(struct TextPosInfo *pos, int font_nr)
2010 int max_text_width = SXSIZE;
2011 int font_width = getFontWidth(font_nr);
2013 if (pos->align == ALIGN_CENTER)
2014 max_text_width = (pos->x < SXSIZE / 2 ? pos->x * 2 : (SXSIZE - pos->x) * 2);
2015 else if (pos->align == ALIGN_RIGHT)
2016 max_text_width = pos->x;
2018 max_text_width = SXSIZE - pos->x;
2020 return max_text_width / font_width;
2023 static void DrawPreviewLevelLabelExt(int mode)
2025 struct TextPosInfo *pos = &menu.main.text.level_info_2;
2026 char label_text[MAX_OUTPUT_LINESIZE + 1];
2027 int max_len_label_text;
2029 int font_nr = pos->font;
2032 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
2033 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
2034 mode == MICROLABEL_IMPORTED_BY_HEAD)
2035 font_nr = pos->font_alt;
2037 int font_nr = FONT_TEXT_2;
2040 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
2041 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
2042 mode == MICROLABEL_IMPORTED_BY_HEAD)
2043 font_nr = FONT_TEXT_3;
2047 max_len_label_text = getMaxTextLength(pos, font_nr);
2049 max_len_label_text = SXSIZE / getFontWidth(font_nr);
2053 if (pos->size != -1)
2054 max_len_label_text = pos->size;
2057 for (i = 0; i < max_len_label_text; i++)
2058 label_text[i] = ' ';
2059 label_text[max_len_label_text] = '\0';
2061 if (strlen(label_text) > 0)
2064 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2066 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
2067 int lypos = MICROLABEL2_YPOS;
2069 DrawText(lxpos, lypos, label_text, font_nr);
2074 (mode == MICROLABEL_LEVEL_NAME ? level.name :
2075 mode == MICROLABEL_LEVEL_AUTHOR_HEAD ? "created by" :
2076 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
2077 mode == MICROLABEL_IMPORTED_FROM_HEAD ? "imported from" :
2078 mode == MICROLABEL_IMPORTED_FROM ? leveldir_current->imported_from :
2079 mode == MICROLABEL_IMPORTED_BY_HEAD ? "imported by" :
2080 mode == MICROLABEL_IMPORTED_BY ? leveldir_current->imported_by :""),
2081 max_len_label_text);
2082 label_text[max_len_label_text] = '\0';
2084 if (strlen(label_text) > 0)
2087 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2089 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
2090 int lypos = MICROLABEL2_YPOS;
2092 DrawText(lxpos, lypos, label_text, font_nr);
2096 redraw_mask |= REDRAW_MICROLEVEL;
2099 void DrawPreviewLevel(boolean restart)
2101 static unsigned long scroll_delay = 0;
2102 static unsigned long label_delay = 0;
2103 static int from_x, from_y, scroll_direction;
2104 static int label_state, label_counter;
2105 unsigned long scroll_delay_value = preview.step_delay;
2106 boolean show_level_border = (BorderElement != EL_EMPTY);
2107 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
2108 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
2109 int last_game_status = game_status; /* save current game status */
2112 /* force PREVIEW font on preview level */
2113 game_status = GAME_MODE_PSEUDO_PREVIEW;
2121 if (preview.anim_mode == ANIM_CENTERED)
2123 if (level_xsize > preview.xsize)
2124 from_x = (level_xsize - preview.xsize) / 2;
2125 if (level_ysize > preview.ysize)
2126 from_y = (level_ysize - preview.ysize) / 2;
2129 from_x += preview.xoffset;
2130 from_y += preview.yoffset;
2132 scroll_direction = MV_RIGHT;
2136 DrawPreviewLevelExt(from_x, from_y);
2137 DrawPreviewLevelLabelExt(label_state);
2139 /* initialize delay counters */
2140 DelayReached(&scroll_delay, 0);
2141 DelayReached(&label_delay, 0);
2143 if (leveldir_current->name)
2145 struct TextPosInfo *pos = &menu.main.text.level_info_1;
2146 char label_text[MAX_OUTPUT_LINESIZE + 1];
2148 int font_nr = pos->font;
2150 int font_nr = FONT_TEXT_1;
2153 int max_len_label_text = getMaxTextLength(pos, font_nr);
2155 int max_len_label_text = SXSIZE / getFontWidth(font_nr);
2163 if (pos->size != -1)
2164 max_len_label_text = pos->size;
2167 strncpy(label_text, leveldir_current->name, max_len_label_text);
2168 label_text[max_len_label_text] = '\0';
2171 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2173 lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
2174 lypos = SY + MICROLABEL1_YPOS;
2176 DrawText(lxpos, lypos, label_text, font_nr);
2180 game_status = last_game_status; /* restore current game status */
2185 /* scroll preview level, if needed */
2186 if (preview.anim_mode != ANIM_NONE &&
2187 (level_xsize > preview.xsize || level_ysize > preview.ysize) &&
2188 DelayReached(&scroll_delay, scroll_delay_value))
2190 switch (scroll_direction)
2195 from_x -= preview.step_offset;
2196 from_x = (from_x < 0 ? 0 : from_x);
2199 scroll_direction = MV_UP;
2203 if (from_x < level_xsize - preview.xsize)
2205 from_x += preview.step_offset;
2206 from_x = (from_x > level_xsize - preview.xsize ?
2207 level_xsize - preview.xsize : from_x);
2210 scroll_direction = MV_DOWN;
2216 from_y -= preview.step_offset;
2217 from_y = (from_y < 0 ? 0 : from_y);
2220 scroll_direction = MV_RIGHT;
2224 if (from_y < level_ysize - preview.ysize)
2226 from_y += preview.step_offset;
2227 from_y = (from_y > level_ysize - preview.ysize ?
2228 level_ysize - preview.ysize : from_y);
2231 scroll_direction = MV_LEFT;
2238 DrawPreviewLevelExt(from_x, from_y);
2241 /* !!! THIS ALL SUCKS -- SHOULD BE CLEANLY REWRITTEN !!! */
2242 /* redraw micro level label, if needed */
2243 if (!strEqual(level.name, NAMELESS_LEVEL_NAME) &&
2244 !strEqual(level.author, ANONYMOUS_NAME) &&
2245 !strEqual(level.author, leveldir_current->name) &&
2246 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
2248 int max_label_counter = 23;
2250 if (leveldir_current->imported_from != NULL &&
2251 strlen(leveldir_current->imported_from) > 0)
2252 max_label_counter += 14;
2253 if (leveldir_current->imported_by != NULL &&
2254 strlen(leveldir_current->imported_by) > 0)
2255 max_label_counter += 14;
2257 label_counter = (label_counter + 1) % max_label_counter;
2258 label_state = (label_counter >= 0 && label_counter <= 7 ?
2259 MICROLABEL_LEVEL_NAME :
2260 label_counter >= 9 && label_counter <= 12 ?
2261 MICROLABEL_LEVEL_AUTHOR_HEAD :
2262 label_counter >= 14 && label_counter <= 21 ?
2263 MICROLABEL_LEVEL_AUTHOR :
2264 label_counter >= 23 && label_counter <= 26 ?
2265 MICROLABEL_IMPORTED_FROM_HEAD :
2266 label_counter >= 28 && label_counter <= 35 ?
2267 MICROLABEL_IMPORTED_FROM :
2268 label_counter >= 37 && label_counter <= 40 ?
2269 MICROLABEL_IMPORTED_BY_HEAD :
2270 label_counter >= 42 && label_counter <= 49 ?
2271 MICROLABEL_IMPORTED_BY : MICROLABEL_EMPTY);
2273 if (leveldir_current->imported_from == NULL &&
2274 (label_state == MICROLABEL_IMPORTED_FROM_HEAD ||
2275 label_state == MICROLABEL_IMPORTED_FROM))
2276 label_state = (label_state == MICROLABEL_IMPORTED_FROM_HEAD ?
2277 MICROLABEL_IMPORTED_BY_HEAD : MICROLABEL_IMPORTED_BY);
2279 DrawPreviewLevelLabelExt(label_state);
2282 game_status = last_game_status; /* restore current game status */
2285 inline void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
2286 int graphic, int sync_frame, int mask_mode)
2288 int frame = getGraphicAnimationFrame(graphic, sync_frame);
2290 if (mask_mode == USE_MASKING)
2291 DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
2293 DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
2296 inline void DrawGraphicAnimation(int x, int y, int graphic)
2298 int lx = LEVELX(x), ly = LEVELY(y);
2300 if (!IN_SCR_FIELD(x, y))
2303 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
2304 graphic, GfxFrame[lx][ly], NO_MASKING);
2305 MarkTileDirty(x, y);
2308 void DrawLevelGraphicAnimation(int x, int y, int graphic)
2310 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
2313 void DrawLevelElementAnimation(int x, int y, int element)
2315 int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
2317 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
2320 inline void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
2322 int sx = SCREENX(x), sy = SCREENY(y);
2324 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
2327 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
2330 DrawGraphicAnimation(sx, sy, graphic);
2333 if (GFX_CRUMBLED(TILE_GFX_ELEMENT(x, y)))
2334 DrawLevelFieldCrumbledSand(x, y);
2336 if (GFX_CRUMBLED(Feld[x][y]))
2337 DrawLevelFieldCrumbledSand(x, y);
2341 void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
2343 int sx = SCREENX(x), sy = SCREENY(y);
2346 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
2349 graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
2351 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
2354 DrawGraphicAnimation(sx, sy, graphic);
2356 if (GFX_CRUMBLED(element))
2357 DrawLevelFieldCrumbledSand(x, y);
2360 static int getPlayerGraphic(struct PlayerInfo *player, int move_dir)
2362 if (player->use_murphy)
2364 /* this works only because currently only one player can be "murphy" ... */
2365 static int last_horizontal_dir = MV_LEFT;
2366 int graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir);
2368 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
2369 last_horizontal_dir = move_dir;
2371 if (graphic == IMG_SP_MURPHY) /* undefined => use special graphic */
2373 int direction = (player->is_snapping ? move_dir : last_horizontal_dir);
2375 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
2381 return el_act_dir2img(player->artwork_element, player->GfxAction,move_dir);
2384 static boolean equalGraphics(int graphic1, int graphic2)
2386 struct GraphicInfo *g1 = &graphic_info[graphic1];
2387 struct GraphicInfo *g2 = &graphic_info[graphic2];
2389 return (g1->bitmap == g2->bitmap &&
2390 g1->src_x == g2->src_x &&
2391 g1->src_y == g2->src_y &&
2392 g1->anim_frames == g2->anim_frames &&
2393 g1->anim_delay == g2->anim_delay &&
2394 g1->anim_mode == g2->anim_mode);
2397 void DrawAllPlayers()
2401 for (i = 0; i < MAX_PLAYERS; i++)
2402 if (stored_player[i].active)
2403 DrawPlayer(&stored_player[i]);
2406 void DrawPlayerField(int x, int y)
2408 if (!IS_PLAYER(x, y))
2411 DrawPlayer(PLAYERINFO(x, y));
2414 void DrawPlayer(struct PlayerInfo *player)
2416 int jx = player->jx;
2417 int jy = player->jy;
2418 int move_dir = player->MovDir;
2419 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? +1 : 0);
2420 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? +1 : 0);
2421 int last_jx = (player->is_moving ? jx - dx : jx);
2422 int last_jy = (player->is_moving ? jy - dy : jy);
2423 int next_jx = jx + dx;
2424 int next_jy = jy + dy;
2425 boolean player_is_moving = (player->MovPos ? TRUE : FALSE);
2426 boolean player_is_opaque = FALSE;
2427 int sx = SCREENX(jx), sy = SCREENY(jy);
2428 int sxx = 0, syy = 0;
2429 int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
2431 int action = ACTION_DEFAULT;
2432 int last_player_graphic = getPlayerGraphic(player, move_dir);
2433 int last_player_frame = player->Frame;
2436 /* GfxElement[][] is set to the element the player is digging or collecting;
2437 remove also for off-screen player if the player is not moving anymore */
2438 if (IN_LEV_FIELD(jx, jy) && !player_is_moving)
2439 GfxElement[jx][jy] = EL_UNDEFINED;
2441 if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
2445 if (!IN_LEV_FIELD(jx, jy))
2447 printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
2448 printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
2449 printf("DrawPlayerField(): This should never happen!\n");
2454 if (element == EL_EXPLOSION)
2457 action = (player->is_pushing ? ACTION_PUSHING :
2458 player->is_digging ? ACTION_DIGGING :
2459 player->is_collecting ? ACTION_COLLECTING :
2460 player->is_moving ? ACTION_MOVING :
2461 player->is_snapping ? ACTION_SNAPPING :
2462 player->is_dropping ? ACTION_DROPPING :
2463 player->is_waiting ? player->action_waiting : ACTION_DEFAULT);
2465 if (player->is_waiting)
2466 move_dir = player->dir_waiting;
2468 InitPlayerGfxAnimation(player, action, move_dir);
2470 /* ----------------------------------------------------------------------- */
2471 /* draw things in the field the player is leaving, if needed */
2472 /* ----------------------------------------------------------------------- */
2474 if (player->is_moving)
2476 if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
2478 DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
2480 if (last_element == EL_DYNAMITE_ACTIVE ||
2481 last_element == EL_EM_DYNAMITE_ACTIVE ||
2482 last_element == EL_SP_DISK_RED_ACTIVE)
2483 DrawDynamite(last_jx, last_jy);
2485 DrawLevelFieldThruMask(last_jx, last_jy);
2487 else if (last_element == EL_DYNAMITE_ACTIVE ||
2488 last_element == EL_EM_DYNAMITE_ACTIVE ||
2489 last_element == EL_SP_DISK_RED_ACTIVE)
2490 DrawDynamite(last_jx, last_jy);
2492 /* !!! this is not enough to prevent flickering of players which are
2493 moving next to each others without a free tile between them -- this
2494 can only be solved by drawing all players layer by layer (first the
2495 background, then the foreground etc.) !!! => TODO */
2496 else if (!IS_PLAYER(last_jx, last_jy))
2497 DrawLevelField(last_jx, last_jy);
2500 DrawLevelField(last_jx, last_jy);
2503 if (player->is_pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
2504 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
2507 if (!IN_SCR_FIELD(sx, sy))
2510 if (setup.direct_draw)
2511 SetDrawtoField(DRAW_BUFFERED);
2513 /* ----------------------------------------------------------------------- */
2514 /* draw things behind the player, if needed */
2515 /* ----------------------------------------------------------------------- */
2518 DrawLevelElement(jx, jy, Back[jx][jy]);
2519 else if (IS_ACTIVE_BOMB(element))
2520 DrawLevelElement(jx, jy, EL_EMPTY);
2523 if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
2525 int old_element = GfxElement[jx][jy];
2526 int old_graphic = el_act_dir2img(old_element, action, move_dir);
2527 int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
2529 if (GFX_CRUMBLED(old_element))
2530 DrawLevelFieldCrumbledSandDigging(jx, jy, move_dir, player->StepFrame);
2532 DrawGraphic(sx, sy, old_graphic, frame);
2534 if (graphic_info[old_graphic].anim_mode & ANIM_OPAQUE_PLAYER)
2535 player_is_opaque = TRUE;
2539 GfxElement[jx][jy] = EL_UNDEFINED;
2541 /* make sure that pushed elements are drawn with correct frame rate */
2543 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
2545 if (player->is_pushing && player->is_moving && !IS_ANIM_MODE_CE(graphic))
2546 GfxFrame[jx][jy] = player->StepFrame;
2548 if (player->is_pushing && player->is_moving)
2549 GfxFrame[jx][jy] = player->StepFrame;
2552 DrawLevelField(jx, jy);
2556 /* ----------------------------------------------------------------------- */
2557 /* draw player himself */
2558 /* ----------------------------------------------------------------------- */
2560 graphic = getPlayerGraphic(player, move_dir);
2562 /* in the case of changed player action or direction, prevent the current
2563 animation frame from being restarted for identical animations */
2564 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
2565 player->Frame = last_player_frame;
2567 frame = getGraphicAnimationFrame(graphic, player->Frame);
2571 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
2572 sxx = player->GfxPos;
2574 syy = player->GfxPos;
2577 if (!setup.soft_scrolling && ScreenMovPos)
2580 if (player_is_opaque)
2581 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
2583 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
2585 if (SHIELD_ON(player))
2587 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
2588 IMG_SHIELD_NORMAL_ACTIVE);
2589 int frame = getGraphicAnimationFrame(graphic, -1);
2591 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
2594 /* ----------------------------------------------------------------------- */
2595 /* draw things the player is pushing, if needed */
2596 /* ----------------------------------------------------------------------- */
2599 printf("::: %d, %d [%d, %d] [%d]\n",
2600 player->is_pushing, player_is_moving, player->GfxAction,
2601 player->is_moving, player_is_moving);
2605 if (player->is_pushing && player->is_moving)
2607 int px = SCREENX(jx), py = SCREENY(jy);
2608 int pxx = (TILEX - ABS(sxx)) * dx;
2609 int pyy = (TILEY - ABS(syy)) * dy;
2610 int gfx_frame = GfxFrame[jx][jy];
2616 if (!IS_MOVING(jx, jy)) /* push movement already finished */
2618 element = Feld[next_jx][next_jy];
2619 gfx_frame = GfxFrame[next_jx][next_jy];
2622 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
2625 sync_frame = (IS_ANIM_MODE_CE(graphic) ? gfx_frame : player->StepFrame);
2626 frame = getGraphicAnimationFrame(graphic, sync_frame);
2628 frame = getGraphicAnimationFrame(graphic, player->StepFrame);
2631 /* draw background element under pushed element (like the Sokoban field) */
2632 if (Back[next_jx][next_jy])
2633 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
2635 /* masked drawing is needed for EMC style (double) movement graphics */
2636 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
2640 /* ----------------------------------------------------------------------- */
2641 /* draw things in front of player (active dynamite or dynabombs) */
2642 /* ----------------------------------------------------------------------- */
2644 if (IS_ACTIVE_BOMB(element))
2646 graphic = el2img(element);
2647 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
2649 if (game.emulation == EMU_SUPAPLEX)
2650 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
2652 DrawGraphicThruMask(sx, sy, graphic, frame);
2655 if (player_is_moving && last_element == EL_EXPLOSION)
2657 int element = (GfxElement[last_jx][last_jy] != EL_UNDEFINED ?
2658 GfxElement[last_jx][last_jy] : EL_EMPTY);
2659 int graphic = el_act2img(element, ACTION_EXPLODING);
2660 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
2661 int phase = ExplodePhase[last_jx][last_jy] - 1;
2662 int frame = getGraphicAnimationFrame(graphic, phase - delay);
2665 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
2668 /* ----------------------------------------------------------------------- */
2669 /* draw elements the player is just walking/passing through/under */
2670 /* ----------------------------------------------------------------------- */
2672 if (player_is_moving)
2674 /* handle the field the player is leaving ... */
2675 if (IS_ACCESSIBLE_INSIDE(last_element))
2676 DrawLevelField(last_jx, last_jy);
2677 else if (IS_ACCESSIBLE_UNDER(last_element))
2678 DrawLevelFieldThruMask(last_jx, last_jy);
2681 /* do not redraw accessible elements if the player is just pushing them */
2682 if (!player_is_moving || !player->is_pushing)
2684 /* ... and the field the player is entering */
2685 if (IS_ACCESSIBLE_INSIDE(element))
2686 DrawLevelField(jx, jy);
2687 else if (IS_ACCESSIBLE_UNDER(element))
2688 DrawLevelFieldThruMask(jx, jy);
2691 if (setup.direct_draw)
2693 int dst_x = SX + SCREENX(MIN(jx, last_jx)) * TILEX;
2694 int dst_y = SY + SCREENY(MIN(jy, last_jy)) * TILEY;
2695 int x_size = TILEX * (1 + ABS(jx - last_jx));
2696 int y_size = TILEY * (1 + ABS(jy - last_jy));
2698 BlitBitmap(drawto_field, window,
2699 dst_x, dst_y, x_size, y_size, dst_x, dst_y);
2700 SetDrawtoField(DRAW_DIRECT);
2703 MarkTileDirty(sx, sy);
2706 /* ------------------------------------------------------------------------- */
2708 void WaitForEventToContinue()
2710 boolean still_wait = TRUE;
2712 /* simulate releasing mouse button over last gadget, if still pressed */
2714 HandleGadgets(-1, -1, 0);
2716 button_status = MB_RELEASED;
2732 case EVENT_BUTTONPRESS:
2733 case EVENT_KEYPRESS:
2737 case EVENT_KEYRELEASE:
2738 ClearPlayerAction();
2742 HandleOtherEvents(&event);
2746 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2753 /* don't eat all CPU time */
2758 #define MAX_REQUEST_LINES 13
2759 #define MAX_REQUEST_LINE_FONT1_LEN 7
2760 #define MAX_REQUEST_LINE_FONT2_LEN 10
2762 boolean Request(char *text, unsigned int req_state)
2764 int mx, my, ty, result = -1;
2765 unsigned int old_door_state;
2766 int last_game_status = game_status; /* save current game status */
2767 int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
2768 int font_nr = FONT_TEXT_2;
2769 int max_word_len = 0;
2772 for (text_ptr = text; *text_ptr; text_ptr++)
2774 max_word_len = (*text_ptr != ' ' ? max_word_len + 1 : 0);
2776 if (max_word_len > MAX_REQUEST_LINE_FONT1_LEN)
2778 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
2780 font_nr = FONT_TEXT_1;
2782 font_nr = FONT_LEVEL_NUMBER;
2789 if (game_status == GAME_MODE_PLAYING &&
2790 level.game_engine_type == GAME_ENGINE_TYPE_EM)
2791 BlitScreenToBitmap_EM(backbuffer);
2793 /* disable deactivated drawing when quick-loading level tape recording */
2794 if (tape.playing && tape.deactivate_display)
2795 TapeDeactivateDisplayOff(TRUE);
2797 SetMouseCursor(CURSOR_DEFAULT);
2799 #if defined(NETWORK_AVALIABLE)
2800 /* pause network game while waiting for request to answer */
2801 if (options.network &&
2802 game_status == GAME_MODE_PLAYING &&
2803 req_state & REQUEST_WAIT_FOR_INPUT)
2804 SendToServer_PausePlaying();
2807 old_door_state = GetDoorState();
2809 /* simulate releasing mouse button over last gadget, if still pressed */
2811 HandleGadgets(-1, -1, 0);
2815 if (old_door_state & DOOR_OPEN_1)
2817 CloseDoor(DOOR_CLOSE_1);
2819 /* save old door content */
2820 BlitBitmap(bitmap_db_door, bitmap_db_door,
2821 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
2822 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
2826 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
2829 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2831 /* clear door drawing field */
2832 DrawBackground(DX, DY, DXSIZE, DYSIZE);
2834 /* force DOOR font inside door area */
2835 game_status = GAME_MODE_PSEUDO_DOOR;
2837 /* write text for request */
2838 for (ty = 0; ty < MAX_REQUEST_LINES; ty++)
2840 char text_line[max_request_line_len + 1];
2846 for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
2849 if (!tc || tc == ' ')
2860 strncpy(text_line, text, tl);
2863 DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
2864 DY + 8 + ty * (getFontHeight(font_nr) + 2),
2865 text_line, font_nr);
2867 text += tl + (tc == ' ' ? 1 : 0);
2870 game_status = last_game_status; /* restore current game status */
2872 if (req_state & REQ_ASK)
2874 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
2875 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
2877 else if (req_state & REQ_CONFIRM)
2879 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
2881 else if (req_state & REQ_PLAYER)
2883 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
2884 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
2885 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
2886 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
2889 /* copy request gadgets to door backbuffer */
2890 BlitBitmap(drawto, bitmap_db_door,
2891 DX, DY, DXSIZE, DYSIZE,
2892 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2894 OpenDoor(DOOR_OPEN_1);
2896 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
2898 if (game_status == GAME_MODE_PLAYING)
2900 SetPanelBackground();
2901 SetDrawBackgroundMask(REDRAW_DOOR_1);
2905 SetDrawBackgroundMask(REDRAW_FIELD);
2911 if (game_status != GAME_MODE_MAIN)
2914 button_status = MB_RELEASED;
2916 request_gadget_id = -1;
2918 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2930 case EVENT_BUTTONPRESS:
2931 case EVENT_BUTTONRELEASE:
2932 case EVENT_MOTIONNOTIFY:
2934 if (event.type == EVENT_MOTIONNOTIFY)
2936 if (!PointerInWindow(window))
2937 continue; /* window and pointer are on different screens */
2942 motion_status = TRUE;
2943 mx = ((MotionEvent *) &event)->x;
2944 my = ((MotionEvent *) &event)->y;
2948 motion_status = FALSE;
2949 mx = ((ButtonEvent *) &event)->x;
2950 my = ((ButtonEvent *) &event)->y;
2951 if (event.type == EVENT_BUTTONPRESS)
2952 button_status = ((ButtonEvent *) &event)->button;
2954 button_status = MB_RELEASED;
2957 /* this sets 'request_gadget_id' */
2958 HandleGadgets(mx, my, button_status);
2960 switch (request_gadget_id)
2962 case TOOL_CTRL_ID_YES:
2965 case TOOL_CTRL_ID_NO:
2968 case TOOL_CTRL_ID_CONFIRM:
2969 result = TRUE | FALSE;
2972 case TOOL_CTRL_ID_PLAYER_1:
2975 case TOOL_CTRL_ID_PLAYER_2:
2978 case TOOL_CTRL_ID_PLAYER_3:
2981 case TOOL_CTRL_ID_PLAYER_4:
2992 case EVENT_KEYPRESS:
2993 switch (GetEventKey((KeyEvent *)&event, TRUE))
2996 if (req_state & REQ_CONFIRM)
3012 if (req_state & REQ_PLAYER)
3016 case EVENT_KEYRELEASE:
3017 ClearPlayerAction();
3021 HandleOtherEvents(&event);
3025 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
3027 int joy = AnyJoystick();
3029 if (joy & JOY_BUTTON_1)
3031 else if (joy & JOY_BUTTON_2)
3037 if (game_status == GAME_MODE_PLAYING && local_player->LevelSolved_GameEnd)
3039 HandleGameActions();
3045 if (!PendingEvent()) /* delay only if no pending events */
3056 if (!PendingEvent()) /* delay only if no pending events */
3059 /* don't eat all CPU time */
3066 if (game_status != GAME_MODE_MAIN)
3071 if (!(req_state & REQ_STAY_OPEN))
3073 CloseDoor(DOOR_CLOSE_1);
3075 if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
3076 (req_state & REQ_REOPEN))
3077 OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
3082 if (game_status == GAME_MODE_PLAYING)
3084 SetPanelBackground();
3085 SetDrawBackgroundMask(REDRAW_DOOR_1);
3089 SetDrawBackgroundMask(REDRAW_FIELD);
3092 #if defined(NETWORK_AVALIABLE)
3093 /* continue network game after request */
3094 if (options.network &&
3095 game_status == GAME_MODE_PLAYING &&
3096 req_state & REQUEST_WAIT_FOR_INPUT)
3097 SendToServer_ContinuePlaying();
3100 /* restore deactivated drawing when quick-loading level tape recording */
3101 if (tape.playing && tape.deactivate_display)
3102 TapeDeactivateDisplayOn();
3107 unsigned int OpenDoor(unsigned int door_state)
3109 if (door_state & DOOR_COPY_BACK)
3111 if (door_state & DOOR_OPEN_1)
3112 BlitBitmap(bitmap_db_door, bitmap_db_door,
3113 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
3114 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
3116 if (door_state & DOOR_OPEN_2)
3117 BlitBitmap(bitmap_db_door, bitmap_db_door,
3118 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY2, VXSIZE, VYSIZE,
3119 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
3121 door_state &= ~DOOR_COPY_BACK;
3124 return MoveDoor(door_state);
3127 unsigned int CloseDoor(unsigned int door_state)
3129 unsigned int old_door_state = GetDoorState();
3131 if (!(door_state & DOOR_NO_COPY_BACK))
3133 if (old_door_state & DOOR_OPEN_1)
3134 BlitBitmap(backbuffer, bitmap_db_door,
3135 DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
3137 if (old_door_state & DOOR_OPEN_2)
3138 BlitBitmap(backbuffer, bitmap_db_door,
3139 VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
3141 door_state &= ~DOOR_NO_COPY_BACK;
3144 return MoveDoor(door_state);
3147 unsigned int GetDoorState()
3149 return MoveDoor(DOOR_GET_STATE);
3152 unsigned int SetDoorState(unsigned int door_state)
3154 return MoveDoor(door_state | DOOR_SET_STATE);
3157 unsigned int MoveDoor(unsigned int door_state)
3159 static int door1 = DOOR_OPEN_1;
3160 static int door2 = DOOR_CLOSE_2;
3161 unsigned long door_delay = 0;
3162 unsigned long door_delay_value;
3165 if (door_1.width < 0 || door_1.width > DXSIZE)
3166 door_1.width = DXSIZE;
3167 if (door_1.height < 0 || door_1.height > DYSIZE)
3168 door_1.height = DYSIZE;
3169 if (door_2.width < 0 || door_2.width > VXSIZE)
3170 door_2.width = VXSIZE;
3171 if (door_2.height < 0 || door_2.height > VYSIZE)
3172 door_2.height = VYSIZE;
3174 if (door_state == DOOR_GET_STATE)
3175 return (door1 | door2);
3177 if (door_state & DOOR_SET_STATE)
3179 if (door_state & DOOR_ACTION_1)
3180 door1 = door_state & DOOR_ACTION_1;
3181 if (door_state & DOOR_ACTION_2)
3182 door2 = door_state & DOOR_ACTION_2;
3184 return (door1 | door2);
3187 if (!(door_state & DOOR_FORCE_REDRAW))
3189 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
3190 door_state &= ~DOOR_OPEN_1;
3191 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
3192 door_state &= ~DOOR_CLOSE_1;
3193 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
3194 door_state &= ~DOOR_OPEN_2;
3195 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
3196 door_state &= ~DOOR_CLOSE_2;
3199 door_delay_value = (door_state & DOOR_ACTION_1 ? door_1.step_delay :
3202 if (setup.quick_doors)
3204 stepsize = 20; /* must be chosen to always draw last frame */
3205 door_delay_value = 0;
3208 if (global.autoplay_leveldir)
3210 door_state |= DOOR_NO_DELAY;
3211 door_state &= ~DOOR_CLOSE_ALL;
3214 if (door_state & DOOR_ACTION)
3216 boolean handle_door_1 = (door_state & DOOR_ACTION_1);
3217 boolean handle_door_2 = (door_state & DOOR_ACTION_2);
3218 boolean door_1_done = (!handle_door_1);
3219 boolean door_2_done = (!handle_door_2);
3220 boolean door_1_vertical = (door_1.anim_mode & ANIM_VERTICAL);
3221 boolean door_2_vertical = (door_2.anim_mode & ANIM_VERTICAL);
3222 int door_size_1 = (door_1_vertical ? door_1.height : door_1.width);
3223 int door_size_2 = (door_2_vertical ? door_2.height : door_2.width);
3224 int max_door_size_1 = (door_1_vertical ? DYSIZE : DXSIZE);
3225 int max_door_size_2 = (door_2_vertical ? VYSIZE : VXSIZE);
3226 int door_size = (handle_door_1 ? door_size_1 : door_size_2);
3227 int max_door_size = (handle_door_1 ? max_door_size_1 : max_door_size_2);
3228 int door_skip = max_door_size - door_size;
3229 int end = door_size;
3230 int start = ((door_state & DOOR_NO_DELAY) ? end : 0);
3233 if (!(door_state & DOOR_NO_DELAY) && !setup.quick_doors)
3235 /* opening door sound has priority over simultaneously closing door */
3236 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
3237 PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
3238 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
3239 PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
3242 for (k = start; k <= end && !(door_1_done && door_2_done); k += stepsize)
3245 Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
3246 GC gc = bitmap->stored_clip_gc;
3248 if (door_state & DOOR_ACTION_1)
3250 int a = MIN(x * door_1.step_offset, end);
3251 int p = (door_state & DOOR_OPEN_1 ? end - a : a);
3252 int i = p + door_skip;
3254 if (door_1.anim_mode & ANIM_STATIC_PANEL)
3256 BlitBitmap(bitmap_db_door, drawto,
3257 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1,
3258 DXSIZE, DYSIZE, DX, DY);
3262 BlitBitmap(bitmap_db_door, drawto,
3263 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + p / 2,
3264 DXSIZE, DYSIZE - p / 2, DX, DY);
3266 ClearRectangle(drawto, DX, DY + DYSIZE - p / 2, DXSIZE, p / 2);
3269 if (door_1.anim_mode & ANIM_HORIZONTAL && x <= DXSIZE)
3271 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
3272 int dst1_x = DX + DXSIZE - i, dst1_y = DY;
3273 int src2_x = DXSIZE - i, src2_y = DOOR_GFX_PAGEY1;
3274 int dst2_x = DX, dst2_y = DY;
3275 int width = i, height = DYSIZE;
3277 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3278 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3281 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3282 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3285 else if (door_1.anim_mode & ANIM_VERTICAL && x <= DYSIZE)
3287 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
3288 int dst1_x = DX, dst1_y = DY + DYSIZE - i;
3289 int src2_x = 0, src2_y = DOOR_GFX_PAGEY1 + DYSIZE - i;
3290 int dst2_x = DX, dst2_y = DY;
3291 int width = DXSIZE, height = i;
3293 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3294 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3297 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3298 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3301 else if (x <= DXSIZE) /* ANIM_DEFAULT */
3303 int j = (door_1.anim_mode == ANIM_DEFAULT ? (DXSIZE - i) / 3 : 0);
3305 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
3306 BlitBitmapMasked(bitmap, drawto,
3307 DXSIZE, DOOR_GFX_PAGEY1, i, 77,
3308 DX + DXSIZE - i, DY + j);
3309 BlitBitmapMasked(bitmap, drawto,
3310 DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
3311 DX + DXSIZE - i, DY + 140 + j);
3312 SetClipOrigin(bitmap, gc, DX - DXSIZE + i,
3313 DY - (DOOR_GFX_PAGEY1 + j));
3314 BlitBitmapMasked(bitmap, drawto,
3315 DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
3317 BlitBitmapMasked(bitmap, drawto,
3318 DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
3321 BlitBitmapMasked(bitmap, drawto,
3322 DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
3324 BlitBitmapMasked(bitmap, drawto,
3325 DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
3327 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
3328 BlitBitmapMasked(bitmap, drawto,
3329 DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
3330 DX + DXSIZE - i, DY + 77 + j);
3331 BlitBitmapMasked(bitmap, drawto,
3332 DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
3333 DX + DXSIZE - i, DY + 203 + j);
3336 redraw_mask |= REDRAW_DOOR_1;
3337 door_1_done = (a == end);
3340 if (door_state & DOOR_ACTION_2)
3342 int a = MIN(x * door_2.step_offset, door_size);
3343 int p = (door_state & DOOR_OPEN_2 ? door_size - a : a);
3344 int i = p + door_skip;
3346 if (door_2.anim_mode & ANIM_STATIC_PANEL)
3348 BlitBitmap(bitmap_db_door, drawto,
3349 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2,
3350 VXSIZE, VYSIZE, VX, VY);
3352 else if (x <= VYSIZE)
3354 BlitBitmap(bitmap_db_door, drawto,
3355 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + p / 2,
3356 VXSIZE, VYSIZE - p / 2, VX, VY);
3358 ClearRectangle(drawto, VX, VY + VYSIZE - p / 2, VXSIZE, p / 2);
3361 if (door_2.anim_mode & ANIM_HORIZONTAL && x <= VXSIZE)
3363 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
3364 int dst1_x = VX + VXSIZE - i, dst1_y = VY;
3365 int src2_x = VXSIZE - i, src2_y = DOOR_GFX_PAGEY2;
3366 int dst2_x = VX, dst2_y = VY;
3367 int width = i, height = VYSIZE;
3369 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3370 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3373 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3374 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3377 else if (door_2.anim_mode & ANIM_VERTICAL && x <= VYSIZE)
3379 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
3380 int dst1_x = VX, dst1_y = VY + VYSIZE - i;
3381 int src2_x = 0, src2_y = DOOR_GFX_PAGEY2 + VYSIZE - i;
3382 int dst2_x = VX, dst2_y = VY;
3383 int width = VXSIZE, height = i;
3385 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3386 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3389 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3390 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3393 else if (x <= VXSIZE) /* ANIM_DEFAULT */
3395 int j = (door_2.anim_mode == ANIM_DEFAULT ? (VXSIZE - i) / 3 : 0);
3397 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
3398 BlitBitmapMasked(bitmap, drawto,
3399 VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
3400 VX + VXSIZE - i, VY + j);
3401 SetClipOrigin(bitmap, gc,
3402 VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
3403 BlitBitmapMasked(bitmap, drawto,
3404 VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
3407 BlitBitmapMasked(bitmap, drawto,
3408 VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
3409 i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
3410 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
3411 BlitBitmapMasked(bitmap, drawto,
3412 VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
3414 VX + VXSIZE - i, VY + VYSIZE / 2 + j);
3417 redraw_mask |= REDRAW_DOOR_2;
3418 door_2_done = (a == VXSIZE);
3421 if (!(door_state & DOOR_NO_DELAY))
3425 if (game_status == GAME_MODE_MAIN)
3428 WaitUntilDelayReached(&door_delay, door_delay_value);
3433 if (door_state & DOOR_ACTION_1)
3434 door1 = door_state & DOOR_ACTION_1;
3435 if (door_state & DOOR_ACTION_2)
3436 door2 = door_state & DOOR_ACTION_2;
3438 return (door1 | door2);
3441 void DrawSpecialEditorDoor()
3443 /* draw bigger toolbox window */
3444 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
3445 DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
3447 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
3448 EX - 6, VY - 4, EXSIZE + 12, EYSIZE - VYSIZE + 4,
3451 redraw_mask |= REDRAW_ALL;
3454 void UndrawSpecialEditorDoor()
3456 /* draw normal tape recorder window */
3457 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
3458 EX - 6, EY - 12, EXSIZE + 12, EYSIZE - VYSIZE + 12,
3461 redraw_mask |= REDRAW_ALL;
3465 /* ---------- new tool button stuff ---------------------------------------- */
3467 /* graphic position values for tool buttons */
3468 #define TOOL_BUTTON_YES_XPOS 2
3469 #define TOOL_BUTTON_YES_YPOS 250
3470 #define TOOL_BUTTON_YES_GFX_YPOS 0
3471 #define TOOL_BUTTON_YES_XSIZE 46
3472 #define TOOL_BUTTON_YES_YSIZE 28
3473 #define TOOL_BUTTON_NO_XPOS 52
3474 #define TOOL_BUTTON_NO_YPOS TOOL_BUTTON_YES_YPOS
3475 #define TOOL_BUTTON_NO_GFX_YPOS TOOL_BUTTON_YES_GFX_YPOS
3476 #define TOOL_BUTTON_NO_XSIZE TOOL_BUTTON_YES_XSIZE
3477 #define TOOL_BUTTON_NO_YSIZE TOOL_BUTTON_YES_YSIZE
3478 #define TOOL_BUTTON_CONFIRM_XPOS TOOL_BUTTON_YES_XPOS
3479 #define TOOL_BUTTON_CONFIRM_YPOS TOOL_BUTTON_YES_YPOS
3480 #define TOOL_BUTTON_CONFIRM_GFX_YPOS 30
3481 #define TOOL_BUTTON_CONFIRM_XSIZE 96
3482 #define TOOL_BUTTON_CONFIRM_YSIZE TOOL_BUTTON_YES_YSIZE
3483 #define TOOL_BUTTON_PLAYER_XSIZE 30
3484 #define TOOL_BUTTON_PLAYER_YSIZE 30
3485 #define TOOL_BUTTON_PLAYER_GFX_XPOS 5
3486 #define TOOL_BUTTON_PLAYER_GFX_YPOS 185
3487 #define TOOL_BUTTON_PLAYER_XPOS (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
3488 #define TOOL_BUTTON_PLAYER_YPOS (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
3489 #define TOOL_BUTTON_PLAYER1_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3490 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
3491 #define TOOL_BUTTON_PLAYER2_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3492 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
3493 #define TOOL_BUTTON_PLAYER3_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3494 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
3495 #define TOOL_BUTTON_PLAYER4_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3496 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
3497 #define TOOL_BUTTON_PLAYER1_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3498 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
3499 #define TOOL_BUTTON_PLAYER2_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3500 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
3501 #define TOOL_BUTTON_PLAYER3_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3502 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
3503 #define TOOL_BUTTON_PLAYER4_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3504 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
3513 } toolbutton_info[NUM_TOOL_BUTTONS] =
3516 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_GFX_YPOS,
3517 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_YPOS,
3518 TOOL_BUTTON_YES_XSIZE, TOOL_BUTTON_YES_YSIZE,
3523 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_GFX_YPOS,
3524 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_YPOS,
3525 TOOL_BUTTON_NO_XSIZE, TOOL_BUTTON_NO_YSIZE,
3530 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_GFX_YPOS,
3531 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_YPOS,
3532 TOOL_BUTTON_CONFIRM_XSIZE, TOOL_BUTTON_CONFIRM_YSIZE,
3533 TOOL_CTRL_ID_CONFIRM,
3537 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3538 TOOL_BUTTON_PLAYER1_XPOS, TOOL_BUTTON_PLAYER1_YPOS,
3539 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3540 TOOL_CTRL_ID_PLAYER_1,
3544 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3545 TOOL_BUTTON_PLAYER2_XPOS, TOOL_BUTTON_PLAYER2_YPOS,
3546 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3547 TOOL_CTRL_ID_PLAYER_2,
3551 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3552 TOOL_BUTTON_PLAYER3_XPOS, TOOL_BUTTON_PLAYER3_YPOS,
3553 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3554 TOOL_CTRL_ID_PLAYER_3,
3558 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3559 TOOL_BUTTON_PLAYER4_XPOS, TOOL_BUTTON_PLAYER4_YPOS,
3560 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3561 TOOL_CTRL_ID_PLAYER_4,
3566 void CreateToolButtons()
3570 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3572 Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
3573 Bitmap *deco_bitmap = None;
3574 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
3575 struct GadgetInfo *gi;
3576 unsigned long event_mask;
3577 int gd_xoffset, gd_yoffset;
3578 int gd_x1, gd_x2, gd_y;
3581 event_mask = GD_EVENT_RELEASED;
3583 gd_xoffset = toolbutton_info[i].xpos;
3584 gd_yoffset = toolbutton_info[i].ypos;
3585 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
3586 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
3587 gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
3589 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
3591 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
3593 getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr),
3594 &deco_bitmap, &deco_x, &deco_y);
3595 deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
3596 deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
3599 gi = CreateGadget(GDI_CUSTOM_ID, id,
3600 GDI_INFO_TEXT, toolbutton_info[i].infotext,
3601 GDI_X, DX + toolbutton_info[i].x,
3602 GDI_Y, DY + toolbutton_info[i].y,
3603 GDI_WIDTH, toolbutton_info[i].width,
3604 GDI_HEIGHT, toolbutton_info[i].height,
3605 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
3606 GDI_STATE, GD_BUTTON_UNPRESSED,
3607 GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
3608 GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
3609 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
3610 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
3611 GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
3612 GDI_DECORATION_SHIFTING, 1, 1,
3613 GDI_DIRECT_DRAW, FALSE,
3614 GDI_EVENT_MASK, event_mask,
3615 GDI_CALLBACK_ACTION, HandleToolButtons,
3619 Error(ERR_EXIT, "cannot create gadget");
3621 tool_gadget[id] = gi;
3625 void FreeToolButtons()
3629 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3630 FreeGadget(tool_gadget[i]);
3633 static void UnmapToolButtons()
3637 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3638 UnmapGadget(tool_gadget[i]);
3641 static void HandleToolButtons(struct GadgetInfo *gi)
3643 request_gadget_id = gi->custom_id;
3646 static struct Mapping_EM_to_RND_object
3649 boolean is_rnd_to_em_mapping; /* unique mapping EM <-> RND */
3650 boolean is_backside; /* backside of moving element */
3656 em_object_mapping_list[] =
3659 Xblank, TRUE, FALSE,
3663 Yacid_splash_eB, FALSE, FALSE,
3664 EL_ACID_SPLASH_RIGHT, -1, -1
3667 Yacid_splash_wB, FALSE, FALSE,
3668 EL_ACID_SPLASH_LEFT, -1, -1
3671 #ifdef EM_ENGINE_BAD_ROLL
3673 Xstone_force_e, FALSE, FALSE,
3674 EL_ROCK, -1, MV_BIT_RIGHT
3677 Xstone_force_w, FALSE, FALSE,
3678 EL_ROCK, -1, MV_BIT_LEFT
3681 Xnut_force_e, FALSE, FALSE,
3682 EL_NUT, -1, MV_BIT_RIGHT
3685 Xnut_force_w, FALSE, FALSE,
3686 EL_NUT, -1, MV_BIT_LEFT
3689 Xspring_force_e, FALSE, FALSE,
3690 EL_SPRING, -1, MV_BIT_RIGHT
3693 Xspring_force_w, FALSE, FALSE,
3694 EL_SPRING, -1, MV_BIT_LEFT
3697 Xemerald_force_e, FALSE, FALSE,
3698 EL_EMERALD, -1, MV_BIT_RIGHT
3701 Xemerald_force_w, FALSE, FALSE,
3702 EL_EMERALD, -1, MV_BIT_LEFT
3705 Xdiamond_force_e, FALSE, FALSE,
3706 EL_DIAMOND, -1, MV_BIT_RIGHT
3709 Xdiamond_force_w, FALSE, FALSE,
3710 EL_DIAMOND, -1, MV_BIT_LEFT
3713 Xbomb_force_e, FALSE, FALSE,
3714 EL_BOMB, -1, MV_BIT_RIGHT
3717 Xbomb_force_w, FALSE, FALSE,
3718 EL_BOMB, -1, MV_BIT_LEFT
3720 #endif /* EM_ENGINE_BAD_ROLL */
3723 Xstone, TRUE, FALSE,
3727 Xstone_pause, FALSE, FALSE,
3731 Xstone_fall, FALSE, FALSE,
3735 Ystone_s, FALSE, FALSE,
3736 EL_ROCK, ACTION_FALLING, -1
3739 Ystone_sB, FALSE, TRUE,
3740 EL_ROCK, ACTION_FALLING, -1
3743 Ystone_e, FALSE, FALSE,
3744 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
3747 Ystone_eB, FALSE, TRUE,
3748 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
3751 Ystone_w, FALSE, FALSE,
3752 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
3755 Ystone_wB, FALSE, TRUE,
3756 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
3763 Xnut_pause, FALSE, FALSE,
3767 Xnut_fall, FALSE, FALSE,
3771 Ynut_s, FALSE, FALSE,
3772 EL_NUT, ACTION_FALLING, -1
3775 Ynut_sB, FALSE, TRUE,
3776 EL_NUT, ACTION_FALLING, -1
3779 Ynut_e, FALSE, FALSE,
3780 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
3783 Ynut_eB, FALSE, TRUE,
3784 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
3787 Ynut_w, FALSE, FALSE,
3788 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
3791 Ynut_wB, FALSE, TRUE,
3792 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
3795 Xbug_n, TRUE, FALSE,
3799 Xbug_e, TRUE, FALSE,
3800 EL_BUG_RIGHT, -1, -1
3803 Xbug_s, TRUE, FALSE,
3807 Xbug_w, TRUE, FALSE,
3811 Xbug_gon, FALSE, FALSE,
3815 Xbug_goe, FALSE, FALSE,
3816 EL_BUG_RIGHT, -1, -1
3819 Xbug_gos, FALSE, FALSE,
3823 Xbug_gow, FALSE, FALSE,
3827 Ybug_n, FALSE, FALSE,
3828 EL_BUG, ACTION_MOVING, MV_BIT_UP
3831 Ybug_nB, FALSE, TRUE,
3832 EL_BUG, ACTION_MOVING, MV_BIT_UP
3835 Ybug_e, FALSE, FALSE,
3836 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
3839 Ybug_eB, FALSE, TRUE,
3840 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
3843 Ybug_s, FALSE, FALSE,
3844 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
3847 Ybug_sB, FALSE, TRUE,
3848 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
3851 Ybug_w, FALSE, FALSE,
3852 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
3855 Ybug_wB, FALSE, TRUE,
3856 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
3859 Ybug_w_n, FALSE, FALSE,
3860 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
3863 Ybug_n_e, FALSE, FALSE,
3864 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
3867 Ybug_e_s, FALSE, FALSE,
3868 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
3871 Ybug_s_w, FALSE, FALSE,
3872 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
3875 Ybug_e_n, FALSE, FALSE,
3876 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
3879 Ybug_s_e, FALSE, FALSE,
3880 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
3883 Ybug_w_s, FALSE, FALSE,
3884 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
3887 Ybug_n_w, FALSE, FALSE,
3888 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
3891 Ybug_stone, FALSE, FALSE,
3892 EL_BUG, ACTION_SMASHED_BY_ROCK, -1
3895 Ybug_spring, FALSE, FALSE,
3896 EL_BUG, ACTION_SMASHED_BY_SPRING, -1
3899 Xtank_n, TRUE, FALSE,
3900 EL_SPACESHIP_UP, -1, -1
3903 Xtank_e, TRUE, FALSE,
3904 EL_SPACESHIP_RIGHT, -1, -1
3907 Xtank_s, TRUE, FALSE,
3908 EL_SPACESHIP_DOWN, -1, -1
3911 Xtank_w, TRUE, FALSE,
3912 EL_SPACESHIP_LEFT, -1, -1
3915 Xtank_gon, FALSE, FALSE,
3916 EL_SPACESHIP_UP, -1, -1
3919 Xtank_goe, FALSE, FALSE,
3920 EL_SPACESHIP_RIGHT, -1, -1
3923 Xtank_gos, FALSE, FALSE,
3924 EL_SPACESHIP_DOWN, -1, -1
3927 Xtank_gow, FALSE, FALSE,
3928 EL_SPACESHIP_LEFT, -1, -1
3931 Ytank_n, FALSE, FALSE,
3932 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
3935 Ytank_nB, FALSE, TRUE,
3936 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
3939 Ytank_e, FALSE, FALSE,
3940 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
3943 Ytank_eB, FALSE, TRUE,
3944 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
3947 Ytank_s, FALSE, FALSE,
3948 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
3951 Ytank_sB, FALSE, TRUE,
3952 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
3955 Ytank_w, FALSE, FALSE,
3956 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
3959 Ytank_wB, FALSE, TRUE,
3960 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
3963 Ytank_w_n, FALSE, FALSE,
3964 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
3967 Ytank_n_e, FALSE, FALSE,
3968 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
3971 Ytank_e_s, FALSE, FALSE,
3972 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
3975 Ytank_s_w, FALSE, FALSE,
3976 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
3979 Ytank_e_n, FALSE, FALSE,
3980 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
3983 Ytank_s_e, FALSE, FALSE,
3984 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
3987 Ytank_w_s, FALSE, FALSE,
3988 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
3991 Ytank_n_w, FALSE, FALSE,
3992 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
3995 Ytank_stone, FALSE, FALSE,
3996 EL_SPACESHIP, ACTION_SMASHED_BY_ROCK, -1
3999 Ytank_spring, FALSE, FALSE,
4000 EL_SPACESHIP, ACTION_SMASHED_BY_SPRING, -1
4003 Xandroid, TRUE, FALSE,
4004 EL_EMC_ANDROID, ACTION_ACTIVE, -1
4007 Xandroid_1_n, FALSE, FALSE,
4008 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
4011 Xandroid_2_n, FALSE, FALSE,
4012 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
4015 Xandroid_1_e, FALSE, FALSE,
4016 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
4019 Xandroid_2_e, FALSE, FALSE,
4020 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
4023 Xandroid_1_w, FALSE, FALSE,
4024 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
4027 Xandroid_2_w, FALSE, FALSE,
4028 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
4031 Xandroid_1_s, FALSE, FALSE,
4032 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
4035 Xandroid_2_s, FALSE, FALSE,
4036 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
4039 Yandroid_n, FALSE, FALSE,
4040 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
4043 Yandroid_nB, FALSE, TRUE,
4044 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
4047 Yandroid_ne, FALSE, FALSE,
4048 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPRIGHT
4051 Yandroid_neB, FALSE, TRUE,
4052 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPRIGHT
4055 Yandroid_e, FALSE, FALSE,
4056 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
4059 Yandroid_eB, FALSE, TRUE,
4060 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
4063 Yandroid_se, FALSE, FALSE,
4064 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNRIGHT
4067 Yandroid_seB, FALSE, TRUE,
4068 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNRIGHT
4071 Yandroid_s, FALSE, FALSE,
4072 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
4075 Yandroid_sB, FALSE, TRUE,
4076 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
4079 Yandroid_sw, FALSE, FALSE,
4080 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNLEFT
4083 Yandroid_swB, FALSE, TRUE,
4084 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNLEFT
4087 Yandroid_w, FALSE, FALSE,
4088 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
4091 Yandroid_wB, FALSE, TRUE,
4092 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
4095 Yandroid_nw, FALSE, FALSE,
4096 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPLEFT
4099 Yandroid_nwB, FALSE, TRUE,
4100 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPLEFT
4103 Xspring, TRUE, FALSE,
4107 Xspring_pause, FALSE, FALSE,
4111 Xspring_e, FALSE, FALSE,
4115 Xspring_w, FALSE, FALSE,
4119 Xspring_fall, FALSE, FALSE,
4123 Yspring_s, FALSE, FALSE,
4124 EL_SPRING, ACTION_FALLING, -1
4127 Yspring_sB, FALSE, TRUE,
4128 EL_SPRING, ACTION_FALLING, -1
4131 Yspring_e, FALSE, FALSE,
4132 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
4135 Yspring_eB, FALSE, TRUE,
4136 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
4139 Yspring_w, FALSE, FALSE,
4140 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
4143 Yspring_wB, FALSE, TRUE,
4144 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
4147 Yspring_kill_e, FALSE, FALSE,
4148 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
4151 Yspring_kill_eB, FALSE, TRUE,
4152 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
4155 Yspring_kill_w, FALSE, FALSE,
4156 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
4159 Yspring_kill_wB, FALSE, TRUE,
4160 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
4163 Xeater_n, TRUE, FALSE,
4164 EL_YAMYAM_UP, -1, -1
4167 Xeater_e, TRUE, FALSE,
4168 EL_YAMYAM_RIGHT, -1, -1
4171 Xeater_w, TRUE, FALSE,
4172 EL_YAMYAM_LEFT, -1, -1
4175 Xeater_s, TRUE, FALSE,
4176 EL_YAMYAM_DOWN, -1, -1
4179 Yeater_n, FALSE, FALSE,
4180 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
4183 Yeater_nB, FALSE, TRUE,
4184 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
4187 Yeater_e, FALSE, FALSE,
4188 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
4191 Yeater_eB, FALSE, TRUE,
4192 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
4195 Yeater_s, FALSE, FALSE,
4196 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
4199 Yeater_sB, FALSE, TRUE,
4200 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
4203 Yeater_w, FALSE, FALSE,
4204 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
4207 Yeater_wB, FALSE, TRUE,
4208 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
4211 Yeater_stone, FALSE, FALSE,
4212 EL_YAMYAM, ACTION_SMASHED_BY_ROCK, -1
4215 Yeater_spring, FALSE, FALSE,
4216 EL_YAMYAM, ACTION_SMASHED_BY_SPRING, -1
4219 Xalien, TRUE, FALSE,
4223 Xalien_pause, FALSE, FALSE,
4227 Yalien_n, FALSE, FALSE,
4228 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
4231 Yalien_nB, FALSE, TRUE,
4232 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
4235 Yalien_e, FALSE, FALSE,
4236 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
4239 Yalien_eB, FALSE, TRUE,
4240 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
4243 Yalien_s, FALSE, FALSE,
4244 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
4247 Yalien_sB, FALSE, TRUE,
4248 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
4251 Yalien_w, FALSE, FALSE,
4252 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
4255 Yalien_wB, FALSE, TRUE,
4256 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
4259 Yalien_stone, FALSE, FALSE,
4260 EL_ROBOT, ACTION_SMASHED_BY_ROCK, -1
4263 Yalien_spring, FALSE, FALSE,
4264 EL_ROBOT, ACTION_SMASHED_BY_SPRING, -1
4267 Xemerald, TRUE, FALSE,
4271 Xemerald_pause, FALSE, FALSE,
4275 Xemerald_fall, FALSE, FALSE,
4279 Xemerald_shine, FALSE, FALSE,
4280 EL_EMERALD, ACTION_TWINKLING, -1
4283 Yemerald_s, FALSE, FALSE,
4284 EL_EMERALD, ACTION_FALLING, -1
4287 Yemerald_sB, FALSE, TRUE,
4288 EL_EMERALD, ACTION_FALLING, -1
4291 Yemerald_e, FALSE, FALSE,
4292 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
4295 Yemerald_eB, FALSE, TRUE,
4296 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
4299 Yemerald_w, FALSE, FALSE,
4300 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
4303 Yemerald_wB, FALSE, TRUE,
4304 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
4307 Yemerald_eat, FALSE, FALSE,
4308 EL_EMERALD, ACTION_COLLECTING, -1
4311 Yemerald_stone, FALSE, FALSE,
4312 EL_NUT, ACTION_BREAKING, -1
4315 Xdiamond, TRUE, FALSE,
4319 Xdiamond_pause, FALSE, FALSE,
4323 Xdiamond_fall, FALSE, FALSE,
4327 Xdiamond_shine, FALSE, FALSE,
4328 EL_DIAMOND, ACTION_TWINKLING, -1
4331 Ydiamond_s, FALSE, FALSE,
4332 EL_DIAMOND, ACTION_FALLING, -1
4335 Ydiamond_sB, FALSE, TRUE,
4336 EL_DIAMOND, ACTION_FALLING, -1
4339 Ydiamond_e, FALSE, FALSE,
4340 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
4343 Ydiamond_eB, FALSE, TRUE,
4344 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
4347 Ydiamond_w, FALSE, FALSE,
4348 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
4351 Ydiamond_wB, FALSE, TRUE,
4352 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
4355 Ydiamond_eat, FALSE, FALSE,
4356 EL_DIAMOND, ACTION_COLLECTING, -1
4359 Ydiamond_stone, FALSE, FALSE,
4360 EL_DIAMOND, ACTION_SMASHED_BY_ROCK, -1
4363 Xdrip_fall, TRUE, FALSE,
4364 EL_AMOEBA_DROP, -1, -1
4367 Xdrip_stretch, FALSE, FALSE,
4368 EL_AMOEBA_DROP, ACTION_FALLING, -1
4371 Xdrip_stretchB, FALSE, TRUE,
4372 EL_AMOEBA_DROP, ACTION_FALLING, -1
4375 Xdrip_eat, FALSE, FALSE,
4376 EL_AMOEBA_DROP, ACTION_GROWING, -1
4379 Ydrip_s1, FALSE, FALSE,
4380 EL_AMOEBA_DROP, ACTION_FALLING, -1
4383 Ydrip_s1B, FALSE, TRUE,
4384 EL_AMOEBA_DROP, ACTION_FALLING, -1
4387 Ydrip_s2, FALSE, FALSE,
4388 EL_AMOEBA_DROP, ACTION_FALLING, -1
4391 Ydrip_s2B, FALSE, TRUE,
4392 EL_AMOEBA_DROP, ACTION_FALLING, -1
4399 Xbomb_pause, FALSE, FALSE,
4403 Xbomb_fall, FALSE, FALSE,
4407 Ybomb_s, FALSE, FALSE,
4408 EL_BOMB, ACTION_FALLING, -1
4411 Ybomb_sB, FALSE, TRUE,
4412 EL_BOMB, ACTION_FALLING, -1
4415 Ybomb_e, FALSE, FALSE,
4416 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
4419 Ybomb_eB, FALSE, TRUE,
4420 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
4423 Ybomb_w, FALSE, FALSE,
4424 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
4427 Ybomb_wB, FALSE, TRUE,
4428 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
4431 Ybomb_eat, FALSE, FALSE,
4432 EL_BOMB, ACTION_ACTIVATING, -1
4435 Xballoon, TRUE, FALSE,
4439 Yballoon_n, FALSE, FALSE,
4440 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
4443 Yballoon_nB, FALSE, TRUE,
4444 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
4447 Yballoon_e, FALSE, FALSE,
4448 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
4451 Yballoon_eB, FALSE, TRUE,
4452 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
4455 Yballoon_s, FALSE, FALSE,
4456 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
4459 Yballoon_sB, FALSE, TRUE,
4460 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
4463 Yballoon_w, FALSE, FALSE,
4464 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
4467 Yballoon_wB, FALSE, TRUE,
4468 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
4471 Xgrass, TRUE, FALSE,
4472 EL_EMC_GRASS, -1, -1
4475 Ygrass_nB, FALSE, FALSE,
4476 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_UP
4479 Ygrass_eB, FALSE, FALSE,
4480 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_RIGHT
4483 Ygrass_sB, FALSE, FALSE,
4484 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_DOWN
4487 Ygrass_wB, FALSE, FALSE,
4488 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_LEFT
4495 Ydirt_nB, FALSE, FALSE,
4496 EL_SAND, ACTION_DIGGING, MV_BIT_UP
4499 Ydirt_eB, FALSE, FALSE,
4500 EL_SAND, ACTION_DIGGING, MV_BIT_RIGHT
4503 Ydirt_sB, FALSE, FALSE,
4504 EL_SAND, ACTION_DIGGING, MV_BIT_DOWN
4507 Ydirt_wB, FALSE, FALSE,
4508 EL_SAND, ACTION_DIGGING, MV_BIT_LEFT
4511 Xacid_ne, TRUE, FALSE,
4512 EL_ACID_POOL_TOPRIGHT, -1, -1
4515 Xacid_se, TRUE, FALSE,
4516 EL_ACID_POOL_BOTTOMRIGHT, -1, -1
4519 Xacid_s, TRUE, FALSE,
4520 EL_ACID_POOL_BOTTOM, -1, -1
4523 Xacid_sw, TRUE, FALSE,
4524 EL_ACID_POOL_BOTTOMLEFT, -1, -1
4527 Xacid_nw, TRUE, FALSE,
4528 EL_ACID_POOL_TOPLEFT, -1, -1
4531 Xacid_1, TRUE, FALSE,
4535 Xacid_2, FALSE, FALSE,
4539 Xacid_3, FALSE, FALSE,
4543 Xacid_4, FALSE, FALSE,
4547 Xacid_5, FALSE, FALSE,
4551 Xacid_6, FALSE, FALSE,
4555 Xacid_7, FALSE, FALSE,
4559 Xacid_8, FALSE, FALSE,
4563 Xball_1, TRUE, FALSE,
4564 EL_EMC_MAGIC_BALL, -1, -1
4567 Xball_1B, FALSE, FALSE,
4568 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4571 Xball_2, FALSE, FALSE,
4572 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4575 Xball_2B, FALSE, FALSE,
4576 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4579 Yball_eat, FALSE, FALSE,
4580 EL_EMC_MAGIC_BALL, ACTION_DROPPING, -1
4583 Ykey_1_eat, FALSE, FALSE,
4584 EL_EM_KEY_1, ACTION_COLLECTING, -1
4587 Ykey_2_eat, FALSE, FALSE,
4588 EL_EM_KEY_2, ACTION_COLLECTING, -1
4591 Ykey_3_eat, FALSE, FALSE,
4592 EL_EM_KEY_3, ACTION_COLLECTING, -1
4595 Ykey_4_eat, FALSE, FALSE,
4596 EL_EM_KEY_4, ACTION_COLLECTING, -1
4599 Ykey_5_eat, FALSE, FALSE,
4600 EL_EMC_KEY_5, ACTION_COLLECTING, -1
4603 Ykey_6_eat, FALSE, FALSE,
4604 EL_EMC_KEY_6, ACTION_COLLECTING, -1
4607 Ykey_7_eat, FALSE, FALSE,
4608 EL_EMC_KEY_7, ACTION_COLLECTING, -1
4611 Ykey_8_eat, FALSE, FALSE,
4612 EL_EMC_KEY_8, ACTION_COLLECTING, -1
4615 Ylenses_eat, FALSE, FALSE,
4616 EL_EMC_LENSES, ACTION_COLLECTING, -1
4619 Ymagnify_eat, FALSE, FALSE,
4620 EL_EMC_MAGNIFIER, ACTION_COLLECTING, -1
4623 Ygrass_eat, FALSE, FALSE,
4624 EL_EMC_GRASS, ACTION_SNAPPING, -1
4627 Ydirt_eat, FALSE, FALSE,
4628 EL_SAND, ACTION_SNAPPING, -1
4631 Xgrow_ns, TRUE, FALSE,
4632 EL_EXPANDABLE_WALL_VERTICAL, -1, -1
4635 Ygrow_ns_eat, FALSE, FALSE,
4636 EL_EXPANDABLE_WALL_VERTICAL, ACTION_GROWING, -1
4639 Xgrow_ew, TRUE, FALSE,
4640 EL_EXPANDABLE_WALL_HORIZONTAL, -1, -1
4643 Ygrow_ew_eat, FALSE, FALSE,
4644 EL_EXPANDABLE_WALL_HORIZONTAL, ACTION_GROWING, -1
4647 Xwonderwall, TRUE, FALSE,
4648 EL_MAGIC_WALL, -1, -1
4651 XwonderwallB, FALSE, FALSE,
4652 EL_MAGIC_WALL, ACTION_ACTIVE, -1
4655 Xamoeba_1, TRUE, FALSE,
4656 EL_AMOEBA_DRY, ACTION_OTHER, -1
4659 Xamoeba_2, FALSE, FALSE,
4660 EL_AMOEBA_DRY, ACTION_OTHER, -1
4663 Xamoeba_3, FALSE, FALSE,
4664 EL_AMOEBA_DRY, ACTION_OTHER, -1
4667 Xamoeba_4, FALSE, FALSE,
4668 EL_AMOEBA_DRY, ACTION_OTHER, -1
4671 Xamoeba_5, TRUE, FALSE,
4672 EL_AMOEBA_WET, ACTION_OTHER, -1
4675 Xamoeba_6, FALSE, FALSE,
4676 EL_AMOEBA_WET, ACTION_OTHER, -1
4679 Xamoeba_7, FALSE, FALSE,
4680 EL_AMOEBA_WET, ACTION_OTHER, -1
4683 Xamoeba_8, FALSE, FALSE,
4684 EL_AMOEBA_WET, ACTION_OTHER, -1
4687 Xdoor_1, TRUE, FALSE,
4688 EL_EM_GATE_1, -1, -1
4691 Xdoor_2, TRUE, FALSE,
4692 EL_EM_GATE_2, -1, -1
4695 Xdoor_3, TRUE, FALSE,
4696 EL_EM_GATE_3, -1, -1
4699 Xdoor_4, TRUE, FALSE,
4700 EL_EM_GATE_4, -1, -1
4703 Xdoor_5, TRUE, FALSE,
4704 EL_EMC_GATE_5, -1, -1
4707 Xdoor_6, TRUE, FALSE,
4708 EL_EMC_GATE_6, -1, -1
4711 Xdoor_7, TRUE, FALSE,
4712 EL_EMC_GATE_7, -1, -1
4715 Xdoor_8, TRUE, FALSE,
4716 EL_EMC_GATE_8, -1, -1
4719 Xkey_1, TRUE, FALSE,
4723 Xkey_2, TRUE, FALSE,
4727 Xkey_3, TRUE, FALSE,
4731 Xkey_4, TRUE, FALSE,
4735 Xkey_5, TRUE, FALSE,
4736 EL_EMC_KEY_5, -1, -1
4739 Xkey_6, TRUE, FALSE,
4740 EL_EMC_KEY_6, -1, -1
4743 Xkey_7, TRUE, FALSE,
4744 EL_EMC_KEY_7, -1, -1
4747 Xkey_8, TRUE, FALSE,
4748 EL_EMC_KEY_8, -1, -1
4751 Xwind_n, TRUE, FALSE,
4752 EL_BALLOON_SWITCH_UP, -1, -1
4755 Xwind_e, TRUE, FALSE,
4756 EL_BALLOON_SWITCH_RIGHT, -1, -1
4759 Xwind_s, TRUE, FALSE,
4760 EL_BALLOON_SWITCH_DOWN, -1, -1
4763 Xwind_w, TRUE, FALSE,
4764 EL_BALLOON_SWITCH_LEFT, -1, -1
4767 Xwind_nesw, TRUE, FALSE,
4768 EL_BALLOON_SWITCH_ANY, -1, -1
4771 Xwind_stop, TRUE, FALSE,
4772 EL_BALLOON_SWITCH_NONE, -1, -1
4776 EL_EM_EXIT_CLOSED, -1, -1
4779 Xexit_1, TRUE, FALSE,
4780 EL_EM_EXIT_OPEN, -1, -1
4783 Xexit_2, FALSE, FALSE,
4784 EL_EM_EXIT_OPEN, -1, -1
4787 Xexit_3, FALSE, FALSE,
4788 EL_EM_EXIT_OPEN, -1, -1
4791 Xdynamite, TRUE, FALSE,
4792 EL_EM_DYNAMITE, -1, -1
4795 Ydynamite_eat, FALSE, FALSE,
4796 EL_EM_DYNAMITE, ACTION_COLLECTING, -1
4799 Xdynamite_1, TRUE, FALSE,
4800 EL_EM_DYNAMITE_ACTIVE, -1, -1
4803 Xdynamite_2, FALSE, FALSE,
4804 EL_EM_DYNAMITE_ACTIVE, -1, -1
4807 Xdynamite_3, FALSE, FALSE,
4808 EL_EM_DYNAMITE_ACTIVE, -1, -1
4811 Xdynamite_4, FALSE, FALSE,
4812 EL_EM_DYNAMITE_ACTIVE, -1, -1
4815 Xbumper, TRUE, FALSE,
4816 EL_EMC_SPRING_BUMPER, -1, -1
4819 XbumperB, FALSE, FALSE,
4820 EL_EMC_SPRING_BUMPER, ACTION_ACTIVE, -1
4823 Xwheel, TRUE, FALSE,
4824 EL_ROBOT_WHEEL, -1, -1
4827 XwheelB, FALSE, FALSE,
4828 EL_ROBOT_WHEEL, ACTION_ACTIVE, -1
4831 Xswitch, TRUE, FALSE,
4832 EL_EMC_MAGIC_BALL_SWITCH, -1, -1
4835 XswitchB, FALSE, FALSE,
4836 EL_EMC_MAGIC_BALL_SWITCH, ACTION_ACTIVE, -1
4840 EL_QUICKSAND_EMPTY, -1, -1
4843 Xsand_stone, TRUE, FALSE,
4844 EL_QUICKSAND_FULL, -1, -1
4847 Xsand_stonein_1, FALSE, TRUE,
4848 EL_ROCK, ACTION_FILLING, -1
4851 Xsand_stonein_2, FALSE, TRUE,
4852 EL_ROCK, ACTION_FILLING, -1
4855 Xsand_stonein_3, FALSE, TRUE,
4856 EL_ROCK, ACTION_FILLING, -1
4859 Xsand_stonein_4, FALSE, TRUE,
4860 EL_ROCK, ACTION_FILLING, -1
4863 Xsand_stonesand_1, FALSE, FALSE,
4864 EL_QUICKSAND_FULL, -1, -1
4867 Xsand_stonesand_2, FALSE, FALSE,
4868 EL_QUICKSAND_FULL, -1, -1
4871 Xsand_stonesand_3, FALSE, FALSE,
4872 EL_QUICKSAND_FULL, -1, -1
4875 Xsand_stonesand_4, FALSE, FALSE,
4876 EL_QUICKSAND_FULL, -1, -1
4879 Xsand_stoneout_1, FALSE, FALSE,
4880 EL_ROCK, ACTION_EMPTYING, -1
4883 Xsand_stoneout_2, FALSE, FALSE,
4884 EL_ROCK, ACTION_EMPTYING, -1
4887 Xsand_sandstone_1, FALSE, FALSE,
4888 EL_QUICKSAND_FULL, -1, -1
4891 Xsand_sandstone_2, FALSE, FALSE,
4892 EL_QUICKSAND_FULL, -1, -1
4895 Xsand_sandstone_3, FALSE, FALSE,
4896 EL_QUICKSAND_FULL, -1, -1
4899 Xsand_sandstone_4, FALSE, FALSE,
4900 EL_QUICKSAND_FULL, -1, -1
4903 Xplant, TRUE, FALSE,
4904 EL_EMC_PLANT, -1, -1
4907 Yplant, FALSE, FALSE,
4908 EL_EMC_PLANT, -1, -1
4911 Xlenses, TRUE, FALSE,
4912 EL_EMC_LENSES, -1, -1
4915 Xmagnify, TRUE, FALSE,
4916 EL_EMC_MAGNIFIER, -1, -1
4919 Xdripper, TRUE, FALSE,
4920 EL_EMC_DRIPPER, -1, -1
4923 XdripperB, FALSE, FALSE,
4924 EL_EMC_DRIPPER, ACTION_ACTIVE, -1
4927 Xfake_blank, TRUE, FALSE,
4928 EL_INVISIBLE_WALL, -1, -1
4931 Xfake_blankB, FALSE, FALSE,
4932 EL_INVISIBLE_WALL, ACTION_ACTIVE, -1
4935 Xfake_grass, TRUE, FALSE,
4936 EL_EMC_FAKE_GRASS, -1, -1
4939 Xfake_grassB, FALSE, FALSE,
4940 EL_EMC_FAKE_GRASS, ACTION_ACTIVE, -1
4943 Xfake_door_1, TRUE, FALSE,
4944 EL_EM_GATE_1_GRAY, -1, -1
4947 Xfake_door_2, TRUE, FALSE,
4948 EL_EM_GATE_2_GRAY, -1, -1
4951 Xfake_door_3, TRUE, FALSE,
4952 EL_EM_GATE_3_GRAY, -1, -1
4955 Xfake_door_4, TRUE, FALSE,
4956 EL_EM_GATE_4_GRAY, -1, -1
4959 Xfake_door_5, TRUE, FALSE,
4960 EL_EMC_GATE_5_GRAY, -1, -1
4963 Xfake_door_6, TRUE, FALSE,
4964 EL_EMC_GATE_6_GRAY, -1, -1
4967 Xfake_door_7, TRUE, FALSE,
4968 EL_EMC_GATE_7_GRAY, -1, -1
4971 Xfake_door_8, TRUE, FALSE,
4972 EL_EMC_GATE_8_GRAY, -1, -1
4975 Xfake_acid_1, TRUE, FALSE,
4976 EL_EMC_FAKE_ACID, -1, -1
4979 Xfake_acid_2, FALSE, FALSE,
4980 EL_EMC_FAKE_ACID, -1, -1
4983 Xfake_acid_3, FALSE, FALSE,
4984 EL_EMC_FAKE_ACID, -1, -1
4987 Xfake_acid_4, FALSE, FALSE,
4988 EL_EMC_FAKE_ACID, -1, -1
4991 Xfake_acid_5, FALSE, FALSE,
4992 EL_EMC_FAKE_ACID, -1, -1
4995 Xfake_acid_6, FALSE, FALSE,
4996 EL_EMC_FAKE_ACID, -1, -1
4999 Xfake_acid_7, FALSE, FALSE,
5000 EL_EMC_FAKE_ACID, -1, -1
5003 Xfake_acid_8, FALSE, FALSE,
5004 EL_EMC_FAKE_ACID, -1, -1
5007 Xsteel_1, TRUE, FALSE,
5008 EL_STEELWALL, -1, -1
5011 Xsteel_2, TRUE, FALSE,
5012 EL_EMC_STEELWALL_2, -1, -1
5015 Xsteel_3, TRUE, FALSE,
5016 EL_EMC_STEELWALL_3, -1, -1
5019 Xsteel_4, TRUE, FALSE,
5020 EL_EMC_STEELWALL_4, -1, -1
5023 Xwall_1, TRUE, FALSE,
5027 Xwall_2, TRUE, FALSE,
5028 EL_EMC_WALL_14, -1, -1
5031 Xwall_3, TRUE, FALSE,
5032 EL_EMC_WALL_15, -1, -1
5035 Xwall_4, TRUE, FALSE,
5036 EL_EMC_WALL_16, -1, -1
5039 Xround_wall_1, TRUE, FALSE,
5040 EL_WALL_SLIPPERY, -1, -1
5043 Xround_wall_2, TRUE, FALSE,
5044 EL_EMC_WALL_SLIPPERY_2, -1, -1
5047 Xround_wall_3, TRUE, FALSE,
5048 EL_EMC_WALL_SLIPPERY_3, -1, -1
5051 Xround_wall_4, TRUE, FALSE,
5052 EL_EMC_WALL_SLIPPERY_4, -1, -1
5055 Xdecor_1, TRUE, FALSE,
5056 EL_EMC_WALL_8, -1, -1
5059 Xdecor_2, TRUE, FALSE,
5060 EL_EMC_WALL_6, -1, -1
5063 Xdecor_3, TRUE, FALSE,
5064 EL_EMC_WALL_4, -1, -1
5067 Xdecor_4, TRUE, FALSE,
5068 EL_EMC_WALL_7, -1, -1
5071 Xdecor_5, TRUE, FALSE,
5072 EL_EMC_WALL_5, -1, -1
5075 Xdecor_6, TRUE, FALSE,
5076 EL_EMC_WALL_9, -1, -1
5079 Xdecor_7, TRUE, FALSE,
5080 EL_EMC_WALL_10, -1, -1
5083 Xdecor_8, TRUE, FALSE,
5084 EL_EMC_WALL_1, -1, -1
5087 Xdecor_9, TRUE, FALSE,
5088 EL_EMC_WALL_2, -1, -1
5091 Xdecor_10, TRUE, FALSE,
5092 EL_EMC_WALL_3, -1, -1
5095 Xdecor_11, TRUE, FALSE,
5096 EL_EMC_WALL_11, -1, -1
5099 Xdecor_12, TRUE, FALSE,
5100 EL_EMC_WALL_12, -1, -1
5103 Xalpha_0, TRUE, FALSE,
5104 EL_CHAR('0'), -1, -1
5107 Xalpha_1, TRUE, FALSE,
5108 EL_CHAR('1'), -1, -1
5111 Xalpha_2, TRUE, FALSE,
5112 EL_CHAR('2'), -1, -1
5115 Xalpha_3, TRUE, FALSE,
5116 EL_CHAR('3'), -1, -1
5119 Xalpha_4, TRUE, FALSE,
5120 EL_CHAR('4'), -1, -1
5123 Xalpha_5, TRUE, FALSE,
5124 EL_CHAR('5'), -1, -1
5127 Xalpha_6, TRUE, FALSE,
5128 EL_CHAR('6'), -1, -1
5131 Xalpha_7, TRUE, FALSE,
5132 EL_CHAR('7'), -1, -1
5135 Xalpha_8, TRUE, FALSE,
5136 EL_CHAR('8'), -1, -1
5139 Xalpha_9, TRUE, FALSE,
5140 EL_CHAR('9'), -1, -1
5143 Xalpha_excla, TRUE, FALSE,
5144 EL_CHAR('!'), -1, -1
5147 Xalpha_quote, TRUE, FALSE,
5148 EL_CHAR('"'), -1, -1
5151 Xalpha_comma, TRUE, FALSE,
5152 EL_CHAR(','), -1, -1
5155 Xalpha_minus, TRUE, FALSE,
5156 EL_CHAR('-'), -1, -1
5159 Xalpha_perio, TRUE, FALSE,
5160 EL_CHAR('.'), -1, -1
5163 Xalpha_colon, TRUE, FALSE,
5164 EL_CHAR(':'), -1, -1
5167 Xalpha_quest, TRUE, FALSE,
5168 EL_CHAR('?'), -1, -1
5171 Xalpha_a, TRUE, FALSE,
5172 EL_CHAR('A'), -1, -1
5175 Xalpha_b, TRUE, FALSE,
5176 EL_CHAR('B'), -1, -1
5179 Xalpha_c, TRUE, FALSE,
5180 EL_CHAR('C'), -1, -1
5183 Xalpha_d, TRUE, FALSE,
5184 EL_CHAR('D'), -1, -1
5187 Xalpha_e, TRUE, FALSE,
5188 EL_CHAR('E'), -1, -1
5191 Xalpha_f, TRUE, FALSE,
5192 EL_CHAR('F'), -1, -1
5195 Xalpha_g, TRUE, FALSE,
5196 EL_CHAR('G'), -1, -1
5199 Xalpha_h, TRUE, FALSE,
5200 EL_CHAR('H'), -1, -1
5203 Xalpha_i, TRUE, FALSE,
5204 EL_CHAR('I'), -1, -1
5207 Xalpha_j, TRUE, FALSE,
5208 EL_CHAR('J'), -1, -1
5211 Xalpha_k, TRUE, FALSE,
5212 EL_CHAR('K'), -1, -1
5215 Xalpha_l, TRUE, FALSE,
5216 EL_CHAR('L'), -1, -1
5219 Xalpha_m, TRUE, FALSE,
5220 EL_CHAR('M'), -1, -1
5223 Xalpha_n, TRUE, FALSE,
5224 EL_CHAR('N'), -1, -1
5227 Xalpha_o, TRUE, FALSE,
5228 EL_CHAR('O'), -1, -1
5231 Xalpha_p, TRUE, FALSE,
5232 EL_CHAR('P'), -1, -1
5235 Xalpha_q, TRUE, FALSE,
5236 EL_CHAR('Q'), -1, -1
5239 Xalpha_r, TRUE, FALSE,
5240 EL_CHAR('R'), -1, -1
5243 Xalpha_s, TRUE, FALSE,
5244 EL_CHAR('S'), -1, -1
5247 Xalpha_t, TRUE, FALSE,
5248 EL_CHAR('T'), -1, -1
5251 Xalpha_u, TRUE, FALSE,
5252 EL_CHAR('U'), -1, -1
5255 Xalpha_v, TRUE, FALSE,
5256 EL_CHAR('V'), -1, -1
5259 Xalpha_w, TRUE, FALSE,
5260 EL_CHAR('W'), -1, -1
5263 Xalpha_x, TRUE, FALSE,
5264 EL_CHAR('X'), -1, -1
5267 Xalpha_y, TRUE, FALSE,
5268 EL_CHAR('Y'), -1, -1
5271 Xalpha_z, TRUE, FALSE,
5272 EL_CHAR('Z'), -1, -1
5275 Xalpha_arrow_e, TRUE, FALSE,
5276 EL_CHAR('>'), -1, -1
5279 Xalpha_arrow_w, TRUE, FALSE,
5280 EL_CHAR('<'), -1, -1
5283 Xalpha_copyr, TRUE, FALSE,
5284 EL_CHAR('©'), -1, -1
5288 Xboom_bug, FALSE, FALSE,
5289 EL_BUG, ACTION_EXPLODING, -1
5292 Xboom_bomb, FALSE, FALSE,
5293 EL_BOMB, ACTION_EXPLODING, -1
5296 Xboom_android, FALSE, FALSE,
5297 EL_EMC_ANDROID, ACTION_OTHER, -1
5300 Xboom_1, FALSE, FALSE,
5301 EL_DEFAULT, ACTION_EXPLODING, -1
5304 Xboom_2, FALSE, FALSE,
5305 EL_DEFAULT, ACTION_EXPLODING, -1
5308 Znormal, FALSE, FALSE,
5312 Zdynamite, FALSE, FALSE,
5316 Zplayer, FALSE, FALSE,
5320 ZBORDER, FALSE, FALSE,
5330 static struct Mapping_EM_to_RND_player
5339 em_player_mapping_list[] =
5343 EL_PLAYER_1, ACTION_MOVING, MV_BIT_UP,
5347 EL_PLAYER_1, ACTION_MOVING, MV_BIT_RIGHT,
5351 EL_PLAYER_1, ACTION_MOVING, MV_BIT_DOWN,
5355 EL_PLAYER_1, ACTION_MOVING, MV_BIT_LEFT,
5359 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_UP,
5363 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_RIGHT,
5367 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_DOWN,
5371 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_LEFT,
5375 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_UP,
5379 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_RIGHT,
5383 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_DOWN,
5387 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_LEFT,
5391 EL_PLAYER_2, ACTION_MOVING, MV_BIT_UP,
5395 EL_PLAYER_2, ACTION_MOVING, MV_BIT_RIGHT,
5399 EL_PLAYER_2, ACTION_MOVING, MV_BIT_DOWN,
5403 EL_PLAYER_2, ACTION_MOVING, MV_BIT_LEFT,
5407 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_UP,
5411 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_RIGHT,
5415 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_DOWN,
5419 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_LEFT,
5423 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_UP,
5427 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_RIGHT,
5431 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_DOWN,
5435 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_LEFT,
5439 EL_PLAYER_1, ACTION_DEFAULT, -1,
5443 EL_PLAYER_2, ACTION_DEFAULT, -1,
5447 EL_PLAYER_3, ACTION_MOVING, MV_BIT_UP,
5451 EL_PLAYER_3, ACTION_MOVING, MV_BIT_RIGHT,
5455 EL_PLAYER_3, ACTION_MOVING, MV_BIT_DOWN,
5459 EL_PLAYER_3, ACTION_MOVING, MV_BIT_LEFT,
5463 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_UP,
5467 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_RIGHT,
5471 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_DOWN,
5475 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_LEFT,
5479 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_UP,
5483 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_RIGHT,
5487 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_DOWN,
5491 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_LEFT,
5495 EL_PLAYER_4, ACTION_MOVING, MV_BIT_UP,
5499 EL_PLAYER_4, ACTION_MOVING, MV_BIT_RIGHT,
5503 EL_PLAYER_4, ACTION_MOVING, MV_BIT_DOWN,
5507 EL_PLAYER_4, ACTION_MOVING, MV_BIT_LEFT,
5511 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_UP,
5515 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_RIGHT,
5519 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_DOWN,
5523 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_LEFT,
5527 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_UP,
5531 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_RIGHT,
5535 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_DOWN,
5539 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_LEFT,
5543 EL_PLAYER_3, ACTION_DEFAULT, -1,
5547 EL_PLAYER_4, ACTION_DEFAULT, -1,
5556 int map_element_RND_to_EM(int element_rnd)
5558 static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
5559 static boolean mapping_initialized = FALSE;
5561 if (!mapping_initialized)
5565 /* return "Xalpha_quest" for all undefined elements in mapping array */
5566 for (i = 0; i < NUM_FILE_ELEMENTS; i++)
5567 mapping_RND_to_EM[i] = Xalpha_quest;
5569 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5570 if (em_object_mapping_list[i].is_rnd_to_em_mapping)
5571 mapping_RND_to_EM[em_object_mapping_list[i].element_rnd] =
5572 em_object_mapping_list[i].element_em;
5574 mapping_initialized = TRUE;
5577 if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
5578 return mapping_RND_to_EM[element_rnd];
5580 Error(ERR_WARN, "invalid RND level element %d", element_rnd);
5585 int map_element_EM_to_RND(int element_em)
5587 static unsigned short mapping_EM_to_RND[TILE_MAX];
5588 static boolean mapping_initialized = FALSE;
5590 if (!mapping_initialized)
5594 /* return "EL_UNKNOWN" for all undefined elements in mapping array */
5595 for (i = 0; i < TILE_MAX; i++)
5596 mapping_EM_to_RND[i] = EL_UNKNOWN;
5598 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5599 mapping_EM_to_RND[em_object_mapping_list[i].element_em] =
5600 em_object_mapping_list[i].element_rnd;
5602 mapping_initialized = TRUE;
5605 if (element_em >= 0 && element_em < TILE_MAX)
5606 return mapping_EM_to_RND[element_em];
5608 Error(ERR_WARN, "invalid EM level element %d", element_em);
5613 void map_android_clone_elements_RND_to_EM(struct LevelInfo *level)
5615 struct LevelInfo_EM *level_em = level->native_em_level;
5616 struct LEVEL *lev = level_em->lev;
5619 for (i = 0; i < TILE_MAX; i++)
5620 lev->android_array[i] = Xblank;
5622 for (i = 0; i < level->num_android_clone_elements; i++)
5624 int element_rnd = level->android_clone_element[i];
5625 int element_em = map_element_RND_to_EM(element_rnd);
5627 for (j = 0; em_object_mapping_list[j].element_em != -1; j++)
5628 if (em_object_mapping_list[j].element_rnd == element_rnd)
5629 lev->android_array[em_object_mapping_list[j].element_em] = element_em;
5633 void map_android_clone_elements_EM_to_RND(struct LevelInfo *level)
5635 struct LevelInfo_EM *level_em = level->native_em_level;
5636 struct LEVEL *lev = level_em->lev;
5639 level->num_android_clone_elements = 0;
5641 for (i = 0; i < TILE_MAX; i++)
5643 int element_em = lev->android_array[i];
5645 boolean element_found = FALSE;
5647 if (element_em == Xblank)
5650 element_rnd = map_element_EM_to_RND(element_em);
5652 for (j = 0; j < level->num_android_clone_elements; j++)
5653 if (level->android_clone_element[j] == element_rnd)
5654 element_found = TRUE;
5658 level->android_clone_element[level->num_android_clone_elements++] =
5661 if (level->num_android_clone_elements == MAX_ANDROID_ELEMENTS)
5666 if (level->num_android_clone_elements == 0)
5668 level->num_android_clone_elements = 1;
5669 level->android_clone_element[0] = EL_EMPTY;
5673 int map_direction_RND_to_EM(int direction)
5675 return (direction == MV_UP ? 0 :
5676 direction == MV_RIGHT ? 1 :
5677 direction == MV_DOWN ? 2 :
5678 direction == MV_LEFT ? 3 :
5682 int map_direction_EM_to_RND(int direction)
5684 return (direction == 0 ? MV_UP :
5685 direction == 1 ? MV_RIGHT :
5686 direction == 2 ? MV_DOWN :
5687 direction == 3 ? MV_LEFT :
5691 int get_next_element(int element)
5695 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
5696 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
5697 case EL_QUICKSAND_FAST_FILLING: return EL_QUICKSAND_FAST_FULL;
5698 case EL_QUICKSAND_FAST_EMPTYING: return EL_QUICKSAND_FAST_EMPTY;
5699 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
5700 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
5701 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
5702 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
5703 case EL_DC_MAGIC_WALL_FILLING: return EL_DC_MAGIC_WALL_FULL;
5704 case EL_DC_MAGIC_WALL_EMPTYING: return EL_DC_MAGIC_WALL_ACTIVE;
5705 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
5707 default: return element;
5712 int el_act_dir2img(int element, int action, int direction)
5714 element = GFX_ELEMENT(element);
5716 if (direction == MV_NONE)
5717 return element_info[element].graphic[action];
5719 direction = MV_DIR_TO_BIT(direction);
5721 return element_info[element].direction_graphic[action][direction];
5724 int el_act_dir2img(int element, int action, int direction)
5726 element = GFX_ELEMENT(element);
5727 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
5729 /* direction_graphic[][] == graphic[] for undefined direction graphics */
5730 return element_info[element].direction_graphic[action][direction];
5735 static int el_act_dir2crm(int element, int action, int direction)
5737 element = GFX_ELEMENT(element);
5739 if (direction == MV_NONE)
5740 return element_info[element].crumbled[action];
5742 direction = MV_DIR_TO_BIT(direction);
5744 return element_info[element].direction_crumbled[action][direction];
5747 static int el_act_dir2crm(int element, int action, int direction)
5749 element = GFX_ELEMENT(element);
5750 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
5752 /* direction_graphic[][] == graphic[] for undefined direction graphics */
5753 return element_info[element].direction_crumbled[action][direction];
5757 int el_act2img(int element, int action)
5759 element = GFX_ELEMENT(element);
5761 return element_info[element].graphic[action];
5764 int el_act2crm(int element, int action)
5766 element = GFX_ELEMENT(element);
5768 return element_info[element].crumbled[action];
5771 int el_dir2img(int element, int direction)
5773 element = GFX_ELEMENT(element);
5775 return el_act_dir2img(element, ACTION_DEFAULT, direction);
5778 int el2baseimg(int element)
5780 return element_info[element].graphic[ACTION_DEFAULT];
5783 int el2img(int element)
5785 element = GFX_ELEMENT(element);
5787 return element_info[element].graphic[ACTION_DEFAULT];
5790 int el2edimg(int element)
5792 element = GFX_ELEMENT(element);
5794 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
5797 int el2preimg(int element)
5799 element = GFX_ELEMENT(element);
5801 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
5804 int el2panelimg(int element)
5806 element = GFX_ELEMENT(element);
5808 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PANEL];
5811 int font2baseimg(int font_nr)
5813 return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
5816 int getBeltNrFromBeltElement(int element)
5818 return (element < EL_CONVEYOR_BELT_2_LEFT ? 0 :
5819 element < EL_CONVEYOR_BELT_3_LEFT ? 1 :
5820 element < EL_CONVEYOR_BELT_4_LEFT ? 2 : 3);
5823 int getBeltNrFromBeltActiveElement(int element)
5825 return (element < EL_CONVEYOR_BELT_2_LEFT_ACTIVE ? 0 :
5826 element < EL_CONVEYOR_BELT_3_LEFT_ACTIVE ? 1 :
5827 element < EL_CONVEYOR_BELT_4_LEFT_ACTIVE ? 2 : 3);
5830 int getBeltNrFromBeltSwitchElement(int element)
5832 return (element < EL_CONVEYOR_BELT_2_SWITCH_LEFT ? 0 :
5833 element < EL_CONVEYOR_BELT_3_SWITCH_LEFT ? 1 :
5834 element < EL_CONVEYOR_BELT_4_SWITCH_LEFT ? 2 : 3);
5837 int getBeltDirNrFromBeltElement(int element)
5839 static int belt_base_element[4] =
5841 EL_CONVEYOR_BELT_1_LEFT,
5842 EL_CONVEYOR_BELT_2_LEFT,
5843 EL_CONVEYOR_BELT_3_LEFT,
5844 EL_CONVEYOR_BELT_4_LEFT
5847 int belt_nr = getBeltNrFromBeltElement(element);
5848 int belt_dir_nr = element - belt_base_element[belt_nr];
5850 return (belt_dir_nr % 3);
5853 int getBeltDirNrFromBeltSwitchElement(int element)
5855 static int belt_base_element[4] =
5857 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
5858 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
5859 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
5860 EL_CONVEYOR_BELT_4_SWITCH_LEFT
5863 int belt_nr = getBeltNrFromBeltSwitchElement(element);
5864 int belt_dir_nr = element - belt_base_element[belt_nr];
5866 return (belt_dir_nr % 3);
5869 int getBeltDirFromBeltElement(int element)
5871 static int belt_move_dir[3] =
5878 int belt_dir_nr = getBeltDirNrFromBeltElement(element);
5880 return belt_move_dir[belt_dir_nr];
5883 int getBeltDirFromBeltSwitchElement(int element)
5885 static int belt_move_dir[3] =
5892 int belt_dir_nr = getBeltDirNrFromBeltSwitchElement(element);
5894 return belt_move_dir[belt_dir_nr];
5897 int getBeltElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
5899 static int belt_base_element[4] =
5901 EL_CONVEYOR_BELT_1_LEFT,
5902 EL_CONVEYOR_BELT_2_LEFT,
5903 EL_CONVEYOR_BELT_3_LEFT,
5904 EL_CONVEYOR_BELT_4_LEFT
5907 return belt_base_element[belt_nr] + belt_dir_nr;
5910 int getBeltElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
5912 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
5914 return getBeltElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
5917 int getBeltSwitchElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
5919 static int belt_base_element[4] =
5921 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
5922 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
5923 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
5924 EL_CONVEYOR_BELT_4_SWITCH_LEFT
5927 return belt_base_element[belt_nr] + belt_dir_nr;
5930 int getBeltSwitchElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
5932 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
5934 return getBeltSwitchElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
5937 int getNumActivePlayers_EM()
5939 int num_players = 0;
5945 for (i = 0; i < MAX_PLAYERS; i++)
5946 if (tape.player_participates[i])
5952 int getGameFrameDelay_EM(int native_em_game_frame_delay)
5954 int game_frame_delay_value;
5956 game_frame_delay_value =
5957 (tape.playing && tape.fast_forward ? FfwdFrameDelay :
5958 GameFrameDelay == GAME_FRAME_DELAY ? native_em_game_frame_delay :
5961 if (tape.playing && tape.warp_forward && !tape.pausing)
5962 game_frame_delay_value = 0;
5964 return game_frame_delay_value;
5967 unsigned int InitRND(long seed)
5969 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
5970 return InitEngineRandom_EM(seed);
5972 return InitEngineRandom_RND(seed);
5976 static struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
5977 static struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
5980 void ResetGfxAnimation_EM(int x, int y, int tile)
5985 void SetGfxAnimation_EM(int tile, int frame_em, int x, int y)
5988 int element = object_mapping[tile].element_rnd;
5990 int action = object_mapping[tile].action;
5991 int direction = object_mapping[tile].direction;
5992 boolean is_backside = object_mapping[tile].is_backside;
5993 boolean action_removing = (action == ACTION_DIGGING ||
5994 action == ACTION_SNAPPING ||
5995 action == ACTION_COLLECTING);
5998 printf("::: SET: %d, %d: '%s'\n", x, y, EL_NAME(element));
6002 if (action_removing)
6005 printf("::: %d, %d: action_removing [%s]\n", x, y, EL_NAME(element));
6008 GfxFrame[x][y] = 7 - frame_em;
6010 else if (action == ACTION_FALLING ||
6011 action == ACTION_MOVING ||
6012 action == ACTION_PUSHING ||
6013 action == ACTION_EATING ||
6014 action == ACTION_FILLING ||
6015 action == ACTION_EMPTYING)
6018 (action == ACTION_FALLING ||
6019 action == ACTION_FILLING ||
6020 action == ACTION_EMPTYING ? MV_DOWN : direction);
6026 if (move_dir == MV_LEFT)
6027 GfxFrame[x - 1][y] = GfxFrame[x][y];
6028 else if (move_dir == MV_RIGHT)
6029 GfxFrame[x + 1][y] = GfxFrame[x][y];
6030 else if (move_dir == MV_UP)
6031 GfxFrame[x][y - 1] = GfxFrame[x][y];
6032 else if (move_dir == MV_DOWN)
6033 GfxFrame[x][y + 1] = GfxFrame[x][y];
6037 printf("::: %d, %d: %s, %d, %d [%d]\n", x, y, EL_NAME(element), is_backside,
6038 move_dir, GfxFrame[x][y]);
6044 GfxFrame[x][y] = 7 - frame_em;
6048 void getGraphicSourceObjectExt_EM(int tile, int frame_em,
6049 Bitmap **src_bitmap, int *src_x, int *src_y,
6050 Bitmap **crumbled_src_bitmap,
6051 int *crumbled_src_x, int *crumbled_src_y,
6054 int element = object_mapping[tile].element_rnd;
6055 int action = object_mapping[tile].action;
6056 int direction = object_mapping[tile].direction;
6057 boolean is_backside = object_mapping[tile].is_backside;
6058 boolean action_removing = (action == ACTION_DIGGING ||
6059 action == ACTION_SNAPPING ||
6060 action == ACTION_COLLECTING);
6061 int effective_element = (frame_em > 0 ? element :
6062 is_backside ? EL_EMPTY :
6063 action_removing ? EL_EMPTY :
6065 int graphic = (direction == MV_NONE ?
6066 el_act2img(effective_element, action) :
6067 el_act_dir2img(effective_element, action, direction));
6068 int crumbled = (direction == MV_NONE ?
6069 el_act2crm(effective_element, action) :
6070 el_act_dir2crm(effective_element, action, direction));
6071 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
6072 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
6073 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
6074 struct GraphicInfo *g = &graphic_info[graphic];
6075 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
6079 printf("::: GET: %d, %d: '%s'\n", x, y, EL_NAME(element));
6083 if (GfxFrame[x][y] < 8)
6084 printf("::: %d, %d: %d [%s]\n", x, y, GfxFrame[x][y], EL_NAME(element));
6088 if (graphic_info[graphic].anim_global_sync)
6089 sync_frame = FrameCounter;
6090 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
6091 sync_frame = GfxFrame[x][y];
6093 sync_frame = 0; /* steel border */
6095 if (graphic_info[graphic].anim_global_sync)
6096 sync_frame = FrameCounter;
6098 sync_frame = 7 - frame_em;
6101 SetRandomAnimationValue(x, y);
6103 int frame = getAnimationFrame(g->anim_frames,
6106 g->anim_start_frame,
6109 getGraphicSourceExt(graphic, frame, src_bitmap, src_x, src_y, FALSE);
6112 if (x == 1 && y == 1 && frame == 0)
6113 printf("--> %d, %d, %d\n", *crumbled_src_x, *crumbled_src_y, tile);
6117 getGraphicSource(crumbled, frame, crumbled_src_bitmap,
6118 crumbled_src_x, crumbled_src_y);
6122 /* (updating the "crumbled" graphic definitions is probably not really needed,
6123 as animations for crumbled graphics can't be longer than one EMC cycle) */
6125 *crumbled_src_bitmap = NULL;
6126 *crumbled_src_x = 0;
6127 *crumbled_src_y = 0;
6129 if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
6131 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
6132 g_crumbled->anim_delay,
6133 g_crumbled->anim_mode,
6134 g_crumbled->anim_start_frame,
6137 getGraphicSource(crumbled, frame_crumbled, crumbled_src_bitmap,
6138 crumbled_src_x, crumbled_src_y);
6143 void getGraphicSourcePlayerExt_EM(int player_nr, int anim, int frame_em,
6144 Bitmap **src_bitmap, int *src_x, int *src_y)
6146 int element = player_mapping[player_nr][anim].element_rnd;
6147 int action = player_mapping[player_nr][anim].action;
6148 int direction = player_mapping[player_nr][anim].direction;
6149 int graphic = (direction == MV_NONE ?
6150 el_act2img(element, action) :
6151 el_act_dir2img(element, action, direction));
6152 struct GraphicInfo *g = &graphic_info[graphic];
6155 InitPlayerGfxAnimation(&stored_player[player_nr], action, direction);
6157 stored_player[player_nr].StepFrame = 7 - frame_em;
6159 sync_frame = stored_player[player_nr].Frame;
6162 printf("::: %d: %d, %d [%d]\n",
6164 stored_player[player_nr].Frame,
6165 stored_player[player_nr].StepFrame,
6169 int frame = getAnimationFrame(g->anim_frames,
6172 g->anim_start_frame,
6175 getGraphicSourceExt(graphic, frame, src_bitmap, src_x, src_y, FALSE);
6178 void InitGraphicInfo_EM(void)
6181 struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
6182 struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
6187 int num_em_gfx_errors = 0;
6189 if (graphic_info_em_object[0][0].bitmap == NULL)
6191 /* EM graphics not yet initialized in em_open_all() */
6196 printf("::: [4 errors can be ignored (1 x 'bomb', 3 x 'em_dynamite']\n");
6199 /* always start with reliable default values */
6200 for (i = 0; i < TILE_MAX; i++)
6202 object_mapping[i].element_rnd = EL_UNKNOWN;
6203 object_mapping[i].is_backside = FALSE;
6204 object_mapping[i].action = ACTION_DEFAULT;
6205 object_mapping[i].direction = MV_NONE;
6208 /* always start with reliable default values */
6209 for (p = 0; p < MAX_PLAYERS; p++)
6211 for (i = 0; i < SPR_MAX; i++)
6213 player_mapping[p][i].element_rnd = EL_UNKNOWN;
6214 player_mapping[p][i].action = ACTION_DEFAULT;
6215 player_mapping[p][i].direction = MV_NONE;
6219 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
6221 int e = em_object_mapping_list[i].element_em;
6223 object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd;
6224 object_mapping[e].is_backside = em_object_mapping_list[i].is_backside;
6226 if (em_object_mapping_list[i].action != -1)
6227 object_mapping[e].action = em_object_mapping_list[i].action;
6229 if (em_object_mapping_list[i].direction != -1)
6230 object_mapping[e].direction =
6231 MV_DIR_FROM_BIT(em_object_mapping_list[i].direction);
6234 for (i = 0; em_player_mapping_list[i].action_em != -1; i++)
6236 int a = em_player_mapping_list[i].action_em;
6237 int p = em_player_mapping_list[i].player_nr;
6239 player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd;
6241 if (em_player_mapping_list[i].action != -1)
6242 player_mapping[p][a].action = em_player_mapping_list[i].action;
6244 if (em_player_mapping_list[i].direction != -1)
6245 player_mapping[p][a].direction =
6246 MV_DIR_FROM_BIT(em_player_mapping_list[i].direction);
6249 for (i = 0; i < TILE_MAX; i++)
6251 int element = object_mapping[i].element_rnd;
6252 int action = object_mapping[i].action;
6253 int direction = object_mapping[i].direction;
6254 boolean is_backside = object_mapping[i].is_backside;
6255 boolean action_removing = (action == ACTION_DIGGING ||
6256 action == ACTION_SNAPPING ||
6257 action == ACTION_COLLECTING);
6258 boolean action_exploding = ((action == ACTION_EXPLODING ||
6259 action == ACTION_SMASHED_BY_ROCK ||
6260 action == ACTION_SMASHED_BY_SPRING) &&
6261 element != EL_DIAMOND);
6262 boolean action_active = (action == ACTION_ACTIVE);
6263 boolean action_other = (action == ACTION_OTHER);
6265 for (j = 0; j < 8; j++)
6267 int effective_element = (j > 5 && i == Yacid_splash_eB ? EL_EMPTY :
6268 j > 5 && i == Yacid_splash_wB ? EL_EMPTY :
6270 i == Xdrip_stretch ? element :
6271 i == Xdrip_stretchB ? element :
6272 i == Ydrip_s1 ? element :
6273 i == Ydrip_s1B ? element :
6274 i == Xball_1B ? element :
6275 i == Xball_2 ? element :
6276 i == Xball_2B ? element :
6277 i == Yball_eat ? element :
6278 i == Ykey_1_eat ? element :
6279 i == Ykey_2_eat ? element :
6280 i == Ykey_3_eat ? element :
6281 i == Ykey_4_eat ? element :
6282 i == Ykey_5_eat ? element :
6283 i == Ykey_6_eat ? element :
6284 i == Ykey_7_eat ? element :
6285 i == Ykey_8_eat ? element :
6286 i == Ylenses_eat ? element :
6287 i == Ymagnify_eat ? element :
6288 i == Ygrass_eat ? element :
6289 i == Ydirt_eat ? element :
6290 i == Yemerald_stone ? EL_EMERALD :
6291 i == Ydiamond_stone ? EL_ROCK :
6292 i == Xsand_stonein_1 ? element :
6293 i == Xsand_stonein_2 ? element :
6294 i == Xsand_stonein_3 ? element :
6295 i == Xsand_stonein_4 ? element :
6296 is_backside ? EL_EMPTY :
6297 action_removing ? EL_EMPTY :
6299 int effective_action = (j < 7 ? action :
6300 i == Xdrip_stretch ? action :
6301 i == Xdrip_stretchB ? action :
6302 i == Ydrip_s1 ? action :
6303 i == Ydrip_s1B ? action :
6304 i == Xball_1B ? action :
6305 i == Xball_2 ? action :
6306 i == Xball_2B ? action :
6307 i == Yball_eat ? action :
6308 i == Ykey_1_eat ? action :
6309 i == Ykey_2_eat ? action :
6310 i == Ykey_3_eat ? action :
6311 i == Ykey_4_eat ? action :
6312 i == Ykey_5_eat ? action :
6313 i == Ykey_6_eat ? action :
6314 i == Ykey_7_eat ? action :
6315 i == Ykey_8_eat ? action :
6316 i == Ylenses_eat ? action :
6317 i == Ymagnify_eat ? action :
6318 i == Ygrass_eat ? action :
6319 i == Ydirt_eat ? action :
6320 i == Xsand_stonein_1 ? action :
6321 i == Xsand_stonein_2 ? action :
6322 i == Xsand_stonein_3 ? action :
6323 i == Xsand_stonein_4 ? action :
6324 i == Xsand_stoneout_1 ? action :
6325 i == Xsand_stoneout_2 ? action :
6326 i == Xboom_android ? ACTION_EXPLODING :
6327 action_exploding ? ACTION_EXPLODING :
6328 action_active ? action :
6329 action_other ? action :
6331 int graphic = (el_act_dir2img(effective_element, effective_action,
6333 int crumbled = (el_act_dir2crm(effective_element, effective_action,
6335 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
6336 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
6337 boolean has_action_graphics = (graphic != base_graphic);
6338 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
6339 struct GraphicInfo *g = &graphic_info[graphic];
6340 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
6341 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
6344 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
6345 boolean special_animation = (action != ACTION_DEFAULT &&
6346 g->anim_frames == 3 &&
6347 g->anim_delay == 2 &&
6348 g->anim_mode & ANIM_LINEAR);
6349 int sync_frame = (i == Xdrip_stretch ? 7 :
6350 i == Xdrip_stretchB ? 7 :
6351 i == Ydrip_s2 ? j + 8 :
6352 i == Ydrip_s2B ? j + 8 :
6361 i == Xfake_acid_1 ? 0 :
6362 i == Xfake_acid_2 ? 10 :
6363 i == Xfake_acid_3 ? 20 :
6364 i == Xfake_acid_4 ? 30 :
6365 i == Xfake_acid_5 ? 40 :
6366 i == Xfake_acid_6 ? 50 :
6367 i == Xfake_acid_7 ? 60 :
6368 i == Xfake_acid_8 ? 70 :
6370 i == Xball_2B ? j + 8 :
6371 i == Yball_eat ? j + 1 :
6372 i == Ykey_1_eat ? j + 1 :
6373 i == Ykey_2_eat ? j + 1 :
6374 i == Ykey_3_eat ? j + 1 :
6375 i == Ykey_4_eat ? j + 1 :
6376 i == Ykey_5_eat ? j + 1 :
6377 i == Ykey_6_eat ? j + 1 :
6378 i == Ykey_7_eat ? j + 1 :
6379 i == Ykey_8_eat ? j + 1 :
6380 i == Ylenses_eat ? j + 1 :
6381 i == Ymagnify_eat ? j + 1 :
6382 i == Ygrass_eat ? j + 1 :
6383 i == Ydirt_eat ? j + 1 :
6384 i == Xamoeba_1 ? 0 :
6385 i == Xamoeba_2 ? 1 :
6386 i == Xamoeba_3 ? 2 :
6387 i == Xamoeba_4 ? 3 :
6388 i == Xamoeba_5 ? 0 :
6389 i == Xamoeba_6 ? 1 :
6390 i == Xamoeba_7 ? 2 :
6391 i == Xamoeba_8 ? 3 :
6392 i == Xexit_2 ? j + 8 :
6393 i == Xexit_3 ? j + 16 :
6394 i == Xdynamite_1 ? 0 :
6395 i == Xdynamite_2 ? 8 :
6396 i == Xdynamite_3 ? 16 :
6397 i == Xdynamite_4 ? 24 :
6398 i == Xsand_stonein_1 ? j + 1 :
6399 i == Xsand_stonein_2 ? j + 9 :
6400 i == Xsand_stonein_3 ? j + 17 :
6401 i == Xsand_stonein_4 ? j + 25 :
6402 i == Xsand_stoneout_1 && j == 0 ? 0 :
6403 i == Xsand_stoneout_1 && j == 1 ? 0 :
6404 i == Xsand_stoneout_1 && j == 2 ? 1 :
6405 i == Xsand_stoneout_1 && j == 3 ? 2 :
6406 i == Xsand_stoneout_1 && j == 4 ? 2 :
6407 i == Xsand_stoneout_1 && j == 5 ? 3 :
6408 i == Xsand_stoneout_1 && j == 6 ? 4 :
6409 i == Xsand_stoneout_1 && j == 7 ? 4 :
6410 i == Xsand_stoneout_2 && j == 0 ? 5 :
6411 i == Xsand_stoneout_2 && j == 1 ? 6 :
6412 i == Xsand_stoneout_2 && j == 2 ? 7 :
6413 i == Xsand_stoneout_2 && j == 3 ? 8 :
6414 i == Xsand_stoneout_2 && j == 4 ? 9 :
6415 i == Xsand_stoneout_2 && j == 5 ? 11 :
6416 i == Xsand_stoneout_2 && j == 6 ? 13 :
6417 i == Xsand_stoneout_2 && j == 7 ? 15 :
6418 i == Xboom_bug && j == 1 ? 2 :
6419 i == Xboom_bug && j == 2 ? 2 :
6420 i == Xboom_bug && j == 3 ? 4 :
6421 i == Xboom_bug && j == 4 ? 4 :
6422 i == Xboom_bug && j == 5 ? 2 :
6423 i == Xboom_bug && j == 6 ? 2 :
6424 i == Xboom_bug && j == 7 ? 0 :
6425 i == Xboom_bomb && j == 1 ? 2 :
6426 i == Xboom_bomb && j == 2 ? 2 :
6427 i == Xboom_bomb && j == 3 ? 4 :
6428 i == Xboom_bomb && j == 4 ? 4 :
6429 i == Xboom_bomb && j == 5 ? 2 :
6430 i == Xboom_bomb && j == 6 ? 2 :
6431 i == Xboom_bomb && j == 7 ? 0 :
6432 i == Xboom_android && j == 7 ? 6 :
6433 i == Xboom_1 && j == 1 ? 2 :
6434 i == Xboom_1 && j == 2 ? 2 :
6435 i == Xboom_1 && j == 3 ? 4 :
6436 i == Xboom_1 && j == 4 ? 4 :
6437 i == Xboom_1 && j == 5 ? 6 :
6438 i == Xboom_1 && j == 6 ? 6 :
6439 i == Xboom_1 && j == 7 ? 8 :
6440 i == Xboom_2 && j == 0 ? 8 :
6441 i == Xboom_2 && j == 1 ? 8 :
6442 i == Xboom_2 && j == 2 ? 10 :
6443 i == Xboom_2 && j == 3 ? 10 :
6444 i == Xboom_2 && j == 4 ? 10 :
6445 i == Xboom_2 && j == 5 ? 12 :
6446 i == Xboom_2 && j == 6 ? 12 :
6447 i == Xboom_2 && j == 7 ? 12 :
6448 special_animation && j == 4 ? 3 :
6449 effective_action != action ? 0 :
6453 Bitmap *debug_bitmap = g_em->bitmap;
6454 int debug_src_x = g_em->src_x;
6455 int debug_src_y = g_em->src_y;
6458 int frame = getAnimationFrame(g->anim_frames,
6461 g->anim_start_frame,
6464 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y,
6465 g->double_movement && is_backside);
6467 g_em->bitmap = src_bitmap;
6468 g_em->src_x = src_x;
6469 g_em->src_y = src_y;
6470 g_em->src_offset_x = 0;
6471 g_em->src_offset_y = 0;
6472 g_em->dst_offset_x = 0;
6473 g_em->dst_offset_y = 0;
6474 g_em->width = TILEX;
6475 g_em->height = TILEY;
6477 g_em->crumbled_bitmap = NULL;
6478 g_em->crumbled_src_x = 0;
6479 g_em->crumbled_src_y = 0;
6480 g_em->crumbled_border_size = 0;
6482 g_em->has_crumbled_graphics = FALSE;
6483 g_em->preserve_background = FALSE;
6486 if (has_crumbled_graphics && crumbled == IMG_EMPTY_SPACE)
6487 printf("::: empty crumbled: %d [%s], %d, %d\n",
6488 effective_element, element_info[effective_element].token_name,
6489 effective_action, direction);
6492 /* if element can be crumbled, but certain action graphics are just empty
6493 space (like instantly snapping sand to empty space in 1 frame), do not
6494 treat these empty space graphics as crumbled graphics in EMC engine */
6495 if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
6497 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
6498 g_crumbled->anim_delay,
6499 g_crumbled->anim_mode,
6500 g_crumbled->anim_start_frame,
6503 getGraphicSource(crumbled, frame_crumbled, &src_bitmap, &src_x, &src_y);
6505 g_em->has_crumbled_graphics = TRUE;
6506 g_em->crumbled_bitmap = src_bitmap;
6507 g_em->crumbled_src_x = src_x;
6508 g_em->crumbled_src_y = src_y;
6509 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
6513 if (g_em == &graphic_info_em_object[207][0])
6514 printf("... %d, %d [%d, %d, %d, %d] [%d, %d, %d, %d, %d, %d => %d]\n",
6515 graphic_info_em_object[207][0].crumbled_src_x,
6516 graphic_info_em_object[207][0].crumbled_src_y,
6518 crumbled, frame, src_x, src_y,
6523 g->anim_start_frame,
6525 gfx.anim_random_frame,
6533 if (element == EL_ROCK &&
6534 effective_action == ACTION_FILLING)
6535 printf("::: has_action_graphics == %d\n", has_action_graphics);
6538 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
6539 effective_action == ACTION_MOVING ||
6540 effective_action == ACTION_PUSHING ||
6541 effective_action == ACTION_EATING)) ||
6542 (!has_action_graphics && (effective_action == ACTION_FILLING ||
6543 effective_action == ACTION_EMPTYING)))
6546 (effective_action == ACTION_FALLING ||
6547 effective_action == ACTION_FILLING ||
6548 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
6549 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
6550 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
6551 int num_steps = (i == Ydrip_s1 ? 16 :
6552 i == Ydrip_s1B ? 16 :
6553 i == Ydrip_s2 ? 16 :
6554 i == Ydrip_s2B ? 16 :
6555 i == Xsand_stonein_1 ? 32 :
6556 i == Xsand_stonein_2 ? 32 :
6557 i == Xsand_stonein_3 ? 32 :
6558 i == Xsand_stonein_4 ? 32 :
6559 i == Xsand_stoneout_1 ? 16 :
6560 i == Xsand_stoneout_2 ? 16 : 8);
6561 int cx = ABS(dx) * (TILEX / num_steps);
6562 int cy = ABS(dy) * (TILEY / num_steps);
6563 int step_frame = (i == Ydrip_s2 ? j + 8 :
6564 i == Ydrip_s2B ? j + 8 :
6565 i == Xsand_stonein_2 ? j + 8 :
6566 i == Xsand_stonein_3 ? j + 16 :
6567 i == Xsand_stonein_4 ? j + 24 :
6568 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
6569 int step = (is_backside ? step_frame : num_steps - step_frame);
6571 if (is_backside) /* tile where movement starts */
6573 if (dx < 0 || dy < 0)
6575 g_em->src_offset_x = cx * step;
6576 g_em->src_offset_y = cy * step;
6580 g_em->dst_offset_x = cx * step;
6581 g_em->dst_offset_y = cy * step;
6584 else /* tile where movement ends */
6586 if (dx < 0 || dy < 0)
6588 g_em->dst_offset_x = cx * step;
6589 g_em->dst_offset_y = cy * step;
6593 g_em->src_offset_x = cx * step;
6594 g_em->src_offset_y = cy * step;
6598 g_em->width = TILEX - cx * step;
6599 g_em->height = TILEY - cy * step;
6602 /* create unique graphic identifier to decide if tile must be redrawn */
6603 /* bit 31 - 16 (16 bit): EM style graphic
6604 bit 15 - 12 ( 4 bit): EM style frame
6605 bit 11 - 6 ( 6 bit): graphic width
6606 bit 5 - 0 ( 6 bit): graphic height */
6607 g_em->unique_identifier =
6608 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
6612 /* skip check for EMC elements not contained in original EMC artwork */
6613 if (element == EL_EMC_FAKE_ACID)
6616 if (g_em->bitmap != debug_bitmap ||
6617 g_em->src_x != debug_src_x ||
6618 g_em->src_y != debug_src_y ||
6619 g_em->src_offset_x != 0 ||
6620 g_em->src_offset_y != 0 ||
6621 g_em->dst_offset_x != 0 ||
6622 g_em->dst_offset_y != 0 ||
6623 g_em->width != TILEX ||
6624 g_em->height != TILEY)
6626 static int last_i = -1;
6634 printf("::: EMC GFX ERROR for element %d -> %d ('%s', '%s', %d)",
6635 i, element, element_info[element].token_name,
6636 element_action_info[effective_action].suffix, direction);
6638 if (element != effective_element)
6639 printf(" [%d ('%s')]",
6641 element_info[effective_element].token_name);
6645 if (g_em->bitmap != debug_bitmap)
6646 printf(" %d (%d): different bitmap! (0x%08x != 0x%08x)\n",
6647 j, is_backside, (int)(g_em->bitmap), (int)(debug_bitmap));
6649 if (g_em->src_x != debug_src_x ||
6650 g_em->src_y != debug_src_y)
6651 printf(" frame %d (%c): %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
6652 j, (is_backside ? 'B' : 'F'),
6653 g_em->src_x, g_em->src_y,
6654 g_em->src_x / 32, g_em->src_y / 32,
6655 debug_src_x, debug_src_y,
6656 debug_src_x / 32, debug_src_y / 32);
6658 if (g_em->src_offset_x != 0 ||
6659 g_em->src_offset_y != 0 ||
6660 g_em->dst_offset_x != 0 ||
6661 g_em->dst_offset_y != 0)
6662 printf(" %d (%d): offsets %d,%d and %d,%d should be all 0\n",
6664 g_em->src_offset_x, g_em->src_offset_y,
6665 g_em->dst_offset_x, g_em->dst_offset_y);
6667 if (g_em->width != TILEX ||
6668 g_em->height != TILEY)
6669 printf(" %d (%d): size %d,%d should be %d,%d\n",
6671 g_em->width, g_em->height, TILEX, TILEY);
6673 num_em_gfx_errors++;
6680 for (i = 0; i < TILE_MAX; i++)
6682 for (j = 0; j < 8; j++)
6684 int element = object_mapping[i].element_rnd;
6685 int action = object_mapping[i].action;
6686 int direction = object_mapping[i].direction;
6687 boolean is_backside = object_mapping[i].is_backside;
6688 int graphic_action = el_act_dir2img(element, action, direction);
6689 int graphic_default = el_act_dir2img(element, ACTION_DEFAULT, direction);
6691 if ((action == ACTION_SMASHED_BY_ROCK ||
6692 action == ACTION_SMASHED_BY_SPRING ||
6693 action == ACTION_EATING) &&
6694 graphic_action == graphic_default)
6696 int e = (action == ACTION_SMASHED_BY_ROCK ? Ystone_s :
6697 action == ACTION_SMASHED_BY_SPRING ? Yspring_s :
6698 direction == MV_LEFT ? (is_backside? Yspring_wB: Yspring_w) :
6699 direction == MV_RIGHT ? (is_backside? Yspring_eB: Yspring_e) :
6702 /* no separate animation for "smashed by rock" -- use rock instead */
6703 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
6704 struct GraphicInfo_EM *g_xx = &graphic_info_em_object[e][7 - j];
6706 g_em->bitmap = g_xx->bitmap;
6707 g_em->src_x = g_xx->src_x;
6708 g_em->src_y = g_xx->src_y;
6709 g_em->src_offset_x = g_xx->src_offset_x;
6710 g_em->src_offset_y = g_xx->src_offset_y;
6711 g_em->dst_offset_x = g_xx->dst_offset_x;
6712 g_em->dst_offset_y = g_xx->dst_offset_y;
6713 g_em->width = g_xx->width;
6714 g_em->height = g_xx->height;
6715 g_em->unique_identifier = g_xx->unique_identifier;
6718 g_em->preserve_background = TRUE;
6723 for (p = 0; p < MAX_PLAYERS; p++)
6725 for (i = 0; i < SPR_MAX; i++)
6727 int element = player_mapping[p][i].element_rnd;
6728 int action = player_mapping[p][i].action;
6729 int direction = player_mapping[p][i].direction;
6731 for (j = 0; j < 8; j++)
6733 int effective_element = element;
6734 int effective_action = action;
6735 int graphic = (direction == MV_NONE ?
6736 el_act2img(effective_element, effective_action) :
6737 el_act_dir2img(effective_element, effective_action,
6739 struct GraphicInfo *g = &graphic_info[graphic];
6740 struct GraphicInfo_EM *g_em = &graphic_info_em_player[p][i][7 - j];
6746 Bitmap *debug_bitmap = g_em->bitmap;
6747 int debug_src_x = g_em->src_x;
6748 int debug_src_y = g_em->src_y;
6751 int frame = getAnimationFrame(g->anim_frames,
6754 g->anim_start_frame,
6757 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
6759 g_em->bitmap = src_bitmap;
6760 g_em->src_x = src_x;
6761 g_em->src_y = src_y;
6762 g_em->src_offset_x = 0;
6763 g_em->src_offset_y = 0;
6764 g_em->dst_offset_x = 0;
6765 g_em->dst_offset_y = 0;
6766 g_em->width = TILEX;
6767 g_em->height = TILEY;
6771 /* skip check for EMC elements not contained in original EMC artwork */
6772 if (element == EL_PLAYER_3 ||
6773 element == EL_PLAYER_4)
6776 if (g_em->bitmap != debug_bitmap ||
6777 g_em->src_x != debug_src_x ||
6778 g_em->src_y != debug_src_y)
6780 static int last_i = -1;
6788 printf("::: EMC GFX ERROR for p/a %d/%d -> %d ('%s', '%s', %d)",
6789 p, i, element, element_info[element].token_name,
6790 element_action_info[effective_action].suffix, direction);
6792 if (element != effective_element)
6793 printf(" [%d ('%s')]",
6795 element_info[effective_element].token_name);
6799 if (g_em->bitmap != debug_bitmap)
6800 printf(" %d: different bitmap! (0x%08x != 0x%08x)\n",
6801 j, (int)(g_em->bitmap), (int)(debug_bitmap));
6803 if (g_em->src_x != debug_src_x ||
6804 g_em->src_y != debug_src_y)
6805 printf(" frame %d: %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
6807 g_em->src_x, g_em->src_y,
6808 g_em->src_x / 32, g_em->src_y / 32,
6809 debug_src_x, debug_src_y,
6810 debug_src_x / 32, debug_src_y / 32);
6812 num_em_gfx_errors++;
6822 printf("::: [%d errors found]\n", num_em_gfx_errors);
6828 void PlayMenuSoundExt(int sound)
6830 if (sound == SND_UNDEFINED)
6833 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
6834 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
6837 if (IS_LOOP_SOUND(sound))
6838 PlaySoundLoop(sound);
6843 void PlayMenuSound()
6845 PlayMenuSoundExt(menu.sound[game_status]);
6848 void PlayMenuSoundStereo(int sound, int stereo_position)
6850 if (sound == SND_UNDEFINED)
6853 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
6854 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
6857 if (IS_LOOP_SOUND(sound))
6858 PlaySoundExt(sound, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_LOOP);
6860 PlaySoundStereo(sound, stereo_position);
6863 void PlayMenuSoundIfLoopExt(int sound)
6865 if (sound == SND_UNDEFINED)
6868 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
6869 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
6872 if (IS_LOOP_SOUND(sound))
6873 PlaySoundLoop(sound);
6876 void PlayMenuSoundIfLoop()
6878 PlayMenuSoundIfLoopExt(menu.sound[game_status]);
6881 void PlayMenuMusicExt(int music)
6883 if (music == MUS_UNDEFINED)
6886 if (!setup.sound_music)
6892 void PlayMenuMusic()
6894 PlayMenuMusicExt(menu.music[game_status]);
6897 void PlaySoundActivating()
6900 PlaySound(SND_MENU_ITEM_ACTIVATING);
6904 void PlaySoundSelecting()
6907 PlaySound(SND_MENU_ITEM_SELECTING);
6911 void ToggleFullscreenIfNeeded()
6913 boolean change_fullscreen = (setup.fullscreen !=
6914 video.fullscreen_enabled);
6915 boolean change_fullscreen_mode = (video.fullscreen_enabled &&
6916 !strEqual(setup.fullscreen_mode,
6917 video.fullscreen_mode_current));
6919 if (!video.fullscreen_available)
6923 if (change_fullscreen || change_fullscreen_mode)
6925 if (setup.fullscreen != video.fullscreen_enabled ||
6926 setup.fullscreen_mode != video.fullscreen_mode_current)
6929 Bitmap *tmp_backbuffer = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
6931 /* save backbuffer content which gets lost when toggling fullscreen mode */
6932 BlitBitmap(backbuffer, tmp_backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
6935 if (change_fullscreen_mode)
6937 if (setup.fullscreen && video.fullscreen_enabled)
6940 /* keep fullscreen, but change fullscreen mode (screen resolution) */
6942 /* (this is now set in sdl.c) */
6944 video.fullscreen_mode_current = setup.fullscreen_mode;
6946 video.fullscreen_enabled = FALSE; /* force new fullscreen mode */
6949 /* toggle fullscreen */
6950 ChangeVideoModeIfNeeded(setup.fullscreen);
6952 setup.fullscreen = video.fullscreen_enabled;
6954 /* restore backbuffer content from temporary backbuffer backup bitmap */
6955 BlitBitmap(tmp_backbuffer, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
6957 FreeBitmap(tmp_backbuffer);
6960 /* update visible window/screen */
6961 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
6963 redraw_mask = REDRAW_ALL;