1 /***********************************************************
2 * Rocks'n'Diamonds -- McDuffin Strikes Back! *
3 *----------------------------------------------------------*
4 * (c) 1995-2006 Artsoft Entertainment *
6 * Detmolder Strasse 189 *
9 * e-mail: info@artsoft.org *
10 *----------------------------------------------------------*
12 ***********************************************************/
14 #include "libgame/libgame.h"
25 /* select level set with EMC X11 graphics before activating EM GFX debugging */
26 #define DEBUG_EM_GFX 0
28 /* tool button identifiers */
29 #define TOOL_CTRL_ID_YES 0
30 #define TOOL_CTRL_ID_NO 1
31 #define TOOL_CTRL_ID_CONFIRM 2
32 #define TOOL_CTRL_ID_PLAYER_1 3
33 #define TOOL_CTRL_ID_PLAYER_2 4
34 #define TOOL_CTRL_ID_PLAYER_3 5
35 #define TOOL_CTRL_ID_PLAYER_4 6
37 #define NUM_TOOL_BUTTONS 7
39 /* forward declaration for internal use */
40 static void UnmapToolButtons();
41 static void HandleToolButtons(struct GadgetInfo *);
42 static int el_act_dir2crm(int, int, int);
43 static int el_act2crm(int, int);
45 static struct GadgetInfo *tool_gadget[NUM_TOOL_BUTTONS];
46 static int request_gadget_id = -1;
48 static char *print_if_not_empty(int element)
50 static char *s = NULL;
51 char *token_name = element_info[element].token_name;
56 s = checked_malloc(strlen(token_name) + 10 + 1);
58 if (element != EL_EMPTY)
59 sprintf(s, "%d\t['%s']", element, token_name);
61 sprintf(s, "%d", element);
66 void DumpTile(int x, int y)
71 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
78 printf("Field Info: SCREEN(%d, %d), LEVEL(%d, %d)\n", sx, sy, x, y);
81 if (!IN_LEV_FIELD(x, y))
83 printf("(not in level field)\n");
89 printf(" Feld: %d\t['%s']\n", Feld[x][y],
90 element_info[Feld[x][y]].token_name);
91 printf(" Back: %s\n", print_if_not_empty(Back[x][y]));
92 printf(" Store: %s\n", print_if_not_empty(Store[x][y]));
93 printf(" Store2: %s\n", print_if_not_empty(Store2[x][y]));
94 printf(" StorePlayer: %s\n", print_if_not_empty(StorePlayer[x][y]));
95 printf(" MovPos: %d\n", MovPos[x][y]);
96 printf(" MovDir: %d\n", MovDir[x][y]);
97 printf(" MovDelay: %d\n", MovDelay[x][y]);
98 printf(" ChangeDelay: %d\n", ChangeDelay[x][y]);
99 printf(" CustomValue: %d\n", CustomValue[x][y]);
100 printf(" GfxElement: %d\n", GfxElement[x][y]);
101 printf(" GfxAction: %d\n", GfxAction[x][y]);
102 printf(" GfxFrame: %d\n", GfxFrame[x][y]);
106 void SetDrawtoField(int mode)
108 if (mode == DRAW_BUFFERED && setup.soft_scrolling)
119 drawto_field = fieldbuffer;
121 else /* DRAW_DIRECT, DRAW_BACKBUFFER */
127 BX2 = SCR_FIELDX - 1;
128 BY2 = SCR_FIELDY - 1;
132 drawto_field = (mode == DRAW_DIRECT ? window : backbuffer);
136 void RedrawPlayfield(boolean force_redraw, int x, int y, int width, int height)
138 if (game_status == GAME_MODE_PLAYING &&
139 level.game_engine_type == GAME_ENGINE_TYPE_EM)
141 /* currently there is no partial redraw -- always redraw whole playfield */
142 RedrawPlayfield_EM(TRUE);
144 /* blit playfield from scroll buffer to normal back buffer for fading in */
145 BlitScreenToBitmap_EM(backbuffer);
147 else if (game_status == GAME_MODE_PLAYING && !game.envelope_active)
153 width = gfx.sxsize + 2 * TILEX;
154 height = gfx.sysize + 2 * TILEY;
157 if (force_redraw || setup.direct_draw)
160 int x1 = (x - SX) / TILEX, y1 = (y - SY) / TILEY;
161 int x2 = (x - SX + width) / TILEX, y2 = (y - SY + height) / TILEY;
163 if (setup.direct_draw)
164 SetDrawtoField(DRAW_BACKBUFFER);
166 for (xx = BX1; xx <= BX2; xx++)
167 for (yy = BY1; yy <= BY2; yy++)
168 if (xx >= x1 && xx <= x2 && yy >= y1 && yy <= y2)
169 DrawScreenField(xx, yy);
172 if (setup.direct_draw)
173 SetDrawtoField(DRAW_DIRECT);
176 if (setup.soft_scrolling)
178 int fx = FX, fy = FY;
180 fx += (ScreenMovDir & (MV_LEFT|MV_RIGHT) ? ScreenGfxPos : 0);
181 fy += (ScreenMovDir & (MV_UP|MV_DOWN) ? ScreenGfxPos : 0);
183 BlitBitmap(fieldbuffer, backbuffer, fx,fy, SXSIZE,SYSIZE, SX,SY);
195 BlitBitmap(drawto, window, x, y, width, height, x, y);
198 void DrawMaskedBorder_Rect(int x, int y, int width, int height)
200 Bitmap *bitmap = graphic_info[IMG_GLOBAL_BORDER].bitmap;
202 SetClipOrigin(bitmap, bitmap->stored_clip_gc, 0, 0);
203 BlitBitmapMasked(bitmap, backbuffer, x, y, width, height, x, y);
206 void DrawMaskedBorder_FIELD()
208 if (global.border_status >= GAME_MODE_TITLE &&
209 global.border_status <= GAME_MODE_PLAYING &&
210 border.draw_masked[global.border_status])
211 DrawMaskedBorder_Rect(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
214 void DrawMaskedBorder_DOOR_1()
216 if (border.draw_masked[GFX_SPECIAL_ARG_DOOR] &&
217 (global.border_status != GAME_MODE_EDITOR ||
218 border.draw_masked[GFX_SPECIAL_ARG_EDITOR]))
219 DrawMaskedBorder_Rect(DX, DY, DXSIZE, DYSIZE);
222 void DrawMaskedBorder_DOOR_2()
224 if (border.draw_masked[GFX_SPECIAL_ARG_DOOR] &&
225 global.border_status != GAME_MODE_EDITOR)
226 DrawMaskedBorder_Rect(VX, VY, VXSIZE, VYSIZE);
229 void DrawMaskedBorder_DOOR_3()
231 /* currently not available */
234 void DrawMaskedBorder_ALL()
236 DrawMaskedBorder_FIELD();
237 DrawMaskedBorder_DOOR_1();
238 DrawMaskedBorder_DOOR_2();
239 DrawMaskedBorder_DOOR_3();
242 void DrawMaskedBorder(int redraw_mask)
244 /* do not draw masked screen borders when displaying title screens */
245 if (effectiveGameStatus() == GAME_MODE_TITLE)
248 if (redraw_mask & REDRAW_ALL)
249 DrawMaskedBorder_ALL();
252 if (redraw_mask & REDRAW_FIELD)
253 DrawMaskedBorder_FIELD();
254 if (redraw_mask & REDRAW_DOOR_1)
255 DrawMaskedBorder_DOOR_1();
256 if (redraw_mask & REDRAW_DOOR_2)
257 DrawMaskedBorder_DOOR_2();
258 if (redraw_mask & REDRAW_DOOR_3)
259 DrawMaskedBorder_DOOR_3();
266 DrawBuffer *buffer = (drawto_field == window ? backbuffer : drawto_field);
268 if (setup.direct_draw && game_status == GAME_MODE_PLAYING)
269 redraw_mask &= ~REDRAW_MAIN;
271 if (redraw_mask & REDRAW_TILES && redraw_tiles > REDRAWTILES_THRESHOLD)
272 redraw_mask |= REDRAW_FIELD;
274 if (redraw_mask & REDRAW_FIELD)
275 redraw_mask &= ~REDRAW_TILES;
277 if (redraw_mask == REDRAW_NONE)
280 if (redraw_mask & REDRAW_TILES &&
281 game_status == GAME_MODE_PLAYING &&
282 border.draw_masked[GAME_MODE_PLAYING])
283 redraw_mask |= REDRAW_FIELD;
285 if (global.fps_slowdown && game_status == GAME_MODE_PLAYING)
287 static boolean last_frame_skipped = FALSE;
288 boolean skip_even_when_not_scrolling = TRUE;
289 boolean just_scrolling = (ScreenMovDir != 0);
290 boolean verbose = FALSE;
292 if (global.fps_slowdown_factor > 1 &&
293 (FrameCounter % global.fps_slowdown_factor) &&
294 (just_scrolling || skip_even_when_not_scrolling))
296 redraw_mask &= ~REDRAW_MAIN;
298 last_frame_skipped = TRUE;
301 printf("FRAME SKIPPED\n");
305 if (last_frame_skipped)
306 redraw_mask |= REDRAW_FIELD;
308 last_frame_skipped = FALSE;
311 printf("frame not skipped\n");
315 /* synchronize X11 graphics at this point; if we would synchronize the
316 display immediately after the buffer switching (after the XFlush),
317 this could mean that we have to wait for the graphics to complete,
318 although we could go on doing calculations for the next frame */
322 /* prevent drawing masked border to backbuffer when using playfield buffer */
323 if (game_status != GAME_MODE_PLAYING ||
324 redraw_mask & REDRAW_FROM_BACKBUFFER ||
325 buffer == backbuffer)
326 DrawMaskedBorder(redraw_mask);
328 DrawMaskedBorder(redraw_mask & REDRAW_DOORS);
330 if (redraw_mask & REDRAW_ALL)
332 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
334 redraw_mask = REDRAW_NONE;
337 if (redraw_mask & REDRAW_FIELD)
339 if (game_status != GAME_MODE_PLAYING ||
340 redraw_mask & REDRAW_FROM_BACKBUFFER)
342 BlitBitmap(backbuffer, window,
343 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE, REAL_SX, REAL_SY);
347 int fx = FX, fy = FY;
349 if (setup.soft_scrolling)
351 fx += (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
352 fy += (ScreenMovDir & (MV_UP | MV_DOWN) ? ScreenGfxPos : 0);
355 if (setup.soft_scrolling ||
356 ABS(ScreenMovPos) + ScrollStepSize == TILEX ||
357 ABS(ScreenMovPos) == ScrollStepSize ||
358 redraw_tiles > REDRAWTILES_THRESHOLD)
360 if (border.draw_masked[GAME_MODE_PLAYING])
362 if (buffer != backbuffer)
364 /* copy playfield buffer to backbuffer to add masked border */
365 BlitBitmap(buffer, backbuffer, fx, fy, SXSIZE, SYSIZE, SX, SY);
366 DrawMaskedBorder(REDRAW_FIELD);
369 BlitBitmap(backbuffer, window,
370 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
375 BlitBitmap(buffer, window, fx, fy, SXSIZE, SYSIZE, SX, SY);
380 printf("redrawing all (ScreenGfxPos == %d) because %s\n",
382 (setup.soft_scrolling ?
383 "setup.soft_scrolling" :
384 ABS(ScreenGfxPos) + ScrollStepSize == TILEX ?
385 "ABS(ScreenGfxPos) + ScrollStepSize == TILEX" :
386 ABS(ScreenGfxPos) == ScrollStepSize ?
387 "ABS(ScreenGfxPos) == ScrollStepSize" :
388 "redraw_tiles > REDRAWTILES_THRESHOLD"));
394 redraw_mask &= ~REDRAW_MAIN;
397 if (redraw_mask & REDRAW_DOORS)
399 if (redraw_mask & REDRAW_DOOR_1)
400 BlitBitmap(backbuffer, window, DX, DY, DXSIZE, DYSIZE, DX, DY);
402 if (redraw_mask & REDRAW_DOOR_2)
403 BlitBitmap(backbuffer, window, VX, VY, VXSIZE, VYSIZE, VX, VY);
405 if (redraw_mask & REDRAW_DOOR_3)
406 BlitBitmap(backbuffer, window, EX, EY, EXSIZE, EYSIZE, EX, EY);
408 redraw_mask &= ~REDRAW_DOORS;
411 if (redraw_mask & REDRAW_MICROLEVEL)
413 BlitBitmap(backbuffer, window, SX, SY + 10 * TILEY, SXSIZE, 7 * TILEY,
414 SX, SY + 10 * TILEY);
416 redraw_mask &= ~REDRAW_MICROLEVEL;
419 if (redraw_mask & REDRAW_TILES)
421 for (x = 0; x < SCR_FIELDX; x++)
422 for (y = 0 ; y < SCR_FIELDY; y++)
423 if (redraw[redraw_x1 + x][redraw_y1 + y])
424 BlitBitmap(buffer, window,
425 FX + x * TILEX, FY + y * TILEY, TILEX, TILEY,
426 SX + x * TILEX, SY + y * TILEY);
429 if (redraw_mask & REDRAW_FPS) /* display frames per second */
434 sprintf(info1, " (only every %d. frame)", global.fps_slowdown_factor);
435 if (!global.fps_slowdown)
438 sprintf(text, "%.1f fps%s", global.frames_per_second, info1);
439 DrawTextExt(window, SX, SY, text, FONT_TEXT_2, BLIT_OPAQUE);
444 for (x = 0; x < MAX_BUF_XSIZE; x++)
445 for (y = 0; y < MAX_BUF_YSIZE; y++)
448 redraw_mask = REDRAW_NONE;
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)
623 global.border_status = game_status;
626 global.fading_status = game_status;
628 if (global.fading_type == TYPE_ENTER_MENU)
629 fading = menu.enter_menu;
630 else if (global.fading_type == TYPE_LEAVE_MENU)
631 fading = menu.leave_menu;
632 else if (global.fading_type == TYPE_ENTER_SCREEN)
633 fading = menu.enter_screen[global.fading_status];
634 else if (global.fading_type == TYPE_LEAVE_SCREEN)
635 fading = menu.leave_screen[global.fading_status];
637 printf("::: FadeIn: %s [0x%08x] [%d]\n",
638 global.fading_type == TYPE_ENTER_MENU ? "enter_menu" :
639 global.fading_type == TYPE_LEAVE_MENU ? "leave_menu" :
640 global.fading_type == TYPE_ENTER_SCREEN ? "enter_screen" :
641 global.fading_type == TYPE_LEAVE_SCREEN ? "leave_screen" : "(?)",
643 global.fading_status);
647 // printf("::: now fading in...\n");
649 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
650 FadeExt(fade_mask, fading.fade_mode);
652 FadeExt(fade_mask, FADE_MODE_FADE_IN);
655 if (fading.fade_mode == FADE_MODE_CROSSFADE)
656 FadeExt(fade_mask, FADE_MODE_CROSSFADE);
658 FadeExt(fade_mask, FADE_MODE_FADE_IN);
660 FadeExt(fade_mask, FADE_MODE_FADE_IN);
665 void FadeOut(int fade_mask)
668 if (global.fading_type == TYPE_ENTER_MENU)
669 fading = menu.enter_menu;
670 else if (global.fading_type == TYPE_LEAVE_MENU)
671 fading = menu.leave_menu;
672 else if (global.fading_type == TYPE_ENTER_SCREEN)
673 fading = menu.enter_screen[global.fading_status];
674 else if (global.fading_type == TYPE_LEAVE_SCREEN)
675 fading = menu.leave_screen[global.fading_status];
677 printf("::: FadeOut: %s [0x%08x] [%d]\n",
678 global.fading_type == TYPE_ENTER_MENU ? "enter_menu" :
679 global.fading_type == TYPE_LEAVE_MENU ? "leave_menu" :
680 global.fading_type == TYPE_ENTER_SCREEN ? "enter_screen" :
681 global.fading_type == TYPE_LEAVE_SCREEN ? "leave_screen" : "(?)",
683 global.fading_status);
687 // printf("::: fading.fade_mode == %d\n", fading.fade_mode);
689 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
690 FadeCrossSaveBackbuffer();
692 FadeExt(fade_mask, FADE_MODE_FADE_OUT);
695 if (fading.fade_mode == FADE_MODE_CROSSFADE)
696 FadeCrossSaveBackbuffer();
698 FadeExt(fade_mask, FADE_MODE_FADE_OUT);
700 FadeExt(fade_mask, FADE_MODE_FADE_OUT);
705 void FadeCross(int fade_mask)
707 FadeExt(fade_mask, FADE_MODE_CROSSFADE);
710 void FadeCrossSaveBackbuffer()
712 BlitBitmap(backbuffer, bitmap_db_cross, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
716 void FadeSetEnterMenu()
718 global.fading_type = TYPE_ENTER_MENU;
721 void FadeSetLeaveMenu()
723 global.fading_type = TYPE_LEAVE_MENU;
726 void FadeSetEnterScreen()
728 global.fading_type = TYPE_ENTER_SCREEN;
731 void FadeSetLeaveScreen()
733 // global.fading_type = TYPE_LEAVE_SCREEN;
735 global.fading_type = (global.fading_type == TYPE_ENTER_SCREEN ?
736 TYPE_LEAVE_SCREEN : TYPE_LEAVE_MENU);
741 static void FadeSetLeaveNext(struct TitleFadingInfo fading_leave, boolean set)
743 static struct TitleFadingInfo fading_leave_stored;
746 fading_leave_stored = fading_leave;
748 fading = fading_leave_stored;
751 void FadeSetEnterMenu()
753 fading = menu.enter_menu;
756 printf("::: storing enter_menu\n");
759 FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
762 void FadeSetLeaveMenu()
764 fading = menu.leave_menu;
767 printf("::: storing leave_menu\n");
770 FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
773 void FadeSetEnterScreen()
775 fading = menu.enter_screen[game_status];
778 printf("::: storing leave_screen[%d]\n", game_status);
782 printf("::: - %d, %d / %d, %d\n",
783 menu.enter_screen[game_status].fade_mode,
784 menu.enter_screen[game_status].fade_delay,
785 menu.leave_screen[game_status].fade_mode,
786 menu.leave_screen[game_status].fade_delay);
789 FadeSetLeaveNext(menu.leave_screen[game_status], TRUE); /* store */
792 void FadeSetLeaveScreen()
795 printf("::: recalling last stored value\n");
798 FadeSetLeaveNext(menu.leave_screen[game_status], FALSE); /* recall */
803 void FadeSetFromType(int type)
805 if (type & TYPE_ENTER_SCREEN)
806 FadeSetEnterScreen();
807 else if (type & TYPE_ENTER)
809 else if (type & TYPE_LEAVE)
813 void FadeSetDisabled()
815 static struct TitleFadingInfo fading_none = { FADE_MODE_NONE, -1, -1, -1 };
817 fading = fading_none;
820 void FadeSkipNextFadeIn()
822 FadeExt(0, FADE_MODE_SKIP_FADE_IN);
825 void FadeSkipNextFadeOut()
827 FadeExt(0, FADE_MODE_SKIP_FADE_OUT);
830 void SetWindowBackgroundImageIfDefined(int graphic)
832 if (graphic_info[graphic].bitmap)
833 SetWindowBackgroundBitmap(graphic_info[graphic].bitmap);
836 void SetMainBackgroundImageIfDefined(int graphic)
838 if (graphic_info[graphic].bitmap)
839 SetMainBackgroundBitmap(graphic_info[graphic].bitmap);
842 void SetDoorBackgroundImageIfDefined(int graphic)
844 if (graphic_info[graphic].bitmap)
845 SetDoorBackgroundBitmap(graphic_info[graphic].bitmap);
848 void SetWindowBackgroundImage(int graphic)
850 SetWindowBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
851 graphic_info[graphic].bitmap ?
852 graphic_info[graphic].bitmap :
853 graphic_info[IMG_BACKGROUND].bitmap);
856 void SetMainBackgroundImage(int graphic)
858 SetMainBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
859 graphic_info[graphic].bitmap ?
860 graphic_info[graphic].bitmap :
861 graphic_info[IMG_BACKGROUND].bitmap);
864 void SetDoorBackgroundImage(int graphic)
866 SetDoorBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
867 graphic_info[graphic].bitmap ?
868 graphic_info[graphic].bitmap :
869 graphic_info[IMG_BACKGROUND].bitmap);
872 void SetPanelBackground()
874 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, bitmap_db_panel,
875 DOOR_GFX_PAGEX5, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE, 0, 0);
877 SetDoorBackgroundBitmap(bitmap_db_panel);
880 void DrawBackground(int x, int y, int width, int height)
882 /* !!! "drawto" might still point to playfield buffer here (see below) !!! */
883 /* (when entering hall of fame after playing) */
885 ClearRectangleOnBackground(drawto, x, y, width, height);
887 ClearRectangleOnBackground(backbuffer, x, y, width, height);
890 redraw_mask |= REDRAW_FIELD;
893 void DrawBackgroundForFont(int x, int y, int width, int height, int font_nr)
895 struct FontBitmapInfo *font = getFontBitmapInfo(font_nr);
897 if (font->bitmap == NULL)
900 DrawBackground(x, y, width, height);
903 void DrawBackgroundForGraphic(int x, int y, int width, int height, int graphic)
905 struct GraphicInfo *g = &graphic_info[graphic];
907 if (g->bitmap == NULL)
910 DrawBackground(x, y, width, height);
915 /* !!! "drawto" might still point to playfield buffer here (see above) !!! */
916 /* (when entering hall of fame after playing) */
917 DrawBackground(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
919 /* !!! maybe this should be done before clearing the background !!! */
920 if (setup.soft_scrolling && game_status == GAME_MODE_PLAYING)
922 ClearRectangle(fieldbuffer, 0, 0, FXSIZE, FYSIZE);
923 SetDrawtoField(DRAW_BUFFERED);
926 SetDrawtoField(DRAW_BACKBUFFER);
928 if (setup.direct_draw && game_status == GAME_MODE_PLAYING)
930 ClearRectangle(window, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
931 SetDrawtoField(DRAW_DIRECT);
935 void MarkTileDirty(int x, int y)
937 int xx = redraw_x1 + x;
938 int yy = redraw_y1 + y;
943 redraw[xx][yy] = TRUE;
944 redraw_mask |= REDRAW_TILES;
947 void SetBorderElement()
951 BorderElement = EL_EMPTY;
953 for (y = 0; y < lev_fieldy && BorderElement == EL_EMPTY; y++)
955 for (x = 0; x < lev_fieldx; x++)
957 if (!IS_INDESTRUCTIBLE(Feld[x][y]))
958 BorderElement = EL_STEELWALL;
960 if (y != 0 && y != lev_fieldy - 1 && x != lev_fieldx - 1)
966 void FloodFillLevel(int from_x, int from_y, int fill_element,
967 short field[MAX_LEV_FIELDX][MAX_LEV_FIELDY],
968 int max_fieldx, int max_fieldy)
972 static int check[4][2] = { { -1, 0 }, { 0, -1 }, { 1, 0 }, { 0, 1 } };
973 static int safety = 0;
975 /* check if starting field still has the desired content */
976 if (field[from_x][from_y] == fill_element)
981 if (safety > max_fieldx * max_fieldy)
982 Error(ERR_EXIT, "Something went wrong in 'FloodFill()'. Please debug.");
984 old_element = field[from_x][from_y];
985 field[from_x][from_y] = fill_element;
987 for (i = 0; i < 4; i++)
989 x = from_x + check[i][0];
990 y = from_y + check[i][1];
992 if (IN_FIELD(x, y, max_fieldx, max_fieldy) && field[x][y] == old_element)
993 FloodFillLevel(x, y, fill_element, field, max_fieldx, max_fieldy);
999 void SetRandomAnimationValue(int x, int y)
1001 gfx.anim_random_frame = GfxRandom[x][y];
1004 inline int getGraphicAnimationFrame(int graphic, int sync_frame)
1006 /* animation synchronized with global frame counter, not move position */
1007 if (graphic_info[graphic].anim_global_sync || sync_frame < 0)
1008 sync_frame = FrameCounter;
1010 return getAnimationFrame(graphic_info[graphic].anim_frames,
1011 graphic_info[graphic].anim_delay,
1012 graphic_info[graphic].anim_mode,
1013 graphic_info[graphic].anim_start_frame,
1017 void getSizedGraphicSource(int graphic, int frame, int tilesize_raw,
1018 Bitmap **bitmap, int *x, int *y)
1022 int width_mult, width_div;
1023 int height_mult, height_div;
1027 { 15, 16, 2, 3 }, /* 1 x 1 */
1028 { 7, 8, 2, 3 }, /* 2 x 2 */
1029 { 3, 4, 2, 3 }, /* 4 x 4 */
1030 { 1, 2, 2, 3 }, /* 8 x 8 */
1031 { 0, 1, 2, 3 }, /* 16 x 16 */
1032 { 0, 1, 0, 1 }, /* 32 x 32 */
1034 struct GraphicInfo *g = &graphic_info[graphic];
1035 Bitmap *src_bitmap = g->bitmap;
1036 int tilesize = MIN(MAX(1, tilesize_raw), TILESIZE);
1037 int offset_calc_pos = log_2(tilesize);
1038 int width_mult = offset_calc[offset_calc_pos].width_mult;
1039 int width_div = offset_calc[offset_calc_pos].width_div;
1040 int height_mult = offset_calc[offset_calc_pos].height_mult;
1041 int height_div = offset_calc[offset_calc_pos].height_div;
1042 int startx = src_bitmap->width * width_mult / width_div;
1043 int starty = src_bitmap->height * height_mult / height_div;
1044 int src_x = g->src_x * tilesize / TILESIZE;
1045 int src_y = g->src_y * tilesize / TILESIZE;
1046 int width = g->width * tilesize / TILESIZE;
1047 int height = g->height * tilesize / TILESIZE;
1048 int offset_x = g->offset_x * tilesize / TILESIZE;
1049 int offset_y = g->offset_y * tilesize / TILESIZE;
1051 if (g->offset_y == 0) /* frames are ordered horizontally */
1053 int max_width = g->anim_frames_per_line * width;
1054 int pos = (src_y / height) * max_width + src_x + frame * offset_x;
1056 src_x = pos % max_width;
1057 src_y = src_y % height + pos / max_width * height;
1059 else if (g->offset_x == 0) /* frames are ordered vertically */
1061 int max_height = g->anim_frames_per_line * height;
1062 int pos = (src_x / width) * max_height + src_y + frame * offset_y;
1064 src_x = src_x % width + pos / max_height * width;
1065 src_y = pos % max_height;
1067 else /* frames are ordered diagonally */
1069 src_x = src_x + frame * offset_x;
1070 src_y = src_y + frame * offset_y;
1073 *bitmap = src_bitmap;
1074 *x = startx + src_x;
1075 *y = starty + src_y;
1078 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
1081 getSizedGraphicSource(graphic, 0, MINI_TILESIZE, bitmap, x, y);
1083 struct GraphicInfo *g = &graphic_info[graphic];
1084 int mini_startx = 0;
1085 int mini_starty = g->bitmap->height * 2 / 3;
1087 *bitmap = g->bitmap;
1088 *x = mini_startx + g->src_x / 2;
1089 *y = mini_starty + g->src_y / 2;
1093 inline void getGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
1094 int *x, int *y, boolean get_backside)
1096 struct GraphicInfo *g = &graphic_info[graphic];
1097 int src_x = g->src_x + (get_backside ? g->offset2_x : 0);
1098 int src_y = g->src_y + (get_backside ? g->offset2_y : 0);
1100 *bitmap = g->bitmap;
1102 if (g->offset_y == 0) /* frames are ordered horizontally */
1104 int max_width = g->anim_frames_per_line * g->width;
1105 int pos = (src_y / g->height) * max_width + src_x + frame * g->offset_x;
1107 *x = pos % max_width;
1108 *y = src_y % g->height + pos / max_width * g->height;
1110 else if (g->offset_x == 0) /* frames are ordered vertically */
1112 int max_height = g->anim_frames_per_line * g->height;
1113 int pos = (src_x / g->width) * max_height + src_y + frame * g->offset_y;
1115 *x = src_x % g->width + pos / max_height * g->width;
1116 *y = pos % max_height;
1118 else /* frames are ordered diagonally */
1120 *x = src_x + frame * g->offset_x;
1121 *y = src_y + frame * g->offset_y;
1125 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
1127 getGraphicSourceExt(graphic, frame, bitmap, x, y, FALSE);
1130 void DrawGraphic(int x, int y, int graphic, int frame)
1133 if (!IN_SCR_FIELD(x, y))
1135 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
1136 printf("DrawGraphic(): This should never happen!\n");
1141 DrawGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic, frame);
1142 MarkTileDirty(x, y);
1145 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
1151 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1152 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
1155 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
1158 if (!IN_SCR_FIELD(x, y))
1160 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
1161 printf("DrawGraphicThruMask(): This should never happen!\n");
1166 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y *TILEY, graphic,
1168 MarkTileDirty(x, y);
1171 void DrawGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y, int graphic,
1177 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1179 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1180 dst_x - src_x, dst_y - src_y);
1181 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dst_x, dst_y);
1184 void DrawSizedGraphic(int x, int y, int graphic, int frame, int tilesize)
1186 DrawSizedGraphicExt(drawto, SX + x * tilesize, SY + y * tilesize, graphic,
1188 MarkTileDirty(x / tilesize, y / tilesize);
1191 void DrawSizedGraphicExt(DrawBuffer *d, int x, int y, int graphic, int frame,
1197 getSizedGraphicSource(graphic, frame, tilesize, &src_bitmap, &src_x, &src_y);
1198 BlitBitmap(src_bitmap, d, src_x, src_y, tilesize, tilesize, x, y);
1201 void DrawMiniGraphic(int x, int y, int graphic)
1203 DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
1204 MarkTileDirty(x / 2, y / 2);
1207 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
1212 getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1213 BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
1216 inline static void DrawGraphicShiftedNormal(int x, int y, int dx, int dy,
1217 int graphic, int frame,
1218 int cut_mode, int mask_mode)
1223 int width = TILEX, height = TILEY;
1226 if (dx || dy) /* shifted graphic */
1228 if (x < BX1) /* object enters playfield from the left */
1235 else if (x > BX2) /* object enters playfield from the right */
1241 else if (x==BX1 && dx < 0) /* object leaves playfield to the left */
1247 else if (x==BX2 && dx > 0) /* object leaves playfield to the right */
1249 else if (dx) /* general horizontal movement */
1250 MarkTileDirty(x + SIGN(dx), y);
1252 if (y < BY1) /* object enters playfield from the top */
1254 if (cut_mode==CUT_BELOW) /* object completely above top border */
1262 else if (y > BY2) /* object enters playfield from the bottom */
1268 else if (y==BY1 && dy < 0) /* object leaves playfield to the top */
1274 else if (dy > 0 && cut_mode == CUT_ABOVE)
1276 if (y == BY2) /* object completely above bottom border */
1282 MarkTileDirty(x, y + 1);
1283 } /* object leaves playfield to the bottom */
1284 else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
1286 else if (dy) /* general vertical movement */
1287 MarkTileDirty(x, y + SIGN(dy));
1291 if (!IN_SCR_FIELD(x, y))
1293 printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
1294 printf("DrawGraphicShifted(): This should never happen!\n");
1299 if (width > 0 && height > 0)
1301 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1306 dst_x = FX + x * TILEX + dx;
1307 dst_y = FY + y * TILEY + dy;
1309 if (mask_mode == USE_MASKING)
1311 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1312 dst_x - src_x, dst_y - src_y);
1313 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1317 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1320 MarkTileDirty(x, y);
1324 inline static void DrawGraphicShiftedDouble(int x, int y, int dx, int dy,
1325 int graphic, int frame,
1326 int cut_mode, int mask_mode)
1331 int width = TILEX, height = TILEY;
1334 int x2 = x + SIGN(dx);
1335 int y2 = y + SIGN(dy);
1336 int anim_frames = graphic_info[graphic].anim_frames;
1337 int sync_frame = (dx ? ABS(dx) : ABS(dy)) * anim_frames / TILESIZE;
1338 boolean draw_start_tile = (cut_mode != CUT_ABOVE); /* only for falling! */
1339 boolean draw_end_tile = (cut_mode != CUT_BELOW); /* only for falling! */
1341 /* re-calculate animation frame for two-tile movement animation */
1342 frame = getGraphicAnimationFrame(graphic, sync_frame);
1344 /* check if movement start graphic inside screen area and should be drawn */
1345 if (draw_start_tile && IN_SCR_FIELD(x1, y1))
1347 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, TRUE);
1349 dst_x = FX + x1 * TILEX;
1350 dst_y = FY + y1 * TILEY;
1352 if (mask_mode == USE_MASKING)
1354 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1355 dst_x - src_x, dst_y - src_y);
1356 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1360 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1363 MarkTileDirty(x1, y1);
1366 /* check if movement end graphic inside screen area and should be drawn */
1367 if (draw_end_tile && IN_SCR_FIELD(x2, y2))
1369 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
1371 dst_x = FX + x2 * TILEX;
1372 dst_y = FY + y2 * TILEY;
1374 if (mask_mode == USE_MASKING)
1376 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1377 dst_x - src_x, dst_y - src_y);
1378 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1382 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1385 MarkTileDirty(x2, y2);
1389 static void DrawGraphicShifted(int x, int y, int dx, int dy,
1390 int graphic, int frame,
1391 int cut_mode, int mask_mode)
1395 DrawGraphic(x, y, graphic, frame);
1400 if (graphic_info[graphic].double_movement) /* EM style movement images */
1401 DrawGraphicShiftedDouble(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1403 DrawGraphicShiftedNormal(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1406 void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
1407 int frame, int cut_mode)
1409 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, USE_MASKING);
1412 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
1413 int cut_mode, int mask_mode)
1415 int lx = LEVELX(x), ly = LEVELY(y);
1419 if (IN_LEV_FIELD(lx, ly))
1421 SetRandomAnimationValue(lx, ly);
1423 graphic = el_act_dir2img(element, GfxAction[lx][ly], GfxDir[lx][ly]);
1424 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1426 /* do not use double (EM style) movement graphic when not moving */
1427 if (graphic_info[graphic].double_movement && !dx && !dy)
1429 graphic = el_act_dir2img(element, ACTION_DEFAULT, GfxDir[lx][ly]);
1430 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1433 else /* border element */
1435 graphic = el2img(element);
1436 frame = getGraphicAnimationFrame(graphic, -1);
1439 if (element == EL_EXPANDABLE_WALL)
1441 boolean left_stopped = FALSE, right_stopped = FALSE;
1443 if (!IN_LEV_FIELD(lx - 1, ly) || IS_WALL(Feld[lx - 1][ly]))
1444 left_stopped = TRUE;
1445 if (!IN_LEV_FIELD(lx + 1, ly) || IS_WALL(Feld[lx + 1][ly]))
1446 right_stopped = TRUE;
1448 if (left_stopped && right_stopped)
1450 else if (left_stopped)
1452 graphic = IMG_EXPANDABLE_WALL_GROWING_RIGHT;
1453 frame = graphic_info[graphic].anim_frames - 1;
1455 else if (right_stopped)
1457 graphic = IMG_EXPANDABLE_WALL_GROWING_LEFT;
1458 frame = graphic_info[graphic].anim_frames - 1;
1463 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
1464 else if (mask_mode == USE_MASKING)
1465 DrawGraphicThruMask(x, y, graphic, frame);
1467 DrawGraphic(x, y, graphic, frame);
1470 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
1471 int cut_mode, int mask_mode)
1473 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1474 DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
1475 cut_mode, mask_mode);
1478 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
1481 DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1484 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
1487 DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1490 void DrawLevelElementThruMask(int x, int y, int element)
1492 DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1495 void DrawLevelFieldThruMask(int x, int y)
1497 DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
1500 static void DrawLevelFieldCrumbledSandExt(int x, int y, int graphic, int frame)
1504 int sx = SCREENX(x), sy = SCREENY(y);
1506 int width, height, cx, cy, i;
1507 int crumbled_border_size = graphic_info[graphic].border_size;
1508 static int xy[4][2] =
1516 if (!IN_LEV_FIELD(x, y))
1519 element = TILE_GFX_ELEMENT(x, y);
1521 /* crumble field itself */
1522 if (GFX_CRUMBLED(element) && !IS_MOVING(x, y))
1524 if (!IN_SCR_FIELD(sx, sy))
1527 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1529 for (i = 0; i < 4; i++)
1531 int xx = x + xy[i][0];
1532 int yy = y + xy[i][1];
1534 element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1537 /* check if neighbour field is of same type */
1538 if (GFX_CRUMBLED(element) && !IS_MOVING(xx, yy))
1541 if (i == 1 || i == 2)
1543 width = crumbled_border_size;
1545 cx = (i == 2 ? TILEX - crumbled_border_size : 0);
1551 height = crumbled_border_size;
1553 cy = (i == 3 ? TILEY - crumbled_border_size : 0);
1556 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1557 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
1560 MarkTileDirty(sx, sy);
1562 else /* crumble neighbour fields */
1564 for (i = 0; i < 4; i++)
1566 int xx = x + xy[i][0];
1567 int yy = y + xy[i][1];
1568 int sxx = sx + xy[i][0];
1569 int syy = sy + xy[i][1];
1571 if (!IN_LEV_FIELD(xx, yy) ||
1572 !IN_SCR_FIELD(sxx, syy) ||
1576 if (Feld[xx][yy] == EL_ELEMENT_SNAPPING)
1579 element = TILE_GFX_ELEMENT(xx, yy);
1581 if (!GFX_CRUMBLED(element))
1584 graphic = el_act2crm(element, ACTION_DEFAULT);
1585 crumbled_border_size = graphic_info[graphic].border_size;
1587 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1589 if (i == 1 || i == 2)
1591 width = crumbled_border_size;
1593 cx = (i == 1 ? TILEX - crumbled_border_size : 0);
1599 height = crumbled_border_size;
1601 cy = (i == 0 ? TILEY - crumbled_border_size : 0);
1604 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1605 width, height, FX + sxx * TILEX + cx, FY + syy * TILEY + cy);
1607 MarkTileDirty(sxx, syy);
1612 void DrawLevelFieldCrumbledSand(int x, int y)
1616 if (!IN_LEV_FIELD(x, y))
1620 /* !!! CHECK THIS !!! */
1623 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
1624 GFX_CRUMBLED(GfxElement[x][y]))
1627 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
1628 GfxElement[x][y] != EL_UNDEFINED &&
1629 GFX_CRUMBLED(GfxElement[x][y]))
1631 DrawLevelFieldCrumbledSandDigging(x, y, GfxDir[x][y], GfxFrame[x][y]);
1638 graphic = el_act2crm(TILE_GFX_ELEMENT(x, y), ACTION_DEFAULT);
1640 graphic = el_act2crm(Feld[x][y], ACTION_DEFAULT);
1643 DrawLevelFieldCrumbledSandExt(x, y, graphic, 0);
1646 void DrawLevelFieldCrumbledSandDigging(int x, int y, int direction,
1649 int graphic1 = el_act_dir2img(GfxElement[x][y], ACTION_DIGGING, direction);
1650 int graphic2 = el_act_dir2crm(GfxElement[x][y], ACTION_DIGGING, direction);
1651 int frame1 = getGraphicAnimationFrame(graphic1, step_frame);
1652 int frame2 = getGraphicAnimationFrame(graphic2, step_frame);
1653 int sx = SCREENX(x), sy = SCREENY(y);
1655 DrawGraphic(sx, sy, graphic1, frame1);
1656 DrawLevelFieldCrumbledSandExt(x, y, graphic2, frame2);
1659 void DrawLevelFieldCrumbledSandNeighbours(int x, int y)
1661 int sx = SCREENX(x), sy = SCREENY(y);
1662 static int xy[4][2] =
1671 for (i = 0; i < 4; i++)
1673 int xx = x + xy[i][0];
1674 int yy = y + xy[i][1];
1675 int sxx = sx + xy[i][0];
1676 int syy = sy + xy[i][1];
1678 if (!IN_LEV_FIELD(xx, yy) ||
1679 !IN_SCR_FIELD(sxx, syy) ||
1680 !GFX_CRUMBLED(Feld[xx][yy]) ||
1684 DrawLevelField(xx, yy);
1688 static int getBorderElement(int x, int y)
1692 { EL_STEELWALL_TOPLEFT, EL_INVISIBLE_STEELWALL_TOPLEFT },
1693 { EL_STEELWALL_TOPRIGHT, EL_INVISIBLE_STEELWALL_TOPRIGHT },
1694 { EL_STEELWALL_BOTTOMLEFT, EL_INVISIBLE_STEELWALL_BOTTOMLEFT },
1695 { EL_STEELWALL_BOTTOMRIGHT, EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
1696 { EL_STEELWALL_VERTICAL, EL_INVISIBLE_STEELWALL_VERTICAL },
1697 { EL_STEELWALL_HORIZONTAL, EL_INVISIBLE_STEELWALL_HORIZONTAL },
1698 { EL_STEELWALL, EL_INVISIBLE_STEELWALL }
1700 int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
1701 int steel_position = (x == -1 && y == -1 ? 0 :
1702 x == lev_fieldx && y == -1 ? 1 :
1703 x == -1 && y == lev_fieldy ? 2 :
1704 x == lev_fieldx && y == lev_fieldy ? 3 :
1705 x == -1 || x == lev_fieldx ? 4 :
1706 y == -1 || y == lev_fieldy ? 5 : 6);
1708 return border[steel_position][steel_type];
1711 void DrawScreenElement(int x, int y, int element)
1713 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
1714 DrawLevelFieldCrumbledSand(LEVELX(x), LEVELY(y));
1717 void DrawLevelElement(int x, int y, int element)
1719 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1720 DrawScreenElement(SCREENX(x), SCREENY(y), element);
1723 void DrawScreenField(int x, int y)
1725 int lx = LEVELX(x), ly = LEVELY(y);
1726 int element, content;
1728 if (!IN_LEV_FIELD(lx, ly))
1730 if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
1733 element = getBorderElement(lx, ly);
1735 DrawScreenElement(x, y, element);
1739 element = Feld[lx][ly];
1740 content = Store[lx][ly];
1742 if (IS_MOVING(lx, ly))
1744 int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
1745 boolean cut_mode = NO_CUTTING;
1747 if (element == EL_QUICKSAND_EMPTYING ||
1748 element == EL_QUICKSAND_FAST_EMPTYING ||
1749 element == EL_MAGIC_WALL_EMPTYING ||
1750 element == EL_BD_MAGIC_WALL_EMPTYING ||
1751 element == EL_DC_MAGIC_WALL_EMPTYING ||
1752 element == EL_AMOEBA_DROPPING)
1753 cut_mode = CUT_ABOVE;
1754 else if (element == EL_QUICKSAND_FILLING ||
1755 element == EL_QUICKSAND_FAST_FILLING ||
1756 element == EL_MAGIC_WALL_FILLING ||
1757 element == EL_BD_MAGIC_WALL_FILLING ||
1758 element == EL_DC_MAGIC_WALL_FILLING)
1759 cut_mode = CUT_BELOW;
1761 if (cut_mode == CUT_ABOVE)
1762 DrawScreenElementShifted(x, y, 0, 0, element, NO_CUTTING);
1764 DrawScreenElement(x, y, EL_EMPTY);
1767 DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
1768 else if (cut_mode == NO_CUTTING)
1769 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
1771 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
1773 if (content == EL_ACID)
1775 int dir = MovDir[lx][ly];
1776 int newlx = lx + (dir == MV_LEFT ? -1 : dir == MV_RIGHT ? +1 : 0);
1777 int newly = ly + (dir == MV_UP ? -1 : dir == MV_DOWN ? +1 : 0);
1779 DrawLevelElementThruMask(newlx, newly, EL_ACID);
1782 else if (IS_BLOCKED(lx, ly))
1787 boolean cut_mode = NO_CUTTING;
1788 int element_old, content_old;
1790 Blocked2Moving(lx, ly, &oldx, &oldy);
1793 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
1794 MovDir[oldx][oldy] == MV_RIGHT);
1796 element_old = Feld[oldx][oldy];
1797 content_old = Store[oldx][oldy];
1799 if (element_old == EL_QUICKSAND_EMPTYING ||
1800 element_old == EL_QUICKSAND_FAST_EMPTYING ||
1801 element_old == EL_MAGIC_WALL_EMPTYING ||
1802 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
1803 element_old == EL_DC_MAGIC_WALL_EMPTYING ||
1804 element_old == EL_AMOEBA_DROPPING)
1805 cut_mode = CUT_ABOVE;
1807 DrawScreenElement(x, y, EL_EMPTY);
1810 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
1812 else if (cut_mode == NO_CUTTING)
1813 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
1816 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
1819 else if (IS_DRAWABLE(element))
1820 DrawScreenElement(x, y, element);
1822 DrawScreenElement(x, y, EL_EMPTY);
1825 void DrawLevelField(int x, int y)
1827 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1828 DrawScreenField(SCREENX(x), SCREENY(y));
1829 else if (IS_MOVING(x, y))
1833 Moving2Blocked(x, y, &newx, &newy);
1834 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
1835 DrawScreenField(SCREENX(newx), SCREENY(newy));
1837 else if (IS_BLOCKED(x, y))
1841 Blocked2Moving(x, y, &oldx, &oldy);
1842 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
1843 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
1847 void DrawMiniElement(int x, int y, int element)
1851 graphic = el2edimg(element);
1852 DrawMiniGraphic(x, y, graphic);
1855 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
1857 int x = sx + scroll_x, y = sy + scroll_y;
1859 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
1860 DrawMiniElement(sx, sy, EL_EMPTY);
1861 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
1862 DrawMiniElement(sx, sy, Feld[x][y]);
1864 DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
1867 void DrawEnvelopeBackground(int envelope_nr, int startx, int starty,
1868 int x, int y, int xsize, int ysize, int font_nr)
1870 int font_width = getFontWidth(font_nr);
1871 int font_height = getFontHeight(font_nr);
1872 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1875 int dst_x = SX + startx + x * font_width;
1876 int dst_y = SY + starty + y * font_height;
1877 int width = graphic_info[graphic].width;
1878 int height = graphic_info[graphic].height;
1879 int inner_width = MAX(width - 2 * font_width, font_width);
1880 int inner_height = MAX(height - 2 * font_height, font_height);
1881 int inner_sx = (width >= 3 * font_width ? font_width : 0);
1882 int inner_sy = (height >= 3 * font_height ? font_height : 0);
1883 boolean draw_masked = graphic_info[graphic].draw_masked;
1885 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1887 if (src_bitmap == NULL || width < font_width || height < font_height)
1889 ClearRectangle(drawto, dst_x, dst_y, font_width, font_height);
1893 src_x += (x == 0 ? 0 : x == xsize - 1 ? width - font_width :
1894 inner_sx + (x - 1) * font_width % inner_width);
1895 src_y += (y == 0 ? 0 : y == ysize - 1 ? height - font_height :
1896 inner_sy + (y - 1) * font_height % inner_height);
1900 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1901 dst_x - src_x, dst_y - src_y);
1902 BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1906 BlitBitmap(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1910 void AnimateEnvelope(int envelope_nr, int anim_mode, int action)
1912 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1913 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1914 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
1915 boolean ffwd_delay = (tape.playing && tape.fast_forward);
1916 boolean no_delay = (tape.warp_forward);
1917 unsigned long anim_delay = 0;
1918 int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
1919 int anim_delay_value = (no_delay ? 0 : frame_delay_value);
1920 int font_nr = FONT_ENVELOPE_1 + envelope_nr;
1921 int font_width = getFontWidth(font_nr);
1922 int font_height = getFontHeight(font_nr);
1923 int max_xsize = level.envelope[envelope_nr].xsize;
1924 int max_ysize = level.envelope[envelope_nr].ysize;
1925 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
1926 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
1927 int xend = max_xsize;
1928 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
1929 int xstep = (xstart < xend ? 1 : 0);
1930 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
1933 for (x = xstart, y = ystart; x <= xend && y <= yend; x += xstep, y += ystep)
1935 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
1936 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
1937 int sx = (SXSIZE - xsize * font_width) / 2;
1938 int sy = (SYSIZE - ysize * font_height) / 2;
1941 SetDrawtoField(DRAW_BUFFERED);
1943 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
1945 SetDrawtoField(DRAW_BACKBUFFER);
1947 for (yy = 0; yy < ysize; yy++) for (xx = 0; xx < xsize; xx++)
1948 DrawEnvelopeBackground(envelope_nr, sx,sy, xx,yy, xsize, ysize, font_nr);
1951 DrawTextBuffer(SX + sx + font_width, SY + sy + font_height,
1952 level.envelope[envelope_nr].text, font_nr, max_xsize,
1953 xsize - 2, ysize - 2, mask_mode,
1954 level.envelope[envelope_nr].autowrap,
1955 level.envelope[envelope_nr].centered, FALSE);
1957 DrawTextToTextArea(SX + sx + font_width, SY + sy + font_height,
1958 level.envelope[envelope_nr].text, font_nr, max_xsize,
1959 xsize - 2, ysize - 2, mask_mode);
1962 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
1965 WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
1969 void ShowEnvelope(int envelope_nr)
1971 int element = EL_ENVELOPE_1 + envelope_nr;
1972 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1973 int sound_opening = element_info[element].sound[ACTION_OPENING];
1974 int sound_closing = element_info[element].sound[ACTION_CLOSING];
1975 boolean ffwd_delay = (tape.playing && tape.fast_forward);
1976 boolean no_delay = (tape.warp_forward);
1977 int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
1978 int wait_delay_value = (no_delay ? 0 : normal_delay_value);
1979 int anim_mode = graphic_info[graphic].anim_mode;
1980 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
1981 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
1983 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
1985 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
1987 if (anim_mode == ANIM_DEFAULT)
1988 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_OPENING);
1990 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_OPENING);
1993 Delay(wait_delay_value);
1995 WaitForEventToContinue();
1997 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
1999 if (anim_mode != ANIM_NONE)
2000 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_CLOSING);
2002 if (anim_mode == ANIM_DEFAULT)
2003 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_CLOSING);
2005 game.envelope_active = FALSE;
2007 SetDrawtoField(DRAW_BUFFERED);
2009 redraw_mask |= REDRAW_FIELD;
2013 void DrawPreviewElement(int dst_x, int dst_y, int element, int tilesize)
2017 int graphic = el2preimg(element);
2019 getSizedGraphicSource(graphic, 0, tilesize, &src_bitmap, &src_x, &src_y);
2020 BlitBitmap(src_bitmap, drawto, src_x, src_y, tilesize, tilesize, dst_x,dst_y);
2027 SetDrawBackgroundMask(REDRAW_NONE);
2030 for (x = BX1; x <= BX2; x++)
2031 for (y = BY1; y <= BY2; y++)
2032 DrawScreenField(x, y);
2034 redraw_mask |= REDRAW_FIELD;
2037 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
2041 for (x = 0; x < size_x; x++)
2042 for (y = 0; y < size_y; y++)
2043 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
2045 redraw_mask |= REDRAW_FIELD;
2048 static void DrawPreviewLevelExt(int from_x, int from_y)
2050 boolean show_level_border = (BorderElement != EL_EMPTY);
2051 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
2052 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
2053 int tile_size = preview.tile_size;
2054 int preview_width = preview.xsize * tile_size;
2055 int preview_height = preview.ysize * tile_size;
2056 int real_preview_xsize = MIN(level_xsize, preview.xsize);
2057 int real_preview_ysize = MIN(level_ysize, preview.ysize);
2058 int dst_x = SX + ALIGNED_XPOS(preview.x, preview_width, preview.align);
2059 int dst_y = SY + ALIGNED_YPOS(preview.y, preview_height, preview.valign);
2062 DrawBackground(dst_x, dst_y, preview_width, preview_height);
2064 dst_x += (preview_width - real_preview_xsize * tile_size) / 2;
2065 dst_y += (preview_height - real_preview_ysize * tile_size) / 2;
2067 for (x = 0; x < real_preview_xsize; x++)
2069 for (y = 0; y < real_preview_ysize; y++)
2071 int lx = from_x + x + (show_level_border ? -1 : 0);
2072 int ly = from_y + y + (show_level_border ? -1 : 0);
2073 int element = (IN_LEV_FIELD(lx, ly) ? level.field[lx][ly] :
2074 getBorderElement(lx, ly));
2076 DrawPreviewElement(dst_x + x * tile_size, dst_y + y * tile_size,
2077 element, tile_size);
2081 redraw_mask |= REDRAW_MICROLEVEL;
2084 #define MICROLABEL_EMPTY 0
2085 #define MICROLABEL_LEVEL_NAME 1
2086 #define MICROLABEL_LEVEL_AUTHOR_HEAD 2
2087 #define MICROLABEL_LEVEL_AUTHOR 3
2088 #define MICROLABEL_IMPORTED_FROM_HEAD 4
2089 #define MICROLABEL_IMPORTED_FROM 5
2090 #define MICROLABEL_IMPORTED_BY_HEAD 6
2091 #define MICROLABEL_IMPORTED_BY 7
2093 static int getMaxTextLength(struct TextPosInfo *pos, int font_nr)
2095 int max_text_width = SXSIZE;
2096 int font_width = getFontWidth(font_nr);
2098 if (pos->align == ALIGN_CENTER)
2099 max_text_width = (pos->x < SXSIZE / 2 ? pos->x * 2 : (SXSIZE - pos->x) * 2);
2100 else if (pos->align == ALIGN_RIGHT)
2101 max_text_width = pos->x;
2103 max_text_width = SXSIZE - pos->x;
2105 return max_text_width / font_width;
2108 static void DrawPreviewLevelLabelExt(int mode)
2110 struct TextPosInfo *pos = &menu.main.text.level_info_2;
2111 char label_text[MAX_OUTPUT_LINESIZE + 1];
2112 int max_len_label_text;
2114 int font_nr = pos->font;
2117 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
2118 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
2119 mode == MICROLABEL_IMPORTED_BY_HEAD)
2120 font_nr = pos->font_alt;
2122 int font_nr = FONT_TEXT_2;
2125 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
2126 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
2127 mode == MICROLABEL_IMPORTED_BY_HEAD)
2128 font_nr = FONT_TEXT_3;
2132 max_len_label_text = getMaxTextLength(pos, font_nr);
2134 max_len_label_text = SXSIZE / getFontWidth(font_nr);
2138 if (pos->size != -1)
2139 max_len_label_text = pos->size;
2142 for (i = 0; i < max_len_label_text; i++)
2143 label_text[i] = ' ';
2144 label_text[max_len_label_text] = '\0';
2146 if (strlen(label_text) > 0)
2149 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2151 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
2152 int lypos = MICROLABEL2_YPOS;
2154 DrawText(lxpos, lypos, label_text, font_nr);
2159 (mode == MICROLABEL_LEVEL_NAME ? level.name :
2160 mode == MICROLABEL_LEVEL_AUTHOR_HEAD ? "created by" :
2161 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
2162 mode == MICROLABEL_IMPORTED_FROM_HEAD ? "imported from" :
2163 mode == MICROLABEL_IMPORTED_FROM ? leveldir_current->imported_from :
2164 mode == MICROLABEL_IMPORTED_BY_HEAD ? "imported by" :
2165 mode == MICROLABEL_IMPORTED_BY ? leveldir_current->imported_by :""),
2166 max_len_label_text);
2167 label_text[max_len_label_text] = '\0';
2169 if (strlen(label_text) > 0)
2172 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2174 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
2175 int lypos = MICROLABEL2_YPOS;
2177 DrawText(lxpos, lypos, label_text, font_nr);
2181 redraw_mask |= REDRAW_MICROLEVEL;
2184 void DrawPreviewLevel(boolean restart)
2186 static unsigned long scroll_delay = 0;
2187 static unsigned long label_delay = 0;
2188 static int from_x, from_y, scroll_direction;
2189 static int label_state, label_counter;
2190 unsigned long scroll_delay_value = preview.step_delay;
2191 boolean show_level_border = (BorderElement != EL_EMPTY);
2192 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
2193 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
2194 int last_game_status = game_status; /* save current game status */
2197 /* force PREVIEW font on preview level */
2198 game_status = GAME_MODE_PSEUDO_PREVIEW;
2206 if (preview.anim_mode == ANIM_CENTERED)
2208 if (level_xsize > preview.xsize)
2209 from_x = (level_xsize - preview.xsize) / 2;
2210 if (level_ysize > preview.ysize)
2211 from_y = (level_ysize - preview.ysize) / 2;
2214 from_x += preview.xoffset;
2215 from_y += preview.yoffset;
2217 scroll_direction = MV_RIGHT;
2221 DrawPreviewLevelExt(from_x, from_y);
2222 DrawPreviewLevelLabelExt(label_state);
2224 /* initialize delay counters */
2225 DelayReached(&scroll_delay, 0);
2226 DelayReached(&label_delay, 0);
2228 if (leveldir_current->name)
2230 struct TextPosInfo *pos = &menu.main.text.level_info_1;
2231 char label_text[MAX_OUTPUT_LINESIZE + 1];
2233 int font_nr = pos->font;
2235 int font_nr = FONT_TEXT_1;
2238 int max_len_label_text = getMaxTextLength(pos, font_nr);
2240 int max_len_label_text = SXSIZE / getFontWidth(font_nr);
2248 if (pos->size != -1)
2249 max_len_label_text = pos->size;
2252 strncpy(label_text, leveldir_current->name, max_len_label_text);
2253 label_text[max_len_label_text] = '\0';
2256 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2258 lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
2259 lypos = SY + MICROLABEL1_YPOS;
2261 DrawText(lxpos, lypos, label_text, font_nr);
2265 game_status = last_game_status; /* restore current game status */
2270 /* scroll preview level, if needed */
2271 if (preview.anim_mode != ANIM_NONE &&
2272 (level_xsize > preview.xsize || level_ysize > preview.ysize) &&
2273 DelayReached(&scroll_delay, scroll_delay_value))
2275 switch (scroll_direction)
2280 from_x -= preview.step_offset;
2281 from_x = (from_x < 0 ? 0 : from_x);
2284 scroll_direction = MV_UP;
2288 if (from_x < level_xsize - preview.xsize)
2290 from_x += preview.step_offset;
2291 from_x = (from_x > level_xsize - preview.xsize ?
2292 level_xsize - preview.xsize : from_x);
2295 scroll_direction = MV_DOWN;
2301 from_y -= preview.step_offset;
2302 from_y = (from_y < 0 ? 0 : from_y);
2305 scroll_direction = MV_RIGHT;
2309 if (from_y < level_ysize - preview.ysize)
2311 from_y += preview.step_offset;
2312 from_y = (from_y > level_ysize - preview.ysize ?
2313 level_ysize - preview.ysize : from_y);
2316 scroll_direction = MV_LEFT;
2323 DrawPreviewLevelExt(from_x, from_y);
2326 /* !!! THIS ALL SUCKS -- SHOULD BE CLEANLY REWRITTEN !!! */
2327 /* redraw micro level label, if needed */
2328 if (!strEqual(level.name, NAMELESS_LEVEL_NAME) &&
2329 !strEqual(level.author, ANONYMOUS_NAME) &&
2330 !strEqual(level.author, leveldir_current->name) &&
2331 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
2333 int max_label_counter = 23;
2335 if (leveldir_current->imported_from != NULL &&
2336 strlen(leveldir_current->imported_from) > 0)
2337 max_label_counter += 14;
2338 if (leveldir_current->imported_by != NULL &&
2339 strlen(leveldir_current->imported_by) > 0)
2340 max_label_counter += 14;
2342 label_counter = (label_counter + 1) % max_label_counter;
2343 label_state = (label_counter >= 0 && label_counter <= 7 ?
2344 MICROLABEL_LEVEL_NAME :
2345 label_counter >= 9 && label_counter <= 12 ?
2346 MICROLABEL_LEVEL_AUTHOR_HEAD :
2347 label_counter >= 14 && label_counter <= 21 ?
2348 MICROLABEL_LEVEL_AUTHOR :
2349 label_counter >= 23 && label_counter <= 26 ?
2350 MICROLABEL_IMPORTED_FROM_HEAD :
2351 label_counter >= 28 && label_counter <= 35 ?
2352 MICROLABEL_IMPORTED_FROM :
2353 label_counter >= 37 && label_counter <= 40 ?
2354 MICROLABEL_IMPORTED_BY_HEAD :
2355 label_counter >= 42 && label_counter <= 49 ?
2356 MICROLABEL_IMPORTED_BY : MICROLABEL_EMPTY);
2358 if (leveldir_current->imported_from == NULL &&
2359 (label_state == MICROLABEL_IMPORTED_FROM_HEAD ||
2360 label_state == MICROLABEL_IMPORTED_FROM))
2361 label_state = (label_state == MICROLABEL_IMPORTED_FROM_HEAD ?
2362 MICROLABEL_IMPORTED_BY_HEAD : MICROLABEL_IMPORTED_BY);
2364 DrawPreviewLevelLabelExt(label_state);
2367 game_status = last_game_status; /* restore current game status */
2370 inline void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
2371 int graphic, int sync_frame, int mask_mode)
2373 int frame = getGraphicAnimationFrame(graphic, sync_frame);
2375 if (mask_mode == USE_MASKING)
2376 DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
2378 DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
2381 inline void DrawGraphicAnimation(int x, int y, int graphic)
2383 int lx = LEVELX(x), ly = LEVELY(y);
2385 if (!IN_SCR_FIELD(x, y))
2388 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
2389 graphic, GfxFrame[lx][ly], NO_MASKING);
2390 MarkTileDirty(x, y);
2393 void DrawLevelGraphicAnimation(int x, int y, int graphic)
2395 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
2398 void DrawLevelElementAnimation(int x, int y, int element)
2400 int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
2402 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
2405 inline void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
2407 int sx = SCREENX(x), sy = SCREENY(y);
2409 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
2412 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
2415 DrawGraphicAnimation(sx, sy, graphic);
2418 if (GFX_CRUMBLED(TILE_GFX_ELEMENT(x, y)))
2419 DrawLevelFieldCrumbledSand(x, y);
2421 if (GFX_CRUMBLED(Feld[x][y]))
2422 DrawLevelFieldCrumbledSand(x, y);
2426 void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
2428 int sx = SCREENX(x), sy = SCREENY(y);
2431 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
2434 graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
2436 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
2439 DrawGraphicAnimation(sx, sy, graphic);
2441 if (GFX_CRUMBLED(element))
2442 DrawLevelFieldCrumbledSand(x, y);
2445 static int getPlayerGraphic(struct PlayerInfo *player, int move_dir)
2447 if (player->use_murphy)
2449 /* this works only because currently only one player can be "murphy" ... */
2450 static int last_horizontal_dir = MV_LEFT;
2451 int graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir);
2453 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
2454 last_horizontal_dir = move_dir;
2456 if (graphic == IMG_SP_MURPHY) /* undefined => use special graphic */
2458 int direction = (player->is_snapping ? move_dir : last_horizontal_dir);
2460 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
2466 return el_act_dir2img(player->artwork_element, player->GfxAction,move_dir);
2469 static boolean equalGraphics(int graphic1, int graphic2)
2471 struct GraphicInfo *g1 = &graphic_info[graphic1];
2472 struct GraphicInfo *g2 = &graphic_info[graphic2];
2474 return (g1->bitmap == g2->bitmap &&
2475 g1->src_x == g2->src_x &&
2476 g1->src_y == g2->src_y &&
2477 g1->anim_frames == g2->anim_frames &&
2478 g1->anim_delay == g2->anim_delay &&
2479 g1->anim_mode == g2->anim_mode);
2482 void DrawAllPlayers()
2486 for (i = 0; i < MAX_PLAYERS; i++)
2487 if (stored_player[i].active)
2488 DrawPlayer(&stored_player[i]);
2491 void DrawPlayerField(int x, int y)
2493 if (!IS_PLAYER(x, y))
2496 DrawPlayer(PLAYERINFO(x, y));
2499 void DrawPlayer(struct PlayerInfo *player)
2501 int jx = player->jx;
2502 int jy = player->jy;
2503 int move_dir = player->MovDir;
2504 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? +1 : 0);
2505 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? +1 : 0);
2506 int last_jx = (player->is_moving ? jx - dx : jx);
2507 int last_jy = (player->is_moving ? jy - dy : jy);
2508 int next_jx = jx + dx;
2509 int next_jy = jy + dy;
2510 boolean player_is_moving = (player->MovPos ? TRUE : FALSE);
2511 boolean player_is_opaque = FALSE;
2512 int sx = SCREENX(jx), sy = SCREENY(jy);
2513 int sxx = 0, syy = 0;
2514 int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
2516 int action = ACTION_DEFAULT;
2517 int last_player_graphic = getPlayerGraphic(player, move_dir);
2518 int last_player_frame = player->Frame;
2521 /* GfxElement[][] is set to the element the player is digging or collecting;
2522 remove also for off-screen player if the player is not moving anymore */
2523 if (IN_LEV_FIELD(jx, jy) && !player_is_moving)
2524 GfxElement[jx][jy] = EL_UNDEFINED;
2526 if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
2530 if (!IN_LEV_FIELD(jx, jy))
2532 printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
2533 printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
2534 printf("DrawPlayerField(): This should never happen!\n");
2539 if (element == EL_EXPLOSION)
2542 action = (player->is_pushing ? ACTION_PUSHING :
2543 player->is_digging ? ACTION_DIGGING :
2544 player->is_collecting ? ACTION_COLLECTING :
2545 player->is_moving ? ACTION_MOVING :
2546 player->is_snapping ? ACTION_SNAPPING :
2547 player->is_dropping ? ACTION_DROPPING :
2548 player->is_waiting ? player->action_waiting : ACTION_DEFAULT);
2550 if (player->is_waiting)
2551 move_dir = player->dir_waiting;
2553 InitPlayerGfxAnimation(player, action, move_dir);
2555 /* ----------------------------------------------------------------------- */
2556 /* draw things in the field the player is leaving, if needed */
2557 /* ----------------------------------------------------------------------- */
2559 if (player->is_moving)
2561 if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
2563 DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
2565 if (last_element == EL_DYNAMITE_ACTIVE ||
2566 last_element == EL_EM_DYNAMITE_ACTIVE ||
2567 last_element == EL_SP_DISK_RED_ACTIVE)
2568 DrawDynamite(last_jx, last_jy);
2570 DrawLevelFieldThruMask(last_jx, last_jy);
2572 else if (last_element == EL_DYNAMITE_ACTIVE ||
2573 last_element == EL_EM_DYNAMITE_ACTIVE ||
2574 last_element == EL_SP_DISK_RED_ACTIVE)
2575 DrawDynamite(last_jx, last_jy);
2577 /* !!! this is not enough to prevent flickering of players which are
2578 moving next to each others without a free tile between them -- this
2579 can only be solved by drawing all players layer by layer (first the
2580 background, then the foreground etc.) !!! => TODO */
2581 else if (!IS_PLAYER(last_jx, last_jy))
2582 DrawLevelField(last_jx, last_jy);
2585 DrawLevelField(last_jx, last_jy);
2588 if (player->is_pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
2589 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
2592 if (!IN_SCR_FIELD(sx, sy))
2595 if (setup.direct_draw)
2596 SetDrawtoField(DRAW_BUFFERED);
2598 /* ----------------------------------------------------------------------- */
2599 /* draw things behind the player, if needed */
2600 /* ----------------------------------------------------------------------- */
2603 DrawLevelElement(jx, jy, Back[jx][jy]);
2604 else if (IS_ACTIVE_BOMB(element))
2605 DrawLevelElement(jx, jy, EL_EMPTY);
2608 if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
2610 int old_element = GfxElement[jx][jy];
2611 int old_graphic = el_act_dir2img(old_element, action, move_dir);
2612 int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
2614 if (GFX_CRUMBLED(old_element))
2615 DrawLevelFieldCrumbledSandDigging(jx, jy, move_dir, player->StepFrame);
2617 DrawGraphic(sx, sy, old_graphic, frame);
2619 if (graphic_info[old_graphic].anim_mode & ANIM_OPAQUE_PLAYER)
2620 player_is_opaque = TRUE;
2624 GfxElement[jx][jy] = EL_UNDEFINED;
2626 /* make sure that pushed elements are drawn with correct frame rate */
2628 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
2630 if (player->is_pushing && player->is_moving && !IS_ANIM_MODE_CE(graphic))
2631 GfxFrame[jx][jy] = player->StepFrame;
2633 if (player->is_pushing && player->is_moving)
2634 GfxFrame[jx][jy] = player->StepFrame;
2637 DrawLevelField(jx, jy);
2641 /* ----------------------------------------------------------------------- */
2642 /* draw player himself */
2643 /* ----------------------------------------------------------------------- */
2645 graphic = getPlayerGraphic(player, move_dir);
2647 /* in the case of changed player action or direction, prevent the current
2648 animation frame from being restarted for identical animations */
2649 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
2650 player->Frame = last_player_frame;
2652 frame = getGraphicAnimationFrame(graphic, player->Frame);
2656 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
2657 sxx = player->GfxPos;
2659 syy = player->GfxPos;
2662 if (!setup.soft_scrolling && ScreenMovPos)
2665 if (player_is_opaque)
2666 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
2668 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
2670 if (SHIELD_ON(player))
2672 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
2673 IMG_SHIELD_NORMAL_ACTIVE);
2674 int frame = getGraphicAnimationFrame(graphic, -1);
2676 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
2679 /* ----------------------------------------------------------------------- */
2680 /* draw things the player is pushing, if needed */
2681 /* ----------------------------------------------------------------------- */
2684 printf("::: %d, %d [%d, %d] [%d]\n",
2685 player->is_pushing, player_is_moving, player->GfxAction,
2686 player->is_moving, player_is_moving);
2690 if (player->is_pushing && player->is_moving)
2692 int px = SCREENX(jx), py = SCREENY(jy);
2693 int pxx = (TILEX - ABS(sxx)) * dx;
2694 int pyy = (TILEY - ABS(syy)) * dy;
2695 int gfx_frame = GfxFrame[jx][jy];
2701 if (!IS_MOVING(jx, jy)) /* push movement already finished */
2703 element = Feld[next_jx][next_jy];
2704 gfx_frame = GfxFrame[next_jx][next_jy];
2707 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
2710 sync_frame = (IS_ANIM_MODE_CE(graphic) ? gfx_frame : player->StepFrame);
2711 frame = getGraphicAnimationFrame(graphic, sync_frame);
2713 frame = getGraphicAnimationFrame(graphic, player->StepFrame);
2716 /* draw background element under pushed element (like the Sokoban field) */
2717 if (Back[next_jx][next_jy])
2718 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
2720 /* masked drawing is needed for EMC style (double) movement graphics */
2721 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
2725 /* ----------------------------------------------------------------------- */
2726 /* draw things in front of player (active dynamite or dynabombs) */
2727 /* ----------------------------------------------------------------------- */
2729 if (IS_ACTIVE_BOMB(element))
2731 graphic = el2img(element);
2732 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
2734 if (game.emulation == EMU_SUPAPLEX)
2735 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
2737 DrawGraphicThruMask(sx, sy, graphic, frame);
2740 if (player_is_moving && last_element == EL_EXPLOSION)
2742 int element = (GfxElement[last_jx][last_jy] != EL_UNDEFINED ?
2743 GfxElement[last_jx][last_jy] : EL_EMPTY);
2744 int graphic = el_act2img(element, ACTION_EXPLODING);
2745 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
2746 int phase = ExplodePhase[last_jx][last_jy] - 1;
2747 int frame = getGraphicAnimationFrame(graphic, phase - delay);
2750 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
2753 /* ----------------------------------------------------------------------- */
2754 /* draw elements the player is just walking/passing through/under */
2755 /* ----------------------------------------------------------------------- */
2757 if (player_is_moving)
2759 /* handle the field the player is leaving ... */
2760 if (IS_ACCESSIBLE_INSIDE(last_element))
2761 DrawLevelField(last_jx, last_jy);
2762 else if (IS_ACCESSIBLE_UNDER(last_element))
2763 DrawLevelFieldThruMask(last_jx, last_jy);
2766 /* do not redraw accessible elements if the player is just pushing them */
2767 if (!player_is_moving || !player->is_pushing)
2769 /* ... and the field the player is entering */
2770 if (IS_ACCESSIBLE_INSIDE(element))
2771 DrawLevelField(jx, jy);
2772 else if (IS_ACCESSIBLE_UNDER(element))
2773 DrawLevelFieldThruMask(jx, jy);
2776 if (setup.direct_draw)
2778 int dst_x = SX + SCREENX(MIN(jx, last_jx)) * TILEX;
2779 int dst_y = SY + SCREENY(MIN(jy, last_jy)) * TILEY;
2780 int x_size = TILEX * (1 + ABS(jx - last_jx));
2781 int y_size = TILEY * (1 + ABS(jy - last_jy));
2783 BlitBitmap(drawto_field, window,
2784 dst_x, dst_y, x_size, y_size, dst_x, dst_y);
2785 SetDrawtoField(DRAW_DIRECT);
2788 MarkTileDirty(sx, sy);
2791 /* ------------------------------------------------------------------------- */
2793 void WaitForEventToContinue()
2795 boolean still_wait = TRUE;
2797 /* simulate releasing mouse button over last gadget, if still pressed */
2799 HandleGadgets(-1, -1, 0);
2801 button_status = MB_RELEASED;
2817 case EVENT_BUTTONPRESS:
2818 case EVENT_KEYPRESS:
2822 case EVENT_KEYRELEASE:
2823 ClearPlayerAction();
2827 HandleOtherEvents(&event);
2831 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2838 /* don't eat all CPU time */
2843 #define MAX_REQUEST_LINES 13
2844 #define MAX_REQUEST_LINE_FONT1_LEN 7
2845 #define MAX_REQUEST_LINE_FONT2_LEN 10
2847 boolean Request(char *text, unsigned int req_state)
2849 int mx, my, ty, result = -1;
2850 unsigned int old_door_state;
2851 int last_game_status = game_status; /* save current game status */
2852 int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
2853 int font_nr = FONT_TEXT_2;
2854 int max_word_len = 0;
2857 for (text_ptr = text; *text_ptr; text_ptr++)
2859 max_word_len = (*text_ptr != ' ' ? max_word_len + 1 : 0);
2861 if (max_word_len > MAX_REQUEST_LINE_FONT1_LEN)
2863 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
2865 font_nr = FONT_TEXT_1;
2867 font_nr = FONT_LEVEL_NUMBER;
2874 if (game_status == GAME_MODE_PLAYING &&
2875 level.game_engine_type == GAME_ENGINE_TYPE_EM)
2876 BlitScreenToBitmap_EM(backbuffer);
2878 /* disable deactivated drawing when quick-loading level tape recording */
2879 if (tape.playing && tape.deactivate_display)
2880 TapeDeactivateDisplayOff(TRUE);
2882 SetMouseCursor(CURSOR_DEFAULT);
2884 #if defined(NETWORK_AVALIABLE)
2885 /* pause network game while waiting for request to answer */
2886 if (options.network &&
2887 game_status == GAME_MODE_PLAYING &&
2888 req_state & REQUEST_WAIT_FOR_INPUT)
2889 SendToServer_PausePlaying();
2892 old_door_state = GetDoorState();
2894 /* simulate releasing mouse button over last gadget, if still pressed */
2896 HandleGadgets(-1, -1, 0);
2900 if (old_door_state & DOOR_OPEN_1)
2902 CloseDoor(DOOR_CLOSE_1);
2904 /* save old door content */
2905 BlitBitmap(bitmap_db_door, bitmap_db_door,
2906 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
2907 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
2911 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
2914 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2916 /* clear door drawing field */
2917 DrawBackground(DX, DY, DXSIZE, DYSIZE);
2919 /* force DOOR font inside door area */
2920 game_status = GAME_MODE_PSEUDO_DOOR;
2922 /* write text for request */
2923 for (ty = 0; ty < MAX_REQUEST_LINES; ty++)
2925 char text_line[max_request_line_len + 1];
2931 for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
2934 if (!tc || tc == ' ')
2945 strncpy(text_line, text, tl);
2948 DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
2949 DY + 8 + ty * (getFontHeight(font_nr) + 2),
2950 text_line, font_nr);
2952 text += tl + (tc == ' ' ? 1 : 0);
2955 game_status = last_game_status; /* restore current game status */
2957 if (req_state & REQ_ASK)
2959 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
2960 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
2962 else if (req_state & REQ_CONFIRM)
2964 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
2966 else if (req_state & REQ_PLAYER)
2968 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
2969 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
2970 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
2971 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
2974 /* copy request gadgets to door backbuffer */
2975 BlitBitmap(drawto, bitmap_db_door,
2976 DX, DY, DXSIZE, DYSIZE,
2977 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2979 OpenDoor(DOOR_OPEN_1);
2981 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
2983 if (game_status == GAME_MODE_PLAYING)
2985 SetPanelBackground();
2986 SetDrawBackgroundMask(REDRAW_DOOR_1);
2990 SetDrawBackgroundMask(REDRAW_FIELD);
2996 if (game_status != GAME_MODE_MAIN)
2999 button_status = MB_RELEASED;
3001 request_gadget_id = -1;
3003 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3015 case EVENT_BUTTONPRESS:
3016 case EVENT_BUTTONRELEASE:
3017 case EVENT_MOTIONNOTIFY:
3019 if (event.type == EVENT_MOTIONNOTIFY)
3021 if (!PointerInWindow(window))
3022 continue; /* window and pointer are on different screens */
3027 motion_status = TRUE;
3028 mx = ((MotionEvent *) &event)->x;
3029 my = ((MotionEvent *) &event)->y;
3033 motion_status = FALSE;
3034 mx = ((ButtonEvent *) &event)->x;
3035 my = ((ButtonEvent *) &event)->y;
3036 if (event.type == EVENT_BUTTONPRESS)
3037 button_status = ((ButtonEvent *) &event)->button;
3039 button_status = MB_RELEASED;
3042 /* this sets 'request_gadget_id' */
3043 HandleGadgets(mx, my, button_status);
3045 switch (request_gadget_id)
3047 case TOOL_CTRL_ID_YES:
3050 case TOOL_CTRL_ID_NO:
3053 case TOOL_CTRL_ID_CONFIRM:
3054 result = TRUE | FALSE;
3057 case TOOL_CTRL_ID_PLAYER_1:
3060 case TOOL_CTRL_ID_PLAYER_2:
3063 case TOOL_CTRL_ID_PLAYER_3:
3066 case TOOL_CTRL_ID_PLAYER_4:
3077 case EVENT_KEYPRESS:
3078 switch (GetEventKey((KeyEvent *)&event, TRUE))
3081 if (req_state & REQ_CONFIRM)
3097 if (req_state & REQ_PLAYER)
3101 case EVENT_KEYRELEASE:
3102 ClearPlayerAction();
3106 HandleOtherEvents(&event);
3110 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
3112 int joy = AnyJoystick();
3114 if (joy & JOY_BUTTON_1)
3116 else if (joy & JOY_BUTTON_2)
3122 if (game_status == GAME_MODE_PLAYING && local_player->LevelSolved_GameEnd)
3124 HandleGameActions();
3130 if (!PendingEvent()) /* delay only if no pending events */
3141 if (!PendingEvent()) /* delay only if no pending events */
3144 /* don't eat all CPU time */
3151 if (game_status != GAME_MODE_MAIN)
3156 if (!(req_state & REQ_STAY_OPEN))
3158 CloseDoor(DOOR_CLOSE_1);
3160 if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
3161 (req_state & REQ_REOPEN))
3162 OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
3167 if (game_status == GAME_MODE_PLAYING)
3169 SetPanelBackground();
3170 SetDrawBackgroundMask(REDRAW_DOOR_1);
3174 SetDrawBackgroundMask(REDRAW_FIELD);
3177 #if defined(NETWORK_AVALIABLE)
3178 /* continue network game after request */
3179 if (options.network &&
3180 game_status == GAME_MODE_PLAYING &&
3181 req_state & REQUEST_WAIT_FOR_INPUT)
3182 SendToServer_ContinuePlaying();
3185 /* restore deactivated drawing when quick-loading level tape recording */
3186 if (tape.playing && tape.deactivate_display)
3187 TapeDeactivateDisplayOn();
3192 unsigned int OpenDoor(unsigned int door_state)
3194 if (door_state & DOOR_COPY_BACK)
3196 if (door_state & DOOR_OPEN_1)
3197 BlitBitmap(bitmap_db_door, bitmap_db_door,
3198 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
3199 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
3201 if (door_state & DOOR_OPEN_2)
3202 BlitBitmap(bitmap_db_door, bitmap_db_door,
3203 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY2, VXSIZE, VYSIZE,
3204 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
3206 door_state &= ~DOOR_COPY_BACK;
3209 return MoveDoor(door_state);
3212 unsigned int CloseDoor(unsigned int door_state)
3214 unsigned int old_door_state = GetDoorState();
3216 if (!(door_state & DOOR_NO_COPY_BACK))
3218 if (old_door_state & DOOR_OPEN_1)
3219 BlitBitmap(backbuffer, bitmap_db_door,
3220 DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
3222 if (old_door_state & DOOR_OPEN_2)
3223 BlitBitmap(backbuffer, bitmap_db_door,
3224 VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
3226 door_state &= ~DOOR_NO_COPY_BACK;
3229 return MoveDoor(door_state);
3232 unsigned int GetDoorState()
3234 return MoveDoor(DOOR_GET_STATE);
3237 unsigned int SetDoorState(unsigned int door_state)
3239 return MoveDoor(door_state | DOOR_SET_STATE);
3242 unsigned int MoveDoor(unsigned int door_state)
3244 static int door1 = DOOR_OPEN_1;
3245 static int door2 = DOOR_CLOSE_2;
3246 unsigned long door_delay = 0;
3247 unsigned long door_delay_value;
3250 if (door_1.width < 0 || door_1.width > DXSIZE)
3251 door_1.width = DXSIZE;
3252 if (door_1.height < 0 || door_1.height > DYSIZE)
3253 door_1.height = DYSIZE;
3254 if (door_2.width < 0 || door_2.width > VXSIZE)
3255 door_2.width = VXSIZE;
3256 if (door_2.height < 0 || door_2.height > VYSIZE)
3257 door_2.height = VYSIZE;
3259 if (door_state == DOOR_GET_STATE)
3260 return (door1 | door2);
3262 if (door_state & DOOR_SET_STATE)
3264 if (door_state & DOOR_ACTION_1)
3265 door1 = door_state & DOOR_ACTION_1;
3266 if (door_state & DOOR_ACTION_2)
3267 door2 = door_state & DOOR_ACTION_2;
3269 return (door1 | door2);
3272 if (!(door_state & DOOR_FORCE_REDRAW))
3274 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
3275 door_state &= ~DOOR_OPEN_1;
3276 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
3277 door_state &= ~DOOR_CLOSE_1;
3278 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
3279 door_state &= ~DOOR_OPEN_2;
3280 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
3281 door_state &= ~DOOR_CLOSE_2;
3284 door_delay_value = (door_state & DOOR_ACTION_1 ? door_1.step_delay :
3287 if (setup.quick_doors)
3289 stepsize = 20; /* must be chosen to always draw last frame */
3290 door_delay_value = 0;
3293 if (global.autoplay_leveldir)
3295 door_state |= DOOR_NO_DELAY;
3296 door_state &= ~DOOR_CLOSE_ALL;
3299 if (door_state & DOOR_ACTION)
3301 boolean handle_door_1 = (door_state & DOOR_ACTION_1);
3302 boolean handle_door_2 = (door_state & DOOR_ACTION_2);
3303 boolean door_1_done = (!handle_door_1);
3304 boolean door_2_done = (!handle_door_2);
3305 boolean door_1_vertical = (door_1.anim_mode & ANIM_VERTICAL);
3306 boolean door_2_vertical = (door_2.anim_mode & ANIM_VERTICAL);
3307 int door_size_1 = (door_1_vertical ? door_1.height : door_1.width);
3308 int door_size_2 = (door_2_vertical ? door_2.height : door_2.width);
3309 int max_door_size_1 = (door_1_vertical ? DYSIZE : DXSIZE);
3310 int max_door_size_2 = (door_2_vertical ? VYSIZE : VXSIZE);
3311 int door_size = (handle_door_1 ? door_size_1 : door_size_2);
3312 int max_door_size = (handle_door_1 ? max_door_size_1 : max_door_size_2);
3313 int door_skip = max_door_size - door_size;
3314 int end = door_size;
3315 int start = ((door_state & DOOR_NO_DELAY) ? end : 0);
3318 if (!(door_state & DOOR_NO_DELAY) && !setup.quick_doors)
3320 /* opening door sound has priority over simultaneously closing door */
3321 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
3322 PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
3323 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
3324 PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
3327 for (k = start; k <= end && !(door_1_done && door_2_done); k += stepsize)
3330 Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
3331 GC gc = bitmap->stored_clip_gc;
3333 if (door_state & DOOR_ACTION_1)
3335 int a = MIN(x * door_1.step_offset, end);
3336 int p = (door_state & DOOR_OPEN_1 ? end - a : a);
3337 int i = p + door_skip;
3339 if (door_1.anim_mode & ANIM_STATIC_PANEL)
3341 BlitBitmap(bitmap_db_door, drawto,
3342 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1,
3343 DXSIZE, DYSIZE, DX, DY);
3347 BlitBitmap(bitmap_db_door, drawto,
3348 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + p / 2,
3349 DXSIZE, DYSIZE - p / 2, DX, DY);
3351 ClearRectangle(drawto, DX, DY + DYSIZE - p / 2, DXSIZE, p / 2);
3354 if (door_1.anim_mode & ANIM_HORIZONTAL && x <= DXSIZE)
3356 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
3357 int dst1_x = DX + DXSIZE - i, dst1_y = DY;
3358 int src2_x = DXSIZE - i, src2_y = DOOR_GFX_PAGEY1;
3359 int dst2_x = DX, dst2_y = DY;
3360 int width = i, height = DYSIZE;
3362 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3363 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3366 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3367 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3370 else if (door_1.anim_mode & ANIM_VERTICAL && x <= DYSIZE)
3372 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
3373 int dst1_x = DX, dst1_y = DY + DYSIZE - i;
3374 int src2_x = 0, src2_y = DOOR_GFX_PAGEY1 + DYSIZE - i;
3375 int dst2_x = DX, dst2_y = DY;
3376 int width = DXSIZE, height = i;
3378 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3379 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3382 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3383 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3386 else if (x <= DXSIZE) /* ANIM_DEFAULT */
3388 int j = (door_1.anim_mode == ANIM_DEFAULT ? (DXSIZE - i) / 3 : 0);
3390 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
3391 BlitBitmapMasked(bitmap, drawto,
3392 DXSIZE, DOOR_GFX_PAGEY1, i, 77,
3393 DX + DXSIZE - i, DY + j);
3394 BlitBitmapMasked(bitmap, drawto,
3395 DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
3396 DX + DXSIZE - i, DY + 140 + j);
3397 SetClipOrigin(bitmap, gc, DX - DXSIZE + i,
3398 DY - (DOOR_GFX_PAGEY1 + j));
3399 BlitBitmapMasked(bitmap, drawto,
3400 DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
3402 BlitBitmapMasked(bitmap, drawto,
3403 DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
3406 BlitBitmapMasked(bitmap, drawto,
3407 DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
3409 BlitBitmapMasked(bitmap, drawto,
3410 DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
3412 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
3413 BlitBitmapMasked(bitmap, drawto,
3414 DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
3415 DX + DXSIZE - i, DY + 77 + j);
3416 BlitBitmapMasked(bitmap, drawto,
3417 DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
3418 DX + DXSIZE - i, DY + 203 + j);
3421 redraw_mask |= REDRAW_DOOR_1;
3422 door_1_done = (a == end);
3425 if (door_state & DOOR_ACTION_2)
3427 int a = MIN(x * door_2.step_offset, door_size);
3428 int p = (door_state & DOOR_OPEN_2 ? door_size - a : a);
3429 int i = p + door_skip;
3431 if (door_2.anim_mode & ANIM_STATIC_PANEL)
3433 BlitBitmap(bitmap_db_door, drawto,
3434 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2,
3435 VXSIZE, VYSIZE, VX, VY);
3437 else if (x <= VYSIZE)
3439 BlitBitmap(bitmap_db_door, drawto,
3440 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + p / 2,
3441 VXSIZE, VYSIZE - p / 2, VX, VY);
3443 ClearRectangle(drawto, VX, VY + VYSIZE - p / 2, VXSIZE, p / 2);
3446 if (door_2.anim_mode & ANIM_HORIZONTAL && x <= VXSIZE)
3448 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
3449 int dst1_x = VX + VXSIZE - i, dst1_y = VY;
3450 int src2_x = VXSIZE - i, src2_y = DOOR_GFX_PAGEY2;
3451 int dst2_x = VX, dst2_y = VY;
3452 int width = i, height = VYSIZE;
3454 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3455 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3458 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3459 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3462 else if (door_2.anim_mode & ANIM_VERTICAL && x <= VYSIZE)
3464 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
3465 int dst1_x = VX, dst1_y = VY + VYSIZE - i;
3466 int src2_x = 0, src2_y = DOOR_GFX_PAGEY2 + VYSIZE - i;
3467 int dst2_x = VX, dst2_y = VY;
3468 int width = VXSIZE, height = i;
3470 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3471 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3474 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3475 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3478 else if (x <= VXSIZE) /* ANIM_DEFAULT */
3480 int j = (door_2.anim_mode == ANIM_DEFAULT ? (VXSIZE - i) / 3 : 0);
3482 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
3483 BlitBitmapMasked(bitmap, drawto,
3484 VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
3485 VX + VXSIZE - i, VY + j);
3486 SetClipOrigin(bitmap, gc,
3487 VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
3488 BlitBitmapMasked(bitmap, drawto,
3489 VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
3492 BlitBitmapMasked(bitmap, drawto,
3493 VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
3494 i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
3495 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
3496 BlitBitmapMasked(bitmap, drawto,
3497 VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
3499 VX + VXSIZE - i, VY + VYSIZE / 2 + j);
3502 redraw_mask |= REDRAW_DOOR_2;
3503 door_2_done = (a == VXSIZE);
3506 if (!(door_state & DOOR_NO_DELAY))
3510 if (game_status == GAME_MODE_MAIN)
3513 WaitUntilDelayReached(&door_delay, door_delay_value);
3518 if (door_state & DOOR_ACTION_1)
3519 door1 = door_state & DOOR_ACTION_1;
3520 if (door_state & DOOR_ACTION_2)
3521 door2 = door_state & DOOR_ACTION_2;
3523 return (door1 | door2);
3526 void DrawSpecialEditorDoor()
3528 /* draw bigger toolbox window */
3529 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
3530 DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
3532 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
3533 EX - 6, VY - 4, EXSIZE + 12, EYSIZE - VYSIZE + 4,
3536 redraw_mask |= REDRAW_ALL;
3539 void UndrawSpecialEditorDoor()
3541 /* draw normal tape recorder window */
3542 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
3543 EX - 6, EY - 12, EXSIZE + 12, EYSIZE - VYSIZE + 12,
3546 redraw_mask |= REDRAW_ALL;
3550 /* ---------- new tool button stuff ---------------------------------------- */
3552 /* graphic position values for tool buttons */
3553 #define TOOL_BUTTON_YES_XPOS 2
3554 #define TOOL_BUTTON_YES_YPOS 250
3555 #define TOOL_BUTTON_YES_GFX_YPOS 0
3556 #define TOOL_BUTTON_YES_XSIZE 46
3557 #define TOOL_BUTTON_YES_YSIZE 28
3558 #define TOOL_BUTTON_NO_XPOS 52
3559 #define TOOL_BUTTON_NO_YPOS TOOL_BUTTON_YES_YPOS
3560 #define TOOL_BUTTON_NO_GFX_YPOS TOOL_BUTTON_YES_GFX_YPOS
3561 #define TOOL_BUTTON_NO_XSIZE TOOL_BUTTON_YES_XSIZE
3562 #define TOOL_BUTTON_NO_YSIZE TOOL_BUTTON_YES_YSIZE
3563 #define TOOL_BUTTON_CONFIRM_XPOS TOOL_BUTTON_YES_XPOS
3564 #define TOOL_BUTTON_CONFIRM_YPOS TOOL_BUTTON_YES_YPOS
3565 #define TOOL_BUTTON_CONFIRM_GFX_YPOS 30
3566 #define TOOL_BUTTON_CONFIRM_XSIZE 96
3567 #define TOOL_BUTTON_CONFIRM_YSIZE TOOL_BUTTON_YES_YSIZE
3568 #define TOOL_BUTTON_PLAYER_XSIZE 30
3569 #define TOOL_BUTTON_PLAYER_YSIZE 30
3570 #define TOOL_BUTTON_PLAYER_GFX_XPOS 5
3571 #define TOOL_BUTTON_PLAYER_GFX_YPOS 185
3572 #define TOOL_BUTTON_PLAYER_XPOS (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
3573 #define TOOL_BUTTON_PLAYER_YPOS (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
3574 #define TOOL_BUTTON_PLAYER1_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3575 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
3576 #define TOOL_BUTTON_PLAYER2_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3577 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
3578 #define TOOL_BUTTON_PLAYER3_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3579 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
3580 #define TOOL_BUTTON_PLAYER4_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3581 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
3582 #define TOOL_BUTTON_PLAYER1_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3583 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
3584 #define TOOL_BUTTON_PLAYER2_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3585 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
3586 #define TOOL_BUTTON_PLAYER3_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3587 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
3588 #define TOOL_BUTTON_PLAYER4_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3589 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
3598 } toolbutton_info[NUM_TOOL_BUTTONS] =
3601 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_GFX_YPOS,
3602 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_YPOS,
3603 TOOL_BUTTON_YES_XSIZE, TOOL_BUTTON_YES_YSIZE,
3608 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_GFX_YPOS,
3609 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_YPOS,
3610 TOOL_BUTTON_NO_XSIZE, TOOL_BUTTON_NO_YSIZE,
3615 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_GFX_YPOS,
3616 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_YPOS,
3617 TOOL_BUTTON_CONFIRM_XSIZE, TOOL_BUTTON_CONFIRM_YSIZE,
3618 TOOL_CTRL_ID_CONFIRM,
3622 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3623 TOOL_BUTTON_PLAYER1_XPOS, TOOL_BUTTON_PLAYER1_YPOS,
3624 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3625 TOOL_CTRL_ID_PLAYER_1,
3629 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3630 TOOL_BUTTON_PLAYER2_XPOS, TOOL_BUTTON_PLAYER2_YPOS,
3631 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3632 TOOL_CTRL_ID_PLAYER_2,
3636 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3637 TOOL_BUTTON_PLAYER3_XPOS, TOOL_BUTTON_PLAYER3_YPOS,
3638 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3639 TOOL_CTRL_ID_PLAYER_3,
3643 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3644 TOOL_BUTTON_PLAYER4_XPOS, TOOL_BUTTON_PLAYER4_YPOS,
3645 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3646 TOOL_CTRL_ID_PLAYER_4,
3651 void CreateToolButtons()
3655 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3657 Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
3658 Bitmap *deco_bitmap = None;
3659 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
3660 struct GadgetInfo *gi;
3661 unsigned long event_mask;
3662 int gd_xoffset, gd_yoffset;
3663 int gd_x1, gd_x2, gd_y;
3666 event_mask = GD_EVENT_RELEASED;
3668 gd_xoffset = toolbutton_info[i].xpos;
3669 gd_yoffset = toolbutton_info[i].ypos;
3670 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
3671 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
3672 gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
3674 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
3676 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
3678 getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr),
3679 &deco_bitmap, &deco_x, &deco_y);
3680 deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
3681 deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
3684 gi = CreateGadget(GDI_CUSTOM_ID, id,
3685 GDI_INFO_TEXT, toolbutton_info[i].infotext,
3686 GDI_X, DX + toolbutton_info[i].x,
3687 GDI_Y, DY + toolbutton_info[i].y,
3688 GDI_WIDTH, toolbutton_info[i].width,
3689 GDI_HEIGHT, toolbutton_info[i].height,
3690 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
3691 GDI_STATE, GD_BUTTON_UNPRESSED,
3692 GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
3693 GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
3694 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
3695 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
3696 GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
3697 GDI_DECORATION_SHIFTING, 1, 1,
3698 GDI_DIRECT_DRAW, FALSE,
3699 GDI_EVENT_MASK, event_mask,
3700 GDI_CALLBACK_ACTION, HandleToolButtons,
3704 Error(ERR_EXIT, "cannot create gadget");
3706 tool_gadget[id] = gi;
3710 void FreeToolButtons()
3714 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3715 FreeGadget(tool_gadget[i]);
3718 static void UnmapToolButtons()
3722 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3723 UnmapGadget(tool_gadget[i]);
3726 static void HandleToolButtons(struct GadgetInfo *gi)
3728 request_gadget_id = gi->custom_id;
3731 static struct Mapping_EM_to_RND_object
3734 boolean is_rnd_to_em_mapping; /* unique mapping EM <-> RND */
3735 boolean is_backside; /* backside of moving element */
3741 em_object_mapping_list[] =
3744 Xblank, TRUE, FALSE,
3748 Yacid_splash_eB, FALSE, FALSE,
3749 EL_ACID_SPLASH_RIGHT, -1, -1
3752 Yacid_splash_wB, FALSE, FALSE,
3753 EL_ACID_SPLASH_LEFT, -1, -1
3756 #ifdef EM_ENGINE_BAD_ROLL
3758 Xstone_force_e, FALSE, FALSE,
3759 EL_ROCK, -1, MV_BIT_RIGHT
3762 Xstone_force_w, FALSE, FALSE,
3763 EL_ROCK, -1, MV_BIT_LEFT
3766 Xnut_force_e, FALSE, FALSE,
3767 EL_NUT, -1, MV_BIT_RIGHT
3770 Xnut_force_w, FALSE, FALSE,
3771 EL_NUT, -1, MV_BIT_LEFT
3774 Xspring_force_e, FALSE, FALSE,
3775 EL_SPRING, -1, MV_BIT_RIGHT
3778 Xspring_force_w, FALSE, FALSE,
3779 EL_SPRING, -1, MV_BIT_LEFT
3782 Xemerald_force_e, FALSE, FALSE,
3783 EL_EMERALD, -1, MV_BIT_RIGHT
3786 Xemerald_force_w, FALSE, FALSE,
3787 EL_EMERALD, -1, MV_BIT_LEFT
3790 Xdiamond_force_e, FALSE, FALSE,
3791 EL_DIAMOND, -1, MV_BIT_RIGHT
3794 Xdiamond_force_w, FALSE, FALSE,
3795 EL_DIAMOND, -1, MV_BIT_LEFT
3798 Xbomb_force_e, FALSE, FALSE,
3799 EL_BOMB, -1, MV_BIT_RIGHT
3802 Xbomb_force_w, FALSE, FALSE,
3803 EL_BOMB, -1, MV_BIT_LEFT
3805 #endif /* EM_ENGINE_BAD_ROLL */
3808 Xstone, TRUE, FALSE,
3812 Xstone_pause, FALSE, FALSE,
3816 Xstone_fall, FALSE, FALSE,
3820 Ystone_s, FALSE, FALSE,
3821 EL_ROCK, ACTION_FALLING, -1
3824 Ystone_sB, FALSE, TRUE,
3825 EL_ROCK, ACTION_FALLING, -1
3828 Ystone_e, FALSE, FALSE,
3829 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
3832 Ystone_eB, FALSE, TRUE,
3833 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
3836 Ystone_w, FALSE, FALSE,
3837 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
3840 Ystone_wB, FALSE, TRUE,
3841 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
3848 Xnut_pause, FALSE, FALSE,
3852 Xnut_fall, FALSE, FALSE,
3856 Ynut_s, FALSE, FALSE,
3857 EL_NUT, ACTION_FALLING, -1
3860 Ynut_sB, FALSE, TRUE,
3861 EL_NUT, ACTION_FALLING, -1
3864 Ynut_e, FALSE, FALSE,
3865 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
3868 Ynut_eB, FALSE, TRUE,
3869 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
3872 Ynut_w, FALSE, FALSE,
3873 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
3876 Ynut_wB, FALSE, TRUE,
3877 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
3880 Xbug_n, TRUE, FALSE,
3884 Xbug_e, TRUE, FALSE,
3885 EL_BUG_RIGHT, -1, -1
3888 Xbug_s, TRUE, FALSE,
3892 Xbug_w, TRUE, FALSE,
3896 Xbug_gon, FALSE, FALSE,
3900 Xbug_goe, FALSE, FALSE,
3901 EL_BUG_RIGHT, -1, -1
3904 Xbug_gos, FALSE, FALSE,
3908 Xbug_gow, FALSE, FALSE,
3912 Ybug_n, FALSE, FALSE,
3913 EL_BUG, ACTION_MOVING, MV_BIT_UP
3916 Ybug_nB, FALSE, TRUE,
3917 EL_BUG, ACTION_MOVING, MV_BIT_UP
3920 Ybug_e, FALSE, FALSE,
3921 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
3924 Ybug_eB, FALSE, TRUE,
3925 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
3928 Ybug_s, FALSE, FALSE,
3929 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
3932 Ybug_sB, FALSE, TRUE,
3933 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
3936 Ybug_w, FALSE, FALSE,
3937 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
3940 Ybug_wB, FALSE, TRUE,
3941 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
3944 Ybug_w_n, FALSE, FALSE,
3945 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
3948 Ybug_n_e, FALSE, FALSE,
3949 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
3952 Ybug_e_s, FALSE, FALSE,
3953 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
3956 Ybug_s_w, FALSE, FALSE,
3957 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
3960 Ybug_e_n, FALSE, FALSE,
3961 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
3964 Ybug_s_e, FALSE, FALSE,
3965 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
3968 Ybug_w_s, FALSE, FALSE,
3969 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
3972 Ybug_n_w, FALSE, FALSE,
3973 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
3976 Ybug_stone, FALSE, FALSE,
3977 EL_BUG, ACTION_SMASHED_BY_ROCK, -1
3980 Ybug_spring, FALSE, FALSE,
3981 EL_BUG, ACTION_SMASHED_BY_SPRING, -1
3984 Xtank_n, TRUE, FALSE,
3985 EL_SPACESHIP_UP, -1, -1
3988 Xtank_e, TRUE, FALSE,
3989 EL_SPACESHIP_RIGHT, -1, -1
3992 Xtank_s, TRUE, FALSE,
3993 EL_SPACESHIP_DOWN, -1, -1
3996 Xtank_w, TRUE, FALSE,
3997 EL_SPACESHIP_LEFT, -1, -1
4000 Xtank_gon, FALSE, FALSE,
4001 EL_SPACESHIP_UP, -1, -1
4004 Xtank_goe, FALSE, FALSE,
4005 EL_SPACESHIP_RIGHT, -1, -1
4008 Xtank_gos, FALSE, FALSE,
4009 EL_SPACESHIP_DOWN, -1, -1
4012 Xtank_gow, FALSE, FALSE,
4013 EL_SPACESHIP_LEFT, -1, -1
4016 Ytank_n, FALSE, FALSE,
4017 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
4020 Ytank_nB, FALSE, TRUE,
4021 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
4024 Ytank_e, FALSE, FALSE,
4025 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
4028 Ytank_eB, FALSE, TRUE,
4029 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
4032 Ytank_s, FALSE, FALSE,
4033 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
4036 Ytank_sB, FALSE, TRUE,
4037 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
4040 Ytank_w, FALSE, FALSE,
4041 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
4044 Ytank_wB, FALSE, TRUE,
4045 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
4048 Ytank_w_n, FALSE, FALSE,
4049 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
4052 Ytank_n_e, FALSE, FALSE,
4053 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
4056 Ytank_e_s, FALSE, FALSE,
4057 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
4060 Ytank_s_w, FALSE, FALSE,
4061 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
4064 Ytank_e_n, FALSE, FALSE,
4065 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
4068 Ytank_s_e, FALSE, FALSE,
4069 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
4072 Ytank_w_s, FALSE, FALSE,
4073 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
4076 Ytank_n_w, FALSE, FALSE,
4077 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
4080 Ytank_stone, FALSE, FALSE,
4081 EL_SPACESHIP, ACTION_SMASHED_BY_ROCK, -1
4084 Ytank_spring, FALSE, FALSE,
4085 EL_SPACESHIP, ACTION_SMASHED_BY_SPRING, -1
4088 Xandroid, TRUE, FALSE,
4089 EL_EMC_ANDROID, ACTION_ACTIVE, -1
4092 Xandroid_1_n, FALSE, FALSE,
4093 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
4096 Xandroid_2_n, FALSE, FALSE,
4097 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
4100 Xandroid_1_e, FALSE, FALSE,
4101 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
4104 Xandroid_2_e, FALSE, FALSE,
4105 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
4108 Xandroid_1_w, FALSE, FALSE,
4109 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
4112 Xandroid_2_w, FALSE, FALSE,
4113 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
4116 Xandroid_1_s, FALSE, FALSE,
4117 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
4120 Xandroid_2_s, FALSE, FALSE,
4121 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
4124 Yandroid_n, FALSE, FALSE,
4125 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
4128 Yandroid_nB, FALSE, TRUE,
4129 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
4132 Yandroid_ne, FALSE, FALSE,
4133 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPRIGHT
4136 Yandroid_neB, FALSE, TRUE,
4137 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPRIGHT
4140 Yandroid_e, FALSE, FALSE,
4141 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
4144 Yandroid_eB, FALSE, TRUE,
4145 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
4148 Yandroid_se, FALSE, FALSE,
4149 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNRIGHT
4152 Yandroid_seB, FALSE, TRUE,
4153 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNRIGHT
4156 Yandroid_s, FALSE, FALSE,
4157 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
4160 Yandroid_sB, FALSE, TRUE,
4161 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
4164 Yandroid_sw, FALSE, FALSE,
4165 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNLEFT
4168 Yandroid_swB, FALSE, TRUE,
4169 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNLEFT
4172 Yandroid_w, FALSE, FALSE,
4173 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
4176 Yandroid_wB, FALSE, TRUE,
4177 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
4180 Yandroid_nw, FALSE, FALSE,
4181 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPLEFT
4184 Yandroid_nwB, FALSE, TRUE,
4185 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPLEFT
4188 Xspring, TRUE, FALSE,
4192 Xspring_pause, FALSE, FALSE,
4196 Xspring_e, FALSE, FALSE,
4200 Xspring_w, FALSE, FALSE,
4204 Xspring_fall, FALSE, FALSE,
4208 Yspring_s, FALSE, FALSE,
4209 EL_SPRING, ACTION_FALLING, -1
4212 Yspring_sB, FALSE, TRUE,
4213 EL_SPRING, ACTION_FALLING, -1
4216 Yspring_e, FALSE, FALSE,
4217 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
4220 Yspring_eB, FALSE, TRUE,
4221 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
4224 Yspring_w, FALSE, FALSE,
4225 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
4228 Yspring_wB, FALSE, TRUE,
4229 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
4232 Yspring_kill_e, FALSE, FALSE,
4233 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
4236 Yspring_kill_eB, FALSE, TRUE,
4237 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
4240 Yspring_kill_w, FALSE, FALSE,
4241 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
4244 Yspring_kill_wB, FALSE, TRUE,
4245 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
4248 Xeater_n, TRUE, FALSE,
4249 EL_YAMYAM_UP, -1, -1
4252 Xeater_e, TRUE, FALSE,
4253 EL_YAMYAM_RIGHT, -1, -1
4256 Xeater_w, TRUE, FALSE,
4257 EL_YAMYAM_LEFT, -1, -1
4260 Xeater_s, TRUE, FALSE,
4261 EL_YAMYAM_DOWN, -1, -1
4264 Yeater_n, FALSE, FALSE,
4265 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
4268 Yeater_nB, FALSE, TRUE,
4269 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
4272 Yeater_e, FALSE, FALSE,
4273 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
4276 Yeater_eB, FALSE, TRUE,
4277 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
4280 Yeater_s, FALSE, FALSE,
4281 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
4284 Yeater_sB, FALSE, TRUE,
4285 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
4288 Yeater_w, FALSE, FALSE,
4289 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
4292 Yeater_wB, FALSE, TRUE,
4293 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
4296 Yeater_stone, FALSE, FALSE,
4297 EL_YAMYAM, ACTION_SMASHED_BY_ROCK, -1
4300 Yeater_spring, FALSE, FALSE,
4301 EL_YAMYAM, ACTION_SMASHED_BY_SPRING, -1
4304 Xalien, TRUE, FALSE,
4308 Xalien_pause, FALSE, FALSE,
4312 Yalien_n, FALSE, FALSE,
4313 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
4316 Yalien_nB, FALSE, TRUE,
4317 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
4320 Yalien_e, FALSE, FALSE,
4321 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
4324 Yalien_eB, FALSE, TRUE,
4325 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
4328 Yalien_s, FALSE, FALSE,
4329 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
4332 Yalien_sB, FALSE, TRUE,
4333 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
4336 Yalien_w, FALSE, FALSE,
4337 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
4340 Yalien_wB, FALSE, TRUE,
4341 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
4344 Yalien_stone, FALSE, FALSE,
4345 EL_ROBOT, ACTION_SMASHED_BY_ROCK, -1
4348 Yalien_spring, FALSE, FALSE,
4349 EL_ROBOT, ACTION_SMASHED_BY_SPRING, -1
4352 Xemerald, TRUE, FALSE,
4356 Xemerald_pause, FALSE, FALSE,
4360 Xemerald_fall, FALSE, FALSE,
4364 Xemerald_shine, FALSE, FALSE,
4365 EL_EMERALD, ACTION_TWINKLING, -1
4368 Yemerald_s, FALSE, FALSE,
4369 EL_EMERALD, ACTION_FALLING, -1
4372 Yemerald_sB, FALSE, TRUE,
4373 EL_EMERALD, ACTION_FALLING, -1
4376 Yemerald_e, FALSE, FALSE,
4377 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
4380 Yemerald_eB, FALSE, TRUE,
4381 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
4384 Yemerald_w, FALSE, FALSE,
4385 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
4388 Yemerald_wB, FALSE, TRUE,
4389 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
4392 Yemerald_eat, FALSE, FALSE,
4393 EL_EMERALD, ACTION_COLLECTING, -1
4396 Yemerald_stone, FALSE, FALSE,
4397 EL_NUT, ACTION_BREAKING, -1
4400 Xdiamond, TRUE, FALSE,
4404 Xdiamond_pause, FALSE, FALSE,
4408 Xdiamond_fall, FALSE, FALSE,
4412 Xdiamond_shine, FALSE, FALSE,
4413 EL_DIAMOND, ACTION_TWINKLING, -1
4416 Ydiamond_s, FALSE, FALSE,
4417 EL_DIAMOND, ACTION_FALLING, -1
4420 Ydiamond_sB, FALSE, TRUE,
4421 EL_DIAMOND, ACTION_FALLING, -1
4424 Ydiamond_e, FALSE, FALSE,
4425 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
4428 Ydiamond_eB, FALSE, TRUE,
4429 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
4432 Ydiamond_w, FALSE, FALSE,
4433 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
4436 Ydiamond_wB, FALSE, TRUE,
4437 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
4440 Ydiamond_eat, FALSE, FALSE,
4441 EL_DIAMOND, ACTION_COLLECTING, -1
4444 Ydiamond_stone, FALSE, FALSE,
4445 EL_DIAMOND, ACTION_SMASHED_BY_ROCK, -1
4448 Xdrip_fall, TRUE, FALSE,
4449 EL_AMOEBA_DROP, -1, -1
4452 Xdrip_stretch, FALSE, FALSE,
4453 EL_AMOEBA_DROP, ACTION_FALLING, -1
4456 Xdrip_stretchB, FALSE, TRUE,
4457 EL_AMOEBA_DROP, ACTION_FALLING, -1
4460 Xdrip_eat, FALSE, FALSE,
4461 EL_AMOEBA_DROP, ACTION_GROWING, -1
4464 Ydrip_s1, FALSE, FALSE,
4465 EL_AMOEBA_DROP, ACTION_FALLING, -1
4468 Ydrip_s1B, FALSE, TRUE,
4469 EL_AMOEBA_DROP, ACTION_FALLING, -1
4472 Ydrip_s2, FALSE, FALSE,
4473 EL_AMOEBA_DROP, ACTION_FALLING, -1
4476 Ydrip_s2B, FALSE, TRUE,
4477 EL_AMOEBA_DROP, ACTION_FALLING, -1
4484 Xbomb_pause, FALSE, FALSE,
4488 Xbomb_fall, FALSE, FALSE,
4492 Ybomb_s, FALSE, FALSE,
4493 EL_BOMB, ACTION_FALLING, -1
4496 Ybomb_sB, FALSE, TRUE,
4497 EL_BOMB, ACTION_FALLING, -1
4500 Ybomb_e, FALSE, FALSE,
4501 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
4504 Ybomb_eB, FALSE, TRUE,
4505 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
4508 Ybomb_w, FALSE, FALSE,
4509 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
4512 Ybomb_wB, FALSE, TRUE,
4513 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
4516 Ybomb_eat, FALSE, FALSE,
4517 EL_BOMB, ACTION_ACTIVATING, -1
4520 Xballoon, TRUE, FALSE,
4524 Yballoon_n, FALSE, FALSE,
4525 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
4528 Yballoon_nB, FALSE, TRUE,
4529 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
4532 Yballoon_e, FALSE, FALSE,
4533 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
4536 Yballoon_eB, FALSE, TRUE,
4537 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
4540 Yballoon_s, FALSE, FALSE,
4541 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
4544 Yballoon_sB, FALSE, TRUE,
4545 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
4548 Yballoon_w, FALSE, FALSE,
4549 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
4552 Yballoon_wB, FALSE, TRUE,
4553 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
4556 Xgrass, TRUE, FALSE,
4557 EL_EMC_GRASS, -1, -1
4560 Ygrass_nB, FALSE, FALSE,
4561 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_UP
4564 Ygrass_eB, FALSE, FALSE,
4565 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_RIGHT
4568 Ygrass_sB, FALSE, FALSE,
4569 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_DOWN
4572 Ygrass_wB, FALSE, FALSE,
4573 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_LEFT
4580 Ydirt_nB, FALSE, FALSE,
4581 EL_SAND, ACTION_DIGGING, MV_BIT_UP
4584 Ydirt_eB, FALSE, FALSE,
4585 EL_SAND, ACTION_DIGGING, MV_BIT_RIGHT
4588 Ydirt_sB, FALSE, FALSE,
4589 EL_SAND, ACTION_DIGGING, MV_BIT_DOWN
4592 Ydirt_wB, FALSE, FALSE,
4593 EL_SAND, ACTION_DIGGING, MV_BIT_LEFT
4596 Xacid_ne, TRUE, FALSE,
4597 EL_ACID_POOL_TOPRIGHT, -1, -1
4600 Xacid_se, TRUE, FALSE,
4601 EL_ACID_POOL_BOTTOMRIGHT, -1, -1
4604 Xacid_s, TRUE, FALSE,
4605 EL_ACID_POOL_BOTTOM, -1, -1
4608 Xacid_sw, TRUE, FALSE,
4609 EL_ACID_POOL_BOTTOMLEFT, -1, -1
4612 Xacid_nw, TRUE, FALSE,
4613 EL_ACID_POOL_TOPLEFT, -1, -1
4616 Xacid_1, TRUE, FALSE,
4620 Xacid_2, FALSE, FALSE,
4624 Xacid_3, FALSE, FALSE,
4628 Xacid_4, FALSE, FALSE,
4632 Xacid_5, FALSE, FALSE,
4636 Xacid_6, FALSE, FALSE,
4640 Xacid_7, FALSE, FALSE,
4644 Xacid_8, FALSE, FALSE,
4648 Xball_1, TRUE, FALSE,
4649 EL_EMC_MAGIC_BALL, -1, -1
4652 Xball_1B, FALSE, FALSE,
4653 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4656 Xball_2, FALSE, FALSE,
4657 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4660 Xball_2B, FALSE, FALSE,
4661 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4664 Yball_eat, FALSE, FALSE,
4665 EL_EMC_MAGIC_BALL, ACTION_DROPPING, -1
4668 Ykey_1_eat, FALSE, FALSE,
4669 EL_EM_KEY_1, ACTION_COLLECTING, -1
4672 Ykey_2_eat, FALSE, FALSE,
4673 EL_EM_KEY_2, ACTION_COLLECTING, -1
4676 Ykey_3_eat, FALSE, FALSE,
4677 EL_EM_KEY_3, ACTION_COLLECTING, -1
4680 Ykey_4_eat, FALSE, FALSE,
4681 EL_EM_KEY_4, ACTION_COLLECTING, -1
4684 Ykey_5_eat, FALSE, FALSE,
4685 EL_EMC_KEY_5, ACTION_COLLECTING, -1
4688 Ykey_6_eat, FALSE, FALSE,
4689 EL_EMC_KEY_6, ACTION_COLLECTING, -1
4692 Ykey_7_eat, FALSE, FALSE,
4693 EL_EMC_KEY_7, ACTION_COLLECTING, -1
4696 Ykey_8_eat, FALSE, FALSE,
4697 EL_EMC_KEY_8, ACTION_COLLECTING, -1
4700 Ylenses_eat, FALSE, FALSE,
4701 EL_EMC_LENSES, ACTION_COLLECTING, -1
4704 Ymagnify_eat, FALSE, FALSE,
4705 EL_EMC_MAGNIFIER, ACTION_COLLECTING, -1
4708 Ygrass_eat, FALSE, FALSE,
4709 EL_EMC_GRASS, ACTION_SNAPPING, -1
4712 Ydirt_eat, FALSE, FALSE,
4713 EL_SAND, ACTION_SNAPPING, -1
4716 Xgrow_ns, TRUE, FALSE,
4717 EL_EXPANDABLE_WALL_VERTICAL, -1, -1
4720 Ygrow_ns_eat, FALSE, FALSE,
4721 EL_EXPANDABLE_WALL_VERTICAL, ACTION_GROWING, -1
4724 Xgrow_ew, TRUE, FALSE,
4725 EL_EXPANDABLE_WALL_HORIZONTAL, -1, -1
4728 Ygrow_ew_eat, FALSE, FALSE,
4729 EL_EXPANDABLE_WALL_HORIZONTAL, ACTION_GROWING, -1
4732 Xwonderwall, TRUE, FALSE,
4733 EL_MAGIC_WALL, -1, -1
4736 XwonderwallB, FALSE, FALSE,
4737 EL_MAGIC_WALL, ACTION_ACTIVE, -1
4740 Xamoeba_1, TRUE, FALSE,
4741 EL_AMOEBA_DRY, ACTION_OTHER, -1
4744 Xamoeba_2, FALSE, FALSE,
4745 EL_AMOEBA_DRY, ACTION_OTHER, -1
4748 Xamoeba_3, FALSE, FALSE,
4749 EL_AMOEBA_DRY, ACTION_OTHER, -1
4752 Xamoeba_4, FALSE, FALSE,
4753 EL_AMOEBA_DRY, ACTION_OTHER, -1
4756 Xamoeba_5, TRUE, FALSE,
4757 EL_AMOEBA_WET, ACTION_OTHER, -1
4760 Xamoeba_6, FALSE, FALSE,
4761 EL_AMOEBA_WET, ACTION_OTHER, -1
4764 Xamoeba_7, FALSE, FALSE,
4765 EL_AMOEBA_WET, ACTION_OTHER, -1
4768 Xamoeba_8, FALSE, FALSE,
4769 EL_AMOEBA_WET, ACTION_OTHER, -1
4772 Xdoor_1, TRUE, FALSE,
4773 EL_EM_GATE_1, -1, -1
4776 Xdoor_2, TRUE, FALSE,
4777 EL_EM_GATE_2, -1, -1
4780 Xdoor_3, TRUE, FALSE,
4781 EL_EM_GATE_3, -1, -1
4784 Xdoor_4, TRUE, FALSE,
4785 EL_EM_GATE_4, -1, -1
4788 Xdoor_5, TRUE, FALSE,
4789 EL_EMC_GATE_5, -1, -1
4792 Xdoor_6, TRUE, FALSE,
4793 EL_EMC_GATE_6, -1, -1
4796 Xdoor_7, TRUE, FALSE,
4797 EL_EMC_GATE_7, -1, -1
4800 Xdoor_8, TRUE, FALSE,
4801 EL_EMC_GATE_8, -1, -1
4804 Xkey_1, TRUE, FALSE,
4808 Xkey_2, TRUE, FALSE,
4812 Xkey_3, TRUE, FALSE,
4816 Xkey_4, TRUE, FALSE,
4820 Xkey_5, TRUE, FALSE,
4821 EL_EMC_KEY_5, -1, -1
4824 Xkey_6, TRUE, FALSE,
4825 EL_EMC_KEY_6, -1, -1
4828 Xkey_7, TRUE, FALSE,
4829 EL_EMC_KEY_7, -1, -1
4832 Xkey_8, TRUE, FALSE,
4833 EL_EMC_KEY_8, -1, -1
4836 Xwind_n, TRUE, FALSE,
4837 EL_BALLOON_SWITCH_UP, -1, -1
4840 Xwind_e, TRUE, FALSE,
4841 EL_BALLOON_SWITCH_RIGHT, -1, -1
4844 Xwind_s, TRUE, FALSE,
4845 EL_BALLOON_SWITCH_DOWN, -1, -1
4848 Xwind_w, TRUE, FALSE,
4849 EL_BALLOON_SWITCH_LEFT, -1, -1
4852 Xwind_nesw, TRUE, FALSE,
4853 EL_BALLOON_SWITCH_ANY, -1, -1
4856 Xwind_stop, TRUE, FALSE,
4857 EL_BALLOON_SWITCH_NONE, -1, -1
4861 EL_EM_EXIT_CLOSED, -1, -1
4864 Xexit_1, TRUE, FALSE,
4865 EL_EM_EXIT_OPEN, -1, -1
4868 Xexit_2, FALSE, FALSE,
4869 EL_EM_EXIT_OPEN, -1, -1
4872 Xexit_3, FALSE, FALSE,
4873 EL_EM_EXIT_OPEN, -1, -1
4876 Xdynamite, TRUE, FALSE,
4877 EL_EM_DYNAMITE, -1, -1
4880 Ydynamite_eat, FALSE, FALSE,
4881 EL_EM_DYNAMITE, ACTION_COLLECTING, -1
4884 Xdynamite_1, TRUE, FALSE,
4885 EL_EM_DYNAMITE_ACTIVE, -1, -1
4888 Xdynamite_2, FALSE, FALSE,
4889 EL_EM_DYNAMITE_ACTIVE, -1, -1
4892 Xdynamite_3, FALSE, FALSE,
4893 EL_EM_DYNAMITE_ACTIVE, -1, -1
4896 Xdynamite_4, FALSE, FALSE,
4897 EL_EM_DYNAMITE_ACTIVE, -1, -1
4900 Xbumper, TRUE, FALSE,
4901 EL_EMC_SPRING_BUMPER, -1, -1
4904 XbumperB, FALSE, FALSE,
4905 EL_EMC_SPRING_BUMPER, ACTION_ACTIVE, -1
4908 Xwheel, TRUE, FALSE,
4909 EL_ROBOT_WHEEL, -1, -1
4912 XwheelB, FALSE, FALSE,
4913 EL_ROBOT_WHEEL, ACTION_ACTIVE, -1
4916 Xswitch, TRUE, FALSE,
4917 EL_EMC_MAGIC_BALL_SWITCH, -1, -1
4920 XswitchB, FALSE, FALSE,
4921 EL_EMC_MAGIC_BALL_SWITCH, ACTION_ACTIVE, -1
4925 EL_QUICKSAND_EMPTY, -1, -1
4928 Xsand_stone, TRUE, FALSE,
4929 EL_QUICKSAND_FULL, -1, -1
4932 Xsand_stonein_1, FALSE, TRUE,
4933 EL_ROCK, ACTION_FILLING, -1
4936 Xsand_stonein_2, FALSE, TRUE,
4937 EL_ROCK, ACTION_FILLING, -1
4940 Xsand_stonein_3, FALSE, TRUE,
4941 EL_ROCK, ACTION_FILLING, -1
4944 Xsand_stonein_4, FALSE, TRUE,
4945 EL_ROCK, ACTION_FILLING, -1
4948 Xsand_stonesand_1, FALSE, FALSE,
4949 EL_QUICKSAND_FULL, -1, -1
4952 Xsand_stonesand_2, FALSE, FALSE,
4953 EL_QUICKSAND_FULL, -1, -1
4956 Xsand_stonesand_3, FALSE, FALSE,
4957 EL_QUICKSAND_FULL, -1, -1
4960 Xsand_stonesand_4, FALSE, FALSE,
4961 EL_QUICKSAND_FULL, -1, -1
4964 Xsand_stoneout_1, FALSE, FALSE,
4965 EL_ROCK, ACTION_EMPTYING, -1
4968 Xsand_stoneout_2, FALSE, FALSE,
4969 EL_ROCK, ACTION_EMPTYING, -1
4972 Xsand_sandstone_1, FALSE, FALSE,
4973 EL_QUICKSAND_FULL, -1, -1
4976 Xsand_sandstone_2, FALSE, FALSE,
4977 EL_QUICKSAND_FULL, -1, -1
4980 Xsand_sandstone_3, FALSE, FALSE,
4981 EL_QUICKSAND_FULL, -1, -1
4984 Xsand_sandstone_4, FALSE, FALSE,
4985 EL_QUICKSAND_FULL, -1, -1
4988 Xplant, TRUE, FALSE,
4989 EL_EMC_PLANT, -1, -1
4992 Yplant, FALSE, FALSE,
4993 EL_EMC_PLANT, -1, -1
4996 Xlenses, TRUE, FALSE,
4997 EL_EMC_LENSES, -1, -1
5000 Xmagnify, TRUE, FALSE,
5001 EL_EMC_MAGNIFIER, -1, -1
5004 Xdripper, TRUE, FALSE,
5005 EL_EMC_DRIPPER, -1, -1
5008 XdripperB, FALSE, FALSE,
5009 EL_EMC_DRIPPER, ACTION_ACTIVE, -1
5012 Xfake_blank, TRUE, FALSE,
5013 EL_INVISIBLE_WALL, -1, -1
5016 Xfake_blankB, FALSE, FALSE,
5017 EL_INVISIBLE_WALL, ACTION_ACTIVE, -1
5020 Xfake_grass, TRUE, FALSE,
5021 EL_EMC_FAKE_GRASS, -1, -1
5024 Xfake_grassB, FALSE, FALSE,
5025 EL_EMC_FAKE_GRASS, ACTION_ACTIVE, -1
5028 Xfake_door_1, TRUE, FALSE,
5029 EL_EM_GATE_1_GRAY, -1, -1
5032 Xfake_door_2, TRUE, FALSE,
5033 EL_EM_GATE_2_GRAY, -1, -1
5036 Xfake_door_3, TRUE, FALSE,
5037 EL_EM_GATE_3_GRAY, -1, -1
5040 Xfake_door_4, TRUE, FALSE,
5041 EL_EM_GATE_4_GRAY, -1, -1
5044 Xfake_door_5, TRUE, FALSE,
5045 EL_EMC_GATE_5_GRAY, -1, -1
5048 Xfake_door_6, TRUE, FALSE,
5049 EL_EMC_GATE_6_GRAY, -1, -1
5052 Xfake_door_7, TRUE, FALSE,
5053 EL_EMC_GATE_7_GRAY, -1, -1
5056 Xfake_door_8, TRUE, FALSE,
5057 EL_EMC_GATE_8_GRAY, -1, -1
5060 Xfake_acid_1, TRUE, FALSE,
5061 EL_EMC_FAKE_ACID, -1, -1
5064 Xfake_acid_2, FALSE, FALSE,
5065 EL_EMC_FAKE_ACID, -1, -1
5068 Xfake_acid_3, FALSE, FALSE,
5069 EL_EMC_FAKE_ACID, -1, -1
5072 Xfake_acid_4, FALSE, FALSE,
5073 EL_EMC_FAKE_ACID, -1, -1
5076 Xfake_acid_5, FALSE, FALSE,
5077 EL_EMC_FAKE_ACID, -1, -1
5080 Xfake_acid_6, FALSE, FALSE,
5081 EL_EMC_FAKE_ACID, -1, -1
5084 Xfake_acid_7, FALSE, FALSE,
5085 EL_EMC_FAKE_ACID, -1, -1
5088 Xfake_acid_8, FALSE, FALSE,
5089 EL_EMC_FAKE_ACID, -1, -1
5092 Xsteel_1, TRUE, FALSE,
5093 EL_STEELWALL, -1, -1
5096 Xsteel_2, TRUE, FALSE,
5097 EL_EMC_STEELWALL_2, -1, -1
5100 Xsteel_3, TRUE, FALSE,
5101 EL_EMC_STEELWALL_3, -1, -1
5104 Xsteel_4, TRUE, FALSE,
5105 EL_EMC_STEELWALL_4, -1, -1
5108 Xwall_1, TRUE, FALSE,
5112 Xwall_2, TRUE, FALSE,
5113 EL_EMC_WALL_14, -1, -1
5116 Xwall_3, TRUE, FALSE,
5117 EL_EMC_WALL_15, -1, -1
5120 Xwall_4, TRUE, FALSE,
5121 EL_EMC_WALL_16, -1, -1
5124 Xround_wall_1, TRUE, FALSE,
5125 EL_WALL_SLIPPERY, -1, -1
5128 Xround_wall_2, TRUE, FALSE,
5129 EL_EMC_WALL_SLIPPERY_2, -1, -1
5132 Xround_wall_3, TRUE, FALSE,
5133 EL_EMC_WALL_SLIPPERY_3, -1, -1
5136 Xround_wall_4, TRUE, FALSE,
5137 EL_EMC_WALL_SLIPPERY_4, -1, -1
5140 Xdecor_1, TRUE, FALSE,
5141 EL_EMC_WALL_8, -1, -1
5144 Xdecor_2, TRUE, FALSE,
5145 EL_EMC_WALL_6, -1, -1
5148 Xdecor_3, TRUE, FALSE,
5149 EL_EMC_WALL_4, -1, -1
5152 Xdecor_4, TRUE, FALSE,
5153 EL_EMC_WALL_7, -1, -1
5156 Xdecor_5, TRUE, FALSE,
5157 EL_EMC_WALL_5, -1, -1
5160 Xdecor_6, TRUE, FALSE,
5161 EL_EMC_WALL_9, -1, -1
5164 Xdecor_7, TRUE, FALSE,
5165 EL_EMC_WALL_10, -1, -1
5168 Xdecor_8, TRUE, FALSE,
5169 EL_EMC_WALL_1, -1, -1
5172 Xdecor_9, TRUE, FALSE,
5173 EL_EMC_WALL_2, -1, -1
5176 Xdecor_10, TRUE, FALSE,
5177 EL_EMC_WALL_3, -1, -1
5180 Xdecor_11, TRUE, FALSE,
5181 EL_EMC_WALL_11, -1, -1
5184 Xdecor_12, TRUE, FALSE,
5185 EL_EMC_WALL_12, -1, -1
5188 Xalpha_0, TRUE, FALSE,
5189 EL_CHAR('0'), -1, -1
5192 Xalpha_1, TRUE, FALSE,
5193 EL_CHAR('1'), -1, -1
5196 Xalpha_2, TRUE, FALSE,
5197 EL_CHAR('2'), -1, -1
5200 Xalpha_3, TRUE, FALSE,
5201 EL_CHAR('3'), -1, -1
5204 Xalpha_4, TRUE, FALSE,
5205 EL_CHAR('4'), -1, -1
5208 Xalpha_5, TRUE, FALSE,
5209 EL_CHAR('5'), -1, -1
5212 Xalpha_6, TRUE, FALSE,
5213 EL_CHAR('6'), -1, -1
5216 Xalpha_7, TRUE, FALSE,
5217 EL_CHAR('7'), -1, -1
5220 Xalpha_8, TRUE, FALSE,
5221 EL_CHAR('8'), -1, -1
5224 Xalpha_9, TRUE, FALSE,
5225 EL_CHAR('9'), -1, -1
5228 Xalpha_excla, TRUE, FALSE,
5229 EL_CHAR('!'), -1, -1
5232 Xalpha_quote, TRUE, FALSE,
5233 EL_CHAR('"'), -1, -1
5236 Xalpha_comma, TRUE, FALSE,
5237 EL_CHAR(','), -1, -1
5240 Xalpha_minus, TRUE, FALSE,
5241 EL_CHAR('-'), -1, -1
5244 Xalpha_perio, TRUE, FALSE,
5245 EL_CHAR('.'), -1, -1
5248 Xalpha_colon, TRUE, FALSE,
5249 EL_CHAR(':'), -1, -1
5252 Xalpha_quest, TRUE, FALSE,
5253 EL_CHAR('?'), -1, -1
5256 Xalpha_a, TRUE, FALSE,
5257 EL_CHAR('A'), -1, -1
5260 Xalpha_b, TRUE, FALSE,
5261 EL_CHAR('B'), -1, -1
5264 Xalpha_c, TRUE, FALSE,
5265 EL_CHAR('C'), -1, -1
5268 Xalpha_d, TRUE, FALSE,
5269 EL_CHAR('D'), -1, -1
5272 Xalpha_e, TRUE, FALSE,
5273 EL_CHAR('E'), -1, -1
5276 Xalpha_f, TRUE, FALSE,
5277 EL_CHAR('F'), -1, -1
5280 Xalpha_g, TRUE, FALSE,
5281 EL_CHAR('G'), -1, -1
5284 Xalpha_h, TRUE, FALSE,
5285 EL_CHAR('H'), -1, -1
5288 Xalpha_i, TRUE, FALSE,
5289 EL_CHAR('I'), -1, -1
5292 Xalpha_j, TRUE, FALSE,
5293 EL_CHAR('J'), -1, -1
5296 Xalpha_k, TRUE, FALSE,
5297 EL_CHAR('K'), -1, -1
5300 Xalpha_l, TRUE, FALSE,
5301 EL_CHAR('L'), -1, -1
5304 Xalpha_m, TRUE, FALSE,
5305 EL_CHAR('M'), -1, -1
5308 Xalpha_n, TRUE, FALSE,
5309 EL_CHAR('N'), -1, -1
5312 Xalpha_o, TRUE, FALSE,
5313 EL_CHAR('O'), -1, -1
5316 Xalpha_p, TRUE, FALSE,
5317 EL_CHAR('P'), -1, -1
5320 Xalpha_q, TRUE, FALSE,
5321 EL_CHAR('Q'), -1, -1
5324 Xalpha_r, TRUE, FALSE,
5325 EL_CHAR('R'), -1, -1
5328 Xalpha_s, TRUE, FALSE,
5329 EL_CHAR('S'), -1, -1
5332 Xalpha_t, TRUE, FALSE,
5333 EL_CHAR('T'), -1, -1
5336 Xalpha_u, TRUE, FALSE,
5337 EL_CHAR('U'), -1, -1
5340 Xalpha_v, TRUE, FALSE,
5341 EL_CHAR('V'), -1, -1
5344 Xalpha_w, TRUE, FALSE,
5345 EL_CHAR('W'), -1, -1
5348 Xalpha_x, TRUE, FALSE,
5349 EL_CHAR('X'), -1, -1
5352 Xalpha_y, TRUE, FALSE,
5353 EL_CHAR('Y'), -1, -1
5356 Xalpha_z, TRUE, FALSE,
5357 EL_CHAR('Z'), -1, -1
5360 Xalpha_arrow_e, TRUE, FALSE,
5361 EL_CHAR('>'), -1, -1
5364 Xalpha_arrow_w, TRUE, FALSE,
5365 EL_CHAR('<'), -1, -1
5368 Xalpha_copyr, TRUE, FALSE,
5369 EL_CHAR('©'), -1, -1
5373 Xboom_bug, FALSE, FALSE,
5374 EL_BUG, ACTION_EXPLODING, -1
5377 Xboom_bomb, FALSE, FALSE,
5378 EL_BOMB, ACTION_EXPLODING, -1
5381 Xboom_android, FALSE, FALSE,
5382 EL_EMC_ANDROID, ACTION_OTHER, -1
5385 Xboom_1, FALSE, FALSE,
5386 EL_DEFAULT, ACTION_EXPLODING, -1
5389 Xboom_2, FALSE, FALSE,
5390 EL_DEFAULT, ACTION_EXPLODING, -1
5393 Znormal, FALSE, FALSE,
5397 Zdynamite, FALSE, FALSE,
5401 Zplayer, FALSE, FALSE,
5405 ZBORDER, FALSE, FALSE,
5415 static struct Mapping_EM_to_RND_player
5424 em_player_mapping_list[] =
5428 EL_PLAYER_1, ACTION_MOVING, MV_BIT_UP,
5432 EL_PLAYER_1, ACTION_MOVING, MV_BIT_RIGHT,
5436 EL_PLAYER_1, ACTION_MOVING, MV_BIT_DOWN,
5440 EL_PLAYER_1, ACTION_MOVING, MV_BIT_LEFT,
5444 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_UP,
5448 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_RIGHT,
5452 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_DOWN,
5456 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_LEFT,
5460 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_UP,
5464 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_RIGHT,
5468 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_DOWN,
5472 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_LEFT,
5476 EL_PLAYER_2, ACTION_MOVING, MV_BIT_UP,
5480 EL_PLAYER_2, ACTION_MOVING, MV_BIT_RIGHT,
5484 EL_PLAYER_2, ACTION_MOVING, MV_BIT_DOWN,
5488 EL_PLAYER_2, ACTION_MOVING, MV_BIT_LEFT,
5492 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_UP,
5496 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_RIGHT,
5500 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_DOWN,
5504 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_LEFT,
5508 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_UP,
5512 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_RIGHT,
5516 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_DOWN,
5520 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_LEFT,
5524 EL_PLAYER_1, ACTION_DEFAULT, -1,
5528 EL_PLAYER_2, ACTION_DEFAULT, -1,
5532 EL_PLAYER_3, ACTION_MOVING, MV_BIT_UP,
5536 EL_PLAYER_3, ACTION_MOVING, MV_BIT_RIGHT,
5540 EL_PLAYER_3, ACTION_MOVING, MV_BIT_DOWN,
5544 EL_PLAYER_3, ACTION_MOVING, MV_BIT_LEFT,
5548 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_UP,
5552 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_RIGHT,
5556 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_DOWN,
5560 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_LEFT,
5564 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_UP,
5568 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_RIGHT,
5572 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_DOWN,
5576 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_LEFT,
5580 EL_PLAYER_4, ACTION_MOVING, MV_BIT_UP,
5584 EL_PLAYER_4, ACTION_MOVING, MV_BIT_RIGHT,
5588 EL_PLAYER_4, ACTION_MOVING, MV_BIT_DOWN,
5592 EL_PLAYER_4, ACTION_MOVING, MV_BIT_LEFT,
5596 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_UP,
5600 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_RIGHT,
5604 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_DOWN,
5608 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_LEFT,
5612 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_UP,
5616 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_RIGHT,
5620 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_DOWN,
5624 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_LEFT,
5628 EL_PLAYER_3, ACTION_DEFAULT, -1,
5632 EL_PLAYER_4, ACTION_DEFAULT, -1,
5641 int map_element_RND_to_EM(int element_rnd)
5643 static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
5644 static boolean mapping_initialized = FALSE;
5646 if (!mapping_initialized)
5650 /* return "Xalpha_quest" for all undefined elements in mapping array */
5651 for (i = 0; i < NUM_FILE_ELEMENTS; i++)
5652 mapping_RND_to_EM[i] = Xalpha_quest;
5654 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5655 if (em_object_mapping_list[i].is_rnd_to_em_mapping)
5656 mapping_RND_to_EM[em_object_mapping_list[i].element_rnd] =
5657 em_object_mapping_list[i].element_em;
5659 mapping_initialized = TRUE;
5662 if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
5663 return mapping_RND_to_EM[element_rnd];
5665 Error(ERR_WARN, "invalid RND level element %d", element_rnd);
5670 int map_element_EM_to_RND(int element_em)
5672 static unsigned short mapping_EM_to_RND[TILE_MAX];
5673 static boolean mapping_initialized = FALSE;
5675 if (!mapping_initialized)
5679 /* return "EL_UNKNOWN" for all undefined elements in mapping array */
5680 for (i = 0; i < TILE_MAX; i++)
5681 mapping_EM_to_RND[i] = EL_UNKNOWN;
5683 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5684 mapping_EM_to_RND[em_object_mapping_list[i].element_em] =
5685 em_object_mapping_list[i].element_rnd;
5687 mapping_initialized = TRUE;
5690 if (element_em >= 0 && element_em < TILE_MAX)
5691 return mapping_EM_to_RND[element_em];
5693 Error(ERR_WARN, "invalid EM level element %d", element_em);
5698 void map_android_clone_elements_RND_to_EM(struct LevelInfo *level)
5700 struct LevelInfo_EM *level_em = level->native_em_level;
5701 struct LEVEL *lev = level_em->lev;
5704 for (i = 0; i < TILE_MAX; i++)
5705 lev->android_array[i] = Xblank;
5707 for (i = 0; i < level->num_android_clone_elements; i++)
5709 int element_rnd = level->android_clone_element[i];
5710 int element_em = map_element_RND_to_EM(element_rnd);
5712 for (j = 0; em_object_mapping_list[j].element_em != -1; j++)
5713 if (em_object_mapping_list[j].element_rnd == element_rnd)
5714 lev->android_array[em_object_mapping_list[j].element_em] = element_em;
5718 void map_android_clone_elements_EM_to_RND(struct LevelInfo *level)
5720 struct LevelInfo_EM *level_em = level->native_em_level;
5721 struct LEVEL *lev = level_em->lev;
5724 level->num_android_clone_elements = 0;
5726 for (i = 0; i < TILE_MAX; i++)
5728 int element_em = lev->android_array[i];
5730 boolean element_found = FALSE;
5732 if (element_em == Xblank)
5735 element_rnd = map_element_EM_to_RND(element_em);
5737 for (j = 0; j < level->num_android_clone_elements; j++)
5738 if (level->android_clone_element[j] == element_rnd)
5739 element_found = TRUE;
5743 level->android_clone_element[level->num_android_clone_elements++] =
5746 if (level->num_android_clone_elements == MAX_ANDROID_ELEMENTS)
5751 if (level->num_android_clone_elements == 0)
5753 level->num_android_clone_elements = 1;
5754 level->android_clone_element[0] = EL_EMPTY;
5758 int map_direction_RND_to_EM(int direction)
5760 return (direction == MV_UP ? 0 :
5761 direction == MV_RIGHT ? 1 :
5762 direction == MV_DOWN ? 2 :
5763 direction == MV_LEFT ? 3 :
5767 int map_direction_EM_to_RND(int direction)
5769 return (direction == 0 ? MV_UP :
5770 direction == 1 ? MV_RIGHT :
5771 direction == 2 ? MV_DOWN :
5772 direction == 3 ? MV_LEFT :
5776 int get_next_element(int element)
5780 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
5781 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
5782 case EL_QUICKSAND_FAST_FILLING: return EL_QUICKSAND_FAST_FULL;
5783 case EL_QUICKSAND_FAST_EMPTYING: return EL_QUICKSAND_FAST_EMPTY;
5784 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
5785 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
5786 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
5787 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
5788 case EL_DC_MAGIC_WALL_FILLING: return EL_DC_MAGIC_WALL_FULL;
5789 case EL_DC_MAGIC_WALL_EMPTYING: return EL_DC_MAGIC_WALL_ACTIVE;
5790 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
5792 default: return element;
5797 int el_act_dir2img(int element, int action, int direction)
5799 element = GFX_ELEMENT(element);
5801 if (direction == MV_NONE)
5802 return element_info[element].graphic[action];
5804 direction = MV_DIR_TO_BIT(direction);
5806 return element_info[element].direction_graphic[action][direction];
5809 int el_act_dir2img(int element, int action, int direction)
5811 element = GFX_ELEMENT(element);
5812 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
5814 /* direction_graphic[][] == graphic[] for undefined direction graphics */
5815 return element_info[element].direction_graphic[action][direction];
5820 static int el_act_dir2crm(int element, int action, int direction)
5822 element = GFX_ELEMENT(element);
5824 if (direction == MV_NONE)
5825 return element_info[element].crumbled[action];
5827 direction = MV_DIR_TO_BIT(direction);
5829 return element_info[element].direction_crumbled[action][direction];
5832 static int el_act_dir2crm(int element, int action, int direction)
5834 element = GFX_ELEMENT(element);
5835 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
5837 /* direction_graphic[][] == graphic[] for undefined direction graphics */
5838 return element_info[element].direction_crumbled[action][direction];
5842 int el_act2img(int element, int action)
5844 element = GFX_ELEMENT(element);
5846 return element_info[element].graphic[action];
5849 int el_act2crm(int element, int action)
5851 element = GFX_ELEMENT(element);
5853 return element_info[element].crumbled[action];
5856 int el_dir2img(int element, int direction)
5858 element = GFX_ELEMENT(element);
5860 return el_act_dir2img(element, ACTION_DEFAULT, direction);
5863 int el2baseimg(int element)
5865 return element_info[element].graphic[ACTION_DEFAULT];
5868 int el2img(int element)
5870 element = GFX_ELEMENT(element);
5872 return element_info[element].graphic[ACTION_DEFAULT];
5875 int el2edimg(int element)
5877 element = GFX_ELEMENT(element);
5879 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
5882 int el2preimg(int element)
5884 element = GFX_ELEMENT(element);
5886 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
5889 int el2panelimg(int element)
5891 element = GFX_ELEMENT(element);
5893 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PANEL];
5896 int font2baseimg(int font_nr)
5898 return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
5901 int getBeltNrFromBeltElement(int element)
5903 return (element < EL_CONVEYOR_BELT_2_LEFT ? 0 :
5904 element < EL_CONVEYOR_BELT_3_LEFT ? 1 :
5905 element < EL_CONVEYOR_BELT_4_LEFT ? 2 : 3);
5908 int getBeltNrFromBeltActiveElement(int element)
5910 return (element < EL_CONVEYOR_BELT_2_LEFT_ACTIVE ? 0 :
5911 element < EL_CONVEYOR_BELT_3_LEFT_ACTIVE ? 1 :
5912 element < EL_CONVEYOR_BELT_4_LEFT_ACTIVE ? 2 : 3);
5915 int getBeltNrFromBeltSwitchElement(int element)
5917 return (element < EL_CONVEYOR_BELT_2_SWITCH_LEFT ? 0 :
5918 element < EL_CONVEYOR_BELT_3_SWITCH_LEFT ? 1 :
5919 element < EL_CONVEYOR_BELT_4_SWITCH_LEFT ? 2 : 3);
5922 int getBeltDirNrFromBeltElement(int element)
5924 static int belt_base_element[4] =
5926 EL_CONVEYOR_BELT_1_LEFT,
5927 EL_CONVEYOR_BELT_2_LEFT,
5928 EL_CONVEYOR_BELT_3_LEFT,
5929 EL_CONVEYOR_BELT_4_LEFT
5932 int belt_nr = getBeltNrFromBeltElement(element);
5933 int belt_dir_nr = element - belt_base_element[belt_nr];
5935 return (belt_dir_nr % 3);
5938 int getBeltDirNrFromBeltSwitchElement(int element)
5940 static int belt_base_element[4] =
5942 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
5943 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
5944 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
5945 EL_CONVEYOR_BELT_4_SWITCH_LEFT
5948 int belt_nr = getBeltNrFromBeltSwitchElement(element);
5949 int belt_dir_nr = element - belt_base_element[belt_nr];
5951 return (belt_dir_nr % 3);
5954 int getBeltDirFromBeltElement(int element)
5956 static int belt_move_dir[3] =
5963 int belt_dir_nr = getBeltDirNrFromBeltElement(element);
5965 return belt_move_dir[belt_dir_nr];
5968 int getBeltDirFromBeltSwitchElement(int element)
5970 static int belt_move_dir[3] =
5977 int belt_dir_nr = getBeltDirNrFromBeltSwitchElement(element);
5979 return belt_move_dir[belt_dir_nr];
5982 int getBeltElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
5984 static int belt_base_element[4] =
5986 EL_CONVEYOR_BELT_1_LEFT,
5987 EL_CONVEYOR_BELT_2_LEFT,
5988 EL_CONVEYOR_BELT_3_LEFT,
5989 EL_CONVEYOR_BELT_4_LEFT
5992 return belt_base_element[belt_nr] + belt_dir_nr;
5995 int getBeltElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
5997 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
5999 return getBeltElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
6002 int getBeltSwitchElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
6004 static int belt_base_element[4] =
6006 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
6007 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
6008 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
6009 EL_CONVEYOR_BELT_4_SWITCH_LEFT
6012 return belt_base_element[belt_nr] + belt_dir_nr;
6015 int getBeltSwitchElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
6017 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
6019 return getBeltSwitchElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
6022 int getNumActivePlayers_EM()
6024 int num_players = 0;
6030 for (i = 0; i < MAX_PLAYERS; i++)
6031 if (tape.player_participates[i])
6037 int getGameFrameDelay_EM(int native_em_game_frame_delay)
6039 int game_frame_delay_value;
6041 game_frame_delay_value =
6042 (tape.playing && tape.fast_forward ? FfwdFrameDelay :
6043 GameFrameDelay == GAME_FRAME_DELAY ? native_em_game_frame_delay :
6046 if (tape.playing && tape.warp_forward && !tape.pausing)
6047 game_frame_delay_value = 0;
6049 return game_frame_delay_value;
6052 unsigned int InitRND(long seed)
6054 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
6055 return InitEngineRandom_EM(seed);
6057 return InitEngineRandom_RND(seed);
6061 static struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
6062 static struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
6065 void ResetGfxAnimation_EM(int x, int y, int tile)
6070 void getGraphicSourceObjectExt_EM(int tile, int frame_em,
6071 Bitmap **src_bitmap, int *src_x, int *src_y,
6074 int element = object_mapping[tile].element_rnd;
6075 int action = object_mapping[tile].action;
6076 int direction = object_mapping[tile].direction;
6077 boolean is_backside = object_mapping[tile].is_backside;
6078 boolean action_removing = (action == ACTION_DIGGING ||
6079 action == ACTION_SNAPPING ||
6080 action == ACTION_COLLECTING);
6081 int effective_element = (frame_em > 0 ? element :
6082 is_backside ? EL_EMPTY :
6083 action_removing ? EL_EMPTY :
6085 int graphic = (direction == MV_NONE ?
6086 el_act2img(effective_element, action) :
6087 el_act_dir2img(effective_element, action, direction));
6088 struct GraphicInfo *g = &graphic_info[graphic];
6091 if (graphic_info[graphic].anim_global_sync)
6092 sync_frame = FrameCounter;
6094 sync_frame = 7 - frame_em;
6096 SetRandomAnimationValue(x, y);
6098 int frame = getAnimationFrame(g->anim_frames,
6101 g->anim_start_frame,
6104 getGraphicSourceExt(graphic, frame, src_bitmap, src_x, src_y, FALSE);
6107 void getGraphicSourcePlayerExt_EM(int player_nr, int anim, int frame_em,
6108 Bitmap **src_bitmap, int *src_x, int *src_y)
6110 int element = player_mapping[player_nr][anim].element_rnd;
6111 int action = player_mapping[player_nr][anim].action;
6112 int direction = player_mapping[player_nr][anim].direction;
6113 int graphic = (direction == MV_NONE ?
6114 el_act2img(element, action) :
6115 el_act_dir2img(element, action, direction));
6116 struct GraphicInfo *g = &graphic_info[graphic];
6119 InitPlayerGfxAnimation(&stored_player[player_nr], action, direction);
6121 stored_player[player_nr].StepFrame = 7 - frame_em;
6123 sync_frame = stored_player[player_nr].Frame;
6126 printf("::: %d: %d, %d [%d]\n",
6128 stored_player[player_nr].Frame,
6129 stored_player[player_nr].StepFrame,
6133 int frame = getAnimationFrame(g->anim_frames,
6136 g->anim_start_frame,
6139 getGraphicSourceExt(graphic, frame, src_bitmap, src_x, src_y, FALSE);
6142 void InitGraphicInfo_EM(void)
6145 struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
6146 struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
6151 int num_em_gfx_errors = 0;
6153 if (graphic_info_em_object[0][0].bitmap == NULL)
6155 /* EM graphics not yet initialized in em_open_all() */
6160 printf("::: [4 errors can be ignored (1 x 'bomb', 3 x 'em_dynamite']\n");
6163 /* always start with reliable default values */
6164 for (i = 0; i < TILE_MAX; i++)
6166 object_mapping[i].element_rnd = EL_UNKNOWN;
6167 object_mapping[i].is_backside = FALSE;
6168 object_mapping[i].action = ACTION_DEFAULT;
6169 object_mapping[i].direction = MV_NONE;
6172 /* always start with reliable default values */
6173 for (p = 0; p < MAX_PLAYERS; p++)
6175 for (i = 0; i < SPR_MAX; i++)
6177 player_mapping[p][i].element_rnd = EL_UNKNOWN;
6178 player_mapping[p][i].action = ACTION_DEFAULT;
6179 player_mapping[p][i].direction = MV_NONE;
6183 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
6185 int e = em_object_mapping_list[i].element_em;
6187 object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd;
6188 object_mapping[e].is_backside = em_object_mapping_list[i].is_backside;
6190 if (em_object_mapping_list[i].action != -1)
6191 object_mapping[e].action = em_object_mapping_list[i].action;
6193 if (em_object_mapping_list[i].direction != -1)
6194 object_mapping[e].direction =
6195 MV_DIR_FROM_BIT(em_object_mapping_list[i].direction);
6198 for (i = 0; em_player_mapping_list[i].action_em != -1; i++)
6200 int a = em_player_mapping_list[i].action_em;
6201 int p = em_player_mapping_list[i].player_nr;
6203 player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd;
6205 if (em_player_mapping_list[i].action != -1)
6206 player_mapping[p][a].action = em_player_mapping_list[i].action;
6208 if (em_player_mapping_list[i].direction != -1)
6209 player_mapping[p][a].direction =
6210 MV_DIR_FROM_BIT(em_player_mapping_list[i].direction);
6213 for (i = 0; i < TILE_MAX; i++)
6215 int element = object_mapping[i].element_rnd;
6216 int action = object_mapping[i].action;
6217 int direction = object_mapping[i].direction;
6218 boolean is_backside = object_mapping[i].is_backside;
6219 boolean action_removing = (action == ACTION_DIGGING ||
6220 action == ACTION_SNAPPING ||
6221 action == ACTION_COLLECTING);
6222 boolean action_exploding = ((action == ACTION_EXPLODING ||
6223 action == ACTION_SMASHED_BY_ROCK ||
6224 action == ACTION_SMASHED_BY_SPRING) &&
6225 element != EL_DIAMOND);
6226 boolean action_active = (action == ACTION_ACTIVE);
6227 boolean action_other = (action == ACTION_OTHER);
6229 for (j = 0; j < 8; j++)
6231 int effective_element = (j > 5 && i == Yacid_splash_eB ? EL_EMPTY :
6232 j > 5 && i == Yacid_splash_wB ? EL_EMPTY :
6234 i == Xdrip_stretch ? element :
6235 i == Xdrip_stretchB ? element :
6236 i == Ydrip_s1 ? element :
6237 i == Ydrip_s1B ? element :
6238 i == Xball_1B ? element :
6239 i == Xball_2 ? element :
6240 i == Xball_2B ? element :
6241 i == Yball_eat ? element :
6242 i == Ykey_1_eat ? element :
6243 i == Ykey_2_eat ? element :
6244 i == Ykey_3_eat ? element :
6245 i == Ykey_4_eat ? element :
6246 i == Ykey_5_eat ? element :
6247 i == Ykey_6_eat ? element :
6248 i == Ykey_7_eat ? element :
6249 i == Ykey_8_eat ? element :
6250 i == Ylenses_eat ? element :
6251 i == Ymagnify_eat ? element :
6252 i == Ygrass_eat ? element :
6253 i == Ydirt_eat ? element :
6254 i == Yemerald_stone ? EL_EMERALD :
6255 i == Ydiamond_stone ? EL_ROCK :
6256 i == Xsand_stonein_1 ? element :
6257 i == Xsand_stonein_2 ? element :
6258 i == Xsand_stonein_3 ? element :
6259 i == Xsand_stonein_4 ? element :
6260 is_backside ? EL_EMPTY :
6261 action_removing ? EL_EMPTY :
6263 int effective_action = (j < 7 ? action :
6264 i == Xdrip_stretch ? action :
6265 i == Xdrip_stretchB ? action :
6266 i == Ydrip_s1 ? action :
6267 i == Ydrip_s1B ? action :
6268 i == Xball_1B ? action :
6269 i == Xball_2 ? action :
6270 i == Xball_2B ? action :
6271 i == Yball_eat ? action :
6272 i == Ykey_1_eat ? action :
6273 i == Ykey_2_eat ? action :
6274 i == Ykey_3_eat ? action :
6275 i == Ykey_4_eat ? action :
6276 i == Ykey_5_eat ? action :
6277 i == Ykey_6_eat ? action :
6278 i == Ykey_7_eat ? action :
6279 i == Ykey_8_eat ? action :
6280 i == Ylenses_eat ? action :
6281 i == Ymagnify_eat ? action :
6282 i == Ygrass_eat ? action :
6283 i == Ydirt_eat ? action :
6284 i == Xsand_stonein_1 ? action :
6285 i == Xsand_stonein_2 ? action :
6286 i == Xsand_stonein_3 ? action :
6287 i == Xsand_stonein_4 ? action :
6288 i == Xsand_stoneout_1 ? action :
6289 i == Xsand_stoneout_2 ? action :
6290 i == Xboom_android ? ACTION_EXPLODING :
6291 action_exploding ? ACTION_EXPLODING :
6292 action_active ? action :
6293 action_other ? action :
6295 int graphic = (el_act_dir2img(effective_element, effective_action,
6297 int crumbled = (el_act_dir2crm(effective_element, effective_action,
6299 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
6300 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
6301 boolean has_action_graphics = (graphic != base_graphic);
6302 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
6303 struct GraphicInfo *g = &graphic_info[graphic];
6304 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
6307 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
6308 boolean special_animation = (action != ACTION_DEFAULT &&
6309 g->anim_frames == 3 &&
6310 g->anim_delay == 2 &&
6311 g->anim_mode & ANIM_LINEAR);
6312 int sync_frame = (i == Xdrip_stretch ? 7 :
6313 i == Xdrip_stretchB ? 7 :
6314 i == Ydrip_s2 ? j + 8 :
6315 i == Ydrip_s2B ? j + 8 :
6324 i == Xfake_acid_1 ? 0 :
6325 i == Xfake_acid_2 ? 10 :
6326 i == Xfake_acid_3 ? 20 :
6327 i == Xfake_acid_4 ? 30 :
6328 i == Xfake_acid_5 ? 40 :
6329 i == Xfake_acid_6 ? 50 :
6330 i == Xfake_acid_7 ? 60 :
6331 i == Xfake_acid_8 ? 70 :
6333 i == Xball_2B ? j + 8 :
6334 i == Yball_eat ? j + 1 :
6335 i == Ykey_1_eat ? j + 1 :
6336 i == Ykey_2_eat ? j + 1 :
6337 i == Ykey_3_eat ? j + 1 :
6338 i == Ykey_4_eat ? j + 1 :
6339 i == Ykey_5_eat ? j + 1 :
6340 i == Ykey_6_eat ? j + 1 :
6341 i == Ykey_7_eat ? j + 1 :
6342 i == Ykey_8_eat ? j + 1 :
6343 i == Ylenses_eat ? j + 1 :
6344 i == Ymagnify_eat ? j + 1 :
6345 i == Ygrass_eat ? j + 1 :
6346 i == Ydirt_eat ? j + 1 :
6347 i == Xamoeba_1 ? 0 :
6348 i == Xamoeba_2 ? 1 :
6349 i == Xamoeba_3 ? 2 :
6350 i == Xamoeba_4 ? 3 :
6351 i == Xamoeba_5 ? 0 :
6352 i == Xamoeba_6 ? 1 :
6353 i == Xamoeba_7 ? 2 :
6354 i == Xamoeba_8 ? 3 :
6355 i == Xexit_2 ? j + 8 :
6356 i == Xexit_3 ? j + 16 :
6357 i == Xdynamite_1 ? 0 :
6358 i == Xdynamite_2 ? 8 :
6359 i == Xdynamite_3 ? 16 :
6360 i == Xdynamite_4 ? 24 :
6361 i == Xsand_stonein_1 ? j + 1 :
6362 i == Xsand_stonein_2 ? j + 9 :
6363 i == Xsand_stonein_3 ? j + 17 :
6364 i == Xsand_stonein_4 ? j + 25 :
6365 i == Xsand_stoneout_1 && j == 0 ? 0 :
6366 i == Xsand_stoneout_1 && j == 1 ? 0 :
6367 i == Xsand_stoneout_1 && j == 2 ? 1 :
6368 i == Xsand_stoneout_1 && j == 3 ? 2 :
6369 i == Xsand_stoneout_1 && j == 4 ? 2 :
6370 i == Xsand_stoneout_1 && j == 5 ? 3 :
6371 i == Xsand_stoneout_1 && j == 6 ? 4 :
6372 i == Xsand_stoneout_1 && j == 7 ? 4 :
6373 i == Xsand_stoneout_2 && j == 0 ? 5 :
6374 i == Xsand_stoneout_2 && j == 1 ? 6 :
6375 i == Xsand_stoneout_2 && j == 2 ? 7 :
6376 i == Xsand_stoneout_2 && j == 3 ? 8 :
6377 i == Xsand_stoneout_2 && j == 4 ? 9 :
6378 i == Xsand_stoneout_2 && j == 5 ? 11 :
6379 i == Xsand_stoneout_2 && j == 6 ? 13 :
6380 i == Xsand_stoneout_2 && j == 7 ? 15 :
6381 i == Xboom_bug && j == 1 ? 2 :
6382 i == Xboom_bug && j == 2 ? 2 :
6383 i == Xboom_bug && j == 3 ? 4 :
6384 i == Xboom_bug && j == 4 ? 4 :
6385 i == Xboom_bug && j == 5 ? 2 :
6386 i == Xboom_bug && j == 6 ? 2 :
6387 i == Xboom_bug && j == 7 ? 0 :
6388 i == Xboom_bomb && j == 1 ? 2 :
6389 i == Xboom_bomb && j == 2 ? 2 :
6390 i == Xboom_bomb && j == 3 ? 4 :
6391 i == Xboom_bomb && j == 4 ? 4 :
6392 i == Xboom_bomb && j == 5 ? 2 :
6393 i == Xboom_bomb && j == 6 ? 2 :
6394 i == Xboom_bomb && j == 7 ? 0 :
6395 i == Xboom_android && j == 7 ? 6 :
6396 i == Xboom_1 && j == 1 ? 2 :
6397 i == Xboom_1 && j == 2 ? 2 :
6398 i == Xboom_1 && j == 3 ? 4 :
6399 i == Xboom_1 && j == 4 ? 4 :
6400 i == Xboom_1 && j == 5 ? 6 :
6401 i == Xboom_1 && j == 6 ? 6 :
6402 i == Xboom_1 && j == 7 ? 8 :
6403 i == Xboom_2 && j == 0 ? 8 :
6404 i == Xboom_2 && j == 1 ? 8 :
6405 i == Xboom_2 && j == 2 ? 10 :
6406 i == Xboom_2 && j == 3 ? 10 :
6407 i == Xboom_2 && j == 4 ? 10 :
6408 i == Xboom_2 && j == 5 ? 12 :
6409 i == Xboom_2 && j == 6 ? 12 :
6410 i == Xboom_2 && j == 7 ? 12 :
6411 special_animation && j == 4 ? 3 :
6412 effective_action != action ? 0 :
6416 Bitmap *debug_bitmap = g_em->bitmap;
6417 int debug_src_x = g_em->src_x;
6418 int debug_src_y = g_em->src_y;
6421 int frame = getAnimationFrame(g->anim_frames,
6424 g->anim_start_frame,
6427 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y,
6428 g->double_movement && is_backside);
6430 g_em->bitmap = src_bitmap;
6431 g_em->src_x = src_x;
6432 g_em->src_y = src_y;
6433 g_em->src_offset_x = 0;
6434 g_em->src_offset_y = 0;
6435 g_em->dst_offset_x = 0;
6436 g_em->dst_offset_y = 0;
6437 g_em->width = TILEX;
6438 g_em->height = TILEY;
6440 g_em->crumbled_bitmap = NULL;
6441 g_em->crumbled_src_x = 0;
6442 g_em->crumbled_src_y = 0;
6443 g_em->crumbled_border_size = 0;
6445 g_em->has_crumbled_graphics = FALSE;
6446 g_em->preserve_background = FALSE;
6449 if (has_crumbled_graphics && crumbled == IMG_EMPTY_SPACE)
6450 printf("::: empty crumbled: %d [%s], %d, %d\n",
6451 effective_element, element_info[effective_element].token_name,
6452 effective_action, direction);
6455 /* if element can be crumbled, but certain action graphics are just empty
6456 space (like snapping sand with the original R'n'D graphics), do not
6457 treat these empty space graphics as crumbled graphics in EMC engine */
6458 if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
6460 getGraphicSource(crumbled, frame, &src_bitmap, &src_x, &src_y);
6462 g_em->has_crumbled_graphics = TRUE;
6463 g_em->crumbled_bitmap = src_bitmap;
6464 g_em->crumbled_src_x = src_x;
6465 g_em->crumbled_src_y = src_y;
6466 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
6470 if (element == EL_ROCK &&
6471 effective_action == ACTION_FILLING)
6472 printf("::: has_action_graphics == %d\n", has_action_graphics);
6475 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
6476 effective_action == ACTION_MOVING ||
6477 effective_action == ACTION_PUSHING ||
6478 effective_action == ACTION_EATING)) ||
6479 (!has_action_graphics && (effective_action == ACTION_FILLING ||
6480 effective_action == ACTION_EMPTYING)))
6483 (effective_action == ACTION_FALLING ||
6484 effective_action == ACTION_FILLING ||
6485 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
6486 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
6487 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
6488 int num_steps = (i == Ydrip_s1 ? 16 :
6489 i == Ydrip_s1B ? 16 :
6490 i == Ydrip_s2 ? 16 :
6491 i == Ydrip_s2B ? 16 :
6492 i == Xsand_stonein_1 ? 32 :
6493 i == Xsand_stonein_2 ? 32 :
6494 i == Xsand_stonein_3 ? 32 :
6495 i == Xsand_stonein_4 ? 32 :
6496 i == Xsand_stoneout_1 ? 16 :
6497 i == Xsand_stoneout_2 ? 16 : 8);
6498 int cx = ABS(dx) * (TILEX / num_steps);
6499 int cy = ABS(dy) * (TILEY / num_steps);
6500 int step_frame = (i == Ydrip_s2 ? j + 8 :
6501 i == Ydrip_s2B ? j + 8 :
6502 i == Xsand_stonein_2 ? j + 8 :
6503 i == Xsand_stonein_3 ? j + 16 :
6504 i == Xsand_stonein_4 ? j + 24 :
6505 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
6506 int step = (is_backside ? step_frame : num_steps - step_frame);
6508 if (is_backside) /* tile where movement starts */
6510 if (dx < 0 || dy < 0)
6512 g_em->src_offset_x = cx * step;
6513 g_em->src_offset_y = cy * step;
6517 g_em->dst_offset_x = cx * step;
6518 g_em->dst_offset_y = cy * step;
6521 else /* tile where movement ends */
6523 if (dx < 0 || dy < 0)
6525 g_em->dst_offset_x = cx * step;
6526 g_em->dst_offset_y = cy * step;
6530 g_em->src_offset_x = cx * step;
6531 g_em->src_offset_y = cy * step;
6535 g_em->width = TILEX - cx * step;
6536 g_em->height = TILEY - cy * step;
6539 /* create unique graphic identifier to decide if tile must be redrawn */
6540 /* bit 31 - 16 (16 bit): EM style graphic
6541 bit 15 - 12 ( 4 bit): EM style frame
6542 bit 11 - 6 ( 6 bit): graphic width
6543 bit 5 - 0 ( 6 bit): graphic height */
6544 g_em->unique_identifier =
6545 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
6549 /* skip check for EMC elements not contained in original EMC artwork */
6550 if (element == EL_EMC_FAKE_ACID)
6553 if (g_em->bitmap != debug_bitmap ||
6554 g_em->src_x != debug_src_x ||
6555 g_em->src_y != debug_src_y ||
6556 g_em->src_offset_x != 0 ||
6557 g_em->src_offset_y != 0 ||
6558 g_em->dst_offset_x != 0 ||
6559 g_em->dst_offset_y != 0 ||
6560 g_em->width != TILEX ||
6561 g_em->height != TILEY)
6563 static int last_i = -1;
6571 printf("::: EMC GFX ERROR for element %d -> %d ('%s', '%s', %d)",
6572 i, element, element_info[element].token_name,
6573 element_action_info[effective_action].suffix, direction);
6575 if (element != effective_element)
6576 printf(" [%d ('%s')]",
6578 element_info[effective_element].token_name);
6582 if (g_em->bitmap != debug_bitmap)
6583 printf(" %d (%d): different bitmap! (0x%08x != 0x%08x)\n",
6584 j, is_backside, (int)(g_em->bitmap), (int)(debug_bitmap));
6586 if (g_em->src_x != debug_src_x ||
6587 g_em->src_y != debug_src_y)
6588 printf(" frame %d (%c): %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
6589 j, (is_backside ? 'B' : 'F'),
6590 g_em->src_x, g_em->src_y,
6591 g_em->src_x / 32, g_em->src_y / 32,
6592 debug_src_x, debug_src_y,
6593 debug_src_x / 32, debug_src_y / 32);
6595 if (g_em->src_offset_x != 0 ||
6596 g_em->src_offset_y != 0 ||
6597 g_em->dst_offset_x != 0 ||
6598 g_em->dst_offset_y != 0)
6599 printf(" %d (%d): offsets %d,%d and %d,%d should be all 0\n",
6601 g_em->src_offset_x, g_em->src_offset_y,
6602 g_em->dst_offset_x, g_em->dst_offset_y);
6604 if (g_em->width != TILEX ||
6605 g_em->height != TILEY)
6606 printf(" %d (%d): size %d,%d should be %d,%d\n",
6608 g_em->width, g_em->height, TILEX, TILEY);
6610 num_em_gfx_errors++;
6617 for (i = 0; i < TILE_MAX; i++)
6619 for (j = 0; j < 8; j++)
6621 int element = object_mapping[i].element_rnd;
6622 int action = object_mapping[i].action;
6623 int direction = object_mapping[i].direction;
6624 boolean is_backside = object_mapping[i].is_backside;
6625 int graphic_action = el_act_dir2img(element, action, direction);
6626 int graphic_default = el_act_dir2img(element, ACTION_DEFAULT, direction);
6628 if ((action == ACTION_SMASHED_BY_ROCK ||
6629 action == ACTION_SMASHED_BY_SPRING ||
6630 action == ACTION_EATING) &&
6631 graphic_action == graphic_default)
6633 int e = (action == ACTION_SMASHED_BY_ROCK ? Ystone_s :
6634 action == ACTION_SMASHED_BY_SPRING ? Yspring_s :
6635 direction == MV_LEFT ? (is_backside? Yspring_wB: Yspring_w) :
6636 direction == MV_RIGHT ? (is_backside? Yspring_eB: Yspring_e) :
6639 /* no separate animation for "smashed by rock" -- use rock instead */
6640 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
6641 struct GraphicInfo_EM *g_xx = &graphic_info_em_object[e][7 - j];
6643 g_em->bitmap = g_xx->bitmap;
6644 g_em->src_x = g_xx->src_x;
6645 g_em->src_y = g_xx->src_y;
6646 g_em->src_offset_x = g_xx->src_offset_x;
6647 g_em->src_offset_y = g_xx->src_offset_y;
6648 g_em->dst_offset_x = g_xx->dst_offset_x;
6649 g_em->dst_offset_y = g_xx->dst_offset_y;
6650 g_em->width = g_xx->width;
6651 g_em->height = g_xx->height;
6652 g_em->unique_identifier = g_xx->unique_identifier;
6655 g_em->preserve_background = TRUE;
6660 for (p = 0; p < MAX_PLAYERS; p++)
6662 for (i = 0; i < SPR_MAX; i++)
6664 int element = player_mapping[p][i].element_rnd;
6665 int action = player_mapping[p][i].action;
6666 int direction = player_mapping[p][i].direction;
6668 for (j = 0; j < 8; j++)
6670 int effective_element = element;
6671 int effective_action = action;
6672 int graphic = (direction == MV_NONE ?
6673 el_act2img(effective_element, effective_action) :
6674 el_act_dir2img(effective_element, effective_action,
6676 struct GraphicInfo *g = &graphic_info[graphic];
6677 struct GraphicInfo_EM *g_em = &graphic_info_em_player[p][i][7 - j];
6683 Bitmap *debug_bitmap = g_em->bitmap;
6684 int debug_src_x = g_em->src_x;
6685 int debug_src_y = g_em->src_y;
6688 int frame = getAnimationFrame(g->anim_frames,
6691 g->anim_start_frame,
6694 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
6696 g_em->bitmap = src_bitmap;
6697 g_em->src_x = src_x;
6698 g_em->src_y = src_y;
6699 g_em->src_offset_x = 0;
6700 g_em->src_offset_y = 0;
6701 g_em->dst_offset_x = 0;
6702 g_em->dst_offset_y = 0;
6703 g_em->width = TILEX;
6704 g_em->height = TILEY;
6708 /* skip check for EMC elements not contained in original EMC artwork */
6709 if (element == EL_PLAYER_3 ||
6710 element == EL_PLAYER_4)
6713 if (g_em->bitmap != debug_bitmap ||
6714 g_em->src_x != debug_src_x ||
6715 g_em->src_y != debug_src_y)
6717 static int last_i = -1;
6725 printf("::: EMC GFX ERROR for p/a %d/%d -> %d ('%s', '%s', %d)",
6726 p, i, element, element_info[element].token_name,
6727 element_action_info[effective_action].suffix, direction);
6729 if (element != effective_element)
6730 printf(" [%d ('%s')]",
6732 element_info[effective_element].token_name);
6736 if (g_em->bitmap != debug_bitmap)
6737 printf(" %d: different bitmap! (0x%08x != 0x%08x)\n",
6738 j, (int)(g_em->bitmap), (int)(debug_bitmap));
6740 if (g_em->src_x != debug_src_x ||
6741 g_em->src_y != debug_src_y)
6742 printf(" frame %d: %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
6744 g_em->src_x, g_em->src_y,
6745 g_em->src_x / 32, g_em->src_y / 32,
6746 debug_src_x, debug_src_y,
6747 debug_src_x / 32, debug_src_y / 32);
6749 num_em_gfx_errors++;
6759 printf("::: [%d errors found]\n", num_em_gfx_errors);
6765 void PlayMenuSoundExt(int sound)
6767 if (sound == SND_UNDEFINED)
6770 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
6771 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
6774 if (IS_LOOP_SOUND(sound))
6775 PlaySoundLoop(sound);
6780 void PlayMenuSound()
6782 PlayMenuSoundExt(menu.sound[game_status]);
6785 void PlayMenuSoundStereo(int sound, int stereo_position)
6787 if (sound == SND_UNDEFINED)
6790 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
6791 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
6794 if (IS_LOOP_SOUND(sound))
6795 PlaySoundExt(sound, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_LOOP);
6797 PlaySoundStereo(sound, stereo_position);
6800 void PlayMenuSoundIfLoopExt(int sound)
6802 if (sound == SND_UNDEFINED)
6805 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
6806 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
6809 if (IS_LOOP_SOUND(sound))
6810 PlaySoundLoop(sound);
6813 void PlayMenuSoundIfLoop()
6815 PlayMenuSoundIfLoopExt(menu.sound[game_status]);
6818 void PlayMenuMusicExt(int music)
6820 if (music == MUS_UNDEFINED)
6823 if (!setup.sound_music)
6829 void PlayMenuMusic()
6831 PlayMenuMusicExt(menu.music[game_status]);
6834 void PlaySoundActivating()
6837 PlaySound(SND_MENU_ITEM_ACTIVATING);
6841 void PlaySoundSelecting()
6844 PlaySound(SND_MENU_ITEM_SELECTING);
6848 void ToggleFullscreenIfNeeded()
6850 boolean change_fullscreen = (setup.fullscreen !=
6851 video.fullscreen_enabled);
6852 boolean change_fullscreen_mode = (video.fullscreen_enabled &&
6853 !strEqual(setup.fullscreen_mode,
6854 video.fullscreen_mode_current));
6856 if (!video.fullscreen_available)
6860 if (change_fullscreen || change_fullscreen_mode)
6862 if (setup.fullscreen != video.fullscreen_enabled ||
6863 setup.fullscreen_mode != video.fullscreen_mode_current)
6866 Bitmap *tmp_backbuffer = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
6868 /* save backbuffer content which gets lost when toggling fullscreen mode */
6869 BlitBitmap(backbuffer, tmp_backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
6872 if (change_fullscreen_mode)
6874 if (setup.fullscreen && video.fullscreen_enabled)
6877 /* keep fullscreen, but change fullscreen mode (screen resolution) */
6879 /* (this is now set in sdl.c) */
6881 video.fullscreen_mode_current = setup.fullscreen_mode;
6883 video.fullscreen_enabled = FALSE; /* force new fullscreen mode */
6886 /* toggle fullscreen */
6887 ChangeVideoModeIfNeeded(setup.fullscreen);
6889 setup.fullscreen = video.fullscreen_enabled;
6891 /* restore backbuffer content from temporary backbuffer backup bitmap */
6892 BlitBitmap(tmp_backbuffer, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
6894 FreeBitmap(tmp_backbuffer);
6897 /* update visible window/screen */
6898 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
6900 redraw_mask = REDRAW_ALL;