diff --git a/client/control.cpp b/client/control.cpp index 6e4298b2eb..5e452ee4e3 100644 --- a/client/control.cpp +++ b/client/control.cpp @@ -287,7 +287,7 @@ void set_hover_state(struct unit_list *punits, enum cursor_hover_state state, enum unit_orders order) { fc_assert_ret((punits && unit_list_size(punits) > 0) - || state == HOVER_NONE); + || (state == HOVER_NONE || state == HOVER_DEBUG_TILE)); fc_assert_ret(state == HOVER_CONNECT || activity == ACTIVITY_LAST); fc_assert_ret((state == HOVER_GOTO || state == HOVER_GOTO_SEL_TGT) || order == ORDER_LAST); @@ -802,7 +802,7 @@ void unit_focus_update() /** Return a pointer to a visible unit, if there is one. */ -struct unit *find_visible_unit(struct tile *ptile) +unit *find_visible_unit(const ::tile *ptile) { struct unit *panyowned = NULL, *panyother = NULL, *ptptother = NULL; @@ -1285,6 +1285,7 @@ void control_mouse_cursor(struct tile *ptile) break; case HOVER_ACT_SEL_TGT: case HOVER_GOTO_SEL_TGT: + case HOVER_DEBUG_TILE: /* Select a tile to target / find targets on. */ mouse_cursor_type = CURSOR_SELECT; break; @@ -2748,6 +2749,16 @@ void do_map_click(struct tile *ptile, enum quickselect_type qtype) fc_assert(action_id_exists(goto_last_action)); do_unit_goto(ptile); break; + case HOVER_DEBUG_TILE: + // This function is called twice, once on mouse press and once on mouse + // release. We get SELECT_POPUP the second time. + // We don't want to do anything the first time we're called to avoid + // selecting units or opening the tile dialog. + if (qtype == SELECT_POPUP) { + debug_tile(ptile); + clear_hover_state(); + } + return; } clear_hover_state(); @@ -3032,6 +3043,9 @@ void key_cancel_action() keyboardless_goto_active = false; keyboardless_goto_start_tile = NULL; break; + case HOVER_DEBUG_TILE: + clear_hover_state(); + break; case HOVER_NONE: break; }; diff --git a/client/control.h b/client/control.h index 1f699ab4b1..c8e3ecf317 100644 --- a/client/control.h +++ b/client/control.h @@ -23,6 +23,7 @@ enum cursor_hover_state { HOVER_PATROL, HOVER_ACT_SEL_TGT, HOVER_GOTO_SEL_TGT, + HOVER_DEBUG_TILE, }; // Selecting unit from a stack without popup. @@ -175,7 +176,7 @@ void unit_focus_update(); void auto_center_on_focus_unit(); void update_unit_pix_label(struct unit_list *punitlist); -struct unit *find_visible_unit(struct tile *ptile); +unit *find_visible_unit(const ::tile *ptile); void set_units_in_combat(struct unit *pattacker, struct unit *pdefender); int blink_active_unit(); int blink_turn_done_button(); diff --git a/client/goto.cpp b/client/goto.cpp index 7ffea16411..c3d4a49e9f 100644 --- a/client/goto.cpp +++ b/client/goto.cpp @@ -999,6 +999,7 @@ static void goto_fill_parameter_full(struct goto_map *goto_map, case HOVER_NONE: case HOVER_PARADROP: case HOVER_ACT_SEL_TGT: + case HOVER_DEBUG_TILE: fc_assert_msg(hover_state != HOVER_NONE, "Goto with HOVER_NONE?"); fc_assert_msg(hover_state != HOVER_PARADROP, "Goto with HOVER_PARADROP?"); diff --git a/client/gui-qt/CMakeLists.txt b/client/gui-qt/CMakeLists.txt index 708da47a1b..f9e0b4eacb 100644 --- a/client/gui-qt/CMakeLists.txt +++ b/client/gui-qt/CMakeLists.txt @@ -49,6 +49,7 @@ add_library( spaceshipdlg.cpp sprite.cpp themes.cpp + tileset_debugger.cpp tradecalculation.cpp tooltips.cpp unitreport.cpp diff --git a/client/gui-qt/fc_client.cpp b/client/gui-qt/fc_client.cpp index ad16937937..3dfc57690b 100644 --- a/client/gui-qt/fc_client.cpp +++ b/client/gui-qt/fc_client.cpp @@ -50,6 +50,7 @@ #include "page_scenario.h" #include "sidebar.h" #include "sprite.h" +#include "tileset_debugger.h" #include "voteinfo_bar.h" fcFont *fcFont::m_instance = 0; @@ -256,6 +257,11 @@ void fc_client::switch_page(int new_pg) set_client_page(PAGE_MAIN); break; } + + // Maybe popdown the tileset debugger + if (page != PAGE_GAME) { + queen()->mapview_wdg->hide_debugger(); + } } /** diff --git a/client/gui-qt/fc_client.h b/client/gui-qt/fc_client.h index 6b5a633743..8646e1a5ea 100644 --- a/client/gui-qt/fc_client.h +++ b/client/gui-qt/fc_client.h @@ -13,6 +13,7 @@ #include #include #include + // common #include "packets.h" // client @@ -36,6 +37,10 @@ class QTimerEvent; class choice_dialog; struct server_scan; +namespace freeciv { +class tileset_debugger; +} + enum connection_state { LOGIN_TYPE, NEW_PASSWORD_TYPE, diff --git a/client/gui-qt/mapview.cpp b/client/gui-qt/mapview.cpp index a6afb463b4..04188d59d3 100644 --- a/client/gui-qt/mapview.cpp +++ b/client/gui-qt/mapview.cpp @@ -196,6 +196,40 @@ void map_view::show_all_fcwidgets() m_hidden_fcwidgets.clear(); } +/** + * Ppens the tileset debugger. + */ +void map_view::show_debugger() +{ + if (!m_debugger) { + // We never destroy it once it's created. + m_debugger = new freeciv::tileset_debugger(this); + connect(m_debugger, &freeciv::tileset_debugger::tile_picking_requested, + [](bool active) { + if (active) { + set_hover_state(NULL, HOVER_DEBUG_TILE, ACTIVITY_LAST, NULL, + NO_TARGET, NO_TARGET, ACTION_NONE, + ORDER_LAST); + } else if (!active && hover_state == HOVER_DEBUG_TILE) { + clear_hover_state(); + } + }); + } + + m_debugger->show(); +} + +/** + * Closes the tileset debugger if it is open. + */ +void map_view::hide_debugger() +{ + if (m_debugger) { + m_debugger->set_tile(nullptr); + m_debugger->close(); + } +} + /** Timer for cursor */ @@ -773,3 +807,12 @@ void show_city_desc(QPixmap *pcanvas, int canvas_x, int canvas_y, p.end(); } + +/** + * Callback to set the tile being debugged. + */ +void debug_tile(tile *tile) +{ + fc_assert_ret(queen()->mapview_wdg->m_debugger); + queen()->mapview_wdg->m_debugger->set_tile(tile); +} diff --git a/client/gui-qt/mapview.h b/client/gui-qt/mapview.h index d6ecaaed13..b5ea22d0f2 100644 --- a/client/gui-qt/mapview.h +++ b/client/gui-qt/mapview.h @@ -12,9 +12,14 @@ // Qt #include #include +#include #include #include #include + +// gui-qt +#include "tileset_debugger.h" + // common #include "tilespec.h" @@ -37,6 +42,10 @@ void draw_calculated_trade_routes(QPainter *painter); **************************************************************************/ class map_view : public QWidget { Q_OBJECT + + // Ought to be a private slot + friend void debug_tile(tile *tile); + void shortcut_pressed(int key); void shortcut_released(Qt::MouseButton mb); @@ -54,6 +63,10 @@ class map_view : public QWidget { bool menu_click; +public slots: + void show_debugger(); + void hide_debugger(); + protected: void paintEvent(QPaintEvent *event) override; void keyPressEvent(QKeyEvent *event) override; @@ -71,6 +84,7 @@ private slots: bool stored_autocenter; int cursor_frame{0}; int cursor; + QPointer m_debugger = nullptr; std::vector m_hidden_fcwidgets; }; diff --git a/client/gui-qt/menu.cpp b/client/gui-qt/menu.cpp index 39991a1b51..50a958ff0d 100644 --- a/client/gui-qt/menu.cpp +++ b/client/gui-qt/menu.cpp @@ -599,6 +599,9 @@ void mr_menu::setup_menus() connect(act, &QAction::triggered, this, &mr_menu::shortcut_options); act = menu->addAction(_("Load another tileset")); connect(act, &QAction::triggered, this, &mr_menu::tileset_custom_load); + act = menu->addAction(_("Tileset debugger")); + connect(act, &QAction::triggered, queen()->mapview_wdg, + &map_view::show_debugger); act = menu->addAction(_("Save Options Now")); act->setIcon(style()->standardIcon(QStyle::SP_DialogSaveButton)); connect(act, &QAction::triggered, this, &mr_menu::save_options_now); diff --git a/client/gui-qt/tileset_debugger.cpp b/client/gui-qt/tileset_debugger.cpp new file mode 100644 index 0000000000..30b8150df8 --- /dev/null +++ b/client/gui-qt/tileset_debugger.cpp @@ -0,0 +1,177 @@ +/************************************************************************** + Copyright (c) 2021 Freeciv21 contributors. This file is + part of Freeciv21. Freeciv21 is free software: you can redistribute it + and/or modify it under the terms of the GNU General Public License as + published by the Free Software Foundation, either version 3 of the + License, or (at your option) any later version. You should have received + a copy of the GNU General Public License along with Freeciv21. If not, + see https://www.gnu.org/licenses/. +**************************************************************************/ + +#include "tileset_debugger.h" + +// client/include +#include "dialogs_g.h" + +// client +#include "climap.h" +#include "editor.h" +#include "tilespec.h" + +// common +#include "map.h" +#include "tile.h" + +// utility +#include "fcintl.h" + +#include +#include +#include +#include +#include + +namespace freeciv { + +/** + * \class tileset_debugger + * \brief A dialog to perform debugging of the tileset. + */ + +/** + * Constructor. + */ +tileset_debugger::tileset_debugger(QWidget *parent) : QDialog(parent) +{ + setWindowTitle(_("Tileset debugger")); + + auto layout = new QVBoxLayout; + setLayout(layout); + + auto toolbar = new QToolBar; + toolbar->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); + layout->addWidget(toolbar); + + m_pick_action = + toolbar->addAction(QIcon::fromTheme("pointer"), _("Pick tile")); + m_pick_action->setToolTip(_("Pick a tile to inspect on the map")); + m_pick_action->setCheckable(true); + connect(m_pick_action, &QAction::toggled, this, + &tileset_debugger::pick_tile); + + m_label = new QLabel; + layout->addWidget(m_label); + + m_content = new QTreeWidget; + m_content->setHeaderHidden(true); + m_content->setSelectionMode(QAbstractItemView::NoSelection); + layout->addWidget(m_content, 100); + + set_tile(nullptr); +} + +/** + * Destructor. + */ +tileset_debugger::~tileset_debugger() {} + +/** + * Sets the tile being debugged. + */ +void tileset_debugger::set_tile(const ::tile *t) +{ + m_tile = t; + m_pick_action->setChecked(false); + + // Update the GUI + if (!t) { + m_label->setText(_("Select a tile to start debugging.")); + return; + } + + m_label->setText(QString(_("Tile at %1, %2")) + .arg(index_to_map_pos_x(tile_index(t))) + .arg(index_to_map_pos_y(tile_index(t)))); + + // Fill tile data + m_content->clear(); + + auto maxSize = QSize(); // Max sprite size + for (const auto &layer : tileset_get_layers(tileset)) { + auto item = new QTreeWidgetItem(m_content); + + const auto name = mapview_layer_name(layer->type()); + item->setText(0, name); + + // Get the list of sprites for this layer + ::unit *unit = nullptr; + if (client_tile_get_known(t) != TILE_UNKNOWN + || (editor_is_active() && editor_tile_is_selected(t))) { + unit = get_drawable_unit(tileset, t); + } + const auto sprites = layer->fill_sprite_array(t, nullptr, nullptr, unit, + tile_city(t), nullptr); + + if (sprites.empty()) { + continue; + } + + // Generate a sprite with this layer only + // Geometry + auto rectangle = QRect(); + for (const auto &ds : sprites) { + rectangle |= QRect(ds.offset_x, ds.offset_y, ds.sprite->width(), + ds.sprite->height()); + } + + // Draw the composite picture + auto this_layer = QPixmap(rectangle.size() + QSize(2, 2)); + this_layer.fill(Qt::transparent); + auto p = QPainter(); + p.begin(&this_layer); + // Outline + p.setPen(palette().color(QPalette::WindowText)); + p.drawRect(0, 0, this_layer.width() - 1, this_layer.height() - 1); + // If there are negative offsets, the pixmap was extended in the negative + // direction. Compensate by offsetting the painter back... + p.translate(-rectangle.topLeft() + QPoint(1, 1)); + for (const auto &ds : sprites) { + p.drawPixmap(ds.offset_x, ds.offset_y, *ds.sprite); + } + p.end(); + item->setIcon(0, QIcon(this_layer)); + + // Add the sprites as children + for (const auto &ds : sprites) { + auto child = new QTreeWidgetItem(item); + auto this_sprite = QPixmap(rectangle.size() + QSize(2, 2)); + this_sprite.fill(Qt::transparent); + p.begin(&this_sprite); + // Outline + p.resetTransform(); + p.setPen(palette().color(QPalette::WindowText)); + p.drawRect(0, 0, this_layer.width() - 1, this_layer.height() - 1); + // We inherit the translation set above + p.translate(-rectangle.topLeft() + QPoint(1, 1)); + p.drawPixmap(ds.offset_x, ds.offset_y, *ds.sprite); + p.end(); + child->setIcon(0, QIcon(this_sprite)); + child->setText( + 0, QString(_("Offset: %1, %2")).arg(ds.offset_x).arg(ds.offset_y)); + maxSize = maxSize.expandedTo(rectangle.size()); + } + } + + m_content->setIconSize(maxSize); + m_content->expandAll(); +} + +/** + * Enters or exits tile picking mode. + */ +void tileset_debugger::pick_tile(bool active) +{ + emit tile_picking_requested(active); +} + +} // namespace freeciv diff --git a/client/gui-qt/tileset_debugger.h b/client/gui-qt/tileset_debugger.h new file mode 100644 index 0000000000..54b40ba8e8 --- /dev/null +++ b/client/gui-qt/tileset_debugger.h @@ -0,0 +1,45 @@ +/************************************************************************** + Copyright (c) 2021 Freeciv21 contributors. This file is + part of Freeciv21. Freeciv21 is free software: you can redistribute it + and/or modify it under the terms of the GNU General Public License as + published by the Free Software Foundation, either version 3 of the + License, or (at your option) any later version. You should have received + a copy of the GNU General Public License along with Freeciv21. If not, + see https://www.gnu.org/licenses/. +**************************************************************************/ +#pragma once + +#include + +class QAction; +class QLabel; +class QTreeWidget; + +struct tile; + +namespace freeciv { + +class tileset_debugger : public QDialog { + Q_OBJECT + +public: + explicit tileset_debugger(QWidget *parent = nullptr); + virtual ~tileset_debugger(); + + const ::tile *tile() const { return m_tile; } + void set_tile(const ::tile *t); + +signals: + void tile_picking_requested(bool active); + +private slots: + void pick_tile(bool active); + +private: + const ::tile *m_tile; + QLabel *m_label; + QAction *m_pick_action; + QTreeWidget *m_content; +}; + +} // namespace freeciv diff --git a/client/include/mapview_g.h b/client/include/mapview_g.h index 50c626792f..1626477166 100644 --- a/client/include/mapview_g.h +++ b/client/include/mapview_g.h @@ -55,3 +55,5 @@ GUI_FUNC_PROTO(void, draw_selection_rectangle, int canvas_x, int canvas_y, GUI_FUNC_PROTO(void, tileset_changed, void) void show_city_desc(QPixmap *pcanvas, int canvas_x, int canvas_y, struct city *pcity, int *width, int *height); + +void debug_tile(tile *t); diff --git a/client/mapctrl_common.cpp b/client/mapctrl_common.cpp index 5a90a494af..29a5f3afa3 100644 --- a/client/mapctrl_common.cpp +++ b/client/mapctrl_common.cpp @@ -632,6 +632,7 @@ void update_line(int canvas_x, int canvas_y) case HOVER_NONE: case HOVER_PARADROP: case HOVER_ACT_SEL_TGT: + case HOVER_DEBUG_TILE: break; }; } @@ -666,6 +667,7 @@ void overview_update_line(int overview_x, int overview_y) case HOVER_NONE: case HOVER_PARADROP: case HOVER_ACT_SEL_TGT: + case HOVER_DEBUG_TILE: break; }; } diff --git a/client/mapview_common.cpp b/client/mapview_common.cpp index ba6cea7565..9121018f09 100644 --- a/client/mapview_common.cpp +++ b/client/mapview_common.cpp @@ -577,6 +577,7 @@ static void base_set_mapview_origin(float gui_x0, float gui_y0) case HOVER_NONE: case HOVER_PARADROP: case HOVER_ACT_SEL_TGT: + case HOVER_DEBUG_TILE: break; }; if (rectangle_active) { diff --git a/client/tilespec.cpp b/client/tilespec.cpp index a87c9593c6..8ada25b3a9 100644 --- a/client/tilespec.cpp +++ b/client/tilespec.cpp @@ -5240,7 +5240,7 @@ void toggle_focus_unit_state(struct tileset *t) /** Find unit that we can display from given tile. */ -struct unit *get_drawable_unit(const struct tileset *t, struct tile *ptile) +struct unit *get_drawable_unit(const struct tileset *t, const ::tile *ptile) { struct unit *punit = find_visible_unit(ptile); diff --git a/client/tilespec.h b/client/tilespec.h index 179c6b9c69..140d11a1c2 100644 --- a/client/tilespec.h +++ b/client/tilespec.h @@ -155,7 +155,7 @@ int get_focus_unit_toggle_timeout(const struct tileset *t); void reset_focus_unit_state(struct tileset *t); void focus_unit_in_combat(struct tileset *t); void toggle_focus_unit_state(struct tileset *t); -struct unit *get_drawable_unit(const struct tileset *t, struct tile *ptile); +struct unit *get_drawable_unit(const struct tileset *t, const ::tile *ptile); bool unit_drawn_with_city_outline(const struct unit *punit, bool check_focus); diff --git a/docs/Developing/style-guide.rst b/docs/Developing/style-guide.rst index bd1da2e6da..7a65804eae 100644 --- a/docs/Developing/style-guide.rst +++ b/docs/Developing/style-guide.rst @@ -6,9 +6,9 @@ Documentation Style Guide .. role:: improvement .. role:: wonder -The Longturn community uses the Python based Sphinx system to generate the documentation available on this -website and in the :file:`doc` directory in the released tarball. Sphinx takes plain text files formatted -with a superset of markdown called reStructuredText (ReST). Sphinx reStructuredText is documented here: +The Longturn community uses the Python based Sphinx system to generate the documentation available on this +website and in the :file:`doc` directory in the released tarball. Sphinx takes plain text files formatted +with a superset of markdown called reStructuredText (ReST). Sphinx reStructuredText is documented here: https://www.sphinx-doc.org/en/master/usage/restructuredtext/index.html This style guide is mostly meant for documentation authors to ensure that we keep a consistent look and feel @@ -19,7 +19,7 @@ Headings Headings create chapter breaks between sections of a document as well as provide the title. -Heading 1 +Heading 1 Heading 1 is used to for the title of the page/document. The asterisk is used to denote Heading 1 like this: @@ -53,31 +53,31 @@ Heading 3 Interpreted Text Roles ====================== -Interpreted text roles are special code blocks that are inserted in line with regular text to create user -interface markup elements to bring attention to something or make it more obvious to the reader what you -want to do. Interpreted text roles are simply a code word surrounded by a colon on both sides and the text +Interpreted text roles are special code blocks that are inserted in line with regular text to create user +interface markup elements to bring attention to something or make it more obvious to the reader what you +want to do. Interpreted text roles are simply a code word surrounded by a colon on both sides and the text you want to alter is placed inside back-ticks. -* :literal:`:doc:` -- Doc is used to create a hyperlink reference between documents in the documentation +* :literal:`:doc:` -- Doc is used to create a hyperlink reference between documents in the documentation system. * :literal:`:emphasis:` -- Emphasis is used to :emphasis:`bring attention to something`. * :literal:`:file:` -- File is used for file names and paths such as :file:`~/.local/share/freeciv21/saves` -* :literal:`:guilabel:` -- GUI Label is used to bring attention to someting on the screen like the +* :literal:`:guilabel:` -- GUI Label is used to bring attention to someting on the screen like the :guilabel:`Next` button on the installer wizard -* :literal:`:literal:` -- Literal is used when you want to note a text element in its raw form. -* :literal:`:menuselection:` -- Menu Selection is used to give the path of menu clicks such as - :menuselection:`Game --> Options --> Local Options`. To create the arrow character in between the options +* :literal:`:literal:` -- Literal is used when you want to note a text element in its raw form. This is equivalent to using four back-ticks: ````text````. +* :literal:`:menuselection:` -- Menu Selection is used to give the path of menu clicks such as + :menuselection:`Game --> Options --> Local Options`. To create the arrow character in between the options you will place a text arrow like this: :literal:`-->` in between the selection items. * :literal:`:strong:` -- Strong is used to :strong:`bold some text`. -* :literal:`:title-reference:` -- Title Reference is used notate a :title-reference:`title entry` in the - in-game help or to refer to a page in the documentation without giving an actual hyperlink reference +* :literal:`:title-reference:` -- Title Reference is used notate a :title-reference:`title entry` in the + in-game help or to refer to a page in the documentation without giving an actual hyperlink reference (see :literal:`:doc:` above). The docutils specification allows for custom Interpreted Text Roles and we use this feature. The docutils -documentation on this feature is available here: +documentation on this feature is available here: https://docutils.sourceforge.io/docs/ref/rst/directives.html#custom-interpreted-text-roles -* :literal:`:unit:` -- This provides an opportunity to highlight a Freeciv21 unit, such as the +* :literal:`:unit:` -- This provides an opportunity to highlight a Freeciv21 unit, such as the :unit:`Musketeer` * :literal:`:improvement:` -- This provides an opportunity to highlight a Freeciv21 building or city improvement, such as the :improvement:`Granary`. @@ -87,17 +87,17 @@ https://docutils.sourceforge.io/docs/ref/rst/directives.html#custom-interpreted- Admonition Directives ===================== -Admonitions are specially marked "topics" that can appear anywhere an ordinary body element can. Typically, -an admonition is rendered as an offset block in a document, sometimes outlined or shaded, with a title +Admonitions are specially marked "topics" that can appear anywhere an ordinary body element can. Typically, +an admonition is rendered as an offset block in a document, sometimes outlined or shaded, with a title matching the admonition type. We use some of the standard admonitions in our documentation as well. -* :literal:`.. attention::` -- Use attention to bring a very important high profile item to the reader's +* :literal:`.. attention::` -- Use attention to bring a very important high profile item to the reader's attention. .. attention:: This is a really important message! Don't forget to eat breakfast every day. -* :literal:`.. todo::` -- Use To Do as a reminder for documentation editors to come back and fix things at +* :literal:`.. todo::` -- Use To Do as a reminder for documentation editors to come back and fix things at a later date. .. todo:: @@ -108,7 +108,7 @@ matching the admonition type. We use some of the standard admonitions in our doc .. note:: It's important to note that Freeciv21 is really fun to play with group's of people online. -* :literal:`.. code-block:: rst` -- The code block is an excellent way to display actual code or any +* :literal:`.. code-block:: rst` -- The code block is an excellent way to display actual code or any pre-formatted plain text. .. code-block:: rst diff --git a/docs/Modding/Tilesets/debugger.rst b/docs/Modding/Tilesets/debugger.rst new file mode 100644 index 0000000000..30f19f9e1e --- /dev/null +++ b/docs/Modding/Tilesets/debugger.rst @@ -0,0 +1,44 @@ +Tileset Debugger +================ + +.. versionadded:: 3.0-alpha6 + +The Tileset Debugger, accessible from the :guilabel:`Game` menu, lets you +inspect how the map is drawn. This is very helpful when developing a tileset, to +understand why something is rendering incorrectly or to understand how other +tilesets work. + +.. attention:: + The Tileset Debugger is still a work in progress. If you have suggestions + regarding its contents and functionality, you're very welcome to let us know + on `Github`_ --- you'll get a chance to shape it to your needs. + +To start using the debugger, click on the :guilabel:`Pick tile` button and then +somewhere on the map. The window will be updated with the list of sprites used +to draw the selected tile: + +.. image:: /_static/images/gui-elements/tileset-debugger.png + :alt: The tileset Debugger with a forest tile picked up. + :align: center + :scale: 75% + +The list has two levels. Each top level item corresponds to one layer used to +draw the map. When something is drawn for a layer, its image is added next to +its name and the individual sprites are added in the second level. The sprites +at the top of the list are drawn first and are hidden by the ones below. Note +that at the moment, only sprites that correspond to the tile (as opposed to its corners and edges) are visible. + +In the picture above, which uses the `amplio2` tileset, the four layers of a +forest tile are shown, two of which have sprites: ``Background``. a terrain +layer (``Terrain1``), ``Darkness``, and another terrain layer (also listed as +``Terrain1``). The first terrain layer is made of five sprites: one for the base +texture and four that blend it with adjacent tiles. The second terrain layer has +only one sprite, used to draw the trees. + +The offsets used to draw the sprites are also shown. The first number +corresponds to the horizontal axis and runs from left to right; the second to +the vertical axis that runs from top to bottom. Depending on the type of layer, +these values may be computed automatically, so they do not necessarily +correspond to a parameters in the ``tilespec`` file. + +.. _Github: https://github.com/longturn/freeciv21/issues/new?assignees=&labels=Untriaged%2C+enhancement&template=feature_request.md&title= diff --git a/docs/Modding/index.rst b/docs/Modding/index.rst index b62a9f9100..550d78c574 100644 --- a/docs/Modding/index.rst +++ b/docs/Modding/index.rst @@ -52,7 +52,12 @@ break out the varying layers. It will always start with a top-level :literal:`.t directory of the same name will have :literal:`.png` graphics files and associated :literal:`.spec` files to explain to Freeciv21 what to do when. -Have a look at :file:`amplio.tilespec` and associated files in :file:`/amplio` for an example. +Have a look at :file:`amplio.tilespec` and associated files in :file:`/amplio` for an example. The following +guides document specific aspects of tileset creation: + +.. toctree:: + Tilesets/debugger.rst + :maxdepth: 1 Soundsets ========= diff --git a/docs/_static/images/gui-elements/tileset-debugger.png b/docs/_static/images/gui-elements/tileset-debugger.png new file mode 100644 index 0000000000..d5752ceb8e Binary files /dev/null and b/docs/_static/images/gui-elements/tileset-debugger.png differ