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();
3036 if (!PendingEvent()) /* delay only if no pending events */
3047 if (!PendingEvent()) /* delay only if no pending events */
3050 /* don't eat all CPU time */
3057 if (game_status != GAME_MODE_MAIN)
3062 if (!(req_state & REQ_STAY_OPEN))
3064 CloseDoor(DOOR_CLOSE_1);
3066 if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
3067 (req_state & REQ_REOPEN))
3068 OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
3073 if (game_status == GAME_MODE_PLAYING)
3075 SetPanelBackground();
3076 SetDrawBackgroundMask(REDRAW_DOOR_1);
3080 SetDrawBackgroundMask(REDRAW_FIELD);
3083 #if defined(NETWORK_AVALIABLE)
3084 /* continue network game after request */
3085 if (options.network &&
3086 game_status == GAME_MODE_PLAYING &&
3087 req_state & REQUEST_WAIT_FOR_INPUT)
3088 SendToServer_ContinuePlaying();
3091 /* restore deactivated drawing when quick-loading level tape recording */
3092 if (tape.playing && tape.deactivate_display)
3093 TapeDeactivateDisplayOn();
3098 unsigned int OpenDoor(unsigned int door_state)
3100 if (door_state & DOOR_COPY_BACK)
3102 if (door_state & DOOR_OPEN_1)
3103 BlitBitmap(bitmap_db_door, bitmap_db_door,
3104 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
3105 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
3107 if (door_state & DOOR_OPEN_2)
3108 BlitBitmap(bitmap_db_door, bitmap_db_door,
3109 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY2, VXSIZE, VYSIZE,
3110 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
3112 door_state &= ~DOOR_COPY_BACK;
3115 return MoveDoor(door_state);
3118 unsigned int CloseDoor(unsigned int door_state)
3120 unsigned int old_door_state = GetDoorState();
3122 if (!(door_state & DOOR_NO_COPY_BACK))
3124 if (old_door_state & DOOR_OPEN_1)
3125 BlitBitmap(backbuffer, bitmap_db_door,
3126 DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
3128 if (old_door_state & DOOR_OPEN_2)
3129 BlitBitmap(backbuffer, bitmap_db_door,
3130 VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
3132 door_state &= ~DOOR_NO_COPY_BACK;
3135 return MoveDoor(door_state);
3138 unsigned int GetDoorState()
3140 return MoveDoor(DOOR_GET_STATE);
3143 unsigned int SetDoorState(unsigned int door_state)
3145 return MoveDoor(door_state | DOOR_SET_STATE);
3148 unsigned int MoveDoor(unsigned int door_state)
3150 static int door1 = DOOR_OPEN_1;
3151 static int door2 = DOOR_CLOSE_2;
3152 unsigned long door_delay = 0;
3153 unsigned long door_delay_value;
3156 if (door_1.width < 0 || door_1.width > DXSIZE)
3157 door_1.width = DXSIZE;
3158 if (door_1.height < 0 || door_1.height > DYSIZE)
3159 door_1.height = DYSIZE;
3160 if (door_2.width < 0 || door_2.width > VXSIZE)
3161 door_2.width = VXSIZE;
3162 if (door_2.height < 0 || door_2.height > VYSIZE)
3163 door_2.height = VYSIZE;
3165 if (door_state == DOOR_GET_STATE)
3166 return (door1 | door2);
3168 if (door_state & DOOR_SET_STATE)
3170 if (door_state & DOOR_ACTION_1)
3171 door1 = door_state & DOOR_ACTION_1;
3172 if (door_state & DOOR_ACTION_2)
3173 door2 = door_state & DOOR_ACTION_2;
3175 return (door1 | door2);
3178 if (!(door_state & DOOR_FORCE_REDRAW))
3180 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
3181 door_state &= ~DOOR_OPEN_1;
3182 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
3183 door_state &= ~DOOR_CLOSE_1;
3184 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
3185 door_state &= ~DOOR_OPEN_2;
3186 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
3187 door_state &= ~DOOR_CLOSE_2;
3190 door_delay_value = (door_state & DOOR_ACTION_1 ? door_1.step_delay :
3193 if (setup.quick_doors)
3195 stepsize = 20; /* must be chosen to always draw last frame */
3196 door_delay_value = 0;
3199 if (global.autoplay_leveldir)
3201 door_state |= DOOR_NO_DELAY;
3202 door_state &= ~DOOR_CLOSE_ALL;
3205 if (door_state & DOOR_ACTION)
3207 boolean handle_door_1 = (door_state & DOOR_ACTION_1);
3208 boolean handle_door_2 = (door_state & DOOR_ACTION_2);
3209 boolean door_1_done = (!handle_door_1);
3210 boolean door_2_done = (!handle_door_2);
3211 boolean door_1_vertical = (door_1.anim_mode & ANIM_VERTICAL);
3212 boolean door_2_vertical = (door_2.anim_mode & ANIM_VERTICAL);
3213 int door_size_1 = (door_1_vertical ? door_1.height : door_1.width);
3214 int door_size_2 = (door_2_vertical ? door_2.height : door_2.width);
3215 int max_door_size_1 = (door_1_vertical ? DYSIZE : DXSIZE);
3216 int max_door_size_2 = (door_2_vertical ? VYSIZE : VXSIZE);
3217 int door_size = (handle_door_1 ? door_size_1 : door_size_2);
3218 int max_door_size = (handle_door_1 ? max_door_size_1 : max_door_size_2);
3219 int door_skip = max_door_size - door_size;
3220 int end = door_size;
3221 int start = ((door_state & DOOR_NO_DELAY) ? end : 0);
3224 if (!(door_state & DOOR_NO_DELAY) && !setup.quick_doors)
3226 /* opening door sound has priority over simultaneously closing door */
3227 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
3228 PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
3229 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
3230 PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
3233 for (k = start; k <= end && !(door_1_done && door_2_done); k += stepsize)
3236 Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
3237 GC gc = bitmap->stored_clip_gc;
3239 if (door_state & DOOR_ACTION_1)
3241 int a = MIN(x * door_1.step_offset, end);
3242 int p = (door_state & DOOR_OPEN_1 ? end - a : a);
3243 int i = p + door_skip;
3245 if (door_1.anim_mode & ANIM_STATIC_PANEL)
3247 BlitBitmap(bitmap_db_door, drawto,
3248 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1,
3249 DXSIZE, DYSIZE, DX, DY);
3253 BlitBitmap(bitmap_db_door, drawto,
3254 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + p / 2,
3255 DXSIZE, DYSIZE - p / 2, DX, DY);
3257 ClearRectangle(drawto, DX, DY + DYSIZE - p / 2, DXSIZE, p / 2);
3260 if (door_1.anim_mode & ANIM_HORIZONTAL && x <= DXSIZE)
3262 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
3263 int dst1_x = DX + DXSIZE - i, dst1_y = DY;
3264 int src2_x = DXSIZE - i, src2_y = DOOR_GFX_PAGEY1;
3265 int dst2_x = DX, dst2_y = DY;
3266 int width = i, height = DYSIZE;
3268 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3269 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3272 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3273 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3276 else if (door_1.anim_mode & ANIM_VERTICAL && x <= DYSIZE)
3278 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
3279 int dst1_x = DX, dst1_y = DY + DYSIZE - i;
3280 int src2_x = 0, src2_y = DOOR_GFX_PAGEY1 + DYSIZE - i;
3281 int dst2_x = DX, dst2_y = DY;
3282 int width = DXSIZE, height = i;
3284 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3285 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3288 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3289 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3292 else if (x <= DXSIZE) /* ANIM_DEFAULT */
3294 int j = (door_1.anim_mode == ANIM_DEFAULT ? (DXSIZE - i) / 3 : 0);
3296 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
3297 BlitBitmapMasked(bitmap, drawto,
3298 DXSIZE, DOOR_GFX_PAGEY1, i, 77,
3299 DX + DXSIZE - i, DY + j);
3300 BlitBitmapMasked(bitmap, drawto,
3301 DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
3302 DX + DXSIZE - i, DY + 140 + j);
3303 SetClipOrigin(bitmap, gc, DX - DXSIZE + i,
3304 DY - (DOOR_GFX_PAGEY1 + j));
3305 BlitBitmapMasked(bitmap, drawto,
3306 DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
3308 BlitBitmapMasked(bitmap, drawto,
3309 DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
3312 BlitBitmapMasked(bitmap, drawto,
3313 DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
3315 BlitBitmapMasked(bitmap, drawto,
3316 DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
3318 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
3319 BlitBitmapMasked(bitmap, drawto,
3320 DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
3321 DX + DXSIZE - i, DY + 77 + j);
3322 BlitBitmapMasked(bitmap, drawto,
3323 DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
3324 DX + DXSIZE - i, DY + 203 + j);
3327 redraw_mask |= REDRAW_DOOR_1;
3328 door_1_done = (a == end);
3331 if (door_state & DOOR_ACTION_2)
3333 int a = MIN(x * door_2.step_offset, door_size);
3334 int p = (door_state & DOOR_OPEN_2 ? door_size - a : a);
3335 int i = p + door_skip;
3337 if (door_2.anim_mode & ANIM_STATIC_PANEL)
3339 BlitBitmap(bitmap_db_door, drawto,
3340 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2,
3341 VXSIZE, VYSIZE, VX, VY);
3343 else if (x <= VYSIZE)
3345 BlitBitmap(bitmap_db_door, drawto,
3346 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + p / 2,
3347 VXSIZE, VYSIZE - p / 2, VX, VY);
3349 ClearRectangle(drawto, VX, VY + VYSIZE - p / 2, VXSIZE, p / 2);
3352 if (door_2.anim_mode & ANIM_HORIZONTAL && x <= VXSIZE)
3354 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
3355 int dst1_x = VX + VXSIZE - i, dst1_y = VY;
3356 int src2_x = VXSIZE - i, src2_y = DOOR_GFX_PAGEY2;
3357 int dst2_x = VX, dst2_y = VY;
3358 int width = i, height = VYSIZE;
3360 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3361 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3364 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3365 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3368 else if (door_2.anim_mode & ANIM_VERTICAL && x <= VYSIZE)
3370 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
3371 int dst1_x = VX, dst1_y = VY + VYSIZE - i;
3372 int src2_x = 0, src2_y = DOOR_GFX_PAGEY2 + VYSIZE - i;
3373 int dst2_x = VX, dst2_y = VY;
3374 int width = VXSIZE, height = i;
3376 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3377 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3380 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3381 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3384 else if (x <= VXSIZE) /* ANIM_DEFAULT */
3386 int j = (door_2.anim_mode == ANIM_DEFAULT ? (VXSIZE - i) / 3 : 0);
3388 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
3389 BlitBitmapMasked(bitmap, drawto,
3390 VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
3391 VX + VXSIZE - i, VY + j);
3392 SetClipOrigin(bitmap, gc,
3393 VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
3394 BlitBitmapMasked(bitmap, drawto,
3395 VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
3398 BlitBitmapMasked(bitmap, drawto,
3399 VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
3400 i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
3401 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
3402 BlitBitmapMasked(bitmap, drawto,
3403 VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
3405 VX + VXSIZE - i, VY + VYSIZE / 2 + j);
3408 redraw_mask |= REDRAW_DOOR_2;
3409 door_2_done = (a == VXSIZE);
3412 if (!(door_state & DOOR_NO_DELAY))
3416 if (game_status == GAME_MODE_MAIN)
3419 WaitUntilDelayReached(&door_delay, door_delay_value);
3424 if (door_state & DOOR_ACTION_1)
3425 door1 = door_state & DOOR_ACTION_1;
3426 if (door_state & DOOR_ACTION_2)
3427 door2 = door_state & DOOR_ACTION_2;
3429 return (door1 | door2);
3432 void DrawSpecialEditorDoor()
3434 /* draw bigger toolbox window */
3435 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
3436 DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
3438 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
3439 EX - 6, VY - 4, EXSIZE + 12, EYSIZE - VYSIZE + 4,
3442 redraw_mask |= REDRAW_ALL;
3445 void UndrawSpecialEditorDoor()
3447 /* draw normal tape recorder window */
3448 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
3449 EX - 6, EY - 12, EXSIZE + 12, EYSIZE - VYSIZE + 12,
3452 redraw_mask |= REDRAW_ALL;
3456 /* ---------- new tool button stuff ---------------------------------------- */
3458 /* graphic position values for tool buttons */
3459 #define TOOL_BUTTON_YES_XPOS 2
3460 #define TOOL_BUTTON_YES_YPOS 250
3461 #define TOOL_BUTTON_YES_GFX_YPOS 0
3462 #define TOOL_BUTTON_YES_XSIZE 46
3463 #define TOOL_BUTTON_YES_YSIZE 28
3464 #define TOOL_BUTTON_NO_XPOS 52
3465 #define TOOL_BUTTON_NO_YPOS TOOL_BUTTON_YES_YPOS
3466 #define TOOL_BUTTON_NO_GFX_YPOS TOOL_BUTTON_YES_GFX_YPOS
3467 #define TOOL_BUTTON_NO_XSIZE TOOL_BUTTON_YES_XSIZE
3468 #define TOOL_BUTTON_NO_YSIZE TOOL_BUTTON_YES_YSIZE
3469 #define TOOL_BUTTON_CONFIRM_XPOS TOOL_BUTTON_YES_XPOS
3470 #define TOOL_BUTTON_CONFIRM_YPOS TOOL_BUTTON_YES_YPOS
3471 #define TOOL_BUTTON_CONFIRM_GFX_YPOS 30
3472 #define TOOL_BUTTON_CONFIRM_XSIZE 96
3473 #define TOOL_BUTTON_CONFIRM_YSIZE TOOL_BUTTON_YES_YSIZE
3474 #define TOOL_BUTTON_PLAYER_XSIZE 30
3475 #define TOOL_BUTTON_PLAYER_YSIZE 30
3476 #define TOOL_BUTTON_PLAYER_GFX_XPOS 5
3477 #define TOOL_BUTTON_PLAYER_GFX_YPOS 185
3478 #define TOOL_BUTTON_PLAYER_XPOS (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
3479 #define TOOL_BUTTON_PLAYER_YPOS (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
3480 #define TOOL_BUTTON_PLAYER1_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3481 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
3482 #define TOOL_BUTTON_PLAYER2_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3483 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
3484 #define TOOL_BUTTON_PLAYER3_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3485 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
3486 #define TOOL_BUTTON_PLAYER4_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3487 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
3488 #define TOOL_BUTTON_PLAYER1_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3489 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
3490 #define TOOL_BUTTON_PLAYER2_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3491 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
3492 #define TOOL_BUTTON_PLAYER3_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3493 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
3494 #define TOOL_BUTTON_PLAYER4_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3495 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
3504 } toolbutton_info[NUM_TOOL_BUTTONS] =
3507 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_GFX_YPOS,
3508 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_YPOS,
3509 TOOL_BUTTON_YES_XSIZE, TOOL_BUTTON_YES_YSIZE,
3514 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_GFX_YPOS,
3515 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_YPOS,
3516 TOOL_BUTTON_NO_XSIZE, TOOL_BUTTON_NO_YSIZE,
3521 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_GFX_YPOS,
3522 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_YPOS,
3523 TOOL_BUTTON_CONFIRM_XSIZE, TOOL_BUTTON_CONFIRM_YSIZE,
3524 TOOL_CTRL_ID_CONFIRM,
3528 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3529 TOOL_BUTTON_PLAYER1_XPOS, TOOL_BUTTON_PLAYER1_YPOS,
3530 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3531 TOOL_CTRL_ID_PLAYER_1,
3535 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3536 TOOL_BUTTON_PLAYER2_XPOS, TOOL_BUTTON_PLAYER2_YPOS,
3537 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3538 TOOL_CTRL_ID_PLAYER_2,
3542 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3543 TOOL_BUTTON_PLAYER3_XPOS, TOOL_BUTTON_PLAYER3_YPOS,
3544 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3545 TOOL_CTRL_ID_PLAYER_3,
3549 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3550 TOOL_BUTTON_PLAYER4_XPOS, TOOL_BUTTON_PLAYER4_YPOS,
3551 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3552 TOOL_CTRL_ID_PLAYER_4,
3557 void CreateToolButtons()
3561 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3563 Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
3564 Bitmap *deco_bitmap = None;
3565 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
3566 struct GadgetInfo *gi;
3567 unsigned long event_mask;
3568 int gd_xoffset, gd_yoffset;
3569 int gd_x1, gd_x2, gd_y;
3572 event_mask = GD_EVENT_RELEASED;
3574 gd_xoffset = toolbutton_info[i].xpos;
3575 gd_yoffset = toolbutton_info[i].ypos;
3576 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
3577 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
3578 gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
3580 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
3582 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
3584 getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr),
3585 &deco_bitmap, &deco_x, &deco_y);
3586 deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
3587 deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
3590 gi = CreateGadget(GDI_CUSTOM_ID, id,
3591 GDI_INFO_TEXT, toolbutton_info[i].infotext,
3592 GDI_X, DX + toolbutton_info[i].x,
3593 GDI_Y, DY + toolbutton_info[i].y,
3594 GDI_WIDTH, toolbutton_info[i].width,
3595 GDI_HEIGHT, toolbutton_info[i].height,
3596 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
3597 GDI_STATE, GD_BUTTON_UNPRESSED,
3598 GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
3599 GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
3600 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
3601 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
3602 GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
3603 GDI_DECORATION_SHIFTING, 1, 1,
3604 GDI_DIRECT_DRAW, FALSE,
3605 GDI_EVENT_MASK, event_mask,
3606 GDI_CALLBACK_ACTION, HandleToolButtons,
3610 Error(ERR_EXIT, "cannot create gadget");
3612 tool_gadget[id] = gi;
3616 void FreeToolButtons()
3620 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3621 FreeGadget(tool_gadget[i]);
3624 static void UnmapToolButtons()
3628 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3629 UnmapGadget(tool_gadget[i]);
3632 static void HandleToolButtons(struct GadgetInfo *gi)
3634 request_gadget_id = gi->custom_id;
3637 static struct Mapping_EM_to_RND_object
3640 boolean is_rnd_to_em_mapping; /* unique mapping EM <-> RND */
3641 boolean is_backside; /* backside of moving element */
3647 em_object_mapping_list[] =
3650 Xblank, TRUE, FALSE,
3654 Yacid_splash_eB, FALSE, FALSE,
3655 EL_ACID_SPLASH_RIGHT, -1, -1
3658 Yacid_splash_wB, FALSE, FALSE,
3659 EL_ACID_SPLASH_LEFT, -1, -1
3662 #ifdef EM_ENGINE_BAD_ROLL
3664 Xstone_force_e, FALSE, FALSE,
3665 EL_ROCK, -1, MV_BIT_RIGHT
3668 Xstone_force_w, FALSE, FALSE,
3669 EL_ROCK, -1, MV_BIT_LEFT
3672 Xnut_force_e, FALSE, FALSE,
3673 EL_NUT, -1, MV_BIT_RIGHT
3676 Xnut_force_w, FALSE, FALSE,
3677 EL_NUT, -1, MV_BIT_LEFT
3680 Xspring_force_e, FALSE, FALSE,
3681 EL_SPRING, -1, MV_BIT_RIGHT
3684 Xspring_force_w, FALSE, FALSE,
3685 EL_SPRING, -1, MV_BIT_LEFT
3688 Xemerald_force_e, FALSE, FALSE,
3689 EL_EMERALD, -1, MV_BIT_RIGHT
3692 Xemerald_force_w, FALSE, FALSE,
3693 EL_EMERALD, -1, MV_BIT_LEFT
3696 Xdiamond_force_e, FALSE, FALSE,
3697 EL_DIAMOND, -1, MV_BIT_RIGHT
3700 Xdiamond_force_w, FALSE, FALSE,
3701 EL_DIAMOND, -1, MV_BIT_LEFT
3704 Xbomb_force_e, FALSE, FALSE,
3705 EL_BOMB, -1, MV_BIT_RIGHT
3708 Xbomb_force_w, FALSE, FALSE,
3709 EL_BOMB, -1, MV_BIT_LEFT
3711 #endif /* EM_ENGINE_BAD_ROLL */
3714 Xstone, TRUE, FALSE,
3718 Xstone_pause, FALSE, FALSE,
3722 Xstone_fall, FALSE, FALSE,
3726 Ystone_s, FALSE, FALSE,
3727 EL_ROCK, ACTION_FALLING, -1
3730 Ystone_sB, FALSE, TRUE,
3731 EL_ROCK, ACTION_FALLING, -1
3734 Ystone_e, FALSE, FALSE,
3735 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
3738 Ystone_eB, FALSE, TRUE,
3739 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
3742 Ystone_w, FALSE, FALSE,
3743 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
3746 Ystone_wB, FALSE, TRUE,
3747 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
3754 Xnut_pause, FALSE, FALSE,
3758 Xnut_fall, FALSE, FALSE,
3762 Ynut_s, FALSE, FALSE,
3763 EL_NUT, ACTION_FALLING, -1
3766 Ynut_sB, FALSE, TRUE,
3767 EL_NUT, ACTION_FALLING, -1
3770 Ynut_e, FALSE, FALSE,
3771 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
3774 Ynut_eB, FALSE, TRUE,
3775 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
3778 Ynut_w, FALSE, FALSE,
3779 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
3782 Ynut_wB, FALSE, TRUE,
3783 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
3786 Xbug_n, TRUE, FALSE,
3790 Xbug_e, TRUE, FALSE,
3791 EL_BUG_RIGHT, -1, -1
3794 Xbug_s, TRUE, FALSE,
3798 Xbug_w, TRUE, FALSE,
3802 Xbug_gon, FALSE, FALSE,
3806 Xbug_goe, FALSE, FALSE,
3807 EL_BUG_RIGHT, -1, -1
3810 Xbug_gos, FALSE, FALSE,
3814 Xbug_gow, FALSE, FALSE,
3818 Ybug_n, FALSE, FALSE,
3819 EL_BUG, ACTION_MOVING, MV_BIT_UP
3822 Ybug_nB, FALSE, TRUE,
3823 EL_BUG, ACTION_MOVING, MV_BIT_UP
3826 Ybug_e, FALSE, FALSE,
3827 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
3830 Ybug_eB, FALSE, TRUE,
3831 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
3834 Ybug_s, FALSE, FALSE,
3835 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
3838 Ybug_sB, FALSE, TRUE,
3839 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
3842 Ybug_w, FALSE, FALSE,
3843 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
3846 Ybug_wB, FALSE, TRUE,
3847 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
3850 Ybug_w_n, FALSE, FALSE,
3851 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
3854 Ybug_n_e, FALSE, FALSE,
3855 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
3858 Ybug_e_s, FALSE, FALSE,
3859 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
3862 Ybug_s_w, FALSE, FALSE,
3863 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
3866 Ybug_e_n, FALSE, FALSE,
3867 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
3870 Ybug_s_e, FALSE, FALSE,
3871 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
3874 Ybug_w_s, FALSE, FALSE,
3875 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
3878 Ybug_n_w, FALSE, FALSE,
3879 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
3882 Ybug_stone, FALSE, FALSE,
3883 EL_BUG, ACTION_SMASHED_BY_ROCK, -1
3886 Ybug_spring, FALSE, FALSE,
3887 EL_BUG, ACTION_SMASHED_BY_SPRING, -1
3890 Xtank_n, TRUE, FALSE,
3891 EL_SPACESHIP_UP, -1, -1
3894 Xtank_e, TRUE, FALSE,
3895 EL_SPACESHIP_RIGHT, -1, -1
3898 Xtank_s, TRUE, FALSE,
3899 EL_SPACESHIP_DOWN, -1, -1
3902 Xtank_w, TRUE, FALSE,
3903 EL_SPACESHIP_LEFT, -1, -1
3906 Xtank_gon, FALSE, FALSE,
3907 EL_SPACESHIP_UP, -1, -1
3910 Xtank_goe, FALSE, FALSE,
3911 EL_SPACESHIP_RIGHT, -1, -1
3914 Xtank_gos, FALSE, FALSE,
3915 EL_SPACESHIP_DOWN, -1, -1
3918 Xtank_gow, FALSE, FALSE,
3919 EL_SPACESHIP_LEFT, -1, -1
3922 Ytank_n, FALSE, FALSE,
3923 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
3926 Ytank_nB, FALSE, TRUE,
3927 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
3930 Ytank_e, FALSE, FALSE,
3931 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
3934 Ytank_eB, FALSE, TRUE,
3935 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
3938 Ytank_s, FALSE, FALSE,
3939 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
3942 Ytank_sB, FALSE, TRUE,
3943 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
3946 Ytank_w, FALSE, FALSE,
3947 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
3950 Ytank_wB, FALSE, TRUE,
3951 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
3954 Ytank_w_n, FALSE, FALSE,
3955 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
3958 Ytank_n_e, FALSE, FALSE,
3959 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
3962 Ytank_e_s, FALSE, FALSE,
3963 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
3966 Ytank_s_w, FALSE, FALSE,
3967 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
3970 Ytank_e_n, FALSE, FALSE,
3971 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
3974 Ytank_s_e, FALSE, FALSE,
3975 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
3978 Ytank_w_s, FALSE, FALSE,
3979 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
3982 Ytank_n_w, FALSE, FALSE,
3983 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
3986 Ytank_stone, FALSE, FALSE,
3987 EL_SPACESHIP, ACTION_SMASHED_BY_ROCK, -1
3990 Ytank_spring, FALSE, FALSE,
3991 EL_SPACESHIP, ACTION_SMASHED_BY_SPRING, -1
3994 Xandroid, TRUE, FALSE,
3995 EL_EMC_ANDROID, ACTION_ACTIVE, -1
3998 Xandroid_1_n, FALSE, FALSE,
3999 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
4002 Xandroid_2_n, FALSE, FALSE,
4003 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
4006 Xandroid_1_e, FALSE, FALSE,
4007 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
4010 Xandroid_2_e, FALSE, FALSE,
4011 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
4014 Xandroid_1_w, FALSE, FALSE,
4015 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
4018 Xandroid_2_w, FALSE, FALSE,
4019 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
4022 Xandroid_1_s, FALSE, FALSE,
4023 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
4026 Xandroid_2_s, FALSE, FALSE,
4027 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
4030 Yandroid_n, FALSE, FALSE,
4031 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
4034 Yandroid_nB, FALSE, TRUE,
4035 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
4038 Yandroid_ne, FALSE, FALSE,
4039 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPRIGHT
4042 Yandroid_neB, FALSE, TRUE,
4043 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPRIGHT
4046 Yandroid_e, FALSE, FALSE,
4047 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
4050 Yandroid_eB, FALSE, TRUE,
4051 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
4054 Yandroid_se, FALSE, FALSE,
4055 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNRIGHT
4058 Yandroid_seB, FALSE, TRUE,
4059 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNRIGHT
4062 Yandroid_s, FALSE, FALSE,
4063 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
4066 Yandroid_sB, FALSE, TRUE,
4067 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
4070 Yandroid_sw, FALSE, FALSE,
4071 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNLEFT
4074 Yandroid_swB, FALSE, TRUE,
4075 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNLEFT
4078 Yandroid_w, FALSE, FALSE,
4079 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
4082 Yandroid_wB, FALSE, TRUE,
4083 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
4086 Yandroid_nw, FALSE, FALSE,
4087 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPLEFT
4090 Yandroid_nwB, FALSE, TRUE,
4091 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPLEFT
4094 Xspring, TRUE, FALSE,
4098 Xspring_pause, FALSE, FALSE,
4102 Xspring_e, FALSE, FALSE,
4106 Xspring_w, FALSE, FALSE,
4110 Xspring_fall, FALSE, FALSE,
4114 Yspring_s, FALSE, FALSE,
4115 EL_SPRING, ACTION_FALLING, -1
4118 Yspring_sB, FALSE, TRUE,
4119 EL_SPRING, ACTION_FALLING, -1
4122 Yspring_e, FALSE, FALSE,
4123 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
4126 Yspring_eB, FALSE, TRUE,
4127 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
4130 Yspring_w, FALSE, FALSE,
4131 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
4134 Yspring_wB, FALSE, TRUE,
4135 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
4138 Yspring_kill_e, FALSE, FALSE,
4139 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
4142 Yspring_kill_eB, FALSE, TRUE,
4143 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
4146 Yspring_kill_w, FALSE, FALSE,
4147 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
4150 Yspring_kill_wB, FALSE, TRUE,
4151 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
4154 Xeater_n, TRUE, FALSE,
4155 EL_YAMYAM_UP, -1, -1
4158 Xeater_e, TRUE, FALSE,
4159 EL_YAMYAM_RIGHT, -1, -1
4162 Xeater_w, TRUE, FALSE,
4163 EL_YAMYAM_LEFT, -1, -1
4166 Xeater_s, TRUE, FALSE,
4167 EL_YAMYAM_DOWN, -1, -1
4170 Yeater_n, FALSE, FALSE,
4171 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
4174 Yeater_nB, FALSE, TRUE,
4175 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
4178 Yeater_e, FALSE, FALSE,
4179 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
4182 Yeater_eB, FALSE, TRUE,
4183 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
4186 Yeater_s, FALSE, FALSE,
4187 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
4190 Yeater_sB, FALSE, TRUE,
4191 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
4194 Yeater_w, FALSE, FALSE,
4195 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
4198 Yeater_wB, FALSE, TRUE,
4199 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
4202 Yeater_stone, FALSE, FALSE,
4203 EL_YAMYAM, ACTION_SMASHED_BY_ROCK, -1
4206 Yeater_spring, FALSE, FALSE,
4207 EL_YAMYAM, ACTION_SMASHED_BY_SPRING, -1
4210 Xalien, TRUE, FALSE,
4214 Xalien_pause, FALSE, FALSE,
4218 Yalien_n, FALSE, FALSE,
4219 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
4222 Yalien_nB, FALSE, TRUE,
4223 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
4226 Yalien_e, FALSE, FALSE,
4227 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
4230 Yalien_eB, FALSE, TRUE,
4231 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
4234 Yalien_s, FALSE, FALSE,
4235 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
4238 Yalien_sB, FALSE, TRUE,
4239 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
4242 Yalien_w, FALSE, FALSE,
4243 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
4246 Yalien_wB, FALSE, TRUE,
4247 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
4250 Yalien_stone, FALSE, FALSE,
4251 EL_ROBOT, ACTION_SMASHED_BY_ROCK, -1
4254 Yalien_spring, FALSE, FALSE,
4255 EL_ROBOT, ACTION_SMASHED_BY_SPRING, -1
4258 Xemerald, TRUE, FALSE,
4262 Xemerald_pause, FALSE, FALSE,
4266 Xemerald_fall, FALSE, FALSE,
4270 Xemerald_shine, FALSE, FALSE,
4271 EL_EMERALD, ACTION_TWINKLING, -1
4274 Yemerald_s, FALSE, FALSE,
4275 EL_EMERALD, ACTION_FALLING, -1
4278 Yemerald_sB, FALSE, TRUE,
4279 EL_EMERALD, ACTION_FALLING, -1
4282 Yemerald_e, FALSE, FALSE,
4283 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
4286 Yemerald_eB, FALSE, TRUE,
4287 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
4290 Yemerald_w, FALSE, FALSE,
4291 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
4294 Yemerald_wB, FALSE, TRUE,
4295 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
4298 Yemerald_eat, FALSE, FALSE,
4299 EL_EMERALD, ACTION_COLLECTING, -1
4302 Yemerald_stone, FALSE, FALSE,
4303 EL_NUT, ACTION_BREAKING, -1
4306 Xdiamond, TRUE, FALSE,
4310 Xdiamond_pause, FALSE, FALSE,
4314 Xdiamond_fall, FALSE, FALSE,
4318 Xdiamond_shine, FALSE, FALSE,
4319 EL_DIAMOND, ACTION_TWINKLING, -1
4322 Ydiamond_s, FALSE, FALSE,
4323 EL_DIAMOND, ACTION_FALLING, -1
4326 Ydiamond_sB, FALSE, TRUE,
4327 EL_DIAMOND, ACTION_FALLING, -1
4330 Ydiamond_e, FALSE, FALSE,
4331 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
4334 Ydiamond_eB, FALSE, TRUE,
4335 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
4338 Ydiamond_w, FALSE, FALSE,
4339 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
4342 Ydiamond_wB, FALSE, TRUE,
4343 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
4346 Ydiamond_eat, FALSE, FALSE,
4347 EL_DIAMOND, ACTION_COLLECTING, -1
4350 Ydiamond_stone, FALSE, FALSE,
4351 EL_DIAMOND, ACTION_SMASHED_BY_ROCK, -1
4354 Xdrip_fall, TRUE, FALSE,
4355 EL_AMOEBA_DROP, -1, -1
4358 Xdrip_stretch, FALSE, FALSE,
4359 EL_AMOEBA_DROP, ACTION_FALLING, -1
4362 Xdrip_stretchB, FALSE, TRUE,
4363 EL_AMOEBA_DROP, ACTION_FALLING, -1
4366 Xdrip_eat, FALSE, FALSE,
4367 EL_AMOEBA_DROP, ACTION_GROWING, -1
4370 Ydrip_s1, FALSE, FALSE,
4371 EL_AMOEBA_DROP, ACTION_FALLING, -1
4374 Ydrip_s1B, FALSE, TRUE,
4375 EL_AMOEBA_DROP, ACTION_FALLING, -1
4378 Ydrip_s2, FALSE, FALSE,
4379 EL_AMOEBA_DROP, ACTION_FALLING, -1
4382 Ydrip_s2B, FALSE, TRUE,
4383 EL_AMOEBA_DROP, ACTION_FALLING, -1
4390 Xbomb_pause, FALSE, FALSE,
4394 Xbomb_fall, FALSE, FALSE,
4398 Ybomb_s, FALSE, FALSE,
4399 EL_BOMB, ACTION_FALLING, -1
4402 Ybomb_sB, FALSE, TRUE,
4403 EL_BOMB, ACTION_FALLING, -1
4406 Ybomb_e, FALSE, FALSE,
4407 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
4410 Ybomb_eB, FALSE, TRUE,
4411 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
4414 Ybomb_w, FALSE, FALSE,
4415 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
4418 Ybomb_wB, FALSE, TRUE,
4419 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
4422 Ybomb_eat, FALSE, FALSE,
4423 EL_BOMB, ACTION_ACTIVATING, -1
4426 Xballoon, TRUE, FALSE,
4430 Yballoon_n, FALSE, FALSE,
4431 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
4434 Yballoon_nB, FALSE, TRUE,
4435 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
4438 Yballoon_e, FALSE, FALSE,
4439 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
4442 Yballoon_eB, FALSE, TRUE,
4443 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
4446 Yballoon_s, FALSE, FALSE,
4447 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
4450 Yballoon_sB, FALSE, TRUE,
4451 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
4454 Yballoon_w, FALSE, FALSE,
4455 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
4458 Yballoon_wB, FALSE, TRUE,
4459 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
4462 Xgrass, TRUE, FALSE,
4463 EL_EMC_GRASS, -1, -1
4466 Ygrass_nB, FALSE, FALSE,
4467 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_UP
4470 Ygrass_eB, FALSE, FALSE,
4471 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_RIGHT
4474 Ygrass_sB, FALSE, FALSE,
4475 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_DOWN
4478 Ygrass_wB, FALSE, FALSE,
4479 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_LEFT
4486 Ydirt_nB, FALSE, FALSE,
4487 EL_SAND, ACTION_DIGGING, MV_BIT_UP
4490 Ydirt_eB, FALSE, FALSE,
4491 EL_SAND, ACTION_DIGGING, MV_BIT_RIGHT
4494 Ydirt_sB, FALSE, FALSE,
4495 EL_SAND, ACTION_DIGGING, MV_BIT_DOWN
4498 Ydirt_wB, FALSE, FALSE,
4499 EL_SAND, ACTION_DIGGING, MV_BIT_LEFT
4502 Xacid_ne, TRUE, FALSE,
4503 EL_ACID_POOL_TOPRIGHT, -1, -1
4506 Xacid_se, TRUE, FALSE,
4507 EL_ACID_POOL_BOTTOMRIGHT, -1, -1
4510 Xacid_s, TRUE, FALSE,
4511 EL_ACID_POOL_BOTTOM, -1, -1
4514 Xacid_sw, TRUE, FALSE,
4515 EL_ACID_POOL_BOTTOMLEFT, -1, -1
4518 Xacid_nw, TRUE, FALSE,
4519 EL_ACID_POOL_TOPLEFT, -1, -1
4522 Xacid_1, TRUE, FALSE,
4526 Xacid_2, FALSE, FALSE,
4530 Xacid_3, FALSE, FALSE,
4534 Xacid_4, FALSE, FALSE,
4538 Xacid_5, FALSE, FALSE,
4542 Xacid_6, FALSE, FALSE,
4546 Xacid_7, FALSE, FALSE,
4550 Xacid_8, FALSE, FALSE,
4554 Xball_1, TRUE, FALSE,
4555 EL_EMC_MAGIC_BALL, -1, -1
4558 Xball_1B, FALSE, FALSE,
4559 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4562 Xball_2, FALSE, FALSE,
4563 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4566 Xball_2B, FALSE, FALSE,
4567 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4570 Yball_eat, FALSE, FALSE,
4571 EL_EMC_MAGIC_BALL, ACTION_DROPPING, -1
4574 Ykey_1_eat, FALSE, FALSE,
4575 EL_EM_KEY_1, ACTION_COLLECTING, -1
4578 Ykey_2_eat, FALSE, FALSE,
4579 EL_EM_KEY_2, ACTION_COLLECTING, -1
4582 Ykey_3_eat, FALSE, FALSE,
4583 EL_EM_KEY_3, ACTION_COLLECTING, -1
4586 Ykey_4_eat, FALSE, FALSE,
4587 EL_EM_KEY_4, ACTION_COLLECTING, -1
4590 Ykey_5_eat, FALSE, FALSE,
4591 EL_EMC_KEY_5, ACTION_COLLECTING, -1
4594 Ykey_6_eat, FALSE, FALSE,
4595 EL_EMC_KEY_6, ACTION_COLLECTING, -1
4598 Ykey_7_eat, FALSE, FALSE,
4599 EL_EMC_KEY_7, ACTION_COLLECTING, -1
4602 Ykey_8_eat, FALSE, FALSE,
4603 EL_EMC_KEY_8, ACTION_COLLECTING, -1
4606 Ylenses_eat, FALSE, FALSE,
4607 EL_EMC_LENSES, ACTION_COLLECTING, -1
4610 Ymagnify_eat, FALSE, FALSE,
4611 EL_EMC_MAGNIFIER, ACTION_COLLECTING, -1
4614 Ygrass_eat, FALSE, FALSE,
4615 EL_EMC_GRASS, ACTION_SNAPPING, -1
4618 Ydirt_eat, FALSE, FALSE,
4619 EL_SAND, ACTION_SNAPPING, -1
4622 Xgrow_ns, TRUE, FALSE,
4623 EL_EXPANDABLE_WALL_VERTICAL, -1, -1
4626 Ygrow_ns_eat, FALSE, FALSE,
4627 EL_EXPANDABLE_WALL_VERTICAL, ACTION_GROWING, -1
4630 Xgrow_ew, TRUE, FALSE,
4631 EL_EXPANDABLE_WALL_HORIZONTAL, -1, -1
4634 Ygrow_ew_eat, FALSE, FALSE,
4635 EL_EXPANDABLE_WALL_HORIZONTAL, ACTION_GROWING, -1
4638 Xwonderwall, TRUE, FALSE,
4639 EL_MAGIC_WALL, -1, -1
4642 XwonderwallB, FALSE, FALSE,
4643 EL_MAGIC_WALL, ACTION_ACTIVE, -1
4646 Xamoeba_1, TRUE, FALSE,
4647 EL_AMOEBA_DRY, ACTION_OTHER, -1
4650 Xamoeba_2, FALSE, FALSE,
4651 EL_AMOEBA_DRY, ACTION_OTHER, -1
4654 Xamoeba_3, FALSE, FALSE,
4655 EL_AMOEBA_DRY, ACTION_OTHER, -1
4658 Xamoeba_4, FALSE, FALSE,
4659 EL_AMOEBA_DRY, ACTION_OTHER, -1
4662 Xamoeba_5, TRUE, FALSE,
4663 EL_AMOEBA_WET, ACTION_OTHER, -1
4666 Xamoeba_6, FALSE, FALSE,
4667 EL_AMOEBA_WET, ACTION_OTHER, -1
4670 Xamoeba_7, FALSE, FALSE,
4671 EL_AMOEBA_WET, ACTION_OTHER, -1
4674 Xamoeba_8, FALSE, FALSE,
4675 EL_AMOEBA_WET, ACTION_OTHER, -1
4678 Xdoor_1, TRUE, FALSE,
4679 EL_EM_GATE_1, -1, -1
4682 Xdoor_2, TRUE, FALSE,
4683 EL_EM_GATE_2, -1, -1
4686 Xdoor_3, TRUE, FALSE,
4687 EL_EM_GATE_3, -1, -1
4690 Xdoor_4, TRUE, FALSE,
4691 EL_EM_GATE_4, -1, -1
4694 Xdoor_5, TRUE, FALSE,
4695 EL_EMC_GATE_5, -1, -1
4698 Xdoor_6, TRUE, FALSE,
4699 EL_EMC_GATE_6, -1, -1
4702 Xdoor_7, TRUE, FALSE,
4703 EL_EMC_GATE_7, -1, -1
4706 Xdoor_8, TRUE, FALSE,
4707 EL_EMC_GATE_8, -1, -1
4710 Xkey_1, TRUE, FALSE,
4714 Xkey_2, TRUE, FALSE,
4718 Xkey_3, TRUE, FALSE,
4722 Xkey_4, TRUE, FALSE,
4726 Xkey_5, TRUE, FALSE,
4727 EL_EMC_KEY_5, -1, -1
4730 Xkey_6, TRUE, FALSE,
4731 EL_EMC_KEY_6, -1, -1
4734 Xkey_7, TRUE, FALSE,
4735 EL_EMC_KEY_7, -1, -1
4738 Xkey_8, TRUE, FALSE,
4739 EL_EMC_KEY_8, -1, -1
4742 Xwind_n, TRUE, FALSE,
4743 EL_BALLOON_SWITCH_UP, -1, -1
4746 Xwind_e, TRUE, FALSE,
4747 EL_BALLOON_SWITCH_RIGHT, -1, -1
4750 Xwind_s, TRUE, FALSE,
4751 EL_BALLOON_SWITCH_DOWN, -1, -1
4754 Xwind_w, TRUE, FALSE,
4755 EL_BALLOON_SWITCH_LEFT, -1, -1
4758 Xwind_nesw, TRUE, FALSE,
4759 EL_BALLOON_SWITCH_ANY, -1, -1
4762 Xwind_stop, TRUE, FALSE,
4763 EL_BALLOON_SWITCH_NONE, -1, -1
4767 EL_EM_EXIT_CLOSED, -1, -1
4770 Xexit_1, TRUE, FALSE,
4771 EL_EM_EXIT_OPEN, -1, -1
4774 Xexit_2, FALSE, FALSE,
4775 EL_EM_EXIT_OPEN, -1, -1
4778 Xexit_3, FALSE, FALSE,
4779 EL_EM_EXIT_OPEN, -1, -1
4782 Xdynamite, TRUE, FALSE,
4783 EL_EM_DYNAMITE, -1, -1
4786 Ydynamite_eat, FALSE, FALSE,
4787 EL_EM_DYNAMITE, ACTION_COLLECTING, -1
4790 Xdynamite_1, TRUE, FALSE,
4791 EL_EM_DYNAMITE_ACTIVE, -1, -1
4794 Xdynamite_2, FALSE, FALSE,
4795 EL_EM_DYNAMITE_ACTIVE, -1, -1
4798 Xdynamite_3, FALSE, FALSE,
4799 EL_EM_DYNAMITE_ACTIVE, -1, -1
4802 Xdynamite_4, FALSE, FALSE,
4803 EL_EM_DYNAMITE_ACTIVE, -1, -1
4806 Xbumper, TRUE, FALSE,
4807 EL_EMC_SPRING_BUMPER, -1, -1
4810 XbumperB, FALSE, FALSE,
4811 EL_EMC_SPRING_BUMPER, ACTION_ACTIVE, -1
4814 Xwheel, TRUE, FALSE,
4815 EL_ROBOT_WHEEL, -1, -1
4818 XwheelB, FALSE, FALSE,
4819 EL_ROBOT_WHEEL, ACTION_ACTIVE, -1
4822 Xswitch, TRUE, FALSE,
4823 EL_EMC_MAGIC_BALL_SWITCH, -1, -1
4826 XswitchB, FALSE, FALSE,
4827 EL_EMC_MAGIC_BALL_SWITCH, ACTION_ACTIVE, -1
4831 EL_QUICKSAND_EMPTY, -1, -1
4834 Xsand_stone, TRUE, FALSE,
4835 EL_QUICKSAND_FULL, -1, -1
4838 Xsand_stonein_1, FALSE, TRUE,
4839 EL_ROCK, ACTION_FILLING, -1
4842 Xsand_stonein_2, FALSE, TRUE,
4843 EL_ROCK, ACTION_FILLING, -1
4846 Xsand_stonein_3, FALSE, TRUE,
4847 EL_ROCK, ACTION_FILLING, -1
4850 Xsand_stonein_4, FALSE, TRUE,
4851 EL_ROCK, ACTION_FILLING, -1
4854 Xsand_stonesand_1, FALSE, FALSE,
4855 EL_QUICKSAND_FULL, -1, -1
4858 Xsand_stonesand_2, FALSE, FALSE,
4859 EL_QUICKSAND_FULL, -1, -1
4862 Xsand_stonesand_3, FALSE, FALSE,
4863 EL_QUICKSAND_FULL, -1, -1
4866 Xsand_stonesand_4, FALSE, FALSE,
4867 EL_QUICKSAND_FULL, -1, -1
4870 Xsand_stoneout_1, FALSE, FALSE,
4871 EL_ROCK, ACTION_EMPTYING, -1
4874 Xsand_stoneout_2, FALSE, FALSE,
4875 EL_ROCK, ACTION_EMPTYING, -1
4878 Xsand_sandstone_1, FALSE, FALSE,
4879 EL_QUICKSAND_FULL, -1, -1
4882 Xsand_sandstone_2, FALSE, FALSE,
4883 EL_QUICKSAND_FULL, -1, -1
4886 Xsand_sandstone_3, FALSE, FALSE,
4887 EL_QUICKSAND_FULL, -1, -1
4890 Xsand_sandstone_4, FALSE, FALSE,
4891 EL_QUICKSAND_FULL, -1, -1
4894 Xplant, TRUE, FALSE,
4895 EL_EMC_PLANT, -1, -1
4898 Yplant, FALSE, FALSE,
4899 EL_EMC_PLANT, -1, -1
4902 Xlenses, TRUE, FALSE,
4903 EL_EMC_LENSES, -1, -1
4906 Xmagnify, TRUE, FALSE,
4907 EL_EMC_MAGNIFIER, -1, -1
4910 Xdripper, TRUE, FALSE,
4911 EL_EMC_DRIPPER, -1, -1
4914 XdripperB, FALSE, FALSE,
4915 EL_EMC_DRIPPER, ACTION_ACTIVE, -1
4918 Xfake_blank, TRUE, FALSE,
4919 EL_INVISIBLE_WALL, -1, -1
4922 Xfake_blankB, FALSE, FALSE,
4923 EL_INVISIBLE_WALL, ACTION_ACTIVE, -1
4926 Xfake_grass, TRUE, FALSE,
4927 EL_EMC_FAKE_GRASS, -1, -1
4930 Xfake_grassB, FALSE, FALSE,
4931 EL_EMC_FAKE_GRASS, ACTION_ACTIVE, -1
4934 Xfake_door_1, TRUE, FALSE,
4935 EL_EM_GATE_1_GRAY, -1, -1
4938 Xfake_door_2, TRUE, FALSE,
4939 EL_EM_GATE_2_GRAY, -1, -1
4942 Xfake_door_3, TRUE, FALSE,
4943 EL_EM_GATE_3_GRAY, -1, -1
4946 Xfake_door_4, TRUE, FALSE,
4947 EL_EM_GATE_4_GRAY, -1, -1
4950 Xfake_door_5, TRUE, FALSE,
4951 EL_EMC_GATE_5_GRAY, -1, -1
4954 Xfake_door_6, TRUE, FALSE,
4955 EL_EMC_GATE_6_GRAY, -1, -1
4958 Xfake_door_7, TRUE, FALSE,
4959 EL_EMC_GATE_7_GRAY, -1, -1
4962 Xfake_door_8, TRUE, FALSE,
4963 EL_EMC_GATE_8_GRAY, -1, -1
4966 Xfake_acid_1, TRUE, FALSE,
4967 EL_EMC_FAKE_ACID, -1, -1
4970 Xfake_acid_2, FALSE, FALSE,
4971 EL_EMC_FAKE_ACID, -1, -1
4974 Xfake_acid_3, FALSE, FALSE,
4975 EL_EMC_FAKE_ACID, -1, -1
4978 Xfake_acid_4, FALSE, FALSE,
4979 EL_EMC_FAKE_ACID, -1, -1
4982 Xfake_acid_5, FALSE, FALSE,
4983 EL_EMC_FAKE_ACID, -1, -1
4986 Xfake_acid_6, FALSE, FALSE,
4987 EL_EMC_FAKE_ACID, -1, -1
4990 Xfake_acid_7, FALSE, FALSE,
4991 EL_EMC_FAKE_ACID, -1, -1
4994 Xfake_acid_8, FALSE, FALSE,
4995 EL_EMC_FAKE_ACID, -1, -1
4998 Xsteel_1, TRUE, FALSE,
4999 EL_STEELWALL, -1, -1
5002 Xsteel_2, TRUE, FALSE,
5003 EL_EMC_STEELWALL_2, -1, -1
5006 Xsteel_3, TRUE, FALSE,
5007 EL_EMC_STEELWALL_3, -1, -1
5010 Xsteel_4, TRUE, FALSE,
5011 EL_EMC_STEELWALL_4, -1, -1
5014 Xwall_1, TRUE, FALSE,
5018 Xwall_2, TRUE, FALSE,
5019 EL_EMC_WALL_14, -1, -1
5022 Xwall_3, TRUE, FALSE,
5023 EL_EMC_WALL_15, -1, -1
5026 Xwall_4, TRUE, FALSE,
5027 EL_EMC_WALL_16, -1, -1
5030 Xround_wall_1, TRUE, FALSE,
5031 EL_WALL_SLIPPERY, -1, -1
5034 Xround_wall_2, TRUE, FALSE,
5035 EL_EMC_WALL_SLIPPERY_2, -1, -1
5038 Xround_wall_3, TRUE, FALSE,
5039 EL_EMC_WALL_SLIPPERY_3, -1, -1
5042 Xround_wall_4, TRUE, FALSE,
5043 EL_EMC_WALL_SLIPPERY_4, -1, -1
5046 Xdecor_1, TRUE, FALSE,
5047 EL_EMC_WALL_8, -1, -1
5050 Xdecor_2, TRUE, FALSE,
5051 EL_EMC_WALL_6, -1, -1
5054 Xdecor_3, TRUE, FALSE,
5055 EL_EMC_WALL_4, -1, -1
5058 Xdecor_4, TRUE, FALSE,
5059 EL_EMC_WALL_7, -1, -1
5062 Xdecor_5, TRUE, FALSE,
5063 EL_EMC_WALL_5, -1, -1
5066 Xdecor_6, TRUE, FALSE,
5067 EL_EMC_WALL_9, -1, -1
5070 Xdecor_7, TRUE, FALSE,
5071 EL_EMC_WALL_10, -1, -1
5074 Xdecor_8, TRUE, FALSE,
5075 EL_EMC_WALL_1, -1, -1
5078 Xdecor_9, TRUE, FALSE,
5079 EL_EMC_WALL_2, -1, -1
5082 Xdecor_10, TRUE, FALSE,
5083 EL_EMC_WALL_3, -1, -1
5086 Xdecor_11, TRUE, FALSE,
5087 EL_EMC_WALL_11, -1, -1
5090 Xdecor_12, TRUE, FALSE,
5091 EL_EMC_WALL_12, -1, -1
5094 Xalpha_0, TRUE, FALSE,
5095 EL_CHAR('0'), -1, -1
5098 Xalpha_1, TRUE, FALSE,
5099 EL_CHAR('1'), -1, -1
5102 Xalpha_2, TRUE, FALSE,
5103 EL_CHAR('2'), -1, -1
5106 Xalpha_3, TRUE, FALSE,
5107 EL_CHAR('3'), -1, -1
5110 Xalpha_4, TRUE, FALSE,
5111 EL_CHAR('4'), -1, -1
5114 Xalpha_5, TRUE, FALSE,
5115 EL_CHAR('5'), -1, -1
5118 Xalpha_6, TRUE, FALSE,
5119 EL_CHAR('6'), -1, -1
5122 Xalpha_7, TRUE, FALSE,
5123 EL_CHAR('7'), -1, -1
5126 Xalpha_8, TRUE, FALSE,
5127 EL_CHAR('8'), -1, -1
5130 Xalpha_9, TRUE, FALSE,
5131 EL_CHAR('9'), -1, -1
5134 Xalpha_excla, TRUE, FALSE,
5135 EL_CHAR('!'), -1, -1
5138 Xalpha_quote, TRUE, FALSE,
5139 EL_CHAR('"'), -1, -1
5142 Xalpha_comma, TRUE, FALSE,
5143 EL_CHAR(','), -1, -1
5146 Xalpha_minus, TRUE, FALSE,
5147 EL_CHAR('-'), -1, -1
5150 Xalpha_perio, TRUE, FALSE,
5151 EL_CHAR('.'), -1, -1
5154 Xalpha_colon, TRUE, FALSE,
5155 EL_CHAR(':'), -1, -1
5158 Xalpha_quest, TRUE, FALSE,
5159 EL_CHAR('?'), -1, -1
5162 Xalpha_a, TRUE, FALSE,
5163 EL_CHAR('A'), -1, -1
5166 Xalpha_b, TRUE, FALSE,
5167 EL_CHAR('B'), -1, -1
5170 Xalpha_c, TRUE, FALSE,
5171 EL_CHAR('C'), -1, -1
5174 Xalpha_d, TRUE, FALSE,
5175 EL_CHAR('D'), -1, -1
5178 Xalpha_e, TRUE, FALSE,
5179 EL_CHAR('E'), -1, -1
5182 Xalpha_f, TRUE, FALSE,
5183 EL_CHAR('F'), -1, -1
5186 Xalpha_g, TRUE, FALSE,
5187 EL_CHAR('G'), -1, -1
5190 Xalpha_h, TRUE, FALSE,
5191 EL_CHAR('H'), -1, -1
5194 Xalpha_i, TRUE, FALSE,
5195 EL_CHAR('I'), -1, -1
5198 Xalpha_j, TRUE, FALSE,
5199 EL_CHAR('J'), -1, -1
5202 Xalpha_k, TRUE, FALSE,
5203 EL_CHAR('K'), -1, -1
5206 Xalpha_l, TRUE, FALSE,
5207 EL_CHAR('L'), -1, -1
5210 Xalpha_m, TRUE, FALSE,
5211 EL_CHAR('M'), -1, -1
5214 Xalpha_n, TRUE, FALSE,
5215 EL_CHAR('N'), -1, -1
5218 Xalpha_o, TRUE, FALSE,
5219 EL_CHAR('O'), -1, -1
5222 Xalpha_p, TRUE, FALSE,
5223 EL_CHAR('P'), -1, -1
5226 Xalpha_q, TRUE, FALSE,
5227 EL_CHAR('Q'), -1, -1
5230 Xalpha_r, TRUE, FALSE,
5231 EL_CHAR('R'), -1, -1
5234 Xalpha_s, TRUE, FALSE,
5235 EL_CHAR('S'), -1, -1
5238 Xalpha_t, TRUE, FALSE,
5239 EL_CHAR('T'), -1, -1
5242 Xalpha_u, TRUE, FALSE,
5243 EL_CHAR('U'), -1, -1
5246 Xalpha_v, TRUE, FALSE,
5247 EL_CHAR('V'), -1, -1
5250 Xalpha_w, TRUE, FALSE,
5251 EL_CHAR('W'), -1, -1
5254 Xalpha_x, TRUE, FALSE,
5255 EL_CHAR('X'), -1, -1
5258 Xalpha_y, TRUE, FALSE,
5259 EL_CHAR('Y'), -1, -1
5262 Xalpha_z, TRUE, FALSE,
5263 EL_CHAR('Z'), -1, -1
5266 Xalpha_arrow_e, TRUE, FALSE,
5267 EL_CHAR('>'), -1, -1
5270 Xalpha_arrow_w, TRUE, FALSE,
5271 EL_CHAR('<'), -1, -1
5274 Xalpha_copyr, TRUE, FALSE,
5275 EL_CHAR('©'), -1, -1
5279 Xboom_bug, FALSE, FALSE,
5280 EL_BUG, ACTION_EXPLODING, -1
5283 Xboom_bomb, FALSE, FALSE,
5284 EL_BOMB, ACTION_EXPLODING, -1
5287 Xboom_android, FALSE, FALSE,
5288 EL_EMC_ANDROID, ACTION_OTHER, -1
5291 Xboom_1, FALSE, FALSE,
5292 EL_DEFAULT, ACTION_EXPLODING, -1
5295 Xboom_2, FALSE, FALSE,
5296 EL_DEFAULT, ACTION_EXPLODING, -1
5299 Znormal, FALSE, FALSE,
5303 Zdynamite, FALSE, FALSE,
5307 Zplayer, FALSE, FALSE,
5311 ZBORDER, FALSE, FALSE,
5321 static struct Mapping_EM_to_RND_player
5330 em_player_mapping_list[] =
5334 EL_PLAYER_1, ACTION_MOVING, MV_BIT_UP,
5338 EL_PLAYER_1, ACTION_MOVING, MV_BIT_RIGHT,
5342 EL_PLAYER_1, ACTION_MOVING, MV_BIT_DOWN,
5346 EL_PLAYER_1, ACTION_MOVING, MV_BIT_LEFT,
5350 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_UP,
5354 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_RIGHT,
5358 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_DOWN,
5362 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_LEFT,
5366 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_UP,
5370 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_RIGHT,
5374 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_DOWN,
5378 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_LEFT,
5382 EL_PLAYER_2, ACTION_MOVING, MV_BIT_UP,
5386 EL_PLAYER_2, ACTION_MOVING, MV_BIT_RIGHT,
5390 EL_PLAYER_2, ACTION_MOVING, MV_BIT_DOWN,
5394 EL_PLAYER_2, ACTION_MOVING, MV_BIT_LEFT,
5398 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_UP,
5402 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_RIGHT,
5406 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_DOWN,
5410 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_LEFT,
5414 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_UP,
5418 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_RIGHT,
5422 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_DOWN,
5426 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_LEFT,
5430 EL_PLAYER_1, ACTION_DEFAULT, -1,
5434 EL_PLAYER_2, ACTION_DEFAULT, -1,
5438 EL_PLAYER_3, ACTION_MOVING, MV_BIT_UP,
5442 EL_PLAYER_3, ACTION_MOVING, MV_BIT_RIGHT,
5446 EL_PLAYER_3, ACTION_MOVING, MV_BIT_DOWN,
5450 EL_PLAYER_3, ACTION_MOVING, MV_BIT_LEFT,
5454 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_UP,
5458 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_RIGHT,
5462 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_DOWN,
5466 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_LEFT,
5470 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_UP,
5474 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_RIGHT,
5478 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_DOWN,
5482 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_LEFT,
5486 EL_PLAYER_4, ACTION_MOVING, MV_BIT_UP,
5490 EL_PLAYER_4, ACTION_MOVING, MV_BIT_RIGHT,
5494 EL_PLAYER_4, ACTION_MOVING, MV_BIT_DOWN,
5498 EL_PLAYER_4, ACTION_MOVING, MV_BIT_LEFT,
5502 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_UP,
5506 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_RIGHT,
5510 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_DOWN,
5514 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_LEFT,
5518 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_UP,
5522 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_RIGHT,
5526 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_DOWN,
5530 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_LEFT,
5534 EL_PLAYER_3, ACTION_DEFAULT, -1,
5538 EL_PLAYER_4, ACTION_DEFAULT, -1,
5547 int map_element_RND_to_EM(int element_rnd)
5549 static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
5550 static boolean mapping_initialized = FALSE;
5552 if (!mapping_initialized)
5556 /* return "Xalpha_quest" for all undefined elements in mapping array */
5557 for (i = 0; i < NUM_FILE_ELEMENTS; i++)
5558 mapping_RND_to_EM[i] = Xalpha_quest;
5560 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5561 if (em_object_mapping_list[i].is_rnd_to_em_mapping)
5562 mapping_RND_to_EM[em_object_mapping_list[i].element_rnd] =
5563 em_object_mapping_list[i].element_em;
5565 mapping_initialized = TRUE;
5568 if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
5569 return mapping_RND_to_EM[element_rnd];
5571 Error(ERR_WARN, "invalid RND level element %d", element_rnd);
5576 int map_element_EM_to_RND(int element_em)
5578 static unsigned short mapping_EM_to_RND[TILE_MAX];
5579 static boolean mapping_initialized = FALSE;
5581 if (!mapping_initialized)
5585 /* return "EL_UNKNOWN" for all undefined elements in mapping array */
5586 for (i = 0; i < TILE_MAX; i++)
5587 mapping_EM_to_RND[i] = EL_UNKNOWN;
5589 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5590 mapping_EM_to_RND[em_object_mapping_list[i].element_em] =
5591 em_object_mapping_list[i].element_rnd;
5593 mapping_initialized = TRUE;
5596 if (element_em >= 0 && element_em < TILE_MAX)
5597 return mapping_EM_to_RND[element_em];
5599 Error(ERR_WARN, "invalid EM level element %d", element_em);
5604 void map_android_clone_elements_RND_to_EM(struct LevelInfo *level)
5606 struct LevelInfo_EM *level_em = level->native_em_level;
5607 struct LEVEL *lev = level_em->lev;
5610 for (i = 0; i < TILE_MAX; i++)
5611 lev->android_array[i] = Xblank;
5613 for (i = 0; i < level->num_android_clone_elements; i++)
5615 int element_rnd = level->android_clone_element[i];
5616 int element_em = map_element_RND_to_EM(element_rnd);
5618 for (j = 0; em_object_mapping_list[j].element_em != -1; j++)
5619 if (em_object_mapping_list[j].element_rnd == element_rnd)
5620 lev->android_array[em_object_mapping_list[j].element_em] = element_em;
5624 void map_android_clone_elements_EM_to_RND(struct LevelInfo *level)
5626 struct LevelInfo_EM *level_em = level->native_em_level;
5627 struct LEVEL *lev = level_em->lev;
5630 level->num_android_clone_elements = 0;
5632 for (i = 0; i < TILE_MAX; i++)
5634 int element_em = lev->android_array[i];
5636 boolean element_found = FALSE;
5638 if (element_em == Xblank)
5641 element_rnd = map_element_EM_to_RND(element_em);
5643 for (j = 0; j < level->num_android_clone_elements; j++)
5644 if (level->android_clone_element[j] == element_rnd)
5645 element_found = TRUE;
5649 level->android_clone_element[level->num_android_clone_elements++] =
5652 if (level->num_android_clone_elements == MAX_ANDROID_ELEMENTS)
5657 if (level->num_android_clone_elements == 0)
5659 level->num_android_clone_elements = 1;
5660 level->android_clone_element[0] = EL_EMPTY;
5664 int map_direction_RND_to_EM(int direction)
5666 return (direction == MV_UP ? 0 :
5667 direction == MV_RIGHT ? 1 :
5668 direction == MV_DOWN ? 2 :
5669 direction == MV_LEFT ? 3 :
5673 int map_direction_EM_to_RND(int direction)
5675 return (direction == 0 ? MV_UP :
5676 direction == 1 ? MV_RIGHT :
5677 direction == 2 ? MV_DOWN :
5678 direction == 3 ? MV_LEFT :
5682 int get_next_element(int element)
5686 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
5687 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
5688 case EL_QUICKSAND_FAST_FILLING: return EL_QUICKSAND_FAST_FULL;
5689 case EL_QUICKSAND_FAST_EMPTYING: return EL_QUICKSAND_FAST_EMPTY;
5690 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
5691 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
5692 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
5693 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
5694 case EL_DC_MAGIC_WALL_FILLING: return EL_DC_MAGIC_WALL_FULL;
5695 case EL_DC_MAGIC_WALL_EMPTYING: return EL_DC_MAGIC_WALL_ACTIVE;
5696 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
5698 default: return element;
5703 int el_act_dir2img(int element, int action, int direction)
5705 element = GFX_ELEMENT(element);
5707 if (direction == MV_NONE)
5708 return element_info[element].graphic[action];
5710 direction = MV_DIR_TO_BIT(direction);
5712 return element_info[element].direction_graphic[action][direction];
5715 int el_act_dir2img(int element, int action, int direction)
5717 element = GFX_ELEMENT(element);
5718 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
5720 /* direction_graphic[][] == graphic[] for undefined direction graphics */
5721 return element_info[element].direction_graphic[action][direction];
5726 static int el_act_dir2crm(int element, int action, int direction)
5728 element = GFX_ELEMENT(element);
5730 if (direction == MV_NONE)
5731 return element_info[element].crumbled[action];
5733 direction = MV_DIR_TO_BIT(direction);
5735 return element_info[element].direction_crumbled[action][direction];
5738 static int el_act_dir2crm(int element, int action, int direction)
5740 element = GFX_ELEMENT(element);
5741 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
5743 /* direction_graphic[][] == graphic[] for undefined direction graphics */
5744 return element_info[element].direction_crumbled[action][direction];
5748 int el_act2img(int element, int action)
5750 element = GFX_ELEMENT(element);
5752 return element_info[element].graphic[action];
5755 int el_act2crm(int element, int action)
5757 element = GFX_ELEMENT(element);
5759 return element_info[element].crumbled[action];
5762 int el_dir2img(int element, int direction)
5764 element = GFX_ELEMENT(element);
5766 return el_act_dir2img(element, ACTION_DEFAULT, direction);
5769 int el2baseimg(int element)
5771 return element_info[element].graphic[ACTION_DEFAULT];
5774 int el2img(int element)
5776 element = GFX_ELEMENT(element);
5778 return element_info[element].graphic[ACTION_DEFAULT];
5781 int el2edimg(int element)
5783 element = GFX_ELEMENT(element);
5785 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
5788 int el2preimg(int element)
5790 element = GFX_ELEMENT(element);
5792 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
5795 int el2panelimg(int element)
5797 element = GFX_ELEMENT(element);
5799 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PANEL];
5802 int font2baseimg(int font_nr)
5804 return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
5807 int getBeltNrFromBeltElement(int element)
5809 return (element < EL_CONVEYOR_BELT_2_LEFT ? 0 :
5810 element < EL_CONVEYOR_BELT_3_LEFT ? 1 :
5811 element < EL_CONVEYOR_BELT_4_LEFT ? 2 : 3);
5814 int getBeltNrFromBeltActiveElement(int element)
5816 return (element < EL_CONVEYOR_BELT_2_LEFT_ACTIVE ? 0 :
5817 element < EL_CONVEYOR_BELT_3_LEFT_ACTIVE ? 1 :
5818 element < EL_CONVEYOR_BELT_4_LEFT_ACTIVE ? 2 : 3);
5821 int getBeltNrFromBeltSwitchElement(int element)
5823 return (element < EL_CONVEYOR_BELT_2_SWITCH_LEFT ? 0 :
5824 element < EL_CONVEYOR_BELT_3_SWITCH_LEFT ? 1 :
5825 element < EL_CONVEYOR_BELT_4_SWITCH_LEFT ? 2 : 3);
5828 int getBeltDirNrFromBeltElement(int element)
5830 static int belt_base_element[4] =
5832 EL_CONVEYOR_BELT_1_LEFT,
5833 EL_CONVEYOR_BELT_2_LEFT,
5834 EL_CONVEYOR_BELT_3_LEFT,
5835 EL_CONVEYOR_BELT_4_LEFT
5838 int belt_nr = getBeltNrFromBeltElement(element);
5839 int belt_dir_nr = element - belt_base_element[belt_nr];
5841 return (belt_dir_nr % 3);
5844 int getBeltDirNrFromBeltSwitchElement(int element)
5846 static int belt_base_element[4] =
5848 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
5849 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
5850 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
5851 EL_CONVEYOR_BELT_4_SWITCH_LEFT
5854 int belt_nr = getBeltNrFromBeltSwitchElement(element);
5855 int belt_dir_nr = element - belt_base_element[belt_nr];
5857 return (belt_dir_nr % 3);
5860 int getBeltDirFromBeltElement(int element)
5862 static int belt_move_dir[3] =
5869 int belt_dir_nr = getBeltDirNrFromBeltElement(element);
5871 return belt_move_dir[belt_dir_nr];
5874 int getBeltDirFromBeltSwitchElement(int element)
5876 static int belt_move_dir[3] =
5883 int belt_dir_nr = getBeltDirNrFromBeltSwitchElement(element);
5885 return belt_move_dir[belt_dir_nr];
5888 int getBeltElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
5890 static int belt_base_element[4] =
5892 EL_CONVEYOR_BELT_1_LEFT,
5893 EL_CONVEYOR_BELT_2_LEFT,
5894 EL_CONVEYOR_BELT_3_LEFT,
5895 EL_CONVEYOR_BELT_4_LEFT
5898 return belt_base_element[belt_nr] + belt_dir_nr;
5901 int getBeltElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
5903 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
5905 return getBeltElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
5908 int getBeltSwitchElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
5910 static int belt_base_element[4] =
5912 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
5913 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
5914 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
5915 EL_CONVEYOR_BELT_4_SWITCH_LEFT
5918 return belt_base_element[belt_nr] + belt_dir_nr;
5921 int getBeltSwitchElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
5923 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
5925 return getBeltSwitchElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
5928 int getNumActivePlayers_EM()
5930 int num_players = 0;
5936 for (i = 0; i < MAX_PLAYERS; i++)
5937 if (tape.player_participates[i])
5943 int getGameFrameDelay_EM(int native_em_game_frame_delay)
5945 int game_frame_delay_value;
5947 game_frame_delay_value =
5948 (tape.playing && tape.fast_forward ? FfwdFrameDelay :
5949 GameFrameDelay == GAME_FRAME_DELAY ? native_em_game_frame_delay :
5952 if (tape.playing && tape.warp_forward && !tape.pausing)
5953 game_frame_delay_value = 0;
5955 return game_frame_delay_value;
5958 unsigned int InitRND(long seed)
5960 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
5961 return InitEngineRandom_EM(seed);
5963 return InitEngineRandom_RND(seed);
5967 static struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
5968 static struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
5971 void ResetGfxAnimation_EM(int x, int y, int tile)
5976 void getGraphicSourceObjectExt_EM(int tile, int frame_em,
5977 Bitmap **src_bitmap, int *src_x, int *src_y,
5980 int element = object_mapping[tile].element_rnd;
5981 int action = object_mapping[tile].action;
5982 int direction = object_mapping[tile].direction;
5983 boolean is_backside = object_mapping[tile].is_backside;
5984 boolean action_removing = (action == ACTION_DIGGING ||
5985 action == ACTION_SNAPPING ||
5986 action == ACTION_COLLECTING);
5987 int effective_element = (frame_em > 0 ? element :
5988 is_backside ? EL_EMPTY :
5989 action_removing ? EL_EMPTY :
5991 int graphic = (direction == MV_NONE ?
5992 el_act2img(effective_element, action) :
5993 el_act_dir2img(effective_element, action, direction));
5994 struct GraphicInfo *g = &graphic_info[graphic];
5997 if (graphic_info[graphic].anim_global_sync)
5998 sync_frame = FrameCounter;
6000 sync_frame = 7 - frame_em;
6002 SetRandomAnimationValue(x, y);
6004 int frame = getAnimationFrame(g->anim_frames,
6007 g->anim_start_frame,
6010 getGraphicSourceExt(graphic, frame, src_bitmap, src_x, src_y, FALSE);
6013 void getGraphicSourcePlayerExt_EM(int player_nr, int anim, int frame_em,
6014 Bitmap **src_bitmap, int *src_x, int *src_y)
6016 int element = player_mapping[player_nr][anim].element_rnd;
6017 int action = player_mapping[player_nr][anim].action;
6018 int direction = player_mapping[player_nr][anim].direction;
6019 int graphic = (direction == MV_NONE ?
6020 el_act2img(element, action) :
6021 el_act_dir2img(element, action, direction));
6022 struct GraphicInfo *g = &graphic_info[graphic];
6025 InitPlayerGfxAnimation(&stored_player[player_nr], action, direction);
6027 stored_player[player_nr].StepFrame = 7 - frame_em;
6029 sync_frame = stored_player[player_nr].Frame;
6032 printf("::: %d: %d, %d [%d]\n",
6034 stored_player[player_nr].Frame,
6035 stored_player[player_nr].StepFrame,
6039 int frame = getAnimationFrame(g->anim_frames,
6042 g->anim_start_frame,
6045 getGraphicSourceExt(graphic, frame, src_bitmap, src_x, src_y, FALSE);
6048 void InitGraphicInfo_EM(void)
6051 struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
6052 struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
6057 int num_em_gfx_errors = 0;
6059 if (graphic_info_em_object[0][0].bitmap == NULL)
6061 /* EM graphics not yet initialized in em_open_all() */
6066 printf("::: [4 errors can be ignored (1 x 'bomb', 3 x 'em_dynamite']\n");
6069 /* always start with reliable default values */
6070 for (i = 0; i < TILE_MAX; i++)
6072 object_mapping[i].element_rnd = EL_UNKNOWN;
6073 object_mapping[i].is_backside = FALSE;
6074 object_mapping[i].action = ACTION_DEFAULT;
6075 object_mapping[i].direction = MV_NONE;
6078 /* always start with reliable default values */
6079 for (p = 0; p < MAX_PLAYERS; p++)
6081 for (i = 0; i < SPR_MAX; i++)
6083 player_mapping[p][i].element_rnd = EL_UNKNOWN;
6084 player_mapping[p][i].action = ACTION_DEFAULT;
6085 player_mapping[p][i].direction = MV_NONE;
6089 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
6091 int e = em_object_mapping_list[i].element_em;
6093 object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd;
6094 object_mapping[e].is_backside = em_object_mapping_list[i].is_backside;
6096 if (em_object_mapping_list[i].action != -1)
6097 object_mapping[e].action = em_object_mapping_list[i].action;
6099 if (em_object_mapping_list[i].direction != -1)
6100 object_mapping[e].direction =
6101 MV_DIR_FROM_BIT(em_object_mapping_list[i].direction);
6104 for (i = 0; em_player_mapping_list[i].action_em != -1; i++)
6106 int a = em_player_mapping_list[i].action_em;
6107 int p = em_player_mapping_list[i].player_nr;
6109 player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd;
6111 if (em_player_mapping_list[i].action != -1)
6112 player_mapping[p][a].action = em_player_mapping_list[i].action;
6114 if (em_player_mapping_list[i].direction != -1)
6115 player_mapping[p][a].direction =
6116 MV_DIR_FROM_BIT(em_player_mapping_list[i].direction);
6119 for (i = 0; i < TILE_MAX; i++)
6121 int element = object_mapping[i].element_rnd;
6122 int action = object_mapping[i].action;
6123 int direction = object_mapping[i].direction;
6124 boolean is_backside = object_mapping[i].is_backside;
6125 boolean action_removing = (action == ACTION_DIGGING ||
6126 action == ACTION_SNAPPING ||
6127 action == ACTION_COLLECTING);
6128 boolean action_exploding = ((action == ACTION_EXPLODING ||
6129 action == ACTION_SMASHED_BY_ROCK ||
6130 action == ACTION_SMASHED_BY_SPRING) &&
6131 element != EL_DIAMOND);
6132 boolean action_active = (action == ACTION_ACTIVE);
6133 boolean action_other = (action == ACTION_OTHER);
6135 for (j = 0; j < 8; j++)
6137 int effective_element = (j > 5 && i == Yacid_splash_eB ? EL_EMPTY :
6138 j > 5 && i == Yacid_splash_wB ? EL_EMPTY :
6140 i == Xdrip_stretch ? element :
6141 i == Xdrip_stretchB ? element :
6142 i == Ydrip_s1 ? element :
6143 i == Ydrip_s1B ? element :
6144 i == Xball_1B ? element :
6145 i == Xball_2 ? element :
6146 i == Xball_2B ? element :
6147 i == Yball_eat ? element :
6148 i == Ykey_1_eat ? element :
6149 i == Ykey_2_eat ? element :
6150 i == Ykey_3_eat ? element :
6151 i == Ykey_4_eat ? element :
6152 i == Ykey_5_eat ? element :
6153 i == Ykey_6_eat ? element :
6154 i == Ykey_7_eat ? element :
6155 i == Ykey_8_eat ? element :
6156 i == Ylenses_eat ? element :
6157 i == Ymagnify_eat ? element :
6158 i == Ygrass_eat ? element :
6159 i == Ydirt_eat ? element :
6160 i == Yemerald_stone ? EL_EMERALD :
6161 i == Ydiamond_stone ? EL_ROCK :
6162 i == Xsand_stonein_1 ? element :
6163 i == Xsand_stonein_2 ? element :
6164 i == Xsand_stonein_3 ? element :
6165 i == Xsand_stonein_4 ? element :
6166 is_backside ? EL_EMPTY :
6167 action_removing ? EL_EMPTY :
6169 int effective_action = (j < 7 ? action :
6170 i == Xdrip_stretch ? action :
6171 i == Xdrip_stretchB ? action :
6172 i == Ydrip_s1 ? action :
6173 i == Ydrip_s1B ? action :
6174 i == Xball_1B ? action :
6175 i == Xball_2 ? action :
6176 i == Xball_2B ? action :
6177 i == Yball_eat ? action :
6178 i == Ykey_1_eat ? action :
6179 i == Ykey_2_eat ? action :
6180 i == Ykey_3_eat ? action :
6181 i == Ykey_4_eat ? action :
6182 i == Ykey_5_eat ? action :
6183 i == Ykey_6_eat ? action :
6184 i == Ykey_7_eat ? action :
6185 i == Ykey_8_eat ? action :
6186 i == Ylenses_eat ? action :
6187 i == Ymagnify_eat ? action :
6188 i == Ygrass_eat ? action :
6189 i == Ydirt_eat ? action :
6190 i == Xsand_stonein_1 ? action :
6191 i == Xsand_stonein_2 ? action :
6192 i == Xsand_stonein_3 ? action :
6193 i == Xsand_stonein_4 ? action :
6194 i == Xsand_stoneout_1 ? action :
6195 i == Xsand_stoneout_2 ? action :
6196 i == Xboom_android ? ACTION_EXPLODING :
6197 action_exploding ? ACTION_EXPLODING :
6198 action_active ? action :
6199 action_other ? action :
6201 int graphic = (el_act_dir2img(effective_element, effective_action,
6203 int crumbled = (el_act_dir2crm(effective_element, effective_action,
6205 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
6206 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
6207 boolean has_action_graphics = (graphic != base_graphic);
6208 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
6209 struct GraphicInfo *g = &graphic_info[graphic];
6210 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
6213 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
6214 boolean special_animation = (action != ACTION_DEFAULT &&
6215 g->anim_frames == 3 &&
6216 g->anim_delay == 2 &&
6217 g->anim_mode & ANIM_LINEAR);
6218 int sync_frame = (i == Xdrip_stretch ? 7 :
6219 i == Xdrip_stretchB ? 7 :
6220 i == Ydrip_s2 ? j + 8 :
6221 i == Ydrip_s2B ? j + 8 :
6230 i == Xfake_acid_1 ? 0 :
6231 i == Xfake_acid_2 ? 10 :
6232 i == Xfake_acid_3 ? 20 :
6233 i == Xfake_acid_4 ? 30 :
6234 i == Xfake_acid_5 ? 40 :
6235 i == Xfake_acid_6 ? 50 :
6236 i == Xfake_acid_7 ? 60 :
6237 i == Xfake_acid_8 ? 70 :
6239 i == Xball_2B ? j + 8 :
6240 i == Yball_eat ? j + 1 :
6241 i == Ykey_1_eat ? j + 1 :
6242 i == Ykey_2_eat ? j + 1 :
6243 i == Ykey_3_eat ? j + 1 :
6244 i == Ykey_4_eat ? j + 1 :
6245 i == Ykey_5_eat ? j + 1 :
6246 i == Ykey_6_eat ? j + 1 :
6247 i == Ykey_7_eat ? j + 1 :
6248 i == Ykey_8_eat ? j + 1 :
6249 i == Ylenses_eat ? j + 1 :
6250 i == Ymagnify_eat ? j + 1 :
6251 i == Ygrass_eat ? j + 1 :
6252 i == Ydirt_eat ? j + 1 :
6253 i == Xamoeba_1 ? 0 :
6254 i == Xamoeba_2 ? 1 :
6255 i == Xamoeba_3 ? 2 :
6256 i == Xamoeba_4 ? 3 :
6257 i == Xamoeba_5 ? 0 :
6258 i == Xamoeba_6 ? 1 :
6259 i == Xamoeba_7 ? 2 :
6260 i == Xamoeba_8 ? 3 :
6261 i == Xexit_2 ? j + 8 :
6262 i == Xexit_3 ? j + 16 :
6263 i == Xdynamite_1 ? 0 :
6264 i == Xdynamite_2 ? 8 :
6265 i == Xdynamite_3 ? 16 :
6266 i == Xdynamite_4 ? 24 :
6267 i == Xsand_stonein_1 ? j + 1 :
6268 i == Xsand_stonein_2 ? j + 9 :
6269 i == Xsand_stonein_3 ? j + 17 :
6270 i == Xsand_stonein_4 ? j + 25 :
6271 i == Xsand_stoneout_1 && j == 0 ? 0 :
6272 i == Xsand_stoneout_1 && j == 1 ? 0 :
6273 i == Xsand_stoneout_1 && j == 2 ? 1 :
6274 i == Xsand_stoneout_1 && j == 3 ? 2 :
6275 i == Xsand_stoneout_1 && j == 4 ? 2 :
6276 i == Xsand_stoneout_1 && j == 5 ? 3 :
6277 i == Xsand_stoneout_1 && j == 6 ? 4 :
6278 i == Xsand_stoneout_1 && j == 7 ? 4 :
6279 i == Xsand_stoneout_2 && j == 0 ? 5 :
6280 i == Xsand_stoneout_2 && j == 1 ? 6 :
6281 i == Xsand_stoneout_2 && j == 2 ? 7 :
6282 i == Xsand_stoneout_2 && j == 3 ? 8 :
6283 i == Xsand_stoneout_2 && j == 4 ? 9 :
6284 i == Xsand_stoneout_2 && j == 5 ? 11 :
6285 i == Xsand_stoneout_2 && j == 6 ? 13 :
6286 i == Xsand_stoneout_2 && j == 7 ? 15 :
6287 i == Xboom_bug && j == 1 ? 2 :
6288 i == Xboom_bug && j == 2 ? 2 :
6289 i == Xboom_bug && j == 3 ? 4 :
6290 i == Xboom_bug && j == 4 ? 4 :
6291 i == Xboom_bug && j == 5 ? 2 :
6292 i == Xboom_bug && j == 6 ? 2 :
6293 i == Xboom_bug && j == 7 ? 0 :
6294 i == Xboom_bomb && j == 1 ? 2 :
6295 i == Xboom_bomb && j == 2 ? 2 :
6296 i == Xboom_bomb && j == 3 ? 4 :
6297 i == Xboom_bomb && j == 4 ? 4 :
6298 i == Xboom_bomb && j == 5 ? 2 :
6299 i == Xboom_bomb && j == 6 ? 2 :
6300 i == Xboom_bomb && j == 7 ? 0 :
6301 i == Xboom_android && j == 7 ? 6 :
6302 i == Xboom_1 && j == 1 ? 2 :
6303 i == Xboom_1 && j == 2 ? 2 :
6304 i == Xboom_1 && j == 3 ? 4 :
6305 i == Xboom_1 && j == 4 ? 4 :
6306 i == Xboom_1 && j == 5 ? 6 :
6307 i == Xboom_1 && j == 6 ? 6 :
6308 i == Xboom_1 && j == 7 ? 8 :
6309 i == Xboom_2 && j == 0 ? 8 :
6310 i == Xboom_2 && j == 1 ? 8 :
6311 i == Xboom_2 && j == 2 ? 10 :
6312 i == Xboom_2 && j == 3 ? 10 :
6313 i == Xboom_2 && j == 4 ? 10 :
6314 i == Xboom_2 && j == 5 ? 12 :
6315 i == Xboom_2 && j == 6 ? 12 :
6316 i == Xboom_2 && j == 7 ? 12 :
6317 special_animation && j == 4 ? 3 :
6318 effective_action != action ? 0 :
6322 Bitmap *debug_bitmap = g_em->bitmap;
6323 int debug_src_x = g_em->src_x;
6324 int debug_src_y = g_em->src_y;
6327 int frame = getAnimationFrame(g->anim_frames,
6330 g->anim_start_frame,
6333 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y,
6334 g->double_movement && is_backside);
6336 g_em->bitmap = src_bitmap;
6337 g_em->src_x = src_x;
6338 g_em->src_y = src_y;
6339 g_em->src_offset_x = 0;
6340 g_em->src_offset_y = 0;
6341 g_em->dst_offset_x = 0;
6342 g_em->dst_offset_y = 0;
6343 g_em->width = TILEX;
6344 g_em->height = TILEY;
6346 g_em->crumbled_bitmap = NULL;
6347 g_em->crumbled_src_x = 0;
6348 g_em->crumbled_src_y = 0;
6349 g_em->crumbled_border_size = 0;
6351 g_em->has_crumbled_graphics = FALSE;
6352 g_em->preserve_background = FALSE;
6355 if (has_crumbled_graphics && crumbled == IMG_EMPTY_SPACE)
6356 printf("::: empty crumbled: %d [%s], %d, %d\n",
6357 effective_element, element_info[effective_element].token_name,
6358 effective_action, direction);
6361 /* if element can be crumbled, but certain action graphics are just empty
6362 space (like snapping sand with the original R'n'D graphics), do not
6363 treat these empty space graphics as crumbled graphics in EMC engine */
6364 if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
6366 getGraphicSource(crumbled, frame, &src_bitmap, &src_x, &src_y);
6368 g_em->has_crumbled_graphics = TRUE;
6369 g_em->crumbled_bitmap = src_bitmap;
6370 g_em->crumbled_src_x = src_x;
6371 g_em->crumbled_src_y = src_y;
6372 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
6376 if (element == EL_ROCK &&
6377 effective_action == ACTION_FILLING)
6378 printf("::: has_action_graphics == %d\n", has_action_graphics);
6381 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
6382 effective_action == ACTION_MOVING ||
6383 effective_action == ACTION_PUSHING ||
6384 effective_action == ACTION_EATING)) ||
6385 (!has_action_graphics && (effective_action == ACTION_FILLING ||
6386 effective_action == ACTION_EMPTYING)))
6389 (effective_action == ACTION_FALLING ||
6390 effective_action == ACTION_FILLING ||
6391 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
6392 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
6393 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
6394 int num_steps = (i == Ydrip_s1 ? 16 :
6395 i == Ydrip_s1B ? 16 :
6396 i == Ydrip_s2 ? 16 :
6397 i == Ydrip_s2B ? 16 :
6398 i == Xsand_stonein_1 ? 32 :
6399 i == Xsand_stonein_2 ? 32 :
6400 i == Xsand_stonein_3 ? 32 :
6401 i == Xsand_stonein_4 ? 32 :
6402 i == Xsand_stoneout_1 ? 16 :
6403 i == Xsand_stoneout_2 ? 16 : 8);
6404 int cx = ABS(dx) * (TILEX / num_steps);
6405 int cy = ABS(dy) * (TILEY / num_steps);
6406 int step_frame = (i == Ydrip_s2 ? j + 8 :
6407 i == Ydrip_s2B ? j + 8 :
6408 i == Xsand_stonein_2 ? j + 8 :
6409 i == Xsand_stonein_3 ? j + 16 :
6410 i == Xsand_stonein_4 ? j + 24 :
6411 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
6412 int step = (is_backside ? step_frame : num_steps - step_frame);
6414 if (is_backside) /* tile where movement starts */
6416 if (dx < 0 || dy < 0)
6418 g_em->src_offset_x = cx * step;
6419 g_em->src_offset_y = cy * step;
6423 g_em->dst_offset_x = cx * step;
6424 g_em->dst_offset_y = cy * step;
6427 else /* tile where movement ends */
6429 if (dx < 0 || dy < 0)
6431 g_em->dst_offset_x = cx * step;
6432 g_em->dst_offset_y = cy * step;
6436 g_em->src_offset_x = cx * step;
6437 g_em->src_offset_y = cy * step;
6441 g_em->width = TILEX - cx * step;
6442 g_em->height = TILEY - cy * step;
6445 /* create unique graphic identifier to decide if tile must be redrawn */
6446 /* bit 31 - 16 (16 bit): EM style graphic
6447 bit 15 - 12 ( 4 bit): EM style frame
6448 bit 11 - 6 ( 6 bit): graphic width
6449 bit 5 - 0 ( 6 bit): graphic height */
6450 g_em->unique_identifier =
6451 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
6455 /* skip check for EMC elements not contained in original EMC artwork */
6456 if (element == EL_EMC_FAKE_ACID)
6459 if (g_em->bitmap != debug_bitmap ||
6460 g_em->src_x != debug_src_x ||
6461 g_em->src_y != debug_src_y ||
6462 g_em->src_offset_x != 0 ||
6463 g_em->src_offset_y != 0 ||
6464 g_em->dst_offset_x != 0 ||
6465 g_em->dst_offset_y != 0 ||
6466 g_em->width != TILEX ||
6467 g_em->height != TILEY)
6469 static int last_i = -1;
6477 printf("::: EMC GFX ERROR for element %d -> %d ('%s', '%s', %d)",
6478 i, element, element_info[element].token_name,
6479 element_action_info[effective_action].suffix, direction);
6481 if (element != effective_element)
6482 printf(" [%d ('%s')]",
6484 element_info[effective_element].token_name);
6488 if (g_em->bitmap != debug_bitmap)
6489 printf(" %d (%d): different bitmap! (0x%08x != 0x%08x)\n",
6490 j, is_backside, (int)(g_em->bitmap), (int)(debug_bitmap));
6492 if (g_em->src_x != debug_src_x ||
6493 g_em->src_y != debug_src_y)
6494 printf(" frame %d (%c): %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
6495 j, (is_backside ? 'B' : 'F'),
6496 g_em->src_x, g_em->src_y,
6497 g_em->src_x / 32, g_em->src_y / 32,
6498 debug_src_x, debug_src_y,
6499 debug_src_x / 32, debug_src_y / 32);
6501 if (g_em->src_offset_x != 0 ||
6502 g_em->src_offset_y != 0 ||
6503 g_em->dst_offset_x != 0 ||
6504 g_em->dst_offset_y != 0)
6505 printf(" %d (%d): offsets %d,%d and %d,%d should be all 0\n",
6507 g_em->src_offset_x, g_em->src_offset_y,
6508 g_em->dst_offset_x, g_em->dst_offset_y);
6510 if (g_em->width != TILEX ||
6511 g_em->height != TILEY)
6512 printf(" %d (%d): size %d,%d should be %d,%d\n",
6514 g_em->width, g_em->height, TILEX, TILEY);
6516 num_em_gfx_errors++;
6523 for (i = 0; i < TILE_MAX; i++)
6525 for (j = 0; j < 8; j++)
6527 int element = object_mapping[i].element_rnd;
6528 int action = object_mapping[i].action;
6529 int direction = object_mapping[i].direction;
6530 boolean is_backside = object_mapping[i].is_backside;
6531 int graphic_action = el_act_dir2img(element, action, direction);
6532 int graphic_default = el_act_dir2img(element, ACTION_DEFAULT, direction);
6534 if ((action == ACTION_SMASHED_BY_ROCK ||
6535 action == ACTION_SMASHED_BY_SPRING ||
6536 action == ACTION_EATING) &&
6537 graphic_action == graphic_default)
6539 int e = (action == ACTION_SMASHED_BY_ROCK ? Ystone_s :
6540 action == ACTION_SMASHED_BY_SPRING ? Yspring_s :
6541 direction == MV_LEFT ? (is_backside? Yspring_wB: Yspring_w) :
6542 direction == MV_RIGHT ? (is_backside? Yspring_eB: Yspring_e) :
6545 /* no separate animation for "smashed by rock" -- use rock instead */
6546 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
6547 struct GraphicInfo_EM *g_xx = &graphic_info_em_object[e][7 - j];
6549 g_em->bitmap = g_xx->bitmap;
6550 g_em->src_x = g_xx->src_x;
6551 g_em->src_y = g_xx->src_y;
6552 g_em->src_offset_x = g_xx->src_offset_x;
6553 g_em->src_offset_y = g_xx->src_offset_y;
6554 g_em->dst_offset_x = g_xx->dst_offset_x;
6555 g_em->dst_offset_y = g_xx->dst_offset_y;
6556 g_em->width = g_xx->width;
6557 g_em->height = g_xx->height;
6558 g_em->unique_identifier = g_xx->unique_identifier;
6561 g_em->preserve_background = TRUE;
6566 for (p = 0; p < MAX_PLAYERS; p++)
6568 for (i = 0; i < SPR_MAX; i++)
6570 int element = player_mapping[p][i].element_rnd;
6571 int action = player_mapping[p][i].action;
6572 int direction = player_mapping[p][i].direction;
6574 for (j = 0; j < 8; j++)
6576 int effective_element = element;
6577 int effective_action = action;
6578 int graphic = (direction == MV_NONE ?
6579 el_act2img(effective_element, effective_action) :
6580 el_act_dir2img(effective_element, effective_action,
6582 struct GraphicInfo *g = &graphic_info[graphic];
6583 struct GraphicInfo_EM *g_em = &graphic_info_em_player[p][i][7 - j];
6589 Bitmap *debug_bitmap = g_em->bitmap;
6590 int debug_src_x = g_em->src_x;
6591 int debug_src_y = g_em->src_y;
6594 int frame = getAnimationFrame(g->anim_frames,
6597 g->anim_start_frame,
6600 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
6602 g_em->bitmap = src_bitmap;
6603 g_em->src_x = src_x;
6604 g_em->src_y = src_y;
6605 g_em->src_offset_x = 0;
6606 g_em->src_offset_y = 0;
6607 g_em->dst_offset_x = 0;
6608 g_em->dst_offset_y = 0;
6609 g_em->width = TILEX;
6610 g_em->height = TILEY;
6614 /* skip check for EMC elements not contained in original EMC artwork */
6615 if (element == EL_PLAYER_3 ||
6616 element == EL_PLAYER_4)
6619 if (g_em->bitmap != debug_bitmap ||
6620 g_em->src_x != debug_src_x ||
6621 g_em->src_y != debug_src_y)
6623 static int last_i = -1;
6631 printf("::: EMC GFX ERROR for p/a %d/%d -> %d ('%s', '%s', %d)",
6632 p, i, element, element_info[element].token_name,
6633 element_action_info[effective_action].suffix, direction);
6635 if (element != effective_element)
6636 printf(" [%d ('%s')]",
6638 element_info[effective_element].token_name);
6642 if (g_em->bitmap != debug_bitmap)
6643 printf(" %d: different bitmap! (0x%08x != 0x%08x)\n",
6644 j, (int)(g_em->bitmap), (int)(debug_bitmap));
6646 if (g_em->src_x != debug_src_x ||
6647 g_em->src_y != debug_src_y)
6648 printf(" frame %d: %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
6650 g_em->src_x, g_em->src_y,
6651 g_em->src_x / 32, g_em->src_y / 32,
6652 debug_src_x, debug_src_y,
6653 debug_src_x / 32, debug_src_y / 32);
6655 num_em_gfx_errors++;
6665 printf("::: [%d errors found]\n", num_em_gfx_errors);
6671 void PlayMenuSoundExt(int sound)
6673 if (sound == SND_UNDEFINED)
6676 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
6677 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
6680 if (IS_LOOP_SOUND(sound))
6681 PlaySoundLoop(sound);
6686 void PlayMenuSound()
6688 PlayMenuSoundExt(menu.sound[game_status]);
6691 void PlayMenuSoundStereo(int sound, int stereo_position)
6693 if (sound == SND_UNDEFINED)
6696 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
6697 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
6700 if (IS_LOOP_SOUND(sound))
6701 PlaySoundExt(sound, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_LOOP);
6703 PlaySoundStereo(sound, stereo_position);
6706 void PlayMenuSoundIfLoopExt(int sound)
6708 if (sound == SND_UNDEFINED)
6711 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
6712 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
6715 if (IS_LOOP_SOUND(sound))
6716 PlaySoundLoop(sound);
6719 void PlayMenuSoundIfLoop()
6721 PlayMenuSoundIfLoopExt(menu.sound[game_status]);
6724 void PlayMenuMusicExt(int music)
6726 if (music == MUS_UNDEFINED)
6729 if (!setup.sound_music)
6735 void PlayMenuMusic()
6737 PlayMenuMusicExt(menu.music[game_status]);
6740 void PlaySoundActivating()
6743 PlaySound(SND_MENU_ITEM_ACTIVATING);
6747 void PlaySoundSelecting()
6750 PlaySound(SND_MENU_ITEM_SELECTING);
6754 void ToggleFullscreenIfNeeded()
6756 boolean change_fullscreen = (setup.fullscreen !=
6757 video.fullscreen_enabled);
6758 boolean change_fullscreen_mode = (video.fullscreen_enabled &&
6759 !strEqual(setup.fullscreen_mode,
6760 video.fullscreen_mode_current));
6762 if (!video.fullscreen_available)
6766 if (change_fullscreen || change_fullscreen_mode)
6768 if (setup.fullscreen != video.fullscreen_enabled ||
6769 setup.fullscreen_mode != video.fullscreen_mode_current)
6772 Bitmap *tmp_backbuffer = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
6774 /* save backbuffer content which gets lost when toggling fullscreen mode */
6775 BlitBitmap(backbuffer, tmp_backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
6778 if (change_fullscreen_mode)
6780 if (setup.fullscreen && video.fullscreen_enabled)
6783 /* keep fullscreen, but change fullscreen mode (screen resolution) */
6785 /* (this is now set in sdl.c) */
6787 video.fullscreen_mode_current = setup.fullscreen_mode;
6789 video.fullscreen_enabled = FALSE; /* force new fullscreen mode */
6792 /* toggle fullscreen */
6793 ChangeVideoModeIfNeeded(setup.fullscreen);
6795 setup.fullscreen = video.fullscreen_enabled;
6797 /* restore backbuffer content from temporary backbuffer backup bitmap */
6798 BlitBitmap(tmp_backbuffer, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
6800 FreeBitmap(tmp_backbuffer);
6803 /* update visible window/screen */
6804 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
6806 redraw_mask = REDRAW_ALL;