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 (game_status >= GAME_MODE_TITLE &&
209 game_status <= GAME_MODE_PLAYING &&
210 border.draw_masked[game_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 (game_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 game_status != GAME_MODE_EDITOR)
226 DrawMaskedBorder_Rect(VX, VY, VXSIZE, VYSIZE);
229 void DrawMaskedBorder_DOOR_3()
231 /* currently not available */
234 void DrawMaskedBorder_ALL()
236 DrawMaskedBorder_FIELD();
237 DrawMaskedBorder_DOOR_1();
238 DrawMaskedBorder_DOOR_2();
239 DrawMaskedBorder_DOOR_3();
242 void DrawMaskedBorder(int redraw_mask)
244 /* do not draw masked screen borders when displaying title screens */
245 if (effectiveGameStatus() == GAME_MODE_TITLE)
248 if (redraw_mask & REDRAW_ALL)
249 DrawMaskedBorder_ALL();
252 if (redraw_mask & REDRAW_FIELD)
253 DrawMaskedBorder_FIELD();
254 if (redraw_mask & REDRAW_DOOR_1)
255 DrawMaskedBorder_DOOR_1();
256 if (redraw_mask & REDRAW_DOOR_2)
257 DrawMaskedBorder_DOOR_2();
258 if (redraw_mask & REDRAW_DOOR_3)
259 DrawMaskedBorder_DOOR_3();
266 DrawBuffer *buffer = (drawto_field == window ? backbuffer : drawto_field);
268 if (setup.direct_draw && game_status == GAME_MODE_PLAYING)
269 redraw_mask &= ~REDRAW_MAIN;
271 if (redraw_mask & REDRAW_TILES && redraw_tiles > REDRAWTILES_THRESHOLD)
272 redraw_mask |= REDRAW_FIELD;
274 if (redraw_mask & REDRAW_FIELD)
275 redraw_mask &= ~REDRAW_TILES;
277 if (redraw_mask == REDRAW_NONE)
280 if (redraw_mask & REDRAW_TILES &&
281 game_status == GAME_MODE_PLAYING &&
282 border.draw_masked[GAME_MODE_PLAYING])
283 redraw_mask |= REDRAW_FIELD;
285 if (global.fps_slowdown && game_status == GAME_MODE_PLAYING)
287 static boolean last_frame_skipped = FALSE;
288 boolean skip_even_when_not_scrolling = TRUE;
289 boolean just_scrolling = (ScreenMovDir != 0);
290 boolean verbose = FALSE;
292 if (global.fps_slowdown_factor > 1 &&
293 (FrameCounter % global.fps_slowdown_factor) &&
294 (just_scrolling || skip_even_when_not_scrolling))
296 redraw_mask &= ~REDRAW_MAIN;
298 last_frame_skipped = TRUE;
301 printf("FRAME SKIPPED\n");
305 if (last_frame_skipped)
306 redraw_mask |= REDRAW_FIELD;
308 last_frame_skipped = FALSE;
311 printf("frame not skipped\n");
315 /* synchronize X11 graphics at this point; if we would synchronize the
316 display immediately after the buffer switching (after the XFlush),
317 this could mean that we have to wait for the graphics to complete,
318 although we could go on doing calculations for the next frame */
322 /* prevent drawing masked border to backbuffer when using playfield buffer */
323 if (game_status != GAME_MODE_PLAYING ||
324 redraw_mask & REDRAW_FROM_BACKBUFFER ||
325 buffer == backbuffer)
326 DrawMaskedBorder(redraw_mask);
328 DrawMaskedBorder(redraw_mask & REDRAW_DOORS);
330 if (redraw_mask & REDRAW_ALL)
332 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
334 redraw_mask = REDRAW_NONE;
337 if (redraw_mask & REDRAW_FIELD)
339 if (game_status != GAME_MODE_PLAYING ||
340 redraw_mask & REDRAW_FROM_BACKBUFFER)
342 BlitBitmap(backbuffer, window,
343 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE, REAL_SX, REAL_SY);
347 int fx = FX, fy = FY;
349 if (setup.soft_scrolling)
351 fx += (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
352 fy += (ScreenMovDir & (MV_UP | MV_DOWN) ? ScreenGfxPos : 0);
355 if (setup.soft_scrolling ||
356 ABS(ScreenMovPos) + ScrollStepSize == TILEX ||
357 ABS(ScreenMovPos) == ScrollStepSize ||
358 redraw_tiles > REDRAWTILES_THRESHOLD)
360 if (border.draw_masked[GAME_MODE_PLAYING])
362 if (buffer != backbuffer)
364 /* copy playfield buffer to backbuffer to add masked border */
365 BlitBitmap(buffer, backbuffer, fx, fy, SXSIZE, SYSIZE, SX, SY);
366 DrawMaskedBorder(REDRAW_FIELD);
369 BlitBitmap(backbuffer, window,
370 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
375 BlitBitmap(buffer, window, fx, fy, SXSIZE, SYSIZE, SX, SY);
380 printf("redrawing all (ScreenGfxPos == %d) because %s\n",
382 (setup.soft_scrolling ?
383 "setup.soft_scrolling" :
384 ABS(ScreenGfxPos) + ScrollStepSize == TILEX ?
385 "ABS(ScreenGfxPos) + ScrollStepSize == TILEX" :
386 ABS(ScreenGfxPos) == ScrollStepSize ?
387 "ABS(ScreenGfxPos) == ScrollStepSize" :
388 "redraw_tiles > REDRAWTILES_THRESHOLD"));
394 redraw_mask &= ~REDRAW_MAIN;
397 if (redraw_mask & REDRAW_DOORS)
399 if (redraw_mask & REDRAW_DOOR_1)
400 BlitBitmap(backbuffer, window, DX, DY, DXSIZE, DYSIZE, DX, DY);
402 if (redraw_mask & REDRAW_DOOR_2)
403 BlitBitmap(backbuffer, window, VX, VY, VXSIZE, VYSIZE, VX, VY);
405 if (redraw_mask & REDRAW_DOOR_3)
406 BlitBitmap(backbuffer, window, EX, EY, EXSIZE, EYSIZE, EX, EY);
408 redraw_mask &= ~REDRAW_DOORS;
411 if (redraw_mask & REDRAW_MICROLEVEL)
413 BlitBitmap(backbuffer, window, SX, SY + 10 * TILEY, SXSIZE, 7 * TILEY,
414 SX, SY + 10 * TILEY);
416 redraw_mask &= ~REDRAW_MICROLEVEL;
419 if (redraw_mask & REDRAW_TILES)
421 for (x = 0; x < SCR_FIELDX; x++)
422 for (y = 0 ; y < SCR_FIELDY; y++)
423 if (redraw[redraw_x1 + x][redraw_y1 + y])
424 BlitBitmap(buffer, window,
425 FX + x * TILEX, FY + y * TILEY, TILEX, TILEY,
426 SX + x * TILEX, SY + y * TILEY);
429 if (redraw_mask & REDRAW_FPS) /* display frames per second */
434 sprintf(info1, " (only every %d. frame)", global.fps_slowdown_factor);
435 if (!global.fps_slowdown)
438 sprintf(text, "%.1f fps%s", global.frames_per_second, info1);
439 DrawTextExt(window, SX, SY, text, FONT_TEXT_2, BLIT_OPAQUE);
444 for (x = 0; x < MAX_BUF_XSIZE; x++)
445 for (y = 0; y < MAX_BUF_YSIZE; y++)
448 redraw_mask = REDRAW_NONE;
454 long fading_delay = 300;
456 if (setup.fading && (redraw_mask & REDRAW_FIELD))
463 ClearRectangle(window, REAL_SX,REAL_SY,FULL_SXSIZE,FULL_SYSIZE);
466 for (i = 0; i < 2 * FULL_SYSIZE; i++)
468 for (y = 0; y < FULL_SYSIZE; y++)
470 BlitBitmap(backbuffer, window,
471 REAL_SX,REAL_SY+i, FULL_SXSIZE,1, REAL_SX,REAL_SY+i);
479 for (i = 1; i < FULL_SYSIZE; i+=2)
480 BlitBitmap(backbuffer, window,
481 REAL_SX,REAL_SY+i, FULL_SXSIZE,1, REAL_SX,REAL_SY+i);
487 SetClipOrigin(clip_gc[PIX_FADEMASK], 0, 0);
488 BlitBitmapMasked(backbuffer, window,
489 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
494 SetClipOrigin(clip_gc[PIX_FADEMASK], -1, -1);
495 BlitBitmapMasked(backbuffer, window,
496 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
501 SetClipOrigin(clip_gc[PIX_FADEMASK], 0, -1);
502 BlitBitmapMasked(backbuffer, window,
503 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
508 SetClipOrigin(clip_gc[PIX_FADEMASK], -1, 0);
509 BlitBitmapMasked(backbuffer, window,
510 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
515 redraw_mask &= ~REDRAW_MAIN;
522 void FadeExt(int fade_mask, int fade_mode)
524 static int fade_mode_skip = FADE_MODE_NONE;
525 void (*draw_border_function)(void) = NULL;
527 Bitmap *bitmap = (fade_mode != FADE_MODE_FADE_IN ? bitmap_db_cross : NULL);
529 Bitmap *bitmap = (fade_mode & FADE_TYPE_TRANSFORM ? bitmap_db_cross : NULL);
531 int x, y, width, height;
532 int fade_delay, post_delay;
534 redraw_mask |= fade_mask;
536 if (fade_mode & FADE_TYPE_SKIP)
539 printf("::: will skip %d ... [%d]\n", fade_mode, fade_mode_skip);
542 fade_mode_skip = fade_mode;
547 if (fade_mode_skip & FADE_TYPE_SKIP)
550 printf("::: skipping %d ... [%d]\n", fade_mode, fade_mode_skip);
553 /* skip all fade operations until specified fade operation */
554 if (fade_mode & fade_mode_skip)
555 fade_mode_skip = FADE_MODE_NONE;
561 if (global.autoplay_leveldir)
563 // fading.fade_mode = FADE_MODE_NONE;
570 if (fading.fade_mode == FADE_MODE_NONE)
578 if (fade_mask & REDRAW_FIELD)
583 height = FULL_SYSIZE;
585 fade_delay = fading.fade_delay;
586 post_delay = (fade_mode == FADE_MODE_FADE_OUT ? fading.post_delay : 0);
588 draw_border_function = DrawMaskedBorder_FIELD;
590 else /* REDRAW_ALL */
597 fade_delay = fading.fade_delay;
598 post_delay = (fade_mode == FADE_MODE_FADE_OUT ? fading.post_delay : 0);
602 if (!setup.fade_screens || fade_delay == 0)
604 if (!setup.fade_screens || fade_delay == 0 || fading.anim_mode == ANIM_NONE)
607 if (fade_mode == FADE_MODE_FADE_OUT)
608 ClearRectangle(backbuffer, x, y, width, height);
615 FadeRectangle(bitmap, x, y, width, height, fade_mode, fade_delay, post_delay,
616 draw_border_function);
618 redraw_mask &= ~fade_mask;
621 void FadeIn(int fade_mask)
624 // printf("::: now fading in...\n");
626 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
627 FadeExt(fade_mask, fading.fade_mode);
629 FadeExt(fade_mask, FADE_MODE_FADE_IN);
632 if (fading.fade_mode == FADE_MODE_CROSSFADE)
633 FadeExt(fade_mask, FADE_MODE_CROSSFADE);
635 FadeExt(fade_mask, FADE_MODE_FADE_IN);
637 FadeExt(fade_mask, FADE_MODE_FADE_IN);
642 void FadeOut(int fade_mask)
645 // printf("::: fading.fade_mode == %d\n", fading.fade_mode);
647 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
648 FadeCrossSaveBackbuffer();
650 FadeExt(fade_mask, FADE_MODE_FADE_OUT);
653 if (fading.fade_mode == FADE_MODE_CROSSFADE)
654 FadeCrossSaveBackbuffer();
656 FadeExt(fade_mask, FADE_MODE_FADE_OUT);
658 FadeExt(fade_mask, FADE_MODE_FADE_OUT);
663 void FadeCross(int fade_mask)
665 FadeExt(fade_mask, FADE_MODE_CROSSFADE);
668 void FadeCrossSaveBackbuffer()
670 BlitBitmap(backbuffer, bitmap_db_cross, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
673 static void FadeSetLeaveNext(struct TitleFadingInfo fading_leave, boolean set)
675 static struct TitleFadingInfo fading_leave_stored;
678 fading_leave_stored = fading_leave;
680 fading = fading_leave_stored;
683 void FadeSetEnterMenu()
685 fading = menu.enter_menu;
687 FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
690 void FadeSetLeaveMenu()
692 fading = menu.leave_menu;
694 FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
697 void FadeSetEnterScreen()
699 fading = menu.enter_screen[game_status];
701 FadeSetLeaveNext(menu.leave_screen[game_status], TRUE); /* store */
704 void FadeSetLeaveScreen()
706 FadeSetLeaveNext(menu.leave_screen[game_status], FALSE); /* recall */
709 void FadeSetFromType(int type)
711 if (type & TYPE_ENTER_SCREEN)
712 FadeSetEnterScreen();
713 else if (type & TYPE_ENTER)
715 else if (type & TYPE_LEAVE)
719 void FadeSetDisabled()
721 static struct TitleFadingInfo fading_none = { FADE_MODE_NONE, -1, -1, -1 };
723 fading = fading_none;
726 void FadeSkipNextFadeIn()
728 FadeExt(0, FADE_MODE_SKIP_FADE_IN);
731 void FadeSkipNextFadeOut()
733 FadeExt(0, FADE_MODE_SKIP_FADE_OUT);
736 void SetWindowBackgroundImageIfDefined(int graphic)
738 if (graphic_info[graphic].bitmap)
739 SetWindowBackgroundBitmap(graphic_info[graphic].bitmap);
742 void SetMainBackgroundImageIfDefined(int graphic)
744 if (graphic_info[graphic].bitmap)
745 SetMainBackgroundBitmap(graphic_info[graphic].bitmap);
748 void SetDoorBackgroundImageIfDefined(int graphic)
750 if (graphic_info[graphic].bitmap)
751 SetDoorBackgroundBitmap(graphic_info[graphic].bitmap);
754 void SetWindowBackgroundImage(int graphic)
756 SetWindowBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
757 graphic_info[graphic].bitmap ?
758 graphic_info[graphic].bitmap :
759 graphic_info[IMG_BACKGROUND].bitmap);
762 void SetMainBackgroundImage(int graphic)
764 SetMainBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
765 graphic_info[graphic].bitmap ?
766 graphic_info[graphic].bitmap :
767 graphic_info[IMG_BACKGROUND].bitmap);
770 void SetDoorBackgroundImage(int graphic)
772 SetDoorBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
773 graphic_info[graphic].bitmap ?
774 graphic_info[graphic].bitmap :
775 graphic_info[IMG_BACKGROUND].bitmap);
778 void SetPanelBackground()
780 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, bitmap_db_panel,
781 DOOR_GFX_PAGEX5, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE, 0, 0);
783 SetDoorBackgroundBitmap(bitmap_db_panel);
786 void DrawBackground(int x, int y, int width, int height)
788 /* !!! "drawto" might still point to playfield buffer here (see below) !!! */
789 /* (when entering hall of fame after playing) */
791 ClearRectangleOnBackground(drawto, x, y, width, height);
793 ClearRectangleOnBackground(backbuffer, x, y, width, height);
796 redraw_mask |= REDRAW_FIELD;
799 void DrawBackgroundForFont(int x, int y, int width, int height, int font_nr)
801 struct FontBitmapInfo *font = getFontBitmapInfo(font_nr);
803 if (font->bitmap == NULL)
806 DrawBackground(x, y, width, height);
809 void DrawBackgroundForGraphic(int x, int y, int width, int height, int graphic)
811 struct GraphicInfo *g = &graphic_info[graphic];
813 if (g->bitmap == NULL)
816 DrawBackground(x, y, width, height);
821 /* !!! "drawto" might still point to playfield buffer here (see above) !!! */
822 /* (when entering hall of fame after playing) */
823 DrawBackground(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
825 /* !!! maybe this should be done before clearing the background !!! */
826 if (setup.soft_scrolling && game_status == GAME_MODE_PLAYING)
828 ClearRectangle(fieldbuffer, 0, 0, FXSIZE, FYSIZE);
829 SetDrawtoField(DRAW_BUFFERED);
832 SetDrawtoField(DRAW_BACKBUFFER);
834 if (setup.direct_draw && game_status == GAME_MODE_PLAYING)
836 ClearRectangle(window, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
837 SetDrawtoField(DRAW_DIRECT);
841 void MarkTileDirty(int x, int y)
843 int xx = redraw_x1 + x;
844 int yy = redraw_y1 + y;
849 redraw[xx][yy] = TRUE;
850 redraw_mask |= REDRAW_TILES;
853 void SetBorderElement()
857 BorderElement = EL_EMPTY;
859 for (y = 0; y < lev_fieldy && BorderElement == EL_EMPTY; y++)
861 for (x = 0; x < lev_fieldx; x++)
863 if (!IS_INDESTRUCTIBLE(Feld[x][y]))
864 BorderElement = EL_STEELWALL;
866 if (y != 0 && y != lev_fieldy - 1 && x != lev_fieldx - 1)
872 void FloodFillLevel(int from_x, int from_y, int fill_element,
873 short field[MAX_LEV_FIELDX][MAX_LEV_FIELDY],
874 int max_fieldx, int max_fieldy)
878 static int check[4][2] = { { -1, 0 }, { 0, -1 }, { 1, 0 }, { 0, 1 } };
879 static int safety = 0;
881 /* check if starting field still has the desired content */
882 if (field[from_x][from_y] == fill_element)
887 if (safety > max_fieldx * max_fieldy)
888 Error(ERR_EXIT, "Something went wrong in 'FloodFill()'. Please debug.");
890 old_element = field[from_x][from_y];
891 field[from_x][from_y] = fill_element;
893 for (i = 0; i < 4; i++)
895 x = from_x + check[i][0];
896 y = from_y + check[i][1];
898 if (IN_FIELD(x, y, max_fieldx, max_fieldy) && field[x][y] == old_element)
899 FloodFillLevel(x, y, fill_element, field, max_fieldx, max_fieldy);
905 void SetRandomAnimationValue(int x, int y)
907 gfx.anim_random_frame = GfxRandom[x][y];
910 inline int getGraphicAnimationFrame(int graphic, int sync_frame)
912 /* animation synchronized with global frame counter, not move position */
913 if (graphic_info[graphic].anim_global_sync || sync_frame < 0)
914 sync_frame = FrameCounter;
916 return getAnimationFrame(graphic_info[graphic].anim_frames,
917 graphic_info[graphic].anim_delay,
918 graphic_info[graphic].anim_mode,
919 graphic_info[graphic].anim_start_frame,
923 void getSizedGraphicSource(int graphic, int frame, int tilesize_raw,
924 Bitmap **bitmap, int *x, int *y)
928 int width_mult, width_div;
929 int height_mult, height_div;
933 { 15, 16, 2, 3 }, /* 1 x 1 */
934 { 7, 8, 2, 3 }, /* 2 x 2 */
935 { 3, 4, 2, 3 }, /* 4 x 4 */
936 { 1, 2, 2, 3 }, /* 8 x 8 */
937 { 0, 1, 2, 3 }, /* 16 x 16 */
938 { 0, 1, 0, 1 }, /* 32 x 32 */
940 struct GraphicInfo *g = &graphic_info[graphic];
941 Bitmap *src_bitmap = g->bitmap;
942 int tilesize = MIN(MAX(1, tilesize_raw), TILESIZE);
943 int offset_calc_pos = log_2(tilesize);
944 int width_mult = offset_calc[offset_calc_pos].width_mult;
945 int width_div = offset_calc[offset_calc_pos].width_div;
946 int height_mult = offset_calc[offset_calc_pos].height_mult;
947 int height_div = offset_calc[offset_calc_pos].height_div;
948 int startx = src_bitmap->width * width_mult / width_div;
949 int starty = src_bitmap->height * height_mult / height_div;
950 int src_x = g->src_x * tilesize / TILESIZE;
951 int src_y = g->src_y * tilesize / TILESIZE;
952 int width = g->width * tilesize / TILESIZE;
953 int height = g->height * tilesize / TILESIZE;
954 int offset_x = g->offset_x * tilesize / TILESIZE;
955 int offset_y = g->offset_y * tilesize / TILESIZE;
957 if (g->offset_y == 0) /* frames are ordered horizontally */
959 int max_width = g->anim_frames_per_line * width;
960 int pos = (src_y / height) * max_width + src_x + frame * offset_x;
962 src_x = pos % max_width;
963 src_y = src_y % height + pos / max_width * height;
965 else if (g->offset_x == 0) /* frames are ordered vertically */
967 int max_height = g->anim_frames_per_line * height;
968 int pos = (src_x / width) * max_height + src_y + frame * offset_y;
970 src_x = src_x % width + pos / max_height * width;
971 src_y = pos % max_height;
973 else /* frames are ordered diagonally */
975 src_x = src_x + frame * offset_x;
976 src_y = src_y + frame * offset_y;
979 *bitmap = src_bitmap;
984 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
987 getSizedGraphicSource(graphic, 0, MINI_TILESIZE, bitmap, x, y);
989 struct GraphicInfo *g = &graphic_info[graphic];
991 int mini_starty = g->bitmap->height * 2 / 3;
994 *x = mini_startx + g->src_x / 2;
995 *y = mini_starty + g->src_y / 2;
999 inline void getGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
1000 int *x, int *y, boolean get_backside)
1002 struct GraphicInfo *g = &graphic_info[graphic];
1003 int src_x = g->src_x + (get_backside ? g->offset2_x : 0);
1004 int src_y = g->src_y + (get_backside ? g->offset2_y : 0);
1006 *bitmap = g->bitmap;
1008 if (g->offset_y == 0) /* frames are ordered horizontally */
1010 int max_width = g->anim_frames_per_line * g->width;
1011 int pos = (src_y / g->height) * max_width + src_x + frame * g->offset_x;
1013 *x = pos % max_width;
1014 *y = src_y % g->height + pos / max_width * g->height;
1016 else if (g->offset_x == 0) /* frames are ordered vertically */
1018 int max_height = g->anim_frames_per_line * g->height;
1019 int pos = (src_x / g->width) * max_height + src_y + frame * g->offset_y;
1021 *x = src_x % g->width + pos / max_height * g->width;
1022 *y = pos % max_height;
1024 else /* frames are ordered diagonally */
1026 *x = src_x + frame * g->offset_x;
1027 *y = src_y + frame * g->offset_y;
1031 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
1033 getGraphicSourceExt(graphic, frame, bitmap, x, y, FALSE);
1036 void DrawGraphic(int x, int y, int graphic, int frame)
1039 if (!IN_SCR_FIELD(x, y))
1041 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
1042 printf("DrawGraphic(): This should never happen!\n");
1047 DrawGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic, frame);
1048 MarkTileDirty(x, y);
1051 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
1057 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1058 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
1061 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
1064 if (!IN_SCR_FIELD(x, y))
1066 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
1067 printf("DrawGraphicThruMask(): This should never happen!\n");
1072 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y *TILEY, graphic,
1074 MarkTileDirty(x, y);
1077 void DrawGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y, int graphic,
1083 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1085 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1086 dst_x - src_x, dst_y - src_y);
1087 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dst_x, dst_y);
1090 void DrawSizedGraphic(int x, int y, int graphic, int frame, int tilesize)
1092 DrawSizedGraphicExt(drawto, SX + x * tilesize, SY + y * tilesize, graphic,
1094 MarkTileDirty(x / tilesize, y / tilesize);
1097 void DrawSizedGraphicExt(DrawBuffer *d, int x, int y, int graphic, int frame,
1103 getSizedGraphicSource(graphic, frame, tilesize, &src_bitmap, &src_x, &src_y);
1104 BlitBitmap(src_bitmap, d, src_x, src_y, tilesize, tilesize, x, y);
1107 void DrawMiniGraphic(int x, int y, int graphic)
1109 DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
1110 MarkTileDirty(x / 2, y / 2);
1113 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
1118 getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1119 BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
1122 inline static void DrawGraphicShiftedNormal(int x, int y, int dx, int dy,
1123 int graphic, int frame,
1124 int cut_mode, int mask_mode)
1129 int width = TILEX, height = TILEY;
1132 if (dx || dy) /* shifted graphic */
1134 if (x < BX1) /* object enters playfield from the left */
1141 else if (x > BX2) /* object enters playfield from the right */
1147 else if (x==BX1 && dx < 0) /* object leaves playfield to the left */
1153 else if (x==BX2 && dx > 0) /* object leaves playfield to the right */
1155 else if (dx) /* general horizontal movement */
1156 MarkTileDirty(x + SIGN(dx), y);
1158 if (y < BY1) /* object enters playfield from the top */
1160 if (cut_mode==CUT_BELOW) /* object completely above top border */
1168 else if (y > BY2) /* object enters playfield from the bottom */
1174 else if (y==BY1 && dy < 0) /* object leaves playfield to the top */
1180 else if (dy > 0 && cut_mode == CUT_ABOVE)
1182 if (y == BY2) /* object completely above bottom border */
1188 MarkTileDirty(x, y + 1);
1189 } /* object leaves playfield to the bottom */
1190 else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
1192 else if (dy) /* general vertical movement */
1193 MarkTileDirty(x, y + SIGN(dy));
1197 if (!IN_SCR_FIELD(x, y))
1199 printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
1200 printf("DrawGraphicShifted(): This should never happen!\n");
1205 if (width > 0 && height > 0)
1207 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1212 dst_x = FX + x * TILEX + dx;
1213 dst_y = FY + y * TILEY + dy;
1215 if (mask_mode == USE_MASKING)
1217 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1218 dst_x - src_x, dst_y - src_y);
1219 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1223 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1226 MarkTileDirty(x, y);
1230 inline static void DrawGraphicShiftedDouble(int x, int y, int dx, int dy,
1231 int graphic, int frame,
1232 int cut_mode, int mask_mode)
1237 int width = TILEX, height = TILEY;
1240 int x2 = x + SIGN(dx);
1241 int y2 = y + SIGN(dy);
1242 int anim_frames = graphic_info[graphic].anim_frames;
1243 int sync_frame = (dx ? ABS(dx) : ABS(dy)) * anim_frames / TILESIZE;
1244 boolean draw_start_tile = (cut_mode != CUT_ABOVE); /* only for falling! */
1245 boolean draw_end_tile = (cut_mode != CUT_BELOW); /* only for falling! */
1247 /* re-calculate animation frame for two-tile movement animation */
1248 frame = getGraphicAnimationFrame(graphic, sync_frame);
1250 /* check if movement start graphic inside screen area and should be drawn */
1251 if (draw_start_tile && IN_SCR_FIELD(x1, y1))
1253 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, TRUE);
1255 dst_x = FX + x1 * TILEX;
1256 dst_y = FY + y1 * TILEY;
1258 if (mask_mode == USE_MASKING)
1260 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1261 dst_x - src_x, dst_y - src_y);
1262 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1266 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1269 MarkTileDirty(x1, y1);
1272 /* check if movement end graphic inside screen area and should be drawn */
1273 if (draw_end_tile && IN_SCR_FIELD(x2, y2))
1275 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
1277 dst_x = FX + x2 * TILEX;
1278 dst_y = FY + y2 * TILEY;
1280 if (mask_mode == USE_MASKING)
1282 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1283 dst_x - src_x, dst_y - src_y);
1284 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1288 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1291 MarkTileDirty(x2, y2);
1295 static void DrawGraphicShifted(int x, int y, int dx, int dy,
1296 int graphic, int frame,
1297 int cut_mode, int mask_mode)
1301 DrawGraphic(x, y, graphic, frame);
1306 if (graphic_info[graphic].double_movement) /* EM style movement images */
1307 DrawGraphicShiftedDouble(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1309 DrawGraphicShiftedNormal(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1312 void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
1313 int frame, int cut_mode)
1315 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, USE_MASKING);
1318 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
1319 int cut_mode, int mask_mode)
1321 int lx = LEVELX(x), ly = LEVELY(y);
1325 if (IN_LEV_FIELD(lx, ly))
1327 SetRandomAnimationValue(lx, ly);
1329 graphic = el_act_dir2img(element, GfxAction[lx][ly], GfxDir[lx][ly]);
1330 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1332 /* do not use double (EM style) movement graphic when not moving */
1333 if (graphic_info[graphic].double_movement && !dx && !dy)
1335 graphic = el_act_dir2img(element, ACTION_DEFAULT, GfxDir[lx][ly]);
1336 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1339 else /* border element */
1341 graphic = el2img(element);
1342 frame = getGraphicAnimationFrame(graphic, -1);
1345 if (element == EL_EXPANDABLE_WALL)
1347 boolean left_stopped = FALSE, right_stopped = FALSE;
1349 if (!IN_LEV_FIELD(lx - 1, ly) || IS_WALL(Feld[lx - 1][ly]))
1350 left_stopped = TRUE;
1351 if (!IN_LEV_FIELD(lx + 1, ly) || IS_WALL(Feld[lx + 1][ly]))
1352 right_stopped = TRUE;
1354 if (left_stopped && right_stopped)
1356 else if (left_stopped)
1358 graphic = IMG_EXPANDABLE_WALL_GROWING_RIGHT;
1359 frame = graphic_info[graphic].anim_frames - 1;
1361 else if (right_stopped)
1363 graphic = IMG_EXPANDABLE_WALL_GROWING_LEFT;
1364 frame = graphic_info[graphic].anim_frames - 1;
1369 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
1370 else if (mask_mode == USE_MASKING)
1371 DrawGraphicThruMask(x, y, graphic, frame);
1373 DrawGraphic(x, y, graphic, frame);
1376 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
1377 int cut_mode, int mask_mode)
1379 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1380 DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
1381 cut_mode, mask_mode);
1384 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
1387 DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1390 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
1393 DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1396 void DrawLevelElementThruMask(int x, int y, int element)
1398 DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1401 void DrawLevelFieldThruMask(int x, int y)
1403 DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
1406 static void DrawLevelFieldCrumbledSandExt(int x, int y, int graphic, int frame)
1410 int sx = SCREENX(x), sy = SCREENY(y);
1412 int width, height, cx, cy, i;
1413 int crumbled_border_size = graphic_info[graphic].border_size;
1414 static int xy[4][2] =
1422 if (!IN_LEV_FIELD(x, y))
1425 element = TILE_GFX_ELEMENT(x, y);
1427 /* crumble field itself */
1428 if (GFX_CRUMBLED(element) && !IS_MOVING(x, y))
1430 if (!IN_SCR_FIELD(sx, sy))
1433 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1435 for (i = 0; i < 4; i++)
1437 int xx = x + xy[i][0];
1438 int yy = y + xy[i][1];
1440 element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1443 /* check if neighbour field is of same type */
1444 if (GFX_CRUMBLED(element) && !IS_MOVING(xx, yy))
1447 if (i == 1 || i == 2)
1449 width = crumbled_border_size;
1451 cx = (i == 2 ? TILEX - crumbled_border_size : 0);
1457 height = crumbled_border_size;
1459 cy = (i == 3 ? TILEY - crumbled_border_size : 0);
1462 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1463 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
1466 MarkTileDirty(sx, sy);
1468 else /* crumble neighbour fields */
1470 for (i = 0; i < 4; i++)
1472 int xx = x + xy[i][0];
1473 int yy = y + xy[i][1];
1474 int sxx = sx + xy[i][0];
1475 int syy = sy + xy[i][1];
1477 if (!IN_LEV_FIELD(xx, yy) ||
1478 !IN_SCR_FIELD(sxx, syy) ||
1482 if (Feld[xx][yy] == EL_ELEMENT_SNAPPING)
1485 element = TILE_GFX_ELEMENT(xx, yy);
1487 if (!GFX_CRUMBLED(element))
1490 graphic = el_act2crm(element, ACTION_DEFAULT);
1491 crumbled_border_size = graphic_info[graphic].border_size;
1493 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1495 if (i == 1 || i == 2)
1497 width = crumbled_border_size;
1499 cx = (i == 1 ? TILEX - crumbled_border_size : 0);
1505 height = crumbled_border_size;
1507 cy = (i == 0 ? TILEY - crumbled_border_size : 0);
1510 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1511 width, height, FX + sxx * TILEX + cx, FY + syy * TILEY + cy);
1513 MarkTileDirty(sxx, syy);
1518 void DrawLevelFieldCrumbledSand(int x, int y)
1522 if (!IN_LEV_FIELD(x, y))
1526 /* !!! CHECK THIS !!! */
1529 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
1530 GFX_CRUMBLED(GfxElement[x][y]))
1533 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
1534 GfxElement[x][y] != EL_UNDEFINED &&
1535 GFX_CRUMBLED(GfxElement[x][y]))
1537 DrawLevelFieldCrumbledSandDigging(x, y, GfxDir[x][y], GfxFrame[x][y]);
1544 graphic = el_act2crm(TILE_GFX_ELEMENT(x, y), ACTION_DEFAULT);
1546 graphic = el_act2crm(Feld[x][y], ACTION_DEFAULT);
1549 DrawLevelFieldCrumbledSandExt(x, y, graphic, 0);
1552 void DrawLevelFieldCrumbledSandDigging(int x, int y, int direction,
1555 int graphic1 = el_act_dir2img(GfxElement[x][y], ACTION_DIGGING, direction);
1556 int graphic2 = el_act_dir2crm(GfxElement[x][y], ACTION_DIGGING, direction);
1557 int frame1 = getGraphicAnimationFrame(graphic1, step_frame);
1558 int frame2 = getGraphicAnimationFrame(graphic2, step_frame);
1559 int sx = SCREENX(x), sy = SCREENY(y);
1561 DrawGraphic(sx, sy, graphic1, frame1);
1562 DrawLevelFieldCrumbledSandExt(x, y, graphic2, frame2);
1565 void DrawLevelFieldCrumbledSandNeighbours(int x, int y)
1567 int sx = SCREENX(x), sy = SCREENY(y);
1568 static int xy[4][2] =
1577 for (i = 0; i < 4; i++)
1579 int xx = x + xy[i][0];
1580 int yy = y + xy[i][1];
1581 int sxx = sx + xy[i][0];
1582 int syy = sy + xy[i][1];
1584 if (!IN_LEV_FIELD(xx, yy) ||
1585 !IN_SCR_FIELD(sxx, syy) ||
1586 !GFX_CRUMBLED(Feld[xx][yy]) ||
1590 DrawLevelField(xx, yy);
1594 static int getBorderElement(int x, int y)
1598 { EL_STEELWALL_TOPLEFT, EL_INVISIBLE_STEELWALL_TOPLEFT },
1599 { EL_STEELWALL_TOPRIGHT, EL_INVISIBLE_STEELWALL_TOPRIGHT },
1600 { EL_STEELWALL_BOTTOMLEFT, EL_INVISIBLE_STEELWALL_BOTTOMLEFT },
1601 { EL_STEELWALL_BOTTOMRIGHT, EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
1602 { EL_STEELWALL_VERTICAL, EL_INVISIBLE_STEELWALL_VERTICAL },
1603 { EL_STEELWALL_HORIZONTAL, EL_INVISIBLE_STEELWALL_HORIZONTAL },
1604 { EL_STEELWALL, EL_INVISIBLE_STEELWALL }
1606 int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
1607 int steel_position = (x == -1 && y == -1 ? 0 :
1608 x == lev_fieldx && y == -1 ? 1 :
1609 x == -1 && y == lev_fieldy ? 2 :
1610 x == lev_fieldx && y == lev_fieldy ? 3 :
1611 x == -1 || x == lev_fieldx ? 4 :
1612 y == -1 || y == lev_fieldy ? 5 : 6);
1614 return border[steel_position][steel_type];
1617 void DrawScreenElement(int x, int y, int element)
1619 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
1620 DrawLevelFieldCrumbledSand(LEVELX(x), LEVELY(y));
1623 void DrawLevelElement(int x, int y, int element)
1625 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1626 DrawScreenElement(SCREENX(x), SCREENY(y), element);
1629 void DrawScreenField(int x, int y)
1631 int lx = LEVELX(x), ly = LEVELY(y);
1632 int element, content;
1634 if (!IN_LEV_FIELD(lx, ly))
1636 if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
1639 element = getBorderElement(lx, ly);
1641 DrawScreenElement(x, y, element);
1645 element = Feld[lx][ly];
1646 content = Store[lx][ly];
1648 if (IS_MOVING(lx, ly))
1650 int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
1651 boolean cut_mode = NO_CUTTING;
1653 if (element == EL_QUICKSAND_EMPTYING ||
1654 element == EL_QUICKSAND_FAST_EMPTYING ||
1655 element == EL_MAGIC_WALL_EMPTYING ||
1656 element == EL_BD_MAGIC_WALL_EMPTYING ||
1657 element == EL_DC_MAGIC_WALL_EMPTYING ||
1658 element == EL_AMOEBA_DROPPING)
1659 cut_mode = CUT_ABOVE;
1660 else if (element == EL_QUICKSAND_FILLING ||
1661 element == EL_QUICKSAND_FAST_FILLING ||
1662 element == EL_MAGIC_WALL_FILLING ||
1663 element == EL_BD_MAGIC_WALL_FILLING ||
1664 element == EL_DC_MAGIC_WALL_FILLING)
1665 cut_mode = CUT_BELOW;
1667 if (cut_mode == CUT_ABOVE)
1668 DrawScreenElementShifted(x, y, 0, 0, element, NO_CUTTING);
1670 DrawScreenElement(x, y, EL_EMPTY);
1673 DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
1674 else if (cut_mode == NO_CUTTING)
1675 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
1677 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
1679 if (content == EL_ACID)
1681 int dir = MovDir[lx][ly];
1682 int newlx = lx + (dir == MV_LEFT ? -1 : dir == MV_RIGHT ? +1 : 0);
1683 int newly = ly + (dir == MV_UP ? -1 : dir == MV_DOWN ? +1 : 0);
1685 DrawLevelElementThruMask(newlx, newly, EL_ACID);
1688 else if (IS_BLOCKED(lx, ly))
1693 boolean cut_mode = NO_CUTTING;
1694 int element_old, content_old;
1696 Blocked2Moving(lx, ly, &oldx, &oldy);
1699 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
1700 MovDir[oldx][oldy] == MV_RIGHT);
1702 element_old = Feld[oldx][oldy];
1703 content_old = Store[oldx][oldy];
1705 if (element_old == EL_QUICKSAND_EMPTYING ||
1706 element_old == EL_QUICKSAND_FAST_EMPTYING ||
1707 element_old == EL_MAGIC_WALL_EMPTYING ||
1708 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
1709 element_old == EL_DC_MAGIC_WALL_EMPTYING ||
1710 element_old == EL_AMOEBA_DROPPING)
1711 cut_mode = CUT_ABOVE;
1713 DrawScreenElement(x, y, EL_EMPTY);
1716 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
1718 else if (cut_mode == NO_CUTTING)
1719 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
1722 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
1725 else if (IS_DRAWABLE(element))
1726 DrawScreenElement(x, y, element);
1728 DrawScreenElement(x, y, EL_EMPTY);
1731 void DrawLevelField(int x, int y)
1733 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1734 DrawScreenField(SCREENX(x), SCREENY(y));
1735 else if (IS_MOVING(x, y))
1739 Moving2Blocked(x, y, &newx, &newy);
1740 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
1741 DrawScreenField(SCREENX(newx), SCREENY(newy));
1743 else if (IS_BLOCKED(x, y))
1747 Blocked2Moving(x, y, &oldx, &oldy);
1748 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
1749 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
1753 void DrawMiniElement(int x, int y, int element)
1757 graphic = el2edimg(element);
1758 DrawMiniGraphic(x, y, graphic);
1761 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
1763 int x = sx + scroll_x, y = sy + scroll_y;
1765 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
1766 DrawMiniElement(sx, sy, EL_EMPTY);
1767 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
1768 DrawMiniElement(sx, sy, Feld[x][y]);
1770 DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
1773 void DrawEnvelopeBackground(int envelope_nr, int startx, int starty,
1774 int x, int y, int xsize, int ysize, int font_nr)
1776 int font_width = getFontWidth(font_nr);
1777 int font_height = getFontHeight(font_nr);
1778 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1781 int dst_x = SX + startx + x * font_width;
1782 int dst_y = SY + starty + y * font_height;
1783 int width = graphic_info[graphic].width;
1784 int height = graphic_info[graphic].height;
1785 int inner_width = MAX(width - 2 * font_width, font_width);
1786 int inner_height = MAX(height - 2 * font_height, font_height);
1787 int inner_sx = (width >= 3 * font_width ? font_width : 0);
1788 int inner_sy = (height >= 3 * font_height ? font_height : 0);
1789 boolean draw_masked = graphic_info[graphic].draw_masked;
1791 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1793 if (src_bitmap == NULL || width < font_width || height < font_height)
1795 ClearRectangle(drawto, dst_x, dst_y, font_width, font_height);
1799 src_x += (x == 0 ? 0 : x == xsize - 1 ? width - font_width :
1800 inner_sx + (x - 1) * font_width % inner_width);
1801 src_y += (y == 0 ? 0 : y == ysize - 1 ? height - font_height :
1802 inner_sy + (y - 1) * font_height % inner_height);
1806 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1807 dst_x - src_x, dst_y - src_y);
1808 BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1812 BlitBitmap(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1816 void AnimateEnvelope(int envelope_nr, int anim_mode, int action)
1818 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1819 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1820 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
1821 boolean ffwd_delay = (tape.playing && tape.fast_forward);
1822 boolean no_delay = (tape.warp_forward);
1823 unsigned long anim_delay = 0;
1824 int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
1825 int anim_delay_value = (no_delay ? 0 : frame_delay_value);
1826 int font_nr = FONT_ENVELOPE_1 + envelope_nr;
1827 int font_width = getFontWidth(font_nr);
1828 int font_height = getFontHeight(font_nr);
1829 int max_xsize = level.envelope[envelope_nr].xsize;
1830 int max_ysize = level.envelope[envelope_nr].ysize;
1831 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
1832 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
1833 int xend = max_xsize;
1834 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
1835 int xstep = (xstart < xend ? 1 : 0);
1836 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
1839 for (x = xstart, y = ystart; x <= xend && y <= yend; x += xstep, y += ystep)
1841 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
1842 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
1843 int sx = (SXSIZE - xsize * font_width) / 2;
1844 int sy = (SYSIZE - ysize * font_height) / 2;
1847 SetDrawtoField(DRAW_BUFFERED);
1849 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
1851 SetDrawtoField(DRAW_BACKBUFFER);
1853 for (yy = 0; yy < ysize; yy++) for (xx = 0; xx < xsize; xx++)
1854 DrawEnvelopeBackground(envelope_nr, sx,sy, xx,yy, xsize, ysize, font_nr);
1857 DrawTextBuffer(SX + sx + font_width, SY + sy + font_height,
1858 level.envelope[envelope_nr].text, font_nr, max_xsize,
1859 xsize - 2, ysize - 2, mask_mode,
1860 level.envelope[envelope_nr].autowrap,
1861 level.envelope[envelope_nr].centered, FALSE);
1863 DrawTextToTextArea(SX + sx + font_width, SY + sy + font_height,
1864 level.envelope[envelope_nr].text, font_nr, max_xsize,
1865 xsize - 2, ysize - 2, mask_mode);
1868 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
1871 WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
1875 void ShowEnvelope(int envelope_nr)
1877 int element = EL_ENVELOPE_1 + envelope_nr;
1878 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1879 int sound_opening = element_info[element].sound[ACTION_OPENING];
1880 int sound_closing = element_info[element].sound[ACTION_CLOSING];
1881 boolean ffwd_delay = (tape.playing && tape.fast_forward);
1882 boolean no_delay = (tape.warp_forward);
1883 int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
1884 int wait_delay_value = (no_delay ? 0 : normal_delay_value);
1885 int anim_mode = graphic_info[graphic].anim_mode;
1886 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
1887 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
1889 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
1891 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
1893 if (anim_mode == ANIM_DEFAULT)
1894 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_OPENING);
1896 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_OPENING);
1899 Delay(wait_delay_value);
1901 WaitForEventToContinue();
1903 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
1905 if (anim_mode != ANIM_NONE)
1906 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_CLOSING);
1908 if (anim_mode == ANIM_DEFAULT)
1909 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_CLOSING);
1911 game.envelope_active = FALSE;
1913 SetDrawtoField(DRAW_BUFFERED);
1915 redraw_mask |= REDRAW_FIELD;
1919 void DrawPreviewElement(int dst_x, int dst_y, int element, int tilesize)
1923 int graphic = el2preimg(element);
1925 getSizedGraphicSource(graphic, 0, tilesize, &src_bitmap, &src_x, &src_y);
1926 BlitBitmap(src_bitmap, drawto, src_x, src_y, tilesize, tilesize, dst_x,dst_y);
1933 SetDrawBackgroundMask(REDRAW_NONE);
1936 for (x = BX1; x <= BX2; x++)
1937 for (y = BY1; y <= BY2; y++)
1938 DrawScreenField(x, y);
1940 redraw_mask |= REDRAW_FIELD;
1943 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
1947 for (x = 0; x < size_x; x++)
1948 for (y = 0; y < size_y; y++)
1949 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
1951 redraw_mask |= REDRAW_FIELD;
1954 static void DrawPreviewLevelExt(int from_x, int from_y)
1956 boolean show_level_border = (BorderElement != EL_EMPTY);
1957 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
1958 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
1959 int tile_size = preview.tile_size;
1960 int preview_width = preview.xsize * tile_size;
1961 int preview_height = preview.ysize * tile_size;
1962 int real_preview_xsize = MIN(level_xsize, preview.xsize);
1963 int real_preview_ysize = MIN(level_ysize, preview.ysize);
1964 int dst_x = SX + ALIGNED_XPOS(preview.x, preview_width, preview.align);
1965 int dst_y = SY + ALIGNED_YPOS(preview.y, preview_height, preview.valign);
1968 DrawBackground(dst_x, dst_y, preview_width, preview_height);
1970 dst_x += (preview_width - real_preview_xsize * tile_size) / 2;
1971 dst_y += (preview_height - real_preview_ysize * tile_size) / 2;
1973 for (x = 0; x < real_preview_xsize; x++)
1975 for (y = 0; y < real_preview_ysize; y++)
1977 int lx = from_x + x + (show_level_border ? -1 : 0);
1978 int ly = from_y + y + (show_level_border ? -1 : 0);
1979 int element = (IN_LEV_FIELD(lx, ly) ? level.field[lx][ly] :
1980 getBorderElement(lx, ly));
1982 DrawPreviewElement(dst_x + x * tile_size, dst_y + y * tile_size,
1983 element, tile_size);
1987 redraw_mask |= REDRAW_MICROLEVEL;
1990 #define MICROLABEL_EMPTY 0
1991 #define MICROLABEL_LEVEL_NAME 1
1992 #define MICROLABEL_LEVEL_AUTHOR_HEAD 2
1993 #define MICROLABEL_LEVEL_AUTHOR 3
1994 #define MICROLABEL_IMPORTED_FROM_HEAD 4
1995 #define MICROLABEL_IMPORTED_FROM 5
1996 #define MICROLABEL_IMPORTED_BY_HEAD 6
1997 #define MICROLABEL_IMPORTED_BY 7
1999 static int getMaxTextLength(struct TextPosInfo *pos, int font_nr)
2001 int max_text_width = SXSIZE;
2002 int font_width = getFontWidth(font_nr);
2004 if (pos->align == ALIGN_CENTER)
2005 max_text_width = (pos->x < SXSIZE / 2 ? pos->x * 2 : (SXSIZE - pos->x) * 2);
2006 else if (pos->align == ALIGN_RIGHT)
2007 max_text_width = pos->x;
2009 max_text_width = SXSIZE - pos->x;
2011 return max_text_width / font_width;
2014 static void DrawPreviewLevelLabelExt(int mode)
2016 struct TextPosInfo *pos = &menu.main.text.level_info_2;
2017 char label_text[MAX_OUTPUT_LINESIZE + 1];
2018 int max_len_label_text;
2020 int font_nr = pos->font;
2023 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
2024 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
2025 mode == MICROLABEL_IMPORTED_BY_HEAD)
2026 font_nr = pos->font_alt;
2028 int font_nr = FONT_TEXT_2;
2031 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
2032 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
2033 mode == MICROLABEL_IMPORTED_BY_HEAD)
2034 font_nr = FONT_TEXT_3;
2038 max_len_label_text = getMaxTextLength(pos, font_nr);
2040 max_len_label_text = SXSIZE / getFontWidth(font_nr);
2044 if (pos->size != -1)
2045 max_len_label_text = pos->size;
2048 for (i = 0; i < max_len_label_text; i++)
2049 label_text[i] = ' ';
2050 label_text[max_len_label_text] = '\0';
2052 if (strlen(label_text) > 0)
2055 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2057 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
2058 int lypos = MICROLABEL2_YPOS;
2060 DrawText(lxpos, lypos, label_text, font_nr);
2065 (mode == MICROLABEL_LEVEL_NAME ? level.name :
2066 mode == MICROLABEL_LEVEL_AUTHOR_HEAD ? "created by" :
2067 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
2068 mode == MICROLABEL_IMPORTED_FROM_HEAD ? "imported from" :
2069 mode == MICROLABEL_IMPORTED_FROM ? leveldir_current->imported_from :
2070 mode == MICROLABEL_IMPORTED_BY_HEAD ? "imported by" :
2071 mode == MICROLABEL_IMPORTED_BY ? leveldir_current->imported_by :""),
2072 max_len_label_text);
2073 label_text[max_len_label_text] = '\0';
2075 if (strlen(label_text) > 0)
2078 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2080 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
2081 int lypos = MICROLABEL2_YPOS;
2083 DrawText(lxpos, lypos, label_text, font_nr);
2087 redraw_mask |= REDRAW_MICROLEVEL;
2090 void DrawPreviewLevel(boolean restart)
2092 static unsigned long scroll_delay = 0;
2093 static unsigned long label_delay = 0;
2094 static int from_x, from_y, scroll_direction;
2095 static int label_state, label_counter;
2096 unsigned long scroll_delay_value = preview.step_delay;
2097 boolean show_level_border = (BorderElement != EL_EMPTY);
2098 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
2099 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
2100 int last_game_status = game_status; /* save current game status */
2103 /* force PREVIEW font on preview level */
2104 game_status = GAME_MODE_PSEUDO_PREVIEW;
2112 if (preview.anim_mode == ANIM_CENTERED)
2114 if (level_xsize > preview.xsize)
2115 from_x = (level_xsize - preview.xsize) / 2;
2116 if (level_ysize > preview.ysize)
2117 from_y = (level_ysize - preview.ysize) / 2;
2120 from_x += preview.xoffset;
2121 from_y += preview.yoffset;
2123 scroll_direction = MV_RIGHT;
2127 DrawPreviewLevelExt(from_x, from_y);
2128 DrawPreviewLevelLabelExt(label_state);
2130 /* initialize delay counters */
2131 DelayReached(&scroll_delay, 0);
2132 DelayReached(&label_delay, 0);
2134 if (leveldir_current->name)
2136 struct TextPosInfo *pos = &menu.main.text.level_info_1;
2137 char label_text[MAX_OUTPUT_LINESIZE + 1];
2139 int font_nr = pos->font;
2141 int font_nr = FONT_TEXT_1;
2144 int max_len_label_text = getMaxTextLength(pos, font_nr);
2146 int max_len_label_text = SXSIZE / getFontWidth(font_nr);
2154 if (pos->size != -1)
2155 max_len_label_text = pos->size;
2158 strncpy(label_text, leveldir_current->name, max_len_label_text);
2159 label_text[max_len_label_text] = '\0';
2162 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2164 lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
2165 lypos = SY + MICROLABEL1_YPOS;
2167 DrawText(lxpos, lypos, label_text, font_nr);
2171 game_status = last_game_status; /* restore current game status */
2176 /* scroll preview level, if needed */
2177 if (preview.anim_mode != ANIM_NONE &&
2178 (level_xsize > preview.xsize || level_ysize > preview.ysize) &&
2179 DelayReached(&scroll_delay, scroll_delay_value))
2181 switch (scroll_direction)
2186 from_x -= preview.step_offset;
2187 from_x = (from_x < 0 ? 0 : from_x);
2190 scroll_direction = MV_UP;
2194 if (from_x < level_xsize - preview.xsize)
2196 from_x += preview.step_offset;
2197 from_x = (from_x > level_xsize - preview.xsize ?
2198 level_xsize - preview.xsize : from_x);
2201 scroll_direction = MV_DOWN;
2207 from_y -= preview.step_offset;
2208 from_y = (from_y < 0 ? 0 : from_y);
2211 scroll_direction = MV_RIGHT;
2215 if (from_y < level_ysize - preview.ysize)
2217 from_y += preview.step_offset;
2218 from_y = (from_y > level_ysize - preview.ysize ?
2219 level_ysize - preview.ysize : from_y);
2222 scroll_direction = MV_LEFT;
2229 DrawPreviewLevelExt(from_x, from_y);
2232 /* !!! THIS ALL SUCKS -- SHOULD BE CLEANLY REWRITTEN !!! */
2233 /* redraw micro level label, if needed */
2234 if (!strEqual(level.name, NAMELESS_LEVEL_NAME) &&
2235 !strEqual(level.author, ANONYMOUS_NAME) &&
2236 !strEqual(level.author, leveldir_current->name) &&
2237 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
2239 int max_label_counter = 23;
2241 if (leveldir_current->imported_from != NULL &&
2242 strlen(leveldir_current->imported_from) > 0)
2243 max_label_counter += 14;
2244 if (leveldir_current->imported_by != NULL &&
2245 strlen(leveldir_current->imported_by) > 0)
2246 max_label_counter += 14;
2248 label_counter = (label_counter + 1) % max_label_counter;
2249 label_state = (label_counter >= 0 && label_counter <= 7 ?
2250 MICROLABEL_LEVEL_NAME :
2251 label_counter >= 9 && label_counter <= 12 ?
2252 MICROLABEL_LEVEL_AUTHOR_HEAD :
2253 label_counter >= 14 && label_counter <= 21 ?
2254 MICROLABEL_LEVEL_AUTHOR :
2255 label_counter >= 23 && label_counter <= 26 ?
2256 MICROLABEL_IMPORTED_FROM_HEAD :
2257 label_counter >= 28 && label_counter <= 35 ?
2258 MICROLABEL_IMPORTED_FROM :
2259 label_counter >= 37 && label_counter <= 40 ?
2260 MICROLABEL_IMPORTED_BY_HEAD :
2261 label_counter >= 42 && label_counter <= 49 ?
2262 MICROLABEL_IMPORTED_BY : MICROLABEL_EMPTY);
2264 if (leveldir_current->imported_from == NULL &&
2265 (label_state == MICROLABEL_IMPORTED_FROM_HEAD ||
2266 label_state == MICROLABEL_IMPORTED_FROM))
2267 label_state = (label_state == MICROLABEL_IMPORTED_FROM_HEAD ?
2268 MICROLABEL_IMPORTED_BY_HEAD : MICROLABEL_IMPORTED_BY);
2270 DrawPreviewLevelLabelExt(label_state);
2273 game_status = last_game_status; /* restore current game status */
2276 inline void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
2277 int graphic, int sync_frame, int mask_mode)
2279 int frame = getGraphicAnimationFrame(graphic, sync_frame);
2281 if (mask_mode == USE_MASKING)
2282 DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
2284 DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
2287 inline void DrawGraphicAnimation(int x, int y, int graphic)
2289 int lx = LEVELX(x), ly = LEVELY(y);
2291 if (!IN_SCR_FIELD(x, y))
2294 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
2295 graphic, GfxFrame[lx][ly], NO_MASKING);
2296 MarkTileDirty(x, y);
2299 void DrawLevelGraphicAnimation(int x, int y, int graphic)
2301 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
2304 void DrawLevelElementAnimation(int x, int y, int element)
2306 int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
2308 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
2311 inline void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
2313 int sx = SCREENX(x), sy = SCREENY(y);
2315 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
2318 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
2321 DrawGraphicAnimation(sx, sy, graphic);
2324 if (GFX_CRUMBLED(TILE_GFX_ELEMENT(x, y)))
2325 DrawLevelFieldCrumbledSand(x, y);
2327 if (GFX_CRUMBLED(Feld[x][y]))
2328 DrawLevelFieldCrumbledSand(x, y);
2332 void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
2334 int sx = SCREENX(x), sy = SCREENY(y);
2337 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
2340 graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
2342 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
2345 DrawGraphicAnimation(sx, sy, graphic);
2347 if (GFX_CRUMBLED(element))
2348 DrawLevelFieldCrumbledSand(x, y);
2351 static int getPlayerGraphic(struct PlayerInfo *player, int move_dir)
2353 if (player->use_murphy)
2355 /* this works only because currently only one player can be "murphy" ... */
2356 static int last_horizontal_dir = MV_LEFT;
2357 int graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir);
2359 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
2360 last_horizontal_dir = move_dir;
2362 if (graphic == IMG_SP_MURPHY) /* undefined => use special graphic */
2364 int direction = (player->is_snapping ? move_dir : last_horizontal_dir);
2366 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
2372 return el_act_dir2img(player->artwork_element, player->GfxAction,move_dir);
2375 static boolean equalGraphics(int graphic1, int graphic2)
2377 struct GraphicInfo *g1 = &graphic_info[graphic1];
2378 struct GraphicInfo *g2 = &graphic_info[graphic2];
2380 return (g1->bitmap == g2->bitmap &&
2381 g1->src_x == g2->src_x &&
2382 g1->src_y == g2->src_y &&
2383 g1->anim_frames == g2->anim_frames &&
2384 g1->anim_delay == g2->anim_delay &&
2385 g1->anim_mode == g2->anim_mode);
2388 void DrawAllPlayers()
2392 for (i = 0; i < MAX_PLAYERS; i++)
2393 if (stored_player[i].active)
2394 DrawPlayer(&stored_player[i]);
2397 void DrawPlayerField(int x, int y)
2399 if (!IS_PLAYER(x, y))
2402 DrawPlayer(PLAYERINFO(x, y));
2405 void DrawPlayer(struct PlayerInfo *player)
2407 int jx = player->jx;
2408 int jy = player->jy;
2409 int move_dir = player->MovDir;
2410 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? +1 : 0);
2411 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? +1 : 0);
2412 int last_jx = (player->is_moving ? jx - dx : jx);
2413 int last_jy = (player->is_moving ? jy - dy : jy);
2414 int next_jx = jx + dx;
2415 int next_jy = jy + dy;
2416 boolean player_is_moving = (player->MovPos ? TRUE : FALSE);
2417 boolean player_is_opaque = FALSE;
2418 int sx = SCREENX(jx), sy = SCREENY(jy);
2419 int sxx = 0, syy = 0;
2420 int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
2422 int action = ACTION_DEFAULT;
2423 int last_player_graphic = getPlayerGraphic(player, move_dir);
2424 int last_player_frame = player->Frame;
2427 /* GfxElement[][] is set to the element the player is digging or collecting;
2428 remove also for off-screen player if the player is not moving anymore */
2429 if (IN_LEV_FIELD(jx, jy) && !player_is_moving)
2430 GfxElement[jx][jy] = EL_UNDEFINED;
2432 if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
2436 if (!IN_LEV_FIELD(jx, jy))
2438 printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
2439 printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
2440 printf("DrawPlayerField(): This should never happen!\n");
2445 if (element == EL_EXPLOSION)
2448 action = (player->is_pushing ? ACTION_PUSHING :
2449 player->is_digging ? ACTION_DIGGING :
2450 player->is_collecting ? ACTION_COLLECTING :
2451 player->is_moving ? ACTION_MOVING :
2452 player->is_snapping ? ACTION_SNAPPING :
2453 player->is_dropping ? ACTION_DROPPING :
2454 player->is_waiting ? player->action_waiting : ACTION_DEFAULT);
2456 if (player->is_waiting)
2457 move_dir = player->dir_waiting;
2459 InitPlayerGfxAnimation(player, action, move_dir);
2461 /* ----------------------------------------------------------------------- */
2462 /* draw things in the field the player is leaving, if needed */
2463 /* ----------------------------------------------------------------------- */
2465 if (player->is_moving)
2467 if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
2469 DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
2471 if (last_element == EL_DYNAMITE_ACTIVE ||
2472 last_element == EL_EM_DYNAMITE_ACTIVE ||
2473 last_element == EL_SP_DISK_RED_ACTIVE)
2474 DrawDynamite(last_jx, last_jy);
2476 DrawLevelFieldThruMask(last_jx, last_jy);
2478 else if (last_element == EL_DYNAMITE_ACTIVE ||
2479 last_element == EL_EM_DYNAMITE_ACTIVE ||
2480 last_element == EL_SP_DISK_RED_ACTIVE)
2481 DrawDynamite(last_jx, last_jy);
2483 /* !!! this is not enough to prevent flickering of players which are
2484 moving next to each others without a free tile between them -- this
2485 can only be solved by drawing all players layer by layer (first the
2486 background, then the foreground etc.) !!! => TODO */
2487 else if (!IS_PLAYER(last_jx, last_jy))
2488 DrawLevelField(last_jx, last_jy);
2491 DrawLevelField(last_jx, last_jy);
2494 if (player->is_pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
2495 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
2498 if (!IN_SCR_FIELD(sx, sy))
2501 if (setup.direct_draw)
2502 SetDrawtoField(DRAW_BUFFERED);
2504 /* ----------------------------------------------------------------------- */
2505 /* draw things behind the player, if needed */
2506 /* ----------------------------------------------------------------------- */
2509 DrawLevelElement(jx, jy, Back[jx][jy]);
2510 else if (IS_ACTIVE_BOMB(element))
2511 DrawLevelElement(jx, jy, EL_EMPTY);
2514 if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
2516 int old_element = GfxElement[jx][jy];
2517 int old_graphic = el_act_dir2img(old_element, action, move_dir);
2518 int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
2520 if (GFX_CRUMBLED(old_element))
2521 DrawLevelFieldCrumbledSandDigging(jx, jy, move_dir, player->StepFrame);
2523 DrawGraphic(sx, sy, old_graphic, frame);
2525 if (graphic_info[old_graphic].anim_mode & ANIM_OPAQUE_PLAYER)
2526 player_is_opaque = TRUE;
2530 GfxElement[jx][jy] = EL_UNDEFINED;
2532 /* make sure that pushed elements are drawn with correct frame rate */
2534 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
2536 if (player->is_pushing && player->is_moving && !IS_ANIM_MODE_CE(graphic))
2537 GfxFrame[jx][jy] = player->StepFrame;
2539 if (player->is_pushing && player->is_moving)
2540 GfxFrame[jx][jy] = player->StepFrame;
2543 DrawLevelField(jx, jy);
2547 /* ----------------------------------------------------------------------- */
2548 /* draw player himself */
2549 /* ----------------------------------------------------------------------- */
2551 graphic = getPlayerGraphic(player, move_dir);
2553 /* in the case of changed player action or direction, prevent the current
2554 animation frame from being restarted for identical animations */
2555 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
2556 player->Frame = last_player_frame;
2558 frame = getGraphicAnimationFrame(graphic, player->Frame);
2562 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
2563 sxx = player->GfxPos;
2565 syy = player->GfxPos;
2568 if (!setup.soft_scrolling && ScreenMovPos)
2571 if (player_is_opaque)
2572 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
2574 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
2576 if (SHIELD_ON(player))
2578 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
2579 IMG_SHIELD_NORMAL_ACTIVE);
2580 int frame = getGraphicAnimationFrame(graphic, -1);
2582 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
2585 /* ----------------------------------------------------------------------- */
2586 /* draw things the player is pushing, if needed */
2587 /* ----------------------------------------------------------------------- */
2590 printf("::: %d, %d [%d, %d] [%d]\n",
2591 player->is_pushing, player_is_moving, player->GfxAction,
2592 player->is_moving, player_is_moving);
2596 if (player->is_pushing && player->is_moving)
2598 int px = SCREENX(jx), py = SCREENY(jy);
2599 int pxx = (TILEX - ABS(sxx)) * dx;
2600 int pyy = (TILEY - ABS(syy)) * dy;
2601 int gfx_frame = GfxFrame[jx][jy];
2607 if (!IS_MOVING(jx, jy)) /* push movement already finished */
2609 element = Feld[next_jx][next_jy];
2610 gfx_frame = GfxFrame[next_jx][next_jy];
2613 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
2616 sync_frame = (IS_ANIM_MODE_CE(graphic) ? gfx_frame : player->StepFrame);
2617 frame = getGraphicAnimationFrame(graphic, sync_frame);
2619 frame = getGraphicAnimationFrame(graphic, player->StepFrame);
2622 /* draw background element under pushed element (like the Sokoban field) */
2623 if (Back[next_jx][next_jy])
2624 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
2626 /* masked drawing is needed for EMC style (double) movement graphics */
2627 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
2631 /* ----------------------------------------------------------------------- */
2632 /* draw things in front of player (active dynamite or dynabombs) */
2633 /* ----------------------------------------------------------------------- */
2635 if (IS_ACTIVE_BOMB(element))
2637 graphic = el2img(element);
2638 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
2640 if (game.emulation == EMU_SUPAPLEX)
2641 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
2643 DrawGraphicThruMask(sx, sy, graphic, frame);
2646 if (player_is_moving && last_element == EL_EXPLOSION)
2648 int element = (GfxElement[last_jx][last_jy] != EL_UNDEFINED ?
2649 GfxElement[last_jx][last_jy] : EL_EMPTY);
2650 int graphic = el_act2img(element, ACTION_EXPLODING);
2651 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
2652 int phase = ExplodePhase[last_jx][last_jy] - 1;
2653 int frame = getGraphicAnimationFrame(graphic, phase - delay);
2656 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
2659 /* ----------------------------------------------------------------------- */
2660 /* draw elements the player is just walking/passing through/under */
2661 /* ----------------------------------------------------------------------- */
2663 if (player_is_moving)
2665 /* handle the field the player is leaving ... */
2666 if (IS_ACCESSIBLE_INSIDE(last_element))
2667 DrawLevelField(last_jx, last_jy);
2668 else if (IS_ACCESSIBLE_UNDER(last_element))
2669 DrawLevelFieldThruMask(last_jx, last_jy);
2672 /* do not redraw accessible elements if the player is just pushing them */
2673 if (!player_is_moving || !player->is_pushing)
2675 /* ... and the field the player is entering */
2676 if (IS_ACCESSIBLE_INSIDE(element))
2677 DrawLevelField(jx, jy);
2678 else if (IS_ACCESSIBLE_UNDER(element))
2679 DrawLevelFieldThruMask(jx, jy);
2682 if (setup.direct_draw)
2684 int dst_x = SX + SCREENX(MIN(jx, last_jx)) * TILEX;
2685 int dst_y = SY + SCREENY(MIN(jy, last_jy)) * TILEY;
2686 int x_size = TILEX * (1 + ABS(jx - last_jx));
2687 int y_size = TILEY * (1 + ABS(jy - last_jy));
2689 BlitBitmap(drawto_field, window,
2690 dst_x, dst_y, x_size, y_size, dst_x, dst_y);
2691 SetDrawtoField(DRAW_DIRECT);
2694 MarkTileDirty(sx, sy);
2697 /* ------------------------------------------------------------------------- */
2699 void WaitForEventToContinue()
2701 boolean still_wait = TRUE;
2703 /* simulate releasing mouse button over last gadget, if still pressed */
2705 HandleGadgets(-1, -1, 0);
2707 button_status = MB_RELEASED;
2723 case EVENT_BUTTONPRESS:
2724 case EVENT_KEYPRESS:
2728 case EVENT_KEYRELEASE:
2729 ClearPlayerAction();
2733 HandleOtherEvents(&event);
2737 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2744 /* don't eat all CPU time */
2749 #define MAX_REQUEST_LINES 13
2750 #define MAX_REQUEST_LINE_FONT1_LEN 7
2751 #define MAX_REQUEST_LINE_FONT2_LEN 10
2753 boolean Request(char *text, unsigned int req_state)
2755 int mx, my, ty, result = -1;
2756 unsigned int old_door_state;
2757 int last_game_status = game_status; /* save current game status */
2758 int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
2759 int font_nr = FONT_TEXT_2;
2760 int max_word_len = 0;
2763 for (text_ptr = text; *text_ptr; text_ptr++)
2765 max_word_len = (*text_ptr != ' ' ? max_word_len + 1 : 0);
2767 if (max_word_len > MAX_REQUEST_LINE_FONT1_LEN)
2769 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
2771 font_nr = FONT_TEXT_1;
2773 font_nr = FONT_LEVEL_NUMBER;
2780 if (game_status == GAME_MODE_PLAYING &&
2781 level.game_engine_type == GAME_ENGINE_TYPE_EM)
2782 BlitScreenToBitmap_EM(backbuffer);
2784 /* disable deactivated drawing when quick-loading level tape recording */
2785 if (tape.playing && tape.deactivate_display)
2786 TapeDeactivateDisplayOff(TRUE);
2788 SetMouseCursor(CURSOR_DEFAULT);
2790 #if defined(NETWORK_AVALIABLE)
2791 /* pause network game while waiting for request to answer */
2792 if (options.network &&
2793 game_status == GAME_MODE_PLAYING &&
2794 req_state & REQUEST_WAIT_FOR_INPUT)
2795 SendToServer_PausePlaying();
2798 old_door_state = GetDoorState();
2800 /* simulate releasing mouse button over last gadget, if still pressed */
2802 HandleGadgets(-1, -1, 0);
2806 if (old_door_state & DOOR_OPEN_1)
2808 CloseDoor(DOOR_CLOSE_1);
2810 /* save old door content */
2811 BlitBitmap(bitmap_db_door, bitmap_db_door,
2812 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
2813 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
2817 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
2820 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2822 /* clear door drawing field */
2823 DrawBackground(DX, DY, DXSIZE, DYSIZE);
2825 /* force DOOR font inside door area */
2826 game_status = GAME_MODE_PSEUDO_DOOR;
2828 /* write text for request */
2829 for (ty = 0; ty < MAX_REQUEST_LINES; ty++)
2831 char text_line[max_request_line_len + 1];
2837 for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
2840 if (!tc || tc == ' ')
2851 strncpy(text_line, text, tl);
2854 DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
2855 DY + 8 + ty * (getFontHeight(font_nr) + 2),
2856 text_line, font_nr);
2858 text += tl + (tc == ' ' ? 1 : 0);
2861 game_status = last_game_status; /* restore current game status */
2863 if (req_state & REQ_ASK)
2865 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
2866 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
2868 else if (req_state & REQ_CONFIRM)
2870 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
2872 else if (req_state & REQ_PLAYER)
2874 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
2875 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
2876 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
2877 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
2880 /* copy request gadgets to door backbuffer */
2881 BlitBitmap(drawto, bitmap_db_door,
2882 DX, DY, DXSIZE, DYSIZE,
2883 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2885 OpenDoor(DOOR_OPEN_1);
2887 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
2889 if (game_status == GAME_MODE_PLAYING)
2891 SetPanelBackground();
2892 SetDrawBackgroundMask(REDRAW_DOOR_1);
2896 SetDrawBackgroundMask(REDRAW_FIELD);
2902 if (game_status != GAME_MODE_MAIN)
2905 button_status = MB_RELEASED;
2907 request_gadget_id = -1;
2909 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2921 case EVENT_BUTTONPRESS:
2922 case EVENT_BUTTONRELEASE:
2923 case EVENT_MOTIONNOTIFY:
2925 if (event.type == EVENT_MOTIONNOTIFY)
2927 if (!PointerInWindow(window))
2928 continue; /* window and pointer are on different screens */
2933 motion_status = TRUE;
2934 mx = ((MotionEvent *) &event)->x;
2935 my = ((MotionEvent *) &event)->y;
2939 motion_status = FALSE;
2940 mx = ((ButtonEvent *) &event)->x;
2941 my = ((ButtonEvent *) &event)->y;
2942 if (event.type == EVENT_BUTTONPRESS)
2943 button_status = ((ButtonEvent *) &event)->button;
2945 button_status = MB_RELEASED;
2948 /* this sets 'request_gadget_id' */
2949 HandleGadgets(mx, my, button_status);
2951 switch (request_gadget_id)
2953 case TOOL_CTRL_ID_YES:
2956 case TOOL_CTRL_ID_NO:
2959 case TOOL_CTRL_ID_CONFIRM:
2960 result = TRUE | FALSE;
2963 case TOOL_CTRL_ID_PLAYER_1:
2966 case TOOL_CTRL_ID_PLAYER_2:
2969 case TOOL_CTRL_ID_PLAYER_3:
2972 case TOOL_CTRL_ID_PLAYER_4:
2983 case EVENT_KEYPRESS:
2984 switch (GetEventKey((KeyEvent *)&event, TRUE))
2987 if (req_state & REQ_CONFIRM)
3003 if (req_state & REQ_PLAYER)
3007 case EVENT_KEYRELEASE:
3008 ClearPlayerAction();
3012 HandleOtherEvents(&event);
3016 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
3018 int joy = AnyJoystick();
3020 if (joy & JOY_BUTTON_1)
3022 else if (joy & JOY_BUTTON_2)
3028 if (game_status == GAME_MODE_PLAYING && local_player->LevelSolved_GameEnd)
3030 HandleGameActions();
3037 if (!PendingEvent()) /* delay only if no pending events */
3046 if (!PendingEvent()) /* delay only if no pending events */
3049 /* don't eat all CPU time */
3056 if (game_status != GAME_MODE_MAIN)
3061 if (!(req_state & REQ_STAY_OPEN))
3063 CloseDoor(DOOR_CLOSE_1);
3065 if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
3066 (req_state & REQ_REOPEN))
3067 OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
3072 if (game_status == GAME_MODE_PLAYING)
3074 SetPanelBackground();
3075 SetDrawBackgroundMask(REDRAW_DOOR_1);
3079 SetDrawBackgroundMask(REDRAW_FIELD);
3082 #if defined(NETWORK_AVALIABLE)
3083 /* continue network game after request */
3084 if (options.network &&
3085 game_status == GAME_MODE_PLAYING &&
3086 req_state & REQUEST_WAIT_FOR_INPUT)
3087 SendToServer_ContinuePlaying();
3090 /* restore deactivated drawing when quick-loading level tape recording */
3091 if (tape.playing && tape.deactivate_display)
3092 TapeDeactivateDisplayOn();
3097 unsigned int OpenDoor(unsigned int door_state)
3099 if (door_state & DOOR_COPY_BACK)
3101 if (door_state & DOOR_OPEN_1)
3102 BlitBitmap(bitmap_db_door, bitmap_db_door,
3103 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
3104 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
3106 if (door_state & DOOR_OPEN_2)
3107 BlitBitmap(bitmap_db_door, bitmap_db_door,
3108 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY2, VXSIZE, VYSIZE,
3109 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
3111 door_state &= ~DOOR_COPY_BACK;
3114 return MoveDoor(door_state);
3117 unsigned int CloseDoor(unsigned int door_state)
3119 unsigned int old_door_state = GetDoorState();
3121 if (!(door_state & DOOR_NO_COPY_BACK))
3123 if (old_door_state & DOOR_OPEN_1)
3124 BlitBitmap(backbuffer, bitmap_db_door,
3125 DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
3127 if (old_door_state & DOOR_OPEN_2)
3128 BlitBitmap(backbuffer, bitmap_db_door,
3129 VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
3131 door_state &= ~DOOR_NO_COPY_BACK;
3134 return MoveDoor(door_state);
3137 unsigned int GetDoorState()
3139 return MoveDoor(DOOR_GET_STATE);
3142 unsigned int SetDoorState(unsigned int door_state)
3144 return MoveDoor(door_state | DOOR_SET_STATE);
3147 unsigned int MoveDoor(unsigned int door_state)
3149 static int door1 = DOOR_OPEN_1;
3150 static int door2 = DOOR_CLOSE_2;
3151 unsigned long door_delay = 0;
3152 unsigned long door_delay_value;
3155 if (door_1.width < 0 || door_1.width > DXSIZE)
3156 door_1.width = DXSIZE;
3157 if (door_1.height < 0 || door_1.height > DYSIZE)
3158 door_1.height = DYSIZE;
3159 if (door_2.width < 0 || door_2.width > VXSIZE)
3160 door_2.width = VXSIZE;
3161 if (door_2.height < 0 || door_2.height > VYSIZE)
3162 door_2.height = VYSIZE;
3164 if (door_state == DOOR_GET_STATE)
3165 return (door1 | door2);
3167 if (door_state & DOOR_SET_STATE)
3169 if (door_state & DOOR_ACTION_1)
3170 door1 = door_state & DOOR_ACTION_1;
3171 if (door_state & DOOR_ACTION_2)
3172 door2 = door_state & DOOR_ACTION_2;
3174 return (door1 | door2);
3177 if (!(door_state & DOOR_FORCE_REDRAW))
3179 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
3180 door_state &= ~DOOR_OPEN_1;
3181 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
3182 door_state &= ~DOOR_CLOSE_1;
3183 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
3184 door_state &= ~DOOR_OPEN_2;
3185 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
3186 door_state &= ~DOOR_CLOSE_2;
3189 door_delay_value = (door_state & DOOR_ACTION_1 ? door_1.step_delay :
3192 if (setup.quick_doors)
3194 stepsize = 20; /* must be chosen to always draw last frame */
3195 door_delay_value = 0;
3198 if (global.autoplay_leveldir)
3200 door_state |= DOOR_NO_DELAY;
3201 door_state &= ~DOOR_CLOSE_ALL;
3204 if (door_state & DOOR_ACTION)
3206 boolean handle_door_1 = (door_state & DOOR_ACTION_1);
3207 boolean handle_door_2 = (door_state & DOOR_ACTION_2);
3208 boolean door_1_done = (!handle_door_1);
3209 boolean door_2_done = (!handle_door_2);
3210 boolean door_1_vertical = (door_1.anim_mode & ANIM_VERTICAL);
3211 boolean door_2_vertical = (door_2.anim_mode & ANIM_VERTICAL);
3212 int door_size_1 = (door_1_vertical ? door_1.height : door_1.width);
3213 int door_size_2 = (door_2_vertical ? door_2.height : door_2.width);
3214 int max_door_size_1 = (door_1_vertical ? DYSIZE : DXSIZE);
3215 int max_door_size_2 = (door_2_vertical ? VYSIZE : VXSIZE);
3216 int door_size = (handle_door_1 ? door_size_1 : door_size_2);
3217 int max_door_size = (handle_door_1 ? max_door_size_1 : max_door_size_2);
3218 int door_skip = max_door_size - door_size;
3219 int end = door_size;
3220 int start = ((door_state & DOOR_NO_DELAY) ? end : 0);
3223 if (!(door_state & DOOR_NO_DELAY) && !setup.quick_doors)
3225 /* opening door sound has priority over simultaneously closing door */
3226 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
3227 PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
3228 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
3229 PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
3232 for (k = start; k <= end && !(door_1_done && door_2_done); k += stepsize)
3235 Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
3236 GC gc = bitmap->stored_clip_gc;
3238 if (door_state & DOOR_ACTION_1)
3240 int a = MIN(x * door_1.step_offset, end);
3241 int p = (door_state & DOOR_OPEN_1 ? end - a : a);
3242 int i = p + door_skip;
3244 if (door_1.anim_mode & ANIM_STATIC_PANEL)
3246 BlitBitmap(bitmap_db_door, drawto,
3247 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1,
3248 DXSIZE, DYSIZE, DX, DY);
3252 BlitBitmap(bitmap_db_door, drawto,
3253 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + p / 2,
3254 DXSIZE, DYSIZE - p / 2, DX, DY);
3256 ClearRectangle(drawto, DX, DY + DYSIZE - p / 2, DXSIZE, p / 2);
3259 if (door_1.anim_mode & ANIM_HORIZONTAL && x <= DXSIZE)
3261 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
3262 int dst1_x = DX + DXSIZE - i, dst1_y = DY;
3263 int src2_x = DXSIZE - i, src2_y = DOOR_GFX_PAGEY1;
3264 int dst2_x = DX, dst2_y = DY;
3265 int width = i, height = DYSIZE;
3267 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3268 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3271 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3272 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3275 else if (door_1.anim_mode & ANIM_VERTICAL && x <= DYSIZE)
3277 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
3278 int dst1_x = DX, dst1_y = DY + DYSIZE - i;
3279 int src2_x = 0, src2_y = DOOR_GFX_PAGEY1 + DYSIZE - i;
3280 int dst2_x = DX, dst2_y = DY;
3281 int width = DXSIZE, height = i;
3283 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3284 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3287 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3288 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3291 else if (x <= DXSIZE) /* ANIM_DEFAULT */
3293 int j = (door_1.anim_mode == ANIM_DEFAULT ? (DXSIZE - i) / 3 : 0);
3295 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
3296 BlitBitmapMasked(bitmap, drawto,
3297 DXSIZE, DOOR_GFX_PAGEY1, i, 77,
3298 DX + DXSIZE - i, DY + j);
3299 BlitBitmapMasked(bitmap, drawto,
3300 DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
3301 DX + DXSIZE - i, DY + 140 + j);
3302 SetClipOrigin(bitmap, gc, DX - DXSIZE + i,
3303 DY - (DOOR_GFX_PAGEY1 + j));
3304 BlitBitmapMasked(bitmap, drawto,
3305 DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
3307 BlitBitmapMasked(bitmap, drawto,
3308 DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
3311 BlitBitmapMasked(bitmap, drawto,
3312 DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
3314 BlitBitmapMasked(bitmap, drawto,
3315 DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
3317 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
3318 BlitBitmapMasked(bitmap, drawto,
3319 DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
3320 DX + DXSIZE - i, DY + 77 + j);
3321 BlitBitmapMasked(bitmap, drawto,
3322 DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
3323 DX + DXSIZE - i, DY + 203 + j);
3326 redraw_mask |= REDRAW_DOOR_1;
3327 door_1_done = (a == end);
3330 if (door_state & DOOR_ACTION_2)
3332 int a = MIN(x * door_2.step_offset, door_size);
3333 int p = (door_state & DOOR_OPEN_2 ? door_size - a : a);
3334 int i = p + door_skip;
3336 if (door_2.anim_mode & ANIM_STATIC_PANEL)
3338 BlitBitmap(bitmap_db_door, drawto,
3339 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2,
3340 VXSIZE, VYSIZE, VX, VY);
3342 else if (x <= VYSIZE)
3344 BlitBitmap(bitmap_db_door, drawto,
3345 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + p / 2,
3346 VXSIZE, VYSIZE - p / 2, VX, VY);
3348 ClearRectangle(drawto, VX, VY + VYSIZE - p / 2, VXSIZE, p / 2);
3351 if (door_2.anim_mode & ANIM_HORIZONTAL && x <= VXSIZE)
3353 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
3354 int dst1_x = VX + VXSIZE - i, dst1_y = VY;
3355 int src2_x = VXSIZE - i, src2_y = DOOR_GFX_PAGEY2;
3356 int dst2_x = VX, dst2_y = VY;
3357 int width = i, height = VYSIZE;
3359 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3360 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3363 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3364 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3367 else if (door_2.anim_mode & ANIM_VERTICAL && x <= VYSIZE)
3369 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
3370 int dst1_x = VX, dst1_y = VY + VYSIZE - i;
3371 int src2_x = 0, src2_y = DOOR_GFX_PAGEY2 + VYSIZE - i;
3372 int dst2_x = VX, dst2_y = VY;
3373 int width = VXSIZE, height = i;
3375 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3376 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3379 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3380 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3383 else if (x <= VXSIZE) /* ANIM_DEFAULT */
3385 int j = (door_2.anim_mode == ANIM_DEFAULT ? (VXSIZE - i) / 3 : 0);
3387 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
3388 BlitBitmapMasked(bitmap, drawto,
3389 VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
3390 VX + VXSIZE - i, VY + j);
3391 SetClipOrigin(bitmap, gc,
3392 VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
3393 BlitBitmapMasked(bitmap, drawto,
3394 VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
3397 BlitBitmapMasked(bitmap, drawto,
3398 VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
3399 i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
3400 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
3401 BlitBitmapMasked(bitmap, drawto,
3402 VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
3404 VX + VXSIZE - i, VY + VYSIZE / 2 + j);
3407 redraw_mask |= REDRAW_DOOR_2;
3408 door_2_done = (a == VXSIZE);
3411 if (!(door_state & DOOR_NO_DELAY))
3415 if (game_status == GAME_MODE_MAIN)
3418 WaitUntilDelayReached(&door_delay, door_delay_value);
3423 if (door_state & DOOR_ACTION_1)
3424 door1 = door_state & DOOR_ACTION_1;
3425 if (door_state & DOOR_ACTION_2)
3426 door2 = door_state & DOOR_ACTION_2;
3428 return (door1 | door2);
3431 void DrawSpecialEditorDoor()
3433 /* draw bigger toolbox window */
3434 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
3435 DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
3437 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
3438 EX - 6, VY - 4, EXSIZE + 12, EYSIZE - VYSIZE + 4,
3441 redraw_mask |= REDRAW_ALL;
3444 void UndrawSpecialEditorDoor()
3446 /* draw normal tape recorder window */
3447 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
3448 EX - 6, EY - 12, EXSIZE + 12, EYSIZE - VYSIZE + 12,
3451 redraw_mask |= REDRAW_ALL;
3455 /* ---------- new tool button stuff ---------------------------------------- */
3457 /* graphic position values for tool buttons */
3458 #define TOOL_BUTTON_YES_XPOS 2
3459 #define TOOL_BUTTON_YES_YPOS 250
3460 #define TOOL_BUTTON_YES_GFX_YPOS 0
3461 #define TOOL_BUTTON_YES_XSIZE 46
3462 #define TOOL_BUTTON_YES_YSIZE 28
3463 #define TOOL_BUTTON_NO_XPOS 52
3464 #define TOOL_BUTTON_NO_YPOS TOOL_BUTTON_YES_YPOS
3465 #define TOOL_BUTTON_NO_GFX_YPOS TOOL_BUTTON_YES_GFX_YPOS
3466 #define TOOL_BUTTON_NO_XSIZE TOOL_BUTTON_YES_XSIZE
3467 #define TOOL_BUTTON_NO_YSIZE TOOL_BUTTON_YES_YSIZE
3468 #define TOOL_BUTTON_CONFIRM_XPOS TOOL_BUTTON_YES_XPOS
3469 #define TOOL_BUTTON_CONFIRM_YPOS TOOL_BUTTON_YES_YPOS
3470 #define TOOL_BUTTON_CONFIRM_GFX_YPOS 30
3471 #define TOOL_BUTTON_CONFIRM_XSIZE 96
3472 #define TOOL_BUTTON_CONFIRM_YSIZE TOOL_BUTTON_YES_YSIZE
3473 #define TOOL_BUTTON_PLAYER_XSIZE 30
3474 #define TOOL_BUTTON_PLAYER_YSIZE 30
3475 #define TOOL_BUTTON_PLAYER_GFX_XPOS 5
3476 #define TOOL_BUTTON_PLAYER_GFX_YPOS 185
3477 #define TOOL_BUTTON_PLAYER_XPOS (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
3478 #define TOOL_BUTTON_PLAYER_YPOS (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
3479 #define TOOL_BUTTON_PLAYER1_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3480 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
3481 #define TOOL_BUTTON_PLAYER2_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3482 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
3483 #define TOOL_BUTTON_PLAYER3_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3484 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
3485 #define TOOL_BUTTON_PLAYER4_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3486 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
3487 #define TOOL_BUTTON_PLAYER1_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3488 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
3489 #define TOOL_BUTTON_PLAYER2_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3490 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
3491 #define TOOL_BUTTON_PLAYER3_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3492 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
3493 #define TOOL_BUTTON_PLAYER4_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3494 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
3503 } toolbutton_info[NUM_TOOL_BUTTONS] =
3506 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_GFX_YPOS,
3507 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_YPOS,
3508 TOOL_BUTTON_YES_XSIZE, TOOL_BUTTON_YES_YSIZE,
3513 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_GFX_YPOS,
3514 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_YPOS,
3515 TOOL_BUTTON_NO_XSIZE, TOOL_BUTTON_NO_YSIZE,
3520 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_GFX_YPOS,
3521 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_YPOS,
3522 TOOL_BUTTON_CONFIRM_XSIZE, TOOL_BUTTON_CONFIRM_YSIZE,
3523 TOOL_CTRL_ID_CONFIRM,
3527 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3528 TOOL_BUTTON_PLAYER1_XPOS, TOOL_BUTTON_PLAYER1_YPOS,
3529 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3530 TOOL_CTRL_ID_PLAYER_1,
3534 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3535 TOOL_BUTTON_PLAYER2_XPOS, TOOL_BUTTON_PLAYER2_YPOS,
3536 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3537 TOOL_CTRL_ID_PLAYER_2,
3541 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3542 TOOL_BUTTON_PLAYER3_XPOS, TOOL_BUTTON_PLAYER3_YPOS,
3543 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3544 TOOL_CTRL_ID_PLAYER_3,
3548 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3549 TOOL_BUTTON_PLAYER4_XPOS, TOOL_BUTTON_PLAYER4_YPOS,
3550 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3551 TOOL_CTRL_ID_PLAYER_4,
3556 void CreateToolButtons()
3560 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3562 Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
3563 Bitmap *deco_bitmap = None;
3564 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
3565 struct GadgetInfo *gi;
3566 unsigned long event_mask;
3567 int gd_xoffset, gd_yoffset;
3568 int gd_x1, gd_x2, gd_y;
3571 event_mask = GD_EVENT_RELEASED;
3573 gd_xoffset = toolbutton_info[i].xpos;
3574 gd_yoffset = toolbutton_info[i].ypos;
3575 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
3576 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
3577 gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
3579 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
3581 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
3583 getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr),
3584 &deco_bitmap, &deco_x, &deco_y);
3585 deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
3586 deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
3589 gi = CreateGadget(GDI_CUSTOM_ID, id,
3590 GDI_INFO_TEXT, toolbutton_info[i].infotext,
3591 GDI_X, DX + toolbutton_info[i].x,
3592 GDI_Y, DY + toolbutton_info[i].y,
3593 GDI_WIDTH, toolbutton_info[i].width,
3594 GDI_HEIGHT, toolbutton_info[i].height,
3595 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
3596 GDI_STATE, GD_BUTTON_UNPRESSED,
3597 GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
3598 GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
3599 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
3600 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
3601 GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
3602 GDI_DECORATION_SHIFTING, 1, 1,
3603 GDI_DIRECT_DRAW, FALSE,
3604 GDI_EVENT_MASK, event_mask,
3605 GDI_CALLBACK_ACTION, HandleToolButtons,
3609 Error(ERR_EXIT, "cannot create gadget");
3611 tool_gadget[id] = gi;
3615 void FreeToolButtons()
3619 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3620 FreeGadget(tool_gadget[i]);
3623 static void UnmapToolButtons()
3627 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3628 UnmapGadget(tool_gadget[i]);
3631 static void HandleToolButtons(struct GadgetInfo *gi)
3633 request_gadget_id = gi->custom_id;
3636 static struct Mapping_EM_to_RND_object
3639 boolean is_rnd_to_em_mapping; /* unique mapping EM <-> RND */
3640 boolean is_backside; /* backside of moving element */
3646 em_object_mapping_list[] =
3649 Xblank, TRUE, FALSE,
3653 Yacid_splash_eB, FALSE, FALSE,
3654 EL_ACID_SPLASH_RIGHT, -1, -1
3657 Yacid_splash_wB, FALSE, FALSE,
3658 EL_ACID_SPLASH_LEFT, -1, -1
3661 #ifdef EM_ENGINE_BAD_ROLL
3663 Xstone_force_e, FALSE, FALSE,
3664 EL_ROCK, -1, MV_BIT_RIGHT
3667 Xstone_force_w, FALSE, FALSE,
3668 EL_ROCK, -1, MV_BIT_LEFT
3671 Xnut_force_e, FALSE, FALSE,
3672 EL_NUT, -1, MV_BIT_RIGHT
3675 Xnut_force_w, FALSE, FALSE,
3676 EL_NUT, -1, MV_BIT_LEFT
3679 Xspring_force_e, FALSE, FALSE,
3680 EL_SPRING, -1, MV_BIT_RIGHT
3683 Xspring_force_w, FALSE, FALSE,
3684 EL_SPRING, -1, MV_BIT_LEFT
3687 Xemerald_force_e, FALSE, FALSE,
3688 EL_EMERALD, -1, MV_BIT_RIGHT
3691 Xemerald_force_w, FALSE, FALSE,
3692 EL_EMERALD, -1, MV_BIT_LEFT
3695 Xdiamond_force_e, FALSE, FALSE,
3696 EL_DIAMOND, -1, MV_BIT_RIGHT
3699 Xdiamond_force_w, FALSE, FALSE,
3700 EL_DIAMOND, -1, MV_BIT_LEFT
3703 Xbomb_force_e, FALSE, FALSE,
3704 EL_BOMB, -1, MV_BIT_RIGHT
3707 Xbomb_force_w, FALSE, FALSE,
3708 EL_BOMB, -1, MV_BIT_LEFT
3710 #endif /* EM_ENGINE_BAD_ROLL */
3713 Xstone, TRUE, FALSE,
3717 Xstone_pause, FALSE, FALSE,
3721 Xstone_fall, FALSE, FALSE,
3725 Ystone_s, FALSE, FALSE,
3726 EL_ROCK, ACTION_FALLING, -1
3729 Ystone_sB, FALSE, TRUE,
3730 EL_ROCK, ACTION_FALLING, -1
3733 Ystone_e, FALSE, FALSE,
3734 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
3737 Ystone_eB, FALSE, TRUE,
3738 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
3741 Ystone_w, FALSE, FALSE,
3742 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
3745 Ystone_wB, FALSE, TRUE,
3746 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
3753 Xnut_pause, FALSE, FALSE,
3757 Xnut_fall, FALSE, FALSE,
3761 Ynut_s, FALSE, FALSE,
3762 EL_NUT, ACTION_FALLING, -1
3765 Ynut_sB, FALSE, TRUE,
3766 EL_NUT, ACTION_FALLING, -1
3769 Ynut_e, FALSE, FALSE,
3770 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
3773 Ynut_eB, FALSE, TRUE,
3774 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
3777 Ynut_w, FALSE, FALSE,
3778 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
3781 Ynut_wB, FALSE, TRUE,
3782 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
3785 Xbug_n, TRUE, FALSE,
3789 Xbug_e, TRUE, FALSE,
3790 EL_BUG_RIGHT, -1, -1
3793 Xbug_s, TRUE, FALSE,
3797 Xbug_w, TRUE, FALSE,
3801 Xbug_gon, FALSE, FALSE,
3805 Xbug_goe, FALSE, FALSE,
3806 EL_BUG_RIGHT, -1, -1
3809 Xbug_gos, FALSE, FALSE,
3813 Xbug_gow, FALSE, FALSE,
3817 Ybug_n, FALSE, FALSE,
3818 EL_BUG, ACTION_MOVING, MV_BIT_UP
3821 Ybug_nB, FALSE, TRUE,
3822 EL_BUG, ACTION_MOVING, MV_BIT_UP
3825 Ybug_e, FALSE, FALSE,
3826 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
3829 Ybug_eB, FALSE, TRUE,
3830 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
3833 Ybug_s, FALSE, FALSE,
3834 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
3837 Ybug_sB, FALSE, TRUE,
3838 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
3841 Ybug_w, FALSE, FALSE,
3842 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
3845 Ybug_wB, FALSE, TRUE,
3846 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
3849 Ybug_w_n, FALSE, FALSE,
3850 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
3853 Ybug_n_e, FALSE, FALSE,
3854 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
3857 Ybug_e_s, FALSE, FALSE,
3858 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
3861 Ybug_s_w, FALSE, FALSE,
3862 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
3865 Ybug_e_n, FALSE, FALSE,
3866 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
3869 Ybug_s_e, FALSE, FALSE,
3870 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
3873 Ybug_w_s, FALSE, FALSE,
3874 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
3877 Ybug_n_w, FALSE, FALSE,
3878 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
3881 Ybug_stone, FALSE, FALSE,
3882 EL_BUG, ACTION_SMASHED_BY_ROCK, -1
3885 Ybug_spring, FALSE, FALSE,
3886 EL_BUG, ACTION_SMASHED_BY_SPRING, -1
3889 Xtank_n, TRUE, FALSE,
3890 EL_SPACESHIP_UP, -1, -1
3893 Xtank_e, TRUE, FALSE,
3894 EL_SPACESHIP_RIGHT, -1, -1
3897 Xtank_s, TRUE, FALSE,
3898 EL_SPACESHIP_DOWN, -1, -1
3901 Xtank_w, TRUE, FALSE,
3902 EL_SPACESHIP_LEFT, -1, -1
3905 Xtank_gon, FALSE, FALSE,
3906 EL_SPACESHIP_UP, -1, -1
3909 Xtank_goe, FALSE, FALSE,
3910 EL_SPACESHIP_RIGHT, -1, -1
3913 Xtank_gos, FALSE, FALSE,
3914 EL_SPACESHIP_DOWN, -1, -1
3917 Xtank_gow, FALSE, FALSE,
3918 EL_SPACESHIP_LEFT, -1, -1
3921 Ytank_n, FALSE, FALSE,
3922 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
3925 Ytank_nB, FALSE, TRUE,
3926 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
3929 Ytank_e, FALSE, FALSE,
3930 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
3933 Ytank_eB, FALSE, TRUE,
3934 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
3937 Ytank_s, FALSE, FALSE,
3938 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
3941 Ytank_sB, FALSE, TRUE,
3942 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
3945 Ytank_w, FALSE, FALSE,
3946 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
3949 Ytank_wB, FALSE, TRUE,
3950 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
3953 Ytank_w_n, FALSE, FALSE,
3954 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
3957 Ytank_n_e, FALSE, FALSE,
3958 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
3961 Ytank_e_s, FALSE, FALSE,
3962 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
3965 Ytank_s_w, FALSE, FALSE,
3966 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
3969 Ytank_e_n, FALSE, FALSE,
3970 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
3973 Ytank_s_e, FALSE, FALSE,
3974 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
3977 Ytank_w_s, FALSE, FALSE,
3978 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
3981 Ytank_n_w, FALSE, FALSE,
3982 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
3985 Ytank_stone, FALSE, FALSE,
3986 EL_SPACESHIP, ACTION_SMASHED_BY_ROCK, -1
3989 Ytank_spring, FALSE, FALSE,
3990 EL_SPACESHIP, ACTION_SMASHED_BY_SPRING, -1
3993 Xandroid, TRUE, FALSE,
3994 EL_EMC_ANDROID, ACTION_ACTIVE, -1
3997 Xandroid_1_n, FALSE, FALSE,
3998 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
4001 Xandroid_2_n, FALSE, FALSE,
4002 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
4005 Xandroid_1_e, FALSE, FALSE,
4006 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
4009 Xandroid_2_e, FALSE, FALSE,
4010 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
4013 Xandroid_1_w, FALSE, FALSE,
4014 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
4017 Xandroid_2_w, FALSE, FALSE,
4018 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
4021 Xandroid_1_s, FALSE, FALSE,
4022 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
4025 Xandroid_2_s, FALSE, FALSE,
4026 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
4029 Yandroid_n, FALSE, FALSE,
4030 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
4033 Yandroid_nB, FALSE, TRUE,
4034 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
4037 Yandroid_ne, FALSE, FALSE,
4038 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPRIGHT
4041 Yandroid_neB, FALSE, TRUE,
4042 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPRIGHT
4045 Yandroid_e, FALSE, FALSE,
4046 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
4049 Yandroid_eB, FALSE, TRUE,
4050 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
4053 Yandroid_se, FALSE, FALSE,
4054 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNRIGHT
4057 Yandroid_seB, FALSE, TRUE,
4058 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNRIGHT
4061 Yandroid_s, FALSE, FALSE,
4062 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
4065 Yandroid_sB, FALSE, TRUE,
4066 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
4069 Yandroid_sw, FALSE, FALSE,
4070 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNLEFT
4073 Yandroid_swB, FALSE, TRUE,
4074 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNLEFT
4077 Yandroid_w, FALSE, FALSE,
4078 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
4081 Yandroid_wB, FALSE, TRUE,
4082 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
4085 Yandroid_nw, FALSE, FALSE,
4086 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPLEFT
4089 Yandroid_nwB, FALSE, TRUE,
4090 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPLEFT
4093 Xspring, TRUE, FALSE,
4097 Xspring_pause, FALSE, FALSE,
4101 Xspring_e, FALSE, FALSE,
4105 Xspring_w, FALSE, FALSE,
4109 Xspring_fall, FALSE, FALSE,
4113 Yspring_s, FALSE, FALSE,
4114 EL_SPRING, ACTION_FALLING, -1
4117 Yspring_sB, FALSE, TRUE,
4118 EL_SPRING, ACTION_FALLING, -1
4121 Yspring_e, FALSE, FALSE,
4122 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
4125 Yspring_eB, FALSE, TRUE,
4126 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
4129 Yspring_w, FALSE, FALSE,
4130 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
4133 Yspring_wB, FALSE, TRUE,
4134 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
4137 Yspring_kill_e, FALSE, FALSE,
4138 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
4141 Yspring_kill_eB, FALSE, TRUE,
4142 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
4145 Yspring_kill_w, FALSE, FALSE,
4146 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
4149 Yspring_kill_wB, FALSE, TRUE,
4150 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
4153 Xeater_n, TRUE, FALSE,
4154 EL_YAMYAM_UP, -1, -1
4157 Xeater_e, TRUE, FALSE,
4158 EL_YAMYAM_RIGHT, -1, -1
4161 Xeater_w, TRUE, FALSE,
4162 EL_YAMYAM_LEFT, -1, -1
4165 Xeater_s, TRUE, FALSE,
4166 EL_YAMYAM_DOWN, -1, -1
4169 Yeater_n, FALSE, FALSE,
4170 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
4173 Yeater_nB, FALSE, TRUE,
4174 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
4177 Yeater_e, FALSE, FALSE,
4178 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
4181 Yeater_eB, FALSE, TRUE,
4182 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
4185 Yeater_s, FALSE, FALSE,
4186 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
4189 Yeater_sB, FALSE, TRUE,
4190 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
4193 Yeater_w, FALSE, FALSE,
4194 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
4197 Yeater_wB, FALSE, TRUE,
4198 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
4201 Yeater_stone, FALSE, FALSE,
4202 EL_YAMYAM, ACTION_SMASHED_BY_ROCK, -1
4205 Yeater_spring, FALSE, FALSE,
4206 EL_YAMYAM, ACTION_SMASHED_BY_SPRING, -1
4209 Xalien, TRUE, FALSE,
4213 Xalien_pause, FALSE, FALSE,
4217 Yalien_n, FALSE, FALSE,
4218 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
4221 Yalien_nB, FALSE, TRUE,
4222 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
4225 Yalien_e, FALSE, FALSE,
4226 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
4229 Yalien_eB, FALSE, TRUE,
4230 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
4233 Yalien_s, FALSE, FALSE,
4234 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
4237 Yalien_sB, FALSE, TRUE,
4238 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
4241 Yalien_w, FALSE, FALSE,
4242 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
4245 Yalien_wB, FALSE, TRUE,
4246 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
4249 Yalien_stone, FALSE, FALSE,
4250 EL_ROBOT, ACTION_SMASHED_BY_ROCK, -1
4253 Yalien_spring, FALSE, FALSE,
4254 EL_ROBOT, ACTION_SMASHED_BY_SPRING, -1
4257 Xemerald, TRUE, FALSE,
4261 Xemerald_pause, FALSE, FALSE,
4265 Xemerald_fall, FALSE, FALSE,
4269 Xemerald_shine, FALSE, FALSE,
4270 EL_EMERALD, ACTION_TWINKLING, -1
4273 Yemerald_s, FALSE, FALSE,
4274 EL_EMERALD, ACTION_FALLING, -1
4277 Yemerald_sB, FALSE, TRUE,
4278 EL_EMERALD, ACTION_FALLING, -1
4281 Yemerald_e, FALSE, FALSE,
4282 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
4285 Yemerald_eB, FALSE, TRUE,
4286 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
4289 Yemerald_w, FALSE, FALSE,
4290 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
4293 Yemerald_wB, FALSE, TRUE,
4294 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
4297 Yemerald_eat, FALSE, FALSE,
4298 EL_EMERALD, ACTION_COLLECTING, -1
4301 Yemerald_stone, FALSE, FALSE,
4302 EL_NUT, ACTION_BREAKING, -1
4305 Xdiamond, TRUE, FALSE,
4309 Xdiamond_pause, FALSE, FALSE,
4313 Xdiamond_fall, FALSE, FALSE,
4317 Xdiamond_shine, FALSE, FALSE,
4318 EL_DIAMOND, ACTION_TWINKLING, -1
4321 Ydiamond_s, FALSE, FALSE,
4322 EL_DIAMOND, ACTION_FALLING, -1
4325 Ydiamond_sB, FALSE, TRUE,
4326 EL_DIAMOND, ACTION_FALLING, -1
4329 Ydiamond_e, FALSE, FALSE,
4330 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
4333 Ydiamond_eB, FALSE, TRUE,
4334 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
4337 Ydiamond_w, FALSE, FALSE,
4338 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
4341 Ydiamond_wB, FALSE, TRUE,
4342 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
4345 Ydiamond_eat, FALSE, FALSE,
4346 EL_DIAMOND, ACTION_COLLECTING, -1
4349 Ydiamond_stone, FALSE, FALSE,
4350 EL_DIAMOND, ACTION_SMASHED_BY_ROCK, -1
4353 Xdrip_fall, TRUE, FALSE,
4354 EL_AMOEBA_DROP, -1, -1
4357 Xdrip_stretch, FALSE, FALSE,
4358 EL_AMOEBA_DROP, ACTION_FALLING, -1
4361 Xdrip_stretchB, FALSE, TRUE,
4362 EL_AMOEBA_DROP, ACTION_FALLING, -1
4365 Xdrip_eat, FALSE, FALSE,
4366 EL_AMOEBA_DROP, ACTION_GROWING, -1
4369 Ydrip_s1, FALSE, FALSE,
4370 EL_AMOEBA_DROP, ACTION_FALLING, -1
4373 Ydrip_s1B, FALSE, TRUE,
4374 EL_AMOEBA_DROP, ACTION_FALLING, -1
4377 Ydrip_s2, FALSE, FALSE,
4378 EL_AMOEBA_DROP, ACTION_FALLING, -1
4381 Ydrip_s2B, FALSE, TRUE,
4382 EL_AMOEBA_DROP, ACTION_FALLING, -1
4389 Xbomb_pause, FALSE, FALSE,
4393 Xbomb_fall, FALSE, FALSE,
4397 Ybomb_s, FALSE, FALSE,
4398 EL_BOMB, ACTION_FALLING, -1
4401 Ybomb_sB, FALSE, TRUE,
4402 EL_BOMB, ACTION_FALLING, -1
4405 Ybomb_e, FALSE, FALSE,
4406 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
4409 Ybomb_eB, FALSE, TRUE,
4410 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
4413 Ybomb_w, FALSE, FALSE,
4414 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
4417 Ybomb_wB, FALSE, TRUE,
4418 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
4421 Ybomb_eat, FALSE, FALSE,
4422 EL_BOMB, ACTION_ACTIVATING, -1
4425 Xballoon, TRUE, FALSE,
4429 Yballoon_n, FALSE, FALSE,
4430 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
4433 Yballoon_nB, FALSE, TRUE,
4434 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
4437 Yballoon_e, FALSE, FALSE,
4438 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
4441 Yballoon_eB, FALSE, TRUE,
4442 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
4445 Yballoon_s, FALSE, FALSE,
4446 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
4449 Yballoon_sB, FALSE, TRUE,
4450 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
4453 Yballoon_w, FALSE, FALSE,
4454 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
4457 Yballoon_wB, FALSE, TRUE,
4458 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
4461 Xgrass, TRUE, FALSE,
4462 EL_EMC_GRASS, -1, -1
4465 Ygrass_nB, FALSE, FALSE,
4466 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_UP
4469 Ygrass_eB, FALSE, FALSE,
4470 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_RIGHT
4473 Ygrass_sB, FALSE, FALSE,
4474 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_DOWN
4477 Ygrass_wB, FALSE, FALSE,
4478 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_LEFT
4485 Ydirt_nB, FALSE, FALSE,
4486 EL_SAND, ACTION_DIGGING, MV_BIT_UP
4489 Ydirt_eB, FALSE, FALSE,
4490 EL_SAND, ACTION_DIGGING, MV_BIT_RIGHT
4493 Ydirt_sB, FALSE, FALSE,
4494 EL_SAND, ACTION_DIGGING, MV_BIT_DOWN
4497 Ydirt_wB, FALSE, FALSE,
4498 EL_SAND, ACTION_DIGGING, MV_BIT_LEFT
4501 Xacid_ne, TRUE, FALSE,
4502 EL_ACID_POOL_TOPRIGHT, -1, -1
4505 Xacid_se, TRUE, FALSE,
4506 EL_ACID_POOL_BOTTOMRIGHT, -1, -1
4509 Xacid_s, TRUE, FALSE,
4510 EL_ACID_POOL_BOTTOM, -1, -1
4513 Xacid_sw, TRUE, FALSE,
4514 EL_ACID_POOL_BOTTOMLEFT, -1, -1
4517 Xacid_nw, TRUE, FALSE,
4518 EL_ACID_POOL_TOPLEFT, -1, -1
4521 Xacid_1, TRUE, FALSE,
4525 Xacid_2, FALSE, FALSE,
4529 Xacid_3, FALSE, FALSE,
4533 Xacid_4, FALSE, FALSE,
4537 Xacid_5, FALSE, FALSE,
4541 Xacid_6, FALSE, FALSE,
4545 Xacid_7, FALSE, FALSE,
4549 Xacid_8, FALSE, FALSE,
4553 Xball_1, TRUE, FALSE,
4554 EL_EMC_MAGIC_BALL, -1, -1
4557 Xball_1B, FALSE, FALSE,
4558 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4561 Xball_2, FALSE, FALSE,
4562 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4565 Xball_2B, FALSE, FALSE,
4566 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4569 Yball_eat, FALSE, FALSE,
4570 EL_EMC_MAGIC_BALL, ACTION_DROPPING, -1
4573 Ykey_1_eat, FALSE, FALSE,
4574 EL_EM_KEY_1, ACTION_COLLECTING, -1
4577 Ykey_2_eat, FALSE, FALSE,
4578 EL_EM_KEY_2, ACTION_COLLECTING, -1
4581 Ykey_3_eat, FALSE, FALSE,
4582 EL_EM_KEY_3, ACTION_COLLECTING, -1
4585 Ykey_4_eat, FALSE, FALSE,
4586 EL_EM_KEY_4, ACTION_COLLECTING, -1
4589 Ykey_5_eat, FALSE, FALSE,
4590 EL_EMC_KEY_5, ACTION_COLLECTING, -1
4593 Ykey_6_eat, FALSE, FALSE,
4594 EL_EMC_KEY_6, ACTION_COLLECTING, -1
4597 Ykey_7_eat, FALSE, FALSE,
4598 EL_EMC_KEY_7, ACTION_COLLECTING, -1
4601 Ykey_8_eat, FALSE, FALSE,
4602 EL_EMC_KEY_8, ACTION_COLLECTING, -1
4605 Ylenses_eat, FALSE, FALSE,
4606 EL_EMC_LENSES, ACTION_COLLECTING, -1
4609 Ymagnify_eat, FALSE, FALSE,
4610 EL_EMC_MAGNIFIER, ACTION_COLLECTING, -1
4613 Ygrass_eat, FALSE, FALSE,
4614 EL_EMC_GRASS, ACTION_SNAPPING, -1
4617 Ydirt_eat, FALSE, FALSE,
4618 EL_SAND, ACTION_SNAPPING, -1
4621 Xgrow_ns, TRUE, FALSE,
4622 EL_EXPANDABLE_WALL_VERTICAL, -1, -1
4625 Ygrow_ns_eat, FALSE, FALSE,
4626 EL_EXPANDABLE_WALL_VERTICAL, ACTION_GROWING, -1
4629 Xgrow_ew, TRUE, FALSE,
4630 EL_EXPANDABLE_WALL_HORIZONTAL, -1, -1
4633 Ygrow_ew_eat, FALSE, FALSE,
4634 EL_EXPANDABLE_WALL_HORIZONTAL, ACTION_GROWING, -1
4637 Xwonderwall, TRUE, FALSE,
4638 EL_MAGIC_WALL, -1, -1
4641 XwonderwallB, FALSE, FALSE,
4642 EL_MAGIC_WALL, ACTION_ACTIVE, -1
4645 Xamoeba_1, TRUE, FALSE,
4646 EL_AMOEBA_DRY, ACTION_OTHER, -1
4649 Xamoeba_2, FALSE, FALSE,
4650 EL_AMOEBA_DRY, ACTION_OTHER, -1
4653 Xamoeba_3, FALSE, FALSE,
4654 EL_AMOEBA_DRY, ACTION_OTHER, -1
4657 Xamoeba_4, FALSE, FALSE,
4658 EL_AMOEBA_DRY, ACTION_OTHER, -1
4661 Xamoeba_5, TRUE, FALSE,
4662 EL_AMOEBA_WET, ACTION_OTHER, -1
4665 Xamoeba_6, FALSE, FALSE,
4666 EL_AMOEBA_WET, ACTION_OTHER, -1
4669 Xamoeba_7, FALSE, FALSE,
4670 EL_AMOEBA_WET, ACTION_OTHER, -1
4673 Xamoeba_8, FALSE, FALSE,
4674 EL_AMOEBA_WET, ACTION_OTHER, -1
4677 Xdoor_1, TRUE, FALSE,
4678 EL_EM_GATE_1, -1, -1
4681 Xdoor_2, TRUE, FALSE,
4682 EL_EM_GATE_2, -1, -1
4685 Xdoor_3, TRUE, FALSE,
4686 EL_EM_GATE_3, -1, -1
4689 Xdoor_4, TRUE, FALSE,
4690 EL_EM_GATE_4, -1, -1
4693 Xdoor_5, TRUE, FALSE,
4694 EL_EMC_GATE_5, -1, -1
4697 Xdoor_6, TRUE, FALSE,
4698 EL_EMC_GATE_6, -1, -1
4701 Xdoor_7, TRUE, FALSE,
4702 EL_EMC_GATE_7, -1, -1
4705 Xdoor_8, TRUE, FALSE,
4706 EL_EMC_GATE_8, -1, -1
4709 Xkey_1, TRUE, FALSE,
4713 Xkey_2, TRUE, FALSE,
4717 Xkey_3, TRUE, FALSE,
4721 Xkey_4, TRUE, FALSE,
4725 Xkey_5, TRUE, FALSE,
4726 EL_EMC_KEY_5, -1, -1
4729 Xkey_6, TRUE, FALSE,
4730 EL_EMC_KEY_6, -1, -1
4733 Xkey_7, TRUE, FALSE,
4734 EL_EMC_KEY_7, -1, -1
4737 Xkey_8, TRUE, FALSE,
4738 EL_EMC_KEY_8, -1, -1
4741 Xwind_n, TRUE, FALSE,
4742 EL_BALLOON_SWITCH_UP, -1, -1
4745 Xwind_e, TRUE, FALSE,
4746 EL_BALLOON_SWITCH_RIGHT, -1, -1
4749 Xwind_s, TRUE, FALSE,
4750 EL_BALLOON_SWITCH_DOWN, -1, -1
4753 Xwind_w, TRUE, FALSE,
4754 EL_BALLOON_SWITCH_LEFT, -1, -1
4757 Xwind_nesw, TRUE, FALSE,
4758 EL_BALLOON_SWITCH_ANY, -1, -1
4761 Xwind_stop, TRUE, FALSE,
4762 EL_BALLOON_SWITCH_NONE, -1, -1
4766 EL_EM_EXIT_CLOSED, -1, -1
4769 Xexit_1, TRUE, FALSE,
4770 EL_EM_EXIT_OPEN, -1, -1
4773 Xexit_2, FALSE, FALSE,
4774 EL_EM_EXIT_OPEN, -1, -1
4777 Xexit_3, FALSE, FALSE,
4778 EL_EM_EXIT_OPEN, -1, -1
4781 Xdynamite, TRUE, FALSE,
4782 EL_EM_DYNAMITE, -1, -1
4785 Ydynamite_eat, FALSE, FALSE,
4786 EL_EM_DYNAMITE, ACTION_COLLECTING, -1
4789 Xdynamite_1, TRUE, FALSE,
4790 EL_EM_DYNAMITE_ACTIVE, -1, -1
4793 Xdynamite_2, FALSE, FALSE,
4794 EL_EM_DYNAMITE_ACTIVE, -1, -1
4797 Xdynamite_3, FALSE, FALSE,
4798 EL_EM_DYNAMITE_ACTIVE, -1, -1
4801 Xdynamite_4, FALSE, FALSE,
4802 EL_EM_DYNAMITE_ACTIVE, -1, -1
4805 Xbumper, TRUE, FALSE,
4806 EL_EMC_SPRING_BUMPER, -1, -1
4809 XbumperB, FALSE, FALSE,
4810 EL_EMC_SPRING_BUMPER, ACTION_ACTIVE, -1
4813 Xwheel, TRUE, FALSE,
4814 EL_ROBOT_WHEEL, -1, -1
4817 XwheelB, FALSE, FALSE,
4818 EL_ROBOT_WHEEL, ACTION_ACTIVE, -1
4821 Xswitch, TRUE, FALSE,
4822 EL_EMC_MAGIC_BALL_SWITCH, -1, -1
4825 XswitchB, FALSE, FALSE,
4826 EL_EMC_MAGIC_BALL_SWITCH, ACTION_ACTIVE, -1
4830 EL_QUICKSAND_EMPTY, -1, -1
4833 Xsand_stone, TRUE, FALSE,
4834 EL_QUICKSAND_FULL, -1, -1
4837 Xsand_stonein_1, FALSE, TRUE,
4838 EL_ROCK, ACTION_FILLING, -1
4841 Xsand_stonein_2, FALSE, TRUE,
4842 EL_ROCK, ACTION_FILLING, -1
4845 Xsand_stonein_3, FALSE, TRUE,
4846 EL_ROCK, ACTION_FILLING, -1
4849 Xsand_stonein_4, FALSE, TRUE,
4850 EL_ROCK, ACTION_FILLING, -1
4853 Xsand_stonesand_1, FALSE, FALSE,
4854 EL_QUICKSAND_FULL, -1, -1
4857 Xsand_stonesand_2, FALSE, FALSE,
4858 EL_QUICKSAND_FULL, -1, -1
4861 Xsand_stonesand_3, FALSE, FALSE,
4862 EL_QUICKSAND_FULL, -1, -1
4865 Xsand_stonesand_4, FALSE, FALSE,
4866 EL_QUICKSAND_FULL, -1, -1
4869 Xsand_stoneout_1, FALSE, FALSE,
4870 EL_ROCK, ACTION_EMPTYING, -1
4873 Xsand_stoneout_2, FALSE, FALSE,
4874 EL_ROCK, ACTION_EMPTYING, -1
4877 Xsand_sandstone_1, FALSE, FALSE,
4878 EL_QUICKSAND_FULL, -1, -1
4881 Xsand_sandstone_2, FALSE, FALSE,
4882 EL_QUICKSAND_FULL, -1, -1
4885 Xsand_sandstone_3, FALSE, FALSE,
4886 EL_QUICKSAND_FULL, -1, -1
4889 Xsand_sandstone_4, FALSE, FALSE,
4890 EL_QUICKSAND_FULL, -1, -1
4893 Xplant, TRUE, FALSE,
4894 EL_EMC_PLANT, -1, -1
4897 Yplant, FALSE, FALSE,
4898 EL_EMC_PLANT, -1, -1
4901 Xlenses, TRUE, FALSE,
4902 EL_EMC_LENSES, -1, -1
4905 Xmagnify, TRUE, FALSE,
4906 EL_EMC_MAGNIFIER, -1, -1
4909 Xdripper, TRUE, FALSE,
4910 EL_EMC_DRIPPER, -1, -1
4913 XdripperB, FALSE, FALSE,
4914 EL_EMC_DRIPPER, ACTION_ACTIVE, -1
4917 Xfake_blank, TRUE, FALSE,
4918 EL_INVISIBLE_WALL, -1, -1
4921 Xfake_blankB, FALSE, FALSE,
4922 EL_INVISIBLE_WALL, ACTION_ACTIVE, -1
4925 Xfake_grass, TRUE, FALSE,
4926 EL_EMC_FAKE_GRASS, -1, -1
4929 Xfake_grassB, FALSE, FALSE,
4930 EL_EMC_FAKE_GRASS, ACTION_ACTIVE, -1
4933 Xfake_door_1, TRUE, FALSE,
4934 EL_EM_GATE_1_GRAY, -1, -1
4937 Xfake_door_2, TRUE, FALSE,
4938 EL_EM_GATE_2_GRAY, -1, -1
4941 Xfake_door_3, TRUE, FALSE,
4942 EL_EM_GATE_3_GRAY, -1, -1
4945 Xfake_door_4, TRUE, FALSE,
4946 EL_EM_GATE_4_GRAY, -1, -1
4949 Xfake_door_5, TRUE, FALSE,
4950 EL_EMC_GATE_5_GRAY, -1, -1
4953 Xfake_door_6, TRUE, FALSE,
4954 EL_EMC_GATE_6_GRAY, -1, -1
4957 Xfake_door_7, TRUE, FALSE,
4958 EL_EMC_GATE_7_GRAY, -1, -1
4961 Xfake_door_8, TRUE, FALSE,
4962 EL_EMC_GATE_8_GRAY, -1, -1
4965 Xfake_acid_1, TRUE, FALSE,
4966 EL_EMC_FAKE_ACID, -1, -1
4969 Xfake_acid_2, FALSE, FALSE,
4970 EL_EMC_FAKE_ACID, -1, -1
4973 Xfake_acid_3, FALSE, FALSE,
4974 EL_EMC_FAKE_ACID, -1, -1
4977 Xfake_acid_4, FALSE, FALSE,
4978 EL_EMC_FAKE_ACID, -1, -1
4981 Xfake_acid_5, FALSE, FALSE,
4982 EL_EMC_FAKE_ACID, -1, -1
4985 Xfake_acid_6, FALSE, FALSE,
4986 EL_EMC_FAKE_ACID, -1, -1
4989 Xfake_acid_7, FALSE, FALSE,
4990 EL_EMC_FAKE_ACID, -1, -1
4993 Xfake_acid_8, FALSE, FALSE,
4994 EL_EMC_FAKE_ACID, -1, -1
4997 Xsteel_1, TRUE, FALSE,
4998 EL_STEELWALL, -1, -1
5001 Xsteel_2, TRUE, FALSE,
5002 EL_EMC_STEELWALL_2, -1, -1
5005 Xsteel_3, TRUE, FALSE,
5006 EL_EMC_STEELWALL_3, -1, -1
5009 Xsteel_4, TRUE, FALSE,
5010 EL_EMC_STEELWALL_4, -1, -1
5013 Xwall_1, TRUE, FALSE,
5017 Xwall_2, TRUE, FALSE,
5018 EL_EMC_WALL_14, -1, -1
5021 Xwall_3, TRUE, FALSE,
5022 EL_EMC_WALL_15, -1, -1
5025 Xwall_4, TRUE, FALSE,
5026 EL_EMC_WALL_16, -1, -1
5029 Xround_wall_1, TRUE, FALSE,
5030 EL_WALL_SLIPPERY, -1, -1
5033 Xround_wall_2, TRUE, FALSE,
5034 EL_EMC_WALL_SLIPPERY_2, -1, -1
5037 Xround_wall_3, TRUE, FALSE,
5038 EL_EMC_WALL_SLIPPERY_3, -1, -1
5041 Xround_wall_4, TRUE, FALSE,
5042 EL_EMC_WALL_SLIPPERY_4, -1, -1
5045 Xdecor_1, TRUE, FALSE,
5046 EL_EMC_WALL_8, -1, -1
5049 Xdecor_2, TRUE, FALSE,
5050 EL_EMC_WALL_6, -1, -1
5053 Xdecor_3, TRUE, FALSE,
5054 EL_EMC_WALL_4, -1, -1
5057 Xdecor_4, TRUE, FALSE,
5058 EL_EMC_WALL_7, -1, -1
5061 Xdecor_5, TRUE, FALSE,
5062 EL_EMC_WALL_5, -1, -1
5065 Xdecor_6, TRUE, FALSE,
5066 EL_EMC_WALL_9, -1, -1
5069 Xdecor_7, TRUE, FALSE,
5070 EL_EMC_WALL_10, -1, -1
5073 Xdecor_8, TRUE, FALSE,
5074 EL_EMC_WALL_1, -1, -1
5077 Xdecor_9, TRUE, FALSE,
5078 EL_EMC_WALL_2, -1, -1
5081 Xdecor_10, TRUE, FALSE,
5082 EL_EMC_WALL_3, -1, -1
5085 Xdecor_11, TRUE, FALSE,
5086 EL_EMC_WALL_11, -1, -1
5089 Xdecor_12, TRUE, FALSE,
5090 EL_EMC_WALL_12, -1, -1
5093 Xalpha_0, TRUE, FALSE,
5094 EL_CHAR('0'), -1, -1
5097 Xalpha_1, TRUE, FALSE,
5098 EL_CHAR('1'), -1, -1
5101 Xalpha_2, TRUE, FALSE,
5102 EL_CHAR('2'), -1, -1
5105 Xalpha_3, TRUE, FALSE,
5106 EL_CHAR('3'), -1, -1
5109 Xalpha_4, TRUE, FALSE,
5110 EL_CHAR('4'), -1, -1
5113 Xalpha_5, TRUE, FALSE,
5114 EL_CHAR('5'), -1, -1
5117 Xalpha_6, TRUE, FALSE,
5118 EL_CHAR('6'), -1, -1
5121 Xalpha_7, TRUE, FALSE,
5122 EL_CHAR('7'), -1, -1
5125 Xalpha_8, TRUE, FALSE,
5126 EL_CHAR('8'), -1, -1
5129 Xalpha_9, TRUE, FALSE,
5130 EL_CHAR('9'), -1, -1
5133 Xalpha_excla, TRUE, FALSE,
5134 EL_CHAR('!'), -1, -1
5137 Xalpha_quote, TRUE, FALSE,
5138 EL_CHAR('"'), -1, -1
5141 Xalpha_comma, TRUE, FALSE,
5142 EL_CHAR(','), -1, -1
5145 Xalpha_minus, TRUE, FALSE,
5146 EL_CHAR('-'), -1, -1
5149 Xalpha_perio, TRUE, FALSE,
5150 EL_CHAR('.'), -1, -1
5153 Xalpha_colon, TRUE, FALSE,
5154 EL_CHAR(':'), -1, -1
5157 Xalpha_quest, TRUE, FALSE,
5158 EL_CHAR('?'), -1, -1
5161 Xalpha_a, TRUE, FALSE,
5162 EL_CHAR('A'), -1, -1
5165 Xalpha_b, TRUE, FALSE,
5166 EL_CHAR('B'), -1, -1
5169 Xalpha_c, TRUE, FALSE,
5170 EL_CHAR('C'), -1, -1
5173 Xalpha_d, TRUE, FALSE,
5174 EL_CHAR('D'), -1, -1
5177 Xalpha_e, TRUE, FALSE,
5178 EL_CHAR('E'), -1, -1
5181 Xalpha_f, TRUE, FALSE,
5182 EL_CHAR('F'), -1, -1
5185 Xalpha_g, TRUE, FALSE,
5186 EL_CHAR('G'), -1, -1
5189 Xalpha_h, TRUE, FALSE,
5190 EL_CHAR('H'), -1, -1
5193 Xalpha_i, TRUE, FALSE,
5194 EL_CHAR('I'), -1, -1
5197 Xalpha_j, TRUE, FALSE,
5198 EL_CHAR('J'), -1, -1
5201 Xalpha_k, TRUE, FALSE,
5202 EL_CHAR('K'), -1, -1
5205 Xalpha_l, TRUE, FALSE,
5206 EL_CHAR('L'), -1, -1
5209 Xalpha_m, TRUE, FALSE,
5210 EL_CHAR('M'), -1, -1
5213 Xalpha_n, TRUE, FALSE,
5214 EL_CHAR('N'), -1, -1
5217 Xalpha_o, TRUE, FALSE,
5218 EL_CHAR('O'), -1, -1
5221 Xalpha_p, TRUE, FALSE,
5222 EL_CHAR('P'), -1, -1
5225 Xalpha_q, TRUE, FALSE,
5226 EL_CHAR('Q'), -1, -1
5229 Xalpha_r, TRUE, FALSE,
5230 EL_CHAR('R'), -1, -1
5233 Xalpha_s, TRUE, FALSE,
5234 EL_CHAR('S'), -1, -1
5237 Xalpha_t, TRUE, FALSE,
5238 EL_CHAR('T'), -1, -1
5241 Xalpha_u, TRUE, FALSE,
5242 EL_CHAR('U'), -1, -1
5245 Xalpha_v, TRUE, FALSE,
5246 EL_CHAR('V'), -1, -1
5249 Xalpha_w, TRUE, FALSE,
5250 EL_CHAR('W'), -1, -1
5253 Xalpha_x, TRUE, FALSE,
5254 EL_CHAR('X'), -1, -1
5257 Xalpha_y, TRUE, FALSE,
5258 EL_CHAR('Y'), -1, -1
5261 Xalpha_z, TRUE, FALSE,
5262 EL_CHAR('Z'), -1, -1
5265 Xalpha_arrow_e, TRUE, FALSE,
5266 EL_CHAR('>'), -1, -1
5269 Xalpha_arrow_w, TRUE, FALSE,
5270 EL_CHAR('<'), -1, -1
5273 Xalpha_copyr, TRUE, FALSE,
5274 EL_CHAR('©'), -1, -1
5278 Xboom_bug, FALSE, FALSE,
5279 EL_BUG, ACTION_EXPLODING, -1
5282 Xboom_bomb, FALSE, FALSE,
5283 EL_BOMB, ACTION_EXPLODING, -1
5286 Xboom_android, FALSE, FALSE,
5287 EL_EMC_ANDROID, ACTION_OTHER, -1
5290 Xboom_1, FALSE, FALSE,
5291 EL_DEFAULT, ACTION_EXPLODING, -1
5294 Xboom_2, FALSE, FALSE,
5295 EL_DEFAULT, ACTION_EXPLODING, -1
5298 Znormal, FALSE, FALSE,
5302 Zdynamite, FALSE, FALSE,
5306 Zplayer, FALSE, FALSE,
5310 ZBORDER, FALSE, FALSE,
5320 static struct Mapping_EM_to_RND_player
5329 em_player_mapping_list[] =
5333 EL_PLAYER_1, ACTION_MOVING, MV_BIT_UP,
5337 EL_PLAYER_1, ACTION_MOVING, MV_BIT_RIGHT,
5341 EL_PLAYER_1, ACTION_MOVING, MV_BIT_DOWN,
5345 EL_PLAYER_1, ACTION_MOVING, MV_BIT_LEFT,
5349 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_UP,
5353 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_RIGHT,
5357 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_DOWN,
5361 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_LEFT,
5365 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_UP,
5369 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_RIGHT,
5373 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_DOWN,
5377 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_LEFT,
5381 EL_PLAYER_2, ACTION_MOVING, MV_BIT_UP,
5385 EL_PLAYER_2, ACTION_MOVING, MV_BIT_RIGHT,
5389 EL_PLAYER_2, ACTION_MOVING, MV_BIT_DOWN,
5393 EL_PLAYER_2, ACTION_MOVING, MV_BIT_LEFT,
5397 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_UP,
5401 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_RIGHT,
5405 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_DOWN,
5409 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_LEFT,
5413 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_UP,
5417 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_RIGHT,
5421 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_DOWN,
5425 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_LEFT,
5429 EL_PLAYER_1, ACTION_DEFAULT, -1,
5433 EL_PLAYER_2, ACTION_DEFAULT, -1,
5437 EL_PLAYER_3, ACTION_MOVING, MV_BIT_UP,
5441 EL_PLAYER_3, ACTION_MOVING, MV_BIT_RIGHT,
5445 EL_PLAYER_3, ACTION_MOVING, MV_BIT_DOWN,
5449 EL_PLAYER_3, ACTION_MOVING, MV_BIT_LEFT,
5453 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_UP,
5457 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_RIGHT,
5461 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_DOWN,
5465 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_LEFT,
5469 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_UP,
5473 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_RIGHT,
5477 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_DOWN,
5481 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_LEFT,
5485 EL_PLAYER_4, ACTION_MOVING, MV_BIT_UP,
5489 EL_PLAYER_4, ACTION_MOVING, MV_BIT_RIGHT,
5493 EL_PLAYER_4, ACTION_MOVING, MV_BIT_DOWN,
5497 EL_PLAYER_4, ACTION_MOVING, MV_BIT_LEFT,
5501 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_UP,
5505 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_RIGHT,
5509 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_DOWN,
5513 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_LEFT,
5517 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_UP,
5521 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_RIGHT,
5525 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_DOWN,
5529 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_LEFT,
5533 EL_PLAYER_3, ACTION_DEFAULT, -1,
5537 EL_PLAYER_4, ACTION_DEFAULT, -1,
5546 int map_element_RND_to_EM(int element_rnd)
5548 static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
5549 static boolean mapping_initialized = FALSE;
5551 if (!mapping_initialized)
5555 /* return "Xalpha_quest" for all undefined elements in mapping array */
5556 for (i = 0; i < NUM_FILE_ELEMENTS; i++)
5557 mapping_RND_to_EM[i] = Xalpha_quest;
5559 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5560 if (em_object_mapping_list[i].is_rnd_to_em_mapping)
5561 mapping_RND_to_EM[em_object_mapping_list[i].element_rnd] =
5562 em_object_mapping_list[i].element_em;
5564 mapping_initialized = TRUE;
5567 if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
5568 return mapping_RND_to_EM[element_rnd];
5570 Error(ERR_WARN, "invalid RND level element %d", element_rnd);
5575 int map_element_EM_to_RND(int element_em)
5577 static unsigned short mapping_EM_to_RND[TILE_MAX];
5578 static boolean mapping_initialized = FALSE;
5580 if (!mapping_initialized)
5584 /* return "EL_UNKNOWN" for all undefined elements in mapping array */
5585 for (i = 0; i < TILE_MAX; i++)
5586 mapping_EM_to_RND[i] = EL_UNKNOWN;
5588 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5589 mapping_EM_to_RND[em_object_mapping_list[i].element_em] =
5590 em_object_mapping_list[i].element_rnd;
5592 mapping_initialized = TRUE;
5595 if (element_em >= 0 && element_em < TILE_MAX)
5596 return mapping_EM_to_RND[element_em];
5598 Error(ERR_WARN, "invalid EM level element %d", element_em);
5603 void map_android_clone_elements_RND_to_EM(struct LevelInfo *level)
5605 struct LevelInfo_EM *level_em = level->native_em_level;
5606 struct LEVEL *lev = level_em->lev;
5609 for (i = 0; i < TILE_MAX; i++)
5610 lev->android_array[i] = Xblank;
5612 for (i = 0; i < level->num_android_clone_elements; i++)
5614 int element_rnd = level->android_clone_element[i];
5615 int element_em = map_element_RND_to_EM(element_rnd);
5617 for (j = 0; em_object_mapping_list[j].element_em != -1; j++)
5618 if (em_object_mapping_list[j].element_rnd == element_rnd)
5619 lev->android_array[em_object_mapping_list[j].element_em] = element_em;
5623 void map_android_clone_elements_EM_to_RND(struct LevelInfo *level)
5625 struct LevelInfo_EM *level_em = level->native_em_level;
5626 struct LEVEL *lev = level_em->lev;
5629 level->num_android_clone_elements = 0;
5631 for (i = 0; i < TILE_MAX; i++)
5633 int element_em = lev->android_array[i];
5635 boolean element_found = FALSE;
5637 if (element_em == Xblank)
5640 element_rnd = map_element_EM_to_RND(element_em);
5642 for (j = 0; j < level->num_android_clone_elements; j++)
5643 if (level->android_clone_element[j] == element_rnd)
5644 element_found = TRUE;
5648 level->android_clone_element[level->num_android_clone_elements++] =
5651 if (level->num_android_clone_elements == MAX_ANDROID_ELEMENTS)
5656 if (level->num_android_clone_elements == 0)
5658 level->num_android_clone_elements = 1;
5659 level->android_clone_element[0] = EL_EMPTY;
5663 int map_direction_RND_to_EM(int direction)
5665 return (direction == MV_UP ? 0 :
5666 direction == MV_RIGHT ? 1 :
5667 direction == MV_DOWN ? 2 :
5668 direction == MV_LEFT ? 3 :
5672 int map_direction_EM_to_RND(int direction)
5674 return (direction == 0 ? MV_UP :
5675 direction == 1 ? MV_RIGHT :
5676 direction == 2 ? MV_DOWN :
5677 direction == 3 ? MV_LEFT :
5681 int get_next_element(int element)
5685 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
5686 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
5687 case EL_QUICKSAND_FAST_FILLING: return EL_QUICKSAND_FAST_FULL;
5688 case EL_QUICKSAND_FAST_EMPTYING: return EL_QUICKSAND_FAST_EMPTY;
5689 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
5690 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
5691 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
5692 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
5693 case EL_DC_MAGIC_WALL_FILLING: return EL_DC_MAGIC_WALL_FULL;
5694 case EL_DC_MAGIC_WALL_EMPTYING: return EL_DC_MAGIC_WALL_ACTIVE;
5695 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
5697 default: return element;
5702 int el_act_dir2img(int element, int action, int direction)
5704 element = GFX_ELEMENT(element);
5706 if (direction == MV_NONE)
5707 return element_info[element].graphic[action];
5709 direction = MV_DIR_TO_BIT(direction);
5711 return element_info[element].direction_graphic[action][direction];
5714 int el_act_dir2img(int element, int action, int direction)
5716 element = GFX_ELEMENT(element);
5717 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
5719 /* direction_graphic[][] == graphic[] for undefined direction graphics */
5720 return element_info[element].direction_graphic[action][direction];
5725 static int el_act_dir2crm(int element, int action, int direction)
5727 element = GFX_ELEMENT(element);
5729 if (direction == MV_NONE)
5730 return element_info[element].crumbled[action];
5732 direction = MV_DIR_TO_BIT(direction);
5734 return element_info[element].direction_crumbled[action][direction];
5737 static int el_act_dir2crm(int element, int action, int direction)
5739 element = GFX_ELEMENT(element);
5740 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
5742 /* direction_graphic[][] == graphic[] for undefined direction graphics */
5743 return element_info[element].direction_crumbled[action][direction];
5747 int el_act2img(int element, int action)
5749 element = GFX_ELEMENT(element);
5751 return element_info[element].graphic[action];
5754 int el_act2crm(int element, int action)
5756 element = GFX_ELEMENT(element);
5758 return element_info[element].crumbled[action];
5761 int el_dir2img(int element, int direction)
5763 element = GFX_ELEMENT(element);
5765 return el_act_dir2img(element, ACTION_DEFAULT, direction);
5768 int el2baseimg(int element)
5770 return element_info[element].graphic[ACTION_DEFAULT];
5773 int el2img(int element)
5775 element = GFX_ELEMENT(element);
5777 return element_info[element].graphic[ACTION_DEFAULT];
5780 int el2edimg(int element)
5782 element = GFX_ELEMENT(element);
5784 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
5787 int el2preimg(int element)
5789 element = GFX_ELEMENT(element);
5791 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
5794 int el2panelimg(int element)
5796 element = GFX_ELEMENT(element);
5798 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PANEL];
5801 int font2baseimg(int font_nr)
5803 return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
5806 int getBeltNrFromBeltElement(int element)
5808 return (element < EL_CONVEYOR_BELT_2_LEFT ? 0 :
5809 element < EL_CONVEYOR_BELT_3_LEFT ? 1 :
5810 element < EL_CONVEYOR_BELT_4_LEFT ? 2 : 3);
5813 int getBeltNrFromBeltActiveElement(int element)
5815 return (element < EL_CONVEYOR_BELT_2_LEFT_ACTIVE ? 0 :
5816 element < EL_CONVEYOR_BELT_3_LEFT_ACTIVE ? 1 :
5817 element < EL_CONVEYOR_BELT_4_LEFT_ACTIVE ? 2 : 3);
5820 int getBeltNrFromBeltSwitchElement(int element)
5822 return (element < EL_CONVEYOR_BELT_2_SWITCH_LEFT ? 0 :
5823 element < EL_CONVEYOR_BELT_3_SWITCH_LEFT ? 1 :
5824 element < EL_CONVEYOR_BELT_4_SWITCH_LEFT ? 2 : 3);
5827 int getBeltDirNrFromBeltElement(int element)
5829 static int belt_base_element[4] =
5831 EL_CONVEYOR_BELT_1_LEFT,
5832 EL_CONVEYOR_BELT_2_LEFT,
5833 EL_CONVEYOR_BELT_3_LEFT,
5834 EL_CONVEYOR_BELT_4_LEFT
5837 int belt_nr = getBeltNrFromBeltElement(element);
5838 int belt_dir_nr = element - belt_base_element[belt_nr];
5840 return (belt_dir_nr % 3);
5843 int getBeltDirNrFromBeltSwitchElement(int element)
5845 static int belt_base_element[4] =
5847 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
5848 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
5849 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
5850 EL_CONVEYOR_BELT_4_SWITCH_LEFT
5853 int belt_nr = getBeltNrFromBeltSwitchElement(element);
5854 int belt_dir_nr = element - belt_base_element[belt_nr];
5856 return (belt_dir_nr % 3);
5859 int getBeltDirFromBeltElement(int element)
5861 static int belt_move_dir[3] =
5868 int belt_dir_nr = getBeltDirNrFromBeltElement(element);
5870 return belt_move_dir[belt_dir_nr];
5873 int getBeltDirFromBeltSwitchElement(int element)
5875 static int belt_move_dir[3] =
5882 int belt_dir_nr = getBeltDirNrFromBeltSwitchElement(element);
5884 return belt_move_dir[belt_dir_nr];
5887 int getBeltElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
5889 static int belt_base_element[4] =
5891 EL_CONVEYOR_BELT_1_LEFT,
5892 EL_CONVEYOR_BELT_2_LEFT,
5893 EL_CONVEYOR_BELT_3_LEFT,
5894 EL_CONVEYOR_BELT_4_LEFT
5897 return belt_base_element[belt_nr] + belt_dir_nr;
5900 int getBeltElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
5902 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
5904 return getBeltElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
5907 int getBeltSwitchElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
5909 static int belt_base_element[4] =
5911 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
5912 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
5913 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
5914 EL_CONVEYOR_BELT_4_SWITCH_LEFT
5917 return belt_base_element[belt_nr] + belt_dir_nr;
5920 int getBeltSwitchElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
5922 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
5924 return getBeltSwitchElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
5927 int getNumActivePlayers_EM()
5929 int num_players = 0;
5935 for (i = 0; i < MAX_PLAYERS; i++)
5936 if (tape.player_participates[i])
5942 int getGameFrameDelay_EM(int native_em_game_frame_delay)
5944 int game_frame_delay_value;
5946 game_frame_delay_value =
5947 (tape.playing && tape.fast_forward ? FfwdFrameDelay :
5948 GameFrameDelay == GAME_FRAME_DELAY ? native_em_game_frame_delay :
5951 if (tape.playing && tape.warp_forward && !tape.pausing)
5952 game_frame_delay_value = 0;
5954 return game_frame_delay_value;
5957 unsigned int InitRND(long seed)
5959 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
5960 return InitEngineRandom_EM(seed);
5962 return InitEngineRandom_RND(seed);
5966 static struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
5967 static struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
5970 void ResetGfxAnimation_EM(int x, int y, int tile)
5975 void getGraphicSourceObjectExt_EM(int tile, int frame_em,
5976 Bitmap **src_bitmap, int *src_x, int *src_y,
5979 int element = object_mapping[tile].element_rnd;
5980 int action = object_mapping[tile].action;
5981 int direction = object_mapping[tile].direction;
5982 boolean is_backside = object_mapping[tile].is_backside;
5983 boolean action_removing = (action == ACTION_DIGGING ||
5984 action == ACTION_SNAPPING ||
5985 action == ACTION_COLLECTING);
5986 int effective_element = (frame_em > 0 ? element :
5987 is_backside ? EL_EMPTY :
5988 action_removing ? EL_EMPTY :
5990 int graphic = (direction == MV_NONE ?
5991 el_act2img(effective_element, action) :
5992 el_act_dir2img(effective_element, action, direction));
5993 struct GraphicInfo *g = &graphic_info[graphic];
5996 if (graphic_info[graphic].anim_global_sync)
5997 sync_frame = FrameCounter;
5999 sync_frame = 7 - frame_em;
6001 SetRandomAnimationValue(x, y);
6003 int frame = getAnimationFrame(g->anim_frames,
6006 g->anim_start_frame,
6009 getGraphicSourceExt(graphic, frame, src_bitmap, src_x, src_y, FALSE);
6012 void getGraphicSourcePlayerExt_EM(int player_nr, int anim, int frame_em,
6013 Bitmap **src_bitmap, int *src_x, int *src_y)
6015 int element = player_mapping[player_nr][anim].element_rnd;
6016 int action = player_mapping[player_nr][anim].action;
6017 int direction = player_mapping[player_nr][anim].direction;
6018 int graphic = (direction == MV_NONE ?
6019 el_act2img(element, action) :
6020 el_act_dir2img(element, action, direction));
6021 struct GraphicInfo *g = &graphic_info[graphic];
6024 InitPlayerGfxAnimation(&stored_player[player_nr], action, direction);
6026 stored_player[player_nr].StepFrame = 7 - frame_em;
6028 sync_frame = stored_player[player_nr].Frame;
6031 printf("::: %d: %d, %d [%d]\n",
6033 stored_player[player_nr].Frame,
6034 stored_player[player_nr].StepFrame,
6038 int frame = getAnimationFrame(g->anim_frames,
6041 g->anim_start_frame,
6044 getGraphicSourceExt(graphic, frame, src_bitmap, src_x, src_y, FALSE);
6047 void InitGraphicInfo_EM(void)
6050 struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
6051 struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
6056 int num_em_gfx_errors = 0;
6058 if (graphic_info_em_object[0][0].bitmap == NULL)
6060 /* EM graphics not yet initialized in em_open_all() */
6065 printf("::: [4 errors can be ignored (1 x 'bomb', 3 x 'em_dynamite']\n");
6068 /* always start with reliable default values */
6069 for (i = 0; i < TILE_MAX; i++)
6071 object_mapping[i].element_rnd = EL_UNKNOWN;
6072 object_mapping[i].is_backside = FALSE;
6073 object_mapping[i].action = ACTION_DEFAULT;
6074 object_mapping[i].direction = MV_NONE;
6077 /* always start with reliable default values */
6078 for (p = 0; p < MAX_PLAYERS; p++)
6080 for (i = 0; i < SPR_MAX; i++)
6082 player_mapping[p][i].element_rnd = EL_UNKNOWN;
6083 player_mapping[p][i].action = ACTION_DEFAULT;
6084 player_mapping[p][i].direction = MV_NONE;
6088 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
6090 int e = em_object_mapping_list[i].element_em;
6092 object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd;
6093 object_mapping[e].is_backside = em_object_mapping_list[i].is_backside;
6095 if (em_object_mapping_list[i].action != -1)
6096 object_mapping[e].action = em_object_mapping_list[i].action;
6098 if (em_object_mapping_list[i].direction != -1)
6099 object_mapping[e].direction =
6100 MV_DIR_FROM_BIT(em_object_mapping_list[i].direction);
6103 for (i = 0; em_player_mapping_list[i].action_em != -1; i++)
6105 int a = em_player_mapping_list[i].action_em;
6106 int p = em_player_mapping_list[i].player_nr;
6108 player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd;
6110 if (em_player_mapping_list[i].action != -1)
6111 player_mapping[p][a].action = em_player_mapping_list[i].action;
6113 if (em_player_mapping_list[i].direction != -1)
6114 player_mapping[p][a].direction =
6115 MV_DIR_FROM_BIT(em_player_mapping_list[i].direction);
6118 for (i = 0; i < TILE_MAX; i++)
6120 int element = object_mapping[i].element_rnd;
6121 int action = object_mapping[i].action;
6122 int direction = object_mapping[i].direction;
6123 boolean is_backside = object_mapping[i].is_backside;
6124 boolean action_removing = (action == ACTION_DIGGING ||
6125 action == ACTION_SNAPPING ||
6126 action == ACTION_COLLECTING);
6127 boolean action_exploding = ((action == ACTION_EXPLODING ||
6128 action == ACTION_SMASHED_BY_ROCK ||
6129 action == ACTION_SMASHED_BY_SPRING) &&
6130 element != EL_DIAMOND);
6131 boolean action_active = (action == ACTION_ACTIVE);
6132 boolean action_other = (action == ACTION_OTHER);
6134 for (j = 0; j < 8; j++)
6136 int effective_element = (j > 5 && i == Yacid_splash_eB ? EL_EMPTY :
6137 j > 5 && i == Yacid_splash_wB ? EL_EMPTY :
6139 i == Xdrip_stretch ? element :
6140 i == Xdrip_stretchB ? element :
6141 i == Ydrip_s1 ? element :
6142 i == Ydrip_s1B ? element :
6143 i == Xball_1B ? element :
6144 i == Xball_2 ? element :
6145 i == Xball_2B ? element :
6146 i == Yball_eat ? element :
6147 i == Ykey_1_eat ? element :
6148 i == Ykey_2_eat ? element :
6149 i == Ykey_3_eat ? element :
6150 i == Ykey_4_eat ? element :
6151 i == Ykey_5_eat ? element :
6152 i == Ykey_6_eat ? element :
6153 i == Ykey_7_eat ? element :
6154 i == Ykey_8_eat ? element :
6155 i == Ylenses_eat ? element :
6156 i == Ymagnify_eat ? element :
6157 i == Ygrass_eat ? element :
6158 i == Ydirt_eat ? element :
6159 i == Yemerald_stone ? EL_EMERALD :
6160 i == Ydiamond_stone ? EL_ROCK :
6161 i == Xsand_stonein_1 ? element :
6162 i == Xsand_stonein_2 ? element :
6163 i == Xsand_stonein_3 ? element :
6164 i == Xsand_stonein_4 ? element :
6165 is_backside ? EL_EMPTY :
6166 action_removing ? EL_EMPTY :
6168 int effective_action = (j < 7 ? action :
6169 i == Xdrip_stretch ? action :
6170 i == Xdrip_stretchB ? action :
6171 i == Ydrip_s1 ? action :
6172 i == Ydrip_s1B ? action :
6173 i == Xball_1B ? action :
6174 i == Xball_2 ? action :
6175 i == Xball_2B ? action :
6176 i == Yball_eat ? action :
6177 i == Ykey_1_eat ? action :
6178 i == Ykey_2_eat ? action :
6179 i == Ykey_3_eat ? action :
6180 i == Ykey_4_eat ? action :
6181 i == Ykey_5_eat ? action :
6182 i == Ykey_6_eat ? action :
6183 i == Ykey_7_eat ? action :
6184 i == Ykey_8_eat ? action :
6185 i == Ylenses_eat ? action :
6186 i == Ymagnify_eat ? action :
6187 i == Ygrass_eat ? action :
6188 i == Ydirt_eat ? action :
6189 i == Xsand_stonein_1 ? action :
6190 i == Xsand_stonein_2 ? action :
6191 i == Xsand_stonein_3 ? action :
6192 i == Xsand_stonein_4 ? action :
6193 i == Xsand_stoneout_1 ? action :
6194 i == Xsand_stoneout_2 ? action :
6195 i == Xboom_android ? ACTION_EXPLODING :
6196 action_exploding ? ACTION_EXPLODING :
6197 action_active ? action :
6198 action_other ? action :
6200 int graphic = (el_act_dir2img(effective_element, effective_action,
6202 int crumbled = (el_act_dir2crm(effective_element, effective_action,
6204 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
6205 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
6206 boolean has_action_graphics = (graphic != base_graphic);
6207 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
6208 struct GraphicInfo *g = &graphic_info[graphic];
6209 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
6212 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
6213 boolean special_animation = (action != ACTION_DEFAULT &&
6214 g->anim_frames == 3 &&
6215 g->anim_delay == 2 &&
6216 g->anim_mode & ANIM_LINEAR);
6217 int sync_frame = (i == Xdrip_stretch ? 7 :
6218 i == Xdrip_stretchB ? 7 :
6219 i == Ydrip_s2 ? j + 8 :
6220 i == Ydrip_s2B ? j + 8 :
6229 i == Xfake_acid_1 ? 0 :
6230 i == Xfake_acid_2 ? 10 :
6231 i == Xfake_acid_3 ? 20 :
6232 i == Xfake_acid_4 ? 30 :
6233 i == Xfake_acid_5 ? 40 :
6234 i == Xfake_acid_6 ? 50 :
6235 i == Xfake_acid_7 ? 60 :
6236 i == Xfake_acid_8 ? 70 :
6238 i == Xball_2B ? j + 8 :
6239 i == Yball_eat ? j + 1 :
6240 i == Ykey_1_eat ? j + 1 :
6241 i == Ykey_2_eat ? j + 1 :
6242 i == Ykey_3_eat ? j + 1 :
6243 i == Ykey_4_eat ? j + 1 :
6244 i == Ykey_5_eat ? j + 1 :
6245 i == Ykey_6_eat ? j + 1 :
6246 i == Ykey_7_eat ? j + 1 :
6247 i == Ykey_8_eat ? j + 1 :
6248 i == Ylenses_eat ? j + 1 :
6249 i == Ymagnify_eat ? j + 1 :
6250 i == Ygrass_eat ? j + 1 :
6251 i == Ydirt_eat ? j + 1 :
6252 i == Xamoeba_1 ? 0 :
6253 i == Xamoeba_2 ? 1 :
6254 i == Xamoeba_3 ? 2 :
6255 i == Xamoeba_4 ? 3 :
6256 i == Xamoeba_5 ? 0 :
6257 i == Xamoeba_6 ? 1 :
6258 i == Xamoeba_7 ? 2 :
6259 i == Xamoeba_8 ? 3 :
6260 i == Xexit_2 ? j + 8 :
6261 i == Xexit_3 ? j + 16 :
6262 i == Xdynamite_1 ? 0 :
6263 i == Xdynamite_2 ? 8 :
6264 i == Xdynamite_3 ? 16 :
6265 i == Xdynamite_4 ? 24 :
6266 i == Xsand_stonein_1 ? j + 1 :
6267 i == Xsand_stonein_2 ? j + 9 :
6268 i == Xsand_stonein_3 ? j + 17 :
6269 i == Xsand_stonein_4 ? j + 25 :
6270 i == Xsand_stoneout_1 && j == 0 ? 0 :
6271 i == Xsand_stoneout_1 && j == 1 ? 0 :
6272 i == Xsand_stoneout_1 && j == 2 ? 1 :
6273 i == Xsand_stoneout_1 && j == 3 ? 2 :
6274 i == Xsand_stoneout_1 && j == 4 ? 2 :
6275 i == Xsand_stoneout_1 && j == 5 ? 3 :
6276 i == Xsand_stoneout_1 && j == 6 ? 4 :
6277 i == Xsand_stoneout_1 && j == 7 ? 4 :
6278 i == Xsand_stoneout_2 && j == 0 ? 5 :
6279 i == Xsand_stoneout_2 && j == 1 ? 6 :
6280 i == Xsand_stoneout_2 && j == 2 ? 7 :
6281 i == Xsand_stoneout_2 && j == 3 ? 8 :
6282 i == Xsand_stoneout_2 && j == 4 ? 9 :
6283 i == Xsand_stoneout_2 && j == 5 ? 11 :
6284 i == Xsand_stoneout_2 && j == 6 ? 13 :
6285 i == Xsand_stoneout_2 && j == 7 ? 15 :
6286 i == Xboom_bug && j == 1 ? 2 :
6287 i == Xboom_bug && j == 2 ? 2 :
6288 i == Xboom_bug && j == 3 ? 4 :
6289 i == Xboom_bug && j == 4 ? 4 :
6290 i == Xboom_bug && j == 5 ? 2 :
6291 i == Xboom_bug && j == 6 ? 2 :
6292 i == Xboom_bug && j == 7 ? 0 :
6293 i == Xboom_bomb && j == 1 ? 2 :
6294 i == Xboom_bomb && j == 2 ? 2 :
6295 i == Xboom_bomb && j == 3 ? 4 :
6296 i == Xboom_bomb && j == 4 ? 4 :
6297 i == Xboom_bomb && j == 5 ? 2 :
6298 i == Xboom_bomb && j == 6 ? 2 :
6299 i == Xboom_bomb && j == 7 ? 0 :
6300 i == Xboom_android && j == 7 ? 6 :
6301 i == Xboom_1 && j == 1 ? 2 :
6302 i == Xboom_1 && j == 2 ? 2 :
6303 i == Xboom_1 && j == 3 ? 4 :
6304 i == Xboom_1 && j == 4 ? 4 :
6305 i == Xboom_1 && j == 5 ? 6 :
6306 i == Xboom_1 && j == 6 ? 6 :
6307 i == Xboom_1 && j == 7 ? 8 :
6308 i == Xboom_2 && j == 0 ? 8 :
6309 i == Xboom_2 && j == 1 ? 8 :
6310 i == Xboom_2 && j == 2 ? 10 :
6311 i == Xboom_2 && j == 3 ? 10 :
6312 i == Xboom_2 && j == 4 ? 10 :
6313 i == Xboom_2 && j == 5 ? 12 :
6314 i == Xboom_2 && j == 6 ? 12 :
6315 i == Xboom_2 && j == 7 ? 12 :
6316 special_animation && j == 4 ? 3 :
6317 effective_action != action ? 0 :
6321 Bitmap *debug_bitmap = g_em->bitmap;
6322 int debug_src_x = g_em->src_x;
6323 int debug_src_y = g_em->src_y;
6326 int frame = getAnimationFrame(g->anim_frames,
6329 g->anim_start_frame,
6332 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y,
6333 g->double_movement && is_backside);
6335 g_em->bitmap = src_bitmap;
6336 g_em->src_x = src_x;
6337 g_em->src_y = src_y;
6338 g_em->src_offset_x = 0;
6339 g_em->src_offset_y = 0;
6340 g_em->dst_offset_x = 0;
6341 g_em->dst_offset_y = 0;
6342 g_em->width = TILEX;
6343 g_em->height = TILEY;
6345 g_em->crumbled_bitmap = NULL;
6346 g_em->crumbled_src_x = 0;
6347 g_em->crumbled_src_y = 0;
6348 g_em->crumbled_border_size = 0;
6350 g_em->has_crumbled_graphics = FALSE;
6351 g_em->preserve_background = FALSE;
6354 if (has_crumbled_graphics && crumbled == IMG_EMPTY_SPACE)
6355 printf("::: empty crumbled: %d [%s], %d, %d\n",
6356 effective_element, element_info[effective_element].token_name,
6357 effective_action, direction);
6360 /* if element can be crumbled, but certain action graphics are just empty
6361 space (like snapping sand with the original R'n'D graphics), do not
6362 treat these empty space graphics as crumbled graphics in EMC engine */
6363 if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
6365 getGraphicSource(crumbled, frame, &src_bitmap, &src_x, &src_y);
6367 g_em->has_crumbled_graphics = TRUE;
6368 g_em->crumbled_bitmap = src_bitmap;
6369 g_em->crumbled_src_x = src_x;
6370 g_em->crumbled_src_y = src_y;
6371 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
6375 if (element == EL_ROCK &&
6376 effective_action == ACTION_FILLING)
6377 printf("::: has_action_graphics == %d\n", has_action_graphics);
6380 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
6381 effective_action == ACTION_MOVING ||
6382 effective_action == ACTION_PUSHING ||
6383 effective_action == ACTION_EATING)) ||
6384 (!has_action_graphics && (effective_action == ACTION_FILLING ||
6385 effective_action == ACTION_EMPTYING)))
6388 (effective_action == ACTION_FALLING ||
6389 effective_action == ACTION_FILLING ||
6390 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
6391 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
6392 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
6393 int num_steps = (i == Ydrip_s1 ? 16 :
6394 i == Ydrip_s1B ? 16 :
6395 i == Ydrip_s2 ? 16 :
6396 i == Ydrip_s2B ? 16 :
6397 i == Xsand_stonein_1 ? 32 :
6398 i == Xsand_stonein_2 ? 32 :
6399 i == Xsand_stonein_3 ? 32 :
6400 i == Xsand_stonein_4 ? 32 :
6401 i == Xsand_stoneout_1 ? 16 :
6402 i == Xsand_stoneout_2 ? 16 : 8);
6403 int cx = ABS(dx) * (TILEX / num_steps);
6404 int cy = ABS(dy) * (TILEY / num_steps);
6405 int step_frame = (i == Ydrip_s2 ? j + 8 :
6406 i == Ydrip_s2B ? j + 8 :
6407 i == Xsand_stonein_2 ? j + 8 :
6408 i == Xsand_stonein_3 ? j + 16 :
6409 i == Xsand_stonein_4 ? j + 24 :
6410 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
6411 int step = (is_backside ? step_frame : num_steps - step_frame);
6413 if (is_backside) /* tile where movement starts */
6415 if (dx < 0 || dy < 0)
6417 g_em->src_offset_x = cx * step;
6418 g_em->src_offset_y = cy * step;
6422 g_em->dst_offset_x = cx * step;
6423 g_em->dst_offset_y = cy * step;
6426 else /* tile where movement ends */
6428 if (dx < 0 || dy < 0)
6430 g_em->dst_offset_x = cx * step;
6431 g_em->dst_offset_y = cy * step;
6435 g_em->src_offset_x = cx * step;
6436 g_em->src_offset_y = cy * step;
6440 g_em->width = TILEX - cx * step;
6441 g_em->height = TILEY - cy * step;
6444 /* create unique graphic identifier to decide if tile must be redrawn */
6445 /* bit 31 - 16 (16 bit): EM style graphic
6446 bit 15 - 12 ( 4 bit): EM style frame
6447 bit 11 - 6 ( 6 bit): graphic width
6448 bit 5 - 0 ( 6 bit): graphic height */
6449 g_em->unique_identifier =
6450 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
6454 /* skip check for EMC elements not contained in original EMC artwork */
6455 if (element == EL_EMC_FAKE_ACID)
6458 if (g_em->bitmap != debug_bitmap ||
6459 g_em->src_x != debug_src_x ||
6460 g_em->src_y != debug_src_y ||
6461 g_em->src_offset_x != 0 ||
6462 g_em->src_offset_y != 0 ||
6463 g_em->dst_offset_x != 0 ||
6464 g_em->dst_offset_y != 0 ||
6465 g_em->width != TILEX ||
6466 g_em->height != TILEY)
6468 static int last_i = -1;
6476 printf("::: EMC GFX ERROR for element %d -> %d ('%s', '%s', %d)",
6477 i, element, element_info[element].token_name,
6478 element_action_info[effective_action].suffix, direction);
6480 if (element != effective_element)
6481 printf(" [%d ('%s')]",
6483 element_info[effective_element].token_name);
6487 if (g_em->bitmap != debug_bitmap)
6488 printf(" %d (%d): different bitmap! (0x%08x != 0x%08x)\n",
6489 j, is_backside, (int)(g_em->bitmap), (int)(debug_bitmap));
6491 if (g_em->src_x != debug_src_x ||
6492 g_em->src_y != debug_src_y)
6493 printf(" frame %d (%c): %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
6494 j, (is_backside ? 'B' : 'F'),
6495 g_em->src_x, g_em->src_y,
6496 g_em->src_x / 32, g_em->src_y / 32,
6497 debug_src_x, debug_src_y,
6498 debug_src_x / 32, debug_src_y / 32);
6500 if (g_em->src_offset_x != 0 ||
6501 g_em->src_offset_y != 0 ||
6502 g_em->dst_offset_x != 0 ||
6503 g_em->dst_offset_y != 0)
6504 printf(" %d (%d): offsets %d,%d and %d,%d should be all 0\n",
6506 g_em->src_offset_x, g_em->src_offset_y,
6507 g_em->dst_offset_x, g_em->dst_offset_y);
6509 if (g_em->width != TILEX ||
6510 g_em->height != TILEY)
6511 printf(" %d (%d): size %d,%d should be %d,%d\n",
6513 g_em->width, g_em->height, TILEX, TILEY);
6515 num_em_gfx_errors++;
6522 for (i = 0; i < TILE_MAX; i++)
6524 for (j = 0; j < 8; j++)
6526 int element = object_mapping[i].element_rnd;
6527 int action = object_mapping[i].action;
6528 int direction = object_mapping[i].direction;
6529 boolean is_backside = object_mapping[i].is_backside;
6530 int graphic_action = el_act_dir2img(element, action, direction);
6531 int graphic_default = el_act_dir2img(element, ACTION_DEFAULT, direction);
6533 if ((action == ACTION_SMASHED_BY_ROCK ||
6534 action == ACTION_SMASHED_BY_SPRING ||
6535 action == ACTION_EATING) &&
6536 graphic_action == graphic_default)
6538 int e = (action == ACTION_SMASHED_BY_ROCK ? Ystone_s :
6539 action == ACTION_SMASHED_BY_SPRING ? Yspring_s :
6540 direction == MV_LEFT ? (is_backside? Yspring_wB: Yspring_w) :
6541 direction == MV_RIGHT ? (is_backside? Yspring_eB: Yspring_e) :
6544 /* no separate animation for "smashed by rock" -- use rock instead */
6545 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
6546 struct GraphicInfo_EM *g_xx = &graphic_info_em_object[e][7 - j];
6548 g_em->bitmap = g_xx->bitmap;
6549 g_em->src_x = g_xx->src_x;
6550 g_em->src_y = g_xx->src_y;
6551 g_em->src_offset_x = g_xx->src_offset_x;
6552 g_em->src_offset_y = g_xx->src_offset_y;
6553 g_em->dst_offset_x = g_xx->dst_offset_x;
6554 g_em->dst_offset_y = g_xx->dst_offset_y;
6555 g_em->width = g_xx->width;
6556 g_em->height = g_xx->height;
6557 g_em->unique_identifier = g_xx->unique_identifier;
6560 g_em->preserve_background = TRUE;
6565 for (p = 0; p < MAX_PLAYERS; p++)
6567 for (i = 0; i < SPR_MAX; i++)
6569 int element = player_mapping[p][i].element_rnd;
6570 int action = player_mapping[p][i].action;
6571 int direction = player_mapping[p][i].direction;
6573 for (j = 0; j < 8; j++)
6575 int effective_element = element;
6576 int effective_action = action;
6577 int graphic = (direction == MV_NONE ?
6578 el_act2img(effective_element, effective_action) :
6579 el_act_dir2img(effective_element, effective_action,
6581 struct GraphicInfo *g = &graphic_info[graphic];
6582 struct GraphicInfo_EM *g_em = &graphic_info_em_player[p][i][7 - j];
6588 Bitmap *debug_bitmap = g_em->bitmap;
6589 int debug_src_x = g_em->src_x;
6590 int debug_src_y = g_em->src_y;
6593 int frame = getAnimationFrame(g->anim_frames,
6596 g->anim_start_frame,
6599 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
6601 g_em->bitmap = src_bitmap;
6602 g_em->src_x = src_x;
6603 g_em->src_y = src_y;
6604 g_em->src_offset_x = 0;
6605 g_em->src_offset_y = 0;
6606 g_em->dst_offset_x = 0;
6607 g_em->dst_offset_y = 0;
6608 g_em->width = TILEX;
6609 g_em->height = TILEY;
6613 /* skip check for EMC elements not contained in original EMC artwork */
6614 if (element == EL_PLAYER_3 ||
6615 element == EL_PLAYER_4)
6618 if (g_em->bitmap != debug_bitmap ||
6619 g_em->src_x != debug_src_x ||
6620 g_em->src_y != debug_src_y)
6622 static int last_i = -1;
6630 printf("::: EMC GFX ERROR for p/a %d/%d -> %d ('%s', '%s', %d)",
6631 p, i, element, element_info[element].token_name,
6632 element_action_info[effective_action].suffix, direction);
6634 if (element != effective_element)
6635 printf(" [%d ('%s')]",
6637 element_info[effective_element].token_name);
6641 if (g_em->bitmap != debug_bitmap)
6642 printf(" %d: different bitmap! (0x%08x != 0x%08x)\n",
6643 j, (int)(g_em->bitmap), (int)(debug_bitmap));
6645 if (g_em->src_x != debug_src_x ||
6646 g_em->src_y != debug_src_y)
6647 printf(" frame %d: %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
6649 g_em->src_x, g_em->src_y,
6650 g_em->src_x / 32, g_em->src_y / 32,
6651 debug_src_x, debug_src_y,
6652 debug_src_x / 32, debug_src_y / 32);
6654 num_em_gfx_errors++;
6664 printf("::: [%d errors found]\n", num_em_gfx_errors);
6670 void PlayMenuSoundExt(int sound)
6672 if (sound == SND_UNDEFINED)
6675 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
6676 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
6679 if (IS_LOOP_SOUND(sound))
6680 PlaySoundLoop(sound);
6685 void PlayMenuSound()
6687 PlayMenuSoundExt(menu.sound[game_status]);
6690 void PlayMenuSoundStereo(int sound, int stereo_position)
6692 if (sound == SND_UNDEFINED)
6695 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
6696 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
6699 if (IS_LOOP_SOUND(sound))
6700 PlaySoundExt(sound, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_LOOP);
6702 PlaySoundStereo(sound, stereo_position);
6705 void PlayMenuSoundIfLoopExt(int sound)
6707 if (sound == SND_UNDEFINED)
6710 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
6711 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
6714 if (IS_LOOP_SOUND(sound))
6715 PlaySoundLoop(sound);
6718 void PlayMenuSoundIfLoop()
6720 PlayMenuSoundIfLoopExt(menu.sound[game_status]);
6723 void PlayMenuMusicExt(int music)
6725 if (music == MUS_UNDEFINED)
6728 if (!setup.sound_music)
6734 void PlayMenuMusic()
6736 PlayMenuMusicExt(menu.music[game_status]);
6739 void PlaySoundActivating()
6742 PlaySound(SND_MENU_ITEM_ACTIVATING);
6746 void PlaySoundSelecting()
6749 PlaySound(SND_MENU_ITEM_SELECTING);
6753 void ToggleFullscreenIfNeeded()
6755 boolean change_fullscreen = (setup.fullscreen !=
6756 video.fullscreen_enabled);
6757 boolean change_fullscreen_mode = (video.fullscreen_enabled &&
6758 !strEqual(setup.fullscreen_mode,
6759 video.fullscreen_mode_current));
6761 if (!video.fullscreen_available)
6765 if (change_fullscreen || change_fullscreen_mode)
6767 if (setup.fullscreen != video.fullscreen_enabled ||
6768 setup.fullscreen_mode != video.fullscreen_mode_current)
6771 Bitmap *tmp_backbuffer = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
6773 /* save backbuffer content which gets lost when toggling fullscreen mode */
6774 BlitBitmap(backbuffer, tmp_backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
6777 if (change_fullscreen_mode)
6779 if (setup.fullscreen && video.fullscreen_enabled)
6782 /* keep fullscreen, but change fullscreen mode (screen resolution) */
6784 /* (this is now set in sdl.c) */
6786 video.fullscreen_mode_current = setup.fullscreen_mode;
6788 video.fullscreen_enabled = FALSE; /* force new fullscreen mode */
6791 /* toggle fullscreen */
6792 ChangeVideoModeIfNeeded(setup.fullscreen);
6794 setup.fullscreen = video.fullscreen_enabled;
6796 /* restore backbuffer content from temporary backbuffer backup bitmap */
6797 BlitBitmap(tmp_backbuffer, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
6799 FreeBitmap(tmp_backbuffer);
6802 /* update visible window/screen */
6803 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
6805 redraw_mask = REDRAW_ALL;