From ca328d339730f8f20a8d6b5e1d83b27f4882fb7a Mon Sep 17 00:00:00 2001 From: Vankata453 <78196474+Vankata453@users.noreply.github.com> Date: Fri, 18 Oct 2024 00:55:32 +0300 Subject: [PATCH] Editor: Support multiple autotilesets per tile Tiles can now be present in multiple autotilesets in the same tileset. They would be autotileable with all (max. 10) autotilesets they are included in. The editor allows for pressing Ctrl+1, Ctrl+2, etc... up until Ctrl+9 to allow for autotiling a tile with additional 9 autotilesets. This is visually indicated in the autotile help strings. --- data/images/autotiles.satc | 4 +- src/editor/editor.cpp | 6 ++ src/editor/editor.hpp | 2 + src/editor/overlay_widget.cpp | 157 +++++++++++++++++++++++++--------- src/editor/overlay_widget.hpp | 9 ++ src/editor/toolbox_widget.cpp | 2 + src/object/tilemap.cpp | 134 +++++++++++------------------ src/object/tilemap.hpp | 11 +-- src/supertux/autotile.hpp | 2 + src/supertux/tile_set.cpp | 27 ++++-- src/supertux/tile_set.hpp | 3 +- 11 files changed, 218 insertions(+), 139 deletions(-) diff --git a/data/images/autotiles.satc b/data/images/autotiles.satc index 44b7eec1162..cfe719b04f7 100644 --- a/data/images/autotiles.satc +++ b/data/images/autotiles.satc @@ -14,7 +14,7 @@ ;; | ;; V ;; Contains : -;; The autotileset name (unused as of writing these lines) : (name "snow") +;; The autotileset name (used as an indicator in the editor) : (name "snow") ;; The name of the autotileset is "snow". ;; The default tile ID (used if no tile matches any mask) : (default 11) ;; If a very special tile is needed (and it doesn't exist), it will use this tile (it's a center tile) by default. @@ -75,7 +75,7 @@ ;; (Contributor, 2020) ;; ;; -;; NOTE : A single id MUST NOT OCCUR MORE THAN ONE AUTOTILE IN THE ENTIRE FILE. +;; NOTE : A single id MUST NOT OCCUR IN MORE THAN ONE AUTOTILE IN AN AUTOTILESET. ;; Otherwise, the behavior is UNDEFINED. (supertux-autotiles diff --git a/src/editor/editor.cpp b/src/editor/editor.cpp index 4c9b0571c42..9c1bd1d4333 100644 --- a/src/editor/editor.cpp +++ b/src/editor/editor.cpp @@ -410,6 +410,12 @@ Editor::get_tileselect_move_mode() const return m_toolbox_widget->get_tileselect_move_mode(); } +void +Editor::update_autotileset() +{ + m_overlay_widget->update_autotileset(); +} + void Editor::scroll(const Vector& velocity) { diff --git a/src/editor/editor.hpp b/src/editor/editor.hpp index d31a5b80cae..5eec578fd42 100644 --- a/src/editor/editor.hpp +++ b/src/editor/editor.hpp @@ -124,6 +124,8 @@ class Editor final : public Screen, void check_deprecated_tiles(bool focus = false); bool has_deprecated_tiles() const { return m_has_deprecated_tiles; } + void update_autotileset(); + /** Checks whether the level can be saved and does not contain obvious issues (currently: check if main sector and a spawn point named "main" is present) */ diff --git a/src/editor/overlay_widget.cpp b/src/editor/overlay_widget.cpp index 6bf19cdd0fd..86864b02aae 100644 --- a/src/editor/overlay_widget.cpp +++ b/src/editor/overlay_widget.cpp @@ -16,6 +16,8 @@ #include "editor/overlay_widget.hpp" +#include + #include "editor/editor.hpp" #include "editor/node_marker.hpp" #include "editor/object_menu.hpp" @@ -53,6 +55,7 @@ EditorOverlayWidget::EditorOverlayWidget(Editor& editor) : m_editor(editor), m_hovered_tile(0, 0), m_hovered_tile_prev(0, 0), + m_last_hovered_tile(0, 0), m_sector_pos(0, 0), m_mouse_pos(0, 0), m_previous_mouse_pos(0, 0), @@ -66,6 +69,8 @@ EditorOverlayWidget::EditorOverlayWidget(Editor& editor) : m_selected_object(nullptr), m_edited_path(nullptr), m_last_node_marker(nullptr), + m_available_autotilesets(), + m_current_autotileset(0), m_object_tip(new Tip()), m_obj_mouse_desync(0, 0), m_rectangle_preview(new TileSelection()), @@ -170,7 +175,7 @@ EditorOverlayWidget::autotile(const Vector& pos, uint32_t tile) if (!tilemap || !is_position_inside_tilemap(tilemap, pos)) return; tilemap->save_state(); - tilemap->autotile(static_cast(pos.x), static_cast(pos.y), tile); + tilemap->autotile(static_cast(pos.x), static_cast(pos.y), tile, get_current_autotileset()); } void @@ -196,7 +201,7 @@ EditorOverlayWidget::autotile_corner(const Vector& pos, uint32_t tile, if (!tilemap || !is_position_inside_tilemap(tilemap, pos)) return; tilemap->save_state(); - tilemap->autotile_corner(static_cast(pos.x), static_cast(pos.y), tile, op); + tilemap->autotile_corner(static_cast(pos.x), static_cast(pos.y), tile, get_current_autotileset(), op); } void @@ -231,25 +236,27 @@ EditorOverlayWidget::put_tile(const Vector& target_tile) { for (add_tile.y = static_cast(tiles->m_height) - 1.0f; add_tile.y >= 0; add_tile.y--) { - uint32_t tile = tiles->pos(static_cast(add_tile.x), static_cast(add_tile.y)); - auto tilemap = m_editor.get_selected_tilemap(); - if (g_config->editor_autotile_mode && ((tilemap && tilemap->get_autotileset(tile)) || tile == 0)) + if (g_config->editor_autotile_mode) { - if (tile == 0) - { - tilemap->autotile_erase(target_tile + add_tile, hovered_corner + add_tile); - } - else if (tilemap->get_autotileset(tile)->is_corner()) + AutotileSet* autotileset = get_current_autotileset(); + if (autotileset) { - input_autotile_corner(hovered_corner + add_tile, - tile, - target_tile + add_tile); - } - else - { - input_autotile(target_tile + add_tile, tile); + if (tile == 0) + { + m_editor.get_selected_tilemap()->autotile_erase(target_tile + add_tile, hovered_corner + add_tile, autotileset); + } + else if (get_current_autotileset()->is_corner()) + { + input_autotile_corner(hovered_corner + add_tile, + tile, + target_tile + add_tile); + } + else + { + input_autotile(target_tile + add_tile, tile); + } } } else @@ -418,10 +425,8 @@ EditorOverlayWidget::check_tiles_for_fill(uint32_t replace_tile, { if (g_config->editor_autotile_mode) { - return m_editor.get_tileset()->get_autotileset_from_tile(replace_tile) - == m_editor.get_tileset()->get_autotileset_from_tile(target_tile) - && m_editor.get_tileset()->get_autotileset_from_tile(replace_tile) - != m_editor.get_tileset()->get_autotileset_from_tile(third_tile); + return m_editor.get_tileset()->has_mutual_autotileset(replace_tile, target_tile) && + !m_editor.get_tileset()->has_mutual_autotileset(replace_tile, third_tile); } else { @@ -1072,6 +1077,8 @@ EditorOverlayWidget::update_tile_selection() } } } + + update_autotileset(); } bool @@ -1197,22 +1204,30 @@ bool EditorOverlayWidget::on_key_up(const SDL_KeyboardEvent& key) { auto sym = key.keysym.sym; - if (sym == SDLK_LSHIFT) { + if (sym == SDLK_LSHIFT) + { g_config->editor_snap_to_grid = !g_config->editor_snap_to_grid; } - if (sym == SDLK_LCTRL || sym == SDLK_RCTRL) + else if (sym == SDLK_LCTRL || sym == SDLK_RCTRL) { if (action_pressed) { g_config->editor_autotile_mode = !g_config->editor_autotile_mode; + m_current_autotileset = 0; action_pressed = false; } // Hovered objects depend on which keys are pressed hover_object(); } - if (sym == SDLK_LALT || sym == SDLK_RALT) { + else if (sym == SDLK_LALT || sym == SDLK_RALT) + { alt_pressed = false; } + else if (sym > SDLK_0 && sym <= SDLK_9) + { + if (m_current_autotileset == static_cast(sym - SDLK_0)) + m_current_autotileset = 0; + } return true; } @@ -1220,22 +1235,32 @@ bool EditorOverlayWidget::on_key_down(const SDL_KeyboardEvent& key) { auto sym = key.keysym.sym; - if (sym == SDLK_F8) { + + if (sym == SDLK_F8) + { g_config->editor_render_grid = !g_config->editor_render_grid; } - if (sym == SDLK_F7 || sym == SDLK_LSHIFT) { + else if (sym == SDLK_F7 || sym == SDLK_LSHIFT) + { g_config->editor_snap_to_grid = !g_config->editor_snap_to_grid; } - if (sym == SDLK_F5 || ((sym == SDLK_LCTRL || sym == SDLK_RCTRL) && !action_pressed)) + else if (sym == SDLK_F5 || ((sym == SDLK_LCTRL || sym == SDLK_RCTRL) && !action_pressed)) { g_config->editor_autotile_mode = !g_config->editor_autotile_mode; + m_current_autotileset = 0; action_pressed = true; // Hovered objects depend on which keys are pressed hover_object(); } - if (sym == SDLK_LALT || sym == SDLK_RALT) { + else if (sym == SDLK_LALT || sym == SDLK_RALT) + { alt_pressed = true; } + else if (sym > SDLK_0 && sym <= SDLK_9) + { + if (m_current_autotileset == 0) + m_current_autotileset = static_cast(sym - SDLK_0); + } return true; } @@ -1254,10 +1279,55 @@ EditorOverlayWidget::update_pos() m_editor.get_sector()->get_camera().get_translation(); m_hovered_tile = sp_to_tp(m_sector_pos); + if (m_last_hovered_tile != m_hovered_tile) + { + m_last_hovered_tile = m_hovered_tile; + + if (m_editor.get_tiles()->pos(0, 0) == 0) // Erasing + update_autotileset(); + } + // update tip hover_object(); } +void +EditorOverlayWidget::update_autotileset() +{ + if (m_editor.get_tiles()->pos(0, 0) == 0) // Erasing + { + const uint32_t current_tile = m_editor.get_selected_tilemap()->get_tile_id(static_cast(m_hovered_tile.x), static_cast(m_hovered_tile.y)); + m_available_autotilesets = m_editor.get_tileset()->get_autotilesets_from_tile(current_tile); + } + else + { + m_available_autotilesets = m_editor.get_tileset()->get_autotilesets_from_tile(m_editor.get_tiles()->pos(0, 0)); + } +} + +AutotileSet* +EditorOverlayWidget::get_current_autotileset() const +{ + if (m_available_autotilesets.empty()) + return nullptr; + + if (m_current_autotileset < 0 || m_current_autotileset > static_cast(m_available_autotilesets.size() - 1)) + return m_available_autotilesets.front(); + + return m_available_autotilesets[m_current_autotileset]; +} + +std::string +EditorOverlayWidget::get_autotileset_key_range() const +{ + if (m_available_autotilesets.size() < 2) + return ""; + if (m_available_autotilesets.size() == 2) + return "(+1)"; + + return "(+1-" + std::to_string(std::min(static_cast(m_available_autotilesets.size() - 1), 9)) + ")"; +} + void EditorOverlayWidget::draw_tile_tip(DrawingContext& context) { @@ -1563,22 +1633,23 @@ EditorOverlayWidget::draw(DrawingContext& context) if (g_config->editor_autotile_help) { - if (m_editor.get_tileset()->get_autotileset_from_tile(m_editor.get_tiles()->pos(0, 0)) != nullptr) + if (g_config->editor_autotile_mode) { - if (g_config->editor_autotile_mode) - { - context.color().draw_text(Resources::normal_font, _("Autotile mode is on"), Vector(144, 16), ALIGN_LEFT, LAYER_OBJECTS+1, EditorOverlayWidget::text_autotile_active_color); - } - else + AutotileSet* autotileset = get_current_autotileset(); + if (m_editor.get_tiles()->pos(0, 0) == 0) { - context.color().draw_text(Resources::normal_font, _("Hold Ctrl to enable autotile"), Vector(144, 16), ALIGN_LEFT, LAYER_OBJECTS+1, EditorOverlayWidget::text_autotile_available_color); + if (autotileset) + { + context.color().draw_text(Resources::normal_font, fmt::format(fmt::runtime(_("Autotile erasing mode is on (\"{}\")")), autotileset->get_name()), Vector(144, 16), ALIGN_LEFT, LAYER_OBJECTS+1, EditorOverlayWidget::text_autotile_active_color); + } + else + { + context.color().draw_text(Resources::normal_font, _("Autotile erasing cannot be performed here"), Vector(144, 16), ALIGN_LEFT, LAYER_OBJECTS+1, EditorOverlayWidget::text_autotile_error_color); + } } - } - else if (g_config->editor_autotile_mode) - { - if (m_editor.get_tiles()->pos(0, 0) == 0) + else if (autotileset) { - context.color().draw_text(Resources::normal_font, _("Autotile erasing mode is on"), Vector(144, 16), ALIGN_LEFT, LAYER_OBJECTS+1, EditorOverlayWidget::text_autotile_active_color); + context.color().draw_text(Resources::normal_font, fmt::format(fmt::runtime(_("Autotile mode is on (\"{}\")")), autotileset->get_name()), Vector(144, 16), ALIGN_LEFT, LAYER_OBJECTS+1, EditorOverlayWidget::text_autotile_active_color); } else { @@ -1587,7 +1658,11 @@ EditorOverlayWidget::draw(DrawingContext& context) } else if (m_editor.get_tiles()->pos(0, 0) == 0) { - context.color().draw_text(Resources::normal_font, _("Hold Ctrl to enable autotile erasing"), Vector(144, 16), ALIGN_LEFT, LAYER_OBJECTS+1, EditorOverlayWidget::text_autotile_available_color); + context.color().draw_text(Resources::normal_font, fmt::format(fmt::runtime(_("Hold Ctrl{} to enable autotile erasing")), get_autotileset_key_range()), Vector(144, 16), ALIGN_LEFT, LAYER_OBJECTS+1, EditorOverlayWidget::text_autotile_available_color); + } + else + { + context.color().draw_text(Resources::normal_font, fmt::format(fmt::runtime(_("Hold Ctrl{} to enable autotile")), get_autotileset_key_range()), Vector(144, 16), ALIGN_LEFT, LAYER_OBJECTS+1, EditorOverlayWidget::text_autotile_available_color); } } } diff --git a/src/editor/overlay_widget.hpp b/src/editor/overlay_widget.hpp index 89b6b9388f6..7f040a95540 100644 --- a/src/editor/overlay_widget.hpp +++ b/src/editor/overlay_widget.hpp @@ -28,6 +28,7 @@ #include "supertux/timer.hpp" #include "util/typed_uid.hpp" +class AutotileSet; class Color; class DrawingContext; class Editor; @@ -64,6 +65,7 @@ class EditorOverlayWidget final : public Widget virtual void on_window_resize() override; void update_pos(); + void update_autotileset(); void delete_markers(); void update_node_iterators(); void on_level_change(); @@ -101,6 +103,9 @@ class EditorOverlayWidget final : public Widget void select_object(); void add_path_node(); + AutotileSet* get_current_autotileset() const; + std::string get_autotileset_key_range() const; + void draw_tile_tip(DrawingContext&); void draw_tile_grid(DrawingContext&, int tile_size, bool draw_shadow) const; void draw_tilemap_border(DrawingContext&); @@ -130,6 +135,7 @@ class EditorOverlayWidget final : public Widget Editor& m_editor; Vector m_hovered_tile; Vector m_hovered_tile_prev; + Vector m_last_hovered_tile; Vector m_sector_pos; Vector m_mouse_pos; Vector m_previous_mouse_pos; @@ -147,6 +153,9 @@ class EditorOverlayWidget final : public Widget TypedUID m_edited_path; TypedUID m_last_node_marker; + std::vector m_available_autotilesets; + int m_current_autotileset; + std::unique_ptr m_object_tip; Vector m_obj_mouse_desync; diff --git a/src/editor/toolbox_widget.cpp b/src/editor/toolbox_widget.cpp index 00fc2b1f3d4..4db15151ce2 100644 --- a/src/editor/toolbox_widget.cpp +++ b/src/editor/toolbox_widget.cpp @@ -108,6 +108,7 @@ EditorToolboxWidget::on_mouse_button_down(const SDL_MouseButtonEvent& button) { if (m_tilebox->on_mouse_button_down(button)) { + m_editor.update_autotileset(); update_mouse_icon(); return true; } @@ -150,6 +151,7 @@ EditorToolboxWidget::on_mouse_button_down(const SDL_MouseButtonEvent& button) case 0: m_tilebox->get_tiles()->set_tile(0); m_tilebox->set_object(""); + m_editor.update_autotileset(); update_mouse_icon(); break; diff --git a/src/object/tilemap.cpp b/src/object/tilemap.cpp index a464917ab22..bc902c0ced6 100644 --- a/src/object/tilemap.cpp +++ b/src/object/tilemap.cpp @@ -726,80 +726,43 @@ TileMap::change_all(uint32_t oldtile, uint32_t newtile) } void -TileMap::autotile(int x, int y, uint32_t tile) +TileMap::autotile(int x, int y, uint32_t tile, AutotileSet* autotileset) { if (x < 0 || x >= m_width || y < 0 || y >= m_height) return; - uint32_t current_tile = m_tiles[y*m_width + x]; - AutotileSet* curr_set; - if (current_tile == 0) - { - // Special case 1 : If the tile is empty, check if we can use a non-solid - // tile from the currently selected tile's autotile set (if any). - curr_set = m_tileset->get_autotileset_from_tile(tile); - } - else if (m_tileset->get_autotileset_from_tile(tile) != nullptr && - m_tileset->get_autotileset_from_tile(tile)->is_member(current_tile)) - { - // Special case 2 : If the tile is in multiple autotilesets, check if it - // is in the same tileset as the selected tile. (Example : tile 47) - curr_set = m_tileset->get_autotileset_from_tile(tile); - } - else - { - curr_set = m_tileset->get_autotileset_from_tile(current_tile); - } - - // If tile is not autotileable, abort - // If tile is from a corner autotileset, abort as well - if (curr_set == nullptr) - { + if (!autotileset || !autotileset->is_member(tile)) return; - } - uint32_t realtile = curr_set->get_autotile(current_tile, - curr_set->is_solid(get_tile_id(x-1, y-1)), - curr_set->is_solid(get_tile_id(x , y-1)), - curr_set->is_solid(get_tile_id(x+1, y-1)), - curr_set->is_solid(get_tile_id(x-1, y )), - curr_set->is_solid(get_tile_id(x , y )), - curr_set->is_solid(get_tile_id(x+1, y )), - curr_set->is_solid(get_tile_id(x-1, y+1)), - curr_set->is_solid(get_tile_id(x , y+1)), - curr_set->is_solid(get_tile_id(x+1, y+1)), + m_tiles[y*m_width + x] = autotileset->get_autotile(m_tiles[y*m_width + x], + autotileset->is_solid(get_tile_id(x-1, y-1)), + autotileset->is_solid(get_tile_id(x , y-1)), + autotileset->is_solid(get_tile_id(x+1, y-1)), + autotileset->is_solid(get_tile_id(x-1, y )), + autotileset->is_solid(get_tile_id(x , y )), + autotileset->is_solid(get_tile_id(x+1, y )), + autotileset->is_solid(get_tile_id(x-1, y+1)), + autotileset->is_solid(get_tile_id(x , y+1)), + autotileset->is_solid(get_tile_id(x+1, y+1)), x, y); - - m_tiles[y*m_width + x] = realtile; } void -TileMap::autotile_corner(int x, int y, uint32_t tile, AutotileCornerOperation op) +TileMap::autotile_corner(int x, int y, uint32_t tile, AutotileSet* autotileset, AutotileCornerOperation op) { if (x < 0 || x >= m_width || y < 0 || y >= m_height) return; - if (!m_tileset->get_autotileset_from_tile(tile)->is_corner()) + if (!autotileset || !autotileset->is_corner() || !autotileset->is_member(tile)) return; - AutotileSet* curr_set = m_tileset->get_autotileset_from_tile(tile); - - // If tile is not autotileable, abort - if (curr_set == nullptr) - { - return; - } - // If tile is not empty or already of the appropriate tileset, abort uint32_t current_tile = m_tiles[y*m_width + x]; - if (current_tile != 0 && (m_tileset->get_autotileset_from_tile(tile) != nullptr - && !m_tileset->get_autotileset_from_tile(tile)->is_member(current_tile))) - { + if (current_tile != 0 && !autotileset->is_member(current_tile)) return; - } // If the current tile is 0, it will automatically return 0 - uint8_t mask = curr_set->get_mask_from_tile(current_tile); + uint8_t mask = autotileset->get_mask_from_tile(current_tile); if (op == AutotileCornerOperation::REMOVE_TOP_LEFT) mask = static_cast(mask & 0x07); if (op == AutotileCornerOperation::REMOVE_TOP_RIGHT) mask = static_cast(mask & 0x0B); if (op == AutotileCornerOperation::REMOVE_BOTTOM_LEFT) mask = static_cast(mask & 0x0D); @@ -809,7 +772,7 @@ TileMap::autotile_corner(int x, int y, uint32_t tile, AutotileCornerOperation op if (op == AutotileCornerOperation::ADD_BOTTOM_LEFT) mask = static_cast(mask | 0x02); if (op == AutotileCornerOperation::ADD_BOTTOM_RIGHT) mask = static_cast(mask | 0x01); - uint32_t realtile = (!mask) ? 0 : curr_set->get_autotile(current_tile, + uint32_t realtile = (!mask) ? 0 : autotileset->get_autotile(current_tile, (mask & 0x08) != 0, false, (mask & 0x04) != 0, @@ -827,12 +790,16 @@ TileMap::autotile_corner(int x, int y, uint32_t tile, AutotileCornerOperation op bool TileMap::is_corner(uint32_t tile) const { - auto* ats = m_tileset->get_autotileset_from_tile(tile); - return ats && ats->is_corner(); + for (const AutotileSet* autotileset : get_autotilesets(tile)) + { + if (autotileset->is_corner()) + return true; + } + return false; } void -TileMap::autotile_erase(const Vector& pos, const Vector& corner_pos) +TileMap::autotile_erase(const Vector& pos, const Vector& corner_pos, AutotileSet* autotileset) { if (pos.x < 0.f || pos.x >= static_cast(m_width) || pos.y < 0.f || pos.y >= static_cast(m_height)) @@ -844,15 +811,16 @@ TileMap::autotile_erase(const Vector& pos, const Vector& corner_pos) uint32_t current_tile = m_tiles[static_cast(pos.y)*m_width + static_cast(pos.x)]; + if (!autotileset || !autotileset->is_member(current_tile)) + return; - AutotileSet* curr_set = m_tileset->get_autotileset_from_tile(current_tile); - - if (curr_set && curr_set->is_corner()) { + if (autotileset->is_corner()) + { int x = static_cast(corner_pos.x), y = static_cast(corner_pos.y); - autotile_corner(x, y, current_tile, AutotileCornerOperation::REMOVE_TOP_LEFT); - autotile_corner(x-1, y, current_tile, AutotileCornerOperation::REMOVE_TOP_RIGHT); - autotile_corner(x, y-1, current_tile, AutotileCornerOperation::REMOVE_BOTTOM_LEFT); - autotile_corner(x-1, y-1, current_tile, AutotileCornerOperation::REMOVE_BOTTOM_RIGHT); + autotile_corner(x, y, current_tile, autotileset, AutotileCornerOperation::REMOVE_TOP_LEFT); + autotile_corner(x-1, y, current_tile, autotileset, AutotileCornerOperation::REMOVE_TOP_RIGHT); + autotile_corner(x, y-1, current_tile, autotileset, AutotileCornerOperation::REMOVE_BOTTOM_LEFT); + autotile_corner(x-1, y-1, current_tile, autotileset, AutotileCornerOperation::REMOVE_BOTTOM_RIGHT); } else { @@ -861,58 +829,58 @@ TileMap::autotile_erase(const Vector& pos, const Vector& corner_pos) if (x - 1 >= 0 && y - 1 >= 0 && !is_corner(m_tiles[(y-1)*m_width + x-1])) { if (m_tiles[y*m_width + x] == 0) - autotile(x, y, m_tiles[(y-1)*m_width + x-1]); - autotile(x-1, y-1, m_tiles[(y-1)*m_width + x-1]); + autotile(x, y, m_tiles[(y-1)*m_width + x-1], autotileset); + autotile(x-1, y-1, m_tiles[(y-1)*m_width + x-1], autotileset); } if (y - 1 >= 0 && !is_corner(m_tiles[(y-1)*m_width + x])) { if (m_tiles[y*m_width + x] == 0) - autotile(x, y, m_tiles[(y-1)*m_width + x]); - autotile(x, y-1, m_tiles[(y-1)*m_width + x]); + autotile(x, y, m_tiles[(y-1)*m_width + x], autotileset); + autotile(x, y-1, m_tiles[(y-1)*m_width + x], autotileset); } if (y - 1 >= 0 && x + 1 < m_width && !is_corner(m_tiles[(y-1)*m_width + x+1])) { if (m_tiles[y*m_width + x] == 0) - autotile(x, y, m_tiles[(y-1)*m_width + x+1]); - autotile(x+1, y-1, m_tiles[(y-1)*m_width + x+1]); + autotile(x, y, m_tiles[(y-1)*m_width + x+1], autotileset); + autotile(x+1, y-1, m_tiles[(y-1)*m_width + x+1], autotileset); } if (x - 1 >= 0 && !is_corner(m_tiles[y*m_width + x-1])) { if (m_tiles[y*m_width + x] == 0) - autotile(x, y, m_tiles[y*m_width + x-1]); - autotile(x-1, y, m_tiles[y*m_width + x-1]); + autotile(x, y, m_tiles[y*m_width + x-1], autotileset); + autotile(x-1, y, m_tiles[y*m_width + x-1], autotileset); } if (x + 1 < m_width && !is_corner(m_tiles[y*m_width + x+1])) { if (m_tiles[y*m_width + x] == 0) - autotile(x, y, m_tiles[y*m_width + x+1]); - autotile(x+1, y, m_tiles[y*m_width + x+1]); + autotile(x, y, m_tiles[y*m_width + x+1], autotileset); + autotile(x+1, y, m_tiles[y*m_width + x+1], autotileset); } if (x - 1 >= 0 && y + 1 < m_height && !is_corner(m_tiles[(y+1)*m_width + x-1])) { if (m_tiles[y*m_width + x] == 0) - autotile(x, y, m_tiles[(y+1)*m_width + x-1]); - autotile(x-1, y+1, m_tiles[(y+1)*m_width + x-1]); + autotile(x, y, m_tiles[(y+1)*m_width + x-1], autotileset); + autotile(x-1, y+1, m_tiles[(y+1)*m_width + x-1], autotileset); } if (y + 1 < m_height && !is_corner(m_tiles[(y+1)*m_width + x])) { if (m_tiles[y*m_width + x] == 0) - autotile(x, y, m_tiles[(y+1)*m_width + x]); - autotile(x, y+1, m_tiles[(y+1)*m_width + x]); + autotile(x, y, m_tiles[(y+1)*m_width + x], autotileset); + autotile(x, y+1, m_tiles[(y+1)*m_width + x], autotileset); } if (y + 1 < m_height && x + 1 < m_width && !is_corner(m_tiles[(y+1)*m_width + x+1])) { if (m_tiles[y*m_width + x] == 0) - autotile(x, y, m_tiles[(y+1)*m_width + x+1]); - autotile(x+1, y+1, m_tiles[(y+1)*m_width + x+1]); + autotile(x, y, m_tiles[(y+1)*m_width + x+1], autotileset); + autotile(x+1, y+1, m_tiles[(y+1)*m_width + x+1], autotileset); } } } -AutotileSet* -TileMap::get_autotileset(uint32_t tile) const +std::vector +TileMap::get_autotilesets(uint32_t tile) const { - return m_tileset->get_autotileset_from_tile(tile); + return m_tileset->get_autotilesets_from_tile(tile); } void diff --git a/src/object/tilemap.hpp b/src/object/tilemap.hpp index 16a3f4a0b43..164c38e8a36 100644 --- a/src/object/tilemap.hpp +++ b/src/object/tilemap.hpp @@ -31,6 +31,7 @@ #include "video/flip.hpp" #include "video/drawing_target.hpp" +class AutotileSet; class CollisionObject; class CollisionGroundMovementManager; class DrawingContext; @@ -205,7 +206,7 @@ class TileMap final : public GameObject, void change_all(uint32_t oldtile, uint32_t newtile); /** Puts the correct autotile block at the given position */ - void autotile(int x, int y, uint32_t tile); + void autotile(int x, int y, uint32_t tile, AutotileSet* autotileset); enum class AutotileCornerOperation { ADD_TOP_LEFT, @@ -219,13 +220,13 @@ class TileMap final : public GameObject, }; /** Puts the correct autotile blocks at the tiles around the given corner */ - void autotile_corner(int x, int y, uint32_t tile, AutotileCornerOperation op); + void autotile_corner(int x, int y, uint32_t tile, AutotileSet* autotileset, AutotileCornerOperation op); /** Erases in autotile mode */ - void autotile_erase(const Vector& pos, const Vector& corner_pos); + void autotile_erase(const Vector& pos, const Vector& corner_pos, AutotileSet* autotileset); - /** Returns the Autotileset associated with the given tile */ - AutotileSet* get_autotileset(uint32_t tile) const; + /** Returns the Autotilesets associated with the given tile */ + std::vector get_autotilesets(uint32_t tile) const; void set_flip(Flip flip) { m_flip = flip; } Flip get_flip() const { return m_flip; } diff --git a/src/supertux/autotile.hpp b/src/supertux/autotile.hpp index e5951c7716c..1d2e8a92df1 100644 --- a/src/supertux/autotile.hpp +++ b/src/supertux/autotile.hpp @@ -100,6 +100,8 @@ class AutotileSet final /** Returns the id of the first block in the autotileset. Used for erronous configs. */ uint32_t get_default_tile() const { return m_default; } + const std::string& get_name() const { return m_name; } + /** true if the given tile is present in the autotileset */ bool is_member(uint32_t tile_id) const; diff --git a/src/supertux/tile_set.cpp b/src/supertux/tile_set.cpp index 7d2b8b16e67..ea5e8277e77 100644 --- a/src/supertux/tile_set.cpp +++ b/src/supertux/tile_set.cpp @@ -87,22 +87,35 @@ TileSet::get(const uint32_t id) const } } -AutotileSet* -TileSet::get_autotileset_from_tile(uint32_t tile_id) const +std::vector +TileSet::get_autotilesets_from_tile(uint32_t tile_id) const { if (tile_id == 0) { - return nullptr; + return {}; } + std::vector autotilesets; for (auto& ats : m_autotilesets) { if (ats->is_member(tile_id)) - { - return ats.get(); - } + autotilesets.push_back(ats.get()); + } + return autotilesets; +} + +bool +TileSet::has_mutual_autotileset(uint32_t lhs, uint32_t rhs) const +{ + if (lhs == rhs) + return true; + + for (const auto& autotileset : m_autotilesets) + { + if (autotileset->is_member(lhs) && autotileset->is_member(rhs)) + return true; } - return nullptr; + return false; } void diff --git a/src/supertux/tile_set.hpp b/src/supertux/tile_set.hpp index 8335e098db3..430f86b9480 100644 --- a/src/supertux/tile_set.hpp +++ b/src/supertux/tile_set.hpp @@ -63,7 +63,8 @@ class TileSet final const Tile& get(const uint32_t id) const; - AutotileSet* get_autotileset_from_tile(uint32_t tile_id) const; + std::vector get_autotilesets_from_tile(uint32_t tile_id) const; + bool has_mutual_autotileset(uint32_t lhs, uint32_t rhs) const; uint32_t get_max_tileid() const { return static_cast(m_tiles.size());