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_MAGIC_WALL_EMPTYING ||
1414 element == EL_BD_MAGIC_WALL_EMPTYING ||
1415 element == EL_AMOEBA_DROPPING)
1416 cut_mode = CUT_ABOVE;
1417 else if (element == EL_QUICKSAND_FILLING ||
1418 element == EL_MAGIC_WALL_FILLING ||
1419 element == EL_BD_MAGIC_WALL_FILLING)
1420 cut_mode = CUT_BELOW;
1422 if (cut_mode == CUT_ABOVE)
1423 DrawScreenElementShifted(x, y, 0, 0, element, NO_CUTTING);
1425 DrawScreenElement(x, y, EL_EMPTY);
1428 DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
1429 else if (cut_mode == NO_CUTTING)
1430 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
1432 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
1434 if (content == EL_ACID)
1436 int dir = MovDir[lx][ly];
1437 int newlx = lx + (dir == MV_LEFT ? -1 : dir == MV_RIGHT ? +1 : 0);
1438 int newly = ly + (dir == MV_UP ? -1 : dir == MV_DOWN ? +1 : 0);
1440 DrawLevelElementThruMask(newlx, newly, EL_ACID);
1443 else if (IS_BLOCKED(lx, ly))
1448 boolean cut_mode = NO_CUTTING;
1449 int element_old, content_old;
1451 Blocked2Moving(lx, ly, &oldx, &oldy);
1454 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
1455 MovDir[oldx][oldy] == MV_RIGHT);
1457 element_old = Feld[oldx][oldy];
1458 content_old = Store[oldx][oldy];
1460 if (element_old == EL_QUICKSAND_EMPTYING ||
1461 element_old == EL_MAGIC_WALL_EMPTYING ||
1462 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
1463 element_old == EL_AMOEBA_DROPPING)
1464 cut_mode = CUT_ABOVE;
1466 DrawScreenElement(x, y, EL_EMPTY);
1469 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
1471 else if (cut_mode == NO_CUTTING)
1472 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
1475 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
1478 else if (IS_DRAWABLE(element))
1479 DrawScreenElement(x, y, element);
1481 DrawScreenElement(x, y, EL_EMPTY);
1484 void DrawLevelField(int x, int y)
1486 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1487 DrawScreenField(SCREENX(x), SCREENY(y));
1488 else if (IS_MOVING(x, y))
1492 Moving2Blocked(x, y, &newx, &newy);
1493 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
1494 DrawScreenField(SCREENX(newx), SCREENY(newy));
1496 else if (IS_BLOCKED(x, y))
1500 Blocked2Moving(x, y, &oldx, &oldy);
1501 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
1502 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
1506 void DrawMiniElement(int x, int y, int element)
1510 graphic = el2edimg(element);
1511 DrawMiniGraphic(x, y, graphic);
1514 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
1516 int x = sx + scroll_x, y = sy + scroll_y;
1518 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
1519 DrawMiniElement(sx, sy, EL_EMPTY);
1520 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
1521 DrawMiniElement(sx, sy, Feld[x][y]);
1523 DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
1526 void DrawEnvelopeBackground(int envelope_nr, int startx, int starty,
1527 int x, int y, int xsize, int ysize, int font_nr)
1529 int font_width = getFontWidth(font_nr);
1530 int font_height = getFontHeight(font_nr);
1531 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1534 int dst_x = SX + startx + x * font_width;
1535 int dst_y = SY + starty + y * font_height;
1536 int width = graphic_info[graphic].width;
1537 int height = graphic_info[graphic].height;
1538 int inner_width = MAX(width - 2 * font_width, font_width);
1539 int inner_height = MAX(height - 2 * font_height, font_height);
1540 int inner_sx = (width >= 3 * font_width ? font_width : 0);
1541 int inner_sy = (height >= 3 * font_height ? font_height : 0);
1542 boolean draw_masked = graphic_info[graphic].draw_masked;
1544 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1546 if (src_bitmap == NULL || width < font_width || height < font_height)
1548 ClearRectangle(drawto, dst_x, dst_y, font_width, font_height);
1552 src_x += (x == 0 ? 0 : x == xsize - 1 ? width - font_width :
1553 inner_sx + (x - 1) * font_width % inner_width);
1554 src_y += (y == 0 ? 0 : y == ysize - 1 ? height - font_height :
1555 inner_sy + (y - 1) * font_height % inner_height);
1559 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1560 dst_x - src_x, dst_y - src_y);
1561 BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1565 BlitBitmap(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1569 void AnimateEnvelope(int envelope_nr, int anim_mode, int action)
1571 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1572 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1573 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
1574 boolean ffwd_delay = (tape.playing && tape.fast_forward);
1575 boolean no_delay = (tape.warp_forward);
1576 unsigned long anim_delay = 0;
1577 int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
1578 int anim_delay_value = (no_delay ? 0 : frame_delay_value);
1579 int font_nr = FONT_ENVELOPE_1 + envelope_nr;
1580 int font_width = getFontWidth(font_nr);
1581 int font_height = getFontHeight(font_nr);
1582 int max_xsize = level.envelope[envelope_nr].xsize;
1583 int max_ysize = level.envelope[envelope_nr].ysize;
1584 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
1585 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
1586 int xend = max_xsize;
1587 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
1588 int xstep = (xstart < xend ? 1 : 0);
1589 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
1592 for (x = xstart, y = ystart; x <= xend && y <= yend; x += xstep, y += ystep)
1594 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
1595 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
1596 int sx = (SXSIZE - xsize * font_width) / 2;
1597 int sy = (SYSIZE - ysize * font_height) / 2;
1600 SetDrawtoField(DRAW_BUFFERED);
1602 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
1604 SetDrawtoField(DRAW_BACKBUFFER);
1606 for (yy = 0; yy < ysize; yy++) for (xx = 0; xx < xsize; xx++)
1607 DrawEnvelopeBackground(envelope_nr, sx,sy, xx,yy, xsize, ysize, font_nr);
1609 DrawTextToTextArea(SX + sx + font_width, SY + sy + font_height,
1610 level.envelope[envelope_nr].text, font_nr, max_xsize,
1611 xsize - 2, ysize - 2, mask_mode);
1613 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
1616 WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
1620 void ShowEnvelope(int envelope_nr)
1622 int element = EL_ENVELOPE_1 + envelope_nr;
1623 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1624 int sound_opening = element_info[element].sound[ACTION_OPENING];
1625 int sound_closing = element_info[element].sound[ACTION_CLOSING];
1626 boolean ffwd_delay = (tape.playing && tape.fast_forward);
1627 boolean no_delay = (tape.warp_forward);
1628 int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
1629 int wait_delay_value = (no_delay ? 0 : normal_delay_value);
1630 int anim_mode = graphic_info[graphic].anim_mode;
1631 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
1632 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
1634 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
1636 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
1638 if (anim_mode == ANIM_DEFAULT)
1639 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_OPENING);
1641 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_OPENING);
1644 Delay(wait_delay_value);
1646 WaitForEventToContinue();
1648 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
1650 if (anim_mode != ANIM_NONE)
1651 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_CLOSING);
1653 if (anim_mode == ANIM_DEFAULT)
1654 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_CLOSING);
1656 game.envelope_active = FALSE;
1658 SetDrawtoField(DRAW_BUFFERED);
1660 redraw_mask |= REDRAW_FIELD;
1664 void getPreviewGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y,
1669 int width_mult, width_div;
1670 int height_mult, height_div;
1678 int offset_calc_pos = (tilesize < MICRO_TILESIZE || tilesize > TILESIZE ? 3 :
1679 5 - log_2(tilesize));
1680 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1681 int width_mult = offset_calc[offset_calc_pos].width_mult;
1682 int width_div = offset_calc[offset_calc_pos].width_div;
1683 int height_mult = offset_calc[offset_calc_pos].height_mult;
1684 int height_div = offset_calc[offset_calc_pos].height_div;
1685 int mini_startx = src_bitmap->width * width_mult / width_div;
1686 int mini_starty = src_bitmap->height * height_mult / height_div;
1687 int src_x = mini_startx + graphic_info[graphic].src_x * tilesize / TILESIZE;
1688 int src_y = mini_starty + graphic_info[graphic].src_y * tilesize / TILESIZE;
1690 *bitmap = src_bitmap;
1695 void DrawPreviewElement(int dst_x, int dst_y, int element, int tilesize)
1699 int graphic = el2preimg(element);
1701 getPreviewGraphicSource(graphic, &src_bitmap, &src_x, &src_y, tilesize);
1702 BlitBitmap(src_bitmap, drawto, src_x, src_y, tilesize, tilesize, dst_x,dst_y);
1709 SetDrawBackgroundMask(REDRAW_NONE);
1712 for (x = BX1; x <= BX2; x++)
1713 for (y = BY1; y <= BY2; y++)
1714 DrawScreenField(x, y);
1716 redraw_mask |= REDRAW_FIELD;
1719 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
1723 for (x = 0; x < size_x; x++)
1724 for (y = 0; y < size_y; y++)
1725 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
1727 redraw_mask |= REDRAW_FIELD;
1730 static void DrawPreviewLevelExt(int from_x, int from_y)
1732 boolean show_level_border = (BorderElement != EL_EMPTY);
1733 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
1734 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
1735 int tile_size = preview.tile_size;
1736 int preview_width = preview.xsize * tile_size;
1737 int preview_height = preview.ysize * tile_size;
1738 int real_preview_xsize = MIN(level_xsize, preview.xsize);
1739 int real_preview_ysize = MIN(level_ysize, preview.ysize);
1740 int dst_x = SX + ALIGNED_XPOS(preview.x, preview_width, preview.align);
1741 int dst_y = SY + preview.y;
1744 DrawBackground(dst_x, dst_y, preview_width, preview_height);
1746 dst_x += (preview_width - real_preview_xsize * tile_size) / 2;
1747 dst_y += (preview_height - real_preview_ysize * tile_size) / 2;
1749 for (x = 0; x < real_preview_xsize; x++)
1751 for (y = 0; y < real_preview_ysize; y++)
1753 int lx = from_x + x + (show_level_border ? -1 : 0);
1754 int ly = from_y + y + (show_level_border ? -1 : 0);
1755 int element = (IN_LEV_FIELD(lx, ly) ? level.field[lx][ly] :
1756 getBorderElement(lx, ly));
1758 DrawPreviewElement(dst_x + x * tile_size, dst_y + y * tile_size,
1759 element, tile_size);
1763 redraw_mask |= REDRAW_MICROLEVEL;
1766 #define MICROLABEL_EMPTY 0
1767 #define MICROLABEL_LEVEL_NAME 1
1768 #define MICROLABEL_LEVEL_AUTHOR_HEAD 2
1769 #define MICROLABEL_LEVEL_AUTHOR 3
1770 #define MICROLABEL_IMPORTED_FROM_HEAD 4
1771 #define MICROLABEL_IMPORTED_FROM 5
1772 #define MICROLABEL_IMPORTED_BY_HEAD 6
1773 #define MICROLABEL_IMPORTED_BY 7
1775 static int getMaxTextLength(struct MenuPosInfo *pos, int font_nr)
1777 int max_text_width = SXSIZE;
1778 int font_width = getFontWidth(font_nr);
1780 if (pos->align == ALIGN_CENTER)
1781 max_text_width = (pos->x < SXSIZE / 2 ? pos->x * 2 : (SXSIZE - pos->x) * 2);
1782 else if (pos->align == ALIGN_RIGHT)
1783 max_text_width = pos->x;
1785 max_text_width = SXSIZE - pos->x;
1787 return max_text_width / font_width;
1790 static void DrawPreviewLevelLabelExt(int mode)
1792 struct MenuPosInfo *pos = &menu.main.text.level_info_2;
1793 char label_text[MAX_OUTPUT_LINESIZE + 1];
1794 int max_len_label_text;
1795 int font_nr = FONT_TEXT_2;
1798 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
1799 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
1800 mode == MICROLABEL_IMPORTED_BY_HEAD)
1801 font_nr = FONT_TEXT_3;
1804 max_len_label_text = getMaxTextLength(pos, font_nr);
1806 max_len_label_text = SXSIZE / getFontWidth(font_nr);
1809 for (i = 0; i < max_len_label_text; i++)
1810 label_text[i] = ' ';
1811 label_text[max_len_label_text] = '\0';
1813 if (strlen(label_text) > 0)
1816 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
1818 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
1819 int lypos = MICROLABEL2_YPOS;
1821 DrawText(lxpos, lypos, label_text, font_nr);
1826 (mode == MICROLABEL_LEVEL_NAME ? level.name :
1827 mode == MICROLABEL_LEVEL_AUTHOR_HEAD ? "created by" :
1828 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
1829 mode == MICROLABEL_IMPORTED_FROM_HEAD ? "imported from" :
1830 mode == MICROLABEL_IMPORTED_FROM ? leveldir_current->imported_from :
1831 mode == MICROLABEL_IMPORTED_BY_HEAD ? "imported by" :
1832 mode == MICROLABEL_IMPORTED_BY ? leveldir_current->imported_by :""),
1833 max_len_label_text);
1834 label_text[max_len_label_text] = '\0';
1836 if (strlen(label_text) > 0)
1839 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
1841 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
1842 int lypos = MICROLABEL2_YPOS;
1844 DrawText(lxpos, lypos, label_text, font_nr);
1848 redraw_mask |= REDRAW_MICROLEVEL;
1851 void DrawPreviewLevel(boolean restart)
1853 static unsigned long scroll_delay = 0;
1854 static unsigned long label_delay = 0;
1855 static int from_x, from_y, scroll_direction;
1856 static int label_state, label_counter;
1857 unsigned long scroll_delay_value = preview.step_delay;
1858 boolean show_level_border = (BorderElement != EL_EMPTY);
1859 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
1860 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
1861 int last_game_status = game_status; /* save current game status */
1863 /* force PREVIEW font on preview level */
1864 game_status = GAME_MODE_PSEUDO_PREVIEW;
1871 if (preview.anim_mode == ANIM_CENTERED)
1873 if (level_xsize > preview.xsize)
1874 from_x = (level_xsize - preview.xsize) / 2;
1875 if (level_ysize > preview.ysize)
1876 from_y = (level_ysize - preview.ysize) / 2;
1879 from_x += preview.xoffset;
1880 from_y += preview.yoffset;
1882 scroll_direction = MV_RIGHT;
1886 DrawPreviewLevelExt(from_x, from_y);
1887 DrawPreviewLevelLabelExt(label_state);
1889 /* initialize delay counters */
1890 DelayReached(&scroll_delay, 0);
1891 DelayReached(&label_delay, 0);
1893 if (leveldir_current->name)
1895 struct MenuPosInfo *pos = &menu.main.text.level_info_1;
1896 char label_text[MAX_OUTPUT_LINESIZE + 1];
1897 int font_nr = FONT_TEXT_1;
1899 int max_len_label_text = getMaxTextLength(pos, font_nr);
1901 int max_len_label_text = SXSIZE / getFontWidth(font_nr);
1908 strncpy(label_text, leveldir_current->name, max_len_label_text);
1909 label_text[max_len_label_text] = '\0';
1912 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
1914 lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
1915 lypos = SY + MICROLABEL1_YPOS;
1917 DrawText(lxpos, lypos, label_text, font_nr);
1921 game_status = last_game_status; /* restore current game status */
1926 /* scroll preview level, if needed */
1927 if (preview.anim_mode != ANIM_NONE &&
1928 (level_xsize > preview.xsize || level_ysize > preview.ysize) &&
1929 DelayReached(&scroll_delay, scroll_delay_value))
1931 switch (scroll_direction)
1936 from_x -= preview.step_offset;
1937 from_x = (from_x < 0 ? 0 : from_x);
1940 scroll_direction = MV_UP;
1944 if (from_x < level_xsize - preview.xsize)
1946 from_x += preview.step_offset;
1947 from_x = (from_x > level_xsize - preview.xsize ?
1948 level_xsize - preview.xsize : from_x);
1951 scroll_direction = MV_DOWN;
1957 from_y -= preview.step_offset;
1958 from_y = (from_y < 0 ? 0 : from_y);
1961 scroll_direction = MV_RIGHT;
1965 if (from_y < level_ysize - preview.ysize)
1967 from_y += preview.step_offset;
1968 from_y = (from_y > level_ysize - preview.ysize ?
1969 level_ysize - preview.ysize : from_y);
1972 scroll_direction = MV_LEFT;
1979 DrawPreviewLevelExt(from_x, from_y);
1982 /* !!! THIS ALL SUCKS -- SHOULD BE CLEANLY REWRITTEN !!! */
1983 /* redraw micro level label, if needed */
1984 if (!strEqual(level.name, NAMELESS_LEVEL_NAME) &&
1985 !strEqual(level.author, ANONYMOUS_NAME) &&
1986 !strEqual(level.author, leveldir_current->name) &&
1987 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
1989 int max_label_counter = 23;
1991 if (leveldir_current->imported_from != NULL &&
1992 strlen(leveldir_current->imported_from) > 0)
1993 max_label_counter += 14;
1994 if (leveldir_current->imported_by != NULL &&
1995 strlen(leveldir_current->imported_by) > 0)
1996 max_label_counter += 14;
1998 label_counter = (label_counter + 1) % max_label_counter;
1999 label_state = (label_counter >= 0 && label_counter <= 7 ?
2000 MICROLABEL_LEVEL_NAME :
2001 label_counter >= 9 && label_counter <= 12 ?
2002 MICROLABEL_LEVEL_AUTHOR_HEAD :
2003 label_counter >= 14 && label_counter <= 21 ?
2004 MICROLABEL_LEVEL_AUTHOR :
2005 label_counter >= 23 && label_counter <= 26 ?
2006 MICROLABEL_IMPORTED_FROM_HEAD :
2007 label_counter >= 28 && label_counter <= 35 ?
2008 MICROLABEL_IMPORTED_FROM :
2009 label_counter >= 37 && label_counter <= 40 ?
2010 MICROLABEL_IMPORTED_BY_HEAD :
2011 label_counter >= 42 && label_counter <= 49 ?
2012 MICROLABEL_IMPORTED_BY : MICROLABEL_EMPTY);
2014 if (leveldir_current->imported_from == NULL &&
2015 (label_state == MICROLABEL_IMPORTED_FROM_HEAD ||
2016 label_state == MICROLABEL_IMPORTED_FROM))
2017 label_state = (label_state == MICROLABEL_IMPORTED_FROM_HEAD ?
2018 MICROLABEL_IMPORTED_BY_HEAD : MICROLABEL_IMPORTED_BY);
2020 DrawPreviewLevelLabelExt(label_state);
2023 game_status = last_game_status; /* restore current game status */
2026 inline void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
2027 int graphic, int sync_frame, int mask_mode)
2029 int frame = getGraphicAnimationFrame(graphic, sync_frame);
2031 if (mask_mode == USE_MASKING)
2032 DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
2034 DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
2037 inline void DrawGraphicAnimation(int x, int y, int graphic)
2039 int lx = LEVELX(x), ly = LEVELY(y);
2041 if (!IN_SCR_FIELD(x, y))
2044 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
2045 graphic, GfxFrame[lx][ly], NO_MASKING);
2046 MarkTileDirty(x, y);
2049 void DrawLevelGraphicAnimation(int x, int y, int graphic)
2051 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
2054 void DrawLevelElementAnimation(int x, int y, int element)
2056 int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
2058 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
2061 inline void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
2063 int sx = SCREENX(x), sy = SCREENY(y);
2065 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
2068 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
2071 DrawGraphicAnimation(sx, sy, graphic);
2074 if (GFX_CRUMBLED(TILE_GFX_ELEMENT(x, y)))
2075 DrawLevelFieldCrumbledSand(x, y);
2077 if (GFX_CRUMBLED(Feld[x][y]))
2078 DrawLevelFieldCrumbledSand(x, y);
2082 void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
2084 int sx = SCREENX(x), sy = SCREENY(y);
2087 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
2090 graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
2092 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
2095 DrawGraphicAnimation(sx, sy, graphic);
2097 if (GFX_CRUMBLED(element))
2098 DrawLevelFieldCrumbledSand(x, y);
2101 static int getPlayerGraphic(struct PlayerInfo *player, int move_dir)
2103 if (player->use_murphy)
2105 /* this works only because currently only one player can be "murphy" ... */
2106 static int last_horizontal_dir = MV_LEFT;
2107 int graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir);
2109 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
2110 last_horizontal_dir = move_dir;
2112 if (graphic == IMG_SP_MURPHY) /* undefined => use special graphic */
2114 int direction = (player->is_snapping ? move_dir : last_horizontal_dir);
2116 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
2122 return el_act_dir2img(player->artwork_element, player->GfxAction,move_dir);
2125 static boolean equalGraphics(int graphic1, int graphic2)
2127 struct GraphicInfo *g1 = &graphic_info[graphic1];
2128 struct GraphicInfo *g2 = &graphic_info[graphic2];
2130 return (g1->bitmap == g2->bitmap &&
2131 g1->src_x == g2->src_x &&
2132 g1->src_y == g2->src_y &&
2133 g1->anim_frames == g2->anim_frames &&
2134 g1->anim_delay == g2->anim_delay &&
2135 g1->anim_mode == g2->anim_mode);
2138 void DrawAllPlayers()
2142 for (i = 0; i < MAX_PLAYERS; i++)
2143 if (stored_player[i].active)
2144 DrawPlayer(&stored_player[i]);
2147 void DrawPlayerField(int x, int y)
2149 if (!IS_PLAYER(x, y))
2152 DrawPlayer(PLAYERINFO(x, y));
2155 void DrawPlayer(struct PlayerInfo *player)
2157 int jx = player->jx;
2158 int jy = player->jy;
2159 int move_dir = player->MovDir;
2160 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? +1 : 0);
2161 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? +1 : 0);
2162 int last_jx = (player->is_moving ? jx - dx : jx);
2163 int last_jy = (player->is_moving ? jy - dy : jy);
2164 int next_jx = jx + dx;
2165 int next_jy = jy + dy;
2166 boolean player_is_moving = (player->MovPos ? TRUE : FALSE);
2167 boolean player_is_opaque = FALSE;
2168 int sx = SCREENX(jx), sy = SCREENY(jy);
2169 int sxx = 0, syy = 0;
2170 int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
2172 int action = ACTION_DEFAULT;
2173 int last_player_graphic = getPlayerGraphic(player, move_dir);
2174 int last_player_frame = player->Frame;
2177 /* GfxElement[][] is set to the element the player is digging or collecting;
2178 remove also for off-screen player if the player is not moving anymore */
2179 if (IN_LEV_FIELD(jx, jy) && !player_is_moving)
2180 GfxElement[jx][jy] = EL_UNDEFINED;
2182 if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
2186 if (!IN_LEV_FIELD(jx, jy))
2188 printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
2189 printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
2190 printf("DrawPlayerField(): This should never happen!\n");
2195 if (element == EL_EXPLOSION)
2198 action = (player->is_pushing ? ACTION_PUSHING :
2199 player->is_digging ? ACTION_DIGGING :
2200 player->is_collecting ? ACTION_COLLECTING :
2201 player->is_moving ? ACTION_MOVING :
2202 player->is_snapping ? ACTION_SNAPPING :
2203 player->is_dropping ? ACTION_DROPPING :
2204 player->is_waiting ? player->action_waiting : ACTION_DEFAULT);
2206 if (player->is_waiting)
2207 move_dir = player->dir_waiting;
2209 InitPlayerGfxAnimation(player, action, move_dir);
2211 /* ----------------------------------------------------------------------- */
2212 /* draw things in the field the player is leaving, if needed */
2213 /* ----------------------------------------------------------------------- */
2215 if (player->is_moving)
2217 if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
2219 DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
2221 if (last_element == EL_DYNAMITE_ACTIVE ||
2222 last_element == EL_EM_DYNAMITE_ACTIVE ||
2223 last_element == EL_SP_DISK_RED_ACTIVE)
2224 DrawDynamite(last_jx, last_jy);
2226 DrawLevelFieldThruMask(last_jx, last_jy);
2228 else if (last_element == EL_DYNAMITE_ACTIVE ||
2229 last_element == EL_EM_DYNAMITE_ACTIVE ||
2230 last_element == EL_SP_DISK_RED_ACTIVE)
2231 DrawDynamite(last_jx, last_jy);
2233 /* !!! this is not enough to prevent flickering of players which are
2234 moving next to each others without a free tile between them -- this
2235 can only be solved by drawing all players layer by layer (first the
2236 background, then the foreground etc.) !!! => TODO */
2237 else if (!IS_PLAYER(last_jx, last_jy))
2238 DrawLevelField(last_jx, last_jy);
2241 DrawLevelField(last_jx, last_jy);
2244 if (player->is_pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
2245 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
2248 if (!IN_SCR_FIELD(sx, sy))
2251 if (setup.direct_draw)
2252 SetDrawtoField(DRAW_BUFFERED);
2254 /* ----------------------------------------------------------------------- */
2255 /* draw things behind the player, if needed */
2256 /* ----------------------------------------------------------------------- */
2259 DrawLevelElement(jx, jy, Back[jx][jy]);
2260 else if (IS_ACTIVE_BOMB(element))
2261 DrawLevelElement(jx, jy, EL_EMPTY);
2264 if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
2266 int old_element = GfxElement[jx][jy];
2267 int old_graphic = el_act_dir2img(old_element, action, move_dir);
2268 int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
2270 if (GFX_CRUMBLED(old_element))
2271 DrawLevelFieldCrumbledSandDigging(jx, jy, move_dir, player->StepFrame);
2273 DrawGraphic(sx, sy, old_graphic, frame);
2275 if (graphic_info[old_graphic].anim_mode & ANIM_OPAQUE_PLAYER)
2276 player_is_opaque = TRUE;
2280 GfxElement[jx][jy] = EL_UNDEFINED;
2282 /* make sure that pushed elements are drawn with correct frame rate */
2284 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
2286 if (player->is_pushing && player->is_moving && !IS_ANIM_MODE_CE(graphic))
2287 GfxFrame[jx][jy] = player->StepFrame;
2289 if (player->is_pushing && player->is_moving)
2290 GfxFrame[jx][jy] = player->StepFrame;
2293 DrawLevelField(jx, jy);
2297 /* ----------------------------------------------------------------------- */
2298 /* draw player himself */
2299 /* ----------------------------------------------------------------------- */
2301 graphic = getPlayerGraphic(player, move_dir);
2303 /* in the case of changed player action or direction, prevent the current
2304 animation frame from being restarted for identical animations */
2305 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
2306 player->Frame = last_player_frame;
2308 frame = getGraphicAnimationFrame(graphic, player->Frame);
2312 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
2313 sxx = player->GfxPos;
2315 syy = player->GfxPos;
2318 if (!setup.soft_scrolling && ScreenMovPos)
2321 if (player_is_opaque)
2322 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
2324 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
2326 if (SHIELD_ON(player))
2328 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
2329 IMG_SHIELD_NORMAL_ACTIVE);
2330 int frame = getGraphicAnimationFrame(graphic, -1);
2332 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
2335 /* ----------------------------------------------------------------------- */
2336 /* draw things the player is pushing, if needed */
2337 /* ----------------------------------------------------------------------- */
2340 printf("::: %d, %d [%d, %d] [%d]\n",
2341 player->is_pushing, player_is_moving, player->GfxAction,
2342 player->is_moving, player_is_moving);
2346 if (player->is_pushing && player->is_moving)
2348 int px = SCREENX(jx), py = SCREENY(jy);
2349 int pxx = (TILEX - ABS(sxx)) * dx;
2350 int pyy = (TILEY - ABS(syy)) * dy;
2351 int gfx_frame = GfxFrame[jx][jy];
2357 if (!IS_MOVING(jx, jy)) /* push movement already finished */
2359 element = Feld[next_jx][next_jy];
2360 gfx_frame = GfxFrame[next_jx][next_jy];
2363 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
2366 sync_frame = (IS_ANIM_MODE_CE(graphic) ? gfx_frame : player->StepFrame);
2367 frame = getGraphicAnimationFrame(graphic, sync_frame);
2369 frame = getGraphicAnimationFrame(graphic, player->StepFrame);
2372 /* draw background element under pushed element (like the Sokoban field) */
2373 if (Back[next_jx][next_jy])
2374 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
2376 /* masked drawing is needed for EMC style (double) movement graphics */
2377 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
2381 /* ----------------------------------------------------------------------- */
2382 /* draw things in front of player (active dynamite or dynabombs) */
2383 /* ----------------------------------------------------------------------- */
2385 if (IS_ACTIVE_BOMB(element))
2387 graphic = el2img(element);
2388 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
2390 if (game.emulation == EMU_SUPAPLEX)
2391 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
2393 DrawGraphicThruMask(sx, sy, graphic, frame);
2396 if (player_is_moving && last_element == EL_EXPLOSION)
2398 int element = (GfxElement[last_jx][last_jy] != EL_UNDEFINED ?
2399 GfxElement[last_jx][last_jy] : EL_EMPTY);
2400 int graphic = el_act2img(element, ACTION_EXPLODING);
2401 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
2402 int phase = ExplodePhase[last_jx][last_jy] - 1;
2403 int frame = getGraphicAnimationFrame(graphic, phase - delay);
2406 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
2409 /* ----------------------------------------------------------------------- */
2410 /* draw elements the player is just walking/passing through/under */
2411 /* ----------------------------------------------------------------------- */
2413 if (player_is_moving)
2415 /* handle the field the player is leaving ... */
2416 if (IS_ACCESSIBLE_INSIDE(last_element))
2417 DrawLevelField(last_jx, last_jy);
2418 else if (IS_ACCESSIBLE_UNDER(last_element))
2419 DrawLevelFieldThruMask(last_jx, last_jy);
2422 /* do not redraw accessible elements if the player is just pushing them */
2423 if (!player_is_moving || !player->is_pushing)
2425 /* ... and the field the player is entering */
2426 if (IS_ACCESSIBLE_INSIDE(element))
2427 DrawLevelField(jx, jy);
2428 else if (IS_ACCESSIBLE_UNDER(element))
2429 DrawLevelFieldThruMask(jx, jy);
2432 if (setup.direct_draw)
2434 int dst_x = SX + SCREENX(MIN(jx, last_jx)) * TILEX;
2435 int dst_y = SY + SCREENY(MIN(jy, last_jy)) * TILEY;
2436 int x_size = TILEX * (1 + ABS(jx - last_jx));
2437 int y_size = TILEY * (1 + ABS(jy - last_jy));
2439 BlitBitmap(drawto_field, window,
2440 dst_x, dst_y, x_size, y_size, dst_x, dst_y);
2441 SetDrawtoField(DRAW_DIRECT);
2444 MarkTileDirty(sx, sy);
2447 /* ------------------------------------------------------------------------- */
2449 void WaitForEventToContinue()
2451 boolean still_wait = TRUE;
2453 /* simulate releasing mouse button over last gadget, if still pressed */
2455 HandleGadgets(-1, -1, 0);
2457 button_status = MB_RELEASED;
2473 case EVENT_BUTTONPRESS:
2474 case EVENT_KEYPRESS:
2478 case EVENT_KEYRELEASE:
2479 ClearPlayerAction();
2483 HandleOtherEvents(&event);
2487 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2494 /* don't eat all CPU time */
2499 #define MAX_REQUEST_LINES 13
2500 #define MAX_REQUEST_LINE_FONT1_LEN 7
2501 #define MAX_REQUEST_LINE_FONT2_LEN 10
2503 boolean Request(char *text, unsigned int req_state)
2505 int mx, my, ty, result = -1;
2506 unsigned int old_door_state;
2507 int last_game_status = game_status; /* save current game status */
2508 int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
2509 int font_nr = FONT_TEXT_2;
2510 int max_word_len = 0;
2513 for (text_ptr = text; *text_ptr; text_ptr++)
2515 max_word_len = (*text_ptr != ' ' ? max_word_len + 1 : 0);
2517 if (max_word_len > MAX_REQUEST_LINE_FONT1_LEN)
2519 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
2520 font_nr = FONT_LEVEL_NUMBER;
2526 if (game_status == GAME_MODE_PLAYING &&
2527 level.game_engine_type == GAME_ENGINE_TYPE_EM)
2528 BlitScreenToBitmap_EM(backbuffer);
2530 /* disable deactivated drawing when quick-loading level tape recording */
2531 if (tape.playing && tape.deactivate_display)
2532 TapeDeactivateDisplayOff(TRUE);
2534 SetMouseCursor(CURSOR_DEFAULT);
2536 #if defined(NETWORK_AVALIABLE)
2537 /* pause network game while waiting for request to answer */
2538 if (options.network &&
2539 game_status == GAME_MODE_PLAYING &&
2540 req_state & REQUEST_WAIT_FOR_INPUT)
2541 SendToServer_PausePlaying();
2544 old_door_state = GetDoorState();
2546 /* simulate releasing mouse button over last gadget, if still pressed */
2548 HandleGadgets(-1, -1, 0);
2552 if (old_door_state & DOOR_OPEN_1)
2554 CloseDoor(DOOR_CLOSE_1);
2556 /* save old door content */
2557 BlitBitmap(bitmap_db_door, bitmap_db_door,
2558 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
2559 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
2563 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
2566 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2568 /* clear door drawing field */
2569 DrawBackground(DX, DY, DXSIZE, DYSIZE);
2571 /* force DOOR font on preview level */
2572 game_status = GAME_MODE_PSEUDO_DOOR;
2574 /* write text for request */
2575 for (ty = 0; ty < MAX_REQUEST_LINES; ty++)
2577 char text_line[max_request_line_len + 1];
2583 for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
2586 if (!tc || tc == ' ')
2597 strncpy(text_line, text, tl);
2600 DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
2601 DY + 8 + ty * (getFontHeight(font_nr) + 2),
2602 text_line, font_nr);
2604 text += tl + (tc == ' ' ? 1 : 0);
2607 game_status = last_game_status; /* restore current game status */
2609 if (req_state & REQ_ASK)
2611 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
2612 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
2614 else if (req_state & REQ_CONFIRM)
2616 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
2618 else if (req_state & REQ_PLAYER)
2620 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
2621 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
2622 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
2623 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
2626 /* copy request gadgets to door backbuffer */
2627 BlitBitmap(drawto, bitmap_db_door,
2628 DX, DY, DXSIZE, DYSIZE,
2629 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2631 OpenDoor(DOOR_OPEN_1);
2633 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
2635 if (game_status == GAME_MODE_PLAYING)
2637 SetPanelBackground();
2638 SetDrawBackgroundMask(REDRAW_DOOR_1);
2642 SetDrawBackgroundMask(REDRAW_FIELD);
2648 if (game_status != GAME_MODE_MAIN)
2651 button_status = MB_RELEASED;
2653 request_gadget_id = -1;
2655 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2667 case EVENT_BUTTONPRESS:
2668 case EVENT_BUTTONRELEASE:
2669 case EVENT_MOTIONNOTIFY:
2671 if (event.type == EVENT_MOTIONNOTIFY)
2673 if (!PointerInWindow(window))
2674 continue; /* window and pointer are on different screens */
2679 motion_status = TRUE;
2680 mx = ((MotionEvent *) &event)->x;
2681 my = ((MotionEvent *) &event)->y;
2685 motion_status = FALSE;
2686 mx = ((ButtonEvent *) &event)->x;
2687 my = ((ButtonEvent *) &event)->y;
2688 if (event.type == EVENT_BUTTONPRESS)
2689 button_status = ((ButtonEvent *) &event)->button;
2691 button_status = MB_RELEASED;
2694 /* this sets 'request_gadget_id' */
2695 HandleGadgets(mx, my, button_status);
2697 switch (request_gadget_id)
2699 case TOOL_CTRL_ID_YES:
2702 case TOOL_CTRL_ID_NO:
2705 case TOOL_CTRL_ID_CONFIRM:
2706 result = TRUE | FALSE;
2709 case TOOL_CTRL_ID_PLAYER_1:
2712 case TOOL_CTRL_ID_PLAYER_2:
2715 case TOOL_CTRL_ID_PLAYER_3:
2718 case TOOL_CTRL_ID_PLAYER_4:
2729 case EVENT_KEYPRESS:
2730 switch (GetEventKey((KeyEvent *)&event, TRUE))
2743 if (req_state & REQ_PLAYER)
2747 case EVENT_KEYRELEASE:
2748 ClearPlayerAction();
2752 HandleOtherEvents(&event);
2756 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2758 int joy = AnyJoystick();
2760 if (joy & JOY_BUTTON_1)
2762 else if (joy & JOY_BUTTON_2)
2769 if (!PendingEvent()) /* delay only if no pending events */
2772 /* don't eat all CPU time */
2777 if (game_status != GAME_MODE_MAIN)
2782 if (!(req_state & REQ_STAY_OPEN))
2784 CloseDoor(DOOR_CLOSE_1);
2786 if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
2787 (req_state & REQ_REOPEN))
2788 OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
2793 if (game_status == GAME_MODE_PLAYING)
2795 SetPanelBackground();
2796 SetDrawBackgroundMask(REDRAW_DOOR_1);
2800 SetDrawBackgroundMask(REDRAW_FIELD);
2803 #if defined(NETWORK_AVALIABLE)
2804 /* continue network game after request */
2805 if (options.network &&
2806 game_status == GAME_MODE_PLAYING &&
2807 req_state & REQUEST_WAIT_FOR_INPUT)
2808 SendToServer_ContinuePlaying();
2811 /* restore deactivated drawing when quick-loading level tape recording */
2812 if (tape.playing && tape.deactivate_display)
2813 TapeDeactivateDisplayOn();
2818 unsigned int OpenDoor(unsigned int door_state)
2820 if (door_state & DOOR_COPY_BACK)
2822 if (door_state & DOOR_OPEN_1)
2823 BlitBitmap(bitmap_db_door, bitmap_db_door,
2824 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
2825 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2827 if (door_state & DOOR_OPEN_2)
2828 BlitBitmap(bitmap_db_door, bitmap_db_door,
2829 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY2, VXSIZE, VYSIZE,
2830 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2832 door_state &= ~DOOR_COPY_BACK;
2835 return MoveDoor(door_state);
2838 unsigned int CloseDoor(unsigned int door_state)
2840 unsigned int old_door_state = GetDoorState();
2842 if (!(door_state & DOOR_NO_COPY_BACK))
2844 if (old_door_state & DOOR_OPEN_1)
2845 BlitBitmap(backbuffer, bitmap_db_door,
2846 DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2848 if (old_door_state & DOOR_OPEN_2)
2849 BlitBitmap(backbuffer, bitmap_db_door,
2850 VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2852 door_state &= ~DOOR_NO_COPY_BACK;
2855 return MoveDoor(door_state);
2858 unsigned int GetDoorState()
2860 return MoveDoor(DOOR_GET_STATE);
2863 unsigned int SetDoorState(unsigned int door_state)
2865 return MoveDoor(door_state | DOOR_SET_STATE);
2868 unsigned int MoveDoor(unsigned int door_state)
2870 static int door1 = DOOR_OPEN_1;
2871 static int door2 = DOOR_CLOSE_2;
2872 unsigned long door_delay = 0;
2873 unsigned long door_delay_value;
2876 if (door_1.width < 0 || door_1.width > DXSIZE)
2877 door_1.width = DXSIZE;
2878 if (door_1.height < 0 || door_1.height > DYSIZE)
2879 door_1.height = DYSIZE;
2880 if (door_2.width < 0 || door_2.width > VXSIZE)
2881 door_2.width = VXSIZE;
2882 if (door_2.height < 0 || door_2.height > VYSIZE)
2883 door_2.height = VYSIZE;
2885 if (door_state == DOOR_GET_STATE)
2886 return (door1 | door2);
2888 if (door_state & DOOR_SET_STATE)
2890 if (door_state & DOOR_ACTION_1)
2891 door1 = door_state & DOOR_ACTION_1;
2892 if (door_state & DOOR_ACTION_2)
2893 door2 = door_state & DOOR_ACTION_2;
2895 return (door1 | door2);
2898 if (!(door_state & DOOR_FORCE_REDRAW))
2900 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
2901 door_state &= ~DOOR_OPEN_1;
2902 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
2903 door_state &= ~DOOR_CLOSE_1;
2904 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
2905 door_state &= ~DOOR_OPEN_2;
2906 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
2907 door_state &= ~DOOR_CLOSE_2;
2910 door_delay_value = (door_state & DOOR_ACTION_1 ? door_1.step_delay :
2913 if (setup.quick_doors)
2915 stepsize = 20; /* must be choosen to always draw last frame */
2916 door_delay_value = 0;
2919 if (global.autoplay_leveldir)
2921 door_state |= DOOR_NO_DELAY;
2922 door_state &= ~DOOR_CLOSE_ALL;
2925 if (door_state & DOOR_ACTION)
2927 boolean handle_door_1 = (door_state & DOOR_ACTION_1);
2928 boolean handle_door_2 = (door_state & DOOR_ACTION_2);
2929 boolean door_1_done = (!handle_door_1);
2930 boolean door_2_done = (!handle_door_2);
2931 boolean door_1_vertical = (door_1.anim_mode & ANIM_VERTICAL);
2932 boolean door_2_vertical = (door_2.anim_mode & ANIM_VERTICAL);
2933 int door_size_1 = (door_1_vertical ? door_1.height : door_1.width);
2934 int door_size_2 = (door_2_vertical ? door_2.height : door_2.width);
2935 int max_door_size_1 = (door_1_vertical ? DYSIZE : DXSIZE);
2936 int max_door_size_2 = (door_2_vertical ? VYSIZE : VXSIZE);
2937 int door_size = (handle_door_1 ? door_size_1 : door_size_2);
2938 int max_door_size = (handle_door_1 ? max_door_size_1 : max_door_size_2);
2939 int door_skip = max_door_size - door_size;
2940 int end = door_size;
2941 int start = ((door_state & DOOR_NO_DELAY) ? end : 0);
2944 if (!(door_state & DOOR_NO_DELAY) && !setup.quick_doors)
2946 /* opening door sound has priority over simultaneously closing door */
2947 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
2948 PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
2949 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
2950 PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
2953 for (k = start; k <= end && !(door_1_done && door_2_done); k += stepsize)
2956 Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2957 GC gc = bitmap->stored_clip_gc;
2959 if (door_state & DOOR_ACTION_1)
2961 int a = MIN(x * door_1.step_offset, end);
2962 int p = (door_state & DOOR_OPEN_1 ? end - a : a);
2963 int i = p + door_skip;
2965 if (door_1.anim_mode & ANIM_STATIC_PANEL)
2967 BlitBitmap(bitmap_db_door, drawto,
2968 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1,
2969 DXSIZE, DYSIZE, DX, DY);
2973 BlitBitmap(bitmap_db_door, drawto,
2974 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + p / 2,
2975 DXSIZE, DYSIZE - p / 2, DX, DY);
2977 ClearRectangle(drawto, DX, DY + DYSIZE - p / 2, DXSIZE, p / 2);
2980 if (door_1.anim_mode & ANIM_HORIZONTAL && x <= DXSIZE)
2982 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
2983 int dst1_x = DX + DXSIZE - i, dst1_y = DY;
2984 int src2_x = DXSIZE - i, src2_y = DOOR_GFX_PAGEY1;
2985 int dst2_x = DX, dst2_y = DY;
2986 int width = i, height = DYSIZE;
2988 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2989 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2992 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2993 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2996 else if (door_1.anim_mode & ANIM_VERTICAL && x <= DYSIZE)
2998 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
2999 int dst1_x = DX, dst1_y = DY + DYSIZE - i;
3000 int src2_x = 0, src2_y = DOOR_GFX_PAGEY1 + DYSIZE - i;
3001 int dst2_x = DX, dst2_y = DY;
3002 int width = DXSIZE, height = i;
3004 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3005 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3008 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3009 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3012 else if (x <= DXSIZE) /* ANIM_DEFAULT */
3014 int j = (door_1.anim_mode == ANIM_DEFAULT ? (DXSIZE - i) / 3 : 0);
3016 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
3017 BlitBitmapMasked(bitmap, drawto,
3018 DXSIZE, DOOR_GFX_PAGEY1, i, 77,
3019 DX + DXSIZE - i, DY + j);
3020 BlitBitmapMasked(bitmap, drawto,
3021 DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
3022 DX + DXSIZE - i, DY + 140 + j);
3023 SetClipOrigin(bitmap, gc, DX - DXSIZE + i,
3024 DY - (DOOR_GFX_PAGEY1 + j));
3025 BlitBitmapMasked(bitmap, drawto,
3026 DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
3028 BlitBitmapMasked(bitmap, drawto,
3029 DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
3032 BlitBitmapMasked(bitmap, drawto,
3033 DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
3035 BlitBitmapMasked(bitmap, drawto,
3036 DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
3038 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
3039 BlitBitmapMasked(bitmap, drawto,
3040 DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
3041 DX + DXSIZE - i, DY + 77 + j);
3042 BlitBitmapMasked(bitmap, drawto,
3043 DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
3044 DX + DXSIZE - i, DY + 203 + j);
3047 redraw_mask |= REDRAW_DOOR_1;
3048 door_1_done = (a == end);
3051 if (door_state & DOOR_ACTION_2)
3053 int a = MIN(x * door_2.step_offset, door_size);
3054 int p = (door_state & DOOR_OPEN_2 ? door_size - a : a);
3055 int i = p + door_skip;
3057 if (door_2.anim_mode & ANIM_STATIC_PANEL)
3059 BlitBitmap(bitmap_db_door, drawto,
3060 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2,
3061 VXSIZE, VYSIZE, VX, VY);
3063 else if (x <= VYSIZE)
3065 BlitBitmap(bitmap_db_door, drawto,
3066 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + p / 2,
3067 VXSIZE, VYSIZE - p / 2, VX, VY);
3069 ClearRectangle(drawto, VX, VY + VYSIZE - p / 2, VXSIZE, p / 2);
3072 if (door_2.anim_mode & ANIM_HORIZONTAL && x <= VXSIZE)
3074 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
3075 int dst1_x = VX + VXSIZE - i, dst1_y = VY;
3076 int src2_x = VXSIZE - i, src2_y = DOOR_GFX_PAGEY2;
3077 int dst2_x = VX, dst2_y = VY;
3078 int width = i, height = VYSIZE;
3080 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3081 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3084 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3085 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3088 else if (door_2.anim_mode & ANIM_VERTICAL && x <= VYSIZE)
3090 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
3091 int dst1_x = VX, dst1_y = VY + VYSIZE - i;
3092 int src2_x = 0, src2_y = DOOR_GFX_PAGEY2 + VYSIZE - i;
3093 int dst2_x = VX, dst2_y = VY;
3094 int width = VXSIZE, height = i;
3096 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3097 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3100 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3101 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3104 else if (x <= VXSIZE) /* ANIM_DEFAULT */
3106 int j = (door_2.anim_mode == ANIM_DEFAULT ? (VXSIZE - i) / 3 : 0);
3108 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
3109 BlitBitmapMasked(bitmap, drawto,
3110 VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
3111 VX + VXSIZE - i, VY + j);
3112 SetClipOrigin(bitmap, gc,
3113 VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
3114 BlitBitmapMasked(bitmap, drawto,
3115 VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
3118 BlitBitmapMasked(bitmap, drawto,
3119 VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
3120 i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
3121 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
3122 BlitBitmapMasked(bitmap, drawto,
3123 VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
3125 VX + VXSIZE - i, VY + VYSIZE / 2 + j);
3128 redraw_mask |= REDRAW_DOOR_2;
3129 door_2_done = (a == VXSIZE);
3132 if (!(door_state & DOOR_NO_DELAY))
3136 if (game_status == GAME_MODE_MAIN)
3139 WaitUntilDelayReached(&door_delay, door_delay_value);
3144 if (door_state & DOOR_ACTION_1)
3145 door1 = door_state & DOOR_ACTION_1;
3146 if (door_state & DOOR_ACTION_2)
3147 door2 = door_state & DOOR_ACTION_2;
3149 return (door1 | door2);
3152 void DrawSpecialEditorDoor()
3154 /* draw bigger toolbox window */
3155 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
3156 DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
3158 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
3159 EX - 6, VY - 4, EXSIZE + 12, EYSIZE - VYSIZE + 4,
3162 redraw_mask |= REDRAW_ALL;
3165 void UndrawSpecialEditorDoor()
3167 /* draw normal tape recorder window */
3168 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
3169 EX - 6, EY - 12, EXSIZE + 12, EYSIZE - VYSIZE + 12,
3172 redraw_mask |= REDRAW_ALL;
3176 /* ---------- new tool button stuff ---------------------------------------- */
3178 /* graphic position values for tool buttons */
3179 #define TOOL_BUTTON_YES_XPOS 2
3180 #define TOOL_BUTTON_YES_YPOS 250
3181 #define TOOL_BUTTON_YES_GFX_YPOS 0
3182 #define TOOL_BUTTON_YES_XSIZE 46
3183 #define TOOL_BUTTON_YES_YSIZE 28
3184 #define TOOL_BUTTON_NO_XPOS 52
3185 #define TOOL_BUTTON_NO_YPOS TOOL_BUTTON_YES_YPOS
3186 #define TOOL_BUTTON_NO_GFX_YPOS TOOL_BUTTON_YES_GFX_YPOS
3187 #define TOOL_BUTTON_NO_XSIZE TOOL_BUTTON_YES_XSIZE
3188 #define TOOL_BUTTON_NO_YSIZE TOOL_BUTTON_YES_YSIZE
3189 #define TOOL_BUTTON_CONFIRM_XPOS TOOL_BUTTON_YES_XPOS
3190 #define TOOL_BUTTON_CONFIRM_YPOS TOOL_BUTTON_YES_YPOS
3191 #define TOOL_BUTTON_CONFIRM_GFX_YPOS 30
3192 #define TOOL_BUTTON_CONFIRM_XSIZE 96
3193 #define TOOL_BUTTON_CONFIRM_YSIZE TOOL_BUTTON_YES_YSIZE
3194 #define TOOL_BUTTON_PLAYER_XSIZE 30
3195 #define TOOL_BUTTON_PLAYER_YSIZE 30
3196 #define TOOL_BUTTON_PLAYER_GFX_XPOS 5
3197 #define TOOL_BUTTON_PLAYER_GFX_YPOS 185
3198 #define TOOL_BUTTON_PLAYER_XPOS (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
3199 #define TOOL_BUTTON_PLAYER_YPOS (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
3200 #define TOOL_BUTTON_PLAYER1_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3201 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
3202 #define TOOL_BUTTON_PLAYER2_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3203 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
3204 #define TOOL_BUTTON_PLAYER3_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3205 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
3206 #define TOOL_BUTTON_PLAYER4_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3207 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
3208 #define TOOL_BUTTON_PLAYER1_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3209 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
3210 #define TOOL_BUTTON_PLAYER2_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3211 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
3212 #define TOOL_BUTTON_PLAYER3_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3213 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
3214 #define TOOL_BUTTON_PLAYER4_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3215 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
3224 } toolbutton_info[NUM_TOOL_BUTTONS] =
3227 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_GFX_YPOS,
3228 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_YPOS,
3229 TOOL_BUTTON_YES_XSIZE, TOOL_BUTTON_YES_YSIZE,
3234 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_GFX_YPOS,
3235 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_YPOS,
3236 TOOL_BUTTON_NO_XSIZE, TOOL_BUTTON_NO_YSIZE,
3241 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_GFX_YPOS,
3242 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_YPOS,
3243 TOOL_BUTTON_CONFIRM_XSIZE, TOOL_BUTTON_CONFIRM_YSIZE,
3244 TOOL_CTRL_ID_CONFIRM,
3248 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3249 TOOL_BUTTON_PLAYER1_XPOS, TOOL_BUTTON_PLAYER1_YPOS,
3250 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3251 TOOL_CTRL_ID_PLAYER_1,
3255 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3256 TOOL_BUTTON_PLAYER2_XPOS, TOOL_BUTTON_PLAYER2_YPOS,
3257 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3258 TOOL_CTRL_ID_PLAYER_2,
3262 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3263 TOOL_BUTTON_PLAYER3_XPOS, TOOL_BUTTON_PLAYER3_YPOS,
3264 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3265 TOOL_CTRL_ID_PLAYER_3,
3269 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3270 TOOL_BUTTON_PLAYER4_XPOS, TOOL_BUTTON_PLAYER4_YPOS,
3271 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3272 TOOL_CTRL_ID_PLAYER_4,
3277 void CreateToolButtons()
3281 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3283 Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
3284 Bitmap *deco_bitmap = None;
3285 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
3286 struct GadgetInfo *gi;
3287 unsigned long event_mask;
3288 int gd_xoffset, gd_yoffset;
3289 int gd_x1, gd_x2, gd_y;
3292 event_mask = GD_EVENT_RELEASED;
3294 gd_xoffset = toolbutton_info[i].xpos;
3295 gd_yoffset = toolbutton_info[i].ypos;
3296 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
3297 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
3298 gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
3300 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
3302 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
3304 getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr),
3305 &deco_bitmap, &deco_x, &deco_y);
3306 deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
3307 deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
3310 gi = CreateGadget(GDI_CUSTOM_ID, id,
3311 GDI_INFO_TEXT, toolbutton_info[i].infotext,
3312 GDI_X, DX + toolbutton_info[i].x,
3313 GDI_Y, DY + toolbutton_info[i].y,
3314 GDI_WIDTH, toolbutton_info[i].width,
3315 GDI_HEIGHT, toolbutton_info[i].height,
3316 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
3317 GDI_STATE, GD_BUTTON_UNPRESSED,
3318 GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
3319 GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
3320 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
3321 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
3322 GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
3323 GDI_DECORATION_SHIFTING, 1, 1,
3324 GDI_DIRECT_DRAW, FALSE,
3325 GDI_EVENT_MASK, event_mask,
3326 GDI_CALLBACK_ACTION, HandleToolButtons,
3330 Error(ERR_EXIT, "cannot create gadget");
3332 tool_gadget[id] = gi;
3336 void FreeToolButtons()
3340 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3341 FreeGadget(tool_gadget[i]);
3344 static void UnmapToolButtons()
3348 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3349 UnmapGadget(tool_gadget[i]);
3352 static void HandleToolButtons(struct GadgetInfo *gi)
3354 request_gadget_id = gi->custom_id;
3357 static struct Mapping_EM_to_RND_object
3360 boolean is_rnd_to_em_mapping; /* unique mapping EM <-> RND */
3361 boolean is_backside; /* backside of moving element */
3367 em_object_mapping_list[] =
3370 Xblank, TRUE, FALSE,
3374 Yacid_splash_eB, FALSE, FALSE,
3375 EL_ACID_SPLASH_RIGHT, -1, -1
3378 Yacid_splash_wB, FALSE, FALSE,
3379 EL_ACID_SPLASH_LEFT, -1, -1
3382 #ifdef EM_ENGINE_BAD_ROLL
3384 Xstone_force_e, FALSE, FALSE,
3385 EL_ROCK, -1, MV_BIT_RIGHT
3388 Xstone_force_w, FALSE, FALSE,
3389 EL_ROCK, -1, MV_BIT_LEFT
3392 Xnut_force_e, FALSE, FALSE,
3393 EL_NUT, -1, MV_BIT_RIGHT
3396 Xnut_force_w, FALSE, FALSE,
3397 EL_NUT, -1, MV_BIT_LEFT
3400 Xspring_force_e, FALSE, FALSE,
3401 EL_SPRING, -1, MV_BIT_RIGHT
3404 Xspring_force_w, FALSE, FALSE,
3405 EL_SPRING, -1, MV_BIT_LEFT
3408 Xemerald_force_e, FALSE, FALSE,
3409 EL_EMERALD, -1, MV_BIT_RIGHT
3412 Xemerald_force_w, FALSE, FALSE,
3413 EL_EMERALD, -1, MV_BIT_LEFT
3416 Xdiamond_force_e, FALSE, FALSE,
3417 EL_DIAMOND, -1, MV_BIT_RIGHT
3420 Xdiamond_force_w, FALSE, FALSE,
3421 EL_DIAMOND, -1, MV_BIT_LEFT
3424 Xbomb_force_e, FALSE, FALSE,
3425 EL_BOMB, -1, MV_BIT_RIGHT
3428 Xbomb_force_w, FALSE, FALSE,
3429 EL_BOMB, -1, MV_BIT_LEFT
3431 #endif /* EM_ENGINE_BAD_ROLL */
3434 Xstone, TRUE, FALSE,
3438 Xstone_pause, FALSE, FALSE,
3442 Xstone_fall, FALSE, FALSE,
3446 Ystone_s, FALSE, FALSE,
3447 EL_ROCK, ACTION_FALLING, -1
3450 Ystone_sB, FALSE, TRUE,
3451 EL_ROCK, ACTION_FALLING, -1
3454 Ystone_e, FALSE, FALSE,
3455 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
3458 Ystone_eB, FALSE, TRUE,
3459 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
3462 Ystone_w, FALSE, FALSE,
3463 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
3466 Ystone_wB, FALSE, TRUE,
3467 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
3474 Xnut_pause, FALSE, FALSE,
3478 Xnut_fall, FALSE, FALSE,
3482 Ynut_s, FALSE, FALSE,
3483 EL_NUT, ACTION_FALLING, -1
3486 Ynut_sB, FALSE, TRUE,
3487 EL_NUT, ACTION_FALLING, -1
3490 Ynut_e, FALSE, FALSE,
3491 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
3494 Ynut_eB, FALSE, TRUE,
3495 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
3498 Ynut_w, FALSE, FALSE,
3499 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
3502 Ynut_wB, FALSE, TRUE,
3503 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
3506 Xbug_n, TRUE, FALSE,
3510 Xbug_e, TRUE, FALSE,
3511 EL_BUG_RIGHT, -1, -1
3514 Xbug_s, TRUE, FALSE,
3518 Xbug_w, TRUE, FALSE,
3522 Xbug_gon, FALSE, FALSE,
3526 Xbug_goe, FALSE, FALSE,
3527 EL_BUG_RIGHT, -1, -1
3530 Xbug_gos, FALSE, FALSE,
3534 Xbug_gow, FALSE, FALSE,
3538 Ybug_n, FALSE, FALSE,
3539 EL_BUG, ACTION_MOVING, MV_BIT_UP
3542 Ybug_nB, FALSE, TRUE,
3543 EL_BUG, ACTION_MOVING, MV_BIT_UP
3546 Ybug_e, FALSE, FALSE,
3547 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
3550 Ybug_eB, FALSE, TRUE,
3551 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
3554 Ybug_s, FALSE, FALSE,
3555 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
3558 Ybug_sB, FALSE, TRUE,
3559 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
3562 Ybug_w, FALSE, FALSE,
3563 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
3566 Ybug_wB, FALSE, TRUE,
3567 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
3570 Ybug_w_n, FALSE, FALSE,
3571 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
3574 Ybug_n_e, FALSE, FALSE,
3575 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
3578 Ybug_e_s, FALSE, FALSE,
3579 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
3582 Ybug_s_w, FALSE, FALSE,
3583 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
3586 Ybug_e_n, FALSE, FALSE,
3587 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
3590 Ybug_s_e, FALSE, FALSE,
3591 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
3594 Ybug_w_s, FALSE, FALSE,
3595 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
3598 Ybug_n_w, FALSE, FALSE,
3599 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
3602 Ybug_stone, FALSE, FALSE,
3603 EL_BUG, ACTION_SMASHED_BY_ROCK, -1
3606 Ybug_spring, FALSE, FALSE,
3607 EL_BUG, ACTION_SMASHED_BY_SPRING, -1
3610 Xtank_n, TRUE, FALSE,
3611 EL_SPACESHIP_UP, -1, -1
3614 Xtank_e, TRUE, FALSE,
3615 EL_SPACESHIP_RIGHT, -1, -1
3618 Xtank_s, TRUE, FALSE,
3619 EL_SPACESHIP_DOWN, -1, -1
3622 Xtank_w, TRUE, FALSE,
3623 EL_SPACESHIP_LEFT, -1, -1
3626 Xtank_gon, FALSE, FALSE,
3627 EL_SPACESHIP_UP, -1, -1
3630 Xtank_goe, FALSE, FALSE,
3631 EL_SPACESHIP_RIGHT, -1, -1
3634 Xtank_gos, FALSE, FALSE,
3635 EL_SPACESHIP_DOWN, -1, -1
3638 Xtank_gow, FALSE, FALSE,
3639 EL_SPACESHIP_LEFT, -1, -1
3642 Ytank_n, FALSE, FALSE,
3643 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
3646 Ytank_nB, FALSE, TRUE,
3647 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
3650 Ytank_e, FALSE, FALSE,
3651 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
3654 Ytank_eB, FALSE, TRUE,
3655 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
3658 Ytank_s, FALSE, FALSE,
3659 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
3662 Ytank_sB, FALSE, TRUE,
3663 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
3666 Ytank_w, FALSE, FALSE,
3667 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
3670 Ytank_wB, FALSE, TRUE,
3671 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
3674 Ytank_w_n, FALSE, FALSE,
3675 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
3678 Ytank_n_e, FALSE, FALSE,
3679 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
3682 Ytank_e_s, FALSE, FALSE,
3683 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
3686 Ytank_s_w, FALSE, FALSE,
3687 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
3690 Ytank_e_n, FALSE, FALSE,
3691 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
3694 Ytank_s_e, FALSE, FALSE,
3695 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
3698 Ytank_w_s, FALSE, FALSE,
3699 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
3702 Ytank_n_w, FALSE, FALSE,
3703 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
3706 Ytank_stone, FALSE, FALSE,
3707 EL_SPACESHIP, ACTION_SMASHED_BY_ROCK, -1
3710 Ytank_spring, FALSE, FALSE,
3711 EL_SPACESHIP, ACTION_SMASHED_BY_SPRING, -1
3714 Xandroid, TRUE, FALSE,
3715 EL_EMC_ANDROID, ACTION_ACTIVE, -1
3718 Xandroid_1_n, FALSE, FALSE,
3719 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
3722 Xandroid_2_n, FALSE, FALSE,
3723 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
3726 Xandroid_1_e, FALSE, FALSE,
3727 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
3730 Xandroid_2_e, FALSE, FALSE,
3731 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
3734 Xandroid_1_w, FALSE, FALSE,
3735 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
3738 Xandroid_2_w, FALSE, FALSE,
3739 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
3742 Xandroid_1_s, FALSE, FALSE,
3743 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
3746 Xandroid_2_s, FALSE, FALSE,
3747 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
3750 Yandroid_n, FALSE, FALSE,
3751 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
3754 Yandroid_nB, FALSE, TRUE,
3755 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
3758 Yandroid_ne, FALSE, FALSE,
3759 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPRIGHT
3762 Yandroid_neB, FALSE, TRUE,
3763 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPRIGHT
3766 Yandroid_e, FALSE, FALSE,
3767 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
3770 Yandroid_eB, FALSE, TRUE,
3771 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
3774 Yandroid_se, FALSE, FALSE,
3775 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNRIGHT
3778 Yandroid_seB, FALSE, TRUE,
3779 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNRIGHT
3782 Yandroid_s, FALSE, FALSE,
3783 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
3786 Yandroid_sB, FALSE, TRUE,
3787 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
3790 Yandroid_sw, FALSE, FALSE,
3791 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNLEFT
3794 Yandroid_swB, FALSE, TRUE,
3795 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNLEFT
3798 Yandroid_w, FALSE, FALSE,
3799 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
3802 Yandroid_wB, FALSE, TRUE,
3803 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
3806 Yandroid_nw, FALSE, FALSE,
3807 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPLEFT
3810 Yandroid_nwB, FALSE, TRUE,
3811 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPLEFT
3814 Xspring, TRUE, FALSE,
3818 Xspring_pause, FALSE, FALSE,
3822 Xspring_e, FALSE, FALSE,
3826 Xspring_w, FALSE, FALSE,
3830 Xspring_fall, FALSE, FALSE,
3834 Yspring_s, FALSE, FALSE,
3835 EL_SPRING, ACTION_FALLING, -1
3838 Yspring_sB, FALSE, TRUE,
3839 EL_SPRING, ACTION_FALLING, -1
3842 Yspring_e, FALSE, FALSE,
3843 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
3846 Yspring_eB, FALSE, TRUE,
3847 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
3850 Yspring_w, FALSE, FALSE,
3851 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
3854 Yspring_wB, FALSE, TRUE,
3855 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
3858 Yspring_kill_e, FALSE, FALSE,
3859 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
3862 Yspring_kill_eB, FALSE, TRUE,
3863 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
3866 Yspring_kill_w, FALSE, FALSE,
3867 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
3870 Yspring_kill_wB, FALSE, TRUE,
3871 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
3874 Xeater_n, TRUE, FALSE,
3875 EL_YAMYAM_UP, -1, -1
3878 Xeater_e, TRUE, FALSE,
3879 EL_YAMYAM_RIGHT, -1, -1
3882 Xeater_w, TRUE, FALSE,
3883 EL_YAMYAM_LEFT, -1, -1
3886 Xeater_s, TRUE, FALSE,
3887 EL_YAMYAM_DOWN, -1, -1
3890 Yeater_n, FALSE, FALSE,
3891 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
3894 Yeater_nB, FALSE, TRUE,
3895 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
3898 Yeater_e, FALSE, FALSE,
3899 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
3902 Yeater_eB, FALSE, TRUE,
3903 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
3906 Yeater_s, FALSE, FALSE,
3907 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
3910 Yeater_sB, FALSE, TRUE,
3911 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
3914 Yeater_w, FALSE, FALSE,
3915 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
3918 Yeater_wB, FALSE, TRUE,
3919 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
3922 Yeater_stone, FALSE, FALSE,
3923 EL_YAMYAM, ACTION_SMASHED_BY_ROCK, -1
3926 Yeater_spring, FALSE, FALSE,
3927 EL_YAMYAM, ACTION_SMASHED_BY_SPRING, -1
3930 Xalien, TRUE, FALSE,
3934 Xalien_pause, FALSE, FALSE,
3938 Yalien_n, FALSE, FALSE,
3939 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
3942 Yalien_nB, FALSE, TRUE,
3943 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
3946 Yalien_e, FALSE, FALSE,
3947 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
3950 Yalien_eB, FALSE, TRUE,
3951 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
3954 Yalien_s, FALSE, FALSE,
3955 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
3958 Yalien_sB, FALSE, TRUE,
3959 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
3962 Yalien_w, FALSE, FALSE,
3963 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
3966 Yalien_wB, FALSE, TRUE,
3967 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
3970 Yalien_stone, FALSE, FALSE,
3971 EL_ROBOT, ACTION_SMASHED_BY_ROCK, -1
3974 Yalien_spring, FALSE, FALSE,
3975 EL_ROBOT, ACTION_SMASHED_BY_SPRING, -1
3978 Xemerald, TRUE, FALSE,
3982 Xemerald_pause, FALSE, FALSE,
3986 Xemerald_fall, FALSE, FALSE,
3990 Xemerald_shine, FALSE, FALSE,
3991 EL_EMERALD, ACTION_TWINKLING, -1
3994 Yemerald_s, FALSE, FALSE,
3995 EL_EMERALD, ACTION_FALLING, -1
3998 Yemerald_sB, FALSE, TRUE,
3999 EL_EMERALD, ACTION_FALLING, -1
4002 Yemerald_e, FALSE, FALSE,
4003 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
4006 Yemerald_eB, FALSE, TRUE,
4007 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
4010 Yemerald_w, FALSE, FALSE,
4011 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
4014 Yemerald_wB, FALSE, TRUE,
4015 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
4018 Yemerald_eat, FALSE, FALSE,
4019 EL_EMERALD, ACTION_COLLECTING, -1
4022 Yemerald_stone, FALSE, FALSE,
4023 EL_NUT, ACTION_BREAKING, -1
4026 Xdiamond, TRUE, FALSE,
4030 Xdiamond_pause, FALSE, FALSE,
4034 Xdiamond_fall, FALSE, FALSE,
4038 Xdiamond_shine, FALSE, FALSE,
4039 EL_DIAMOND, ACTION_TWINKLING, -1
4042 Ydiamond_s, FALSE, FALSE,
4043 EL_DIAMOND, ACTION_FALLING, -1
4046 Ydiamond_sB, FALSE, TRUE,
4047 EL_DIAMOND, ACTION_FALLING, -1
4050 Ydiamond_e, FALSE, FALSE,
4051 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
4054 Ydiamond_eB, FALSE, TRUE,
4055 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
4058 Ydiamond_w, FALSE, FALSE,
4059 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
4062 Ydiamond_wB, FALSE, TRUE,
4063 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
4066 Ydiamond_eat, FALSE, FALSE,
4067 EL_DIAMOND, ACTION_COLLECTING, -1
4070 Ydiamond_stone, FALSE, FALSE,
4071 EL_DIAMOND, ACTION_SMASHED_BY_ROCK, -1
4074 Xdrip_fall, TRUE, FALSE,
4075 EL_AMOEBA_DROP, -1, -1
4078 Xdrip_stretch, FALSE, FALSE,
4079 EL_AMOEBA_DROP, ACTION_FALLING, -1
4082 Xdrip_stretchB, FALSE, TRUE,
4083 EL_AMOEBA_DROP, ACTION_FALLING, -1
4086 Xdrip_eat, FALSE, FALSE,
4087 EL_AMOEBA_DROP, ACTION_GROWING, -1
4090 Ydrip_s1, FALSE, FALSE,
4091 EL_AMOEBA_DROP, ACTION_FALLING, -1
4094 Ydrip_s1B, FALSE, TRUE,
4095 EL_AMOEBA_DROP, ACTION_FALLING, -1
4098 Ydrip_s2, FALSE, FALSE,
4099 EL_AMOEBA_DROP, ACTION_FALLING, -1
4102 Ydrip_s2B, FALSE, TRUE,
4103 EL_AMOEBA_DROP, ACTION_FALLING, -1
4110 Xbomb_pause, FALSE, FALSE,
4114 Xbomb_fall, FALSE, FALSE,
4118 Ybomb_s, FALSE, FALSE,
4119 EL_BOMB, ACTION_FALLING, -1
4122 Ybomb_sB, FALSE, TRUE,
4123 EL_BOMB, ACTION_FALLING, -1
4126 Ybomb_e, FALSE, FALSE,
4127 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
4130 Ybomb_eB, FALSE, TRUE,
4131 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
4134 Ybomb_w, FALSE, FALSE,
4135 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
4138 Ybomb_wB, FALSE, TRUE,
4139 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
4142 Ybomb_eat, FALSE, FALSE,
4143 EL_BOMB, ACTION_ACTIVATING, -1
4146 Xballoon, TRUE, FALSE,
4150 Yballoon_n, FALSE, FALSE,
4151 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
4154 Yballoon_nB, FALSE, TRUE,
4155 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
4158 Yballoon_e, FALSE, FALSE,
4159 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
4162 Yballoon_eB, FALSE, TRUE,
4163 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
4166 Yballoon_s, FALSE, FALSE,
4167 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
4170 Yballoon_sB, FALSE, TRUE,
4171 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
4174 Yballoon_w, FALSE, FALSE,
4175 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
4178 Yballoon_wB, FALSE, TRUE,
4179 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
4182 Xgrass, TRUE, FALSE,
4183 EL_EMC_GRASS, -1, -1
4186 Ygrass_nB, FALSE, FALSE,
4187 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_UP
4190 Ygrass_eB, FALSE, FALSE,
4191 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_RIGHT
4194 Ygrass_sB, FALSE, FALSE,
4195 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_DOWN
4198 Ygrass_wB, FALSE, FALSE,
4199 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_LEFT
4206 Ydirt_nB, FALSE, FALSE,
4207 EL_SAND, ACTION_DIGGING, MV_BIT_UP
4210 Ydirt_eB, FALSE, FALSE,
4211 EL_SAND, ACTION_DIGGING, MV_BIT_RIGHT
4214 Ydirt_sB, FALSE, FALSE,
4215 EL_SAND, ACTION_DIGGING, MV_BIT_DOWN
4218 Ydirt_wB, FALSE, FALSE,
4219 EL_SAND, ACTION_DIGGING, MV_BIT_LEFT
4222 Xacid_ne, TRUE, FALSE,
4223 EL_ACID_POOL_TOPRIGHT, -1, -1
4226 Xacid_se, TRUE, FALSE,
4227 EL_ACID_POOL_BOTTOMRIGHT, -1, -1
4230 Xacid_s, TRUE, FALSE,
4231 EL_ACID_POOL_BOTTOM, -1, -1
4234 Xacid_sw, TRUE, FALSE,
4235 EL_ACID_POOL_BOTTOMLEFT, -1, -1
4238 Xacid_nw, TRUE, FALSE,
4239 EL_ACID_POOL_TOPLEFT, -1, -1
4242 Xacid_1, TRUE, FALSE,
4246 Xacid_2, FALSE, FALSE,
4250 Xacid_3, FALSE, FALSE,
4254 Xacid_4, FALSE, FALSE,
4258 Xacid_5, FALSE, FALSE,
4262 Xacid_6, FALSE, FALSE,
4266 Xacid_7, FALSE, FALSE,
4270 Xacid_8, FALSE, FALSE,
4274 Xball_1, TRUE, FALSE,
4275 EL_EMC_MAGIC_BALL, -1, -1
4278 Xball_1B, FALSE, FALSE,
4279 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4282 Xball_2, FALSE, FALSE,
4283 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4286 Xball_2B, FALSE, FALSE,
4287 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4290 Yball_eat, FALSE, FALSE,
4291 EL_EMC_MAGIC_BALL, ACTION_DROPPING, -1
4294 Ykey_1_eat, FALSE, FALSE,
4295 EL_EM_KEY_1, ACTION_COLLECTING, -1
4298 Ykey_2_eat, FALSE, FALSE,
4299 EL_EM_KEY_2, ACTION_COLLECTING, -1
4302 Ykey_3_eat, FALSE, FALSE,
4303 EL_EM_KEY_3, ACTION_COLLECTING, -1
4306 Ykey_4_eat, FALSE, FALSE,
4307 EL_EM_KEY_4, ACTION_COLLECTING, -1
4310 Ykey_5_eat, FALSE, FALSE,
4311 EL_EMC_KEY_5, ACTION_COLLECTING, -1
4314 Ykey_6_eat, FALSE, FALSE,
4315 EL_EMC_KEY_6, ACTION_COLLECTING, -1
4318 Ykey_7_eat, FALSE, FALSE,
4319 EL_EMC_KEY_7, ACTION_COLLECTING, -1
4322 Ykey_8_eat, FALSE, FALSE,
4323 EL_EMC_KEY_8, ACTION_COLLECTING, -1
4326 Ylenses_eat, FALSE, FALSE,
4327 EL_EMC_LENSES, ACTION_COLLECTING, -1
4330 Ymagnify_eat, FALSE, FALSE,
4331 EL_EMC_MAGNIFIER, ACTION_COLLECTING, -1
4334 Ygrass_eat, FALSE, FALSE,
4335 EL_EMC_GRASS, ACTION_SNAPPING, -1
4338 Ydirt_eat, FALSE, FALSE,
4339 EL_SAND, ACTION_SNAPPING, -1
4342 Xgrow_ns, TRUE, FALSE,
4343 EL_EXPANDABLE_WALL_VERTICAL, -1, -1
4346 Ygrow_ns_eat, FALSE, FALSE,
4347 EL_EXPANDABLE_WALL_VERTICAL, ACTION_GROWING, -1
4350 Xgrow_ew, TRUE, FALSE,
4351 EL_EXPANDABLE_WALL_HORIZONTAL, -1, -1
4354 Ygrow_ew_eat, FALSE, FALSE,
4355 EL_EXPANDABLE_WALL_HORIZONTAL, ACTION_GROWING, -1
4358 Xwonderwall, TRUE, FALSE,
4359 EL_MAGIC_WALL, -1, -1
4362 XwonderwallB, FALSE, FALSE,
4363 EL_MAGIC_WALL, ACTION_ACTIVE, -1
4366 Xamoeba_1, TRUE, FALSE,
4367 EL_AMOEBA_DRY, ACTION_OTHER, -1
4370 Xamoeba_2, FALSE, FALSE,
4371 EL_AMOEBA_DRY, ACTION_OTHER, -1
4374 Xamoeba_3, FALSE, FALSE,
4375 EL_AMOEBA_DRY, ACTION_OTHER, -1
4378 Xamoeba_4, FALSE, FALSE,
4379 EL_AMOEBA_DRY, ACTION_OTHER, -1
4382 Xamoeba_5, TRUE, FALSE,
4383 EL_AMOEBA_WET, ACTION_OTHER, -1
4386 Xamoeba_6, FALSE, FALSE,
4387 EL_AMOEBA_WET, ACTION_OTHER, -1
4390 Xamoeba_7, FALSE, FALSE,
4391 EL_AMOEBA_WET, ACTION_OTHER, -1
4394 Xamoeba_8, FALSE, FALSE,
4395 EL_AMOEBA_WET, ACTION_OTHER, -1
4398 Xdoor_1, TRUE, FALSE,
4399 EL_EM_GATE_1, -1, -1
4402 Xdoor_2, TRUE, FALSE,
4403 EL_EM_GATE_2, -1, -1
4406 Xdoor_3, TRUE, FALSE,
4407 EL_EM_GATE_3, -1, -1
4410 Xdoor_4, TRUE, FALSE,
4411 EL_EM_GATE_4, -1, -1
4414 Xdoor_5, TRUE, FALSE,
4415 EL_EMC_GATE_5, -1, -1
4418 Xdoor_6, TRUE, FALSE,
4419 EL_EMC_GATE_6, -1, -1
4422 Xdoor_7, TRUE, FALSE,
4423 EL_EMC_GATE_7, -1, -1
4426 Xdoor_8, TRUE, FALSE,
4427 EL_EMC_GATE_8, -1, -1
4430 Xkey_1, TRUE, FALSE,
4434 Xkey_2, TRUE, FALSE,
4438 Xkey_3, TRUE, FALSE,
4442 Xkey_4, TRUE, FALSE,
4446 Xkey_5, TRUE, FALSE,
4447 EL_EMC_KEY_5, -1, -1
4450 Xkey_6, TRUE, FALSE,
4451 EL_EMC_KEY_6, -1, -1
4454 Xkey_7, TRUE, FALSE,
4455 EL_EMC_KEY_7, -1, -1
4458 Xkey_8, TRUE, FALSE,
4459 EL_EMC_KEY_8, -1, -1
4462 Xwind_n, TRUE, FALSE,
4463 EL_BALLOON_SWITCH_UP, -1, -1
4466 Xwind_e, TRUE, FALSE,
4467 EL_BALLOON_SWITCH_RIGHT, -1, -1
4470 Xwind_s, TRUE, FALSE,
4471 EL_BALLOON_SWITCH_DOWN, -1, -1
4474 Xwind_w, TRUE, FALSE,
4475 EL_BALLOON_SWITCH_LEFT, -1, -1
4478 Xwind_nesw, TRUE, FALSE,
4479 EL_BALLOON_SWITCH_ANY, -1, -1
4482 Xwind_stop, TRUE, FALSE,
4483 EL_BALLOON_SWITCH_NONE, -1, -1
4487 EL_EM_EXIT_CLOSED, -1, -1
4490 Xexit_1, TRUE, FALSE,
4491 EL_EM_EXIT_OPEN, -1, -1
4494 Xexit_2, FALSE, FALSE,
4495 EL_EM_EXIT_OPEN, -1, -1
4498 Xexit_3, FALSE, FALSE,
4499 EL_EM_EXIT_OPEN, -1, -1
4502 Xdynamite, TRUE, FALSE,
4503 EL_EM_DYNAMITE, -1, -1
4506 Ydynamite_eat, FALSE, FALSE,
4507 EL_EM_DYNAMITE, ACTION_COLLECTING, -1
4510 Xdynamite_1, TRUE, FALSE,
4511 EL_EM_DYNAMITE_ACTIVE, -1, -1
4514 Xdynamite_2, FALSE, FALSE,
4515 EL_EM_DYNAMITE_ACTIVE, -1, -1
4518 Xdynamite_3, FALSE, FALSE,
4519 EL_EM_DYNAMITE_ACTIVE, -1, -1
4522 Xdynamite_4, FALSE, FALSE,
4523 EL_EM_DYNAMITE_ACTIVE, -1, -1
4526 Xbumper, TRUE, FALSE,
4527 EL_EMC_SPRING_BUMPER, -1, -1
4530 XbumperB, FALSE, FALSE,
4531 EL_EMC_SPRING_BUMPER, ACTION_ACTIVE, -1
4534 Xwheel, TRUE, FALSE,
4535 EL_ROBOT_WHEEL, -1, -1
4538 XwheelB, FALSE, FALSE,
4539 EL_ROBOT_WHEEL, ACTION_ACTIVE, -1
4542 Xswitch, TRUE, FALSE,
4543 EL_EMC_MAGIC_BALL_SWITCH, -1, -1
4546 XswitchB, FALSE, FALSE,
4547 EL_EMC_MAGIC_BALL_SWITCH, ACTION_ACTIVE, -1
4551 EL_QUICKSAND_EMPTY, -1, -1
4554 Xsand_stone, TRUE, FALSE,
4555 EL_QUICKSAND_FULL, -1, -1
4558 Xsand_stonein_1, FALSE, TRUE,
4559 EL_ROCK, ACTION_FILLING, -1
4562 Xsand_stonein_2, FALSE, TRUE,
4563 EL_ROCK, ACTION_FILLING, -1
4566 Xsand_stonein_3, FALSE, TRUE,
4567 EL_ROCK, ACTION_FILLING, -1
4570 Xsand_stonein_4, FALSE, TRUE,
4571 EL_ROCK, ACTION_FILLING, -1
4574 Xsand_stonesand_1, FALSE, FALSE,
4575 EL_QUICKSAND_FULL, -1, -1
4578 Xsand_stonesand_2, FALSE, FALSE,
4579 EL_QUICKSAND_FULL, -1, -1
4582 Xsand_stonesand_3, FALSE, FALSE,
4583 EL_QUICKSAND_FULL, -1, -1
4586 Xsand_stonesand_4, FALSE, FALSE,
4587 EL_QUICKSAND_FULL, -1, -1
4590 Xsand_stoneout_1, FALSE, FALSE,
4591 EL_ROCK, ACTION_EMPTYING, -1
4594 Xsand_stoneout_2, FALSE, FALSE,
4595 EL_ROCK, ACTION_EMPTYING, -1
4598 Xsand_sandstone_1, FALSE, FALSE,
4599 EL_QUICKSAND_FULL, -1, -1
4602 Xsand_sandstone_2, FALSE, FALSE,
4603 EL_QUICKSAND_FULL, -1, -1
4606 Xsand_sandstone_3, FALSE, FALSE,
4607 EL_QUICKSAND_FULL, -1, -1
4610 Xsand_sandstone_4, FALSE, FALSE,
4611 EL_QUICKSAND_FULL, -1, -1
4614 Xplant, TRUE, FALSE,
4615 EL_EMC_PLANT, -1, -1
4618 Yplant, FALSE, FALSE,
4619 EL_EMC_PLANT, -1, -1
4622 Xlenses, TRUE, FALSE,
4623 EL_EMC_LENSES, -1, -1
4626 Xmagnify, TRUE, FALSE,
4627 EL_EMC_MAGNIFIER, -1, -1
4630 Xdripper, TRUE, FALSE,
4631 EL_EMC_DRIPPER, -1, -1
4634 XdripperB, FALSE, FALSE,
4635 EL_EMC_DRIPPER, ACTION_ACTIVE, -1
4638 Xfake_blank, TRUE, FALSE,
4639 EL_INVISIBLE_WALL, -1, -1
4642 Xfake_blankB, FALSE, FALSE,
4643 EL_INVISIBLE_WALL, ACTION_ACTIVE, -1
4646 Xfake_grass, TRUE, FALSE,
4647 EL_EMC_FAKE_GRASS, -1, -1
4650 Xfake_grassB, FALSE, FALSE,
4651 EL_EMC_FAKE_GRASS, ACTION_ACTIVE, -1
4654 Xfake_door_1, TRUE, FALSE,
4655 EL_EM_GATE_1_GRAY, -1, -1
4658 Xfake_door_2, TRUE, FALSE,
4659 EL_EM_GATE_2_GRAY, -1, -1
4662 Xfake_door_3, TRUE, FALSE,
4663 EL_EM_GATE_3_GRAY, -1, -1
4666 Xfake_door_4, TRUE, FALSE,
4667 EL_EM_GATE_4_GRAY, -1, -1
4670 Xfake_door_5, TRUE, FALSE,
4671 EL_EMC_GATE_5_GRAY, -1, -1
4674 Xfake_door_6, TRUE, FALSE,
4675 EL_EMC_GATE_6_GRAY, -1, -1
4678 Xfake_door_7, TRUE, FALSE,
4679 EL_EMC_GATE_7_GRAY, -1, -1
4682 Xfake_door_8, TRUE, FALSE,
4683 EL_EMC_GATE_8_GRAY, -1, -1
4686 Xfake_acid_1, TRUE, FALSE,
4687 EL_EMC_FAKE_ACID, -1, -1
4690 Xfake_acid_2, FALSE, FALSE,
4691 EL_EMC_FAKE_ACID, -1, -1
4694 Xfake_acid_3, FALSE, FALSE,
4695 EL_EMC_FAKE_ACID, -1, -1
4698 Xfake_acid_4, FALSE, FALSE,
4699 EL_EMC_FAKE_ACID, -1, -1
4702 Xfake_acid_5, FALSE, FALSE,
4703 EL_EMC_FAKE_ACID, -1, -1
4706 Xfake_acid_6, FALSE, FALSE,
4707 EL_EMC_FAKE_ACID, -1, -1
4710 Xfake_acid_7, FALSE, FALSE,
4711 EL_EMC_FAKE_ACID, -1, -1
4714 Xfake_acid_8, FALSE, FALSE,
4715 EL_EMC_FAKE_ACID, -1, -1
4718 Xsteel_1, TRUE, FALSE,
4719 EL_STEELWALL, -1, -1
4722 Xsteel_2, TRUE, FALSE,
4723 EL_EMC_STEELWALL_2, -1, -1
4726 Xsteel_3, TRUE, FALSE,
4727 EL_EMC_STEELWALL_3, -1, -1
4730 Xsteel_4, TRUE, FALSE,
4731 EL_EMC_STEELWALL_4, -1, -1
4734 Xwall_1, TRUE, FALSE,
4738 Xwall_2, TRUE, FALSE,
4739 EL_EMC_WALL_14, -1, -1
4742 Xwall_3, TRUE, FALSE,
4743 EL_EMC_WALL_15, -1, -1
4746 Xwall_4, TRUE, FALSE,
4747 EL_EMC_WALL_16, -1, -1
4750 Xround_wall_1, TRUE, FALSE,
4751 EL_WALL_SLIPPERY, -1, -1
4754 Xround_wall_2, TRUE, FALSE,
4755 EL_EMC_WALL_SLIPPERY_2, -1, -1
4758 Xround_wall_3, TRUE, FALSE,
4759 EL_EMC_WALL_SLIPPERY_3, -1, -1
4762 Xround_wall_4, TRUE, FALSE,
4763 EL_EMC_WALL_SLIPPERY_4, -1, -1
4766 Xdecor_1, TRUE, FALSE,
4767 EL_EMC_WALL_8, -1, -1
4770 Xdecor_2, TRUE, FALSE,
4771 EL_EMC_WALL_6, -1, -1
4774 Xdecor_3, TRUE, FALSE,
4775 EL_EMC_WALL_4, -1, -1
4778 Xdecor_4, TRUE, FALSE,
4779 EL_EMC_WALL_7, -1, -1
4782 Xdecor_5, TRUE, FALSE,
4783 EL_EMC_WALL_5, -1, -1
4786 Xdecor_6, TRUE, FALSE,
4787 EL_EMC_WALL_9, -1, -1
4790 Xdecor_7, TRUE, FALSE,
4791 EL_EMC_WALL_10, -1, -1
4794 Xdecor_8, TRUE, FALSE,
4795 EL_EMC_WALL_1, -1, -1
4798 Xdecor_9, TRUE, FALSE,
4799 EL_EMC_WALL_2, -1, -1
4802 Xdecor_10, TRUE, FALSE,
4803 EL_EMC_WALL_3, -1, -1
4806 Xdecor_11, TRUE, FALSE,
4807 EL_EMC_WALL_11, -1, -1
4810 Xdecor_12, TRUE, FALSE,
4811 EL_EMC_WALL_12, -1, -1
4814 Xalpha_0, TRUE, FALSE,
4815 EL_CHAR('0'), -1, -1
4818 Xalpha_1, TRUE, FALSE,
4819 EL_CHAR('1'), -1, -1
4822 Xalpha_2, TRUE, FALSE,
4823 EL_CHAR('2'), -1, -1
4826 Xalpha_3, TRUE, FALSE,
4827 EL_CHAR('3'), -1, -1
4830 Xalpha_4, TRUE, FALSE,
4831 EL_CHAR('4'), -1, -1
4834 Xalpha_5, TRUE, FALSE,
4835 EL_CHAR('5'), -1, -1
4838 Xalpha_6, TRUE, FALSE,
4839 EL_CHAR('6'), -1, -1
4842 Xalpha_7, TRUE, FALSE,
4843 EL_CHAR('7'), -1, -1
4846 Xalpha_8, TRUE, FALSE,
4847 EL_CHAR('8'), -1, -1
4850 Xalpha_9, TRUE, FALSE,
4851 EL_CHAR('9'), -1, -1
4854 Xalpha_excla, TRUE, FALSE,
4855 EL_CHAR('!'), -1, -1
4858 Xalpha_quote, TRUE, FALSE,
4859 EL_CHAR('"'), -1, -1
4862 Xalpha_comma, TRUE, FALSE,
4863 EL_CHAR(','), -1, -1
4866 Xalpha_minus, TRUE, FALSE,
4867 EL_CHAR('-'), -1, -1
4870 Xalpha_perio, TRUE, FALSE,
4871 EL_CHAR('.'), -1, -1
4874 Xalpha_colon, TRUE, FALSE,
4875 EL_CHAR(':'), -1, -1
4878 Xalpha_quest, TRUE, FALSE,
4879 EL_CHAR('?'), -1, -1
4882 Xalpha_a, TRUE, FALSE,
4883 EL_CHAR('A'), -1, -1
4886 Xalpha_b, TRUE, FALSE,
4887 EL_CHAR('B'), -1, -1
4890 Xalpha_c, TRUE, FALSE,
4891 EL_CHAR('C'), -1, -1
4894 Xalpha_d, TRUE, FALSE,
4895 EL_CHAR('D'), -1, -1
4898 Xalpha_e, TRUE, FALSE,
4899 EL_CHAR('E'), -1, -1
4902 Xalpha_f, TRUE, FALSE,
4903 EL_CHAR('F'), -1, -1
4906 Xalpha_g, TRUE, FALSE,
4907 EL_CHAR('G'), -1, -1
4910 Xalpha_h, TRUE, FALSE,
4911 EL_CHAR('H'), -1, -1
4914 Xalpha_i, TRUE, FALSE,
4915 EL_CHAR('I'), -1, -1
4918 Xalpha_j, TRUE, FALSE,
4919 EL_CHAR('J'), -1, -1
4922 Xalpha_k, TRUE, FALSE,
4923 EL_CHAR('K'), -1, -1
4926 Xalpha_l, TRUE, FALSE,
4927 EL_CHAR('L'), -1, -1
4930 Xalpha_m, TRUE, FALSE,
4931 EL_CHAR('M'), -1, -1
4934 Xalpha_n, TRUE, FALSE,
4935 EL_CHAR('N'), -1, -1
4938 Xalpha_o, TRUE, FALSE,
4939 EL_CHAR('O'), -1, -1
4942 Xalpha_p, TRUE, FALSE,
4943 EL_CHAR('P'), -1, -1
4946 Xalpha_q, TRUE, FALSE,
4947 EL_CHAR('Q'), -1, -1
4950 Xalpha_r, TRUE, FALSE,
4951 EL_CHAR('R'), -1, -1
4954 Xalpha_s, TRUE, FALSE,
4955 EL_CHAR('S'), -1, -1
4958 Xalpha_t, TRUE, FALSE,
4959 EL_CHAR('T'), -1, -1
4962 Xalpha_u, TRUE, FALSE,
4963 EL_CHAR('U'), -1, -1
4966 Xalpha_v, TRUE, FALSE,
4967 EL_CHAR('V'), -1, -1
4970 Xalpha_w, TRUE, FALSE,
4971 EL_CHAR('W'), -1, -1
4974 Xalpha_x, TRUE, FALSE,
4975 EL_CHAR('X'), -1, -1
4978 Xalpha_y, TRUE, FALSE,
4979 EL_CHAR('Y'), -1, -1
4982 Xalpha_z, TRUE, FALSE,
4983 EL_CHAR('Z'), -1, -1
4986 Xalpha_arrow_e, TRUE, FALSE,
4987 EL_CHAR('>'), -1, -1
4990 Xalpha_arrow_w, TRUE, FALSE,
4991 EL_CHAR('<'), -1, -1
4994 Xalpha_copyr, TRUE, FALSE,
4995 EL_CHAR('©'), -1, -1
4999 Xboom_bug, FALSE, FALSE,
5000 EL_BUG, ACTION_EXPLODING, -1
5003 Xboom_bomb, FALSE, FALSE,
5004 EL_BOMB, ACTION_EXPLODING, -1
5007 Xboom_android, FALSE, FALSE,
5008 EL_EMC_ANDROID, ACTION_OTHER, -1
5011 Xboom_1, FALSE, FALSE,
5012 EL_DEFAULT, ACTION_EXPLODING, -1
5015 Xboom_2, FALSE, FALSE,
5016 EL_DEFAULT, ACTION_EXPLODING, -1
5019 Znormal, FALSE, FALSE,
5023 Zdynamite, FALSE, FALSE,
5027 Zplayer, FALSE, FALSE,
5031 ZBORDER, FALSE, FALSE,
5041 static struct Mapping_EM_to_RND_player
5050 em_player_mapping_list[] =
5054 EL_PLAYER_1, ACTION_MOVING, MV_BIT_UP,
5058 EL_PLAYER_1, ACTION_MOVING, MV_BIT_RIGHT,
5062 EL_PLAYER_1, ACTION_MOVING, MV_BIT_DOWN,
5066 EL_PLAYER_1, ACTION_MOVING, MV_BIT_LEFT,
5070 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_UP,
5074 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_RIGHT,
5078 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_DOWN,
5082 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_LEFT,
5086 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_UP,
5090 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_RIGHT,
5094 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_DOWN,
5098 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_LEFT,
5102 EL_PLAYER_2, ACTION_MOVING, MV_BIT_UP,
5106 EL_PLAYER_2, ACTION_MOVING, MV_BIT_RIGHT,
5110 EL_PLAYER_2, ACTION_MOVING, MV_BIT_DOWN,
5114 EL_PLAYER_2, ACTION_MOVING, MV_BIT_LEFT,
5118 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_UP,
5122 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_RIGHT,
5126 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_DOWN,
5130 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_LEFT,
5134 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_UP,
5138 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_RIGHT,
5142 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_DOWN,
5146 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_LEFT,
5150 EL_PLAYER_1, ACTION_DEFAULT, -1,
5154 EL_PLAYER_2, ACTION_DEFAULT, -1,
5158 EL_PLAYER_3, ACTION_MOVING, MV_BIT_UP,
5162 EL_PLAYER_3, ACTION_MOVING, MV_BIT_RIGHT,
5166 EL_PLAYER_3, ACTION_MOVING, MV_BIT_DOWN,
5170 EL_PLAYER_3, ACTION_MOVING, MV_BIT_LEFT,
5174 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_UP,
5178 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_RIGHT,
5182 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_DOWN,
5186 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_LEFT,
5190 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_UP,
5194 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_RIGHT,
5198 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_DOWN,
5202 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_LEFT,
5206 EL_PLAYER_4, ACTION_MOVING, MV_BIT_UP,
5210 EL_PLAYER_4, ACTION_MOVING, MV_BIT_RIGHT,
5214 EL_PLAYER_4, ACTION_MOVING, MV_BIT_DOWN,
5218 EL_PLAYER_4, ACTION_MOVING, MV_BIT_LEFT,
5222 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_UP,
5226 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_RIGHT,
5230 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_DOWN,
5234 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_LEFT,
5238 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_UP,
5242 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_RIGHT,
5246 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_DOWN,
5250 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_LEFT,
5254 EL_PLAYER_3, ACTION_DEFAULT, -1,
5258 EL_PLAYER_4, ACTION_DEFAULT, -1,
5267 int map_element_RND_to_EM(int element_rnd)
5269 static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
5270 static boolean mapping_initialized = FALSE;
5272 if (!mapping_initialized)
5276 /* return "Xalpha_quest" for all undefined elements in mapping array */
5277 for (i = 0; i < NUM_FILE_ELEMENTS; i++)
5278 mapping_RND_to_EM[i] = Xalpha_quest;
5280 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5281 if (em_object_mapping_list[i].is_rnd_to_em_mapping)
5282 mapping_RND_to_EM[em_object_mapping_list[i].element_rnd] =
5283 em_object_mapping_list[i].element_em;
5285 mapping_initialized = TRUE;
5288 if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
5289 return mapping_RND_to_EM[element_rnd];
5291 Error(ERR_WARN, "invalid RND level element %d", element_rnd);
5296 int map_element_EM_to_RND(int element_em)
5298 static unsigned short mapping_EM_to_RND[TILE_MAX];
5299 static boolean mapping_initialized = FALSE;
5301 if (!mapping_initialized)
5305 /* return "EL_UNKNOWN" for all undefined elements in mapping array */
5306 for (i = 0; i < TILE_MAX; i++)
5307 mapping_EM_to_RND[i] = EL_UNKNOWN;
5309 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5310 mapping_EM_to_RND[em_object_mapping_list[i].element_em] =
5311 em_object_mapping_list[i].element_rnd;
5313 mapping_initialized = TRUE;
5316 if (element_em >= 0 && element_em < TILE_MAX)
5317 return mapping_EM_to_RND[element_em];
5319 Error(ERR_WARN, "invalid EM level element %d", element_em);
5324 void map_android_clone_elements_RND_to_EM(struct LevelInfo *level)
5326 struct LevelInfo_EM *level_em = level->native_em_level;
5327 struct LEVEL *lev = level_em->lev;
5330 for (i = 0; i < TILE_MAX; i++)
5331 lev->android_array[i] = Xblank;
5333 for (i = 0; i < level->num_android_clone_elements; i++)
5335 int element_rnd = level->android_clone_element[i];
5336 int element_em = map_element_RND_to_EM(element_rnd);
5338 for (j = 0; em_object_mapping_list[j].element_em != -1; j++)
5339 if (em_object_mapping_list[j].element_rnd == element_rnd)
5340 lev->android_array[em_object_mapping_list[j].element_em] = element_em;
5344 void map_android_clone_elements_EM_to_RND(struct LevelInfo *level)
5346 struct LevelInfo_EM *level_em = level->native_em_level;
5347 struct LEVEL *lev = level_em->lev;
5350 level->num_android_clone_elements = 0;
5352 for (i = 0; i < TILE_MAX; i++)
5354 int element_em = lev->android_array[i];
5356 boolean element_found = FALSE;
5358 if (element_em == Xblank)
5361 element_rnd = map_element_EM_to_RND(element_em);
5363 for (j = 0; j < level->num_android_clone_elements; j++)
5364 if (level->android_clone_element[j] == element_rnd)
5365 element_found = TRUE;
5369 level->android_clone_element[level->num_android_clone_elements++] =
5372 if (level->num_android_clone_elements == MAX_ANDROID_ELEMENTS)
5377 if (level->num_android_clone_elements == 0)
5379 level->num_android_clone_elements = 1;
5380 level->android_clone_element[0] = EL_EMPTY;
5384 int map_direction_RND_to_EM(int direction)
5386 return (direction == MV_UP ? 0 :
5387 direction == MV_RIGHT ? 1 :
5388 direction == MV_DOWN ? 2 :
5389 direction == MV_LEFT ? 3 :
5393 int map_direction_EM_to_RND(int direction)
5395 return (direction == 0 ? MV_UP :
5396 direction == 1 ? MV_RIGHT :
5397 direction == 2 ? MV_DOWN :
5398 direction == 3 ? MV_LEFT :
5402 int get_next_element(int element)
5406 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
5407 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
5408 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
5409 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
5410 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
5411 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
5412 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
5414 default: return element;
5419 int el_act_dir2img(int element, int action, int direction)
5421 element = GFX_ELEMENT(element);
5423 if (direction == MV_NONE)
5424 return element_info[element].graphic[action];
5426 direction = MV_DIR_TO_BIT(direction);
5428 return element_info[element].direction_graphic[action][direction];
5431 int el_act_dir2img(int element, int action, int direction)
5433 element = GFX_ELEMENT(element);
5434 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
5436 /* direction_graphic[][] == graphic[] for undefined direction graphics */
5437 return element_info[element].direction_graphic[action][direction];
5442 static int el_act_dir2crm(int element, int action, int direction)
5444 element = GFX_ELEMENT(element);
5446 if (direction == MV_NONE)
5447 return element_info[element].crumbled[action];
5449 direction = MV_DIR_TO_BIT(direction);
5451 return element_info[element].direction_crumbled[action][direction];
5454 static int el_act_dir2crm(int element, int action, int direction)
5456 element = GFX_ELEMENT(element);
5457 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
5459 /* direction_graphic[][] == graphic[] for undefined direction graphics */
5460 return element_info[element].direction_crumbled[action][direction];
5464 int el_act2img(int element, int action)
5466 element = GFX_ELEMENT(element);
5468 return element_info[element].graphic[action];
5471 int el_act2crm(int element, int action)
5473 element = GFX_ELEMENT(element);
5475 return element_info[element].crumbled[action];
5478 int el_dir2img(int element, int direction)
5480 element = GFX_ELEMENT(element);
5482 return el_act_dir2img(element, ACTION_DEFAULT, direction);
5485 int el2baseimg(int element)
5487 return element_info[element].graphic[ACTION_DEFAULT];
5490 int el2img(int element)
5492 element = GFX_ELEMENT(element);
5494 return element_info[element].graphic[ACTION_DEFAULT];
5497 int el2edimg(int element)
5499 element = GFX_ELEMENT(element);
5501 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
5504 int el2preimg(int element)
5506 element = GFX_ELEMENT(element);
5508 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
5511 int font2baseimg(int font_nr)
5513 return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
5516 int getNumActivePlayers_EM()
5518 int num_players = 0;
5524 for (i = 0; i < MAX_PLAYERS; i++)
5525 if (tape.player_participates[i])
5531 int getGameFrameDelay_EM(int native_em_game_frame_delay)
5533 int game_frame_delay_value;
5535 game_frame_delay_value =
5536 (tape.playing && tape.fast_forward ? FfwdFrameDelay :
5537 GameFrameDelay == GAME_FRAME_DELAY ? native_em_game_frame_delay :
5540 if (tape.playing && tape.warp_forward && !tape.pausing)
5541 game_frame_delay_value = 0;
5543 return game_frame_delay_value;
5546 unsigned int InitRND(long seed)
5548 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
5549 return InitEngineRandom_EM(seed);
5551 return InitEngineRandom_RND(seed);
5554 void InitGraphicInfo_EM(void)
5556 struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
5557 struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
5561 int num_em_gfx_errors = 0;
5563 if (graphic_info_em_object[0][0].bitmap == NULL)
5565 /* EM graphics not yet initialized in em_open_all() */
5570 printf("::: [4 errors can be ignored (1 x 'bomb', 3 x 'em_dynamite']\n");
5573 /* always start with reliable default values */
5574 for (i = 0; i < TILE_MAX; i++)
5576 object_mapping[i].element_rnd = EL_UNKNOWN;
5577 object_mapping[i].is_backside = FALSE;
5578 object_mapping[i].action = ACTION_DEFAULT;
5579 object_mapping[i].direction = MV_NONE;
5582 /* always start with reliable default values */
5583 for (p = 0; p < MAX_PLAYERS; p++)
5585 for (i = 0; i < SPR_MAX; i++)
5587 player_mapping[p][i].element_rnd = EL_UNKNOWN;
5588 player_mapping[p][i].action = ACTION_DEFAULT;
5589 player_mapping[p][i].direction = MV_NONE;
5593 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5595 int e = em_object_mapping_list[i].element_em;
5597 object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd;
5598 object_mapping[e].is_backside = em_object_mapping_list[i].is_backside;
5600 if (em_object_mapping_list[i].action != -1)
5601 object_mapping[e].action = em_object_mapping_list[i].action;
5603 if (em_object_mapping_list[i].direction != -1)
5604 object_mapping[e].direction =
5605 MV_DIR_FROM_BIT(em_object_mapping_list[i].direction);
5608 for (i = 0; em_player_mapping_list[i].action_em != -1; i++)
5610 int a = em_player_mapping_list[i].action_em;
5611 int p = em_player_mapping_list[i].player_nr;
5613 player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd;
5615 if (em_player_mapping_list[i].action != -1)
5616 player_mapping[p][a].action = em_player_mapping_list[i].action;
5618 if (em_player_mapping_list[i].direction != -1)
5619 player_mapping[p][a].direction =
5620 MV_DIR_FROM_BIT(em_player_mapping_list[i].direction);
5623 for (i = 0; i < TILE_MAX; i++)
5625 int element = object_mapping[i].element_rnd;
5626 int action = object_mapping[i].action;
5627 int direction = object_mapping[i].direction;
5628 boolean is_backside = object_mapping[i].is_backside;
5629 boolean action_removing = (action == ACTION_DIGGING ||
5630 action == ACTION_SNAPPING ||
5631 action == ACTION_COLLECTING);
5632 boolean action_exploding = ((action == ACTION_EXPLODING ||
5633 action == ACTION_SMASHED_BY_ROCK ||
5634 action == ACTION_SMASHED_BY_SPRING) &&
5635 element != EL_DIAMOND);
5636 boolean action_active = (action == ACTION_ACTIVE);
5637 boolean action_other = (action == ACTION_OTHER);
5639 for (j = 0; j < 8; j++)
5641 int effective_element = (j > 5 && i == Yacid_splash_eB ? EL_EMPTY :
5642 j > 5 && i == Yacid_splash_wB ? EL_EMPTY :
5644 i == Xdrip_stretch ? element :
5645 i == Xdrip_stretchB ? element :
5646 i == Ydrip_s1 ? element :
5647 i == Ydrip_s1B ? element :
5648 i == Xball_1B ? element :
5649 i == Xball_2 ? element :
5650 i == Xball_2B ? element :
5651 i == Yball_eat ? element :
5652 i == Ykey_1_eat ? element :
5653 i == Ykey_2_eat ? element :
5654 i == Ykey_3_eat ? element :
5655 i == Ykey_4_eat ? element :
5656 i == Ykey_5_eat ? element :
5657 i == Ykey_6_eat ? element :
5658 i == Ykey_7_eat ? element :
5659 i == Ykey_8_eat ? element :
5660 i == Ylenses_eat ? element :
5661 i == Ymagnify_eat ? element :
5662 i == Ygrass_eat ? element :
5663 i == Ydirt_eat ? element :
5664 i == Yemerald_stone ? EL_EMERALD :
5665 i == Ydiamond_stone ? EL_ROCK :
5666 i == Xsand_stonein_1 ? element :
5667 i == Xsand_stonein_2 ? element :
5668 i == Xsand_stonein_3 ? element :
5669 i == Xsand_stonein_4 ? element :
5670 is_backside ? EL_EMPTY :
5671 action_removing ? EL_EMPTY :
5673 int effective_action = (j < 7 ? action :
5674 i == Xdrip_stretch ? action :
5675 i == Xdrip_stretchB ? action :
5676 i == Ydrip_s1 ? action :
5677 i == Ydrip_s1B ? action :
5678 i == Xball_1B ? action :
5679 i == Xball_2 ? action :
5680 i == Xball_2B ? action :
5681 i == Yball_eat ? action :
5682 i == Ykey_1_eat ? action :
5683 i == Ykey_2_eat ? action :
5684 i == Ykey_3_eat ? action :
5685 i == Ykey_4_eat ? action :
5686 i == Ykey_5_eat ? action :
5687 i == Ykey_6_eat ? action :
5688 i == Ykey_7_eat ? action :
5689 i == Ykey_8_eat ? action :
5690 i == Ylenses_eat ? action :
5691 i == Ymagnify_eat ? action :
5692 i == Ygrass_eat ? action :
5693 i == Ydirt_eat ? action :
5694 i == Xsand_stonein_1 ? action :
5695 i == Xsand_stonein_2 ? action :
5696 i == Xsand_stonein_3 ? action :
5697 i == Xsand_stonein_4 ? action :
5698 i == Xsand_stoneout_1 ? action :
5699 i == Xsand_stoneout_2 ? action :
5700 i == Xboom_android ? ACTION_EXPLODING :
5701 action_exploding ? ACTION_EXPLODING :
5702 action_active ? action :
5703 action_other ? action :
5705 int graphic = (el_act_dir2img(effective_element, effective_action,
5707 int crumbled = (el_act_dir2crm(effective_element, effective_action,
5709 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
5710 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
5711 boolean has_action_graphics = (graphic != base_graphic);
5712 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
5713 struct GraphicInfo *g = &graphic_info[graphic];
5714 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
5717 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
5718 boolean special_animation = (action != ACTION_DEFAULT &&
5719 g->anim_frames == 3 &&
5720 g->anim_delay == 2 &&
5721 g->anim_mode & ANIM_LINEAR);
5722 int sync_frame = (i == Xdrip_stretch ? 7 :
5723 i == Xdrip_stretchB ? 7 :
5724 i == Ydrip_s2 ? j + 8 :
5725 i == Ydrip_s2B ? j + 8 :
5734 i == Xfake_acid_1 ? 0 :
5735 i == Xfake_acid_2 ? 10 :
5736 i == Xfake_acid_3 ? 20 :
5737 i == Xfake_acid_4 ? 30 :
5738 i == Xfake_acid_5 ? 40 :
5739 i == Xfake_acid_6 ? 50 :
5740 i == Xfake_acid_7 ? 60 :
5741 i == Xfake_acid_8 ? 70 :
5743 i == Xball_2B ? j + 8 :
5744 i == Yball_eat ? j + 1 :
5745 i == Ykey_1_eat ? j + 1 :
5746 i == Ykey_2_eat ? j + 1 :
5747 i == Ykey_3_eat ? j + 1 :
5748 i == Ykey_4_eat ? j + 1 :
5749 i == Ykey_5_eat ? j + 1 :
5750 i == Ykey_6_eat ? j + 1 :
5751 i == Ykey_7_eat ? j + 1 :
5752 i == Ykey_8_eat ? j + 1 :
5753 i == Ylenses_eat ? j + 1 :
5754 i == Ymagnify_eat ? j + 1 :
5755 i == Ygrass_eat ? j + 1 :
5756 i == Ydirt_eat ? j + 1 :
5757 i == Xamoeba_1 ? 0 :
5758 i == Xamoeba_2 ? 1 :
5759 i == Xamoeba_3 ? 2 :
5760 i == Xamoeba_4 ? 3 :
5761 i == Xamoeba_5 ? 0 :
5762 i == Xamoeba_6 ? 1 :
5763 i == Xamoeba_7 ? 2 :
5764 i == Xamoeba_8 ? 3 :
5765 i == Xexit_2 ? j + 8 :
5766 i == Xexit_3 ? j + 16 :
5767 i == Xdynamite_1 ? 0 :
5768 i == Xdynamite_2 ? 8 :
5769 i == Xdynamite_3 ? 16 :
5770 i == Xdynamite_4 ? 24 :
5771 i == Xsand_stonein_1 ? j + 1 :
5772 i == Xsand_stonein_2 ? j + 9 :
5773 i == Xsand_stonein_3 ? j + 17 :
5774 i == Xsand_stonein_4 ? j + 25 :
5775 i == Xsand_stoneout_1 && j == 0 ? 0 :
5776 i == Xsand_stoneout_1 && j == 1 ? 0 :
5777 i == Xsand_stoneout_1 && j == 2 ? 1 :
5778 i == Xsand_stoneout_1 && j == 3 ? 2 :
5779 i == Xsand_stoneout_1 && j == 4 ? 2 :
5780 i == Xsand_stoneout_1 && j == 5 ? 3 :
5781 i == Xsand_stoneout_1 && j == 6 ? 4 :
5782 i == Xsand_stoneout_1 && j == 7 ? 4 :
5783 i == Xsand_stoneout_2 && j == 0 ? 5 :
5784 i == Xsand_stoneout_2 && j == 1 ? 6 :
5785 i == Xsand_stoneout_2 && j == 2 ? 7 :
5786 i == Xsand_stoneout_2 && j == 3 ? 8 :
5787 i == Xsand_stoneout_2 && j == 4 ? 9 :
5788 i == Xsand_stoneout_2 && j == 5 ? 11 :
5789 i == Xsand_stoneout_2 && j == 6 ? 13 :
5790 i == Xsand_stoneout_2 && j == 7 ? 15 :
5791 i == Xboom_bug && j == 1 ? 2 :
5792 i == Xboom_bug && j == 2 ? 2 :
5793 i == Xboom_bug && j == 3 ? 4 :
5794 i == Xboom_bug && j == 4 ? 4 :
5795 i == Xboom_bug && j == 5 ? 2 :
5796 i == Xboom_bug && j == 6 ? 2 :
5797 i == Xboom_bug && j == 7 ? 0 :
5798 i == Xboom_bomb && j == 1 ? 2 :
5799 i == Xboom_bomb && j == 2 ? 2 :
5800 i == Xboom_bomb && j == 3 ? 4 :
5801 i == Xboom_bomb && j == 4 ? 4 :
5802 i == Xboom_bomb && j == 5 ? 2 :
5803 i == Xboom_bomb && j == 6 ? 2 :
5804 i == Xboom_bomb && j == 7 ? 0 :
5805 i == Xboom_android && j == 7 ? 6 :
5806 i == Xboom_1 && j == 1 ? 2 :
5807 i == Xboom_1 && j == 2 ? 2 :
5808 i == Xboom_1 && j == 3 ? 4 :
5809 i == Xboom_1 && j == 4 ? 4 :
5810 i == Xboom_1 && j == 5 ? 6 :
5811 i == Xboom_1 && j == 6 ? 6 :
5812 i == Xboom_1 && j == 7 ? 8 :
5813 i == Xboom_2 && j == 0 ? 8 :
5814 i == Xboom_2 && j == 1 ? 8 :
5815 i == Xboom_2 && j == 2 ? 10 :
5816 i == Xboom_2 && j == 3 ? 10 :
5817 i == Xboom_2 && j == 4 ? 10 :
5818 i == Xboom_2 && j == 5 ? 12 :
5819 i == Xboom_2 && j == 6 ? 12 :
5820 i == Xboom_2 && j == 7 ? 12 :
5821 special_animation && j == 4 ? 3 :
5822 effective_action != action ? 0 :
5826 Bitmap *debug_bitmap = g_em->bitmap;
5827 int debug_src_x = g_em->src_x;
5828 int debug_src_y = g_em->src_y;
5831 int frame = getAnimationFrame(g->anim_frames,
5834 g->anim_start_frame,
5837 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y,
5838 g->double_movement && is_backside);
5840 g_em->bitmap = src_bitmap;
5841 g_em->src_x = src_x;
5842 g_em->src_y = src_y;
5843 g_em->src_offset_x = 0;
5844 g_em->src_offset_y = 0;
5845 g_em->dst_offset_x = 0;
5846 g_em->dst_offset_y = 0;
5847 g_em->width = TILEX;
5848 g_em->height = TILEY;
5850 g_em->crumbled_bitmap = NULL;
5851 g_em->crumbled_src_x = 0;
5852 g_em->crumbled_src_y = 0;
5853 g_em->crumbled_border_size = 0;
5855 g_em->has_crumbled_graphics = FALSE;
5856 g_em->preserve_background = FALSE;
5859 if (has_crumbled_graphics && crumbled == IMG_EMPTY_SPACE)
5860 printf("::: empty crumbled: %d [%s], %d, %d\n",
5861 effective_element, element_info[effective_element].token_name,
5862 effective_action, direction);
5865 /* if element can be crumbled, but certain action graphics are just empty
5866 space (like snapping sand with the original R'n'D graphics), do not
5867 treat these empty space graphics as crumbled graphics in EMC engine */
5868 if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
5870 getGraphicSource(crumbled, frame, &src_bitmap, &src_x, &src_y);
5872 g_em->has_crumbled_graphics = TRUE;
5873 g_em->crumbled_bitmap = src_bitmap;
5874 g_em->crumbled_src_x = src_x;
5875 g_em->crumbled_src_y = src_y;
5876 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
5880 if (element == EL_ROCK &&
5881 effective_action == ACTION_FILLING)
5882 printf("::: has_action_graphics == %d\n", has_action_graphics);
5885 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
5886 effective_action == ACTION_MOVING ||
5887 effective_action == ACTION_PUSHING ||
5888 effective_action == ACTION_EATING)) ||
5889 (!has_action_graphics && (effective_action == ACTION_FILLING ||
5890 effective_action == ACTION_EMPTYING)))
5893 (effective_action == ACTION_FALLING ||
5894 effective_action == ACTION_FILLING ||
5895 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
5896 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
5897 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
5898 int num_steps = (i == Ydrip_s1 ? 16 :
5899 i == Ydrip_s1B ? 16 :
5900 i == Ydrip_s2 ? 16 :
5901 i == Ydrip_s2B ? 16 :
5902 i == Xsand_stonein_1 ? 32 :
5903 i == Xsand_stonein_2 ? 32 :
5904 i == Xsand_stonein_3 ? 32 :
5905 i == Xsand_stonein_4 ? 32 :
5906 i == Xsand_stoneout_1 ? 16 :
5907 i == Xsand_stoneout_2 ? 16 : 8);
5908 int cx = ABS(dx) * (TILEX / num_steps);
5909 int cy = ABS(dy) * (TILEY / num_steps);
5910 int step_frame = (i == Ydrip_s2 ? j + 8 :
5911 i == Ydrip_s2B ? j + 8 :
5912 i == Xsand_stonein_2 ? j + 8 :
5913 i == Xsand_stonein_3 ? j + 16 :
5914 i == Xsand_stonein_4 ? j + 24 :
5915 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
5916 int step = (is_backside ? step_frame : num_steps - step_frame);
5918 if (is_backside) /* tile where movement starts */
5920 if (dx < 0 || dy < 0)
5922 g_em->src_offset_x = cx * step;
5923 g_em->src_offset_y = cy * step;
5927 g_em->dst_offset_x = cx * step;
5928 g_em->dst_offset_y = cy * step;
5931 else /* tile where movement ends */
5933 if (dx < 0 || dy < 0)
5935 g_em->dst_offset_x = cx * step;
5936 g_em->dst_offset_y = cy * step;
5940 g_em->src_offset_x = cx * step;
5941 g_em->src_offset_y = cy * step;
5945 g_em->width = TILEX - cx * step;
5946 g_em->height = TILEY - cy * step;
5949 /* create unique graphic identifier to decide if tile must be redrawn */
5950 /* bit 31 - 16 (16 bit): EM style graphic
5951 bit 15 - 12 ( 4 bit): EM style frame
5952 bit 11 - 6 ( 6 bit): graphic width
5953 bit 5 - 0 ( 6 bit): graphic height */
5954 g_em->unique_identifier =
5955 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
5959 /* skip check for EMC elements not contained in original EMC artwork */
5960 if (element == EL_EMC_FAKE_ACID)
5963 if (g_em->bitmap != debug_bitmap ||
5964 g_em->src_x != debug_src_x ||
5965 g_em->src_y != debug_src_y ||
5966 g_em->src_offset_x != 0 ||
5967 g_em->src_offset_y != 0 ||
5968 g_em->dst_offset_x != 0 ||
5969 g_em->dst_offset_y != 0 ||
5970 g_em->width != TILEX ||
5971 g_em->height != TILEY)
5973 static int last_i = -1;
5981 printf("::: EMC GFX ERROR for element %d -> %d ('%s', '%s', %d)",
5982 i, element, element_info[element].token_name,
5983 element_action_info[effective_action].suffix, direction);
5985 if (element != effective_element)
5986 printf(" [%d ('%s')]",
5988 element_info[effective_element].token_name);
5992 if (g_em->bitmap != debug_bitmap)
5993 printf(" %d (%d): different bitmap! (0x%08x != 0x%08x)\n",
5994 j, is_backside, (int)(g_em->bitmap), (int)(debug_bitmap));
5996 if (g_em->src_x != debug_src_x ||
5997 g_em->src_y != debug_src_y)
5998 printf(" frame %d (%c): %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
5999 j, (is_backside ? 'B' : 'F'),
6000 g_em->src_x, g_em->src_y,
6001 g_em->src_x / 32, g_em->src_y / 32,
6002 debug_src_x, debug_src_y,
6003 debug_src_x / 32, debug_src_y / 32);
6005 if (g_em->src_offset_x != 0 ||
6006 g_em->src_offset_y != 0 ||
6007 g_em->dst_offset_x != 0 ||
6008 g_em->dst_offset_y != 0)
6009 printf(" %d (%d): offsets %d,%d and %d,%d should be all 0\n",
6011 g_em->src_offset_x, g_em->src_offset_y,
6012 g_em->dst_offset_x, g_em->dst_offset_y);
6014 if (g_em->width != TILEX ||
6015 g_em->height != TILEY)
6016 printf(" %d (%d): size %d,%d should be %d,%d\n",
6018 g_em->width, g_em->height, TILEX, TILEY);
6020 num_em_gfx_errors++;
6027 for (i = 0; i < TILE_MAX; i++)
6029 for (j = 0; j < 8; j++)
6031 int element = object_mapping[i].element_rnd;
6032 int action = object_mapping[i].action;
6033 int direction = object_mapping[i].direction;
6034 boolean is_backside = object_mapping[i].is_backside;
6035 int graphic_action = el_act_dir2img(element, action, direction);
6036 int graphic_default = el_act_dir2img(element, ACTION_DEFAULT, direction);
6038 if ((action == ACTION_SMASHED_BY_ROCK ||
6039 action == ACTION_SMASHED_BY_SPRING ||
6040 action == ACTION_EATING) &&
6041 graphic_action == graphic_default)
6043 int e = (action == ACTION_SMASHED_BY_ROCK ? Ystone_s :
6044 action == ACTION_SMASHED_BY_SPRING ? Yspring_s :
6045 direction == MV_LEFT ? (is_backside? Yspring_wB: Yspring_w) :
6046 direction == MV_RIGHT ? (is_backside? Yspring_eB: Yspring_e) :
6049 /* no separate animation for "smashed by rock" -- use rock instead */
6050 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
6051 struct GraphicInfo_EM *g_xx = &graphic_info_em_object[e][7 - j];
6053 g_em->bitmap = g_xx->bitmap;
6054 g_em->src_x = g_xx->src_x;
6055 g_em->src_y = g_xx->src_y;
6056 g_em->src_offset_x = g_xx->src_offset_x;
6057 g_em->src_offset_y = g_xx->src_offset_y;
6058 g_em->dst_offset_x = g_xx->dst_offset_x;
6059 g_em->dst_offset_y = g_xx->dst_offset_y;
6060 g_em->width = g_xx->width;
6061 g_em->height = g_xx->height;
6062 g_em->unique_identifier = g_xx->unique_identifier;
6065 g_em->preserve_background = TRUE;
6070 for (p = 0; p < MAX_PLAYERS; p++)
6072 for (i = 0; i < SPR_MAX; i++)
6074 int element = player_mapping[p][i].element_rnd;
6075 int action = player_mapping[p][i].action;
6076 int direction = player_mapping[p][i].direction;
6078 for (j = 0; j < 8; j++)
6080 int effective_element = element;
6081 int effective_action = action;
6082 int graphic = (direction == MV_NONE ?
6083 el_act2img(effective_element, effective_action) :
6084 el_act_dir2img(effective_element, effective_action,
6086 struct GraphicInfo *g = &graphic_info[graphic];
6087 struct GraphicInfo_EM *g_em = &graphic_info_em_player[p][i][7 - j];
6093 Bitmap *debug_bitmap = g_em->bitmap;
6094 int debug_src_x = g_em->src_x;
6095 int debug_src_y = g_em->src_y;
6098 int frame = getAnimationFrame(g->anim_frames,
6101 g->anim_start_frame,
6104 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x,&src_y, FALSE);
6106 g_em->bitmap = src_bitmap;
6107 g_em->src_x = src_x;
6108 g_em->src_y = src_y;
6109 g_em->src_offset_x = 0;
6110 g_em->src_offset_y = 0;
6111 g_em->dst_offset_x = 0;
6112 g_em->dst_offset_y = 0;
6113 g_em->width = TILEX;
6114 g_em->height = TILEY;
6118 /* skip check for EMC elements not contained in original EMC artwork */
6119 if (element == EL_PLAYER_3 ||
6120 element == EL_PLAYER_4)
6123 if (g_em->bitmap != debug_bitmap ||
6124 g_em->src_x != debug_src_x ||
6125 g_em->src_y != debug_src_y)
6127 static int last_i = -1;
6135 printf("::: EMC GFX ERROR for p/a %d/%d -> %d ('%s', '%s', %d)",
6136 p, i, element, element_info[element].token_name,
6137 element_action_info[effective_action].suffix, direction);
6139 if (element != effective_element)
6140 printf(" [%d ('%s')]",
6142 element_info[effective_element].token_name);
6146 if (g_em->bitmap != debug_bitmap)
6147 printf(" %d: different bitmap! (0x%08x != 0x%08x)\n",
6148 j, (int)(g_em->bitmap), (int)(debug_bitmap));
6150 if (g_em->src_x != debug_src_x ||
6151 g_em->src_y != debug_src_y)
6152 printf(" frame %d: %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
6154 g_em->src_x, g_em->src_y,
6155 g_em->src_x / 32, g_em->src_y / 32,
6156 debug_src_x, debug_src_y,
6157 debug_src_x / 32, debug_src_y / 32);
6159 num_em_gfx_errors++;
6169 printf("::: [%d errors found]\n", num_em_gfx_errors);
6175 void PlayMenuSound()
6177 int sound = menu.sound[game_status];
6179 if (sound == SND_UNDEFINED)
6182 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
6183 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
6186 if (IS_LOOP_SOUND(sound))
6187 PlaySoundLoop(sound);
6192 void PlayMenuSoundStereo(int sound, int stereo_position)
6194 if (sound == SND_UNDEFINED)
6197 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
6198 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
6201 if (IS_LOOP_SOUND(sound))
6202 PlaySoundExt(sound, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_LOOP);
6204 PlaySoundStereo(sound, stereo_position);
6207 void PlayMenuSoundIfLoop()
6209 int sound = menu.sound[game_status];
6211 if (sound == SND_UNDEFINED)
6214 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
6215 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
6218 if (IS_LOOP_SOUND(sound))
6219 PlaySoundLoop(sound);
6222 void PlayMenuMusic()
6224 int music = menu.music[game_status];
6226 if (music == MUS_UNDEFINED)
6229 if (!setup.sound_music)
6235 void PlaySoundActivating()
6238 PlaySound(SND_MENU_ITEM_ACTIVATING);
6242 void PlaySoundSelecting()
6245 PlaySound(SND_MENU_ITEM_SELECTING);
6249 void ToggleFullscreenIfNeeded()
6251 boolean change_fullscreen = (setup.fullscreen !=
6252 video.fullscreen_enabled);
6253 boolean change_fullscreen_mode = (video.fullscreen_enabled &&
6254 !strEqual(setup.fullscreen_mode,
6255 video.fullscreen_mode_current));
6257 if (!video.fullscreen_available)
6261 if (change_fullscreen || change_fullscreen_mode)
6263 if (setup.fullscreen != video.fullscreen_enabled ||
6264 setup.fullscreen_mode != video.fullscreen_mode_current)
6267 Bitmap *tmp_backbuffer = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
6269 /* save backbuffer content which gets lost when toggling fullscreen mode */
6270 BlitBitmap(backbuffer, tmp_backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
6273 if (change_fullscreen_mode)
6275 if (setup.fullscreen && video.fullscreen_enabled)
6278 /* keep fullscreen, but change fullscreen mode (screen resolution) */
6280 /* (this is now set in sdl.c) */
6282 video.fullscreen_mode_current = setup.fullscreen_mode;
6284 video.fullscreen_enabled = FALSE; /* force new fullscreen mode */
6287 /* toggle fullscreen */
6288 ChangeVideoModeIfNeeded(setup.fullscreen);
6290 setup.fullscreen = video.fullscreen_enabled;
6292 /* restore backbuffer content from temporary backbuffer backup bitmap */
6293 BlitBitmap(tmp_backbuffer, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
6295 FreeBitmap(tmp_backbuffer);
6298 /* update visible window/screen */
6299 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
6301 redraw_mask = REDRAW_ALL;