1 /***********************************************************
2 * Rocks'n'Diamonds -- McDuffin Strikes Back! *
3 *----------------------------------------------------------*
4 * (c) 1995-2006 Artsoft Entertainment *
6 * Detmolder Strasse 189 *
9 * e-mail: info@artsoft.org *
10 *----------------------------------------------------------*
12 ***********************************************************/
14 #include "libgame/libgame.h"
25 /* select level set with EMC X11 graphics before activating EM GFX debugging */
26 #define DEBUG_EM_GFX 0
28 /* tool button identifiers */
29 #define TOOL_CTRL_ID_YES 0
30 #define TOOL_CTRL_ID_NO 1
31 #define TOOL_CTRL_ID_CONFIRM 2
32 #define TOOL_CTRL_ID_PLAYER_1 3
33 #define TOOL_CTRL_ID_PLAYER_2 4
34 #define TOOL_CTRL_ID_PLAYER_3 5
35 #define TOOL_CTRL_ID_PLAYER_4 6
37 #define NUM_TOOL_BUTTONS 7
39 /* forward declaration for internal use */
40 static void UnmapToolButtons();
41 static void HandleToolButtons(struct GadgetInfo *);
42 static int el_act_dir2crm(int, int, int);
43 static int el_act2crm(int, int);
45 static struct GadgetInfo *tool_gadget[NUM_TOOL_BUTTONS];
46 static int request_gadget_id = -1;
48 static char *print_if_not_empty(int element)
50 static char *s = NULL;
51 char *token_name = element_info[element].token_name;
56 s = checked_malloc(strlen(token_name) + 10 + 1);
58 if (element != EL_EMPTY)
59 sprintf(s, "%d\t['%s']", element, token_name);
61 sprintf(s, "%d", element);
66 void DumpTile(int x, int y)
71 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
78 printf("Field Info: SCREEN(%d, %d), LEVEL(%d, %d)\n", sx, sy, x, y);
81 if (!IN_LEV_FIELD(x, y))
83 printf("(not in level field)\n");
89 printf(" Feld: %d\t['%s']\n", Feld[x][y],
90 element_info[Feld[x][y]].token_name);
91 printf(" Back: %s\n", print_if_not_empty(Back[x][y]));
92 printf(" Store: %s\n", print_if_not_empty(Store[x][y]));
93 printf(" Store2: %s\n", print_if_not_empty(Store2[x][y]));
94 printf(" StorePlayer: %s\n", print_if_not_empty(StorePlayer[x][y]));
95 printf(" MovPos: %d\n", MovPos[x][y]);
96 printf(" MovDir: %d\n", MovDir[x][y]);
97 printf(" MovDelay: %d\n", MovDelay[x][y]);
98 printf(" ChangeDelay: %d\n", ChangeDelay[x][y]);
99 printf(" CustomValue: %d\n", CustomValue[x][y]);
100 printf(" GfxElement: %d\n", GfxElement[x][y]);
101 printf(" GfxAction: %d\n", GfxAction[x][y]);
102 printf(" GfxFrame: %d\n", GfxFrame[x][y]);
106 void SetDrawtoField(int mode)
108 if (mode == DRAW_BUFFERED && setup.soft_scrolling)
119 drawto_field = fieldbuffer;
121 else /* DRAW_DIRECT, DRAW_BACKBUFFER */
127 BX2 = SCR_FIELDX - 1;
128 BY2 = SCR_FIELDY - 1;
132 drawto_field = (mode == DRAW_DIRECT ? window : backbuffer);
136 void RedrawPlayfield(boolean force_redraw, int x, int y, int width, int height)
138 if (game_status == GAME_MODE_PLAYING &&
139 level.game_engine_type == GAME_ENGINE_TYPE_EM)
141 /* currently there is no partial redraw -- always redraw whole playfield */
142 RedrawPlayfield_EM(TRUE);
144 /* blit playfield from scroll buffer to normal back buffer for fading in */
145 BlitScreenToBitmap_EM(backbuffer);
147 else if (game_status == GAME_MODE_PLAYING && !game.envelope_active)
153 width = gfx.sxsize + 2 * TILEX;
154 height = gfx.sysize + 2 * TILEY;
157 if (force_redraw || setup.direct_draw)
160 int x1 = (x - SX) / TILEX, y1 = (y - SY) / TILEY;
161 int x2 = (x - SX + width) / TILEX, y2 = (y - SY + height) / TILEY;
163 if (setup.direct_draw)
164 SetDrawtoField(DRAW_BACKBUFFER);
166 for (xx = BX1; xx <= BX2; xx++)
167 for (yy = BY1; yy <= BY2; yy++)
168 if (xx >= x1 && xx <= x2 && yy >= y1 && yy <= y2)
169 DrawScreenField(xx, yy);
172 if (setup.direct_draw)
173 SetDrawtoField(DRAW_DIRECT);
176 if (setup.soft_scrolling)
178 int fx = FX, fy = FY;
180 fx += (ScreenMovDir & (MV_LEFT|MV_RIGHT) ? ScreenGfxPos : 0);
181 fy += (ScreenMovDir & (MV_UP|MV_DOWN) ? ScreenGfxPos : 0);
183 BlitBitmap(fieldbuffer, backbuffer, fx,fy, SXSIZE,SYSIZE, SX,SY);
195 BlitBitmap(drawto, window, x, y, width, height, x, y);
198 void DrawMaskedBorder_Rect(int x, int y, int width, int height)
200 Bitmap *bitmap = graphic_info[IMG_GLOBAL_BORDER].bitmap;
202 SetClipOrigin(bitmap, bitmap->stored_clip_gc, 0, 0);
203 BlitBitmapMasked(bitmap, backbuffer, x, y, width, height, x, y);
206 void DrawMaskedBorder_FIELD()
208 if (game_status >= GAME_MODE_TITLE &&
209 game_status <= GAME_MODE_PLAYING &&
210 border.draw_masked[game_status])
211 DrawMaskedBorder_Rect(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
214 void DrawMaskedBorder_DOOR_1()
216 if (border.draw_masked[GFX_SPECIAL_ARG_DOOR] &&
217 (game_status != GAME_MODE_EDITOR ||
218 border.draw_masked[GFX_SPECIAL_ARG_EDITOR]))
219 DrawMaskedBorder_Rect(DX, DY, DXSIZE, DYSIZE);
222 void DrawMaskedBorder_DOOR_2()
224 if (border.draw_masked[GFX_SPECIAL_ARG_DOOR] &&
225 game_status != GAME_MODE_EDITOR)
226 DrawMaskedBorder_Rect(VX, VY, VXSIZE, VYSIZE);
229 void DrawMaskedBorder_DOOR_3()
231 /* currently not available */
234 void DrawMaskedBorder_ALL()
236 DrawMaskedBorder_FIELD();
237 DrawMaskedBorder_DOOR_1();
238 DrawMaskedBorder_DOOR_2();
239 DrawMaskedBorder_DOOR_3();
242 void DrawMaskedBorder(int redraw_mask)
244 /* do not draw masked screen borders when displaying title screens */
245 if (effectiveGameStatus() == GAME_MODE_TITLE ||
246 effectiveGameStatus() == GAME_MODE_MESSAGE)
249 if (redraw_mask & REDRAW_ALL)
250 DrawMaskedBorder_ALL();
253 if (redraw_mask & REDRAW_FIELD)
254 DrawMaskedBorder_FIELD();
255 if (redraw_mask & REDRAW_DOOR_1)
256 DrawMaskedBorder_DOOR_1();
257 if (redraw_mask & REDRAW_DOOR_2)
258 DrawMaskedBorder_DOOR_2();
259 if (redraw_mask & REDRAW_DOOR_3)
260 DrawMaskedBorder_DOOR_3();
267 DrawBuffer *buffer = (drawto_field == window ? backbuffer : drawto_field);
269 if (setup.direct_draw && game_status == GAME_MODE_PLAYING)
270 redraw_mask &= ~REDRAW_MAIN;
272 if (redraw_mask & REDRAW_TILES && redraw_tiles > REDRAWTILES_THRESHOLD)
273 redraw_mask |= REDRAW_FIELD;
275 if (redraw_mask & REDRAW_FIELD)
276 redraw_mask &= ~REDRAW_TILES;
278 if (redraw_mask == REDRAW_NONE)
281 if (redraw_mask & REDRAW_TILES &&
282 game_status == GAME_MODE_PLAYING &&
283 border.draw_masked[GAME_MODE_PLAYING])
284 redraw_mask |= REDRAW_FIELD;
286 if (global.fps_slowdown && game_status == GAME_MODE_PLAYING)
288 static boolean last_frame_skipped = FALSE;
289 boolean skip_even_when_not_scrolling = TRUE;
290 boolean just_scrolling = (ScreenMovDir != 0);
291 boolean verbose = FALSE;
293 if (global.fps_slowdown_factor > 1 &&
294 (FrameCounter % global.fps_slowdown_factor) &&
295 (just_scrolling || skip_even_when_not_scrolling))
297 redraw_mask &= ~REDRAW_MAIN;
299 last_frame_skipped = TRUE;
302 printf("FRAME SKIPPED\n");
306 if (last_frame_skipped)
307 redraw_mask |= REDRAW_FIELD;
309 last_frame_skipped = FALSE;
312 printf("frame not skipped\n");
316 /* synchronize X11 graphics at this point; if we would synchronize the
317 display immediately after the buffer switching (after the XFlush),
318 this could mean that we have to wait for the graphics to complete,
319 although we could go on doing calculations for the next frame */
323 /* prevent drawing masked border to backbuffer when using playfield buffer */
324 if (game_status != GAME_MODE_PLAYING ||
325 redraw_mask & REDRAW_FROM_BACKBUFFER ||
326 buffer == backbuffer)
327 DrawMaskedBorder(redraw_mask);
329 DrawMaskedBorder(redraw_mask & REDRAW_DOORS);
331 if (redraw_mask & REDRAW_ALL)
333 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
335 redraw_mask = REDRAW_NONE;
338 if (redraw_mask & REDRAW_FIELD)
340 if (game_status != GAME_MODE_PLAYING ||
341 redraw_mask & REDRAW_FROM_BACKBUFFER)
343 BlitBitmap(backbuffer, window,
344 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE, REAL_SX, REAL_SY);
348 int fx = FX, fy = FY;
350 if (setup.soft_scrolling)
352 fx += (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
353 fy += (ScreenMovDir & (MV_UP | MV_DOWN) ? ScreenGfxPos : 0);
356 if (setup.soft_scrolling ||
357 ABS(ScreenMovPos) + ScrollStepSize == TILEX ||
358 ABS(ScreenMovPos) == ScrollStepSize ||
359 redraw_tiles > REDRAWTILES_THRESHOLD)
361 if (border.draw_masked[GAME_MODE_PLAYING])
363 if (buffer != backbuffer)
365 /* copy playfield buffer to backbuffer to add masked border */
366 BlitBitmap(buffer, backbuffer, fx, fy, SXSIZE, SYSIZE, SX, SY);
367 DrawMaskedBorder(REDRAW_FIELD);
370 BlitBitmap(backbuffer, window,
371 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
376 BlitBitmap(buffer, window, fx, fy, SXSIZE, SYSIZE, SX, SY);
381 printf("redrawing all (ScreenGfxPos == %d) because %s\n",
383 (setup.soft_scrolling ?
384 "setup.soft_scrolling" :
385 ABS(ScreenGfxPos) + ScrollStepSize == TILEX ?
386 "ABS(ScreenGfxPos) + ScrollStepSize == TILEX" :
387 ABS(ScreenGfxPos) == ScrollStepSize ?
388 "ABS(ScreenGfxPos) == ScrollStepSize" :
389 "redraw_tiles > REDRAWTILES_THRESHOLD"));
395 redraw_mask &= ~REDRAW_MAIN;
398 if (redraw_mask & REDRAW_DOORS)
400 if (redraw_mask & REDRAW_DOOR_1)
401 BlitBitmap(backbuffer, window, DX, DY, DXSIZE, DYSIZE, DX, DY);
403 if (redraw_mask & REDRAW_DOOR_2)
404 BlitBitmap(backbuffer, window, VX, VY, VXSIZE, VYSIZE, VX, VY);
406 if (redraw_mask & REDRAW_DOOR_3)
407 BlitBitmap(backbuffer, window, EX, EY, EXSIZE, EYSIZE, EX, EY);
409 redraw_mask &= ~REDRAW_DOORS;
412 if (redraw_mask & REDRAW_MICROLEVEL)
414 BlitBitmap(backbuffer, window, SX, SY + 10 * TILEY, SXSIZE, 7 * TILEY,
415 SX, SY + 10 * TILEY);
417 redraw_mask &= ~REDRAW_MICROLEVEL;
420 if (redraw_mask & REDRAW_TILES)
422 for (x = 0; x < SCR_FIELDX; x++)
423 for (y = 0 ; y < SCR_FIELDY; y++)
424 if (redraw[redraw_x1 + x][redraw_y1 + y])
425 BlitBitmap(buffer, window,
426 FX + x * TILEX, FY + y * TILEY, TILEX, TILEY,
427 SX + x * TILEX, SY + y * TILEY);
430 if (redraw_mask & REDRAW_FPS) /* display frames per second */
435 sprintf(info1, " (only every %d. frame)", global.fps_slowdown_factor);
436 if (!global.fps_slowdown)
439 sprintf(text, "%.1f fps%s", global.frames_per_second, info1);
440 DrawTextExt(window, SX, SY, text, FONT_TEXT_2, BLIT_OPAQUE);
445 for (x = 0; x < MAX_BUF_XSIZE; x++)
446 for (y = 0; y < MAX_BUF_YSIZE; y++)
449 redraw_mask = REDRAW_NONE;
455 long fading_delay = 300;
457 if (setup.fading && (redraw_mask & REDRAW_FIELD))
464 ClearRectangle(window, REAL_SX,REAL_SY,FULL_SXSIZE,FULL_SYSIZE);
467 for (i = 0; i < 2 * FULL_SYSIZE; i++)
469 for (y = 0; y < FULL_SYSIZE; y++)
471 BlitBitmap(backbuffer, window,
472 REAL_SX,REAL_SY+i, FULL_SXSIZE,1, REAL_SX,REAL_SY+i);
480 for (i = 1; i < FULL_SYSIZE; i+=2)
481 BlitBitmap(backbuffer, window,
482 REAL_SX,REAL_SY+i, FULL_SXSIZE,1, REAL_SX,REAL_SY+i);
488 SetClipOrigin(clip_gc[PIX_FADEMASK], 0, 0);
489 BlitBitmapMasked(backbuffer, window,
490 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
495 SetClipOrigin(clip_gc[PIX_FADEMASK], -1, -1);
496 BlitBitmapMasked(backbuffer, window,
497 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
502 SetClipOrigin(clip_gc[PIX_FADEMASK], 0, -1);
503 BlitBitmapMasked(backbuffer, window,
504 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
509 SetClipOrigin(clip_gc[PIX_FADEMASK], -1, 0);
510 BlitBitmapMasked(backbuffer, window,
511 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
516 redraw_mask &= ~REDRAW_MAIN;
523 void FadeExt(int fade_mask, int fade_mode)
525 void (*draw_border_function)(void) = NULL;
526 Bitmap *bitmap = (fade_mode == FADE_MODE_CROSSFADE ? bitmap_db_cross : NULL);
527 int x, y, width, height;
528 int fade_delay, post_delay;
530 if (fade_mask & REDRAW_FIELD)
535 height = FULL_SYSIZE;
537 fade_delay = menu.fade_delay;
538 post_delay = (fade_mode == FADE_MODE_FADE_OUT ? menu.post_delay : 0);
540 draw_border_function = DrawMaskedBorder_FIELD;
542 else /* REDRAW_ALL */
549 fade_delay = title.fade_delay_final;
550 post_delay = (fade_mode == FADE_MODE_FADE_OUT ? title.post_delay_final : 0);
553 redraw_mask |= fade_mask;
555 if (!setup.fade_screens || fade_delay == 0)
557 if (fade_mode == FADE_MODE_FADE_OUT)
558 ClearRectangle(backbuffer, x, y, width, height);
565 FadeRectangle(bitmap, x, y, width, height, fade_mode, fade_delay, post_delay,
566 draw_border_function);
568 redraw_mask &= ~fade_mask;
571 void FadeIn(int fade_mask)
573 FadeExt(fade_mask, FADE_MODE_FADE_IN);
576 void FadeOut(int fade_mask)
578 FadeExt(fade_mask, FADE_MODE_FADE_OUT);
581 void FadeCross(int fade_mask)
583 FadeExt(fade_mask, FADE_MODE_CROSSFADE);
586 void FadeCrossSaveBackbuffer()
588 BlitBitmap(backbuffer, bitmap_db_cross, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
591 void SetWindowBackgroundImageIfDefined(int graphic)
593 if (graphic_info[graphic].bitmap)
594 SetWindowBackgroundBitmap(graphic_info[graphic].bitmap);
597 void SetMainBackgroundImageIfDefined(int graphic)
599 if (graphic_info[graphic].bitmap)
600 SetMainBackgroundBitmap(graphic_info[graphic].bitmap);
603 void SetMainBackgroundImage(int graphic)
605 SetMainBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
606 graphic_info[graphic].bitmap ?
607 graphic_info[graphic].bitmap :
608 graphic_info[IMG_BACKGROUND].bitmap);
611 void SetDoorBackgroundImage(int graphic)
613 SetDoorBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
614 graphic_info[graphic].bitmap ?
615 graphic_info[graphic].bitmap :
616 graphic_info[IMG_BACKGROUND].bitmap);
619 void SetPanelBackground()
621 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, bitmap_db_panel,
622 DOOR_GFX_PAGEX5, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE, 0, 0);
624 SetDoorBackgroundBitmap(bitmap_db_panel);
627 void DrawBackground(int x, int y, int width, int height)
629 /* !!! "drawto" might still point to playfield buffer here (see below) !!! */
630 /* (when entering hall of fame after playing) */
632 ClearRectangleOnBackground(drawto, x, y, width, height);
634 ClearRectangleOnBackground(backbuffer, x, y, width, height);
637 redraw_mask |= REDRAW_FIELD;
640 void DrawBackgroundForFont(int x, int y, int width, int height, int font_nr)
642 struct FontBitmapInfo *font = getFontBitmapInfo(font_nr);
644 if (font->bitmap == NULL)
647 DrawBackground(x, y, width, height);
650 void DrawBackgroundForGraphic(int x, int y, int width, int height, int graphic)
652 struct GraphicInfo *g = &graphic_info[graphic];
654 if (g->bitmap == NULL)
657 DrawBackground(x, y, width, height);
662 /* !!! "drawto" might still point to playfield buffer here (see above) !!! */
663 /* (when entering hall of fame after playing) */
664 DrawBackground(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
666 /* !!! maybe this should be done before clearing the background !!! */
667 if (setup.soft_scrolling && game_status == GAME_MODE_PLAYING)
669 ClearRectangle(fieldbuffer, 0, 0, FXSIZE, FYSIZE);
670 SetDrawtoField(DRAW_BUFFERED);
673 SetDrawtoField(DRAW_BACKBUFFER);
675 if (setup.direct_draw && game_status == GAME_MODE_PLAYING)
677 ClearRectangle(window, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
678 SetDrawtoField(DRAW_DIRECT);
682 void MarkTileDirty(int x, int y)
684 int xx = redraw_x1 + x;
685 int yy = redraw_y1 + y;
690 redraw[xx][yy] = TRUE;
691 redraw_mask |= REDRAW_TILES;
694 void SetBorderElement()
698 BorderElement = EL_EMPTY;
700 for (y = 0; y < lev_fieldy && BorderElement == EL_EMPTY; y++)
702 for (x = 0; x < lev_fieldx; x++)
704 if (!IS_INDESTRUCTIBLE(Feld[x][y]))
705 BorderElement = EL_STEELWALL;
707 if (y != 0 && y != lev_fieldy - 1 && x != lev_fieldx - 1)
713 void FloodFillLevel(int from_x, int from_y, int fill_element,
714 short field[MAX_LEV_FIELDX][MAX_LEV_FIELDY],
715 int max_fieldx, int max_fieldy)
719 static int check[4][2] = { { -1, 0 }, { 0, -1 }, { 1, 0 }, { 0, 1 } };
720 static int safety = 0;
722 /* check if starting field still has the desired content */
723 if (field[from_x][from_y] == fill_element)
728 if (safety > max_fieldx * max_fieldy)
729 Error(ERR_EXIT, "Something went wrong in 'FloodFill()'. Please debug.");
731 old_element = field[from_x][from_y];
732 field[from_x][from_y] = fill_element;
734 for (i = 0; i < 4; i++)
736 x = from_x + check[i][0];
737 y = from_y + check[i][1];
739 if (IN_FIELD(x, y, max_fieldx, max_fieldy) && field[x][y] == old_element)
740 FloodFillLevel(x, y, fill_element, field, max_fieldx, max_fieldy);
746 void SetRandomAnimationValue(int x, int y)
748 gfx.anim_random_frame = GfxRandom[x][y];
751 inline int getGraphicAnimationFrame(int graphic, int sync_frame)
753 /* animation synchronized with global frame counter, not move position */
754 if (graphic_info[graphic].anim_global_sync || sync_frame < 0)
755 sync_frame = FrameCounter;
757 return getAnimationFrame(graphic_info[graphic].anim_frames,
758 graphic_info[graphic].anim_delay,
759 graphic_info[graphic].anim_mode,
760 graphic_info[graphic].anim_start_frame,
764 inline void getGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
765 int *x, int *y, boolean get_backside)
767 struct GraphicInfo *g = &graphic_info[graphic];
768 int src_x = g->src_x + (get_backside ? g->offset2_x : 0);
769 int src_y = g->src_y + (get_backside ? g->offset2_y : 0);
773 if (g->offset_y == 0) /* frames are ordered horizontally */
775 int max_width = g->anim_frames_per_line * g->width;
776 int pos = (src_y / g->height) * max_width + src_x + frame * g->offset_x;
778 *x = pos % max_width;
779 *y = src_y % g->height + pos / max_width * g->height;
781 else if (g->offset_x == 0) /* frames are ordered vertically */
783 int max_height = g->anim_frames_per_line * g->height;
784 int pos = (src_x / g->width) * max_height + src_y + frame * g->offset_y;
786 *x = src_x % g->width + pos / max_height * g->width;
787 *y = pos % max_height;
789 else /* frames are ordered diagonally */
791 *x = src_x + frame * g->offset_x;
792 *y = src_y + frame * g->offset_y;
796 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
798 getGraphicSourceExt(graphic, frame, bitmap, x, y, FALSE);
801 void DrawGraphic(int x, int y, int graphic, int frame)
804 if (!IN_SCR_FIELD(x, y))
806 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
807 printf("DrawGraphic(): This should never happen!\n");
812 DrawGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic, frame);
816 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
822 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
823 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
826 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
829 if (!IN_SCR_FIELD(x, y))
831 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
832 printf("DrawGraphicThruMask(): This should never happen!\n");
837 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y *TILEY, graphic,
842 void DrawGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y, int graphic,
848 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
850 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
851 dst_x - src_x, dst_y - src_y);
852 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dst_x, dst_y);
855 void DrawMiniGraphic(int x, int y, int graphic)
857 DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
858 MarkTileDirty(x / 2, y / 2);
861 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
863 struct GraphicInfo *g = &graphic_info[graphic];
865 int mini_starty = g->bitmap->height * 2 / 3;
868 *x = mini_startx + g->src_x / 2;
869 *y = mini_starty + g->src_y / 2;
872 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
877 getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
878 BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
881 inline static void DrawGraphicShiftedNormal(int x, int y, int dx, int dy,
882 int graphic, int frame,
883 int cut_mode, int mask_mode)
888 int width = TILEX, height = TILEY;
891 if (dx || dy) /* shifted graphic */
893 if (x < BX1) /* object enters playfield from the left */
900 else if (x > BX2) /* object enters playfield from the right */
906 else if (x==BX1 && dx < 0) /* object leaves playfield to the left */
912 else if (x==BX2 && dx > 0) /* object leaves playfield to the right */
914 else if (dx) /* general horizontal movement */
915 MarkTileDirty(x + SIGN(dx), y);
917 if (y < BY1) /* object enters playfield from the top */
919 if (cut_mode==CUT_BELOW) /* object completely above top border */
927 else if (y > BY2) /* object enters playfield from the bottom */
933 else if (y==BY1 && dy < 0) /* object leaves playfield to the top */
939 else if (dy > 0 && cut_mode == CUT_ABOVE)
941 if (y == BY2) /* object completely above bottom border */
947 MarkTileDirty(x, y + 1);
948 } /* object leaves playfield to the bottom */
949 else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
951 else if (dy) /* general vertical movement */
952 MarkTileDirty(x, y + SIGN(dy));
956 if (!IN_SCR_FIELD(x, y))
958 printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
959 printf("DrawGraphicShifted(): This should never happen!\n");
964 if (width > 0 && height > 0)
966 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
971 dst_x = FX + x * TILEX + dx;
972 dst_y = FY + y * TILEY + dy;
974 if (mask_mode == USE_MASKING)
976 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
977 dst_x - src_x, dst_y - src_y);
978 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
982 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
989 inline static void DrawGraphicShiftedDouble(int x, int y, int dx, int dy,
990 int graphic, int frame,
991 int cut_mode, int mask_mode)
996 int width = TILEX, height = TILEY;
999 int x2 = x + SIGN(dx);
1000 int y2 = y + SIGN(dy);
1001 int anim_frames = graphic_info[graphic].anim_frames;
1002 int sync_frame = (dx ? ABS(dx) : ABS(dy)) * anim_frames / TILESIZE;
1003 boolean draw_start_tile = (cut_mode != CUT_ABOVE); /* only for falling! */
1004 boolean draw_end_tile = (cut_mode != CUT_BELOW); /* only for falling! */
1006 /* re-calculate animation frame for two-tile movement animation */
1007 frame = getGraphicAnimationFrame(graphic, sync_frame);
1009 /* check if movement start graphic inside screen area and should be drawn */
1010 if (draw_start_tile && IN_SCR_FIELD(x1, y1))
1012 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, TRUE);
1014 dst_x = FX + x1 * TILEX;
1015 dst_y = FY + y1 * TILEY;
1017 if (mask_mode == USE_MASKING)
1019 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1020 dst_x - src_x, dst_y - src_y);
1021 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1025 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1028 MarkTileDirty(x1, y1);
1031 /* check if movement end graphic inside screen area and should be drawn */
1032 if (draw_end_tile && IN_SCR_FIELD(x2, y2))
1034 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
1036 dst_x = FX + x2 * TILEX;
1037 dst_y = FY + y2 * TILEY;
1039 if (mask_mode == USE_MASKING)
1041 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1042 dst_x - src_x, dst_y - src_y);
1043 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1047 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1050 MarkTileDirty(x2, y2);
1054 static void DrawGraphicShifted(int x, int y, int dx, int dy,
1055 int graphic, int frame,
1056 int cut_mode, int mask_mode)
1060 DrawGraphic(x, y, graphic, frame);
1065 if (graphic_info[graphic].double_movement) /* EM style movement images */
1066 DrawGraphicShiftedDouble(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1068 DrawGraphicShiftedNormal(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1071 void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
1072 int frame, int cut_mode)
1074 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, USE_MASKING);
1077 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
1078 int cut_mode, int mask_mode)
1080 int lx = LEVELX(x), ly = LEVELY(y);
1084 if (IN_LEV_FIELD(lx, ly))
1086 SetRandomAnimationValue(lx, ly);
1088 graphic = el_act_dir2img(element, GfxAction[lx][ly], GfxDir[lx][ly]);
1089 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1091 /* do not use double (EM style) movement graphic when not moving */
1092 if (graphic_info[graphic].double_movement && !dx && !dy)
1094 graphic = el_act_dir2img(element, ACTION_DEFAULT, GfxDir[lx][ly]);
1095 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1098 else /* border element */
1100 graphic = el2img(element);
1101 frame = getGraphicAnimationFrame(graphic, -1);
1104 if (element == EL_EXPANDABLE_WALL)
1106 boolean left_stopped = FALSE, right_stopped = FALSE;
1108 if (!IN_LEV_FIELD(lx - 1, ly) || IS_WALL(Feld[lx - 1][ly]))
1109 left_stopped = TRUE;
1110 if (!IN_LEV_FIELD(lx + 1, ly) || IS_WALL(Feld[lx + 1][ly]))
1111 right_stopped = TRUE;
1113 if (left_stopped && right_stopped)
1115 else if (left_stopped)
1117 graphic = IMG_EXPANDABLE_WALL_GROWING_RIGHT;
1118 frame = graphic_info[graphic].anim_frames - 1;
1120 else if (right_stopped)
1122 graphic = IMG_EXPANDABLE_WALL_GROWING_LEFT;
1123 frame = graphic_info[graphic].anim_frames - 1;
1128 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
1129 else if (mask_mode == USE_MASKING)
1130 DrawGraphicThruMask(x, y, graphic, frame);
1132 DrawGraphic(x, y, graphic, frame);
1135 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
1136 int cut_mode, int mask_mode)
1138 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1139 DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
1140 cut_mode, mask_mode);
1143 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
1146 DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1149 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
1152 DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1155 void DrawLevelElementThruMask(int x, int y, int element)
1157 DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1160 void DrawLevelFieldThruMask(int x, int y)
1162 DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
1165 static void DrawLevelFieldCrumbledSandExt(int x, int y, int graphic, int frame)
1169 int sx = SCREENX(x), sy = SCREENY(y);
1171 int width, height, cx, cy, i;
1172 int crumbled_border_size = graphic_info[graphic].border_size;
1173 static int xy[4][2] =
1181 if (!IN_LEV_FIELD(x, y))
1184 element = TILE_GFX_ELEMENT(x, y);
1186 /* crumble field itself */
1187 if (GFX_CRUMBLED(element) && !IS_MOVING(x, y))
1189 if (!IN_SCR_FIELD(sx, sy))
1192 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1194 for (i = 0; i < 4; i++)
1196 int xx = x + xy[i][0];
1197 int yy = y + xy[i][1];
1199 element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1202 /* check if neighbour field is of same type */
1203 if (GFX_CRUMBLED(element) && !IS_MOVING(xx, yy))
1206 if (i == 1 || i == 2)
1208 width = crumbled_border_size;
1210 cx = (i == 2 ? TILEX - crumbled_border_size : 0);
1216 height = crumbled_border_size;
1218 cy = (i == 3 ? TILEY - crumbled_border_size : 0);
1221 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1222 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
1225 MarkTileDirty(sx, sy);
1227 else /* crumble neighbour fields */
1229 for (i = 0; i < 4; i++)
1231 int xx = x + xy[i][0];
1232 int yy = y + xy[i][1];
1233 int sxx = sx + xy[i][0];
1234 int syy = sy + xy[i][1];
1236 if (!IN_LEV_FIELD(xx, yy) ||
1237 !IN_SCR_FIELD(sxx, syy) ||
1241 if (Feld[xx][yy] == EL_ELEMENT_SNAPPING)
1244 element = TILE_GFX_ELEMENT(xx, yy);
1246 if (!GFX_CRUMBLED(element))
1249 graphic = el_act2crm(element, ACTION_DEFAULT);
1250 crumbled_border_size = graphic_info[graphic].border_size;
1252 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1254 if (i == 1 || i == 2)
1256 width = crumbled_border_size;
1258 cx = (i == 1 ? TILEX - crumbled_border_size : 0);
1264 height = crumbled_border_size;
1266 cy = (i == 0 ? TILEY - crumbled_border_size : 0);
1269 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1270 width, height, FX + sxx * TILEX + cx, FY + syy * TILEY + cy);
1272 MarkTileDirty(sxx, syy);
1277 void DrawLevelFieldCrumbledSand(int x, int y)
1281 if (!IN_LEV_FIELD(x, y))
1285 /* !!! CHECK THIS !!! */
1288 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
1289 GFX_CRUMBLED(GfxElement[x][y]))
1292 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
1293 GfxElement[x][y] != EL_UNDEFINED &&
1294 GFX_CRUMBLED(GfxElement[x][y]))
1296 DrawLevelFieldCrumbledSandDigging(x, y, GfxDir[x][y], GfxFrame[x][y]);
1303 graphic = el_act2crm(TILE_GFX_ELEMENT(x, y), ACTION_DEFAULT);
1305 graphic = el_act2crm(Feld[x][y], ACTION_DEFAULT);
1308 DrawLevelFieldCrumbledSandExt(x, y, graphic, 0);
1311 void DrawLevelFieldCrumbledSandDigging(int x, int y, int direction,
1314 int graphic1 = el_act_dir2img(GfxElement[x][y], ACTION_DIGGING, direction);
1315 int graphic2 = el_act_dir2crm(GfxElement[x][y], ACTION_DIGGING, direction);
1316 int frame1 = getGraphicAnimationFrame(graphic1, step_frame);
1317 int frame2 = getGraphicAnimationFrame(graphic2, step_frame);
1318 int sx = SCREENX(x), sy = SCREENY(y);
1320 DrawGraphic(sx, sy, graphic1, frame1);
1321 DrawLevelFieldCrumbledSandExt(x, y, graphic2, frame2);
1324 void DrawLevelFieldCrumbledSandNeighbours(int x, int y)
1326 int sx = SCREENX(x), sy = SCREENY(y);
1327 static int xy[4][2] =
1336 for (i = 0; i < 4; i++)
1338 int xx = x + xy[i][0];
1339 int yy = y + xy[i][1];
1340 int sxx = sx + xy[i][0];
1341 int syy = sy + xy[i][1];
1343 if (!IN_LEV_FIELD(xx, yy) ||
1344 !IN_SCR_FIELD(sxx, syy) ||
1345 !GFX_CRUMBLED(Feld[xx][yy]) ||
1349 DrawLevelField(xx, yy);
1353 static int getBorderElement(int x, int y)
1357 { EL_STEELWALL_TOPLEFT, EL_INVISIBLE_STEELWALL_TOPLEFT },
1358 { EL_STEELWALL_TOPRIGHT, EL_INVISIBLE_STEELWALL_TOPRIGHT },
1359 { EL_STEELWALL_BOTTOMLEFT, EL_INVISIBLE_STEELWALL_BOTTOMLEFT },
1360 { EL_STEELWALL_BOTTOMRIGHT, EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
1361 { EL_STEELWALL_VERTICAL, EL_INVISIBLE_STEELWALL_VERTICAL },
1362 { EL_STEELWALL_HORIZONTAL, EL_INVISIBLE_STEELWALL_HORIZONTAL },
1363 { EL_STEELWALL, EL_INVISIBLE_STEELWALL }
1365 int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
1366 int steel_position = (x == -1 && y == -1 ? 0 :
1367 x == lev_fieldx && y == -1 ? 1 :
1368 x == -1 && y == lev_fieldy ? 2 :
1369 x == lev_fieldx && y == lev_fieldy ? 3 :
1370 x == -1 || x == lev_fieldx ? 4 :
1371 y == -1 || y == lev_fieldy ? 5 : 6);
1373 return border[steel_position][steel_type];
1376 void DrawScreenElement(int x, int y, int element)
1378 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
1379 DrawLevelFieldCrumbledSand(LEVELX(x), LEVELY(y));
1382 void DrawLevelElement(int x, int y, int element)
1384 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1385 DrawScreenElement(SCREENX(x), SCREENY(y), element);
1388 void DrawScreenField(int x, int y)
1390 int lx = LEVELX(x), ly = LEVELY(y);
1391 int element, content;
1393 if (!IN_LEV_FIELD(lx, ly))
1395 if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
1398 element = getBorderElement(lx, ly);
1400 DrawScreenElement(x, y, element);
1404 element = Feld[lx][ly];
1405 content = Store[lx][ly];
1407 if (IS_MOVING(lx, ly))
1409 int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
1410 boolean cut_mode = NO_CUTTING;
1412 if (element == EL_QUICKSAND_EMPTYING ||
1413 element == EL_QUICKSAND_FAST_EMPTYING ||
1414 element == EL_MAGIC_WALL_EMPTYING ||
1415 element == EL_BD_MAGIC_WALL_EMPTYING ||
1416 element == EL_DC_MAGIC_WALL_EMPTYING ||
1417 element == EL_AMOEBA_DROPPING)
1418 cut_mode = CUT_ABOVE;
1419 else if (element == EL_QUICKSAND_FILLING ||
1420 element == EL_QUICKSAND_FAST_FILLING ||
1421 element == EL_MAGIC_WALL_FILLING ||
1422 element == EL_BD_MAGIC_WALL_FILLING ||
1423 element == EL_DC_MAGIC_WALL_FILLING)
1424 cut_mode = CUT_BELOW;
1426 if (cut_mode == CUT_ABOVE)
1427 DrawScreenElementShifted(x, y, 0, 0, element, NO_CUTTING);
1429 DrawScreenElement(x, y, EL_EMPTY);
1432 DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
1433 else if (cut_mode == NO_CUTTING)
1434 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
1436 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
1438 if (content == EL_ACID)
1440 int dir = MovDir[lx][ly];
1441 int newlx = lx + (dir == MV_LEFT ? -1 : dir == MV_RIGHT ? +1 : 0);
1442 int newly = ly + (dir == MV_UP ? -1 : dir == MV_DOWN ? +1 : 0);
1444 DrawLevelElementThruMask(newlx, newly, EL_ACID);
1447 else if (IS_BLOCKED(lx, ly))
1452 boolean cut_mode = NO_CUTTING;
1453 int element_old, content_old;
1455 Blocked2Moving(lx, ly, &oldx, &oldy);
1458 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
1459 MovDir[oldx][oldy] == MV_RIGHT);
1461 element_old = Feld[oldx][oldy];
1462 content_old = Store[oldx][oldy];
1464 if (element_old == EL_QUICKSAND_EMPTYING ||
1465 element_old == EL_QUICKSAND_FAST_EMPTYING ||
1466 element_old == EL_MAGIC_WALL_EMPTYING ||
1467 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
1468 element_old == EL_DC_MAGIC_WALL_EMPTYING ||
1469 element_old == EL_AMOEBA_DROPPING)
1470 cut_mode = CUT_ABOVE;
1472 DrawScreenElement(x, y, EL_EMPTY);
1475 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
1477 else if (cut_mode == NO_CUTTING)
1478 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
1481 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
1484 else if (IS_DRAWABLE(element))
1485 DrawScreenElement(x, y, element);
1487 DrawScreenElement(x, y, EL_EMPTY);
1490 void DrawLevelField(int x, int y)
1492 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1493 DrawScreenField(SCREENX(x), SCREENY(y));
1494 else if (IS_MOVING(x, y))
1498 Moving2Blocked(x, y, &newx, &newy);
1499 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
1500 DrawScreenField(SCREENX(newx), SCREENY(newy));
1502 else if (IS_BLOCKED(x, y))
1506 Blocked2Moving(x, y, &oldx, &oldy);
1507 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
1508 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
1512 void DrawMiniElement(int x, int y, int element)
1516 graphic = el2edimg(element);
1517 DrawMiniGraphic(x, y, graphic);
1520 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
1522 int x = sx + scroll_x, y = sy + scroll_y;
1524 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
1525 DrawMiniElement(sx, sy, EL_EMPTY);
1526 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
1527 DrawMiniElement(sx, sy, Feld[x][y]);
1529 DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
1532 void DrawEnvelopeBackground(int envelope_nr, int startx, int starty,
1533 int x, int y, int xsize, int ysize, int font_nr)
1535 int font_width = getFontWidth(font_nr);
1536 int font_height = getFontHeight(font_nr);
1537 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1540 int dst_x = SX + startx + x * font_width;
1541 int dst_y = SY + starty + y * font_height;
1542 int width = graphic_info[graphic].width;
1543 int height = graphic_info[graphic].height;
1544 int inner_width = MAX(width - 2 * font_width, font_width);
1545 int inner_height = MAX(height - 2 * font_height, font_height);
1546 int inner_sx = (width >= 3 * font_width ? font_width : 0);
1547 int inner_sy = (height >= 3 * font_height ? font_height : 0);
1548 boolean draw_masked = graphic_info[graphic].draw_masked;
1550 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1552 if (src_bitmap == NULL || width < font_width || height < font_height)
1554 ClearRectangle(drawto, dst_x, dst_y, font_width, font_height);
1558 src_x += (x == 0 ? 0 : x == xsize - 1 ? width - font_width :
1559 inner_sx + (x - 1) * font_width % inner_width);
1560 src_y += (y == 0 ? 0 : y == ysize - 1 ? height - font_height :
1561 inner_sy + (y - 1) * font_height % inner_height);
1565 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1566 dst_x - src_x, dst_y - src_y);
1567 BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1571 BlitBitmap(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1575 void AnimateEnvelope(int envelope_nr, int anim_mode, int action)
1577 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1578 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1579 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
1580 boolean ffwd_delay = (tape.playing && tape.fast_forward);
1581 boolean no_delay = (tape.warp_forward);
1582 unsigned long anim_delay = 0;
1583 int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
1584 int anim_delay_value = (no_delay ? 0 : frame_delay_value);
1585 int font_nr = FONT_ENVELOPE_1 + envelope_nr;
1586 int font_width = getFontWidth(font_nr);
1587 int font_height = getFontHeight(font_nr);
1588 int max_xsize = level.envelope[envelope_nr].xsize;
1589 int max_ysize = level.envelope[envelope_nr].ysize;
1590 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
1591 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
1592 int xend = max_xsize;
1593 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
1594 int xstep = (xstart < xend ? 1 : 0);
1595 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
1598 for (x = xstart, y = ystart; x <= xend && y <= yend; x += xstep, y += ystep)
1600 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
1601 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
1602 int sx = (SXSIZE - xsize * font_width) / 2;
1603 int sy = (SYSIZE - ysize * font_height) / 2;
1606 SetDrawtoField(DRAW_BUFFERED);
1608 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
1610 SetDrawtoField(DRAW_BACKBUFFER);
1612 for (yy = 0; yy < ysize; yy++) for (xx = 0; xx < xsize; xx++)
1613 DrawEnvelopeBackground(envelope_nr, sx,sy, xx,yy, xsize, ysize, font_nr);
1615 DrawTextToTextArea(SX + sx + font_width, SY + sy + font_height,
1616 level.envelope[envelope_nr].text, font_nr, max_xsize,
1617 xsize - 2, ysize - 2, mask_mode);
1619 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
1622 WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
1626 void ShowEnvelope(int envelope_nr)
1628 int element = EL_ENVELOPE_1 + envelope_nr;
1629 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1630 int sound_opening = element_info[element].sound[ACTION_OPENING];
1631 int sound_closing = element_info[element].sound[ACTION_CLOSING];
1632 boolean ffwd_delay = (tape.playing && tape.fast_forward);
1633 boolean no_delay = (tape.warp_forward);
1634 int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
1635 int wait_delay_value = (no_delay ? 0 : normal_delay_value);
1636 int anim_mode = graphic_info[graphic].anim_mode;
1637 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
1638 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
1640 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
1642 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
1644 if (anim_mode == ANIM_DEFAULT)
1645 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_OPENING);
1647 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_OPENING);
1650 Delay(wait_delay_value);
1652 WaitForEventToContinue();
1654 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
1656 if (anim_mode != ANIM_NONE)
1657 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_CLOSING);
1659 if (anim_mode == ANIM_DEFAULT)
1660 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_CLOSING);
1662 game.envelope_active = FALSE;
1664 SetDrawtoField(DRAW_BUFFERED);
1666 redraw_mask |= REDRAW_FIELD;
1670 void getPreviewGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y,
1675 int width_mult, width_div;
1676 int height_mult, height_div;
1684 int offset_calc_pos = (tilesize < MICRO_TILESIZE || tilesize > TILESIZE ? 3 :
1685 5 - log_2(tilesize));
1686 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1687 int width_mult = offset_calc[offset_calc_pos].width_mult;
1688 int width_div = offset_calc[offset_calc_pos].width_div;
1689 int height_mult = offset_calc[offset_calc_pos].height_mult;
1690 int height_div = offset_calc[offset_calc_pos].height_div;
1691 int mini_startx = src_bitmap->width * width_mult / width_div;
1692 int mini_starty = src_bitmap->height * height_mult / height_div;
1693 int src_x = mini_startx + graphic_info[graphic].src_x * tilesize / TILESIZE;
1694 int src_y = mini_starty + graphic_info[graphic].src_y * tilesize / TILESIZE;
1696 *bitmap = src_bitmap;
1701 void DrawPreviewElement(int dst_x, int dst_y, int element, int tilesize)
1705 int graphic = el2preimg(element);
1707 getPreviewGraphicSource(graphic, &src_bitmap, &src_x, &src_y, tilesize);
1708 BlitBitmap(src_bitmap, drawto, src_x, src_y, tilesize, tilesize, dst_x,dst_y);
1715 SetDrawBackgroundMask(REDRAW_NONE);
1718 for (x = BX1; x <= BX2; x++)
1719 for (y = BY1; y <= BY2; y++)
1720 DrawScreenField(x, y);
1722 redraw_mask |= REDRAW_FIELD;
1725 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
1729 for (x = 0; x < size_x; x++)
1730 for (y = 0; y < size_y; y++)
1731 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
1733 redraw_mask |= REDRAW_FIELD;
1736 static void DrawPreviewLevelExt(int from_x, int from_y)
1738 boolean show_level_border = (BorderElement != EL_EMPTY);
1739 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
1740 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
1741 int tile_size = preview.tile_size;
1742 int preview_width = preview.xsize * tile_size;
1743 int preview_height = preview.ysize * tile_size;
1744 int real_preview_xsize = MIN(level_xsize, preview.xsize);
1745 int real_preview_ysize = MIN(level_ysize, preview.ysize);
1746 int dst_x = SX + ALIGNED_XPOS(preview.x, preview_width, preview.align);
1747 int dst_y = SY + preview.y;
1750 DrawBackground(dst_x, dst_y, preview_width, preview_height);
1752 dst_x += (preview_width - real_preview_xsize * tile_size) / 2;
1753 dst_y += (preview_height - real_preview_ysize * tile_size) / 2;
1755 for (x = 0; x < real_preview_xsize; x++)
1757 for (y = 0; y < real_preview_ysize; y++)
1759 int lx = from_x + x + (show_level_border ? -1 : 0);
1760 int ly = from_y + y + (show_level_border ? -1 : 0);
1761 int element = (IN_LEV_FIELD(lx, ly) ? level.field[lx][ly] :
1762 getBorderElement(lx, ly));
1764 DrawPreviewElement(dst_x + x * tile_size, dst_y + y * tile_size,
1765 element, tile_size);
1769 redraw_mask |= REDRAW_MICROLEVEL;
1772 #define MICROLABEL_EMPTY 0
1773 #define MICROLABEL_LEVEL_NAME 1
1774 #define MICROLABEL_LEVEL_AUTHOR_HEAD 2
1775 #define MICROLABEL_LEVEL_AUTHOR 3
1776 #define MICROLABEL_IMPORTED_FROM_HEAD 4
1777 #define MICROLABEL_IMPORTED_FROM 5
1778 #define MICROLABEL_IMPORTED_BY_HEAD 6
1779 #define MICROLABEL_IMPORTED_BY 7
1781 static int getMaxTextLength(struct MenuPosInfo *pos, int font_nr)
1783 int max_text_width = SXSIZE;
1784 int font_width = getFontWidth(font_nr);
1786 if (pos->align == ALIGN_CENTER)
1787 max_text_width = (pos->x < SXSIZE / 2 ? pos->x * 2 : (SXSIZE - pos->x) * 2);
1788 else if (pos->align == ALIGN_RIGHT)
1789 max_text_width = pos->x;
1791 max_text_width = SXSIZE - pos->x;
1793 return max_text_width / font_width;
1796 static void DrawPreviewLevelLabelExt(int mode)
1798 struct MenuPosInfo *pos = &menu.main.text.level_info_2;
1799 char label_text[MAX_OUTPUT_LINESIZE + 1];
1800 int max_len_label_text;
1801 int font_nr = FONT_TEXT_2;
1804 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
1805 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
1806 mode == MICROLABEL_IMPORTED_BY_HEAD)
1807 font_nr = FONT_TEXT_3;
1810 max_len_label_text = getMaxTextLength(pos, font_nr);
1812 max_len_label_text = SXSIZE / getFontWidth(font_nr);
1815 for (i = 0; i < max_len_label_text; i++)
1816 label_text[i] = ' ';
1817 label_text[max_len_label_text] = '\0';
1819 if (strlen(label_text) > 0)
1822 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
1824 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
1825 int lypos = MICROLABEL2_YPOS;
1827 DrawText(lxpos, lypos, label_text, font_nr);
1832 (mode == MICROLABEL_LEVEL_NAME ? level.name :
1833 mode == MICROLABEL_LEVEL_AUTHOR_HEAD ? "created by" :
1834 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
1835 mode == MICROLABEL_IMPORTED_FROM_HEAD ? "imported from" :
1836 mode == MICROLABEL_IMPORTED_FROM ? leveldir_current->imported_from :
1837 mode == MICROLABEL_IMPORTED_BY_HEAD ? "imported by" :
1838 mode == MICROLABEL_IMPORTED_BY ? leveldir_current->imported_by :""),
1839 max_len_label_text);
1840 label_text[max_len_label_text] = '\0';
1842 if (strlen(label_text) > 0)
1845 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
1847 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
1848 int lypos = MICROLABEL2_YPOS;
1850 DrawText(lxpos, lypos, label_text, font_nr);
1854 redraw_mask |= REDRAW_MICROLEVEL;
1857 void DrawPreviewLevel(boolean restart)
1859 static unsigned long scroll_delay = 0;
1860 static unsigned long label_delay = 0;
1861 static int from_x, from_y, scroll_direction;
1862 static int label_state, label_counter;
1863 unsigned long scroll_delay_value = preview.step_delay;
1864 boolean show_level_border = (BorderElement != EL_EMPTY);
1865 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
1866 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
1867 int last_game_status = game_status; /* save current game status */
1869 /* force PREVIEW font on preview level */
1870 game_status = GAME_MODE_PSEUDO_PREVIEW;
1877 if (preview.anim_mode == ANIM_CENTERED)
1879 if (level_xsize > preview.xsize)
1880 from_x = (level_xsize - preview.xsize) / 2;
1881 if (level_ysize > preview.ysize)
1882 from_y = (level_ysize - preview.ysize) / 2;
1885 from_x += preview.xoffset;
1886 from_y += preview.yoffset;
1888 scroll_direction = MV_RIGHT;
1892 DrawPreviewLevelExt(from_x, from_y);
1893 DrawPreviewLevelLabelExt(label_state);
1895 /* initialize delay counters */
1896 DelayReached(&scroll_delay, 0);
1897 DelayReached(&label_delay, 0);
1899 if (leveldir_current->name)
1901 struct MenuPosInfo *pos = &menu.main.text.level_info_1;
1902 char label_text[MAX_OUTPUT_LINESIZE + 1];
1903 int font_nr = FONT_TEXT_1;
1905 int max_len_label_text = getMaxTextLength(pos, font_nr);
1907 int max_len_label_text = SXSIZE / getFontWidth(font_nr);
1914 strncpy(label_text, leveldir_current->name, max_len_label_text);
1915 label_text[max_len_label_text] = '\0';
1918 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
1920 lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
1921 lypos = SY + MICROLABEL1_YPOS;
1923 DrawText(lxpos, lypos, label_text, font_nr);
1927 game_status = last_game_status; /* restore current game status */
1932 /* scroll preview level, if needed */
1933 if (preview.anim_mode != ANIM_NONE &&
1934 (level_xsize > preview.xsize || level_ysize > preview.ysize) &&
1935 DelayReached(&scroll_delay, scroll_delay_value))
1937 switch (scroll_direction)
1942 from_x -= preview.step_offset;
1943 from_x = (from_x < 0 ? 0 : from_x);
1946 scroll_direction = MV_UP;
1950 if (from_x < level_xsize - preview.xsize)
1952 from_x += preview.step_offset;
1953 from_x = (from_x > level_xsize - preview.xsize ?
1954 level_xsize - preview.xsize : from_x);
1957 scroll_direction = MV_DOWN;
1963 from_y -= preview.step_offset;
1964 from_y = (from_y < 0 ? 0 : from_y);
1967 scroll_direction = MV_RIGHT;
1971 if (from_y < level_ysize - preview.ysize)
1973 from_y += preview.step_offset;
1974 from_y = (from_y > level_ysize - preview.ysize ?
1975 level_ysize - preview.ysize : from_y);
1978 scroll_direction = MV_LEFT;
1985 DrawPreviewLevelExt(from_x, from_y);
1988 /* !!! THIS ALL SUCKS -- SHOULD BE CLEANLY REWRITTEN !!! */
1989 /* redraw micro level label, if needed */
1990 if (!strEqual(level.name, NAMELESS_LEVEL_NAME) &&
1991 !strEqual(level.author, ANONYMOUS_NAME) &&
1992 !strEqual(level.author, leveldir_current->name) &&
1993 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
1995 int max_label_counter = 23;
1997 if (leveldir_current->imported_from != NULL &&
1998 strlen(leveldir_current->imported_from) > 0)
1999 max_label_counter += 14;
2000 if (leveldir_current->imported_by != NULL &&
2001 strlen(leveldir_current->imported_by) > 0)
2002 max_label_counter += 14;
2004 label_counter = (label_counter + 1) % max_label_counter;
2005 label_state = (label_counter >= 0 && label_counter <= 7 ?
2006 MICROLABEL_LEVEL_NAME :
2007 label_counter >= 9 && label_counter <= 12 ?
2008 MICROLABEL_LEVEL_AUTHOR_HEAD :
2009 label_counter >= 14 && label_counter <= 21 ?
2010 MICROLABEL_LEVEL_AUTHOR :
2011 label_counter >= 23 && label_counter <= 26 ?
2012 MICROLABEL_IMPORTED_FROM_HEAD :
2013 label_counter >= 28 && label_counter <= 35 ?
2014 MICROLABEL_IMPORTED_FROM :
2015 label_counter >= 37 && label_counter <= 40 ?
2016 MICROLABEL_IMPORTED_BY_HEAD :
2017 label_counter >= 42 && label_counter <= 49 ?
2018 MICROLABEL_IMPORTED_BY : MICROLABEL_EMPTY);
2020 if (leveldir_current->imported_from == NULL &&
2021 (label_state == MICROLABEL_IMPORTED_FROM_HEAD ||
2022 label_state == MICROLABEL_IMPORTED_FROM))
2023 label_state = (label_state == MICROLABEL_IMPORTED_FROM_HEAD ?
2024 MICROLABEL_IMPORTED_BY_HEAD : MICROLABEL_IMPORTED_BY);
2026 DrawPreviewLevelLabelExt(label_state);
2029 game_status = last_game_status; /* restore current game status */
2032 inline void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
2033 int graphic, int sync_frame, int mask_mode)
2035 int frame = getGraphicAnimationFrame(graphic, sync_frame);
2037 if (mask_mode == USE_MASKING)
2038 DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
2040 DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
2043 inline void DrawGraphicAnimation(int x, int y, int graphic)
2045 int lx = LEVELX(x), ly = LEVELY(y);
2047 if (!IN_SCR_FIELD(x, y))
2050 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
2051 graphic, GfxFrame[lx][ly], NO_MASKING);
2052 MarkTileDirty(x, y);
2055 void DrawLevelGraphicAnimation(int x, int y, int graphic)
2057 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
2060 void DrawLevelElementAnimation(int x, int y, int element)
2062 int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
2064 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
2067 inline void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
2069 int sx = SCREENX(x), sy = SCREENY(y);
2071 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
2074 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
2077 DrawGraphicAnimation(sx, sy, graphic);
2080 if (GFX_CRUMBLED(TILE_GFX_ELEMENT(x, y)))
2081 DrawLevelFieldCrumbledSand(x, y);
2083 if (GFX_CRUMBLED(Feld[x][y]))
2084 DrawLevelFieldCrumbledSand(x, y);
2088 void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
2090 int sx = SCREENX(x), sy = SCREENY(y);
2093 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
2096 graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
2098 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
2101 DrawGraphicAnimation(sx, sy, graphic);
2103 if (GFX_CRUMBLED(element))
2104 DrawLevelFieldCrumbledSand(x, y);
2107 static int getPlayerGraphic(struct PlayerInfo *player, int move_dir)
2109 if (player->use_murphy)
2111 /* this works only because currently only one player can be "murphy" ... */
2112 static int last_horizontal_dir = MV_LEFT;
2113 int graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir);
2115 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
2116 last_horizontal_dir = move_dir;
2118 if (graphic == IMG_SP_MURPHY) /* undefined => use special graphic */
2120 int direction = (player->is_snapping ? move_dir : last_horizontal_dir);
2122 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
2128 return el_act_dir2img(player->artwork_element, player->GfxAction,move_dir);
2131 static boolean equalGraphics(int graphic1, int graphic2)
2133 struct GraphicInfo *g1 = &graphic_info[graphic1];
2134 struct GraphicInfo *g2 = &graphic_info[graphic2];
2136 return (g1->bitmap == g2->bitmap &&
2137 g1->src_x == g2->src_x &&
2138 g1->src_y == g2->src_y &&
2139 g1->anim_frames == g2->anim_frames &&
2140 g1->anim_delay == g2->anim_delay &&
2141 g1->anim_mode == g2->anim_mode);
2144 void DrawAllPlayers()
2148 for (i = 0; i < MAX_PLAYERS; i++)
2149 if (stored_player[i].active)
2150 DrawPlayer(&stored_player[i]);
2153 void DrawPlayerField(int x, int y)
2155 if (!IS_PLAYER(x, y))
2158 DrawPlayer(PLAYERINFO(x, y));
2161 void DrawPlayer(struct PlayerInfo *player)
2163 int jx = player->jx;
2164 int jy = player->jy;
2165 int move_dir = player->MovDir;
2166 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? +1 : 0);
2167 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? +1 : 0);
2168 int last_jx = (player->is_moving ? jx - dx : jx);
2169 int last_jy = (player->is_moving ? jy - dy : jy);
2170 int next_jx = jx + dx;
2171 int next_jy = jy + dy;
2172 boolean player_is_moving = (player->MovPos ? TRUE : FALSE);
2173 boolean player_is_opaque = FALSE;
2174 int sx = SCREENX(jx), sy = SCREENY(jy);
2175 int sxx = 0, syy = 0;
2176 int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
2178 int action = ACTION_DEFAULT;
2179 int last_player_graphic = getPlayerGraphic(player, move_dir);
2180 int last_player_frame = player->Frame;
2183 /* GfxElement[][] is set to the element the player is digging or collecting;
2184 remove also for off-screen player if the player is not moving anymore */
2185 if (IN_LEV_FIELD(jx, jy) && !player_is_moving)
2186 GfxElement[jx][jy] = EL_UNDEFINED;
2188 if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
2192 if (!IN_LEV_FIELD(jx, jy))
2194 printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
2195 printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
2196 printf("DrawPlayerField(): This should never happen!\n");
2201 if (element == EL_EXPLOSION)
2204 action = (player->is_pushing ? ACTION_PUSHING :
2205 player->is_digging ? ACTION_DIGGING :
2206 player->is_collecting ? ACTION_COLLECTING :
2207 player->is_moving ? ACTION_MOVING :
2208 player->is_snapping ? ACTION_SNAPPING :
2209 player->is_dropping ? ACTION_DROPPING :
2210 player->is_waiting ? player->action_waiting : ACTION_DEFAULT);
2212 if (player->is_waiting)
2213 move_dir = player->dir_waiting;
2215 InitPlayerGfxAnimation(player, action, move_dir);
2217 /* ----------------------------------------------------------------------- */
2218 /* draw things in the field the player is leaving, if needed */
2219 /* ----------------------------------------------------------------------- */
2221 if (player->is_moving)
2223 if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
2225 DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
2227 if (last_element == EL_DYNAMITE_ACTIVE ||
2228 last_element == EL_EM_DYNAMITE_ACTIVE ||
2229 last_element == EL_SP_DISK_RED_ACTIVE)
2230 DrawDynamite(last_jx, last_jy);
2232 DrawLevelFieldThruMask(last_jx, last_jy);
2234 else if (last_element == EL_DYNAMITE_ACTIVE ||
2235 last_element == EL_EM_DYNAMITE_ACTIVE ||
2236 last_element == EL_SP_DISK_RED_ACTIVE)
2237 DrawDynamite(last_jx, last_jy);
2239 /* !!! this is not enough to prevent flickering of players which are
2240 moving next to each others without a free tile between them -- this
2241 can only be solved by drawing all players layer by layer (first the
2242 background, then the foreground etc.) !!! => TODO */
2243 else if (!IS_PLAYER(last_jx, last_jy))
2244 DrawLevelField(last_jx, last_jy);
2247 DrawLevelField(last_jx, last_jy);
2250 if (player->is_pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
2251 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
2254 if (!IN_SCR_FIELD(sx, sy))
2257 if (setup.direct_draw)
2258 SetDrawtoField(DRAW_BUFFERED);
2260 /* ----------------------------------------------------------------------- */
2261 /* draw things behind the player, if needed */
2262 /* ----------------------------------------------------------------------- */
2265 DrawLevelElement(jx, jy, Back[jx][jy]);
2266 else if (IS_ACTIVE_BOMB(element))
2267 DrawLevelElement(jx, jy, EL_EMPTY);
2270 if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
2272 int old_element = GfxElement[jx][jy];
2273 int old_graphic = el_act_dir2img(old_element, action, move_dir);
2274 int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
2276 if (GFX_CRUMBLED(old_element))
2277 DrawLevelFieldCrumbledSandDigging(jx, jy, move_dir, player->StepFrame);
2279 DrawGraphic(sx, sy, old_graphic, frame);
2281 if (graphic_info[old_graphic].anim_mode & ANIM_OPAQUE_PLAYER)
2282 player_is_opaque = TRUE;
2286 GfxElement[jx][jy] = EL_UNDEFINED;
2288 /* make sure that pushed elements are drawn with correct frame rate */
2290 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
2292 if (player->is_pushing && player->is_moving && !IS_ANIM_MODE_CE(graphic))
2293 GfxFrame[jx][jy] = player->StepFrame;
2295 if (player->is_pushing && player->is_moving)
2296 GfxFrame[jx][jy] = player->StepFrame;
2299 DrawLevelField(jx, jy);
2303 /* ----------------------------------------------------------------------- */
2304 /* draw player himself */
2305 /* ----------------------------------------------------------------------- */
2307 graphic = getPlayerGraphic(player, move_dir);
2309 /* in the case of changed player action or direction, prevent the current
2310 animation frame from being restarted for identical animations */
2311 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
2312 player->Frame = last_player_frame;
2314 frame = getGraphicAnimationFrame(graphic, player->Frame);
2318 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
2319 sxx = player->GfxPos;
2321 syy = player->GfxPos;
2324 if (!setup.soft_scrolling && ScreenMovPos)
2327 if (player_is_opaque)
2328 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
2330 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
2332 if (SHIELD_ON(player))
2334 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
2335 IMG_SHIELD_NORMAL_ACTIVE);
2336 int frame = getGraphicAnimationFrame(graphic, -1);
2338 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
2341 /* ----------------------------------------------------------------------- */
2342 /* draw things the player is pushing, if needed */
2343 /* ----------------------------------------------------------------------- */
2346 printf("::: %d, %d [%d, %d] [%d]\n",
2347 player->is_pushing, player_is_moving, player->GfxAction,
2348 player->is_moving, player_is_moving);
2352 if (player->is_pushing && player->is_moving)
2354 int px = SCREENX(jx), py = SCREENY(jy);
2355 int pxx = (TILEX - ABS(sxx)) * dx;
2356 int pyy = (TILEY - ABS(syy)) * dy;
2357 int gfx_frame = GfxFrame[jx][jy];
2363 if (!IS_MOVING(jx, jy)) /* push movement already finished */
2365 element = Feld[next_jx][next_jy];
2366 gfx_frame = GfxFrame[next_jx][next_jy];
2369 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
2372 sync_frame = (IS_ANIM_MODE_CE(graphic) ? gfx_frame : player->StepFrame);
2373 frame = getGraphicAnimationFrame(graphic, sync_frame);
2375 frame = getGraphicAnimationFrame(graphic, player->StepFrame);
2378 /* draw background element under pushed element (like the Sokoban field) */
2379 if (Back[next_jx][next_jy])
2380 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
2382 /* masked drawing is needed for EMC style (double) movement graphics */
2383 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
2387 /* ----------------------------------------------------------------------- */
2388 /* draw things in front of player (active dynamite or dynabombs) */
2389 /* ----------------------------------------------------------------------- */
2391 if (IS_ACTIVE_BOMB(element))
2393 graphic = el2img(element);
2394 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
2396 if (game.emulation == EMU_SUPAPLEX)
2397 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
2399 DrawGraphicThruMask(sx, sy, graphic, frame);
2402 if (player_is_moving && last_element == EL_EXPLOSION)
2404 int element = (GfxElement[last_jx][last_jy] != EL_UNDEFINED ?
2405 GfxElement[last_jx][last_jy] : EL_EMPTY);
2406 int graphic = el_act2img(element, ACTION_EXPLODING);
2407 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
2408 int phase = ExplodePhase[last_jx][last_jy] - 1;
2409 int frame = getGraphicAnimationFrame(graphic, phase - delay);
2412 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
2415 /* ----------------------------------------------------------------------- */
2416 /* draw elements the player is just walking/passing through/under */
2417 /* ----------------------------------------------------------------------- */
2419 if (player_is_moving)
2421 /* handle the field the player is leaving ... */
2422 if (IS_ACCESSIBLE_INSIDE(last_element))
2423 DrawLevelField(last_jx, last_jy);
2424 else if (IS_ACCESSIBLE_UNDER(last_element))
2425 DrawLevelFieldThruMask(last_jx, last_jy);
2428 /* do not redraw accessible elements if the player is just pushing them */
2429 if (!player_is_moving || !player->is_pushing)
2431 /* ... and the field the player is entering */
2432 if (IS_ACCESSIBLE_INSIDE(element))
2433 DrawLevelField(jx, jy);
2434 else if (IS_ACCESSIBLE_UNDER(element))
2435 DrawLevelFieldThruMask(jx, jy);
2438 if (setup.direct_draw)
2440 int dst_x = SX + SCREENX(MIN(jx, last_jx)) * TILEX;
2441 int dst_y = SY + SCREENY(MIN(jy, last_jy)) * TILEY;
2442 int x_size = TILEX * (1 + ABS(jx - last_jx));
2443 int y_size = TILEY * (1 + ABS(jy - last_jy));
2445 BlitBitmap(drawto_field, window,
2446 dst_x, dst_y, x_size, y_size, dst_x, dst_y);
2447 SetDrawtoField(DRAW_DIRECT);
2450 MarkTileDirty(sx, sy);
2453 /* ------------------------------------------------------------------------- */
2455 void WaitForEventToContinue()
2457 boolean still_wait = TRUE;
2459 /* simulate releasing mouse button over last gadget, if still pressed */
2461 HandleGadgets(-1, -1, 0);
2463 button_status = MB_RELEASED;
2479 case EVENT_BUTTONPRESS:
2480 case EVENT_KEYPRESS:
2484 case EVENT_KEYRELEASE:
2485 ClearPlayerAction();
2489 HandleOtherEvents(&event);
2493 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2500 /* don't eat all CPU time */
2505 #define MAX_REQUEST_LINES 13
2506 #define MAX_REQUEST_LINE_FONT1_LEN 7
2507 #define MAX_REQUEST_LINE_FONT2_LEN 10
2509 boolean Request(char *text, unsigned int req_state)
2511 int mx, my, ty, result = -1;
2512 unsigned int old_door_state;
2513 int last_game_status = game_status; /* save current game status */
2514 int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
2515 int font_nr = FONT_TEXT_2;
2516 int max_word_len = 0;
2519 for (text_ptr = text; *text_ptr; text_ptr++)
2521 max_word_len = (*text_ptr != ' ' ? max_word_len + 1 : 0);
2523 if (max_word_len > MAX_REQUEST_LINE_FONT1_LEN)
2525 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
2527 font_nr = FONT_TEXT_1;
2529 font_nr = FONT_LEVEL_NUMBER;
2536 if (game_status == GAME_MODE_PLAYING &&
2537 level.game_engine_type == GAME_ENGINE_TYPE_EM)
2538 BlitScreenToBitmap_EM(backbuffer);
2540 /* disable deactivated drawing when quick-loading level tape recording */
2541 if (tape.playing && tape.deactivate_display)
2542 TapeDeactivateDisplayOff(TRUE);
2544 SetMouseCursor(CURSOR_DEFAULT);
2546 #if defined(NETWORK_AVALIABLE)
2547 /* pause network game while waiting for request to answer */
2548 if (options.network &&
2549 game_status == GAME_MODE_PLAYING &&
2550 req_state & REQUEST_WAIT_FOR_INPUT)
2551 SendToServer_PausePlaying();
2554 old_door_state = GetDoorState();
2556 /* simulate releasing mouse button over last gadget, if still pressed */
2558 HandleGadgets(-1, -1, 0);
2562 if (old_door_state & DOOR_OPEN_1)
2564 CloseDoor(DOOR_CLOSE_1);
2566 /* save old door content */
2567 BlitBitmap(bitmap_db_door, bitmap_db_door,
2568 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
2569 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
2573 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
2576 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2578 /* clear door drawing field */
2579 DrawBackground(DX, DY, DXSIZE, DYSIZE);
2581 /* force DOOR font on preview level */
2582 game_status = GAME_MODE_PSEUDO_DOOR;
2584 /* write text for request */
2585 for (ty = 0; ty < MAX_REQUEST_LINES; ty++)
2587 char text_line[max_request_line_len + 1];
2593 for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
2596 if (!tc || tc == ' ')
2607 strncpy(text_line, text, tl);
2610 DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
2611 DY + 8 + ty * (getFontHeight(font_nr) + 2),
2612 text_line, font_nr);
2614 text += tl + (tc == ' ' ? 1 : 0);
2617 game_status = last_game_status; /* restore current game status */
2619 if (req_state & REQ_ASK)
2621 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
2622 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
2624 else if (req_state & REQ_CONFIRM)
2626 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
2628 else if (req_state & REQ_PLAYER)
2630 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
2631 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
2632 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
2633 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
2636 /* copy request gadgets to door backbuffer */
2637 BlitBitmap(drawto, bitmap_db_door,
2638 DX, DY, DXSIZE, DYSIZE,
2639 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2641 OpenDoor(DOOR_OPEN_1);
2643 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
2645 if (game_status == GAME_MODE_PLAYING)
2647 SetPanelBackground();
2648 SetDrawBackgroundMask(REDRAW_DOOR_1);
2652 SetDrawBackgroundMask(REDRAW_FIELD);
2658 if (game_status != GAME_MODE_MAIN)
2661 button_status = MB_RELEASED;
2663 request_gadget_id = -1;
2665 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2677 case EVENT_BUTTONPRESS:
2678 case EVENT_BUTTONRELEASE:
2679 case EVENT_MOTIONNOTIFY:
2681 if (event.type == EVENT_MOTIONNOTIFY)
2683 if (!PointerInWindow(window))
2684 continue; /* window and pointer are on different screens */
2689 motion_status = TRUE;
2690 mx = ((MotionEvent *) &event)->x;
2691 my = ((MotionEvent *) &event)->y;
2695 motion_status = FALSE;
2696 mx = ((ButtonEvent *) &event)->x;
2697 my = ((ButtonEvent *) &event)->y;
2698 if (event.type == EVENT_BUTTONPRESS)
2699 button_status = ((ButtonEvent *) &event)->button;
2701 button_status = MB_RELEASED;
2704 /* this sets 'request_gadget_id' */
2705 HandleGadgets(mx, my, button_status);
2707 switch (request_gadget_id)
2709 case TOOL_CTRL_ID_YES:
2712 case TOOL_CTRL_ID_NO:
2715 case TOOL_CTRL_ID_CONFIRM:
2716 result = TRUE | FALSE;
2719 case TOOL_CTRL_ID_PLAYER_1:
2722 case TOOL_CTRL_ID_PLAYER_2:
2725 case TOOL_CTRL_ID_PLAYER_3:
2728 case TOOL_CTRL_ID_PLAYER_4:
2739 case EVENT_KEYPRESS:
2740 switch (GetEventKey((KeyEvent *)&event, TRUE))
2753 if (req_state & REQ_PLAYER)
2757 case EVENT_KEYRELEASE:
2758 ClearPlayerAction();
2762 HandleOtherEvents(&event);
2766 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2768 int joy = AnyJoystick();
2770 if (joy & JOY_BUTTON_1)
2772 else if (joy & JOY_BUTTON_2)
2779 if (!PendingEvent()) /* delay only if no pending events */
2782 /* don't eat all CPU time */
2787 if (game_status != GAME_MODE_MAIN)
2792 if (!(req_state & REQ_STAY_OPEN))
2794 CloseDoor(DOOR_CLOSE_1);
2796 if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
2797 (req_state & REQ_REOPEN))
2798 OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
2803 if (game_status == GAME_MODE_PLAYING)
2805 SetPanelBackground();
2806 SetDrawBackgroundMask(REDRAW_DOOR_1);
2810 SetDrawBackgroundMask(REDRAW_FIELD);
2813 #if defined(NETWORK_AVALIABLE)
2814 /* continue network game after request */
2815 if (options.network &&
2816 game_status == GAME_MODE_PLAYING &&
2817 req_state & REQUEST_WAIT_FOR_INPUT)
2818 SendToServer_ContinuePlaying();
2821 /* restore deactivated drawing when quick-loading level tape recording */
2822 if (tape.playing && tape.deactivate_display)
2823 TapeDeactivateDisplayOn();
2828 unsigned int OpenDoor(unsigned int door_state)
2830 if (door_state & DOOR_COPY_BACK)
2832 if (door_state & DOOR_OPEN_1)
2833 BlitBitmap(bitmap_db_door, bitmap_db_door,
2834 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
2835 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2837 if (door_state & DOOR_OPEN_2)
2838 BlitBitmap(bitmap_db_door, bitmap_db_door,
2839 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY2, VXSIZE, VYSIZE,
2840 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2842 door_state &= ~DOOR_COPY_BACK;
2845 return MoveDoor(door_state);
2848 unsigned int CloseDoor(unsigned int door_state)
2850 unsigned int old_door_state = GetDoorState();
2852 if (!(door_state & DOOR_NO_COPY_BACK))
2854 if (old_door_state & DOOR_OPEN_1)
2855 BlitBitmap(backbuffer, bitmap_db_door,
2856 DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2858 if (old_door_state & DOOR_OPEN_2)
2859 BlitBitmap(backbuffer, bitmap_db_door,
2860 VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2862 door_state &= ~DOOR_NO_COPY_BACK;
2865 return MoveDoor(door_state);
2868 unsigned int GetDoorState()
2870 return MoveDoor(DOOR_GET_STATE);
2873 unsigned int SetDoorState(unsigned int door_state)
2875 return MoveDoor(door_state | DOOR_SET_STATE);
2878 unsigned int MoveDoor(unsigned int door_state)
2880 static int door1 = DOOR_OPEN_1;
2881 static int door2 = DOOR_CLOSE_2;
2882 unsigned long door_delay = 0;
2883 unsigned long door_delay_value;
2886 if (door_1.width < 0 || door_1.width > DXSIZE)
2887 door_1.width = DXSIZE;
2888 if (door_1.height < 0 || door_1.height > DYSIZE)
2889 door_1.height = DYSIZE;
2890 if (door_2.width < 0 || door_2.width > VXSIZE)
2891 door_2.width = VXSIZE;
2892 if (door_2.height < 0 || door_2.height > VYSIZE)
2893 door_2.height = VYSIZE;
2895 if (door_state == DOOR_GET_STATE)
2896 return (door1 | door2);
2898 if (door_state & DOOR_SET_STATE)
2900 if (door_state & DOOR_ACTION_1)
2901 door1 = door_state & DOOR_ACTION_1;
2902 if (door_state & DOOR_ACTION_2)
2903 door2 = door_state & DOOR_ACTION_2;
2905 return (door1 | door2);
2908 if (!(door_state & DOOR_FORCE_REDRAW))
2910 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
2911 door_state &= ~DOOR_OPEN_1;
2912 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
2913 door_state &= ~DOOR_CLOSE_1;
2914 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
2915 door_state &= ~DOOR_OPEN_2;
2916 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
2917 door_state &= ~DOOR_CLOSE_2;
2920 door_delay_value = (door_state & DOOR_ACTION_1 ? door_1.step_delay :
2923 if (setup.quick_doors)
2925 stepsize = 20; /* must be choosen to always draw last frame */
2926 door_delay_value = 0;
2929 if (global.autoplay_leveldir)
2931 door_state |= DOOR_NO_DELAY;
2932 door_state &= ~DOOR_CLOSE_ALL;
2935 if (door_state & DOOR_ACTION)
2937 boolean handle_door_1 = (door_state & DOOR_ACTION_1);
2938 boolean handle_door_2 = (door_state & DOOR_ACTION_2);
2939 boolean door_1_done = (!handle_door_1);
2940 boolean door_2_done = (!handle_door_2);
2941 boolean door_1_vertical = (door_1.anim_mode & ANIM_VERTICAL);
2942 boolean door_2_vertical = (door_2.anim_mode & ANIM_VERTICAL);
2943 int door_size_1 = (door_1_vertical ? door_1.height : door_1.width);
2944 int door_size_2 = (door_2_vertical ? door_2.height : door_2.width);
2945 int max_door_size_1 = (door_1_vertical ? DYSIZE : DXSIZE);
2946 int max_door_size_2 = (door_2_vertical ? VYSIZE : VXSIZE);
2947 int door_size = (handle_door_1 ? door_size_1 : door_size_2);
2948 int max_door_size = (handle_door_1 ? max_door_size_1 : max_door_size_2);
2949 int door_skip = max_door_size - door_size;
2950 int end = door_size;
2951 int start = ((door_state & DOOR_NO_DELAY) ? end : 0);
2954 if (!(door_state & DOOR_NO_DELAY) && !setup.quick_doors)
2956 /* opening door sound has priority over simultaneously closing door */
2957 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
2958 PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
2959 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
2960 PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
2963 for (k = start; k <= end && !(door_1_done && door_2_done); k += stepsize)
2966 Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2967 GC gc = bitmap->stored_clip_gc;
2969 if (door_state & DOOR_ACTION_1)
2971 int a = MIN(x * door_1.step_offset, end);
2972 int p = (door_state & DOOR_OPEN_1 ? end - a : a);
2973 int i = p + door_skip;
2975 if (door_1.anim_mode & ANIM_STATIC_PANEL)
2977 BlitBitmap(bitmap_db_door, drawto,
2978 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1,
2979 DXSIZE, DYSIZE, DX, DY);
2983 BlitBitmap(bitmap_db_door, drawto,
2984 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + p / 2,
2985 DXSIZE, DYSIZE - p / 2, DX, DY);
2987 ClearRectangle(drawto, DX, DY + DYSIZE - p / 2, DXSIZE, p / 2);
2990 if (door_1.anim_mode & ANIM_HORIZONTAL && x <= DXSIZE)
2992 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
2993 int dst1_x = DX + DXSIZE - i, dst1_y = DY;
2994 int src2_x = DXSIZE - i, src2_y = DOOR_GFX_PAGEY1;
2995 int dst2_x = DX, dst2_y = DY;
2996 int width = i, height = DYSIZE;
2998 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2999 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3002 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3003 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3006 else if (door_1.anim_mode & ANIM_VERTICAL && x <= DYSIZE)
3008 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
3009 int dst1_x = DX, dst1_y = DY + DYSIZE - i;
3010 int src2_x = 0, src2_y = DOOR_GFX_PAGEY1 + DYSIZE - i;
3011 int dst2_x = DX, dst2_y = DY;
3012 int width = DXSIZE, height = i;
3014 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3015 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3018 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3019 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3022 else if (x <= DXSIZE) /* ANIM_DEFAULT */
3024 int j = (door_1.anim_mode == ANIM_DEFAULT ? (DXSIZE - i) / 3 : 0);
3026 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
3027 BlitBitmapMasked(bitmap, drawto,
3028 DXSIZE, DOOR_GFX_PAGEY1, i, 77,
3029 DX + DXSIZE - i, DY + j);
3030 BlitBitmapMasked(bitmap, drawto,
3031 DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
3032 DX + DXSIZE - i, DY + 140 + j);
3033 SetClipOrigin(bitmap, gc, DX - DXSIZE + i,
3034 DY - (DOOR_GFX_PAGEY1 + j));
3035 BlitBitmapMasked(bitmap, drawto,
3036 DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
3038 BlitBitmapMasked(bitmap, drawto,
3039 DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
3042 BlitBitmapMasked(bitmap, drawto,
3043 DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
3045 BlitBitmapMasked(bitmap, drawto,
3046 DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
3048 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
3049 BlitBitmapMasked(bitmap, drawto,
3050 DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
3051 DX + DXSIZE - i, DY + 77 + j);
3052 BlitBitmapMasked(bitmap, drawto,
3053 DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
3054 DX + DXSIZE - i, DY + 203 + j);
3057 redraw_mask |= REDRAW_DOOR_1;
3058 door_1_done = (a == end);
3061 if (door_state & DOOR_ACTION_2)
3063 int a = MIN(x * door_2.step_offset, door_size);
3064 int p = (door_state & DOOR_OPEN_2 ? door_size - a : a);
3065 int i = p + door_skip;
3067 if (door_2.anim_mode & ANIM_STATIC_PANEL)
3069 BlitBitmap(bitmap_db_door, drawto,
3070 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2,
3071 VXSIZE, VYSIZE, VX, VY);
3073 else if (x <= VYSIZE)
3075 BlitBitmap(bitmap_db_door, drawto,
3076 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + p / 2,
3077 VXSIZE, VYSIZE - p / 2, VX, VY);
3079 ClearRectangle(drawto, VX, VY + VYSIZE - p / 2, VXSIZE, p / 2);
3082 if (door_2.anim_mode & ANIM_HORIZONTAL && x <= VXSIZE)
3084 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
3085 int dst1_x = VX + VXSIZE - i, dst1_y = VY;
3086 int src2_x = VXSIZE - i, src2_y = DOOR_GFX_PAGEY2;
3087 int dst2_x = VX, dst2_y = VY;
3088 int width = i, height = VYSIZE;
3090 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3091 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3094 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3095 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3098 else if (door_2.anim_mode & ANIM_VERTICAL && x <= VYSIZE)
3100 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
3101 int dst1_x = VX, dst1_y = VY + VYSIZE - i;
3102 int src2_x = 0, src2_y = DOOR_GFX_PAGEY2 + VYSIZE - i;
3103 int dst2_x = VX, dst2_y = VY;
3104 int width = VXSIZE, height = i;
3106 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3107 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3110 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3111 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3114 else if (x <= VXSIZE) /* ANIM_DEFAULT */
3116 int j = (door_2.anim_mode == ANIM_DEFAULT ? (VXSIZE - i) / 3 : 0);
3118 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
3119 BlitBitmapMasked(bitmap, drawto,
3120 VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
3121 VX + VXSIZE - i, VY + j);
3122 SetClipOrigin(bitmap, gc,
3123 VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
3124 BlitBitmapMasked(bitmap, drawto,
3125 VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
3128 BlitBitmapMasked(bitmap, drawto,
3129 VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
3130 i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
3131 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
3132 BlitBitmapMasked(bitmap, drawto,
3133 VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
3135 VX + VXSIZE - i, VY + VYSIZE / 2 + j);
3138 redraw_mask |= REDRAW_DOOR_2;
3139 door_2_done = (a == VXSIZE);
3142 if (!(door_state & DOOR_NO_DELAY))
3146 if (game_status == GAME_MODE_MAIN)
3149 WaitUntilDelayReached(&door_delay, door_delay_value);
3154 if (door_state & DOOR_ACTION_1)
3155 door1 = door_state & DOOR_ACTION_1;
3156 if (door_state & DOOR_ACTION_2)
3157 door2 = door_state & DOOR_ACTION_2;
3159 return (door1 | door2);
3162 void DrawSpecialEditorDoor()
3164 /* draw bigger toolbox window */
3165 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
3166 DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
3168 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
3169 EX - 6, VY - 4, EXSIZE + 12, EYSIZE - VYSIZE + 4,
3172 redraw_mask |= REDRAW_ALL;
3175 void UndrawSpecialEditorDoor()
3177 /* draw normal tape recorder window */
3178 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
3179 EX - 6, EY - 12, EXSIZE + 12, EYSIZE - VYSIZE + 12,
3182 redraw_mask |= REDRAW_ALL;
3186 /* ---------- new tool button stuff ---------------------------------------- */
3188 /* graphic position values for tool buttons */
3189 #define TOOL_BUTTON_YES_XPOS 2
3190 #define TOOL_BUTTON_YES_YPOS 250
3191 #define TOOL_BUTTON_YES_GFX_YPOS 0
3192 #define TOOL_BUTTON_YES_XSIZE 46
3193 #define TOOL_BUTTON_YES_YSIZE 28
3194 #define TOOL_BUTTON_NO_XPOS 52
3195 #define TOOL_BUTTON_NO_YPOS TOOL_BUTTON_YES_YPOS
3196 #define TOOL_BUTTON_NO_GFX_YPOS TOOL_BUTTON_YES_GFX_YPOS
3197 #define TOOL_BUTTON_NO_XSIZE TOOL_BUTTON_YES_XSIZE
3198 #define TOOL_BUTTON_NO_YSIZE TOOL_BUTTON_YES_YSIZE
3199 #define TOOL_BUTTON_CONFIRM_XPOS TOOL_BUTTON_YES_XPOS
3200 #define TOOL_BUTTON_CONFIRM_YPOS TOOL_BUTTON_YES_YPOS
3201 #define TOOL_BUTTON_CONFIRM_GFX_YPOS 30
3202 #define TOOL_BUTTON_CONFIRM_XSIZE 96
3203 #define TOOL_BUTTON_CONFIRM_YSIZE TOOL_BUTTON_YES_YSIZE
3204 #define TOOL_BUTTON_PLAYER_XSIZE 30
3205 #define TOOL_BUTTON_PLAYER_YSIZE 30
3206 #define TOOL_BUTTON_PLAYER_GFX_XPOS 5
3207 #define TOOL_BUTTON_PLAYER_GFX_YPOS 185
3208 #define TOOL_BUTTON_PLAYER_XPOS (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
3209 #define TOOL_BUTTON_PLAYER_YPOS (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
3210 #define TOOL_BUTTON_PLAYER1_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3211 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
3212 #define TOOL_BUTTON_PLAYER2_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3213 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
3214 #define TOOL_BUTTON_PLAYER3_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3215 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
3216 #define TOOL_BUTTON_PLAYER4_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3217 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
3218 #define TOOL_BUTTON_PLAYER1_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3219 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
3220 #define TOOL_BUTTON_PLAYER2_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3221 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
3222 #define TOOL_BUTTON_PLAYER3_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3223 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
3224 #define TOOL_BUTTON_PLAYER4_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3225 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
3234 } toolbutton_info[NUM_TOOL_BUTTONS] =
3237 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_GFX_YPOS,
3238 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_YPOS,
3239 TOOL_BUTTON_YES_XSIZE, TOOL_BUTTON_YES_YSIZE,
3244 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_GFX_YPOS,
3245 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_YPOS,
3246 TOOL_BUTTON_NO_XSIZE, TOOL_BUTTON_NO_YSIZE,
3251 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_GFX_YPOS,
3252 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_YPOS,
3253 TOOL_BUTTON_CONFIRM_XSIZE, TOOL_BUTTON_CONFIRM_YSIZE,
3254 TOOL_CTRL_ID_CONFIRM,
3258 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3259 TOOL_BUTTON_PLAYER1_XPOS, TOOL_BUTTON_PLAYER1_YPOS,
3260 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3261 TOOL_CTRL_ID_PLAYER_1,
3265 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3266 TOOL_BUTTON_PLAYER2_XPOS, TOOL_BUTTON_PLAYER2_YPOS,
3267 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3268 TOOL_CTRL_ID_PLAYER_2,
3272 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3273 TOOL_BUTTON_PLAYER3_XPOS, TOOL_BUTTON_PLAYER3_YPOS,
3274 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3275 TOOL_CTRL_ID_PLAYER_3,
3279 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3280 TOOL_BUTTON_PLAYER4_XPOS, TOOL_BUTTON_PLAYER4_YPOS,
3281 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3282 TOOL_CTRL_ID_PLAYER_4,
3287 void CreateToolButtons()
3291 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3293 Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
3294 Bitmap *deco_bitmap = None;
3295 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
3296 struct GadgetInfo *gi;
3297 unsigned long event_mask;
3298 int gd_xoffset, gd_yoffset;
3299 int gd_x1, gd_x2, gd_y;
3302 event_mask = GD_EVENT_RELEASED;
3304 gd_xoffset = toolbutton_info[i].xpos;
3305 gd_yoffset = toolbutton_info[i].ypos;
3306 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
3307 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
3308 gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
3310 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
3312 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
3314 getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr),
3315 &deco_bitmap, &deco_x, &deco_y);
3316 deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
3317 deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
3320 gi = CreateGadget(GDI_CUSTOM_ID, id,
3321 GDI_INFO_TEXT, toolbutton_info[i].infotext,
3322 GDI_X, DX + toolbutton_info[i].x,
3323 GDI_Y, DY + toolbutton_info[i].y,
3324 GDI_WIDTH, toolbutton_info[i].width,
3325 GDI_HEIGHT, toolbutton_info[i].height,
3326 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
3327 GDI_STATE, GD_BUTTON_UNPRESSED,
3328 GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
3329 GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
3330 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
3331 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
3332 GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
3333 GDI_DECORATION_SHIFTING, 1, 1,
3334 GDI_DIRECT_DRAW, FALSE,
3335 GDI_EVENT_MASK, event_mask,
3336 GDI_CALLBACK_ACTION, HandleToolButtons,
3340 Error(ERR_EXIT, "cannot create gadget");
3342 tool_gadget[id] = gi;
3346 void FreeToolButtons()
3350 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3351 FreeGadget(tool_gadget[i]);
3354 static void UnmapToolButtons()
3358 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3359 UnmapGadget(tool_gadget[i]);
3362 static void HandleToolButtons(struct GadgetInfo *gi)
3364 request_gadget_id = gi->custom_id;
3367 static struct Mapping_EM_to_RND_object
3370 boolean is_rnd_to_em_mapping; /* unique mapping EM <-> RND */
3371 boolean is_backside; /* backside of moving element */
3377 em_object_mapping_list[] =
3380 Xblank, TRUE, FALSE,
3384 Yacid_splash_eB, FALSE, FALSE,
3385 EL_ACID_SPLASH_RIGHT, -1, -1
3388 Yacid_splash_wB, FALSE, FALSE,
3389 EL_ACID_SPLASH_LEFT, -1, -1
3392 #ifdef EM_ENGINE_BAD_ROLL
3394 Xstone_force_e, FALSE, FALSE,
3395 EL_ROCK, -1, MV_BIT_RIGHT
3398 Xstone_force_w, FALSE, FALSE,
3399 EL_ROCK, -1, MV_BIT_LEFT
3402 Xnut_force_e, FALSE, FALSE,
3403 EL_NUT, -1, MV_BIT_RIGHT
3406 Xnut_force_w, FALSE, FALSE,
3407 EL_NUT, -1, MV_BIT_LEFT
3410 Xspring_force_e, FALSE, FALSE,
3411 EL_SPRING, -1, MV_BIT_RIGHT
3414 Xspring_force_w, FALSE, FALSE,
3415 EL_SPRING, -1, MV_BIT_LEFT
3418 Xemerald_force_e, FALSE, FALSE,
3419 EL_EMERALD, -1, MV_BIT_RIGHT
3422 Xemerald_force_w, FALSE, FALSE,
3423 EL_EMERALD, -1, MV_BIT_LEFT
3426 Xdiamond_force_e, FALSE, FALSE,
3427 EL_DIAMOND, -1, MV_BIT_RIGHT
3430 Xdiamond_force_w, FALSE, FALSE,
3431 EL_DIAMOND, -1, MV_BIT_LEFT
3434 Xbomb_force_e, FALSE, FALSE,
3435 EL_BOMB, -1, MV_BIT_RIGHT
3438 Xbomb_force_w, FALSE, FALSE,
3439 EL_BOMB, -1, MV_BIT_LEFT
3441 #endif /* EM_ENGINE_BAD_ROLL */
3444 Xstone, TRUE, FALSE,
3448 Xstone_pause, FALSE, FALSE,
3452 Xstone_fall, FALSE, FALSE,
3456 Ystone_s, FALSE, FALSE,
3457 EL_ROCK, ACTION_FALLING, -1
3460 Ystone_sB, FALSE, TRUE,
3461 EL_ROCK, ACTION_FALLING, -1
3464 Ystone_e, FALSE, FALSE,
3465 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
3468 Ystone_eB, FALSE, TRUE,
3469 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
3472 Ystone_w, FALSE, FALSE,
3473 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
3476 Ystone_wB, FALSE, TRUE,
3477 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
3484 Xnut_pause, FALSE, FALSE,
3488 Xnut_fall, FALSE, FALSE,
3492 Ynut_s, FALSE, FALSE,
3493 EL_NUT, ACTION_FALLING, -1
3496 Ynut_sB, FALSE, TRUE,
3497 EL_NUT, ACTION_FALLING, -1
3500 Ynut_e, FALSE, FALSE,
3501 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
3504 Ynut_eB, FALSE, TRUE,
3505 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
3508 Ynut_w, FALSE, FALSE,
3509 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
3512 Ynut_wB, FALSE, TRUE,
3513 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
3516 Xbug_n, TRUE, FALSE,
3520 Xbug_e, TRUE, FALSE,
3521 EL_BUG_RIGHT, -1, -1
3524 Xbug_s, TRUE, FALSE,
3528 Xbug_w, TRUE, FALSE,
3532 Xbug_gon, FALSE, FALSE,
3536 Xbug_goe, FALSE, FALSE,
3537 EL_BUG_RIGHT, -1, -1
3540 Xbug_gos, FALSE, FALSE,
3544 Xbug_gow, FALSE, FALSE,
3548 Ybug_n, FALSE, FALSE,
3549 EL_BUG, ACTION_MOVING, MV_BIT_UP
3552 Ybug_nB, FALSE, TRUE,
3553 EL_BUG, ACTION_MOVING, MV_BIT_UP
3556 Ybug_e, FALSE, FALSE,
3557 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
3560 Ybug_eB, FALSE, TRUE,
3561 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
3564 Ybug_s, FALSE, FALSE,
3565 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
3568 Ybug_sB, FALSE, TRUE,
3569 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
3572 Ybug_w, FALSE, FALSE,
3573 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
3576 Ybug_wB, FALSE, TRUE,
3577 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
3580 Ybug_w_n, FALSE, FALSE,
3581 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
3584 Ybug_n_e, FALSE, FALSE,
3585 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
3588 Ybug_e_s, FALSE, FALSE,
3589 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
3592 Ybug_s_w, FALSE, FALSE,
3593 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
3596 Ybug_e_n, FALSE, FALSE,
3597 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
3600 Ybug_s_e, FALSE, FALSE,
3601 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
3604 Ybug_w_s, FALSE, FALSE,
3605 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
3608 Ybug_n_w, FALSE, FALSE,
3609 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
3612 Ybug_stone, FALSE, FALSE,
3613 EL_BUG, ACTION_SMASHED_BY_ROCK, -1
3616 Ybug_spring, FALSE, FALSE,
3617 EL_BUG, ACTION_SMASHED_BY_SPRING, -1
3620 Xtank_n, TRUE, FALSE,
3621 EL_SPACESHIP_UP, -1, -1
3624 Xtank_e, TRUE, FALSE,
3625 EL_SPACESHIP_RIGHT, -1, -1
3628 Xtank_s, TRUE, FALSE,
3629 EL_SPACESHIP_DOWN, -1, -1
3632 Xtank_w, TRUE, FALSE,
3633 EL_SPACESHIP_LEFT, -1, -1
3636 Xtank_gon, FALSE, FALSE,
3637 EL_SPACESHIP_UP, -1, -1
3640 Xtank_goe, FALSE, FALSE,
3641 EL_SPACESHIP_RIGHT, -1, -1
3644 Xtank_gos, FALSE, FALSE,
3645 EL_SPACESHIP_DOWN, -1, -1
3648 Xtank_gow, FALSE, FALSE,
3649 EL_SPACESHIP_LEFT, -1, -1
3652 Ytank_n, FALSE, FALSE,
3653 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
3656 Ytank_nB, FALSE, TRUE,
3657 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
3660 Ytank_e, FALSE, FALSE,
3661 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
3664 Ytank_eB, FALSE, TRUE,
3665 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
3668 Ytank_s, FALSE, FALSE,
3669 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
3672 Ytank_sB, FALSE, TRUE,
3673 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
3676 Ytank_w, FALSE, FALSE,
3677 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
3680 Ytank_wB, FALSE, TRUE,
3681 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
3684 Ytank_w_n, FALSE, FALSE,
3685 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
3688 Ytank_n_e, FALSE, FALSE,
3689 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
3692 Ytank_e_s, FALSE, FALSE,
3693 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
3696 Ytank_s_w, FALSE, FALSE,
3697 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
3700 Ytank_e_n, FALSE, FALSE,
3701 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
3704 Ytank_s_e, FALSE, FALSE,
3705 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
3708 Ytank_w_s, FALSE, FALSE,
3709 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
3712 Ytank_n_w, FALSE, FALSE,
3713 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
3716 Ytank_stone, FALSE, FALSE,
3717 EL_SPACESHIP, ACTION_SMASHED_BY_ROCK, -1
3720 Ytank_spring, FALSE, FALSE,
3721 EL_SPACESHIP, ACTION_SMASHED_BY_SPRING, -1
3724 Xandroid, TRUE, FALSE,
3725 EL_EMC_ANDROID, ACTION_ACTIVE, -1
3728 Xandroid_1_n, FALSE, FALSE,
3729 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
3732 Xandroid_2_n, FALSE, FALSE,
3733 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
3736 Xandroid_1_e, FALSE, FALSE,
3737 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
3740 Xandroid_2_e, FALSE, FALSE,
3741 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
3744 Xandroid_1_w, FALSE, FALSE,
3745 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
3748 Xandroid_2_w, FALSE, FALSE,
3749 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
3752 Xandroid_1_s, FALSE, FALSE,
3753 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
3756 Xandroid_2_s, FALSE, FALSE,
3757 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
3760 Yandroid_n, FALSE, FALSE,
3761 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
3764 Yandroid_nB, FALSE, TRUE,
3765 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
3768 Yandroid_ne, FALSE, FALSE,
3769 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPRIGHT
3772 Yandroid_neB, FALSE, TRUE,
3773 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPRIGHT
3776 Yandroid_e, FALSE, FALSE,
3777 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
3780 Yandroid_eB, FALSE, TRUE,
3781 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
3784 Yandroid_se, FALSE, FALSE,
3785 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNRIGHT
3788 Yandroid_seB, FALSE, TRUE,
3789 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNRIGHT
3792 Yandroid_s, FALSE, FALSE,
3793 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
3796 Yandroid_sB, FALSE, TRUE,
3797 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
3800 Yandroid_sw, FALSE, FALSE,
3801 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNLEFT
3804 Yandroid_swB, FALSE, TRUE,
3805 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNLEFT
3808 Yandroid_w, FALSE, FALSE,
3809 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
3812 Yandroid_wB, FALSE, TRUE,
3813 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
3816 Yandroid_nw, FALSE, FALSE,
3817 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPLEFT
3820 Yandroid_nwB, FALSE, TRUE,
3821 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPLEFT
3824 Xspring, TRUE, FALSE,
3828 Xspring_pause, FALSE, FALSE,
3832 Xspring_e, FALSE, FALSE,
3836 Xspring_w, FALSE, FALSE,
3840 Xspring_fall, FALSE, FALSE,
3844 Yspring_s, FALSE, FALSE,
3845 EL_SPRING, ACTION_FALLING, -1
3848 Yspring_sB, FALSE, TRUE,
3849 EL_SPRING, ACTION_FALLING, -1
3852 Yspring_e, FALSE, FALSE,
3853 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
3856 Yspring_eB, FALSE, TRUE,
3857 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
3860 Yspring_w, FALSE, FALSE,
3861 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
3864 Yspring_wB, FALSE, TRUE,
3865 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
3868 Yspring_kill_e, FALSE, FALSE,
3869 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
3872 Yspring_kill_eB, FALSE, TRUE,
3873 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
3876 Yspring_kill_w, FALSE, FALSE,
3877 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
3880 Yspring_kill_wB, FALSE, TRUE,
3881 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
3884 Xeater_n, TRUE, FALSE,
3885 EL_YAMYAM_UP, -1, -1
3888 Xeater_e, TRUE, FALSE,
3889 EL_YAMYAM_RIGHT, -1, -1
3892 Xeater_w, TRUE, FALSE,
3893 EL_YAMYAM_LEFT, -1, -1
3896 Xeater_s, TRUE, FALSE,
3897 EL_YAMYAM_DOWN, -1, -1
3900 Yeater_n, FALSE, FALSE,
3901 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
3904 Yeater_nB, FALSE, TRUE,
3905 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
3908 Yeater_e, FALSE, FALSE,
3909 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
3912 Yeater_eB, FALSE, TRUE,
3913 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
3916 Yeater_s, FALSE, FALSE,
3917 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
3920 Yeater_sB, FALSE, TRUE,
3921 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
3924 Yeater_w, FALSE, FALSE,
3925 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
3928 Yeater_wB, FALSE, TRUE,
3929 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
3932 Yeater_stone, FALSE, FALSE,
3933 EL_YAMYAM, ACTION_SMASHED_BY_ROCK, -1
3936 Yeater_spring, FALSE, FALSE,
3937 EL_YAMYAM, ACTION_SMASHED_BY_SPRING, -1
3940 Xalien, TRUE, FALSE,
3944 Xalien_pause, FALSE, FALSE,
3948 Yalien_n, FALSE, FALSE,
3949 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
3952 Yalien_nB, FALSE, TRUE,
3953 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
3956 Yalien_e, FALSE, FALSE,
3957 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
3960 Yalien_eB, FALSE, TRUE,
3961 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
3964 Yalien_s, FALSE, FALSE,
3965 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
3968 Yalien_sB, FALSE, TRUE,
3969 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
3972 Yalien_w, FALSE, FALSE,
3973 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
3976 Yalien_wB, FALSE, TRUE,
3977 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
3980 Yalien_stone, FALSE, FALSE,
3981 EL_ROBOT, ACTION_SMASHED_BY_ROCK, -1
3984 Yalien_spring, FALSE, FALSE,
3985 EL_ROBOT, ACTION_SMASHED_BY_SPRING, -1
3988 Xemerald, TRUE, FALSE,
3992 Xemerald_pause, FALSE, FALSE,
3996 Xemerald_fall, FALSE, FALSE,
4000 Xemerald_shine, FALSE, FALSE,
4001 EL_EMERALD, ACTION_TWINKLING, -1
4004 Yemerald_s, FALSE, FALSE,
4005 EL_EMERALD, ACTION_FALLING, -1
4008 Yemerald_sB, FALSE, TRUE,
4009 EL_EMERALD, ACTION_FALLING, -1
4012 Yemerald_e, FALSE, FALSE,
4013 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
4016 Yemerald_eB, FALSE, TRUE,
4017 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
4020 Yemerald_w, FALSE, FALSE,
4021 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
4024 Yemerald_wB, FALSE, TRUE,
4025 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
4028 Yemerald_eat, FALSE, FALSE,
4029 EL_EMERALD, ACTION_COLLECTING, -1
4032 Yemerald_stone, FALSE, FALSE,
4033 EL_NUT, ACTION_BREAKING, -1
4036 Xdiamond, TRUE, FALSE,
4040 Xdiamond_pause, FALSE, FALSE,
4044 Xdiamond_fall, FALSE, FALSE,
4048 Xdiamond_shine, FALSE, FALSE,
4049 EL_DIAMOND, ACTION_TWINKLING, -1
4052 Ydiamond_s, FALSE, FALSE,
4053 EL_DIAMOND, ACTION_FALLING, -1
4056 Ydiamond_sB, FALSE, TRUE,
4057 EL_DIAMOND, ACTION_FALLING, -1
4060 Ydiamond_e, FALSE, FALSE,
4061 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
4064 Ydiamond_eB, FALSE, TRUE,
4065 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
4068 Ydiamond_w, FALSE, FALSE,
4069 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
4072 Ydiamond_wB, FALSE, TRUE,
4073 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
4076 Ydiamond_eat, FALSE, FALSE,
4077 EL_DIAMOND, ACTION_COLLECTING, -1
4080 Ydiamond_stone, FALSE, FALSE,
4081 EL_DIAMOND, ACTION_SMASHED_BY_ROCK, -1
4084 Xdrip_fall, TRUE, FALSE,
4085 EL_AMOEBA_DROP, -1, -1
4088 Xdrip_stretch, FALSE, FALSE,
4089 EL_AMOEBA_DROP, ACTION_FALLING, -1
4092 Xdrip_stretchB, FALSE, TRUE,
4093 EL_AMOEBA_DROP, ACTION_FALLING, -1
4096 Xdrip_eat, FALSE, FALSE,
4097 EL_AMOEBA_DROP, ACTION_GROWING, -1
4100 Ydrip_s1, FALSE, FALSE,
4101 EL_AMOEBA_DROP, ACTION_FALLING, -1
4104 Ydrip_s1B, FALSE, TRUE,
4105 EL_AMOEBA_DROP, ACTION_FALLING, -1
4108 Ydrip_s2, FALSE, FALSE,
4109 EL_AMOEBA_DROP, ACTION_FALLING, -1
4112 Ydrip_s2B, FALSE, TRUE,
4113 EL_AMOEBA_DROP, ACTION_FALLING, -1
4120 Xbomb_pause, FALSE, FALSE,
4124 Xbomb_fall, FALSE, FALSE,
4128 Ybomb_s, FALSE, FALSE,
4129 EL_BOMB, ACTION_FALLING, -1
4132 Ybomb_sB, FALSE, TRUE,
4133 EL_BOMB, ACTION_FALLING, -1
4136 Ybomb_e, FALSE, FALSE,
4137 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
4140 Ybomb_eB, FALSE, TRUE,
4141 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
4144 Ybomb_w, FALSE, FALSE,
4145 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
4148 Ybomb_wB, FALSE, TRUE,
4149 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
4152 Ybomb_eat, FALSE, FALSE,
4153 EL_BOMB, ACTION_ACTIVATING, -1
4156 Xballoon, TRUE, FALSE,
4160 Yballoon_n, FALSE, FALSE,
4161 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
4164 Yballoon_nB, FALSE, TRUE,
4165 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
4168 Yballoon_e, FALSE, FALSE,
4169 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
4172 Yballoon_eB, FALSE, TRUE,
4173 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
4176 Yballoon_s, FALSE, FALSE,
4177 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
4180 Yballoon_sB, FALSE, TRUE,
4181 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
4184 Yballoon_w, FALSE, FALSE,
4185 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
4188 Yballoon_wB, FALSE, TRUE,
4189 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
4192 Xgrass, TRUE, FALSE,
4193 EL_EMC_GRASS, -1, -1
4196 Ygrass_nB, FALSE, FALSE,
4197 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_UP
4200 Ygrass_eB, FALSE, FALSE,
4201 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_RIGHT
4204 Ygrass_sB, FALSE, FALSE,
4205 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_DOWN
4208 Ygrass_wB, FALSE, FALSE,
4209 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_LEFT
4216 Ydirt_nB, FALSE, FALSE,
4217 EL_SAND, ACTION_DIGGING, MV_BIT_UP
4220 Ydirt_eB, FALSE, FALSE,
4221 EL_SAND, ACTION_DIGGING, MV_BIT_RIGHT
4224 Ydirt_sB, FALSE, FALSE,
4225 EL_SAND, ACTION_DIGGING, MV_BIT_DOWN
4228 Ydirt_wB, FALSE, FALSE,
4229 EL_SAND, ACTION_DIGGING, MV_BIT_LEFT
4232 Xacid_ne, TRUE, FALSE,
4233 EL_ACID_POOL_TOPRIGHT, -1, -1
4236 Xacid_se, TRUE, FALSE,
4237 EL_ACID_POOL_BOTTOMRIGHT, -1, -1
4240 Xacid_s, TRUE, FALSE,
4241 EL_ACID_POOL_BOTTOM, -1, -1
4244 Xacid_sw, TRUE, FALSE,
4245 EL_ACID_POOL_BOTTOMLEFT, -1, -1
4248 Xacid_nw, TRUE, FALSE,
4249 EL_ACID_POOL_TOPLEFT, -1, -1
4252 Xacid_1, TRUE, FALSE,
4256 Xacid_2, FALSE, FALSE,
4260 Xacid_3, FALSE, FALSE,
4264 Xacid_4, FALSE, FALSE,
4268 Xacid_5, FALSE, FALSE,
4272 Xacid_6, FALSE, FALSE,
4276 Xacid_7, FALSE, FALSE,
4280 Xacid_8, FALSE, FALSE,
4284 Xball_1, TRUE, FALSE,
4285 EL_EMC_MAGIC_BALL, -1, -1
4288 Xball_1B, FALSE, FALSE,
4289 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4292 Xball_2, FALSE, FALSE,
4293 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4296 Xball_2B, FALSE, FALSE,
4297 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4300 Yball_eat, FALSE, FALSE,
4301 EL_EMC_MAGIC_BALL, ACTION_DROPPING, -1
4304 Ykey_1_eat, FALSE, FALSE,
4305 EL_EM_KEY_1, ACTION_COLLECTING, -1
4308 Ykey_2_eat, FALSE, FALSE,
4309 EL_EM_KEY_2, ACTION_COLLECTING, -1
4312 Ykey_3_eat, FALSE, FALSE,
4313 EL_EM_KEY_3, ACTION_COLLECTING, -1
4316 Ykey_4_eat, FALSE, FALSE,
4317 EL_EM_KEY_4, ACTION_COLLECTING, -1
4320 Ykey_5_eat, FALSE, FALSE,
4321 EL_EMC_KEY_5, ACTION_COLLECTING, -1
4324 Ykey_6_eat, FALSE, FALSE,
4325 EL_EMC_KEY_6, ACTION_COLLECTING, -1
4328 Ykey_7_eat, FALSE, FALSE,
4329 EL_EMC_KEY_7, ACTION_COLLECTING, -1
4332 Ykey_8_eat, FALSE, FALSE,
4333 EL_EMC_KEY_8, ACTION_COLLECTING, -1
4336 Ylenses_eat, FALSE, FALSE,
4337 EL_EMC_LENSES, ACTION_COLLECTING, -1
4340 Ymagnify_eat, FALSE, FALSE,
4341 EL_EMC_MAGNIFIER, ACTION_COLLECTING, -1
4344 Ygrass_eat, FALSE, FALSE,
4345 EL_EMC_GRASS, ACTION_SNAPPING, -1
4348 Ydirt_eat, FALSE, FALSE,
4349 EL_SAND, ACTION_SNAPPING, -1
4352 Xgrow_ns, TRUE, FALSE,
4353 EL_EXPANDABLE_WALL_VERTICAL, -1, -1
4356 Ygrow_ns_eat, FALSE, FALSE,
4357 EL_EXPANDABLE_WALL_VERTICAL, ACTION_GROWING, -1
4360 Xgrow_ew, TRUE, FALSE,
4361 EL_EXPANDABLE_WALL_HORIZONTAL, -1, -1
4364 Ygrow_ew_eat, FALSE, FALSE,
4365 EL_EXPANDABLE_WALL_HORIZONTAL, ACTION_GROWING, -1
4368 Xwonderwall, TRUE, FALSE,
4369 EL_MAGIC_WALL, -1, -1
4372 XwonderwallB, FALSE, FALSE,
4373 EL_MAGIC_WALL, ACTION_ACTIVE, -1
4376 Xamoeba_1, TRUE, FALSE,
4377 EL_AMOEBA_DRY, ACTION_OTHER, -1
4380 Xamoeba_2, FALSE, FALSE,
4381 EL_AMOEBA_DRY, ACTION_OTHER, -1
4384 Xamoeba_3, FALSE, FALSE,
4385 EL_AMOEBA_DRY, ACTION_OTHER, -1
4388 Xamoeba_4, FALSE, FALSE,
4389 EL_AMOEBA_DRY, ACTION_OTHER, -1
4392 Xamoeba_5, TRUE, FALSE,
4393 EL_AMOEBA_WET, ACTION_OTHER, -1
4396 Xamoeba_6, FALSE, FALSE,
4397 EL_AMOEBA_WET, ACTION_OTHER, -1
4400 Xamoeba_7, FALSE, FALSE,
4401 EL_AMOEBA_WET, ACTION_OTHER, -1
4404 Xamoeba_8, FALSE, FALSE,
4405 EL_AMOEBA_WET, ACTION_OTHER, -1
4408 Xdoor_1, TRUE, FALSE,
4409 EL_EM_GATE_1, -1, -1
4412 Xdoor_2, TRUE, FALSE,
4413 EL_EM_GATE_2, -1, -1
4416 Xdoor_3, TRUE, FALSE,
4417 EL_EM_GATE_3, -1, -1
4420 Xdoor_4, TRUE, FALSE,
4421 EL_EM_GATE_4, -1, -1
4424 Xdoor_5, TRUE, FALSE,
4425 EL_EMC_GATE_5, -1, -1
4428 Xdoor_6, TRUE, FALSE,
4429 EL_EMC_GATE_6, -1, -1
4432 Xdoor_7, TRUE, FALSE,
4433 EL_EMC_GATE_7, -1, -1
4436 Xdoor_8, TRUE, FALSE,
4437 EL_EMC_GATE_8, -1, -1
4440 Xkey_1, TRUE, FALSE,
4444 Xkey_2, TRUE, FALSE,
4448 Xkey_3, TRUE, FALSE,
4452 Xkey_4, TRUE, FALSE,
4456 Xkey_5, TRUE, FALSE,
4457 EL_EMC_KEY_5, -1, -1
4460 Xkey_6, TRUE, FALSE,
4461 EL_EMC_KEY_6, -1, -1
4464 Xkey_7, TRUE, FALSE,
4465 EL_EMC_KEY_7, -1, -1
4468 Xkey_8, TRUE, FALSE,
4469 EL_EMC_KEY_8, -1, -1
4472 Xwind_n, TRUE, FALSE,
4473 EL_BALLOON_SWITCH_UP, -1, -1
4476 Xwind_e, TRUE, FALSE,
4477 EL_BALLOON_SWITCH_RIGHT, -1, -1
4480 Xwind_s, TRUE, FALSE,
4481 EL_BALLOON_SWITCH_DOWN, -1, -1
4484 Xwind_w, TRUE, FALSE,
4485 EL_BALLOON_SWITCH_LEFT, -1, -1
4488 Xwind_nesw, TRUE, FALSE,
4489 EL_BALLOON_SWITCH_ANY, -1, -1
4492 Xwind_stop, TRUE, FALSE,
4493 EL_BALLOON_SWITCH_NONE, -1, -1
4497 EL_EM_EXIT_CLOSED, -1, -1
4500 Xexit_1, TRUE, FALSE,
4501 EL_EM_EXIT_OPEN, -1, -1
4504 Xexit_2, FALSE, FALSE,
4505 EL_EM_EXIT_OPEN, -1, -1
4508 Xexit_3, FALSE, FALSE,
4509 EL_EM_EXIT_OPEN, -1, -1
4512 Xdynamite, TRUE, FALSE,
4513 EL_EM_DYNAMITE, -1, -1
4516 Ydynamite_eat, FALSE, FALSE,
4517 EL_EM_DYNAMITE, ACTION_COLLECTING, -1
4520 Xdynamite_1, TRUE, FALSE,
4521 EL_EM_DYNAMITE_ACTIVE, -1, -1
4524 Xdynamite_2, FALSE, FALSE,
4525 EL_EM_DYNAMITE_ACTIVE, -1, -1
4528 Xdynamite_3, FALSE, FALSE,
4529 EL_EM_DYNAMITE_ACTIVE, -1, -1
4532 Xdynamite_4, FALSE, FALSE,
4533 EL_EM_DYNAMITE_ACTIVE, -1, -1
4536 Xbumper, TRUE, FALSE,
4537 EL_EMC_SPRING_BUMPER, -1, -1
4540 XbumperB, FALSE, FALSE,
4541 EL_EMC_SPRING_BUMPER, ACTION_ACTIVE, -1
4544 Xwheel, TRUE, FALSE,
4545 EL_ROBOT_WHEEL, -1, -1
4548 XwheelB, FALSE, FALSE,
4549 EL_ROBOT_WHEEL, ACTION_ACTIVE, -1
4552 Xswitch, TRUE, FALSE,
4553 EL_EMC_MAGIC_BALL_SWITCH, -1, -1
4556 XswitchB, FALSE, FALSE,
4557 EL_EMC_MAGIC_BALL_SWITCH, ACTION_ACTIVE, -1
4561 EL_QUICKSAND_EMPTY, -1, -1
4564 Xsand_stone, TRUE, FALSE,
4565 EL_QUICKSAND_FULL, -1, -1
4568 Xsand_stonein_1, FALSE, TRUE,
4569 EL_ROCK, ACTION_FILLING, -1
4572 Xsand_stonein_2, FALSE, TRUE,
4573 EL_ROCK, ACTION_FILLING, -1
4576 Xsand_stonein_3, FALSE, TRUE,
4577 EL_ROCK, ACTION_FILLING, -1
4580 Xsand_stonein_4, FALSE, TRUE,
4581 EL_ROCK, ACTION_FILLING, -1
4584 Xsand_stonesand_1, FALSE, FALSE,
4585 EL_QUICKSAND_FULL, -1, -1
4588 Xsand_stonesand_2, FALSE, FALSE,
4589 EL_QUICKSAND_FULL, -1, -1
4592 Xsand_stonesand_3, FALSE, FALSE,
4593 EL_QUICKSAND_FULL, -1, -1
4596 Xsand_stonesand_4, FALSE, FALSE,
4597 EL_QUICKSAND_FULL, -1, -1
4600 Xsand_stoneout_1, FALSE, FALSE,
4601 EL_ROCK, ACTION_EMPTYING, -1
4604 Xsand_stoneout_2, FALSE, FALSE,
4605 EL_ROCK, ACTION_EMPTYING, -1
4608 Xsand_sandstone_1, FALSE, FALSE,
4609 EL_QUICKSAND_FULL, -1, -1
4612 Xsand_sandstone_2, FALSE, FALSE,
4613 EL_QUICKSAND_FULL, -1, -1
4616 Xsand_sandstone_3, FALSE, FALSE,
4617 EL_QUICKSAND_FULL, -1, -1
4620 Xsand_sandstone_4, FALSE, FALSE,
4621 EL_QUICKSAND_FULL, -1, -1
4624 Xplant, TRUE, FALSE,
4625 EL_EMC_PLANT, -1, -1
4628 Yplant, FALSE, FALSE,
4629 EL_EMC_PLANT, -1, -1
4632 Xlenses, TRUE, FALSE,
4633 EL_EMC_LENSES, -1, -1
4636 Xmagnify, TRUE, FALSE,
4637 EL_EMC_MAGNIFIER, -1, -1
4640 Xdripper, TRUE, FALSE,
4641 EL_EMC_DRIPPER, -1, -1
4644 XdripperB, FALSE, FALSE,
4645 EL_EMC_DRIPPER, ACTION_ACTIVE, -1
4648 Xfake_blank, TRUE, FALSE,
4649 EL_INVISIBLE_WALL, -1, -1
4652 Xfake_blankB, FALSE, FALSE,
4653 EL_INVISIBLE_WALL, ACTION_ACTIVE, -1
4656 Xfake_grass, TRUE, FALSE,
4657 EL_EMC_FAKE_GRASS, -1, -1
4660 Xfake_grassB, FALSE, FALSE,
4661 EL_EMC_FAKE_GRASS, ACTION_ACTIVE, -1
4664 Xfake_door_1, TRUE, FALSE,
4665 EL_EM_GATE_1_GRAY, -1, -1
4668 Xfake_door_2, TRUE, FALSE,
4669 EL_EM_GATE_2_GRAY, -1, -1
4672 Xfake_door_3, TRUE, FALSE,
4673 EL_EM_GATE_3_GRAY, -1, -1
4676 Xfake_door_4, TRUE, FALSE,
4677 EL_EM_GATE_4_GRAY, -1, -1
4680 Xfake_door_5, TRUE, FALSE,
4681 EL_EMC_GATE_5_GRAY, -1, -1
4684 Xfake_door_6, TRUE, FALSE,
4685 EL_EMC_GATE_6_GRAY, -1, -1
4688 Xfake_door_7, TRUE, FALSE,
4689 EL_EMC_GATE_7_GRAY, -1, -1
4692 Xfake_door_8, TRUE, FALSE,
4693 EL_EMC_GATE_8_GRAY, -1, -1
4696 Xfake_acid_1, TRUE, FALSE,
4697 EL_EMC_FAKE_ACID, -1, -1
4700 Xfake_acid_2, FALSE, FALSE,
4701 EL_EMC_FAKE_ACID, -1, -1
4704 Xfake_acid_3, FALSE, FALSE,
4705 EL_EMC_FAKE_ACID, -1, -1
4708 Xfake_acid_4, FALSE, FALSE,
4709 EL_EMC_FAKE_ACID, -1, -1
4712 Xfake_acid_5, FALSE, FALSE,
4713 EL_EMC_FAKE_ACID, -1, -1
4716 Xfake_acid_6, FALSE, FALSE,
4717 EL_EMC_FAKE_ACID, -1, -1
4720 Xfake_acid_7, FALSE, FALSE,
4721 EL_EMC_FAKE_ACID, -1, -1
4724 Xfake_acid_8, FALSE, FALSE,
4725 EL_EMC_FAKE_ACID, -1, -1
4728 Xsteel_1, TRUE, FALSE,
4729 EL_STEELWALL, -1, -1
4732 Xsteel_2, TRUE, FALSE,
4733 EL_EMC_STEELWALL_2, -1, -1
4736 Xsteel_3, TRUE, FALSE,
4737 EL_EMC_STEELWALL_3, -1, -1
4740 Xsteel_4, TRUE, FALSE,
4741 EL_EMC_STEELWALL_4, -1, -1
4744 Xwall_1, TRUE, FALSE,
4748 Xwall_2, TRUE, FALSE,
4749 EL_EMC_WALL_14, -1, -1
4752 Xwall_3, TRUE, FALSE,
4753 EL_EMC_WALL_15, -1, -1
4756 Xwall_4, TRUE, FALSE,
4757 EL_EMC_WALL_16, -1, -1
4760 Xround_wall_1, TRUE, FALSE,
4761 EL_WALL_SLIPPERY, -1, -1
4764 Xround_wall_2, TRUE, FALSE,
4765 EL_EMC_WALL_SLIPPERY_2, -1, -1
4768 Xround_wall_3, TRUE, FALSE,
4769 EL_EMC_WALL_SLIPPERY_3, -1, -1
4772 Xround_wall_4, TRUE, FALSE,
4773 EL_EMC_WALL_SLIPPERY_4, -1, -1
4776 Xdecor_1, TRUE, FALSE,
4777 EL_EMC_WALL_8, -1, -1
4780 Xdecor_2, TRUE, FALSE,
4781 EL_EMC_WALL_6, -1, -1
4784 Xdecor_3, TRUE, FALSE,
4785 EL_EMC_WALL_4, -1, -1
4788 Xdecor_4, TRUE, FALSE,
4789 EL_EMC_WALL_7, -1, -1
4792 Xdecor_5, TRUE, FALSE,
4793 EL_EMC_WALL_5, -1, -1
4796 Xdecor_6, TRUE, FALSE,
4797 EL_EMC_WALL_9, -1, -1
4800 Xdecor_7, TRUE, FALSE,
4801 EL_EMC_WALL_10, -1, -1
4804 Xdecor_8, TRUE, FALSE,
4805 EL_EMC_WALL_1, -1, -1
4808 Xdecor_9, TRUE, FALSE,
4809 EL_EMC_WALL_2, -1, -1
4812 Xdecor_10, TRUE, FALSE,
4813 EL_EMC_WALL_3, -1, -1
4816 Xdecor_11, TRUE, FALSE,
4817 EL_EMC_WALL_11, -1, -1
4820 Xdecor_12, TRUE, FALSE,
4821 EL_EMC_WALL_12, -1, -1
4824 Xalpha_0, TRUE, FALSE,
4825 EL_CHAR('0'), -1, -1
4828 Xalpha_1, TRUE, FALSE,
4829 EL_CHAR('1'), -1, -1
4832 Xalpha_2, TRUE, FALSE,
4833 EL_CHAR('2'), -1, -1
4836 Xalpha_3, TRUE, FALSE,
4837 EL_CHAR('3'), -1, -1
4840 Xalpha_4, TRUE, FALSE,
4841 EL_CHAR('4'), -1, -1
4844 Xalpha_5, TRUE, FALSE,
4845 EL_CHAR('5'), -1, -1
4848 Xalpha_6, TRUE, FALSE,
4849 EL_CHAR('6'), -1, -1
4852 Xalpha_7, TRUE, FALSE,
4853 EL_CHAR('7'), -1, -1
4856 Xalpha_8, TRUE, FALSE,
4857 EL_CHAR('8'), -1, -1
4860 Xalpha_9, TRUE, FALSE,
4861 EL_CHAR('9'), -1, -1
4864 Xalpha_excla, TRUE, FALSE,
4865 EL_CHAR('!'), -1, -1
4868 Xalpha_quote, TRUE, FALSE,
4869 EL_CHAR('"'), -1, -1
4872 Xalpha_comma, TRUE, FALSE,
4873 EL_CHAR(','), -1, -1
4876 Xalpha_minus, TRUE, FALSE,
4877 EL_CHAR('-'), -1, -1
4880 Xalpha_perio, TRUE, FALSE,
4881 EL_CHAR('.'), -1, -1
4884 Xalpha_colon, TRUE, FALSE,
4885 EL_CHAR(':'), -1, -1
4888 Xalpha_quest, TRUE, FALSE,
4889 EL_CHAR('?'), -1, -1
4892 Xalpha_a, TRUE, FALSE,
4893 EL_CHAR('A'), -1, -1
4896 Xalpha_b, TRUE, FALSE,
4897 EL_CHAR('B'), -1, -1
4900 Xalpha_c, TRUE, FALSE,
4901 EL_CHAR('C'), -1, -1
4904 Xalpha_d, TRUE, FALSE,
4905 EL_CHAR('D'), -1, -1
4908 Xalpha_e, TRUE, FALSE,
4909 EL_CHAR('E'), -1, -1
4912 Xalpha_f, TRUE, FALSE,
4913 EL_CHAR('F'), -1, -1
4916 Xalpha_g, TRUE, FALSE,
4917 EL_CHAR('G'), -1, -1
4920 Xalpha_h, TRUE, FALSE,
4921 EL_CHAR('H'), -1, -1
4924 Xalpha_i, TRUE, FALSE,
4925 EL_CHAR('I'), -1, -1
4928 Xalpha_j, TRUE, FALSE,
4929 EL_CHAR('J'), -1, -1
4932 Xalpha_k, TRUE, FALSE,
4933 EL_CHAR('K'), -1, -1
4936 Xalpha_l, TRUE, FALSE,
4937 EL_CHAR('L'), -1, -1
4940 Xalpha_m, TRUE, FALSE,
4941 EL_CHAR('M'), -1, -1
4944 Xalpha_n, TRUE, FALSE,
4945 EL_CHAR('N'), -1, -1
4948 Xalpha_o, TRUE, FALSE,
4949 EL_CHAR('O'), -1, -1
4952 Xalpha_p, TRUE, FALSE,
4953 EL_CHAR('P'), -1, -1
4956 Xalpha_q, TRUE, FALSE,
4957 EL_CHAR('Q'), -1, -1
4960 Xalpha_r, TRUE, FALSE,
4961 EL_CHAR('R'), -1, -1
4964 Xalpha_s, TRUE, FALSE,
4965 EL_CHAR('S'), -1, -1
4968 Xalpha_t, TRUE, FALSE,
4969 EL_CHAR('T'), -1, -1
4972 Xalpha_u, TRUE, FALSE,
4973 EL_CHAR('U'), -1, -1
4976 Xalpha_v, TRUE, FALSE,
4977 EL_CHAR('V'), -1, -1
4980 Xalpha_w, TRUE, FALSE,
4981 EL_CHAR('W'), -1, -1
4984 Xalpha_x, TRUE, FALSE,
4985 EL_CHAR('X'), -1, -1
4988 Xalpha_y, TRUE, FALSE,
4989 EL_CHAR('Y'), -1, -1
4992 Xalpha_z, TRUE, FALSE,
4993 EL_CHAR('Z'), -1, -1
4996 Xalpha_arrow_e, TRUE, FALSE,
4997 EL_CHAR('>'), -1, -1
5000 Xalpha_arrow_w, TRUE, FALSE,
5001 EL_CHAR('<'), -1, -1
5004 Xalpha_copyr, TRUE, FALSE,
5005 EL_CHAR('©'), -1, -1
5009 Xboom_bug, FALSE, FALSE,
5010 EL_BUG, ACTION_EXPLODING, -1
5013 Xboom_bomb, FALSE, FALSE,
5014 EL_BOMB, ACTION_EXPLODING, -1
5017 Xboom_android, FALSE, FALSE,
5018 EL_EMC_ANDROID, ACTION_OTHER, -1
5021 Xboom_1, FALSE, FALSE,
5022 EL_DEFAULT, ACTION_EXPLODING, -1
5025 Xboom_2, FALSE, FALSE,
5026 EL_DEFAULT, ACTION_EXPLODING, -1
5029 Znormal, FALSE, FALSE,
5033 Zdynamite, FALSE, FALSE,
5037 Zplayer, FALSE, FALSE,
5041 ZBORDER, FALSE, FALSE,
5051 static struct Mapping_EM_to_RND_player
5060 em_player_mapping_list[] =
5064 EL_PLAYER_1, ACTION_MOVING, MV_BIT_UP,
5068 EL_PLAYER_1, ACTION_MOVING, MV_BIT_RIGHT,
5072 EL_PLAYER_1, ACTION_MOVING, MV_BIT_DOWN,
5076 EL_PLAYER_1, ACTION_MOVING, MV_BIT_LEFT,
5080 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_UP,
5084 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_RIGHT,
5088 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_DOWN,
5092 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_LEFT,
5096 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_UP,
5100 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_RIGHT,
5104 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_DOWN,
5108 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_LEFT,
5112 EL_PLAYER_2, ACTION_MOVING, MV_BIT_UP,
5116 EL_PLAYER_2, ACTION_MOVING, MV_BIT_RIGHT,
5120 EL_PLAYER_2, ACTION_MOVING, MV_BIT_DOWN,
5124 EL_PLAYER_2, ACTION_MOVING, MV_BIT_LEFT,
5128 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_UP,
5132 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_RIGHT,
5136 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_DOWN,
5140 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_LEFT,
5144 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_UP,
5148 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_RIGHT,
5152 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_DOWN,
5156 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_LEFT,
5160 EL_PLAYER_1, ACTION_DEFAULT, -1,
5164 EL_PLAYER_2, ACTION_DEFAULT, -1,
5168 EL_PLAYER_3, ACTION_MOVING, MV_BIT_UP,
5172 EL_PLAYER_3, ACTION_MOVING, MV_BIT_RIGHT,
5176 EL_PLAYER_3, ACTION_MOVING, MV_BIT_DOWN,
5180 EL_PLAYER_3, ACTION_MOVING, MV_BIT_LEFT,
5184 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_UP,
5188 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_RIGHT,
5192 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_DOWN,
5196 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_LEFT,
5200 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_UP,
5204 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_RIGHT,
5208 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_DOWN,
5212 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_LEFT,
5216 EL_PLAYER_4, ACTION_MOVING, MV_BIT_UP,
5220 EL_PLAYER_4, ACTION_MOVING, MV_BIT_RIGHT,
5224 EL_PLAYER_4, ACTION_MOVING, MV_BIT_DOWN,
5228 EL_PLAYER_4, ACTION_MOVING, MV_BIT_LEFT,
5232 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_UP,
5236 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_RIGHT,
5240 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_DOWN,
5244 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_LEFT,
5248 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_UP,
5252 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_RIGHT,
5256 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_DOWN,
5260 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_LEFT,
5264 EL_PLAYER_3, ACTION_DEFAULT, -1,
5268 EL_PLAYER_4, ACTION_DEFAULT, -1,
5277 int map_element_RND_to_EM(int element_rnd)
5279 static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
5280 static boolean mapping_initialized = FALSE;
5282 if (!mapping_initialized)
5286 /* return "Xalpha_quest" for all undefined elements in mapping array */
5287 for (i = 0; i < NUM_FILE_ELEMENTS; i++)
5288 mapping_RND_to_EM[i] = Xalpha_quest;
5290 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5291 if (em_object_mapping_list[i].is_rnd_to_em_mapping)
5292 mapping_RND_to_EM[em_object_mapping_list[i].element_rnd] =
5293 em_object_mapping_list[i].element_em;
5295 mapping_initialized = TRUE;
5298 if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
5299 return mapping_RND_to_EM[element_rnd];
5301 Error(ERR_WARN, "invalid RND level element %d", element_rnd);
5306 int map_element_EM_to_RND(int element_em)
5308 static unsigned short mapping_EM_to_RND[TILE_MAX];
5309 static boolean mapping_initialized = FALSE;
5311 if (!mapping_initialized)
5315 /* return "EL_UNKNOWN" for all undefined elements in mapping array */
5316 for (i = 0; i < TILE_MAX; i++)
5317 mapping_EM_to_RND[i] = EL_UNKNOWN;
5319 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5320 mapping_EM_to_RND[em_object_mapping_list[i].element_em] =
5321 em_object_mapping_list[i].element_rnd;
5323 mapping_initialized = TRUE;
5326 if (element_em >= 0 && element_em < TILE_MAX)
5327 return mapping_EM_to_RND[element_em];
5329 Error(ERR_WARN, "invalid EM level element %d", element_em);
5334 void map_android_clone_elements_RND_to_EM(struct LevelInfo *level)
5336 struct LevelInfo_EM *level_em = level->native_em_level;
5337 struct LEVEL *lev = level_em->lev;
5340 for (i = 0; i < TILE_MAX; i++)
5341 lev->android_array[i] = Xblank;
5343 for (i = 0; i < level->num_android_clone_elements; i++)
5345 int element_rnd = level->android_clone_element[i];
5346 int element_em = map_element_RND_to_EM(element_rnd);
5348 for (j = 0; em_object_mapping_list[j].element_em != -1; j++)
5349 if (em_object_mapping_list[j].element_rnd == element_rnd)
5350 lev->android_array[em_object_mapping_list[j].element_em] = element_em;
5354 void map_android_clone_elements_EM_to_RND(struct LevelInfo *level)
5356 struct LevelInfo_EM *level_em = level->native_em_level;
5357 struct LEVEL *lev = level_em->lev;
5360 level->num_android_clone_elements = 0;
5362 for (i = 0; i < TILE_MAX; i++)
5364 int element_em = lev->android_array[i];
5366 boolean element_found = FALSE;
5368 if (element_em == Xblank)
5371 element_rnd = map_element_EM_to_RND(element_em);
5373 for (j = 0; j < level->num_android_clone_elements; j++)
5374 if (level->android_clone_element[j] == element_rnd)
5375 element_found = TRUE;
5379 level->android_clone_element[level->num_android_clone_elements++] =
5382 if (level->num_android_clone_elements == MAX_ANDROID_ELEMENTS)
5387 if (level->num_android_clone_elements == 0)
5389 level->num_android_clone_elements = 1;
5390 level->android_clone_element[0] = EL_EMPTY;
5394 int map_direction_RND_to_EM(int direction)
5396 return (direction == MV_UP ? 0 :
5397 direction == MV_RIGHT ? 1 :
5398 direction == MV_DOWN ? 2 :
5399 direction == MV_LEFT ? 3 :
5403 int map_direction_EM_to_RND(int direction)
5405 return (direction == 0 ? MV_UP :
5406 direction == 1 ? MV_RIGHT :
5407 direction == 2 ? MV_DOWN :
5408 direction == 3 ? MV_LEFT :
5412 int get_next_element(int element)
5416 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
5417 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
5418 case EL_QUICKSAND_FAST_FILLING: return EL_QUICKSAND_FAST_FULL;
5419 case EL_QUICKSAND_FAST_EMPTYING: return EL_QUICKSAND_FAST_EMPTY;
5420 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
5421 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
5422 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
5423 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
5424 case EL_DC_MAGIC_WALL_FILLING: return EL_DC_MAGIC_WALL_FULL;
5425 case EL_DC_MAGIC_WALL_EMPTYING: return EL_DC_MAGIC_WALL_ACTIVE;
5426 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
5428 default: return element;
5433 int el_act_dir2img(int element, int action, int direction)
5435 element = GFX_ELEMENT(element);
5437 if (direction == MV_NONE)
5438 return element_info[element].graphic[action];
5440 direction = MV_DIR_TO_BIT(direction);
5442 return element_info[element].direction_graphic[action][direction];
5445 int el_act_dir2img(int element, int action, int direction)
5447 element = GFX_ELEMENT(element);
5448 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
5450 /* direction_graphic[][] == graphic[] for undefined direction graphics */
5451 return element_info[element].direction_graphic[action][direction];
5456 static int el_act_dir2crm(int element, int action, int direction)
5458 element = GFX_ELEMENT(element);
5460 if (direction == MV_NONE)
5461 return element_info[element].crumbled[action];
5463 direction = MV_DIR_TO_BIT(direction);
5465 return element_info[element].direction_crumbled[action][direction];
5468 static int el_act_dir2crm(int element, int action, int direction)
5470 element = GFX_ELEMENT(element);
5471 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
5473 /* direction_graphic[][] == graphic[] for undefined direction graphics */
5474 return element_info[element].direction_crumbled[action][direction];
5478 int el_act2img(int element, int action)
5480 element = GFX_ELEMENT(element);
5482 return element_info[element].graphic[action];
5485 int el_act2crm(int element, int action)
5487 element = GFX_ELEMENT(element);
5489 return element_info[element].crumbled[action];
5492 int el_dir2img(int element, int direction)
5494 element = GFX_ELEMENT(element);
5496 return el_act_dir2img(element, ACTION_DEFAULT, direction);
5499 int el2baseimg(int element)
5501 return element_info[element].graphic[ACTION_DEFAULT];
5504 int el2img(int element)
5506 element = GFX_ELEMENT(element);
5508 return element_info[element].graphic[ACTION_DEFAULT];
5511 int el2edimg(int element)
5513 element = GFX_ELEMENT(element);
5515 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
5518 int el2preimg(int element)
5520 element = GFX_ELEMENT(element);
5522 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
5525 int font2baseimg(int font_nr)
5527 return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
5530 int getNumActivePlayers_EM()
5532 int num_players = 0;
5538 for (i = 0; i < MAX_PLAYERS; i++)
5539 if (tape.player_participates[i])
5545 int getGameFrameDelay_EM(int native_em_game_frame_delay)
5547 int game_frame_delay_value;
5549 game_frame_delay_value =
5550 (tape.playing && tape.fast_forward ? FfwdFrameDelay :
5551 GameFrameDelay == GAME_FRAME_DELAY ? native_em_game_frame_delay :
5554 if (tape.playing && tape.warp_forward && !tape.pausing)
5555 game_frame_delay_value = 0;
5557 return game_frame_delay_value;
5560 unsigned int InitRND(long seed)
5562 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
5563 return InitEngineRandom_EM(seed);
5565 return InitEngineRandom_RND(seed);
5568 void InitGraphicInfo_EM(void)
5570 struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
5571 struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
5575 int num_em_gfx_errors = 0;
5577 if (graphic_info_em_object[0][0].bitmap == NULL)
5579 /* EM graphics not yet initialized in em_open_all() */
5584 printf("::: [4 errors can be ignored (1 x 'bomb', 3 x 'em_dynamite']\n");
5587 /* always start with reliable default values */
5588 for (i = 0; i < TILE_MAX; i++)
5590 object_mapping[i].element_rnd = EL_UNKNOWN;
5591 object_mapping[i].is_backside = FALSE;
5592 object_mapping[i].action = ACTION_DEFAULT;
5593 object_mapping[i].direction = MV_NONE;
5596 /* always start with reliable default values */
5597 for (p = 0; p < MAX_PLAYERS; p++)
5599 for (i = 0; i < SPR_MAX; i++)
5601 player_mapping[p][i].element_rnd = EL_UNKNOWN;
5602 player_mapping[p][i].action = ACTION_DEFAULT;
5603 player_mapping[p][i].direction = MV_NONE;
5607 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5609 int e = em_object_mapping_list[i].element_em;
5611 object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd;
5612 object_mapping[e].is_backside = em_object_mapping_list[i].is_backside;
5614 if (em_object_mapping_list[i].action != -1)
5615 object_mapping[e].action = em_object_mapping_list[i].action;
5617 if (em_object_mapping_list[i].direction != -1)
5618 object_mapping[e].direction =
5619 MV_DIR_FROM_BIT(em_object_mapping_list[i].direction);
5622 for (i = 0; em_player_mapping_list[i].action_em != -1; i++)
5624 int a = em_player_mapping_list[i].action_em;
5625 int p = em_player_mapping_list[i].player_nr;
5627 player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd;
5629 if (em_player_mapping_list[i].action != -1)
5630 player_mapping[p][a].action = em_player_mapping_list[i].action;
5632 if (em_player_mapping_list[i].direction != -1)
5633 player_mapping[p][a].direction =
5634 MV_DIR_FROM_BIT(em_player_mapping_list[i].direction);
5637 for (i = 0; i < TILE_MAX; i++)
5639 int element = object_mapping[i].element_rnd;
5640 int action = object_mapping[i].action;
5641 int direction = object_mapping[i].direction;
5642 boolean is_backside = object_mapping[i].is_backside;
5643 boolean action_removing = (action == ACTION_DIGGING ||
5644 action == ACTION_SNAPPING ||
5645 action == ACTION_COLLECTING);
5646 boolean action_exploding = ((action == ACTION_EXPLODING ||
5647 action == ACTION_SMASHED_BY_ROCK ||
5648 action == ACTION_SMASHED_BY_SPRING) &&
5649 element != EL_DIAMOND);
5650 boolean action_active = (action == ACTION_ACTIVE);
5651 boolean action_other = (action == ACTION_OTHER);
5653 for (j = 0; j < 8; j++)
5655 int effective_element = (j > 5 && i == Yacid_splash_eB ? EL_EMPTY :
5656 j > 5 && i == Yacid_splash_wB ? EL_EMPTY :
5658 i == Xdrip_stretch ? element :
5659 i == Xdrip_stretchB ? element :
5660 i == Ydrip_s1 ? element :
5661 i == Ydrip_s1B ? element :
5662 i == Xball_1B ? element :
5663 i == Xball_2 ? element :
5664 i == Xball_2B ? element :
5665 i == Yball_eat ? element :
5666 i == Ykey_1_eat ? element :
5667 i == Ykey_2_eat ? element :
5668 i == Ykey_3_eat ? element :
5669 i == Ykey_4_eat ? element :
5670 i == Ykey_5_eat ? element :
5671 i == Ykey_6_eat ? element :
5672 i == Ykey_7_eat ? element :
5673 i == Ykey_8_eat ? element :
5674 i == Ylenses_eat ? element :
5675 i == Ymagnify_eat ? element :
5676 i == Ygrass_eat ? element :
5677 i == Ydirt_eat ? element :
5678 i == Yemerald_stone ? EL_EMERALD :
5679 i == Ydiamond_stone ? EL_ROCK :
5680 i == Xsand_stonein_1 ? element :
5681 i == Xsand_stonein_2 ? element :
5682 i == Xsand_stonein_3 ? element :
5683 i == Xsand_stonein_4 ? element :
5684 is_backside ? EL_EMPTY :
5685 action_removing ? EL_EMPTY :
5687 int effective_action = (j < 7 ? action :
5688 i == Xdrip_stretch ? action :
5689 i == Xdrip_stretchB ? action :
5690 i == Ydrip_s1 ? action :
5691 i == Ydrip_s1B ? action :
5692 i == Xball_1B ? action :
5693 i == Xball_2 ? action :
5694 i == Xball_2B ? action :
5695 i == Yball_eat ? action :
5696 i == Ykey_1_eat ? action :
5697 i == Ykey_2_eat ? action :
5698 i == Ykey_3_eat ? action :
5699 i == Ykey_4_eat ? action :
5700 i == Ykey_5_eat ? action :
5701 i == Ykey_6_eat ? action :
5702 i == Ykey_7_eat ? action :
5703 i == Ykey_8_eat ? action :
5704 i == Ylenses_eat ? action :
5705 i == Ymagnify_eat ? action :
5706 i == Ygrass_eat ? action :
5707 i == Ydirt_eat ? action :
5708 i == Xsand_stonein_1 ? action :
5709 i == Xsand_stonein_2 ? action :
5710 i == Xsand_stonein_3 ? action :
5711 i == Xsand_stonein_4 ? action :
5712 i == Xsand_stoneout_1 ? action :
5713 i == Xsand_stoneout_2 ? action :
5714 i == Xboom_android ? ACTION_EXPLODING :
5715 action_exploding ? ACTION_EXPLODING :
5716 action_active ? action :
5717 action_other ? action :
5719 int graphic = (el_act_dir2img(effective_element, effective_action,
5721 int crumbled = (el_act_dir2crm(effective_element, effective_action,
5723 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
5724 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
5725 boolean has_action_graphics = (graphic != base_graphic);
5726 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
5727 struct GraphicInfo *g = &graphic_info[graphic];
5728 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
5731 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
5732 boolean special_animation = (action != ACTION_DEFAULT &&
5733 g->anim_frames == 3 &&
5734 g->anim_delay == 2 &&
5735 g->anim_mode & ANIM_LINEAR);
5736 int sync_frame = (i == Xdrip_stretch ? 7 :
5737 i == Xdrip_stretchB ? 7 :
5738 i == Ydrip_s2 ? j + 8 :
5739 i == Ydrip_s2B ? j + 8 :
5748 i == Xfake_acid_1 ? 0 :
5749 i == Xfake_acid_2 ? 10 :
5750 i == Xfake_acid_3 ? 20 :
5751 i == Xfake_acid_4 ? 30 :
5752 i == Xfake_acid_5 ? 40 :
5753 i == Xfake_acid_6 ? 50 :
5754 i == Xfake_acid_7 ? 60 :
5755 i == Xfake_acid_8 ? 70 :
5757 i == Xball_2B ? j + 8 :
5758 i == Yball_eat ? j + 1 :
5759 i == Ykey_1_eat ? j + 1 :
5760 i == Ykey_2_eat ? j + 1 :
5761 i == Ykey_3_eat ? j + 1 :
5762 i == Ykey_4_eat ? j + 1 :
5763 i == Ykey_5_eat ? j + 1 :
5764 i == Ykey_6_eat ? j + 1 :
5765 i == Ykey_7_eat ? j + 1 :
5766 i == Ykey_8_eat ? j + 1 :
5767 i == Ylenses_eat ? j + 1 :
5768 i == Ymagnify_eat ? j + 1 :
5769 i == Ygrass_eat ? j + 1 :
5770 i == Ydirt_eat ? j + 1 :
5771 i == Xamoeba_1 ? 0 :
5772 i == Xamoeba_2 ? 1 :
5773 i == Xamoeba_3 ? 2 :
5774 i == Xamoeba_4 ? 3 :
5775 i == Xamoeba_5 ? 0 :
5776 i == Xamoeba_6 ? 1 :
5777 i == Xamoeba_7 ? 2 :
5778 i == Xamoeba_8 ? 3 :
5779 i == Xexit_2 ? j + 8 :
5780 i == Xexit_3 ? j + 16 :
5781 i == Xdynamite_1 ? 0 :
5782 i == Xdynamite_2 ? 8 :
5783 i == Xdynamite_3 ? 16 :
5784 i == Xdynamite_4 ? 24 :
5785 i == Xsand_stonein_1 ? j + 1 :
5786 i == Xsand_stonein_2 ? j + 9 :
5787 i == Xsand_stonein_3 ? j + 17 :
5788 i == Xsand_stonein_4 ? j + 25 :
5789 i == Xsand_stoneout_1 && j == 0 ? 0 :
5790 i == Xsand_stoneout_1 && j == 1 ? 0 :
5791 i == Xsand_stoneout_1 && j == 2 ? 1 :
5792 i == Xsand_stoneout_1 && j == 3 ? 2 :
5793 i == Xsand_stoneout_1 && j == 4 ? 2 :
5794 i == Xsand_stoneout_1 && j == 5 ? 3 :
5795 i == Xsand_stoneout_1 && j == 6 ? 4 :
5796 i == Xsand_stoneout_1 && j == 7 ? 4 :
5797 i == Xsand_stoneout_2 && j == 0 ? 5 :
5798 i == Xsand_stoneout_2 && j == 1 ? 6 :
5799 i == Xsand_stoneout_2 && j == 2 ? 7 :
5800 i == Xsand_stoneout_2 && j == 3 ? 8 :
5801 i == Xsand_stoneout_2 && j == 4 ? 9 :
5802 i == Xsand_stoneout_2 && j == 5 ? 11 :
5803 i == Xsand_stoneout_2 && j == 6 ? 13 :
5804 i == Xsand_stoneout_2 && j == 7 ? 15 :
5805 i == Xboom_bug && j == 1 ? 2 :
5806 i == Xboom_bug && j == 2 ? 2 :
5807 i == Xboom_bug && j == 3 ? 4 :
5808 i == Xboom_bug && j == 4 ? 4 :
5809 i == Xboom_bug && j == 5 ? 2 :
5810 i == Xboom_bug && j == 6 ? 2 :
5811 i == Xboom_bug && j == 7 ? 0 :
5812 i == Xboom_bomb && j == 1 ? 2 :
5813 i == Xboom_bomb && j == 2 ? 2 :
5814 i == Xboom_bomb && j == 3 ? 4 :
5815 i == Xboom_bomb && j == 4 ? 4 :
5816 i == Xboom_bomb && j == 5 ? 2 :
5817 i == Xboom_bomb && j == 6 ? 2 :
5818 i == Xboom_bomb && j == 7 ? 0 :
5819 i == Xboom_android && j == 7 ? 6 :
5820 i == Xboom_1 && j == 1 ? 2 :
5821 i == Xboom_1 && j == 2 ? 2 :
5822 i == Xboom_1 && j == 3 ? 4 :
5823 i == Xboom_1 && j == 4 ? 4 :
5824 i == Xboom_1 && j == 5 ? 6 :
5825 i == Xboom_1 && j == 6 ? 6 :
5826 i == Xboom_1 && j == 7 ? 8 :
5827 i == Xboom_2 && j == 0 ? 8 :
5828 i == Xboom_2 && j == 1 ? 8 :
5829 i == Xboom_2 && j == 2 ? 10 :
5830 i == Xboom_2 && j == 3 ? 10 :
5831 i == Xboom_2 && j == 4 ? 10 :
5832 i == Xboom_2 && j == 5 ? 12 :
5833 i == Xboom_2 && j == 6 ? 12 :
5834 i == Xboom_2 && j == 7 ? 12 :
5835 special_animation && j == 4 ? 3 :
5836 effective_action != action ? 0 :
5840 Bitmap *debug_bitmap = g_em->bitmap;
5841 int debug_src_x = g_em->src_x;
5842 int debug_src_y = g_em->src_y;
5845 int frame = getAnimationFrame(g->anim_frames,
5848 g->anim_start_frame,
5851 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y,
5852 g->double_movement && is_backside);
5854 g_em->bitmap = src_bitmap;
5855 g_em->src_x = src_x;
5856 g_em->src_y = src_y;
5857 g_em->src_offset_x = 0;
5858 g_em->src_offset_y = 0;
5859 g_em->dst_offset_x = 0;
5860 g_em->dst_offset_y = 0;
5861 g_em->width = TILEX;
5862 g_em->height = TILEY;
5864 g_em->crumbled_bitmap = NULL;
5865 g_em->crumbled_src_x = 0;
5866 g_em->crumbled_src_y = 0;
5867 g_em->crumbled_border_size = 0;
5869 g_em->has_crumbled_graphics = FALSE;
5870 g_em->preserve_background = FALSE;
5873 if (has_crumbled_graphics && crumbled == IMG_EMPTY_SPACE)
5874 printf("::: empty crumbled: %d [%s], %d, %d\n",
5875 effective_element, element_info[effective_element].token_name,
5876 effective_action, direction);
5879 /* if element can be crumbled, but certain action graphics are just empty
5880 space (like snapping sand with the original R'n'D graphics), do not
5881 treat these empty space graphics as crumbled graphics in EMC engine */
5882 if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
5884 getGraphicSource(crumbled, frame, &src_bitmap, &src_x, &src_y);
5886 g_em->has_crumbled_graphics = TRUE;
5887 g_em->crumbled_bitmap = src_bitmap;
5888 g_em->crumbled_src_x = src_x;
5889 g_em->crumbled_src_y = src_y;
5890 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
5894 if (element == EL_ROCK &&
5895 effective_action == ACTION_FILLING)
5896 printf("::: has_action_graphics == %d\n", has_action_graphics);
5899 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
5900 effective_action == ACTION_MOVING ||
5901 effective_action == ACTION_PUSHING ||
5902 effective_action == ACTION_EATING)) ||
5903 (!has_action_graphics && (effective_action == ACTION_FILLING ||
5904 effective_action == ACTION_EMPTYING)))
5907 (effective_action == ACTION_FALLING ||
5908 effective_action == ACTION_FILLING ||
5909 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
5910 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
5911 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
5912 int num_steps = (i == Ydrip_s1 ? 16 :
5913 i == Ydrip_s1B ? 16 :
5914 i == Ydrip_s2 ? 16 :
5915 i == Ydrip_s2B ? 16 :
5916 i == Xsand_stonein_1 ? 32 :
5917 i == Xsand_stonein_2 ? 32 :
5918 i == Xsand_stonein_3 ? 32 :
5919 i == Xsand_stonein_4 ? 32 :
5920 i == Xsand_stoneout_1 ? 16 :
5921 i == Xsand_stoneout_2 ? 16 : 8);
5922 int cx = ABS(dx) * (TILEX / num_steps);
5923 int cy = ABS(dy) * (TILEY / num_steps);
5924 int step_frame = (i == Ydrip_s2 ? j + 8 :
5925 i == Ydrip_s2B ? j + 8 :
5926 i == Xsand_stonein_2 ? j + 8 :
5927 i == Xsand_stonein_3 ? j + 16 :
5928 i == Xsand_stonein_4 ? j + 24 :
5929 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
5930 int step = (is_backside ? step_frame : num_steps - step_frame);
5932 if (is_backside) /* tile where movement starts */
5934 if (dx < 0 || dy < 0)
5936 g_em->src_offset_x = cx * step;
5937 g_em->src_offset_y = cy * step;
5941 g_em->dst_offset_x = cx * step;
5942 g_em->dst_offset_y = cy * step;
5945 else /* tile where movement ends */
5947 if (dx < 0 || dy < 0)
5949 g_em->dst_offset_x = cx * step;
5950 g_em->dst_offset_y = cy * step;
5954 g_em->src_offset_x = cx * step;
5955 g_em->src_offset_y = cy * step;
5959 g_em->width = TILEX - cx * step;
5960 g_em->height = TILEY - cy * step;
5963 /* create unique graphic identifier to decide if tile must be redrawn */
5964 /* bit 31 - 16 (16 bit): EM style graphic
5965 bit 15 - 12 ( 4 bit): EM style frame
5966 bit 11 - 6 ( 6 bit): graphic width
5967 bit 5 - 0 ( 6 bit): graphic height */
5968 g_em->unique_identifier =
5969 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
5973 /* skip check for EMC elements not contained in original EMC artwork */
5974 if (element == EL_EMC_FAKE_ACID)
5977 if (g_em->bitmap != debug_bitmap ||
5978 g_em->src_x != debug_src_x ||
5979 g_em->src_y != debug_src_y ||
5980 g_em->src_offset_x != 0 ||
5981 g_em->src_offset_y != 0 ||
5982 g_em->dst_offset_x != 0 ||
5983 g_em->dst_offset_y != 0 ||
5984 g_em->width != TILEX ||
5985 g_em->height != TILEY)
5987 static int last_i = -1;
5995 printf("::: EMC GFX ERROR for element %d -> %d ('%s', '%s', %d)",
5996 i, element, element_info[element].token_name,
5997 element_action_info[effective_action].suffix, direction);
5999 if (element != effective_element)
6000 printf(" [%d ('%s')]",
6002 element_info[effective_element].token_name);
6006 if (g_em->bitmap != debug_bitmap)
6007 printf(" %d (%d): different bitmap! (0x%08x != 0x%08x)\n",
6008 j, is_backside, (int)(g_em->bitmap), (int)(debug_bitmap));
6010 if (g_em->src_x != debug_src_x ||
6011 g_em->src_y != debug_src_y)
6012 printf(" frame %d (%c): %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
6013 j, (is_backside ? 'B' : 'F'),
6014 g_em->src_x, g_em->src_y,
6015 g_em->src_x / 32, g_em->src_y / 32,
6016 debug_src_x, debug_src_y,
6017 debug_src_x / 32, debug_src_y / 32);
6019 if (g_em->src_offset_x != 0 ||
6020 g_em->src_offset_y != 0 ||
6021 g_em->dst_offset_x != 0 ||
6022 g_em->dst_offset_y != 0)
6023 printf(" %d (%d): offsets %d,%d and %d,%d should be all 0\n",
6025 g_em->src_offset_x, g_em->src_offset_y,
6026 g_em->dst_offset_x, g_em->dst_offset_y);
6028 if (g_em->width != TILEX ||
6029 g_em->height != TILEY)
6030 printf(" %d (%d): size %d,%d should be %d,%d\n",
6032 g_em->width, g_em->height, TILEX, TILEY);
6034 num_em_gfx_errors++;
6041 for (i = 0; i < TILE_MAX; i++)
6043 for (j = 0; j < 8; j++)
6045 int element = object_mapping[i].element_rnd;
6046 int action = object_mapping[i].action;
6047 int direction = object_mapping[i].direction;
6048 boolean is_backside = object_mapping[i].is_backside;
6049 int graphic_action = el_act_dir2img(element, action, direction);
6050 int graphic_default = el_act_dir2img(element, ACTION_DEFAULT, direction);
6052 if ((action == ACTION_SMASHED_BY_ROCK ||
6053 action == ACTION_SMASHED_BY_SPRING ||
6054 action == ACTION_EATING) &&
6055 graphic_action == graphic_default)
6057 int e = (action == ACTION_SMASHED_BY_ROCK ? Ystone_s :
6058 action == ACTION_SMASHED_BY_SPRING ? Yspring_s :
6059 direction == MV_LEFT ? (is_backside? Yspring_wB: Yspring_w) :
6060 direction == MV_RIGHT ? (is_backside? Yspring_eB: Yspring_e) :
6063 /* no separate animation for "smashed by rock" -- use rock instead */
6064 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
6065 struct GraphicInfo_EM *g_xx = &graphic_info_em_object[e][7 - j];
6067 g_em->bitmap = g_xx->bitmap;
6068 g_em->src_x = g_xx->src_x;
6069 g_em->src_y = g_xx->src_y;
6070 g_em->src_offset_x = g_xx->src_offset_x;
6071 g_em->src_offset_y = g_xx->src_offset_y;
6072 g_em->dst_offset_x = g_xx->dst_offset_x;
6073 g_em->dst_offset_y = g_xx->dst_offset_y;
6074 g_em->width = g_xx->width;
6075 g_em->height = g_xx->height;
6076 g_em->unique_identifier = g_xx->unique_identifier;
6079 g_em->preserve_background = TRUE;
6084 for (p = 0; p < MAX_PLAYERS; p++)
6086 for (i = 0; i < SPR_MAX; i++)
6088 int element = player_mapping[p][i].element_rnd;
6089 int action = player_mapping[p][i].action;
6090 int direction = player_mapping[p][i].direction;
6092 for (j = 0; j < 8; j++)
6094 int effective_element = element;
6095 int effective_action = action;
6096 int graphic = (direction == MV_NONE ?
6097 el_act2img(effective_element, effective_action) :
6098 el_act_dir2img(effective_element, effective_action,
6100 struct GraphicInfo *g = &graphic_info[graphic];
6101 struct GraphicInfo_EM *g_em = &graphic_info_em_player[p][i][7 - j];
6107 Bitmap *debug_bitmap = g_em->bitmap;
6108 int debug_src_x = g_em->src_x;
6109 int debug_src_y = g_em->src_y;
6112 int frame = getAnimationFrame(g->anim_frames,
6115 g->anim_start_frame,
6118 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x,&src_y, FALSE);
6120 g_em->bitmap = src_bitmap;
6121 g_em->src_x = src_x;
6122 g_em->src_y = src_y;
6123 g_em->src_offset_x = 0;
6124 g_em->src_offset_y = 0;
6125 g_em->dst_offset_x = 0;
6126 g_em->dst_offset_y = 0;
6127 g_em->width = TILEX;
6128 g_em->height = TILEY;
6132 /* skip check for EMC elements not contained in original EMC artwork */
6133 if (element == EL_PLAYER_3 ||
6134 element == EL_PLAYER_4)
6137 if (g_em->bitmap != debug_bitmap ||
6138 g_em->src_x != debug_src_x ||
6139 g_em->src_y != debug_src_y)
6141 static int last_i = -1;
6149 printf("::: EMC GFX ERROR for p/a %d/%d -> %d ('%s', '%s', %d)",
6150 p, i, element, element_info[element].token_name,
6151 element_action_info[effective_action].suffix, direction);
6153 if (element != effective_element)
6154 printf(" [%d ('%s')]",
6156 element_info[effective_element].token_name);
6160 if (g_em->bitmap != debug_bitmap)
6161 printf(" %d: different bitmap! (0x%08x != 0x%08x)\n",
6162 j, (int)(g_em->bitmap), (int)(debug_bitmap));
6164 if (g_em->src_x != debug_src_x ||
6165 g_em->src_y != debug_src_y)
6166 printf(" frame %d: %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
6168 g_em->src_x, g_em->src_y,
6169 g_em->src_x / 32, g_em->src_y / 32,
6170 debug_src_x, debug_src_y,
6171 debug_src_x / 32, debug_src_y / 32);
6173 num_em_gfx_errors++;
6183 printf("::: [%d errors found]\n", num_em_gfx_errors);
6189 void PlayMenuSound()
6191 int sound = menu.sound[game_status];
6193 if (sound == SND_UNDEFINED)
6196 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
6197 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
6200 if (IS_LOOP_SOUND(sound))
6201 PlaySoundLoop(sound);
6206 void PlayMenuSoundStereo(int sound, int stereo_position)
6208 if (sound == SND_UNDEFINED)
6211 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
6212 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
6215 if (IS_LOOP_SOUND(sound))
6216 PlaySoundExt(sound, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_LOOP);
6218 PlaySoundStereo(sound, stereo_position);
6221 void PlayMenuSoundIfLoop()
6223 int sound = menu.sound[game_status];
6225 if (sound == SND_UNDEFINED)
6228 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
6229 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
6232 if (IS_LOOP_SOUND(sound))
6233 PlaySoundLoop(sound);
6236 void PlayMenuMusic()
6238 int music = menu.music[game_status];
6240 if (music == MUS_UNDEFINED)
6243 if (!setup.sound_music)
6249 void PlaySoundActivating()
6252 PlaySound(SND_MENU_ITEM_ACTIVATING);
6256 void PlaySoundSelecting()
6259 PlaySound(SND_MENU_ITEM_SELECTING);
6263 void ToggleFullscreenIfNeeded()
6265 boolean change_fullscreen = (setup.fullscreen !=
6266 video.fullscreen_enabled);
6267 boolean change_fullscreen_mode = (video.fullscreen_enabled &&
6268 !strEqual(setup.fullscreen_mode,
6269 video.fullscreen_mode_current));
6271 if (!video.fullscreen_available)
6275 if (change_fullscreen || change_fullscreen_mode)
6277 if (setup.fullscreen != video.fullscreen_enabled ||
6278 setup.fullscreen_mode != video.fullscreen_mode_current)
6281 Bitmap *tmp_backbuffer = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
6283 /* save backbuffer content which gets lost when toggling fullscreen mode */
6284 BlitBitmap(backbuffer, tmp_backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
6287 if (change_fullscreen_mode)
6289 if (setup.fullscreen && video.fullscreen_enabled)
6292 /* keep fullscreen, but change fullscreen mode (screen resolution) */
6294 /* (this is now set in sdl.c) */
6296 video.fullscreen_mode_current = setup.fullscreen_mode;
6298 video.fullscreen_enabled = FALSE; /* force new fullscreen mode */
6301 /* toggle fullscreen */
6302 ChangeVideoModeIfNeeded(setup.fullscreen);
6304 setup.fullscreen = video.fullscreen_enabled;
6306 /* restore backbuffer content from temporary backbuffer backup bitmap */
6307 BlitBitmap(tmp_backbuffer, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
6309 FreeBitmap(tmp_backbuffer);
6312 /* update visible window/screen */
6313 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
6315 redraw_mask = REDRAW_ALL;