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