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 TextPosInfo *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 TextPosInfo *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);
1816 if (pos->chars != -1)
1817 max_len_label_text = pos->chars;
1820 for (i = 0; i < max_len_label_text; i++)
1821 label_text[i] = ' ';
1822 label_text[max_len_label_text] = '\0';
1824 if (strlen(label_text) > 0)
1827 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
1829 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
1830 int lypos = MICROLABEL2_YPOS;
1832 DrawText(lxpos, lypos, label_text, font_nr);
1837 (mode == MICROLABEL_LEVEL_NAME ? level.name :
1838 mode == MICROLABEL_LEVEL_AUTHOR_HEAD ? "created by" :
1839 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
1840 mode == MICROLABEL_IMPORTED_FROM_HEAD ? "imported from" :
1841 mode == MICROLABEL_IMPORTED_FROM ? leveldir_current->imported_from :
1842 mode == MICROLABEL_IMPORTED_BY_HEAD ? "imported by" :
1843 mode == MICROLABEL_IMPORTED_BY ? leveldir_current->imported_by :""),
1844 max_len_label_text);
1845 label_text[max_len_label_text] = '\0';
1847 if (strlen(label_text) > 0)
1850 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
1852 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
1853 int lypos = MICROLABEL2_YPOS;
1855 DrawText(lxpos, lypos, label_text, font_nr);
1859 redraw_mask |= REDRAW_MICROLEVEL;
1862 void DrawPreviewLevel(boolean restart)
1864 static unsigned long scroll_delay = 0;
1865 static unsigned long label_delay = 0;
1866 static int from_x, from_y, scroll_direction;
1867 static int label_state, label_counter;
1868 unsigned long scroll_delay_value = preview.step_delay;
1869 boolean show_level_border = (BorderElement != EL_EMPTY);
1870 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
1871 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
1872 int last_game_status = game_status; /* save current game status */
1874 /* force PREVIEW font on preview level */
1875 game_status = GAME_MODE_PSEUDO_PREVIEW;
1882 if (preview.anim_mode == ANIM_CENTERED)
1884 if (level_xsize > preview.xsize)
1885 from_x = (level_xsize - preview.xsize) / 2;
1886 if (level_ysize > preview.ysize)
1887 from_y = (level_ysize - preview.ysize) / 2;
1890 from_x += preview.xoffset;
1891 from_y += preview.yoffset;
1893 scroll_direction = MV_RIGHT;
1897 DrawPreviewLevelExt(from_x, from_y);
1898 DrawPreviewLevelLabelExt(label_state);
1900 /* initialize delay counters */
1901 DelayReached(&scroll_delay, 0);
1902 DelayReached(&label_delay, 0);
1904 if (leveldir_current->name)
1906 struct TextPosInfo *pos = &menu.main.text.level_info_1;
1907 char label_text[MAX_OUTPUT_LINESIZE + 1];
1908 int font_nr = FONT_TEXT_1;
1910 int max_len_label_text = getMaxTextLength(pos, font_nr);
1912 int max_len_label_text = SXSIZE / getFontWidth(font_nr);
1920 if (pos->chars != -1)
1921 max_len_label_text = pos->chars;
1924 strncpy(label_text, leveldir_current->name, max_len_label_text);
1925 label_text[max_len_label_text] = '\0';
1928 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
1930 lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
1931 lypos = SY + MICROLABEL1_YPOS;
1933 DrawText(lxpos, lypos, label_text, font_nr);
1937 game_status = last_game_status; /* restore current game status */
1942 /* scroll preview level, if needed */
1943 if (preview.anim_mode != ANIM_NONE &&
1944 (level_xsize > preview.xsize || level_ysize > preview.ysize) &&
1945 DelayReached(&scroll_delay, scroll_delay_value))
1947 switch (scroll_direction)
1952 from_x -= preview.step_offset;
1953 from_x = (from_x < 0 ? 0 : from_x);
1956 scroll_direction = MV_UP;
1960 if (from_x < level_xsize - preview.xsize)
1962 from_x += preview.step_offset;
1963 from_x = (from_x > level_xsize - preview.xsize ?
1964 level_xsize - preview.xsize : from_x);
1967 scroll_direction = MV_DOWN;
1973 from_y -= preview.step_offset;
1974 from_y = (from_y < 0 ? 0 : from_y);
1977 scroll_direction = MV_RIGHT;
1981 if (from_y < level_ysize - preview.ysize)
1983 from_y += preview.step_offset;
1984 from_y = (from_y > level_ysize - preview.ysize ?
1985 level_ysize - preview.ysize : from_y);
1988 scroll_direction = MV_LEFT;
1995 DrawPreviewLevelExt(from_x, from_y);
1998 /* !!! THIS ALL SUCKS -- SHOULD BE CLEANLY REWRITTEN !!! */
1999 /* redraw micro level label, if needed */
2000 if (!strEqual(level.name, NAMELESS_LEVEL_NAME) &&
2001 !strEqual(level.author, ANONYMOUS_NAME) &&
2002 !strEqual(level.author, leveldir_current->name) &&
2003 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
2005 int max_label_counter = 23;
2007 if (leveldir_current->imported_from != NULL &&
2008 strlen(leveldir_current->imported_from) > 0)
2009 max_label_counter += 14;
2010 if (leveldir_current->imported_by != NULL &&
2011 strlen(leveldir_current->imported_by) > 0)
2012 max_label_counter += 14;
2014 label_counter = (label_counter + 1) % max_label_counter;
2015 label_state = (label_counter >= 0 && label_counter <= 7 ?
2016 MICROLABEL_LEVEL_NAME :
2017 label_counter >= 9 && label_counter <= 12 ?
2018 MICROLABEL_LEVEL_AUTHOR_HEAD :
2019 label_counter >= 14 && label_counter <= 21 ?
2020 MICROLABEL_LEVEL_AUTHOR :
2021 label_counter >= 23 && label_counter <= 26 ?
2022 MICROLABEL_IMPORTED_FROM_HEAD :
2023 label_counter >= 28 && label_counter <= 35 ?
2024 MICROLABEL_IMPORTED_FROM :
2025 label_counter >= 37 && label_counter <= 40 ?
2026 MICROLABEL_IMPORTED_BY_HEAD :
2027 label_counter >= 42 && label_counter <= 49 ?
2028 MICROLABEL_IMPORTED_BY : MICROLABEL_EMPTY);
2030 if (leveldir_current->imported_from == NULL &&
2031 (label_state == MICROLABEL_IMPORTED_FROM_HEAD ||
2032 label_state == MICROLABEL_IMPORTED_FROM))
2033 label_state = (label_state == MICROLABEL_IMPORTED_FROM_HEAD ?
2034 MICROLABEL_IMPORTED_BY_HEAD : MICROLABEL_IMPORTED_BY);
2036 DrawPreviewLevelLabelExt(label_state);
2039 game_status = last_game_status; /* restore current game status */
2042 inline void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
2043 int graphic, int sync_frame, int mask_mode)
2045 int frame = getGraphicAnimationFrame(graphic, sync_frame);
2047 if (mask_mode == USE_MASKING)
2048 DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
2050 DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
2053 inline void DrawGraphicAnimation(int x, int y, int graphic)
2055 int lx = LEVELX(x), ly = LEVELY(y);
2057 if (!IN_SCR_FIELD(x, y))
2060 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
2061 graphic, GfxFrame[lx][ly], NO_MASKING);
2062 MarkTileDirty(x, y);
2065 void DrawLevelGraphicAnimation(int x, int y, int graphic)
2067 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
2070 void DrawLevelElementAnimation(int x, int y, int element)
2072 int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
2074 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
2077 inline void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
2079 int sx = SCREENX(x), sy = SCREENY(y);
2081 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
2084 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
2087 DrawGraphicAnimation(sx, sy, graphic);
2090 if (GFX_CRUMBLED(TILE_GFX_ELEMENT(x, y)))
2091 DrawLevelFieldCrumbledSand(x, y);
2093 if (GFX_CRUMBLED(Feld[x][y]))
2094 DrawLevelFieldCrumbledSand(x, y);
2098 void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
2100 int sx = SCREENX(x), sy = SCREENY(y);
2103 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
2106 graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
2108 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
2111 DrawGraphicAnimation(sx, sy, graphic);
2113 if (GFX_CRUMBLED(element))
2114 DrawLevelFieldCrumbledSand(x, y);
2117 static int getPlayerGraphic(struct PlayerInfo *player, int move_dir)
2119 if (player->use_murphy)
2121 /* this works only because currently only one player can be "murphy" ... */
2122 static int last_horizontal_dir = MV_LEFT;
2123 int graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir);
2125 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
2126 last_horizontal_dir = move_dir;
2128 if (graphic == IMG_SP_MURPHY) /* undefined => use special graphic */
2130 int direction = (player->is_snapping ? move_dir : last_horizontal_dir);
2132 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
2138 return el_act_dir2img(player->artwork_element, player->GfxAction,move_dir);
2141 static boolean equalGraphics(int graphic1, int graphic2)
2143 struct GraphicInfo *g1 = &graphic_info[graphic1];
2144 struct GraphicInfo *g2 = &graphic_info[graphic2];
2146 return (g1->bitmap == g2->bitmap &&
2147 g1->src_x == g2->src_x &&
2148 g1->src_y == g2->src_y &&
2149 g1->anim_frames == g2->anim_frames &&
2150 g1->anim_delay == g2->anim_delay &&
2151 g1->anim_mode == g2->anim_mode);
2154 void DrawAllPlayers()
2158 for (i = 0; i < MAX_PLAYERS; i++)
2159 if (stored_player[i].active)
2160 DrawPlayer(&stored_player[i]);
2163 void DrawPlayerField(int x, int y)
2165 if (!IS_PLAYER(x, y))
2168 DrawPlayer(PLAYERINFO(x, y));
2171 void DrawPlayer(struct PlayerInfo *player)
2173 int jx = player->jx;
2174 int jy = player->jy;
2175 int move_dir = player->MovDir;
2176 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? +1 : 0);
2177 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? +1 : 0);
2178 int last_jx = (player->is_moving ? jx - dx : jx);
2179 int last_jy = (player->is_moving ? jy - dy : jy);
2180 int next_jx = jx + dx;
2181 int next_jy = jy + dy;
2182 boolean player_is_moving = (player->MovPos ? TRUE : FALSE);
2183 boolean player_is_opaque = FALSE;
2184 int sx = SCREENX(jx), sy = SCREENY(jy);
2185 int sxx = 0, syy = 0;
2186 int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
2188 int action = ACTION_DEFAULT;
2189 int last_player_graphic = getPlayerGraphic(player, move_dir);
2190 int last_player_frame = player->Frame;
2193 /* GfxElement[][] is set to the element the player is digging or collecting;
2194 remove also for off-screen player if the player is not moving anymore */
2195 if (IN_LEV_FIELD(jx, jy) && !player_is_moving)
2196 GfxElement[jx][jy] = EL_UNDEFINED;
2198 if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
2202 if (!IN_LEV_FIELD(jx, jy))
2204 printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
2205 printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
2206 printf("DrawPlayerField(): This should never happen!\n");
2211 if (element == EL_EXPLOSION)
2214 action = (player->is_pushing ? ACTION_PUSHING :
2215 player->is_digging ? ACTION_DIGGING :
2216 player->is_collecting ? ACTION_COLLECTING :
2217 player->is_moving ? ACTION_MOVING :
2218 player->is_snapping ? ACTION_SNAPPING :
2219 player->is_dropping ? ACTION_DROPPING :
2220 player->is_waiting ? player->action_waiting : ACTION_DEFAULT);
2222 if (player->is_waiting)
2223 move_dir = player->dir_waiting;
2225 InitPlayerGfxAnimation(player, action, move_dir);
2227 /* ----------------------------------------------------------------------- */
2228 /* draw things in the field the player is leaving, if needed */
2229 /* ----------------------------------------------------------------------- */
2231 if (player->is_moving)
2233 if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
2235 DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
2237 if (last_element == EL_DYNAMITE_ACTIVE ||
2238 last_element == EL_EM_DYNAMITE_ACTIVE ||
2239 last_element == EL_SP_DISK_RED_ACTIVE)
2240 DrawDynamite(last_jx, last_jy);
2242 DrawLevelFieldThruMask(last_jx, last_jy);
2244 else if (last_element == EL_DYNAMITE_ACTIVE ||
2245 last_element == EL_EM_DYNAMITE_ACTIVE ||
2246 last_element == EL_SP_DISK_RED_ACTIVE)
2247 DrawDynamite(last_jx, last_jy);
2249 /* !!! this is not enough to prevent flickering of players which are
2250 moving next to each others without a free tile between them -- this
2251 can only be solved by drawing all players layer by layer (first the
2252 background, then the foreground etc.) !!! => TODO */
2253 else if (!IS_PLAYER(last_jx, last_jy))
2254 DrawLevelField(last_jx, last_jy);
2257 DrawLevelField(last_jx, last_jy);
2260 if (player->is_pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
2261 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
2264 if (!IN_SCR_FIELD(sx, sy))
2267 if (setup.direct_draw)
2268 SetDrawtoField(DRAW_BUFFERED);
2270 /* ----------------------------------------------------------------------- */
2271 /* draw things behind the player, if needed */
2272 /* ----------------------------------------------------------------------- */
2275 DrawLevelElement(jx, jy, Back[jx][jy]);
2276 else if (IS_ACTIVE_BOMB(element))
2277 DrawLevelElement(jx, jy, EL_EMPTY);
2280 if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
2282 int old_element = GfxElement[jx][jy];
2283 int old_graphic = el_act_dir2img(old_element, action, move_dir);
2284 int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
2286 if (GFX_CRUMBLED(old_element))
2287 DrawLevelFieldCrumbledSandDigging(jx, jy, move_dir, player->StepFrame);
2289 DrawGraphic(sx, sy, old_graphic, frame);
2291 if (graphic_info[old_graphic].anim_mode & ANIM_OPAQUE_PLAYER)
2292 player_is_opaque = TRUE;
2296 GfxElement[jx][jy] = EL_UNDEFINED;
2298 /* make sure that pushed elements are drawn with correct frame rate */
2300 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
2302 if (player->is_pushing && player->is_moving && !IS_ANIM_MODE_CE(graphic))
2303 GfxFrame[jx][jy] = player->StepFrame;
2305 if (player->is_pushing && player->is_moving)
2306 GfxFrame[jx][jy] = player->StepFrame;
2309 DrawLevelField(jx, jy);
2313 /* ----------------------------------------------------------------------- */
2314 /* draw player himself */
2315 /* ----------------------------------------------------------------------- */
2317 graphic = getPlayerGraphic(player, move_dir);
2319 /* in the case of changed player action or direction, prevent the current
2320 animation frame from being restarted for identical animations */
2321 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
2322 player->Frame = last_player_frame;
2324 frame = getGraphicAnimationFrame(graphic, player->Frame);
2328 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
2329 sxx = player->GfxPos;
2331 syy = player->GfxPos;
2334 if (!setup.soft_scrolling && ScreenMovPos)
2337 if (player_is_opaque)
2338 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
2340 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
2342 if (SHIELD_ON(player))
2344 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
2345 IMG_SHIELD_NORMAL_ACTIVE);
2346 int frame = getGraphicAnimationFrame(graphic, -1);
2348 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
2351 /* ----------------------------------------------------------------------- */
2352 /* draw things the player is pushing, if needed */
2353 /* ----------------------------------------------------------------------- */
2356 printf("::: %d, %d [%d, %d] [%d]\n",
2357 player->is_pushing, player_is_moving, player->GfxAction,
2358 player->is_moving, player_is_moving);
2362 if (player->is_pushing && player->is_moving)
2364 int px = SCREENX(jx), py = SCREENY(jy);
2365 int pxx = (TILEX - ABS(sxx)) * dx;
2366 int pyy = (TILEY - ABS(syy)) * dy;
2367 int gfx_frame = GfxFrame[jx][jy];
2373 if (!IS_MOVING(jx, jy)) /* push movement already finished */
2375 element = Feld[next_jx][next_jy];
2376 gfx_frame = GfxFrame[next_jx][next_jy];
2379 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
2382 sync_frame = (IS_ANIM_MODE_CE(graphic) ? gfx_frame : player->StepFrame);
2383 frame = getGraphicAnimationFrame(graphic, sync_frame);
2385 frame = getGraphicAnimationFrame(graphic, player->StepFrame);
2388 /* draw background element under pushed element (like the Sokoban field) */
2389 if (Back[next_jx][next_jy])
2390 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
2392 /* masked drawing is needed for EMC style (double) movement graphics */
2393 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
2397 /* ----------------------------------------------------------------------- */
2398 /* draw things in front of player (active dynamite or dynabombs) */
2399 /* ----------------------------------------------------------------------- */
2401 if (IS_ACTIVE_BOMB(element))
2403 graphic = el2img(element);
2404 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
2406 if (game.emulation == EMU_SUPAPLEX)
2407 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
2409 DrawGraphicThruMask(sx, sy, graphic, frame);
2412 if (player_is_moving && last_element == EL_EXPLOSION)
2414 int element = (GfxElement[last_jx][last_jy] != EL_UNDEFINED ?
2415 GfxElement[last_jx][last_jy] : EL_EMPTY);
2416 int graphic = el_act2img(element, ACTION_EXPLODING);
2417 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
2418 int phase = ExplodePhase[last_jx][last_jy] - 1;
2419 int frame = getGraphicAnimationFrame(graphic, phase - delay);
2422 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
2425 /* ----------------------------------------------------------------------- */
2426 /* draw elements the player is just walking/passing through/under */
2427 /* ----------------------------------------------------------------------- */
2429 if (player_is_moving)
2431 /* handle the field the player is leaving ... */
2432 if (IS_ACCESSIBLE_INSIDE(last_element))
2433 DrawLevelField(last_jx, last_jy);
2434 else if (IS_ACCESSIBLE_UNDER(last_element))
2435 DrawLevelFieldThruMask(last_jx, last_jy);
2438 /* do not redraw accessible elements if the player is just pushing them */
2439 if (!player_is_moving || !player->is_pushing)
2441 /* ... and the field the player is entering */
2442 if (IS_ACCESSIBLE_INSIDE(element))
2443 DrawLevelField(jx, jy);
2444 else if (IS_ACCESSIBLE_UNDER(element))
2445 DrawLevelFieldThruMask(jx, jy);
2448 if (setup.direct_draw)
2450 int dst_x = SX + SCREENX(MIN(jx, last_jx)) * TILEX;
2451 int dst_y = SY + SCREENY(MIN(jy, last_jy)) * TILEY;
2452 int x_size = TILEX * (1 + ABS(jx - last_jx));
2453 int y_size = TILEY * (1 + ABS(jy - last_jy));
2455 BlitBitmap(drawto_field, window,
2456 dst_x, dst_y, x_size, y_size, dst_x, dst_y);
2457 SetDrawtoField(DRAW_DIRECT);
2460 MarkTileDirty(sx, sy);
2463 /* ------------------------------------------------------------------------- */
2465 void WaitForEventToContinue()
2467 boolean still_wait = TRUE;
2469 /* simulate releasing mouse button over last gadget, if still pressed */
2471 HandleGadgets(-1, -1, 0);
2473 button_status = MB_RELEASED;
2489 case EVENT_BUTTONPRESS:
2490 case EVENT_KEYPRESS:
2494 case EVENT_KEYRELEASE:
2495 ClearPlayerAction();
2499 HandleOtherEvents(&event);
2503 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2510 /* don't eat all CPU time */
2515 #define MAX_REQUEST_LINES 13
2516 #define MAX_REQUEST_LINE_FONT1_LEN 7
2517 #define MAX_REQUEST_LINE_FONT2_LEN 10
2519 boolean Request(char *text, unsigned int req_state)
2521 int mx, my, ty, result = -1;
2522 unsigned int old_door_state;
2523 int last_game_status = game_status; /* save current game status */
2524 int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
2525 int font_nr = FONT_TEXT_2;
2526 int max_word_len = 0;
2529 for (text_ptr = text; *text_ptr; text_ptr++)
2531 max_word_len = (*text_ptr != ' ' ? max_word_len + 1 : 0);
2533 if (max_word_len > MAX_REQUEST_LINE_FONT1_LEN)
2535 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
2537 font_nr = FONT_TEXT_1;
2539 font_nr = FONT_LEVEL_NUMBER;
2546 if (game_status == GAME_MODE_PLAYING &&
2547 level.game_engine_type == GAME_ENGINE_TYPE_EM)
2548 BlitScreenToBitmap_EM(backbuffer);
2550 /* disable deactivated drawing when quick-loading level tape recording */
2551 if (tape.playing && tape.deactivate_display)
2552 TapeDeactivateDisplayOff(TRUE);
2554 SetMouseCursor(CURSOR_DEFAULT);
2556 #if defined(NETWORK_AVALIABLE)
2557 /* pause network game while waiting for request to answer */
2558 if (options.network &&
2559 game_status == GAME_MODE_PLAYING &&
2560 req_state & REQUEST_WAIT_FOR_INPUT)
2561 SendToServer_PausePlaying();
2564 old_door_state = GetDoorState();
2566 /* simulate releasing mouse button over last gadget, if still pressed */
2568 HandleGadgets(-1, -1, 0);
2572 if (old_door_state & DOOR_OPEN_1)
2574 CloseDoor(DOOR_CLOSE_1);
2576 /* save old door content */
2577 BlitBitmap(bitmap_db_door, bitmap_db_door,
2578 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
2579 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
2583 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
2586 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2588 /* clear door drawing field */
2589 DrawBackground(DX, DY, DXSIZE, DYSIZE);
2591 /* force DOOR font on preview level */
2592 game_status = GAME_MODE_PSEUDO_DOOR;
2594 /* write text for request */
2595 for (ty = 0; ty < MAX_REQUEST_LINES; ty++)
2597 char text_line[max_request_line_len + 1];
2603 for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
2606 if (!tc || tc == ' ')
2617 strncpy(text_line, text, tl);
2620 DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
2621 DY + 8 + ty * (getFontHeight(font_nr) + 2),
2622 text_line, font_nr);
2624 text += tl + (tc == ' ' ? 1 : 0);
2627 game_status = last_game_status; /* restore current game status */
2629 if (req_state & REQ_ASK)
2631 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
2632 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
2634 else if (req_state & REQ_CONFIRM)
2636 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
2638 else if (req_state & REQ_PLAYER)
2640 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
2641 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
2642 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
2643 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
2646 /* copy request gadgets to door backbuffer */
2647 BlitBitmap(drawto, bitmap_db_door,
2648 DX, DY, DXSIZE, DYSIZE,
2649 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2651 OpenDoor(DOOR_OPEN_1);
2653 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
2655 if (game_status == GAME_MODE_PLAYING)
2657 SetPanelBackground();
2658 SetDrawBackgroundMask(REDRAW_DOOR_1);
2662 SetDrawBackgroundMask(REDRAW_FIELD);
2668 if (game_status != GAME_MODE_MAIN)
2671 button_status = MB_RELEASED;
2673 request_gadget_id = -1;
2675 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2687 case EVENT_BUTTONPRESS:
2688 case EVENT_BUTTONRELEASE:
2689 case EVENT_MOTIONNOTIFY:
2691 if (event.type == EVENT_MOTIONNOTIFY)
2693 if (!PointerInWindow(window))
2694 continue; /* window and pointer are on different screens */
2699 motion_status = TRUE;
2700 mx = ((MotionEvent *) &event)->x;
2701 my = ((MotionEvent *) &event)->y;
2705 motion_status = FALSE;
2706 mx = ((ButtonEvent *) &event)->x;
2707 my = ((ButtonEvent *) &event)->y;
2708 if (event.type == EVENT_BUTTONPRESS)
2709 button_status = ((ButtonEvent *) &event)->button;
2711 button_status = MB_RELEASED;
2714 /* this sets 'request_gadget_id' */
2715 HandleGadgets(mx, my, button_status);
2717 switch (request_gadget_id)
2719 case TOOL_CTRL_ID_YES:
2722 case TOOL_CTRL_ID_NO:
2725 case TOOL_CTRL_ID_CONFIRM:
2726 result = TRUE | FALSE;
2729 case TOOL_CTRL_ID_PLAYER_1:
2732 case TOOL_CTRL_ID_PLAYER_2:
2735 case TOOL_CTRL_ID_PLAYER_3:
2738 case TOOL_CTRL_ID_PLAYER_4:
2749 case EVENT_KEYPRESS:
2750 switch (GetEventKey((KeyEvent *)&event, TRUE))
2763 if (req_state & REQ_PLAYER)
2767 case EVENT_KEYRELEASE:
2768 ClearPlayerAction();
2772 HandleOtherEvents(&event);
2776 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2778 int joy = AnyJoystick();
2780 if (joy & JOY_BUTTON_1)
2782 else if (joy & JOY_BUTTON_2)
2789 if (!PendingEvent()) /* delay only if no pending events */
2792 /* don't eat all CPU time */
2797 if (game_status != GAME_MODE_MAIN)
2802 if (!(req_state & REQ_STAY_OPEN))
2804 CloseDoor(DOOR_CLOSE_1);
2806 if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
2807 (req_state & REQ_REOPEN))
2808 OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
2813 if (game_status == GAME_MODE_PLAYING)
2815 SetPanelBackground();
2816 SetDrawBackgroundMask(REDRAW_DOOR_1);
2820 SetDrawBackgroundMask(REDRAW_FIELD);
2823 #if defined(NETWORK_AVALIABLE)
2824 /* continue network game after request */
2825 if (options.network &&
2826 game_status == GAME_MODE_PLAYING &&
2827 req_state & REQUEST_WAIT_FOR_INPUT)
2828 SendToServer_ContinuePlaying();
2831 /* restore deactivated drawing when quick-loading level tape recording */
2832 if (tape.playing && tape.deactivate_display)
2833 TapeDeactivateDisplayOn();
2838 unsigned int OpenDoor(unsigned int door_state)
2840 if (door_state & DOOR_COPY_BACK)
2842 if (door_state & DOOR_OPEN_1)
2843 BlitBitmap(bitmap_db_door, bitmap_db_door,
2844 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
2845 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2847 if (door_state & DOOR_OPEN_2)
2848 BlitBitmap(bitmap_db_door, bitmap_db_door,
2849 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY2, VXSIZE, VYSIZE,
2850 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2852 door_state &= ~DOOR_COPY_BACK;
2855 return MoveDoor(door_state);
2858 unsigned int CloseDoor(unsigned int door_state)
2860 unsigned int old_door_state = GetDoorState();
2862 if (!(door_state & DOOR_NO_COPY_BACK))
2864 if (old_door_state & DOOR_OPEN_1)
2865 BlitBitmap(backbuffer, bitmap_db_door,
2866 DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2868 if (old_door_state & DOOR_OPEN_2)
2869 BlitBitmap(backbuffer, bitmap_db_door,
2870 VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2872 door_state &= ~DOOR_NO_COPY_BACK;
2875 return MoveDoor(door_state);
2878 unsigned int GetDoorState()
2880 return MoveDoor(DOOR_GET_STATE);
2883 unsigned int SetDoorState(unsigned int door_state)
2885 return MoveDoor(door_state | DOOR_SET_STATE);
2888 unsigned int MoveDoor(unsigned int door_state)
2890 static int door1 = DOOR_OPEN_1;
2891 static int door2 = DOOR_CLOSE_2;
2892 unsigned long door_delay = 0;
2893 unsigned long door_delay_value;
2896 if (door_1.width < 0 || door_1.width > DXSIZE)
2897 door_1.width = DXSIZE;
2898 if (door_1.height < 0 || door_1.height > DYSIZE)
2899 door_1.height = DYSIZE;
2900 if (door_2.width < 0 || door_2.width > VXSIZE)
2901 door_2.width = VXSIZE;
2902 if (door_2.height < 0 || door_2.height > VYSIZE)
2903 door_2.height = VYSIZE;
2905 if (door_state == DOOR_GET_STATE)
2906 return (door1 | door2);
2908 if (door_state & DOOR_SET_STATE)
2910 if (door_state & DOOR_ACTION_1)
2911 door1 = door_state & DOOR_ACTION_1;
2912 if (door_state & DOOR_ACTION_2)
2913 door2 = door_state & DOOR_ACTION_2;
2915 return (door1 | door2);
2918 if (!(door_state & DOOR_FORCE_REDRAW))
2920 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
2921 door_state &= ~DOOR_OPEN_1;
2922 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
2923 door_state &= ~DOOR_CLOSE_1;
2924 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
2925 door_state &= ~DOOR_OPEN_2;
2926 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
2927 door_state &= ~DOOR_CLOSE_2;
2930 door_delay_value = (door_state & DOOR_ACTION_1 ? door_1.step_delay :
2933 if (setup.quick_doors)
2935 stepsize = 20; /* must be choosen to always draw last frame */
2936 door_delay_value = 0;
2939 if (global.autoplay_leveldir)
2941 door_state |= DOOR_NO_DELAY;
2942 door_state &= ~DOOR_CLOSE_ALL;
2945 if (door_state & DOOR_ACTION)
2947 boolean handle_door_1 = (door_state & DOOR_ACTION_1);
2948 boolean handle_door_2 = (door_state & DOOR_ACTION_2);
2949 boolean door_1_done = (!handle_door_1);
2950 boolean door_2_done = (!handle_door_2);
2951 boolean door_1_vertical = (door_1.anim_mode & ANIM_VERTICAL);
2952 boolean door_2_vertical = (door_2.anim_mode & ANIM_VERTICAL);
2953 int door_size_1 = (door_1_vertical ? door_1.height : door_1.width);
2954 int door_size_2 = (door_2_vertical ? door_2.height : door_2.width);
2955 int max_door_size_1 = (door_1_vertical ? DYSIZE : DXSIZE);
2956 int max_door_size_2 = (door_2_vertical ? VYSIZE : VXSIZE);
2957 int door_size = (handle_door_1 ? door_size_1 : door_size_2);
2958 int max_door_size = (handle_door_1 ? max_door_size_1 : max_door_size_2);
2959 int door_skip = max_door_size - door_size;
2960 int end = door_size;
2961 int start = ((door_state & DOOR_NO_DELAY) ? end : 0);
2964 if (!(door_state & DOOR_NO_DELAY) && !setup.quick_doors)
2966 /* opening door sound has priority over simultaneously closing door */
2967 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
2968 PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
2969 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
2970 PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
2973 for (k = start; k <= end && !(door_1_done && door_2_done); k += stepsize)
2976 Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2977 GC gc = bitmap->stored_clip_gc;
2979 if (door_state & DOOR_ACTION_1)
2981 int a = MIN(x * door_1.step_offset, end);
2982 int p = (door_state & DOOR_OPEN_1 ? end - a : a);
2983 int i = p + door_skip;
2985 if (door_1.anim_mode & ANIM_STATIC_PANEL)
2987 BlitBitmap(bitmap_db_door, drawto,
2988 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1,
2989 DXSIZE, DYSIZE, DX, DY);
2993 BlitBitmap(bitmap_db_door, drawto,
2994 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + p / 2,
2995 DXSIZE, DYSIZE - p / 2, DX, DY);
2997 ClearRectangle(drawto, DX, DY + DYSIZE - p / 2, DXSIZE, p / 2);
3000 if (door_1.anim_mode & ANIM_HORIZONTAL && x <= DXSIZE)
3002 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
3003 int dst1_x = DX + DXSIZE - i, dst1_y = DY;
3004 int src2_x = DXSIZE - i, src2_y = DOOR_GFX_PAGEY1;
3005 int dst2_x = DX, dst2_y = DY;
3006 int width = i, height = DYSIZE;
3008 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3009 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3012 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3013 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3016 else if (door_1.anim_mode & ANIM_VERTICAL && x <= DYSIZE)
3018 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
3019 int dst1_x = DX, dst1_y = DY + DYSIZE - i;
3020 int src2_x = 0, src2_y = DOOR_GFX_PAGEY1 + DYSIZE - i;
3021 int dst2_x = DX, dst2_y = DY;
3022 int width = DXSIZE, height = i;
3024 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3025 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3028 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3029 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3032 else if (x <= DXSIZE) /* ANIM_DEFAULT */
3034 int j = (door_1.anim_mode == ANIM_DEFAULT ? (DXSIZE - i) / 3 : 0);
3036 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
3037 BlitBitmapMasked(bitmap, drawto,
3038 DXSIZE, DOOR_GFX_PAGEY1, i, 77,
3039 DX + DXSIZE - i, DY + j);
3040 BlitBitmapMasked(bitmap, drawto,
3041 DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
3042 DX + DXSIZE - i, DY + 140 + j);
3043 SetClipOrigin(bitmap, gc, DX - DXSIZE + i,
3044 DY - (DOOR_GFX_PAGEY1 + j));
3045 BlitBitmapMasked(bitmap, drawto,
3046 DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
3048 BlitBitmapMasked(bitmap, drawto,
3049 DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
3052 BlitBitmapMasked(bitmap, drawto,
3053 DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
3055 BlitBitmapMasked(bitmap, drawto,
3056 DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
3058 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
3059 BlitBitmapMasked(bitmap, drawto,
3060 DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
3061 DX + DXSIZE - i, DY + 77 + j);
3062 BlitBitmapMasked(bitmap, drawto,
3063 DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
3064 DX + DXSIZE - i, DY + 203 + j);
3067 redraw_mask |= REDRAW_DOOR_1;
3068 door_1_done = (a == end);
3071 if (door_state & DOOR_ACTION_2)
3073 int a = MIN(x * door_2.step_offset, door_size);
3074 int p = (door_state & DOOR_OPEN_2 ? door_size - a : a);
3075 int i = p + door_skip;
3077 if (door_2.anim_mode & ANIM_STATIC_PANEL)
3079 BlitBitmap(bitmap_db_door, drawto,
3080 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2,
3081 VXSIZE, VYSIZE, VX, VY);
3083 else if (x <= VYSIZE)
3085 BlitBitmap(bitmap_db_door, drawto,
3086 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + p / 2,
3087 VXSIZE, VYSIZE - p / 2, VX, VY);
3089 ClearRectangle(drawto, VX, VY + VYSIZE - p / 2, VXSIZE, p / 2);
3092 if (door_2.anim_mode & ANIM_HORIZONTAL && x <= VXSIZE)
3094 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
3095 int dst1_x = VX + VXSIZE - i, dst1_y = VY;
3096 int src2_x = VXSIZE - i, src2_y = DOOR_GFX_PAGEY2;
3097 int dst2_x = VX, dst2_y = VY;
3098 int width = i, height = VYSIZE;
3100 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3101 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3104 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3105 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3108 else if (door_2.anim_mode & ANIM_VERTICAL && x <= VYSIZE)
3110 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
3111 int dst1_x = VX, dst1_y = VY + VYSIZE - i;
3112 int src2_x = 0, src2_y = DOOR_GFX_PAGEY2 + VYSIZE - i;
3113 int dst2_x = VX, dst2_y = VY;
3114 int width = VXSIZE, height = i;
3116 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3117 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3120 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3121 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3124 else if (x <= VXSIZE) /* ANIM_DEFAULT */
3126 int j = (door_2.anim_mode == ANIM_DEFAULT ? (VXSIZE - i) / 3 : 0);
3128 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
3129 BlitBitmapMasked(bitmap, drawto,
3130 VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
3131 VX + VXSIZE - i, VY + j);
3132 SetClipOrigin(bitmap, gc,
3133 VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
3134 BlitBitmapMasked(bitmap, drawto,
3135 VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
3138 BlitBitmapMasked(bitmap, drawto,
3139 VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
3140 i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
3141 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
3142 BlitBitmapMasked(bitmap, drawto,
3143 VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
3145 VX + VXSIZE - i, VY + VYSIZE / 2 + j);
3148 redraw_mask |= REDRAW_DOOR_2;
3149 door_2_done = (a == VXSIZE);
3152 if (!(door_state & DOOR_NO_DELAY))
3156 if (game_status == GAME_MODE_MAIN)
3159 WaitUntilDelayReached(&door_delay, door_delay_value);
3164 if (door_state & DOOR_ACTION_1)
3165 door1 = door_state & DOOR_ACTION_1;
3166 if (door_state & DOOR_ACTION_2)
3167 door2 = door_state & DOOR_ACTION_2;
3169 return (door1 | door2);
3172 void DrawSpecialEditorDoor()
3174 /* draw bigger toolbox window */
3175 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
3176 DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
3178 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
3179 EX - 6, VY - 4, EXSIZE + 12, EYSIZE - VYSIZE + 4,
3182 redraw_mask |= REDRAW_ALL;
3185 void UndrawSpecialEditorDoor()
3187 /* draw normal tape recorder window */
3188 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
3189 EX - 6, EY - 12, EXSIZE + 12, EYSIZE - VYSIZE + 12,
3192 redraw_mask |= REDRAW_ALL;
3196 /* ---------- new tool button stuff ---------------------------------------- */
3198 /* graphic position values for tool buttons */
3199 #define TOOL_BUTTON_YES_XPOS 2
3200 #define TOOL_BUTTON_YES_YPOS 250
3201 #define TOOL_BUTTON_YES_GFX_YPOS 0
3202 #define TOOL_BUTTON_YES_XSIZE 46
3203 #define TOOL_BUTTON_YES_YSIZE 28
3204 #define TOOL_BUTTON_NO_XPOS 52
3205 #define TOOL_BUTTON_NO_YPOS TOOL_BUTTON_YES_YPOS
3206 #define TOOL_BUTTON_NO_GFX_YPOS TOOL_BUTTON_YES_GFX_YPOS
3207 #define TOOL_BUTTON_NO_XSIZE TOOL_BUTTON_YES_XSIZE
3208 #define TOOL_BUTTON_NO_YSIZE TOOL_BUTTON_YES_YSIZE
3209 #define TOOL_BUTTON_CONFIRM_XPOS TOOL_BUTTON_YES_XPOS
3210 #define TOOL_BUTTON_CONFIRM_YPOS TOOL_BUTTON_YES_YPOS
3211 #define TOOL_BUTTON_CONFIRM_GFX_YPOS 30
3212 #define TOOL_BUTTON_CONFIRM_XSIZE 96
3213 #define TOOL_BUTTON_CONFIRM_YSIZE TOOL_BUTTON_YES_YSIZE
3214 #define TOOL_BUTTON_PLAYER_XSIZE 30
3215 #define TOOL_BUTTON_PLAYER_YSIZE 30
3216 #define TOOL_BUTTON_PLAYER_GFX_XPOS 5
3217 #define TOOL_BUTTON_PLAYER_GFX_YPOS 185
3218 #define TOOL_BUTTON_PLAYER_XPOS (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
3219 #define TOOL_BUTTON_PLAYER_YPOS (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
3220 #define TOOL_BUTTON_PLAYER1_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3221 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
3222 #define TOOL_BUTTON_PLAYER2_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3223 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
3224 #define TOOL_BUTTON_PLAYER3_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3225 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
3226 #define TOOL_BUTTON_PLAYER4_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3227 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
3228 #define TOOL_BUTTON_PLAYER1_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3229 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
3230 #define TOOL_BUTTON_PLAYER2_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3231 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
3232 #define TOOL_BUTTON_PLAYER3_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3233 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
3234 #define TOOL_BUTTON_PLAYER4_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3235 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
3244 } toolbutton_info[NUM_TOOL_BUTTONS] =
3247 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_GFX_YPOS,
3248 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_YPOS,
3249 TOOL_BUTTON_YES_XSIZE, TOOL_BUTTON_YES_YSIZE,
3254 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_GFX_YPOS,
3255 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_YPOS,
3256 TOOL_BUTTON_NO_XSIZE, TOOL_BUTTON_NO_YSIZE,
3261 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_GFX_YPOS,
3262 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_YPOS,
3263 TOOL_BUTTON_CONFIRM_XSIZE, TOOL_BUTTON_CONFIRM_YSIZE,
3264 TOOL_CTRL_ID_CONFIRM,
3268 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3269 TOOL_BUTTON_PLAYER1_XPOS, TOOL_BUTTON_PLAYER1_YPOS,
3270 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3271 TOOL_CTRL_ID_PLAYER_1,
3275 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3276 TOOL_BUTTON_PLAYER2_XPOS, TOOL_BUTTON_PLAYER2_YPOS,
3277 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3278 TOOL_CTRL_ID_PLAYER_2,
3282 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3283 TOOL_BUTTON_PLAYER3_XPOS, TOOL_BUTTON_PLAYER3_YPOS,
3284 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3285 TOOL_CTRL_ID_PLAYER_3,
3289 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3290 TOOL_BUTTON_PLAYER4_XPOS, TOOL_BUTTON_PLAYER4_YPOS,
3291 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3292 TOOL_CTRL_ID_PLAYER_4,
3297 void CreateToolButtons()
3301 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3303 Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
3304 Bitmap *deco_bitmap = None;
3305 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
3306 struct GadgetInfo *gi;
3307 unsigned long event_mask;
3308 int gd_xoffset, gd_yoffset;
3309 int gd_x1, gd_x2, gd_y;
3312 event_mask = GD_EVENT_RELEASED;
3314 gd_xoffset = toolbutton_info[i].xpos;
3315 gd_yoffset = toolbutton_info[i].ypos;
3316 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
3317 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
3318 gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
3320 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
3322 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
3324 getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr),
3325 &deco_bitmap, &deco_x, &deco_y);
3326 deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
3327 deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
3330 gi = CreateGadget(GDI_CUSTOM_ID, id,
3331 GDI_INFO_TEXT, toolbutton_info[i].infotext,
3332 GDI_X, DX + toolbutton_info[i].x,
3333 GDI_Y, DY + toolbutton_info[i].y,
3334 GDI_WIDTH, toolbutton_info[i].width,
3335 GDI_HEIGHT, toolbutton_info[i].height,
3336 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
3337 GDI_STATE, GD_BUTTON_UNPRESSED,
3338 GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
3339 GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
3340 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
3341 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
3342 GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
3343 GDI_DECORATION_SHIFTING, 1, 1,
3344 GDI_DIRECT_DRAW, FALSE,
3345 GDI_EVENT_MASK, event_mask,
3346 GDI_CALLBACK_ACTION, HandleToolButtons,
3350 Error(ERR_EXIT, "cannot create gadget");
3352 tool_gadget[id] = gi;
3356 void FreeToolButtons()
3360 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3361 FreeGadget(tool_gadget[i]);
3364 static void UnmapToolButtons()
3368 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3369 UnmapGadget(tool_gadget[i]);
3372 static void HandleToolButtons(struct GadgetInfo *gi)
3374 request_gadget_id = gi->custom_id;
3377 static struct Mapping_EM_to_RND_object
3380 boolean is_rnd_to_em_mapping; /* unique mapping EM <-> RND */
3381 boolean is_backside; /* backside of moving element */
3387 em_object_mapping_list[] =
3390 Xblank, TRUE, FALSE,
3394 Yacid_splash_eB, FALSE, FALSE,
3395 EL_ACID_SPLASH_RIGHT, -1, -1
3398 Yacid_splash_wB, FALSE, FALSE,
3399 EL_ACID_SPLASH_LEFT, -1, -1
3402 #ifdef EM_ENGINE_BAD_ROLL
3404 Xstone_force_e, FALSE, FALSE,
3405 EL_ROCK, -1, MV_BIT_RIGHT
3408 Xstone_force_w, FALSE, FALSE,
3409 EL_ROCK, -1, MV_BIT_LEFT
3412 Xnut_force_e, FALSE, FALSE,
3413 EL_NUT, -1, MV_BIT_RIGHT
3416 Xnut_force_w, FALSE, FALSE,
3417 EL_NUT, -1, MV_BIT_LEFT
3420 Xspring_force_e, FALSE, FALSE,
3421 EL_SPRING, -1, MV_BIT_RIGHT
3424 Xspring_force_w, FALSE, FALSE,
3425 EL_SPRING, -1, MV_BIT_LEFT
3428 Xemerald_force_e, FALSE, FALSE,
3429 EL_EMERALD, -1, MV_BIT_RIGHT
3432 Xemerald_force_w, FALSE, FALSE,
3433 EL_EMERALD, -1, MV_BIT_LEFT
3436 Xdiamond_force_e, FALSE, FALSE,
3437 EL_DIAMOND, -1, MV_BIT_RIGHT
3440 Xdiamond_force_w, FALSE, FALSE,
3441 EL_DIAMOND, -1, MV_BIT_LEFT
3444 Xbomb_force_e, FALSE, FALSE,
3445 EL_BOMB, -1, MV_BIT_RIGHT
3448 Xbomb_force_w, FALSE, FALSE,
3449 EL_BOMB, -1, MV_BIT_LEFT
3451 #endif /* EM_ENGINE_BAD_ROLL */
3454 Xstone, TRUE, FALSE,
3458 Xstone_pause, FALSE, FALSE,
3462 Xstone_fall, FALSE, FALSE,
3466 Ystone_s, FALSE, FALSE,
3467 EL_ROCK, ACTION_FALLING, -1
3470 Ystone_sB, FALSE, TRUE,
3471 EL_ROCK, ACTION_FALLING, -1
3474 Ystone_e, FALSE, FALSE,
3475 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
3478 Ystone_eB, FALSE, TRUE,
3479 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
3482 Ystone_w, FALSE, FALSE,
3483 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
3486 Ystone_wB, FALSE, TRUE,
3487 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
3494 Xnut_pause, FALSE, FALSE,
3498 Xnut_fall, FALSE, FALSE,
3502 Ynut_s, FALSE, FALSE,
3503 EL_NUT, ACTION_FALLING, -1
3506 Ynut_sB, FALSE, TRUE,
3507 EL_NUT, ACTION_FALLING, -1
3510 Ynut_e, FALSE, FALSE,
3511 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
3514 Ynut_eB, FALSE, TRUE,
3515 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
3518 Ynut_w, FALSE, FALSE,
3519 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
3522 Ynut_wB, FALSE, TRUE,
3523 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
3526 Xbug_n, TRUE, FALSE,
3530 Xbug_e, TRUE, FALSE,
3531 EL_BUG_RIGHT, -1, -1
3534 Xbug_s, TRUE, FALSE,
3538 Xbug_w, TRUE, FALSE,
3542 Xbug_gon, FALSE, FALSE,
3546 Xbug_goe, FALSE, FALSE,
3547 EL_BUG_RIGHT, -1, -1
3550 Xbug_gos, FALSE, FALSE,
3554 Xbug_gow, FALSE, FALSE,
3558 Ybug_n, FALSE, FALSE,
3559 EL_BUG, ACTION_MOVING, MV_BIT_UP
3562 Ybug_nB, FALSE, TRUE,
3563 EL_BUG, ACTION_MOVING, MV_BIT_UP
3566 Ybug_e, FALSE, FALSE,
3567 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
3570 Ybug_eB, FALSE, TRUE,
3571 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
3574 Ybug_s, FALSE, FALSE,
3575 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
3578 Ybug_sB, FALSE, TRUE,
3579 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
3582 Ybug_w, FALSE, FALSE,
3583 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
3586 Ybug_wB, FALSE, TRUE,
3587 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
3590 Ybug_w_n, FALSE, FALSE,
3591 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
3594 Ybug_n_e, FALSE, FALSE,
3595 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
3598 Ybug_e_s, FALSE, FALSE,
3599 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
3602 Ybug_s_w, FALSE, FALSE,
3603 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
3606 Ybug_e_n, FALSE, FALSE,
3607 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
3610 Ybug_s_e, FALSE, FALSE,
3611 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
3614 Ybug_w_s, FALSE, FALSE,
3615 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
3618 Ybug_n_w, FALSE, FALSE,
3619 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
3622 Ybug_stone, FALSE, FALSE,
3623 EL_BUG, ACTION_SMASHED_BY_ROCK, -1
3626 Ybug_spring, FALSE, FALSE,
3627 EL_BUG, ACTION_SMASHED_BY_SPRING, -1
3630 Xtank_n, TRUE, FALSE,
3631 EL_SPACESHIP_UP, -1, -1
3634 Xtank_e, TRUE, FALSE,
3635 EL_SPACESHIP_RIGHT, -1, -1
3638 Xtank_s, TRUE, FALSE,
3639 EL_SPACESHIP_DOWN, -1, -1
3642 Xtank_w, TRUE, FALSE,
3643 EL_SPACESHIP_LEFT, -1, -1
3646 Xtank_gon, FALSE, FALSE,
3647 EL_SPACESHIP_UP, -1, -1
3650 Xtank_goe, FALSE, FALSE,
3651 EL_SPACESHIP_RIGHT, -1, -1
3654 Xtank_gos, FALSE, FALSE,
3655 EL_SPACESHIP_DOWN, -1, -1
3658 Xtank_gow, FALSE, FALSE,
3659 EL_SPACESHIP_LEFT, -1, -1
3662 Ytank_n, FALSE, FALSE,
3663 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
3666 Ytank_nB, FALSE, TRUE,
3667 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
3670 Ytank_e, FALSE, FALSE,
3671 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
3674 Ytank_eB, FALSE, TRUE,
3675 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
3678 Ytank_s, FALSE, FALSE,
3679 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
3682 Ytank_sB, FALSE, TRUE,
3683 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
3686 Ytank_w, FALSE, FALSE,
3687 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
3690 Ytank_wB, FALSE, TRUE,
3691 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
3694 Ytank_w_n, FALSE, FALSE,
3695 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
3698 Ytank_n_e, FALSE, FALSE,
3699 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
3702 Ytank_e_s, FALSE, FALSE,
3703 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
3706 Ytank_s_w, FALSE, FALSE,
3707 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
3710 Ytank_e_n, FALSE, FALSE,
3711 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
3714 Ytank_s_e, FALSE, FALSE,
3715 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
3718 Ytank_w_s, FALSE, FALSE,
3719 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
3722 Ytank_n_w, FALSE, FALSE,
3723 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
3726 Ytank_stone, FALSE, FALSE,
3727 EL_SPACESHIP, ACTION_SMASHED_BY_ROCK, -1
3730 Ytank_spring, FALSE, FALSE,
3731 EL_SPACESHIP, ACTION_SMASHED_BY_SPRING, -1
3734 Xandroid, TRUE, FALSE,
3735 EL_EMC_ANDROID, ACTION_ACTIVE, -1
3738 Xandroid_1_n, FALSE, FALSE,
3739 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
3742 Xandroid_2_n, FALSE, FALSE,
3743 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
3746 Xandroid_1_e, FALSE, FALSE,
3747 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
3750 Xandroid_2_e, FALSE, FALSE,
3751 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
3754 Xandroid_1_w, FALSE, FALSE,
3755 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
3758 Xandroid_2_w, FALSE, FALSE,
3759 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
3762 Xandroid_1_s, FALSE, FALSE,
3763 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
3766 Xandroid_2_s, FALSE, FALSE,
3767 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
3770 Yandroid_n, FALSE, FALSE,
3771 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
3774 Yandroid_nB, FALSE, TRUE,
3775 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
3778 Yandroid_ne, FALSE, FALSE,
3779 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPRIGHT
3782 Yandroid_neB, FALSE, TRUE,
3783 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPRIGHT
3786 Yandroid_e, FALSE, FALSE,
3787 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
3790 Yandroid_eB, FALSE, TRUE,
3791 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
3794 Yandroid_se, FALSE, FALSE,
3795 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNRIGHT
3798 Yandroid_seB, FALSE, TRUE,
3799 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNRIGHT
3802 Yandroid_s, FALSE, FALSE,
3803 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
3806 Yandroid_sB, FALSE, TRUE,
3807 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
3810 Yandroid_sw, FALSE, FALSE,
3811 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNLEFT
3814 Yandroid_swB, FALSE, TRUE,
3815 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNLEFT
3818 Yandroid_w, FALSE, FALSE,
3819 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
3822 Yandroid_wB, FALSE, TRUE,
3823 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
3826 Yandroid_nw, FALSE, FALSE,
3827 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPLEFT
3830 Yandroid_nwB, FALSE, TRUE,
3831 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPLEFT
3834 Xspring, TRUE, FALSE,
3838 Xspring_pause, FALSE, FALSE,
3842 Xspring_e, FALSE, FALSE,
3846 Xspring_w, FALSE, FALSE,
3850 Xspring_fall, FALSE, FALSE,
3854 Yspring_s, FALSE, FALSE,
3855 EL_SPRING, ACTION_FALLING, -1
3858 Yspring_sB, FALSE, TRUE,
3859 EL_SPRING, ACTION_FALLING, -1
3862 Yspring_e, FALSE, FALSE,
3863 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
3866 Yspring_eB, FALSE, TRUE,
3867 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
3870 Yspring_w, FALSE, FALSE,
3871 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
3874 Yspring_wB, FALSE, TRUE,
3875 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
3878 Yspring_kill_e, FALSE, FALSE,
3879 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
3882 Yspring_kill_eB, FALSE, TRUE,
3883 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
3886 Yspring_kill_w, FALSE, FALSE,
3887 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
3890 Yspring_kill_wB, FALSE, TRUE,
3891 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
3894 Xeater_n, TRUE, FALSE,
3895 EL_YAMYAM_UP, -1, -1
3898 Xeater_e, TRUE, FALSE,
3899 EL_YAMYAM_RIGHT, -1, -1
3902 Xeater_w, TRUE, FALSE,
3903 EL_YAMYAM_LEFT, -1, -1
3906 Xeater_s, TRUE, FALSE,
3907 EL_YAMYAM_DOWN, -1, -1
3910 Yeater_n, FALSE, FALSE,
3911 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
3914 Yeater_nB, FALSE, TRUE,
3915 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
3918 Yeater_e, FALSE, FALSE,
3919 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
3922 Yeater_eB, FALSE, TRUE,
3923 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
3926 Yeater_s, FALSE, FALSE,
3927 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
3930 Yeater_sB, FALSE, TRUE,
3931 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
3934 Yeater_w, FALSE, FALSE,
3935 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
3938 Yeater_wB, FALSE, TRUE,
3939 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
3942 Yeater_stone, FALSE, FALSE,
3943 EL_YAMYAM, ACTION_SMASHED_BY_ROCK, -1
3946 Yeater_spring, FALSE, FALSE,
3947 EL_YAMYAM, ACTION_SMASHED_BY_SPRING, -1
3950 Xalien, TRUE, FALSE,
3954 Xalien_pause, FALSE, FALSE,
3958 Yalien_n, FALSE, FALSE,
3959 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
3962 Yalien_nB, FALSE, TRUE,
3963 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
3966 Yalien_e, FALSE, FALSE,
3967 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
3970 Yalien_eB, FALSE, TRUE,
3971 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
3974 Yalien_s, FALSE, FALSE,
3975 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
3978 Yalien_sB, FALSE, TRUE,
3979 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
3982 Yalien_w, FALSE, FALSE,
3983 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
3986 Yalien_wB, FALSE, TRUE,
3987 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
3990 Yalien_stone, FALSE, FALSE,
3991 EL_ROBOT, ACTION_SMASHED_BY_ROCK, -1
3994 Yalien_spring, FALSE, FALSE,
3995 EL_ROBOT, ACTION_SMASHED_BY_SPRING, -1
3998 Xemerald, TRUE, FALSE,
4002 Xemerald_pause, FALSE, FALSE,
4006 Xemerald_fall, FALSE, FALSE,
4010 Xemerald_shine, FALSE, FALSE,
4011 EL_EMERALD, ACTION_TWINKLING, -1
4014 Yemerald_s, FALSE, FALSE,
4015 EL_EMERALD, ACTION_FALLING, -1
4018 Yemerald_sB, FALSE, TRUE,
4019 EL_EMERALD, ACTION_FALLING, -1
4022 Yemerald_e, FALSE, FALSE,
4023 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
4026 Yemerald_eB, FALSE, TRUE,
4027 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
4030 Yemerald_w, FALSE, FALSE,
4031 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
4034 Yemerald_wB, FALSE, TRUE,
4035 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
4038 Yemerald_eat, FALSE, FALSE,
4039 EL_EMERALD, ACTION_COLLECTING, -1
4042 Yemerald_stone, FALSE, FALSE,
4043 EL_NUT, ACTION_BREAKING, -1
4046 Xdiamond, TRUE, FALSE,
4050 Xdiamond_pause, FALSE, FALSE,
4054 Xdiamond_fall, FALSE, FALSE,
4058 Xdiamond_shine, FALSE, FALSE,
4059 EL_DIAMOND, ACTION_TWINKLING, -1
4062 Ydiamond_s, FALSE, FALSE,
4063 EL_DIAMOND, ACTION_FALLING, -1
4066 Ydiamond_sB, FALSE, TRUE,
4067 EL_DIAMOND, ACTION_FALLING, -1
4070 Ydiamond_e, FALSE, FALSE,
4071 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
4074 Ydiamond_eB, FALSE, TRUE,
4075 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
4078 Ydiamond_w, FALSE, FALSE,
4079 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
4082 Ydiamond_wB, FALSE, TRUE,
4083 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
4086 Ydiamond_eat, FALSE, FALSE,
4087 EL_DIAMOND, ACTION_COLLECTING, -1
4090 Ydiamond_stone, FALSE, FALSE,
4091 EL_DIAMOND, ACTION_SMASHED_BY_ROCK, -1
4094 Xdrip_fall, TRUE, FALSE,
4095 EL_AMOEBA_DROP, -1, -1
4098 Xdrip_stretch, FALSE, FALSE,
4099 EL_AMOEBA_DROP, ACTION_FALLING, -1
4102 Xdrip_stretchB, FALSE, TRUE,
4103 EL_AMOEBA_DROP, ACTION_FALLING, -1
4106 Xdrip_eat, FALSE, FALSE,
4107 EL_AMOEBA_DROP, ACTION_GROWING, -1
4110 Ydrip_s1, FALSE, FALSE,
4111 EL_AMOEBA_DROP, ACTION_FALLING, -1
4114 Ydrip_s1B, FALSE, TRUE,
4115 EL_AMOEBA_DROP, ACTION_FALLING, -1
4118 Ydrip_s2, FALSE, FALSE,
4119 EL_AMOEBA_DROP, ACTION_FALLING, -1
4122 Ydrip_s2B, FALSE, TRUE,
4123 EL_AMOEBA_DROP, ACTION_FALLING, -1
4130 Xbomb_pause, FALSE, FALSE,
4134 Xbomb_fall, FALSE, FALSE,
4138 Ybomb_s, FALSE, FALSE,
4139 EL_BOMB, ACTION_FALLING, -1
4142 Ybomb_sB, FALSE, TRUE,
4143 EL_BOMB, ACTION_FALLING, -1
4146 Ybomb_e, FALSE, FALSE,
4147 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
4150 Ybomb_eB, FALSE, TRUE,
4151 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
4154 Ybomb_w, FALSE, FALSE,
4155 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
4158 Ybomb_wB, FALSE, TRUE,
4159 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
4162 Ybomb_eat, FALSE, FALSE,
4163 EL_BOMB, ACTION_ACTIVATING, -1
4166 Xballoon, TRUE, FALSE,
4170 Yballoon_n, FALSE, FALSE,
4171 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
4174 Yballoon_nB, FALSE, TRUE,
4175 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
4178 Yballoon_e, FALSE, FALSE,
4179 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
4182 Yballoon_eB, FALSE, TRUE,
4183 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
4186 Yballoon_s, FALSE, FALSE,
4187 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
4190 Yballoon_sB, FALSE, TRUE,
4191 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
4194 Yballoon_w, FALSE, FALSE,
4195 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
4198 Yballoon_wB, FALSE, TRUE,
4199 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
4202 Xgrass, TRUE, FALSE,
4203 EL_EMC_GRASS, -1, -1
4206 Ygrass_nB, FALSE, FALSE,
4207 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_UP
4210 Ygrass_eB, FALSE, FALSE,
4211 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_RIGHT
4214 Ygrass_sB, FALSE, FALSE,
4215 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_DOWN
4218 Ygrass_wB, FALSE, FALSE,
4219 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_LEFT
4226 Ydirt_nB, FALSE, FALSE,
4227 EL_SAND, ACTION_DIGGING, MV_BIT_UP
4230 Ydirt_eB, FALSE, FALSE,
4231 EL_SAND, ACTION_DIGGING, MV_BIT_RIGHT
4234 Ydirt_sB, FALSE, FALSE,
4235 EL_SAND, ACTION_DIGGING, MV_BIT_DOWN
4238 Ydirt_wB, FALSE, FALSE,
4239 EL_SAND, ACTION_DIGGING, MV_BIT_LEFT
4242 Xacid_ne, TRUE, FALSE,
4243 EL_ACID_POOL_TOPRIGHT, -1, -1
4246 Xacid_se, TRUE, FALSE,
4247 EL_ACID_POOL_BOTTOMRIGHT, -1, -1
4250 Xacid_s, TRUE, FALSE,
4251 EL_ACID_POOL_BOTTOM, -1, -1
4254 Xacid_sw, TRUE, FALSE,
4255 EL_ACID_POOL_BOTTOMLEFT, -1, -1
4258 Xacid_nw, TRUE, FALSE,
4259 EL_ACID_POOL_TOPLEFT, -1, -1
4262 Xacid_1, TRUE, FALSE,
4266 Xacid_2, FALSE, FALSE,
4270 Xacid_3, FALSE, FALSE,
4274 Xacid_4, FALSE, FALSE,
4278 Xacid_5, FALSE, FALSE,
4282 Xacid_6, FALSE, FALSE,
4286 Xacid_7, FALSE, FALSE,
4290 Xacid_8, FALSE, FALSE,
4294 Xball_1, TRUE, FALSE,
4295 EL_EMC_MAGIC_BALL, -1, -1
4298 Xball_1B, FALSE, FALSE,
4299 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4302 Xball_2, FALSE, FALSE,
4303 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4306 Xball_2B, FALSE, FALSE,
4307 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4310 Yball_eat, FALSE, FALSE,
4311 EL_EMC_MAGIC_BALL, ACTION_DROPPING, -1
4314 Ykey_1_eat, FALSE, FALSE,
4315 EL_EM_KEY_1, ACTION_COLLECTING, -1
4318 Ykey_2_eat, FALSE, FALSE,
4319 EL_EM_KEY_2, ACTION_COLLECTING, -1
4322 Ykey_3_eat, FALSE, FALSE,
4323 EL_EM_KEY_3, ACTION_COLLECTING, -1
4326 Ykey_4_eat, FALSE, FALSE,
4327 EL_EM_KEY_4, ACTION_COLLECTING, -1
4330 Ykey_5_eat, FALSE, FALSE,
4331 EL_EMC_KEY_5, ACTION_COLLECTING, -1
4334 Ykey_6_eat, FALSE, FALSE,
4335 EL_EMC_KEY_6, ACTION_COLLECTING, -1
4338 Ykey_7_eat, FALSE, FALSE,
4339 EL_EMC_KEY_7, ACTION_COLLECTING, -1
4342 Ykey_8_eat, FALSE, FALSE,
4343 EL_EMC_KEY_8, ACTION_COLLECTING, -1
4346 Ylenses_eat, FALSE, FALSE,
4347 EL_EMC_LENSES, ACTION_COLLECTING, -1
4350 Ymagnify_eat, FALSE, FALSE,
4351 EL_EMC_MAGNIFIER, ACTION_COLLECTING, -1
4354 Ygrass_eat, FALSE, FALSE,
4355 EL_EMC_GRASS, ACTION_SNAPPING, -1
4358 Ydirt_eat, FALSE, FALSE,
4359 EL_SAND, ACTION_SNAPPING, -1
4362 Xgrow_ns, TRUE, FALSE,
4363 EL_EXPANDABLE_WALL_VERTICAL, -1, -1
4366 Ygrow_ns_eat, FALSE, FALSE,
4367 EL_EXPANDABLE_WALL_VERTICAL, ACTION_GROWING, -1
4370 Xgrow_ew, TRUE, FALSE,
4371 EL_EXPANDABLE_WALL_HORIZONTAL, -1, -1
4374 Ygrow_ew_eat, FALSE, FALSE,
4375 EL_EXPANDABLE_WALL_HORIZONTAL, ACTION_GROWING, -1
4378 Xwonderwall, TRUE, FALSE,
4379 EL_MAGIC_WALL, -1, -1
4382 XwonderwallB, FALSE, FALSE,
4383 EL_MAGIC_WALL, ACTION_ACTIVE, -1
4386 Xamoeba_1, TRUE, FALSE,
4387 EL_AMOEBA_DRY, ACTION_OTHER, -1
4390 Xamoeba_2, FALSE, FALSE,
4391 EL_AMOEBA_DRY, ACTION_OTHER, -1
4394 Xamoeba_3, FALSE, FALSE,
4395 EL_AMOEBA_DRY, ACTION_OTHER, -1
4398 Xamoeba_4, FALSE, FALSE,
4399 EL_AMOEBA_DRY, ACTION_OTHER, -1
4402 Xamoeba_5, TRUE, FALSE,
4403 EL_AMOEBA_WET, ACTION_OTHER, -1
4406 Xamoeba_6, FALSE, FALSE,
4407 EL_AMOEBA_WET, ACTION_OTHER, -1
4410 Xamoeba_7, FALSE, FALSE,
4411 EL_AMOEBA_WET, ACTION_OTHER, -1
4414 Xamoeba_8, FALSE, FALSE,
4415 EL_AMOEBA_WET, ACTION_OTHER, -1
4418 Xdoor_1, TRUE, FALSE,
4419 EL_EM_GATE_1, -1, -1
4422 Xdoor_2, TRUE, FALSE,
4423 EL_EM_GATE_2, -1, -1
4426 Xdoor_3, TRUE, FALSE,
4427 EL_EM_GATE_3, -1, -1
4430 Xdoor_4, TRUE, FALSE,
4431 EL_EM_GATE_4, -1, -1
4434 Xdoor_5, TRUE, FALSE,
4435 EL_EMC_GATE_5, -1, -1
4438 Xdoor_6, TRUE, FALSE,
4439 EL_EMC_GATE_6, -1, -1
4442 Xdoor_7, TRUE, FALSE,
4443 EL_EMC_GATE_7, -1, -1
4446 Xdoor_8, TRUE, FALSE,
4447 EL_EMC_GATE_8, -1, -1
4450 Xkey_1, TRUE, FALSE,
4454 Xkey_2, TRUE, FALSE,
4458 Xkey_3, TRUE, FALSE,
4462 Xkey_4, TRUE, FALSE,
4466 Xkey_5, TRUE, FALSE,
4467 EL_EMC_KEY_5, -1, -1
4470 Xkey_6, TRUE, FALSE,
4471 EL_EMC_KEY_6, -1, -1
4474 Xkey_7, TRUE, FALSE,
4475 EL_EMC_KEY_7, -1, -1
4478 Xkey_8, TRUE, FALSE,
4479 EL_EMC_KEY_8, -1, -1
4482 Xwind_n, TRUE, FALSE,
4483 EL_BALLOON_SWITCH_UP, -1, -1
4486 Xwind_e, TRUE, FALSE,
4487 EL_BALLOON_SWITCH_RIGHT, -1, -1
4490 Xwind_s, TRUE, FALSE,
4491 EL_BALLOON_SWITCH_DOWN, -1, -1
4494 Xwind_w, TRUE, FALSE,
4495 EL_BALLOON_SWITCH_LEFT, -1, -1
4498 Xwind_nesw, TRUE, FALSE,
4499 EL_BALLOON_SWITCH_ANY, -1, -1
4502 Xwind_stop, TRUE, FALSE,
4503 EL_BALLOON_SWITCH_NONE, -1, -1
4507 EL_EM_EXIT_CLOSED, -1, -1
4510 Xexit_1, TRUE, FALSE,
4511 EL_EM_EXIT_OPEN, -1, -1
4514 Xexit_2, FALSE, FALSE,
4515 EL_EM_EXIT_OPEN, -1, -1
4518 Xexit_3, FALSE, FALSE,
4519 EL_EM_EXIT_OPEN, -1, -1
4522 Xdynamite, TRUE, FALSE,
4523 EL_EM_DYNAMITE, -1, -1
4526 Ydynamite_eat, FALSE, FALSE,
4527 EL_EM_DYNAMITE, ACTION_COLLECTING, -1
4530 Xdynamite_1, TRUE, FALSE,
4531 EL_EM_DYNAMITE_ACTIVE, -1, -1
4534 Xdynamite_2, FALSE, FALSE,
4535 EL_EM_DYNAMITE_ACTIVE, -1, -1
4538 Xdynamite_3, FALSE, FALSE,
4539 EL_EM_DYNAMITE_ACTIVE, -1, -1
4542 Xdynamite_4, FALSE, FALSE,
4543 EL_EM_DYNAMITE_ACTIVE, -1, -1
4546 Xbumper, TRUE, FALSE,
4547 EL_EMC_SPRING_BUMPER, -1, -1
4550 XbumperB, FALSE, FALSE,
4551 EL_EMC_SPRING_BUMPER, ACTION_ACTIVE, -1
4554 Xwheel, TRUE, FALSE,
4555 EL_ROBOT_WHEEL, -1, -1
4558 XwheelB, FALSE, FALSE,
4559 EL_ROBOT_WHEEL, ACTION_ACTIVE, -1
4562 Xswitch, TRUE, FALSE,
4563 EL_EMC_MAGIC_BALL_SWITCH, -1, -1
4566 XswitchB, FALSE, FALSE,
4567 EL_EMC_MAGIC_BALL_SWITCH, ACTION_ACTIVE, -1
4571 EL_QUICKSAND_EMPTY, -1, -1
4574 Xsand_stone, TRUE, FALSE,
4575 EL_QUICKSAND_FULL, -1, -1
4578 Xsand_stonein_1, FALSE, TRUE,
4579 EL_ROCK, ACTION_FILLING, -1
4582 Xsand_stonein_2, FALSE, TRUE,
4583 EL_ROCK, ACTION_FILLING, -1
4586 Xsand_stonein_3, FALSE, TRUE,
4587 EL_ROCK, ACTION_FILLING, -1
4590 Xsand_stonein_4, FALSE, TRUE,
4591 EL_ROCK, ACTION_FILLING, -1
4594 Xsand_stonesand_1, FALSE, FALSE,
4595 EL_QUICKSAND_FULL, -1, -1
4598 Xsand_stonesand_2, FALSE, FALSE,
4599 EL_QUICKSAND_FULL, -1, -1
4602 Xsand_stonesand_3, FALSE, FALSE,
4603 EL_QUICKSAND_FULL, -1, -1
4606 Xsand_stonesand_4, FALSE, FALSE,
4607 EL_QUICKSAND_FULL, -1, -1
4610 Xsand_stoneout_1, FALSE, FALSE,
4611 EL_ROCK, ACTION_EMPTYING, -1
4614 Xsand_stoneout_2, FALSE, FALSE,
4615 EL_ROCK, ACTION_EMPTYING, -1
4618 Xsand_sandstone_1, FALSE, FALSE,
4619 EL_QUICKSAND_FULL, -1, -1
4622 Xsand_sandstone_2, FALSE, FALSE,
4623 EL_QUICKSAND_FULL, -1, -1
4626 Xsand_sandstone_3, FALSE, FALSE,
4627 EL_QUICKSAND_FULL, -1, -1
4630 Xsand_sandstone_4, FALSE, FALSE,
4631 EL_QUICKSAND_FULL, -1, -1
4634 Xplant, TRUE, FALSE,
4635 EL_EMC_PLANT, -1, -1
4638 Yplant, FALSE, FALSE,
4639 EL_EMC_PLANT, -1, -1
4642 Xlenses, TRUE, FALSE,
4643 EL_EMC_LENSES, -1, -1
4646 Xmagnify, TRUE, FALSE,
4647 EL_EMC_MAGNIFIER, -1, -1
4650 Xdripper, TRUE, FALSE,
4651 EL_EMC_DRIPPER, -1, -1
4654 XdripperB, FALSE, FALSE,
4655 EL_EMC_DRIPPER, ACTION_ACTIVE, -1
4658 Xfake_blank, TRUE, FALSE,
4659 EL_INVISIBLE_WALL, -1, -1
4662 Xfake_blankB, FALSE, FALSE,
4663 EL_INVISIBLE_WALL, ACTION_ACTIVE, -1
4666 Xfake_grass, TRUE, FALSE,
4667 EL_EMC_FAKE_GRASS, -1, -1
4670 Xfake_grassB, FALSE, FALSE,
4671 EL_EMC_FAKE_GRASS, ACTION_ACTIVE, -1
4674 Xfake_door_1, TRUE, FALSE,
4675 EL_EM_GATE_1_GRAY, -1, -1
4678 Xfake_door_2, TRUE, FALSE,
4679 EL_EM_GATE_2_GRAY, -1, -1
4682 Xfake_door_3, TRUE, FALSE,
4683 EL_EM_GATE_3_GRAY, -1, -1
4686 Xfake_door_4, TRUE, FALSE,
4687 EL_EM_GATE_4_GRAY, -1, -1
4690 Xfake_door_5, TRUE, FALSE,
4691 EL_EMC_GATE_5_GRAY, -1, -1
4694 Xfake_door_6, TRUE, FALSE,
4695 EL_EMC_GATE_6_GRAY, -1, -1
4698 Xfake_door_7, TRUE, FALSE,
4699 EL_EMC_GATE_7_GRAY, -1, -1
4702 Xfake_door_8, TRUE, FALSE,
4703 EL_EMC_GATE_8_GRAY, -1, -1
4706 Xfake_acid_1, TRUE, FALSE,
4707 EL_EMC_FAKE_ACID, -1, -1
4710 Xfake_acid_2, FALSE, FALSE,
4711 EL_EMC_FAKE_ACID, -1, -1
4714 Xfake_acid_3, FALSE, FALSE,
4715 EL_EMC_FAKE_ACID, -1, -1
4718 Xfake_acid_4, FALSE, FALSE,
4719 EL_EMC_FAKE_ACID, -1, -1
4722 Xfake_acid_5, FALSE, FALSE,
4723 EL_EMC_FAKE_ACID, -1, -1
4726 Xfake_acid_6, FALSE, FALSE,
4727 EL_EMC_FAKE_ACID, -1, -1
4730 Xfake_acid_7, FALSE, FALSE,
4731 EL_EMC_FAKE_ACID, -1, -1
4734 Xfake_acid_8, FALSE, FALSE,
4735 EL_EMC_FAKE_ACID, -1, -1
4738 Xsteel_1, TRUE, FALSE,
4739 EL_STEELWALL, -1, -1
4742 Xsteel_2, TRUE, FALSE,
4743 EL_EMC_STEELWALL_2, -1, -1
4746 Xsteel_3, TRUE, FALSE,
4747 EL_EMC_STEELWALL_3, -1, -1
4750 Xsteel_4, TRUE, FALSE,
4751 EL_EMC_STEELWALL_4, -1, -1
4754 Xwall_1, TRUE, FALSE,
4758 Xwall_2, TRUE, FALSE,
4759 EL_EMC_WALL_14, -1, -1
4762 Xwall_3, TRUE, FALSE,
4763 EL_EMC_WALL_15, -1, -1
4766 Xwall_4, TRUE, FALSE,
4767 EL_EMC_WALL_16, -1, -1
4770 Xround_wall_1, TRUE, FALSE,
4771 EL_WALL_SLIPPERY, -1, -1
4774 Xround_wall_2, TRUE, FALSE,
4775 EL_EMC_WALL_SLIPPERY_2, -1, -1
4778 Xround_wall_3, TRUE, FALSE,
4779 EL_EMC_WALL_SLIPPERY_3, -1, -1
4782 Xround_wall_4, TRUE, FALSE,
4783 EL_EMC_WALL_SLIPPERY_4, -1, -1
4786 Xdecor_1, TRUE, FALSE,
4787 EL_EMC_WALL_8, -1, -1
4790 Xdecor_2, TRUE, FALSE,
4791 EL_EMC_WALL_6, -1, -1
4794 Xdecor_3, TRUE, FALSE,
4795 EL_EMC_WALL_4, -1, -1
4798 Xdecor_4, TRUE, FALSE,
4799 EL_EMC_WALL_7, -1, -1
4802 Xdecor_5, TRUE, FALSE,
4803 EL_EMC_WALL_5, -1, -1
4806 Xdecor_6, TRUE, FALSE,
4807 EL_EMC_WALL_9, -1, -1
4810 Xdecor_7, TRUE, FALSE,
4811 EL_EMC_WALL_10, -1, -1
4814 Xdecor_8, TRUE, FALSE,
4815 EL_EMC_WALL_1, -1, -1
4818 Xdecor_9, TRUE, FALSE,
4819 EL_EMC_WALL_2, -1, -1
4822 Xdecor_10, TRUE, FALSE,
4823 EL_EMC_WALL_3, -1, -1
4826 Xdecor_11, TRUE, FALSE,
4827 EL_EMC_WALL_11, -1, -1
4830 Xdecor_12, TRUE, FALSE,
4831 EL_EMC_WALL_12, -1, -1
4834 Xalpha_0, TRUE, FALSE,
4835 EL_CHAR('0'), -1, -1
4838 Xalpha_1, TRUE, FALSE,
4839 EL_CHAR('1'), -1, -1
4842 Xalpha_2, TRUE, FALSE,
4843 EL_CHAR('2'), -1, -1
4846 Xalpha_3, TRUE, FALSE,
4847 EL_CHAR('3'), -1, -1
4850 Xalpha_4, TRUE, FALSE,
4851 EL_CHAR('4'), -1, -1
4854 Xalpha_5, TRUE, FALSE,
4855 EL_CHAR('5'), -1, -1
4858 Xalpha_6, TRUE, FALSE,
4859 EL_CHAR('6'), -1, -1
4862 Xalpha_7, TRUE, FALSE,
4863 EL_CHAR('7'), -1, -1
4866 Xalpha_8, TRUE, FALSE,
4867 EL_CHAR('8'), -1, -1
4870 Xalpha_9, TRUE, FALSE,
4871 EL_CHAR('9'), -1, -1
4874 Xalpha_excla, TRUE, FALSE,
4875 EL_CHAR('!'), -1, -1
4878 Xalpha_quote, TRUE, FALSE,
4879 EL_CHAR('"'), -1, -1
4882 Xalpha_comma, TRUE, FALSE,
4883 EL_CHAR(','), -1, -1
4886 Xalpha_minus, TRUE, FALSE,
4887 EL_CHAR('-'), -1, -1
4890 Xalpha_perio, TRUE, FALSE,
4891 EL_CHAR('.'), -1, -1
4894 Xalpha_colon, TRUE, FALSE,
4895 EL_CHAR(':'), -1, -1
4898 Xalpha_quest, TRUE, FALSE,
4899 EL_CHAR('?'), -1, -1
4902 Xalpha_a, TRUE, FALSE,
4903 EL_CHAR('A'), -1, -1
4906 Xalpha_b, TRUE, FALSE,
4907 EL_CHAR('B'), -1, -1
4910 Xalpha_c, TRUE, FALSE,
4911 EL_CHAR('C'), -1, -1
4914 Xalpha_d, TRUE, FALSE,
4915 EL_CHAR('D'), -1, -1
4918 Xalpha_e, TRUE, FALSE,
4919 EL_CHAR('E'), -1, -1
4922 Xalpha_f, TRUE, FALSE,
4923 EL_CHAR('F'), -1, -1
4926 Xalpha_g, TRUE, FALSE,
4927 EL_CHAR('G'), -1, -1
4930 Xalpha_h, TRUE, FALSE,
4931 EL_CHAR('H'), -1, -1
4934 Xalpha_i, TRUE, FALSE,
4935 EL_CHAR('I'), -1, -1
4938 Xalpha_j, TRUE, FALSE,
4939 EL_CHAR('J'), -1, -1
4942 Xalpha_k, TRUE, FALSE,
4943 EL_CHAR('K'), -1, -1
4946 Xalpha_l, TRUE, FALSE,
4947 EL_CHAR('L'), -1, -1
4950 Xalpha_m, TRUE, FALSE,
4951 EL_CHAR('M'), -1, -1
4954 Xalpha_n, TRUE, FALSE,
4955 EL_CHAR('N'), -1, -1
4958 Xalpha_o, TRUE, FALSE,
4959 EL_CHAR('O'), -1, -1
4962 Xalpha_p, TRUE, FALSE,
4963 EL_CHAR('P'), -1, -1
4966 Xalpha_q, TRUE, FALSE,
4967 EL_CHAR('Q'), -1, -1
4970 Xalpha_r, TRUE, FALSE,
4971 EL_CHAR('R'), -1, -1
4974 Xalpha_s, TRUE, FALSE,
4975 EL_CHAR('S'), -1, -1
4978 Xalpha_t, TRUE, FALSE,
4979 EL_CHAR('T'), -1, -1
4982 Xalpha_u, TRUE, FALSE,
4983 EL_CHAR('U'), -1, -1
4986 Xalpha_v, TRUE, FALSE,
4987 EL_CHAR('V'), -1, -1
4990 Xalpha_w, TRUE, FALSE,
4991 EL_CHAR('W'), -1, -1
4994 Xalpha_x, TRUE, FALSE,
4995 EL_CHAR('X'), -1, -1
4998 Xalpha_y, TRUE, FALSE,
4999 EL_CHAR('Y'), -1, -1
5002 Xalpha_z, TRUE, FALSE,
5003 EL_CHAR('Z'), -1, -1
5006 Xalpha_arrow_e, TRUE, FALSE,
5007 EL_CHAR('>'), -1, -1
5010 Xalpha_arrow_w, TRUE, FALSE,
5011 EL_CHAR('<'), -1, -1
5014 Xalpha_copyr, TRUE, FALSE,
5015 EL_CHAR('©'), -1, -1
5019 Xboom_bug, FALSE, FALSE,
5020 EL_BUG, ACTION_EXPLODING, -1
5023 Xboom_bomb, FALSE, FALSE,
5024 EL_BOMB, ACTION_EXPLODING, -1
5027 Xboom_android, FALSE, FALSE,
5028 EL_EMC_ANDROID, ACTION_OTHER, -1
5031 Xboom_1, FALSE, FALSE,
5032 EL_DEFAULT, ACTION_EXPLODING, -1
5035 Xboom_2, FALSE, FALSE,
5036 EL_DEFAULT, ACTION_EXPLODING, -1
5039 Znormal, FALSE, FALSE,
5043 Zdynamite, FALSE, FALSE,
5047 Zplayer, FALSE, FALSE,
5051 ZBORDER, FALSE, FALSE,
5061 static struct Mapping_EM_to_RND_player
5070 em_player_mapping_list[] =
5074 EL_PLAYER_1, ACTION_MOVING, MV_BIT_UP,
5078 EL_PLAYER_1, ACTION_MOVING, MV_BIT_RIGHT,
5082 EL_PLAYER_1, ACTION_MOVING, MV_BIT_DOWN,
5086 EL_PLAYER_1, ACTION_MOVING, MV_BIT_LEFT,
5090 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_UP,
5094 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_RIGHT,
5098 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_DOWN,
5102 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_LEFT,
5106 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_UP,
5110 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_RIGHT,
5114 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_DOWN,
5118 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_LEFT,
5122 EL_PLAYER_2, ACTION_MOVING, MV_BIT_UP,
5126 EL_PLAYER_2, ACTION_MOVING, MV_BIT_RIGHT,
5130 EL_PLAYER_2, ACTION_MOVING, MV_BIT_DOWN,
5134 EL_PLAYER_2, ACTION_MOVING, MV_BIT_LEFT,
5138 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_UP,
5142 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_RIGHT,
5146 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_DOWN,
5150 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_LEFT,
5154 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_UP,
5158 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_RIGHT,
5162 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_DOWN,
5166 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_LEFT,
5170 EL_PLAYER_1, ACTION_DEFAULT, -1,
5174 EL_PLAYER_2, ACTION_DEFAULT, -1,
5178 EL_PLAYER_3, ACTION_MOVING, MV_BIT_UP,
5182 EL_PLAYER_3, ACTION_MOVING, MV_BIT_RIGHT,
5186 EL_PLAYER_3, ACTION_MOVING, MV_BIT_DOWN,
5190 EL_PLAYER_3, ACTION_MOVING, MV_BIT_LEFT,
5194 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_UP,
5198 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_RIGHT,
5202 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_DOWN,
5206 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_LEFT,
5210 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_UP,
5214 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_RIGHT,
5218 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_DOWN,
5222 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_LEFT,
5226 EL_PLAYER_4, ACTION_MOVING, MV_BIT_UP,
5230 EL_PLAYER_4, ACTION_MOVING, MV_BIT_RIGHT,
5234 EL_PLAYER_4, ACTION_MOVING, MV_BIT_DOWN,
5238 EL_PLAYER_4, ACTION_MOVING, MV_BIT_LEFT,
5242 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_UP,
5246 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_RIGHT,
5250 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_DOWN,
5254 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_LEFT,
5258 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_UP,
5262 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_RIGHT,
5266 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_DOWN,
5270 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_LEFT,
5274 EL_PLAYER_3, ACTION_DEFAULT, -1,
5278 EL_PLAYER_4, ACTION_DEFAULT, -1,
5287 int map_element_RND_to_EM(int element_rnd)
5289 static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
5290 static boolean mapping_initialized = FALSE;
5292 if (!mapping_initialized)
5296 /* return "Xalpha_quest" for all undefined elements in mapping array */
5297 for (i = 0; i < NUM_FILE_ELEMENTS; i++)
5298 mapping_RND_to_EM[i] = Xalpha_quest;
5300 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5301 if (em_object_mapping_list[i].is_rnd_to_em_mapping)
5302 mapping_RND_to_EM[em_object_mapping_list[i].element_rnd] =
5303 em_object_mapping_list[i].element_em;
5305 mapping_initialized = TRUE;
5308 if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
5309 return mapping_RND_to_EM[element_rnd];
5311 Error(ERR_WARN, "invalid RND level element %d", element_rnd);
5316 int map_element_EM_to_RND(int element_em)
5318 static unsigned short mapping_EM_to_RND[TILE_MAX];
5319 static boolean mapping_initialized = FALSE;
5321 if (!mapping_initialized)
5325 /* return "EL_UNKNOWN" for all undefined elements in mapping array */
5326 for (i = 0; i < TILE_MAX; i++)
5327 mapping_EM_to_RND[i] = EL_UNKNOWN;
5329 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5330 mapping_EM_to_RND[em_object_mapping_list[i].element_em] =
5331 em_object_mapping_list[i].element_rnd;
5333 mapping_initialized = TRUE;
5336 if (element_em >= 0 && element_em < TILE_MAX)
5337 return mapping_EM_to_RND[element_em];
5339 Error(ERR_WARN, "invalid EM level element %d", element_em);
5344 void map_android_clone_elements_RND_to_EM(struct LevelInfo *level)
5346 struct LevelInfo_EM *level_em = level->native_em_level;
5347 struct LEVEL *lev = level_em->lev;
5350 for (i = 0; i < TILE_MAX; i++)
5351 lev->android_array[i] = Xblank;
5353 for (i = 0; i < level->num_android_clone_elements; i++)
5355 int element_rnd = level->android_clone_element[i];
5356 int element_em = map_element_RND_to_EM(element_rnd);
5358 for (j = 0; em_object_mapping_list[j].element_em != -1; j++)
5359 if (em_object_mapping_list[j].element_rnd == element_rnd)
5360 lev->android_array[em_object_mapping_list[j].element_em] = element_em;
5364 void map_android_clone_elements_EM_to_RND(struct LevelInfo *level)
5366 struct LevelInfo_EM *level_em = level->native_em_level;
5367 struct LEVEL *lev = level_em->lev;
5370 level->num_android_clone_elements = 0;
5372 for (i = 0; i < TILE_MAX; i++)
5374 int element_em = lev->android_array[i];
5376 boolean element_found = FALSE;
5378 if (element_em == Xblank)
5381 element_rnd = map_element_EM_to_RND(element_em);
5383 for (j = 0; j < level->num_android_clone_elements; j++)
5384 if (level->android_clone_element[j] == element_rnd)
5385 element_found = TRUE;
5389 level->android_clone_element[level->num_android_clone_elements++] =
5392 if (level->num_android_clone_elements == MAX_ANDROID_ELEMENTS)
5397 if (level->num_android_clone_elements == 0)
5399 level->num_android_clone_elements = 1;
5400 level->android_clone_element[0] = EL_EMPTY;
5404 int map_direction_RND_to_EM(int direction)
5406 return (direction == MV_UP ? 0 :
5407 direction == MV_RIGHT ? 1 :
5408 direction == MV_DOWN ? 2 :
5409 direction == MV_LEFT ? 3 :
5413 int map_direction_EM_to_RND(int direction)
5415 return (direction == 0 ? MV_UP :
5416 direction == 1 ? MV_RIGHT :
5417 direction == 2 ? MV_DOWN :
5418 direction == 3 ? MV_LEFT :
5422 int get_next_element(int element)
5426 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
5427 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
5428 case EL_QUICKSAND_FAST_FILLING: return EL_QUICKSAND_FAST_FULL;
5429 case EL_QUICKSAND_FAST_EMPTYING: return EL_QUICKSAND_FAST_EMPTY;
5430 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
5431 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
5432 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
5433 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
5434 case EL_DC_MAGIC_WALL_FILLING: return EL_DC_MAGIC_WALL_FULL;
5435 case EL_DC_MAGIC_WALL_EMPTYING: return EL_DC_MAGIC_WALL_ACTIVE;
5436 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
5438 default: return element;
5443 int el_act_dir2img(int element, int action, int direction)
5445 element = GFX_ELEMENT(element);
5447 if (direction == MV_NONE)
5448 return element_info[element].graphic[action];
5450 direction = MV_DIR_TO_BIT(direction);
5452 return element_info[element].direction_graphic[action][direction];
5455 int el_act_dir2img(int element, int action, int direction)
5457 element = GFX_ELEMENT(element);
5458 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
5460 /* direction_graphic[][] == graphic[] for undefined direction graphics */
5461 return element_info[element].direction_graphic[action][direction];
5466 static int el_act_dir2crm(int element, int action, int direction)
5468 element = GFX_ELEMENT(element);
5470 if (direction == MV_NONE)
5471 return element_info[element].crumbled[action];
5473 direction = MV_DIR_TO_BIT(direction);
5475 return element_info[element].direction_crumbled[action][direction];
5478 static int el_act_dir2crm(int element, int action, int direction)
5480 element = GFX_ELEMENT(element);
5481 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
5483 /* direction_graphic[][] == graphic[] for undefined direction graphics */
5484 return element_info[element].direction_crumbled[action][direction];
5488 int el_act2img(int element, int action)
5490 element = GFX_ELEMENT(element);
5492 return element_info[element].graphic[action];
5495 int el_act2crm(int element, int action)
5497 element = GFX_ELEMENT(element);
5499 return element_info[element].crumbled[action];
5502 int el_dir2img(int element, int direction)
5504 element = GFX_ELEMENT(element);
5506 return el_act_dir2img(element, ACTION_DEFAULT, direction);
5509 int el2baseimg(int element)
5511 return element_info[element].graphic[ACTION_DEFAULT];
5514 int el2img(int element)
5516 element = GFX_ELEMENT(element);
5518 return element_info[element].graphic[ACTION_DEFAULT];
5521 int el2edimg(int element)
5523 element = GFX_ELEMENT(element);
5525 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
5528 int el2preimg(int element)
5530 element = GFX_ELEMENT(element);
5532 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
5535 int font2baseimg(int font_nr)
5537 return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
5540 int getNumActivePlayers_EM()
5542 int num_players = 0;
5548 for (i = 0; i < MAX_PLAYERS; i++)
5549 if (tape.player_participates[i])
5555 int getGameFrameDelay_EM(int native_em_game_frame_delay)
5557 int game_frame_delay_value;
5559 game_frame_delay_value =
5560 (tape.playing && tape.fast_forward ? FfwdFrameDelay :
5561 GameFrameDelay == GAME_FRAME_DELAY ? native_em_game_frame_delay :
5564 if (tape.playing && tape.warp_forward && !tape.pausing)
5565 game_frame_delay_value = 0;
5567 return game_frame_delay_value;
5570 unsigned int InitRND(long seed)
5572 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
5573 return InitEngineRandom_EM(seed);
5575 return InitEngineRandom_RND(seed);
5578 void InitGraphicInfo_EM(void)
5580 struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
5581 struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
5585 int num_em_gfx_errors = 0;
5587 if (graphic_info_em_object[0][0].bitmap == NULL)
5589 /* EM graphics not yet initialized in em_open_all() */
5594 printf("::: [4 errors can be ignored (1 x 'bomb', 3 x 'em_dynamite']\n");
5597 /* always start with reliable default values */
5598 for (i = 0; i < TILE_MAX; i++)
5600 object_mapping[i].element_rnd = EL_UNKNOWN;
5601 object_mapping[i].is_backside = FALSE;
5602 object_mapping[i].action = ACTION_DEFAULT;
5603 object_mapping[i].direction = MV_NONE;
5606 /* always start with reliable default values */
5607 for (p = 0; p < MAX_PLAYERS; p++)
5609 for (i = 0; i < SPR_MAX; i++)
5611 player_mapping[p][i].element_rnd = EL_UNKNOWN;
5612 player_mapping[p][i].action = ACTION_DEFAULT;
5613 player_mapping[p][i].direction = MV_NONE;
5617 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5619 int e = em_object_mapping_list[i].element_em;
5621 object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd;
5622 object_mapping[e].is_backside = em_object_mapping_list[i].is_backside;
5624 if (em_object_mapping_list[i].action != -1)
5625 object_mapping[e].action = em_object_mapping_list[i].action;
5627 if (em_object_mapping_list[i].direction != -1)
5628 object_mapping[e].direction =
5629 MV_DIR_FROM_BIT(em_object_mapping_list[i].direction);
5632 for (i = 0; em_player_mapping_list[i].action_em != -1; i++)
5634 int a = em_player_mapping_list[i].action_em;
5635 int p = em_player_mapping_list[i].player_nr;
5637 player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd;
5639 if (em_player_mapping_list[i].action != -1)
5640 player_mapping[p][a].action = em_player_mapping_list[i].action;
5642 if (em_player_mapping_list[i].direction != -1)
5643 player_mapping[p][a].direction =
5644 MV_DIR_FROM_BIT(em_player_mapping_list[i].direction);
5647 for (i = 0; i < TILE_MAX; i++)
5649 int element = object_mapping[i].element_rnd;
5650 int action = object_mapping[i].action;
5651 int direction = object_mapping[i].direction;
5652 boolean is_backside = object_mapping[i].is_backside;
5653 boolean action_removing = (action == ACTION_DIGGING ||
5654 action == ACTION_SNAPPING ||
5655 action == ACTION_COLLECTING);
5656 boolean action_exploding = ((action == ACTION_EXPLODING ||
5657 action == ACTION_SMASHED_BY_ROCK ||
5658 action == ACTION_SMASHED_BY_SPRING) &&
5659 element != EL_DIAMOND);
5660 boolean action_active = (action == ACTION_ACTIVE);
5661 boolean action_other = (action == ACTION_OTHER);
5663 for (j = 0; j < 8; j++)
5665 int effective_element = (j > 5 && i == Yacid_splash_eB ? EL_EMPTY :
5666 j > 5 && i == Yacid_splash_wB ? EL_EMPTY :
5668 i == Xdrip_stretch ? element :
5669 i == Xdrip_stretchB ? element :
5670 i == Ydrip_s1 ? element :
5671 i == Ydrip_s1B ? element :
5672 i == Xball_1B ? element :
5673 i == Xball_2 ? element :
5674 i == Xball_2B ? element :
5675 i == Yball_eat ? element :
5676 i == Ykey_1_eat ? element :
5677 i == Ykey_2_eat ? element :
5678 i == Ykey_3_eat ? element :
5679 i == Ykey_4_eat ? element :
5680 i == Ykey_5_eat ? element :
5681 i == Ykey_6_eat ? element :
5682 i == Ykey_7_eat ? element :
5683 i == Ykey_8_eat ? element :
5684 i == Ylenses_eat ? element :
5685 i == Ymagnify_eat ? element :
5686 i == Ygrass_eat ? element :
5687 i == Ydirt_eat ? element :
5688 i == Yemerald_stone ? EL_EMERALD :
5689 i == Ydiamond_stone ? EL_ROCK :
5690 i == Xsand_stonein_1 ? element :
5691 i == Xsand_stonein_2 ? element :
5692 i == Xsand_stonein_3 ? element :
5693 i == Xsand_stonein_4 ? element :
5694 is_backside ? EL_EMPTY :
5695 action_removing ? EL_EMPTY :
5697 int effective_action = (j < 7 ? action :
5698 i == Xdrip_stretch ? action :
5699 i == Xdrip_stretchB ? action :
5700 i == Ydrip_s1 ? action :
5701 i == Ydrip_s1B ? action :
5702 i == Xball_1B ? action :
5703 i == Xball_2 ? action :
5704 i == Xball_2B ? action :
5705 i == Yball_eat ? action :
5706 i == Ykey_1_eat ? action :
5707 i == Ykey_2_eat ? action :
5708 i == Ykey_3_eat ? action :
5709 i == Ykey_4_eat ? action :
5710 i == Ykey_5_eat ? action :
5711 i == Ykey_6_eat ? action :
5712 i == Ykey_7_eat ? action :
5713 i == Ykey_8_eat ? action :
5714 i == Ylenses_eat ? action :
5715 i == Ymagnify_eat ? action :
5716 i == Ygrass_eat ? action :
5717 i == Ydirt_eat ? action :
5718 i == Xsand_stonein_1 ? action :
5719 i == Xsand_stonein_2 ? action :
5720 i == Xsand_stonein_3 ? action :
5721 i == Xsand_stonein_4 ? action :
5722 i == Xsand_stoneout_1 ? action :
5723 i == Xsand_stoneout_2 ? action :
5724 i == Xboom_android ? ACTION_EXPLODING :
5725 action_exploding ? ACTION_EXPLODING :
5726 action_active ? action :
5727 action_other ? action :
5729 int graphic = (el_act_dir2img(effective_element, effective_action,
5731 int crumbled = (el_act_dir2crm(effective_element, effective_action,
5733 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
5734 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
5735 boolean has_action_graphics = (graphic != base_graphic);
5736 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
5737 struct GraphicInfo *g = &graphic_info[graphic];
5738 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
5741 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
5742 boolean special_animation = (action != ACTION_DEFAULT &&
5743 g->anim_frames == 3 &&
5744 g->anim_delay == 2 &&
5745 g->anim_mode & ANIM_LINEAR);
5746 int sync_frame = (i == Xdrip_stretch ? 7 :
5747 i == Xdrip_stretchB ? 7 :
5748 i == Ydrip_s2 ? j + 8 :
5749 i == Ydrip_s2B ? j + 8 :
5758 i == Xfake_acid_1 ? 0 :
5759 i == Xfake_acid_2 ? 10 :
5760 i == Xfake_acid_3 ? 20 :
5761 i == Xfake_acid_4 ? 30 :
5762 i == Xfake_acid_5 ? 40 :
5763 i == Xfake_acid_6 ? 50 :
5764 i == Xfake_acid_7 ? 60 :
5765 i == Xfake_acid_8 ? 70 :
5767 i == Xball_2B ? j + 8 :
5768 i == Yball_eat ? j + 1 :
5769 i == Ykey_1_eat ? j + 1 :
5770 i == Ykey_2_eat ? j + 1 :
5771 i == Ykey_3_eat ? j + 1 :
5772 i == Ykey_4_eat ? j + 1 :
5773 i == Ykey_5_eat ? j + 1 :
5774 i == Ykey_6_eat ? j + 1 :
5775 i == Ykey_7_eat ? j + 1 :
5776 i == Ykey_8_eat ? j + 1 :
5777 i == Ylenses_eat ? j + 1 :
5778 i == Ymagnify_eat ? j + 1 :
5779 i == Ygrass_eat ? j + 1 :
5780 i == Ydirt_eat ? j + 1 :
5781 i == Xamoeba_1 ? 0 :
5782 i == Xamoeba_2 ? 1 :
5783 i == Xamoeba_3 ? 2 :
5784 i == Xamoeba_4 ? 3 :
5785 i == Xamoeba_5 ? 0 :
5786 i == Xamoeba_6 ? 1 :
5787 i == Xamoeba_7 ? 2 :
5788 i == Xamoeba_8 ? 3 :
5789 i == Xexit_2 ? j + 8 :
5790 i == Xexit_3 ? j + 16 :
5791 i == Xdynamite_1 ? 0 :
5792 i == Xdynamite_2 ? 8 :
5793 i == Xdynamite_3 ? 16 :
5794 i == Xdynamite_4 ? 24 :
5795 i == Xsand_stonein_1 ? j + 1 :
5796 i == Xsand_stonein_2 ? j + 9 :
5797 i == Xsand_stonein_3 ? j + 17 :
5798 i == Xsand_stonein_4 ? j + 25 :
5799 i == Xsand_stoneout_1 && j == 0 ? 0 :
5800 i == Xsand_stoneout_1 && j == 1 ? 0 :
5801 i == Xsand_stoneout_1 && j == 2 ? 1 :
5802 i == Xsand_stoneout_1 && j == 3 ? 2 :
5803 i == Xsand_stoneout_1 && j == 4 ? 2 :
5804 i == Xsand_stoneout_1 && j == 5 ? 3 :
5805 i == Xsand_stoneout_1 && j == 6 ? 4 :
5806 i == Xsand_stoneout_1 && j == 7 ? 4 :
5807 i == Xsand_stoneout_2 && j == 0 ? 5 :
5808 i == Xsand_stoneout_2 && j == 1 ? 6 :
5809 i == Xsand_stoneout_2 && j == 2 ? 7 :
5810 i == Xsand_stoneout_2 && j == 3 ? 8 :
5811 i == Xsand_stoneout_2 && j == 4 ? 9 :
5812 i == Xsand_stoneout_2 && j == 5 ? 11 :
5813 i == Xsand_stoneout_2 && j == 6 ? 13 :
5814 i == Xsand_stoneout_2 && j == 7 ? 15 :
5815 i == Xboom_bug && j == 1 ? 2 :
5816 i == Xboom_bug && j == 2 ? 2 :
5817 i == Xboom_bug && j == 3 ? 4 :
5818 i == Xboom_bug && j == 4 ? 4 :
5819 i == Xboom_bug && j == 5 ? 2 :
5820 i == Xboom_bug && j == 6 ? 2 :
5821 i == Xboom_bug && j == 7 ? 0 :
5822 i == Xboom_bomb && j == 1 ? 2 :
5823 i == Xboom_bomb && j == 2 ? 2 :
5824 i == Xboom_bomb && j == 3 ? 4 :
5825 i == Xboom_bomb && j == 4 ? 4 :
5826 i == Xboom_bomb && j == 5 ? 2 :
5827 i == Xboom_bomb && j == 6 ? 2 :
5828 i == Xboom_bomb && j == 7 ? 0 :
5829 i == Xboom_android && j == 7 ? 6 :
5830 i == Xboom_1 && j == 1 ? 2 :
5831 i == Xboom_1 && j == 2 ? 2 :
5832 i == Xboom_1 && j == 3 ? 4 :
5833 i == Xboom_1 && j == 4 ? 4 :
5834 i == Xboom_1 && j == 5 ? 6 :
5835 i == Xboom_1 && j == 6 ? 6 :
5836 i == Xboom_1 && j == 7 ? 8 :
5837 i == Xboom_2 && j == 0 ? 8 :
5838 i == Xboom_2 && j == 1 ? 8 :
5839 i == Xboom_2 && j == 2 ? 10 :
5840 i == Xboom_2 && j == 3 ? 10 :
5841 i == Xboom_2 && j == 4 ? 10 :
5842 i == Xboom_2 && j == 5 ? 12 :
5843 i == Xboom_2 && j == 6 ? 12 :
5844 i == Xboom_2 && j == 7 ? 12 :
5845 special_animation && j == 4 ? 3 :
5846 effective_action != action ? 0 :
5850 Bitmap *debug_bitmap = g_em->bitmap;
5851 int debug_src_x = g_em->src_x;
5852 int debug_src_y = g_em->src_y;
5855 int frame = getAnimationFrame(g->anim_frames,
5858 g->anim_start_frame,
5861 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y,
5862 g->double_movement && is_backside);
5864 g_em->bitmap = src_bitmap;
5865 g_em->src_x = src_x;
5866 g_em->src_y = src_y;
5867 g_em->src_offset_x = 0;
5868 g_em->src_offset_y = 0;
5869 g_em->dst_offset_x = 0;
5870 g_em->dst_offset_y = 0;
5871 g_em->width = TILEX;
5872 g_em->height = TILEY;
5874 g_em->crumbled_bitmap = NULL;
5875 g_em->crumbled_src_x = 0;
5876 g_em->crumbled_src_y = 0;
5877 g_em->crumbled_border_size = 0;
5879 g_em->has_crumbled_graphics = FALSE;
5880 g_em->preserve_background = FALSE;
5883 if (has_crumbled_graphics && crumbled == IMG_EMPTY_SPACE)
5884 printf("::: empty crumbled: %d [%s], %d, %d\n",
5885 effective_element, element_info[effective_element].token_name,
5886 effective_action, direction);
5889 /* if element can be crumbled, but certain action graphics are just empty
5890 space (like snapping sand with the original R'n'D graphics), do not
5891 treat these empty space graphics as crumbled graphics in EMC engine */
5892 if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
5894 getGraphicSource(crumbled, frame, &src_bitmap, &src_x, &src_y);
5896 g_em->has_crumbled_graphics = TRUE;
5897 g_em->crumbled_bitmap = src_bitmap;
5898 g_em->crumbled_src_x = src_x;
5899 g_em->crumbled_src_y = src_y;
5900 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
5904 if (element == EL_ROCK &&
5905 effective_action == ACTION_FILLING)
5906 printf("::: has_action_graphics == %d\n", has_action_graphics);
5909 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
5910 effective_action == ACTION_MOVING ||
5911 effective_action == ACTION_PUSHING ||
5912 effective_action == ACTION_EATING)) ||
5913 (!has_action_graphics && (effective_action == ACTION_FILLING ||
5914 effective_action == ACTION_EMPTYING)))
5917 (effective_action == ACTION_FALLING ||
5918 effective_action == ACTION_FILLING ||
5919 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
5920 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
5921 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
5922 int num_steps = (i == Ydrip_s1 ? 16 :
5923 i == Ydrip_s1B ? 16 :
5924 i == Ydrip_s2 ? 16 :
5925 i == Ydrip_s2B ? 16 :
5926 i == Xsand_stonein_1 ? 32 :
5927 i == Xsand_stonein_2 ? 32 :
5928 i == Xsand_stonein_3 ? 32 :
5929 i == Xsand_stonein_4 ? 32 :
5930 i == Xsand_stoneout_1 ? 16 :
5931 i == Xsand_stoneout_2 ? 16 : 8);
5932 int cx = ABS(dx) * (TILEX / num_steps);
5933 int cy = ABS(dy) * (TILEY / num_steps);
5934 int step_frame = (i == Ydrip_s2 ? j + 8 :
5935 i == Ydrip_s2B ? j + 8 :
5936 i == Xsand_stonein_2 ? j + 8 :
5937 i == Xsand_stonein_3 ? j + 16 :
5938 i == Xsand_stonein_4 ? j + 24 :
5939 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
5940 int step = (is_backside ? step_frame : num_steps - step_frame);
5942 if (is_backside) /* tile where movement starts */
5944 if (dx < 0 || dy < 0)
5946 g_em->src_offset_x = cx * step;
5947 g_em->src_offset_y = cy * step;
5951 g_em->dst_offset_x = cx * step;
5952 g_em->dst_offset_y = cy * step;
5955 else /* tile where movement ends */
5957 if (dx < 0 || dy < 0)
5959 g_em->dst_offset_x = cx * step;
5960 g_em->dst_offset_y = cy * step;
5964 g_em->src_offset_x = cx * step;
5965 g_em->src_offset_y = cy * step;
5969 g_em->width = TILEX - cx * step;
5970 g_em->height = TILEY - cy * step;
5973 /* create unique graphic identifier to decide if tile must be redrawn */
5974 /* bit 31 - 16 (16 bit): EM style graphic
5975 bit 15 - 12 ( 4 bit): EM style frame
5976 bit 11 - 6 ( 6 bit): graphic width
5977 bit 5 - 0 ( 6 bit): graphic height */
5978 g_em->unique_identifier =
5979 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
5983 /* skip check for EMC elements not contained in original EMC artwork */
5984 if (element == EL_EMC_FAKE_ACID)
5987 if (g_em->bitmap != debug_bitmap ||
5988 g_em->src_x != debug_src_x ||
5989 g_em->src_y != debug_src_y ||
5990 g_em->src_offset_x != 0 ||
5991 g_em->src_offset_y != 0 ||
5992 g_em->dst_offset_x != 0 ||
5993 g_em->dst_offset_y != 0 ||
5994 g_em->width != TILEX ||
5995 g_em->height != TILEY)
5997 static int last_i = -1;
6005 printf("::: EMC GFX ERROR for element %d -> %d ('%s', '%s', %d)",
6006 i, element, element_info[element].token_name,
6007 element_action_info[effective_action].suffix, direction);
6009 if (element != effective_element)
6010 printf(" [%d ('%s')]",
6012 element_info[effective_element].token_name);
6016 if (g_em->bitmap != debug_bitmap)
6017 printf(" %d (%d): different bitmap! (0x%08x != 0x%08x)\n",
6018 j, is_backside, (int)(g_em->bitmap), (int)(debug_bitmap));
6020 if (g_em->src_x != debug_src_x ||
6021 g_em->src_y != debug_src_y)
6022 printf(" frame %d (%c): %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
6023 j, (is_backside ? 'B' : 'F'),
6024 g_em->src_x, g_em->src_y,
6025 g_em->src_x / 32, g_em->src_y / 32,
6026 debug_src_x, debug_src_y,
6027 debug_src_x / 32, debug_src_y / 32);
6029 if (g_em->src_offset_x != 0 ||
6030 g_em->src_offset_y != 0 ||
6031 g_em->dst_offset_x != 0 ||
6032 g_em->dst_offset_y != 0)
6033 printf(" %d (%d): offsets %d,%d and %d,%d should be all 0\n",
6035 g_em->src_offset_x, g_em->src_offset_y,
6036 g_em->dst_offset_x, g_em->dst_offset_y);
6038 if (g_em->width != TILEX ||
6039 g_em->height != TILEY)
6040 printf(" %d (%d): size %d,%d should be %d,%d\n",
6042 g_em->width, g_em->height, TILEX, TILEY);
6044 num_em_gfx_errors++;
6051 for (i = 0; i < TILE_MAX; i++)
6053 for (j = 0; j < 8; j++)
6055 int element = object_mapping[i].element_rnd;
6056 int action = object_mapping[i].action;
6057 int direction = object_mapping[i].direction;
6058 boolean is_backside = object_mapping[i].is_backside;
6059 int graphic_action = el_act_dir2img(element, action, direction);
6060 int graphic_default = el_act_dir2img(element, ACTION_DEFAULT, direction);
6062 if ((action == ACTION_SMASHED_BY_ROCK ||
6063 action == ACTION_SMASHED_BY_SPRING ||
6064 action == ACTION_EATING) &&
6065 graphic_action == graphic_default)
6067 int e = (action == ACTION_SMASHED_BY_ROCK ? Ystone_s :
6068 action == ACTION_SMASHED_BY_SPRING ? Yspring_s :
6069 direction == MV_LEFT ? (is_backside? Yspring_wB: Yspring_w) :
6070 direction == MV_RIGHT ? (is_backside? Yspring_eB: Yspring_e) :
6073 /* no separate animation for "smashed by rock" -- use rock instead */
6074 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
6075 struct GraphicInfo_EM *g_xx = &graphic_info_em_object[e][7 - j];
6077 g_em->bitmap = g_xx->bitmap;
6078 g_em->src_x = g_xx->src_x;
6079 g_em->src_y = g_xx->src_y;
6080 g_em->src_offset_x = g_xx->src_offset_x;
6081 g_em->src_offset_y = g_xx->src_offset_y;
6082 g_em->dst_offset_x = g_xx->dst_offset_x;
6083 g_em->dst_offset_y = g_xx->dst_offset_y;
6084 g_em->width = g_xx->width;
6085 g_em->height = g_xx->height;
6086 g_em->unique_identifier = g_xx->unique_identifier;
6089 g_em->preserve_background = TRUE;
6094 for (p = 0; p < MAX_PLAYERS; p++)
6096 for (i = 0; i < SPR_MAX; i++)
6098 int element = player_mapping[p][i].element_rnd;
6099 int action = player_mapping[p][i].action;
6100 int direction = player_mapping[p][i].direction;
6102 for (j = 0; j < 8; j++)
6104 int effective_element = element;
6105 int effective_action = action;
6106 int graphic = (direction == MV_NONE ?
6107 el_act2img(effective_element, effective_action) :
6108 el_act_dir2img(effective_element, effective_action,
6110 struct GraphicInfo *g = &graphic_info[graphic];
6111 struct GraphicInfo_EM *g_em = &graphic_info_em_player[p][i][7 - j];
6117 Bitmap *debug_bitmap = g_em->bitmap;
6118 int debug_src_x = g_em->src_x;
6119 int debug_src_y = g_em->src_y;
6122 int frame = getAnimationFrame(g->anim_frames,
6125 g->anim_start_frame,
6128 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x,&src_y, FALSE);
6130 g_em->bitmap = src_bitmap;
6131 g_em->src_x = src_x;
6132 g_em->src_y = src_y;
6133 g_em->src_offset_x = 0;
6134 g_em->src_offset_y = 0;
6135 g_em->dst_offset_x = 0;
6136 g_em->dst_offset_y = 0;
6137 g_em->width = TILEX;
6138 g_em->height = TILEY;
6142 /* skip check for EMC elements not contained in original EMC artwork */
6143 if (element == EL_PLAYER_3 ||
6144 element == EL_PLAYER_4)
6147 if (g_em->bitmap != debug_bitmap ||
6148 g_em->src_x != debug_src_x ||
6149 g_em->src_y != debug_src_y)
6151 static int last_i = -1;
6159 printf("::: EMC GFX ERROR for p/a %d/%d -> %d ('%s', '%s', %d)",
6160 p, i, element, element_info[element].token_name,
6161 element_action_info[effective_action].suffix, direction);
6163 if (element != effective_element)
6164 printf(" [%d ('%s')]",
6166 element_info[effective_element].token_name);
6170 if (g_em->bitmap != debug_bitmap)
6171 printf(" %d: different bitmap! (0x%08x != 0x%08x)\n",
6172 j, (int)(g_em->bitmap), (int)(debug_bitmap));
6174 if (g_em->src_x != debug_src_x ||
6175 g_em->src_y != debug_src_y)
6176 printf(" frame %d: %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
6178 g_em->src_x, g_em->src_y,
6179 g_em->src_x / 32, g_em->src_y / 32,
6180 debug_src_x, debug_src_y,
6181 debug_src_x / 32, debug_src_y / 32);
6183 num_em_gfx_errors++;
6193 printf("::: [%d errors found]\n", num_em_gfx_errors);
6199 void PlayMenuSound()
6201 int sound = menu.sound[game_status];
6203 if (sound == SND_UNDEFINED)
6206 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
6207 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
6210 if (IS_LOOP_SOUND(sound))
6211 PlaySoundLoop(sound);
6216 void PlayMenuSoundStereo(int sound, int stereo_position)
6218 if (sound == SND_UNDEFINED)
6221 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
6222 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
6225 if (IS_LOOP_SOUND(sound))
6226 PlaySoundExt(sound, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_LOOP);
6228 PlaySoundStereo(sound, stereo_position);
6231 void PlayMenuSoundIfLoop()
6233 int sound = menu.sound[game_status];
6235 if (sound == SND_UNDEFINED)
6238 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
6239 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
6242 if (IS_LOOP_SOUND(sound))
6243 PlaySoundLoop(sound);
6246 void PlayMenuMusic()
6248 int music = menu.music[game_status];
6250 if (music == MUS_UNDEFINED)
6253 if (!setup.sound_music)
6259 void PlaySoundActivating()
6262 PlaySound(SND_MENU_ITEM_ACTIVATING);
6266 void PlaySoundSelecting()
6269 PlaySound(SND_MENU_ITEM_SELECTING);
6273 void ToggleFullscreenIfNeeded()
6275 boolean change_fullscreen = (setup.fullscreen !=
6276 video.fullscreen_enabled);
6277 boolean change_fullscreen_mode = (video.fullscreen_enabled &&
6278 !strEqual(setup.fullscreen_mode,
6279 video.fullscreen_mode_current));
6281 if (!video.fullscreen_available)
6285 if (change_fullscreen || change_fullscreen_mode)
6287 if (setup.fullscreen != video.fullscreen_enabled ||
6288 setup.fullscreen_mode != video.fullscreen_mode_current)
6291 Bitmap *tmp_backbuffer = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
6293 /* save backbuffer content which gets lost when toggling fullscreen mode */
6294 BlitBitmap(backbuffer, tmp_backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
6297 if (change_fullscreen_mode)
6299 if (setup.fullscreen && video.fullscreen_enabled)
6302 /* keep fullscreen, but change fullscreen mode (screen resolution) */
6304 /* (this is now set in sdl.c) */
6306 video.fullscreen_mode_current = setup.fullscreen_mode;
6308 video.fullscreen_enabled = FALSE; /* force new fullscreen mode */
6311 /* toggle fullscreen */
6312 ChangeVideoModeIfNeeded(setup.fullscreen);
6314 setup.fullscreen = video.fullscreen_enabled;
6316 /* restore backbuffer content from temporary backbuffer backup bitmap */
6317 BlitBitmap(tmp_backbuffer, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
6319 FreeBitmap(tmp_backbuffer);
6322 /* update visible window/screen */
6323 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
6325 redraw_mask = REDRAW_ALL;