X-Git-Url: https://git.artsoft.org/?p=rocksndiamonds.git;a=blobdiff_plain;f=src%2Feditor.c;h=093b229083d6f4e3539ebfd28ccd0559718e21c2;hp=7757fe51e4053a7beb27682fba4bcb42d84c4b7f;hb=1fc11ecd0789cf873639c9bbbff6f72656abac08;hpb=12a8fd3a64d6bee5ca5f5b89e4a00b49d78bbd2c diff --git a/src/editor.c b/src/editor.c index 7757fe51..093b2290 100644 --- a/src/editor.c +++ b/src/editor.c @@ -65,8 +65,10 @@ #define ED_ELEMENTLIST_YPOS (editor.palette.y) #define ED_ELEMENTLIST_XSIZE (graphic_info[IMG_EDITOR_PALETTE_BUTTON].width) #define ED_ELEMENTLIST_YSIZE (graphic_info[IMG_EDITOR_PALETTE_BUTTON].height) -#define ED_ELEMENTLIST_BUTTONS_HORIZ (editor.palette.cols) -#define ED_ELEMENTLIST_BUTTONS_VERT (editor.palette.rows) +#define ED_ELEMENTLIST_COLS MAX(1, editor.palette.cols) +#define ED_ELEMENTLIST_ROWS MAX(1, editor.palette.rows) +#define ED_ELEMENTLIST_BUTTONS_HORIZ (ED_ELEMENTLIST_COLS) +#define ED_ELEMENTLIST_BUTTONS_VERT (ED_ELEMENTLIST_ROWS) #define ED_NUM_ELEMENTLIST_BUTTONS (ED_ELEMENTLIST_BUTTONS_HORIZ * \ ED_ELEMENTLIST_BUTTONS_VERT) @@ -642,6 +644,8 @@ enum GADGET_ID_RANDOM_BALL_CONTENT, GADGET_ID_INITIAL_BALL_STATE, GADGET_ID_GROW_INTO_DIGGABLE, + GADGET_ID_SB_FIELDS_NEEDED, + GADGET_ID_SB_OBJECTS_NEEDED, GADGET_ID_AUTO_EXIT_SOKOBAN, GADGET_ID_SOLVED_BY_ONE_PLAYER, GADGET_ID_CONTINUOUS_SNAPPING, @@ -945,6 +949,8 @@ enum ED_CHECKBUTTON_ID_RANDOM_BALL_CONTENT, ED_CHECKBUTTON_ID_INITIAL_BALL_STATE, ED_CHECKBUTTON_ID_GROW_INTO_DIGGABLE, + ED_CHECKBUTTON_ID_SB_FIELDS_NEEDED, + ED_CHECKBUTTON_ID_SB_OBJECTS_NEEDED, ED_CHECKBUTTON_ID_AUTO_EXIT_SOKOBAN, ED_CHECKBUTTON_ID_SOLVED_BY_ONE_PLAYER, ED_CHECKBUTTON_ID_CONTINUOUS_SNAPPING, @@ -3068,10 +3074,24 @@ static struct }, { ED_ELEMENT_SETTINGS_XPOS(0), ED_ELEMENT_SETTINGS_YPOS(0), + GADGET_ID_SB_FIELDS_NEEDED, GADGET_ID_NONE, + &level.sb_fields_needed, + NULL, NULL, + "all fields need to be filled", "require all SB fields to be solved" + }, + { + ED_ELEMENT_SETTINGS_XPOS(0), ED_ELEMENT_SETTINGS_YPOS(0), + GADGET_ID_SB_OBJECTS_NEEDED, GADGET_ID_NONE, + &level.sb_objects_needed, + NULL, NULL, + "all objects need to be placed", "require all SB objects to be solved" + }, + { + ED_ELEMENT_SETTINGS_XPOS(0), ED_ELEMENT_SETTINGS_YPOS(1), GADGET_ID_AUTO_EXIT_SOKOBAN, GADGET_ID_NONE, &level.auto_exit_sokoban, NULL, NULL, - "exit level if all fields solved", "automatically finish Sokoban levels" + "exit level if all tasks solved", "automatically finish Sokoban levels" }, { ED_ELEMENT_SETTINGS_XPOS(0), ED_ELEMENT_SETTINGS_YPOS(14), @@ -3778,6 +3798,8 @@ static int use_permanent_palette = TRUE; #define PYSIZE (use_permanent_palette ? DYSIZE : SYSIZE) // forward declaration for internal use +static void CopyBrushToCursor(int, int); +static void DeleteBrushFromCursor(void); static void ModifyEditorCounterValue(int, int); static void ModifyEditorCounterLimits(int, int, int); static void ModifyEditorSelectboxValue(int, int); @@ -5738,7 +5760,7 @@ static void ReinitializeElementList(void) { // required for correct padding of palette headline buttons if (*editor_elements_info[i].headline_list_size > 0) - num_editor_elements += editor.palette.cols; + num_editor_elements += ED_ELEMENTLIST_COLS; for (j = 0; j < *editor_elements_info[i].headline_list_size; j++) { @@ -5755,8 +5777,8 @@ static void ReinitializeElementList(void) // required for correct padding of palette element buttons int element_list_size = *editor_elements_info[i].element_list_size; int element_rows = - (element_list_size + editor.palette.cols - 1) / editor.palette.cols; - int element_buttons = editor.palette.cols * element_rows; + (element_list_size + ED_ELEMENTLIST_COLS - 1) / ED_ELEMENTLIST_COLS; + int element_buttons = ED_ELEMENTLIST_COLS * element_rows; num_editor_elements += element_buttons; } @@ -5788,7 +5810,7 @@ static void ReinitializeElementList(void) { // required for correct padding of palette headline buttons int headline_size = (*editor_elements_info[i].headline_list_size > 0 ? - editor.palette.cols : 0); + ED_ELEMENTLIST_COLS : 0); for (j = 0; j < headline_size; j++) { @@ -5810,8 +5832,8 @@ static void ReinitializeElementList(void) // required for correct padding of palette element buttons int element_list_size = *editor_elements_info[i].element_list_size; int element_rows = - (element_list_size + editor.palette.cols - 1) / editor.palette.cols; - int element_buttons = editor.palette.cols * element_rows; + (element_list_size + ED_ELEMENTLIST_COLS - 1) / ED_ELEMENTLIST_COLS; + int element_buttons = ED_ELEMENTLIST_COLS * element_rows; // copy all elements from element list for (j = 0; j < element_list_size; j++) @@ -7126,7 +7148,10 @@ void CreateLevelEditorGadgets(void) right_gadget_border = checked_calloc(num_editor_gadgets * sizeof(int)); - editor_el_empty = checked_calloc(ED_NUM_ELEMENTLIST_BUTTONS * sizeof(int)); + // set number of empty (padding) element buttons to maximum number of buttons + num_editor_el_empty = ED_NUM_ELEMENTLIST_BUTTONS; + + editor_el_empty = checked_calloc(num_editor_el_empty * sizeof(int)); editor_el_empty_ptr = editor_el_empty; use_permanent_palette = !editor.palette.show_as_separate_screen; @@ -8478,29 +8503,31 @@ static boolean useEditorDoorAnimation(void) return (door_1_viewport_unchanged && door_1_contains_toolbox); } +static void DrawEditorDoorBackground(int graphic, int x, int y, + int width, int height) +{ + struct GraphicInfo *g = &graphic_info[graphic]; + + if (g->bitmap != NULL) + BlitBitmap(g->bitmap, drawto, g->src_x, g->src_y, + MIN(width, g->width), MIN(height, g->height), x, y); + else + ClearRectangle(drawto, x, y, width, height); +} + static void DrawEditorDoorContent(void) { // needed for gadgets drawn on background (like palette scrollbar) SetDoorBackgroundImage(IMG_UNDEFINED); // copy default editor door content to main double buffer - BlitBitmap(graphic_info[IMG_BACKGROUND_PALETTE].bitmap, drawto, - graphic_info[IMG_BACKGROUND_PALETTE].src_x, - graphic_info[IMG_BACKGROUND_PALETTE].src_y, - MIN(DXSIZE, graphic_info[IMG_BACKGROUND_PALETTE].width), - MIN(DYSIZE, graphic_info[IMG_BACKGROUND_PALETTE].height), - DX, DY); + DrawEditorDoorBackground(IMG_BACKGROUND_PALETTE, DX, DY, DXSIZE, DYSIZE); // draw bigger door DrawSpecialEditorDoor(); // draw new control window - BlitBitmap(graphic_info[IMG_BACKGROUND_TOOLBOX].bitmap, drawto, - graphic_info[IMG_BACKGROUND_TOOLBOX].src_x, - graphic_info[IMG_BACKGROUND_TOOLBOX].src_y, - MIN(EXSIZE, graphic_info[IMG_BACKGROUND_TOOLBOX].width), - MIN(EYSIZE, graphic_info[IMG_BACKGROUND_TOOLBOX].height), - EX, EY); + DrawEditorDoorBackground(IMG_BACKGROUND_TOOLBOX, EX, EY, EXSIZE, EYSIZE); // draw all toolbox gadgets to editor doors MapControlButtons(); @@ -8519,7 +8546,7 @@ void DrawLevelEd(void) FadeSoundsAndMusic(); - if (CheckIfGlobalBorderOrPlayfieldViewportHasChanged()) + if (CheckFadeAll()) fade_mask = REDRAW_ALL; FadeOut(fade_mask); @@ -9725,10 +9752,43 @@ static void SetAutomaticNumberOfGemsNeeded(void) { int element = Feld[x][y]; - if (IS_GEM(element) || - element == EL_MM_KETTLE || - element == EL_DF_CELL) - level.gems_needed++; + switch (element) + { + case EL_EMERALD: + case EL_EMERALD_YELLOW: + case EL_EMERALD_RED: + case EL_EMERALD_PURPLE: + case EL_BD_DIAMOND: + case EL_WALL_EMERALD: + case EL_WALL_EMERALD_YELLOW: + case EL_WALL_EMERALD_RED: + case EL_WALL_EMERALD_PURPLE: + case EL_WALL_BD_DIAMOND: + case EL_NUT: + case EL_SP_INFOTRON: + case EL_MM_KETTLE: + case EL_DF_CELL: + level.gems_needed++; + break; + + case EL_DIAMOND: + case EL_WALL_DIAMOND: + level.gems_needed += 3; + break; + + case EL_PEARL: + case EL_WALL_PEARL: + level.gems_needed += 5; + break; + + case EL_CRYSTAL: + case EL_WALL_CRYSTAL: + level.gems_needed += 8; + break; + + default: + break; + } } } @@ -9931,10 +9991,22 @@ static void DrawPropertiesConfig(void) MapCheckbuttonGadget(ED_CHECKBUTTON_ID_GROW_INTO_DIGGABLE); } + if (properties_element == EL_SOKOBAN_FIELD_EMPTY) + MapCheckbuttonGadget(ED_CHECKBUTTON_ID_SB_FIELDS_NEEDED); + + if (properties_element == EL_SOKOBAN_OBJECT) + MapCheckbuttonGadget(ED_CHECKBUTTON_ID_SB_OBJECTS_NEEDED); + if (properties_element == EL_SOKOBAN_OBJECT || properties_element == EL_SOKOBAN_FIELD_EMPTY || properties_element == EL_SOKOBAN_FIELD_FULL) + { + checkbutton_info[ED_CHECKBUTTON_ID_AUTO_EXIT_SOKOBAN].y = + ED_ELEMENT_SETTINGS_XPOS(properties_element == EL_SOKOBAN_FIELD_FULL ? + 0 : 1); + MapCheckbuttonGadget(ED_CHECKBUTTON_ID_AUTO_EXIT_SOKOBAN); + } if (IS_BALLOON_ELEMENT(properties_element)) MapSelectboxGadget(ED_SELECTBOX_ID_WIND_DIRECTION); @@ -10804,7 +10876,6 @@ static void SetElementIntelliDraw(int x, int y, int new_element, }; static int last_x = -1; static int last_y = -1; - int old_element = IntelliDrawBuffer[x][y]; if (new_element == EL_UNDEFINED) { @@ -10814,6 +10885,8 @@ static void SetElementIntelliDraw(int x, int y, int new_element, return; } + int old_element = IntelliDrawBuffer[x][y]; + if (IS_TUBE(new_element)) { int last_element_new = EL_UNDEFINED; @@ -11588,11 +11661,21 @@ static void ResetIntelliDraw(void) static boolean draw_mode_hires = FALSE; +static boolean isHiresTileElement(int element) +{ + return (IS_MM_WALL(element) || element == EL_EMPTY); +} + +static boolean isHiresDrawElement(int element) +{ + return (IS_MM_WALL_EDITOR(element) || element == EL_EMPTY); +} + static void SetDrawModeHiRes(int element) { draw_mode_hires = (level.game_engine_type == GAME_ENGINE_TYPE_MM && - (IS_MM_WALL_EDITOR(element) || element == EL_EMPTY)); + isHiresDrawElement(element)); } static boolean getDrawModeHiRes(void) @@ -11865,12 +11948,23 @@ static void SelectArea(int from_x, int from_y, int to_x, int to_y, } // values for CopyBrushExt() -#define CB_AREA_TO_BRUSH 0 -#define CB_BRUSH_TO_CURSOR 1 -#define CB_BRUSH_TO_LEVEL 2 -#define CB_DELETE_OLD_CURSOR 3 -#define CB_DUMP_BRUSH 4 -#define CB_DUMP_BRUSH_SMALL 5 +#define CB_AREA_TO_BRUSH 0 +#define CB_BRUSH_TO_CURSOR 1 +#define CB_BRUSH_TO_LEVEL 2 +#define CB_DELETE_OLD_CURSOR 3 +#define CB_DUMP_BRUSH 4 +#define CB_DUMP_BRUSH_SMALL 5 +#define CB_CLIPBOARD_TO_BRUSH 6 +#define CB_BRUSH_TO_CLIPBOARD 7 +#define CB_BRUSH_TO_CLIPBOARD_SMALL 8 +#define CB_UPDATE_BRUSH_POSITION 9 + +#define MAX_CB_PART_SIZE 10 +#define MAX_CB_LINE_SIZE (MAX_LEV_FIELDX + 1) // text plus newline +#define MAX_CB_NUM_LINES (MAX_LEV_FIELDY) +#define MAX_CB_TEXT_SIZE (MAX_CB_LINE_SIZE * \ + MAX_CB_NUM_LINES * \ + MAX_CB_PART_SIZE) static void DrawBrushElement(int sx, int sy, int element, boolean change_level) { @@ -11883,26 +11977,31 @@ static void CopyBrushExt(int from_x, int from_y, int to_x, int to_y, static short brush_buffer[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; static int brush_width, brush_height; static int last_cursor_x = -1, last_cursor_y = -1; - static boolean delete_old_brush; + static boolean delete_old_brush = FALSE; int new_element = BUTTON_ELEMENT(button); int x, y; if (mode == CB_DUMP_BRUSH || - mode == CB_DUMP_BRUSH_SMALL) + mode == CB_DUMP_BRUSH_SMALL || + mode == CB_BRUSH_TO_CLIPBOARD || + mode == CB_BRUSH_TO_CLIPBOARD_SMALL) { - if (!draw_with_brush) - { - Error(ERR_WARN, "no brush selected"); - + if (edit_mode != ED_MODE_DRAWING) return; - } - for (y = 0; y < brush_height; y++) + char part[MAX_CB_PART_SIZE + 1] = ""; + char text[MAX_CB_TEXT_SIZE + 1] = ""; + int width = (draw_with_brush ? brush_width : lev_fieldx); + int height = (draw_with_brush ? brush_height : lev_fieldy); + + for (y = 0; y < height; y++) { - for (x = 0; x < brush_width; x++) + for (x = 0; x < width; x++) { - int element = brush_buffer[x][y]; + int element = (draw_with_brush ? brush_buffer[x][y] : Feld[x][y]); int element_mapped = element; + char *prefix = (mode == CB_DUMP_BRUSH || + mode == CB_BRUSH_TO_CLIPBOARD ? "`" : "¸"); if (IS_CUSTOM_ELEMENT(element)) element_mapped = EL_CUSTOM_START; @@ -11911,13 +12010,176 @@ static void CopyBrushExt(int from_x, int from_y, int to_x, int to_y, else if (element >= NUM_FILE_ELEMENTS) element_mapped = EL_UNKNOWN; - // dump brush as level sketch text for the R'n'D forum: + // copy brush to level sketch text buffer for the R'n'D forum: // - large tiles: `xxx (0x60 ASCII) // - small tiles: ¸xxx (0xb8 ISO-8859-1, 0xc2b8 UTF-8) - printf("%s%03d", (mode == CB_DUMP_BRUSH ? "`" : "¸"), element_mapped); + snprintf(part, MAX_CB_PART_SIZE + 1, "%s%03d", prefix, element_mapped); + strcat(text, part); + } + + strcat(text, "\n"); + } + + if (mode == CB_BRUSH_TO_CLIPBOARD || + mode == CB_BRUSH_TO_CLIPBOARD_SMALL) + SDL_SetClipboardText(text); + else + printf("%s", text); + + return; + } + + if (mode == CB_CLIPBOARD_TO_BRUSH) + { + if (edit_mode != ED_MODE_DRAWING) + return; + + if (!SDL_HasClipboardText()) + { + Request("Clipboard is empty!", REQ_CONFIRM); + + return; + } + + boolean copy_to_brush = (draw_with_brush || + drawing_function == GADGET_ID_GRAB_BRUSH); + + // this will delete the old brush, if already drawing with a brush + if (copy_to_brush) + ClickOnGadget(level_editor_gadget[GADGET_ID_SINGLE_ITEMS], MB_LEFTBUTTON); + + // initialization is required for "odd" (incomplete) clipboard content + for (x = 0; x < MAX_LEV_FIELDX; x++) + for (y = 0; y < MAX_LEV_FIELDY; y++) + brush_buffer[x][y] = EL_EMPTY; + + brush_width = 0; + brush_height = 0; + x = 0; + y = 0; + + char *clipboard_text = SDL_GetClipboardText(); + char *ptr = clipboard_text; + boolean stop = FALSE; + + while (*ptr && !stop) + { + boolean prefix_found = FALSE; + + // level sketch element number prefixes (may be multi-byte characters) + char *prefix_list[] = { "`", "¸" }; + int i; + + for (i = 0; i < ARRAY_SIZE(prefix_list); i++) + { + char *prefix = prefix_list[i]; + + // check if string is large enough for prefix + if (strlen(ptr) < strlen(prefix)) + { + stop = TRUE; + + break; + } + + // check if string starts with prefix + if (strPrefix(ptr, prefix)) + { + ptr += strlen(prefix); + + prefix_found = TRUE; + + break; + } + } + + // continue with next character if prefix not found + if (!prefix_found) + { + ptr++; // !!! FIX THIS for real UTF-8 handling !!! + + continue; } - printf("\n"); + // continue with next character if prefix not found + if (strlen(ptr) < 3) + break; + + if (ptr[0] >= '0' && ptr[0] <= '9' && + ptr[1] >= '0' && ptr[1] <= '9' && + ptr[2] >= '0' && ptr[2] <= '9') + { + int element = ((ptr[0] - '0') * 100 + + (ptr[1] - '0') * 10 + + (ptr[2] - '0')); + + ptr += 3; + + if (element >= NUM_FILE_ELEMENTS) + element = EL_UNKNOWN; + + brush_buffer[x][y] = element; + + brush_width = MAX(x + 1, brush_width); + brush_height = MAX(y + 1, brush_height); + + x++; + + if (x >= MAX_LEV_FIELDX || *ptr == '\n') + { + x = 0; + y++; + + if (y >= MAX_LEV_FIELDY) + stop = TRUE; + } + } + } + + SDL_free(clipboard_text); + + if (brush_width == 0 || brush_height == 0) + { + Request("No level sketch found in clipboard!", REQ_CONFIRM); + + return; + } + + if (copy_to_brush) + { + struct GadgetInfo *gi = level_editor_gadget[GADGET_ID_DRAWING_LEVEL]; + int mx, my; + + SDL_GetMouseState(&mx, &my); + + // if inside drawing area, activate and draw brush at last mouse position + if (mx >= gi->x && mx < gi->x + gi->width && + my >= gi->y && my < gi->y + gi->height) + CopyBrushToCursor(last_cursor_x, last_cursor_y); + + draw_with_brush = TRUE; + } + else + { + char request[100]; + + sprintf(request, "Replace level with %dx%d level sketch from clipboard?", + brush_width, brush_height); + + if (!Request(request, REQ_ASK)) + return; + + for (x = 0; x < MAX_LEV_FIELDX; x++) + for (y = 0; y < MAX_LEV_FIELDY; y++) + Feld[x][y] = brush_buffer[x][y]; + + lev_fieldx = level.fieldx = brush_width; + lev_fieldy = level.fieldy = brush_height; + + SetBorderElement(); + + DrawEditModeWindow(); + CopyLevelToUndoBuffer(UNDO_IMMEDIATE); } return; @@ -11975,6 +12237,7 @@ static void CopyBrushExt(int from_x, int from_y, int to_x, int to_y, !IN_LEV_FIELD(cursor_x + level_xpos, cursor_y + level_ypos)) { delete_old_brush = FALSE; + return; } @@ -12012,8 +12275,15 @@ static void CopyBrushExt(int from_x, int from_y, int to_x, int to_y, last_cursor_x = cursor_x; last_cursor_y = cursor_y; + delete_old_brush = TRUE; } + + if (mode == CB_UPDATE_BRUSH_POSITION) + { + last_cursor_x = from_x; + last_cursor_y = from_y; + } } static void CopyAreaToBrush(int from_x, int from_y, int to_x, int to_y, @@ -12032,6 +12302,11 @@ static void CopyBrushToCursor(int x, int y) CopyBrushExt(x, y, 0, 0, 0, CB_BRUSH_TO_CURSOR); } +static void UpdateBrushPosition(int x, int y) +{ + CopyBrushExt(x, y, 0, 0, 0, CB_UPDATE_BRUSH_POSITION); +} + static void DeleteBrushFromCursor(void) { CopyBrushExt(0, 0, 0, 0, 0, CB_DELETE_OLD_CURSOR); @@ -12047,6 +12322,21 @@ void DumpBrush_Small(void) CopyBrushExt(0, 0, 0, 0, 0, CB_DUMP_BRUSH_SMALL); } +void CopyClipboardToBrush(void) +{ + CopyBrushExt(0, 0, 0, 0, 0, CB_CLIPBOARD_TO_BRUSH); +} + +void CopyBrushToClipboard(void) +{ + CopyBrushExt(0, 0, 0, 0, 0, CB_BRUSH_TO_CLIPBOARD); +} + +void CopyBrushToClipboard_Small(void) +{ + CopyBrushExt(0, 0, 0, 0, 0, CB_BRUSH_TO_CLIPBOARD_SMALL); +} + static void FloodFill(int from_x, int from_y, int fill_element) { FloodFillLevel(from_x, from_y, fill_element, Feld, lev_fieldx, lev_fieldy); @@ -12137,6 +12427,8 @@ static int DrawLevelText(int sx, int sy, char letter, int mode) case TEXT_SETCURSOR: DrawEditorElement(last_sx, last_sy, Feld[lx][ly]); DrawAreaBorder(sx, sy, sx, sy); + StartTextInput(SX + sx * ed_tilesize, SY + sy * ed_tilesize, + ed_tilesize, ed_tilesize); last_sx = sx; last_sy = sy; break; @@ -12172,7 +12464,7 @@ static int DrawLevelText(int sx, int sy, char letter, int mode) break; case TEXT_NEWLINE: - if (sy + 1 < ed_fieldy - 1 && ly + 1 < lev_fieldy - 1) + if (sy + 1 < ed_fieldy && ly + 1 < lev_fieldy) DrawLevelText(start_sx, sy + 1, 0, TEXT_SETCURSOR); else DrawLevelText(0, 0, 0, TEXT_END); @@ -12181,6 +12473,7 @@ static int DrawLevelText(int sx, int sy, char letter, int mode) case TEXT_END: CopyLevelToUndoBuffer(UNDO_IMMEDIATE); DrawEditorElement(sx, sy, Feld[lx][ly]); + StopTextInput(); typing = FALSE; break; @@ -12423,9 +12716,13 @@ static void HandleDrawingAreas(struct GadgetInfo *gi) } else if (!button_press_event) { + int old_element = (IN_LEV_FIELD(lx, ly) ? Feld[lx][ly] : EL_UNDEFINED); + boolean hires_drawing = (level.game_engine_type == GAME_ENGINE_TYPE_MM && + isHiresTileElement(old_element) && + isHiresDrawElement(new_element)); + // prevent handling events for every pixel position when moving mouse - if ((sx == last_sx && sy == last_sy && - !IS_MM_WALL_EDITOR(new_element) && new_element != EL_EMPTY) || + if ((sx == last_sx && sy == last_sy && !hires_drawing) || (sx2 == last_sx2 && sy2 == last_sy2)) return; } @@ -12495,13 +12792,37 @@ static void HandleDrawingAreas(struct GadgetInfo *gi) { SetDrawModeHiRes(new_element); - if (new_element == EL_PLAYER_1) + if (ELEM_IS_PLAYER(new_element)) { // remove player at old position for (y = 0; y < lev_fieldy; y++) + { for (x = 0; x < lev_fieldx; x++) - if (Feld[x][y] == EL_PLAYER_1) - SetElement(x, y, EL_EMPTY); + { + int old_element = Feld[x][y]; + + if (ELEM_IS_PLAYER(old_element)) + { + int replaced_with_element = + (old_element == EL_SOKOBAN_FIELD_PLAYER && + new_element == EL_PLAYER_1 ? EL_SOKOBAN_FIELD_EMPTY : + + old_element == EL_SOKOBAN_FIELD_PLAYER && + new_element == old_element ? EL_SOKOBAN_FIELD_EMPTY : + + new_element == EL_SOKOBAN_FIELD_PLAYER && + old_element == EL_PLAYER_1 ? EL_EMPTY : + + new_element >= EL_PLAYER_1 && + new_element <= EL_PLAYER_4 && + new_element == old_element ? EL_EMPTY : + + old_element); + + SetElement(x, y, replaced_with_element); + } + } + } } SetElementButton(lx, ly, dx, dy, new_element, button); @@ -14101,6 +14422,9 @@ static void HandleDrawingAreaInfo(struct GadgetInfo *gi) else DeleteBrushFromCursor(); } + + if (!draw_with_brush) + UpdateBrushPosition(sx, sy); } else if (actual_drawing_function == GADGET_ID_PICK_ELEMENT) {