+}
+
+static void DrawSizedWallExt_MM(int dst_x, int dst_y, int element, int tilesize,
+ int (*el2img_function)(int), boolean masked,
+ int element_bits_draw)
+{
+ int element_base = map_mm_wall_element(element);
+ int element_bits = (IS_DF_WALL(element) ?
+ element - EL_DF_WALL_START :
+ IS_MM_WALL(element) ?
+ element - EL_MM_WALL_START : EL_EMPTY) & 0x000f;
+ int graphic = el2img_function(element_base);
+ int tilesize_draw = tilesize / 2;
+ Bitmap *src_bitmap;
+ int src_x, src_y;
+ int i;
+
+ getSizedGraphicSource(graphic, 0, tilesize_draw, &src_bitmap, &src_x, &src_y);
+
+ for (i = 0; i < 4; i++)
+ {
+ int dst_draw_x = dst_x + (i % 2) * tilesize_draw;
+ int dst_draw_y = dst_y + (i / 2) * tilesize_draw;
+
+ if (!(element_bits_draw & (1 << i)))
+ continue;
+
+ if (element_bits & (1 << i))
+ {
+ if (masked)
+ BlitBitmapMasked(src_bitmap, drawto, src_x, src_y,
+ tilesize_draw, tilesize_draw, dst_draw_x, dst_draw_y);
+ else
+ BlitBitmap(src_bitmap, drawto, src_x, src_y,
+ tilesize_draw, tilesize_draw, dst_draw_x, dst_draw_y);
+ }
+ else
+ {
+ if (!masked)
+ ClearRectangle(drawto, dst_draw_x, dst_draw_y,
+ tilesize_draw, tilesize_draw);
+ }
+ }
+}
+
+void DrawSizedWallParts_MM(int x, int y, int element, int tilesize,
+ boolean masked, int element_bits_draw)
+{
+ DrawSizedWallExt_MM(SX + x * tilesize, SY + y * tilesize,
+ element, tilesize, el2edimg, masked, element_bits_draw);
+}
+
+static void DrawSizedWall_MM(int dst_x, int dst_y, int element, int tilesize,
+ int (*el2img_function)(int))
+{
+ DrawSizedWallExt_MM(dst_x, dst_y, element, tilesize, el2img_function, FALSE,
+ 0x000f);
+}
+
+static void DrawSizedElementExt(int x, int y, int element, int tilesize,
+ boolean masked)
+{
+ if (IS_MM_WALL(element))
+ {
+ DrawSizedWallExt_MM(SX + x * tilesize, SY + y * tilesize,
+ element, tilesize, el2edimg, masked, 0x000f);
+ }
+ else
+ {
+ int graphic = el2edimg(element);
+
+ if (masked)
+ DrawSizedGraphicThruMask(x, y, graphic, 0, tilesize);
+ else
+ DrawSizedGraphic(x, y, graphic, 0, tilesize);
+ }
+}
+
+void DrawSizedElement(int x, int y, int element, int tilesize)
+{
+ DrawSizedElementExt(x, y, element, tilesize, FALSE);
+}
+
+void DrawSizedElementThruMask(int x, int y, int element, int tilesize)
+{
+ DrawSizedElementExt(x, y, element, tilesize, TRUE);
+}
+
+void DrawMiniElement(int x, int y, int element)
+{
+ int graphic;
+
+ graphic = el2edimg(element);
+ DrawMiniGraphic(x, y, graphic);
+}
+
+void DrawSizedElementOrWall(int sx, int sy, int scroll_x, int scroll_y,
+ int tilesize)
+{
+ int x = sx + scroll_x, y = sy + scroll_y;
+
+ if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
+ DrawSizedElement(sx, sy, EL_EMPTY, tilesize);
+ else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
+ DrawSizedElement(sx, sy, Tile[x][y], tilesize);
+ else
+ DrawSizedGraphic(sx, sy, el2edimg(getBorderElement(x, y)), 0, tilesize);
+}
+
+void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
+{
+ int x = sx + scroll_x, y = sy + scroll_y;
+
+ if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
+ DrawMiniElement(sx, sy, EL_EMPTY);
+ else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
+ DrawMiniElement(sx, sy, Tile[x][y]);
+ else
+ DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
+}
+
+static void DrawEnvelopeBackgroundTiles(int graphic, int startx, int starty,
+ int x, int y, int xsize, int ysize,
+ int tile_width, int tile_height)
+{
+ Bitmap *src_bitmap;
+ int src_x, src_y;
+ int dst_x = startx + x * tile_width;
+ int dst_y = starty + y * tile_height;
+ int width = graphic_info[graphic].width;
+ int height = graphic_info[graphic].height;
+ int inner_width_raw = MAX(width - 2 * tile_width, tile_width);
+ int inner_height_raw = MAX(height - 2 * tile_height, tile_height);
+ int inner_width = inner_width_raw - (inner_width_raw % tile_width);
+ int inner_height = inner_height_raw - (inner_height_raw % tile_height);
+ int inner_sx = (width >= 3 * tile_width ? tile_width : 0);
+ int inner_sy = (height >= 3 * tile_height ? tile_height : 0);
+ boolean draw_masked = graphic_info[graphic].draw_masked;
+
+ getFixedGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
+
+ if (src_bitmap == NULL || width < tile_width || height < tile_height)
+ {
+ ClearRectangle(drawto, dst_x, dst_y, tile_width, tile_height);
+ return;
+ }
+
+ src_x += (x == 0 ? 0 : x == xsize - 1 ? width - tile_width :
+ inner_sx + (x - 1) * tile_width % inner_width);
+ src_y += (y == 0 ? 0 : y == ysize - 1 ? height - tile_height :
+ inner_sy + (y - 1) * tile_height % inner_height);
+
+ if (draw_masked)
+ BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, tile_width, tile_height,
+ dst_x, dst_y);
+ else
+ BlitBitmap(src_bitmap, drawto, src_x, src_y, tile_width, tile_height,
+ dst_x, dst_y);
+}
+
+static void DrawEnvelopeBackground(int graphic, int startx, int starty,
+ int x, int y, int xsize, int ysize,
+ int font_nr)
+{
+ int font_width = getFontWidth(font_nr);
+ int font_height = getFontHeight(font_nr);
+
+ DrawEnvelopeBackgroundTiles(graphic, startx, starty, x, y, xsize, ysize,
+ font_width, font_height);
+}
+
+static void AnimateEnvelope(int envelope_nr, int anim_mode, int action)
+{
+ int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
+ Bitmap *src_bitmap = graphic_info[graphic].bitmap;
+ int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
+ boolean ffwd_delay = (tape.playing && tape.fast_forward);
+ boolean no_delay = (tape.warp_forward);
+ int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
+ int anim_delay_value = MAX(1, (no_delay ? 0 : frame_delay_value) / 2);
+ DelayCounter anim_delay = { anim_delay_value };
+ int font_nr = FONT_ENVELOPE_1 + envelope_nr;
+ int font_width = getFontWidth(font_nr);
+ int font_height = getFontHeight(font_nr);
+ int max_xsize = level.envelope[envelope_nr].xsize;
+ int max_ysize = level.envelope[envelope_nr].ysize;
+ int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
+ int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
+ int xend = max_xsize;
+ int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
+ int xstep = (xstart < xend ? 1 : 0);
+ int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
+ int start = 0;
+ int end = MAX(xend - xstart, yend - ystart);
+ int i;
+
+ for (i = start; i <= end; i++)
+ {
+ int last_frame = end; // last frame of this "for" loop
+ int x = xstart + i * xstep;
+ int y = ystart + i * ystep;
+ int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
+ int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
+ int sx = SX + (SXSIZE - xsize * font_width) / 2;
+ int sy = SY + (SYSIZE - ysize * font_height) / 2;
+ int xx, yy;
+
+ SetDrawtoField(DRAW_TO_FIELDBUFFER);
+
+ BlitScreenToBitmap(backbuffer);
+
+ SetDrawtoField(DRAW_TO_BACKBUFFER);
+
+ for (yy = 0; yy < ysize; yy++)
+ for (xx = 0; xx < xsize; xx++)
+ DrawEnvelopeBackground(graphic, sx, sy, xx, yy, xsize, ysize, font_nr);
+
+ DrawTextArea(sx + font_width, sy + font_height,
+ level.envelope[envelope_nr].text, font_nr, max_xsize,
+ xsize - 2, ysize - 2, 0, mask_mode,
+ level.envelope[envelope_nr].autowrap,
+ level.envelope[envelope_nr].centered, FALSE);
+
+ redraw_mask |= REDRAW_FIELD;
+ BackToFront();
+
+ SkipUntilDelayReached(&anim_delay, &i, last_frame);
+ }
+
+ ClearAutoRepeatKeyEvents();
+}
+
+void ShowEnvelope(int envelope_nr)
+{
+ int element = EL_ENVELOPE_1 + envelope_nr;
+ int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
+ int sound_opening = element_info[element].sound[ACTION_OPENING];
+ int sound_closing = element_info[element].sound[ACTION_CLOSING];
+ boolean ffwd_delay = (tape.playing && tape.fast_forward);
+ boolean no_delay = (tape.warp_forward);
+ int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
+ int wait_delay_value = (no_delay ? 0 : normal_delay_value);
+ int anim_mode = graphic_info[graphic].anim_mode;
+ int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
+ anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
+ boolean overlay_enabled = GetOverlayEnabled();
+
+ game.envelope_active = TRUE; // needed for RedrawPlayfield() events
+
+ SetOverlayEnabled(FALSE);
+ UnmapAllGadgets();
+
+ PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
+
+ if (anim_mode == ANIM_DEFAULT)
+ AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_OPENING);
+
+ AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_OPENING);
+
+ if (tape.playing)
+ Delay_WithScreenUpdates(wait_delay_value);
+ else
+ WaitForEventToContinue();
+
+ RemapAllGadgets();
+ SetOverlayEnabled(overlay_enabled);
+
+ PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
+
+ if (anim_mode != ANIM_NONE)
+ AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_CLOSING);
+
+ if (anim_mode == ANIM_DEFAULT)
+ AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_CLOSING);
+
+ game.envelope_active = FALSE;
+
+ SetDrawtoField(DRAW_TO_FIELDBUFFER);
+
+ redraw_mask |= REDRAW_FIELD;
+ BackToFront();
+}
+
+static void PrepareEnvelopeRequestToScreen(Bitmap *bitmap, int sx, int sy,
+ int xsize, int ysize)
+{
+ if (!global.use_envelope_request)
+ return;
+
+ if (request.bitmap == NULL ||
+ xsize > request.xsize ||
+ ysize > request.ysize)
+ {
+ if (request.bitmap != NULL)
+ FreeBitmap(request.bitmap);
+
+ request.bitmap = CreateBitmap(xsize, ysize, DEFAULT_DEPTH);
+
+ SDL_Surface *surface = request.bitmap->surface;
+
+ if ((request.bitmap->surface_masked = SDLGetNativeSurface(surface)) == NULL)
+ Fail("SDLGetNativeSurface() failed");
+ }
+
+ BlitBitmap(bitmap, request.bitmap, sx, sy, xsize, ysize, 0, 0);
+
+ // create masked surface for request bitmap, if needed
+ if (graphic_info[IMG_BACKGROUND_REQUEST].draw_masked)
+ {
+ SDL_Surface *surface = request.bitmap->surface;
+ SDL_Surface *surface_masked = request.bitmap->surface_masked;
+
+ SDLBlitSurface(surface, surface_masked, 0, 0, xsize, ysize, 0, 0);
+ SDL_SetColorKey(surface_masked, SET_TRANSPARENT_PIXEL,
+ SDL_MapRGB(surface_masked->format, 0x00, 0x00, 0x00));
+ }
+
+ SDLFreeBitmapTextures(request.bitmap);
+ SDLCreateBitmapTextures(request.bitmap);
+
+ ResetBitmapAlpha(request.bitmap);
+
+ // set envelope request run-time values
+ request.sx = sx;
+ request.sy = sy;
+ request.xsize = xsize;
+ request.ysize = ysize;
+}
+
+void DrawEnvelopeRequestToScreen(int drawing_target)
+{
+ if (global.use_envelope_request &&
+ game.request_active &&
+ drawing_target == DRAW_TO_SCREEN)
+ {
+ struct GraphicInfo *g = &graphic_info[IMG_BACKGROUND_REQUEST];
+
+ SetBitmapAlphaNextBlit(request.bitmap, g->alpha);
+
+ if (g->draw_masked)
+ BlitToScreenMasked(request.bitmap, 0, 0, request.xsize, request.ysize,
+ request.sx, request.sy);
+ else
+ BlitToScreen(request.bitmap, 0, 0, request.xsize, request.ysize,
+ request.sx, request.sy);
+ }
+}
+
+static void setRequestBasePosition(int *x, int *y)
+{
+ int sx_base, sy_base;
+
+ if (request.x != -1)
+ sx_base = request.x;
+ else if (request.align == ALIGN_LEFT)
+ sx_base = SX;
+ else if (request.align == ALIGN_RIGHT)
+ sx_base = SX + SXSIZE;
+ else
+ sx_base = SX + SXSIZE / 2;
+
+ if (request.y != -1)
+ sy_base = request.y;
+ else if (request.valign == VALIGN_TOP)
+ sy_base = SY;
+ else if (request.valign == VALIGN_BOTTOM)
+ sy_base = SY + SYSIZE;
+ else
+ sy_base = SY + SYSIZE / 2;
+
+ *x = sx_base;
+ *y = sy_base;
+}
+
+static void setRequestPositionExt(int *x, int *y, int width, int height,
+ boolean add_border_size)
+{
+ int border_size = request.border_size;
+ int sx_base, sy_base;
+ int sx, sy;
+
+ setRequestBasePosition(&sx_base, &sy_base);
+
+ if (request.align == ALIGN_LEFT)
+ sx = sx_base;
+ else if (request.align == ALIGN_RIGHT)
+ sx = sx_base - width;
+ else
+ sx = sx_base - width / 2;
+
+ if (request.valign == VALIGN_TOP)
+ sy = sy_base;
+ else if (request.valign == VALIGN_BOTTOM)
+ sy = sy_base - height;
+ else
+ sy = sy_base - height / 2;
+
+ sx = MAX(0, MIN(sx, WIN_XSIZE - width));
+ sy = MAX(0, MIN(sy, WIN_YSIZE - height));
+
+ if (add_border_size)
+ {
+ sx += border_size;
+ sy += border_size;
+ }
+
+ *x = sx;
+ *y = sy;
+}
+
+static void setRequestPosition(int *x, int *y, boolean add_border_size)
+{
+ setRequestPositionExt(x, y, request.width, request.height, add_border_size);
+}
+
+static void DrawEnvelopeRequestText(int sx, int sy, char *text)
+{
+ char *text_final = text;
+ char *text_door_style = NULL;
+ int graphic = IMG_BACKGROUND_REQUEST;
+ Bitmap *src_bitmap = graphic_info[graphic].bitmap;
+ int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
+ int font_nr = FONT_REQUEST;
+ int font_width = getFontWidth(font_nr);
+ int font_height = getFontHeight(font_nr);
+ int border_size = request.border_size;
+ int line_spacing = request.line_spacing;
+ int line_height = font_height + line_spacing;
+ int max_text_width = request.width - 2 * border_size;
+ int max_text_height = request.height - 2 * border_size;
+ int line_length = max_text_width / font_width;
+ int max_lines = max_text_height / line_height;
+ int text_width = line_length * font_width;
+ int sx_offset = border_size;
+ int sy_offset = border_size;
+
+ // force DOOR font inside door area
+ SetFontStatus(GAME_MODE_PSEUDO_DOOR);
+
+ if (request.centered)
+ sx_offset = (request.width - text_width) / 2;
+
+ if (request.wrap_single_words && !request.autowrap)
+ {
+ char *src_text_ptr, *dst_text_ptr;
+
+ if (maxWordLengthInRequestString(text) > line_length)
+ {
+ font_nr = FONT_REQUEST_NARROW;
+ font_width = getFontWidth(font_nr);
+ line_length = max_text_width / font_width;
+ }
+
+ text_door_style = checked_malloc(2 * strlen(text) + 1);
+
+ src_text_ptr = text;
+ dst_text_ptr = text_door_style;
+
+ while (*src_text_ptr)
+ {
+ if (*src_text_ptr == ' ' ||
+ *src_text_ptr == '?' ||
+ *src_text_ptr == '!')
+ *dst_text_ptr++ = '\n';
+
+ if (*src_text_ptr != ' ')
+ *dst_text_ptr++ = *src_text_ptr;
+
+ src_text_ptr++;
+ }
+
+ *dst_text_ptr = '\0';
+
+ text_final = text_door_style;
+ }