diff --git a/client/CMakeLists.txt b/client/CMakeLists.txt index 86e6c61a4a..e735b6e846 100644 --- a/client/CMakeLists.txt +++ b/client/CMakeLists.txt @@ -97,6 +97,7 @@ target_sources( themes.cpp themes_common.cpp tileset_debugger.cpp + tileset_options.cpp tooltips.cpp top_bar.cpp tradecalculation.cpp diff --git a/client/menu.cpp b/client/menu.cpp index e19daf50f0..dd8e85ec81 100644 --- a/client/menu.cpp +++ b/client/menu.cpp @@ -15,9 +15,11 @@ #include <QApplication> #include <QFileDialog> #include <QMainWindow> +#include <QMenuBar> #include <QMessageBox> #include <QStandardPaths> #include <QVBoxLayout> + // utility #include "fcintl.h" // common @@ -29,6 +31,7 @@ #include "map.h" #include "multipliers.h" #include "road.h" +#include "tileset_options.h" #include "unit.h" // client #include "audio/audio.h" @@ -577,6 +580,10 @@ void mr_menu::setup_menus() connect(act, &QAction::triggered, this, &mr_menu::tileset_custom_load); act = menu->addAction(_("Add Modpacks")); connect(act, &QAction::triggered, this, &mr_menu::add_modpacks); + tileset_options = menu->addAction(_("Tileset Options")); + connect(tileset_options, &QAction::triggered, this, + &mr_menu::show_tileset_options); + tileset_options->setEnabled(tileset_has_options(tileset)); act = menu->addAction(_("Tileset Debugger")); connect(act, &QAction::triggered, queen()->mapview_wdg, &map_view::show_debugger); @@ -2662,6 +2669,15 @@ void mr_menu::tileset_custom_load() dialog->show(); } +/** + * Slot for loading modpack installer + */ +void mr_menu::show_tileset_options() +{ + auto dialog = new freeciv::tileset_options_dialog(tileset, this); + dialog->show(); +} + /** * Slot for loading modpack installer */ @@ -2735,6 +2751,17 @@ void mr_menu::slot_build_base(int id) } } +/** + * Reimplemented virtual function. + */ +bool mr_menu::event(QEvent *event) +{ + if (event->type() == TilesetChanged) { + tileset_options->setEnabled(tileset_has_options(tileset)); + } + return QMenuBar::event(event); +} + /** Invoke dialog with interface (local) options */ diff --git a/client/menu.h b/client/menu.h index 69a6b51375..e99d0d6567 100644 --- a/client/menu.h +++ b/client/menu.h @@ -181,6 +181,7 @@ class mr_menu : public QMenuBar { void update_bases_menu(); void set_tile_for_order(struct tile *ptile); bool shortcut_exists(const fc_shortcut &fcs, QString &where); + QAction *tileset_options = nullptr; QAction *minimap_status = nullptr; QAction *scale_fonts_status = nullptr; QAction *lock_status = nullptr; @@ -191,6 +192,10 @@ class mr_menu : public QMenuBar { bool delayed_order = false; bool quick_airlifting = false; Unit_type_id airlift_type_id = 0; + +protected: + bool event(QEvent *event) override; + private slots: // game menu void local_options(); @@ -204,6 +209,7 @@ private slots: void tileset_custom_load(); void load_new_tileset(); void add_modpacks(); + void show_tileset_options(); void back_to_menu(); void quit_game(); diff --git a/client/options.cpp b/client/options.cpp index 6708d96f86..9f31e42cee 100644 --- a/client/options.cpp +++ b/client/options.cpp @@ -14,6 +14,7 @@ #include <fc_config.h> #include <cstring> +#include <qglobal.h> #include <sys/stat.h> // Qt @@ -65,6 +66,8 @@ #include "views/view_map_common.h" #include "views/view_nations_data.h" +const char *const TILESET_OPTIONS_PREFIX = "tileset_"; + typedef QHash<QString, QString> optionsHash; typedef QHash<QString, intptr_t> dialOptionsHash; @@ -3870,6 +3873,91 @@ static const char *get_last_option_file_name(bool *allow_digital_boolean) Q_GLOBAL_STATIC(optionsHash, settable_options) +/** + * Migrate players using cimpletoon/toonhex to amplio2/hexemplio with the + * cimpletoon option enabled. + * + * \since 3.1 + */ +static void +tileset_options_migrate_cimpletoon(struct client_options *options) +{ + for (auto &name : {options->default_tileset_iso_name, + options->default_tileset_isohex_name, + options->default_tileset_square_name}) { + if (name == QStringLiteral("cimpletoon")) { + fc_strlcpy(name, "amplio2", sizeof(name)); + options->tileset_options[QStringLiteral("amplio2")] + [QStringLiteral("cimpletoon")] = true; + } else if (name == QStringLiteral("toonhex")) { + fc_strlcpy(name, "hexemplio", sizeof(name)); + options->tileset_options[QStringLiteral("hexemplio")] + [QStringLiteral("cimpletoon")] = true; + } + } +} + +/** + * Load tileset options. + * + * Every tileset has its own section called tileset_xxx. The options are + * saved as name=value pairs. + * \see tileset_options_save + */ +static void tileset_options_load(struct section_file *sf, + struct client_options *options) +{ + // Gather all tileset_xxx sections + auto sections = + secfile_sections_by_name_prefix(sf, TILESET_OPTIONS_PREFIX); + if (!sections) { + return; + } + + section_list_iterate(sections, psection) + { + // Extract the tileset name from the name of the section. + auto tileset_name = + section_name(psection) + strlen(TILESET_OPTIONS_PREFIX); + + // Get all values from the section and fill a map with them. + auto entries = section_entries(psection); + auto settings = std::map<QString, bool>(); + entry_list_iterate(entries, pentry) + { + bool value = true; + if (entry_bool_get(pentry, &value)) { + settings[entry_name(pentry)] = value; + } else { + // Ignore options we can't convert to a bool, but warn the user. + qWarning("Could not load option %s for tileset %s", + entry_name(pentry), tileset_name); + } + } + entry_list_iterate_end; + + // Store the loaded options for later use. + options->tileset_options[tileset_name] = settings; + } + section_list_iterate_end; +} + +/** + * Save tileset options. + * + * \see tileset_options_load + */ +static void tileset_options_save(struct section_file *sf, + const struct client_options *options) +{ + for (const auto &[tileset, settings] : options->tileset_options) { + for (const auto &[name, value] : settings) { + secfile_insert_bool(sf, value, "%s%s.%s", TILESET_OPTIONS_PREFIX, + qUtf8Printable(tileset), qUtf8Printable(name)); + } + } +} + /** Load the server options. */ @@ -4381,6 +4469,8 @@ void options_load() create_default_cma_presets(); } + tileset_options_load(sf, gui_options); + tileset_options_migrate_cimpletoon(gui_options); settable_options_load(sf); global_worklists_load(sf); @@ -4435,6 +4525,9 @@ void options_save(option_save_log_callback log_cb) message_options_save(sf, "client"); options_dialogs_save(sf); + // Tileset options + tileset_options_save(sf, gui_options); + // server settings save_cma_presets(sf); settable_options_save(sf); diff --git a/client/options.h b/client/options.h index ac79380398..ba2c8339e2 100644 --- a/client/options.h +++ b/client/options.h @@ -177,6 +177,10 @@ struct client_options { bool gui_qt_show_titlebar = true; struct overview overview = {}; + + /// Saved tileset options. The first index is the tileset name, the second + /// is the option name. + std::map<QString, std::map<QString, bool>> tileset_options; }; extern client_options *gui_options; diff --git a/client/tileset/tilespec.cpp b/client/tileset/tilespec.cpp index bac1989d07..0c1021e10e 100644 --- a/client/tileset/tilespec.cpp +++ b/client/tileset/tilespec.cpp @@ -35,6 +35,7 @@ #include "deprecations.h" #include "fcintl.h" #include "log.h" +#include "name_translation.h" #include "rand.h" #include "registry.h" #include "registry_ini.h" @@ -79,7 +80,7 @@ #include "layer_special.h" #include "layer_terrain.h" #include "layer_units.h" -#include "options.h" // for fill_xxx +#include "options.h" // for fill_xxx, tileset options #include "page_game.h" #include "tilespec.h" #include "utils/colorizer.h" @@ -88,7 +89,7 @@ #define TILESPEC_CAPSTR \ "+Freeciv-tilespec-Devel-2019-Jul-03 duplicates_ok precise-hp-bars " \ "unlimited-unit-select-frames unlimited-upkeep-sprites hex_corner " \ - "terrain-specific-extras" + "terrain-specific-extras options" /* * Tilespec capabilities acceptable to this program: * @@ -112,19 +113,26 @@ * (upkeep.unhappy*, upkeep.output*) * hex_corner * - The sprite type "hex_corner" is supported + * options + * - Signals that tileset options are supported */ -#define SPEC_CAPSTR "+Freeciv-spec-Devel-2019-Jul-03" +#define SPEC_CAPSTR "+Freeciv-spec-Devel-2019-Jul-03 options" /* * Individual spec file capabilities acceptable to this program: * * +Freeciv-3.1-spec * - basic format for Freeciv versions 3.1.x; required + * options + * - Signals that tileset options are supported */ #define TILESPEC_SUFFIX ".tilespec" #define TILE_SECTION_PREFIX "tile_" +/// The prefix for option sections in the tilespec file. +const static char *const OPTION_SECTION_PREFIX = "option_"; + #define NUM_TILES_DIGITS 10 #define FULL_TILE_X_OFFSET ((t->normal_tile_width - t->full_tile_width) / 2) @@ -269,7 +277,7 @@ struct specfile { char *file_name; }; -/* +/** * Information about an individual sprite. All fields except 'sprite' are * filled at the time of the scan of the specfile. 'Sprite' is * set/cleared on demand in load_sprite/unload_sprite. @@ -301,6 +309,8 @@ struct tileset { std::vector<tileset_log_entry> log; + std::map<QString, tileset_option> options; + std::vector<std::unique_ptr<freeciv::layer>> layers; struct { freeciv::layer_special *background, *middleground, *foreground; @@ -367,6 +377,9 @@ static bool tileset_update = false; static struct tileset *tileset_read_toplevel(const QString &tileset_name, bool verbose, int topology_id); +static bool tileset_setup_options(struct tileset *t, + const section_file *file); + static void tileset_setup_base(struct tileset *t, const struct extra_type *pextra, const char *tag); @@ -988,8 +1001,7 @@ bool tilespec_try_read(const QString &tileset_name, bool verbose, Unlike the initial reading code, which reads pieces one at a time, this gets rid of the old data and reads in the new all at once. If the new tileset fails to load the old tileset may be reloaded; otherwise the - client will exit. If a nullptr name is given the current tileset will be - reread. + client will exit. It will also call the necessary functions to redraw the graphics. @@ -1331,11 +1343,28 @@ static void scan_specfile(struct tileset *t, struct specfile *sf, secfile_error()); continue; } + + // Cursor pointing coordinates hot_x = secfile_lookup_int_default(file, 0, "%s.tiles%d.hot_x", sec_name, j); hot_y = secfile_lookup_int_default(file, 0, "%s.tiles%d.hot_y", sec_name, j); + // User-configured options + auto option = QString::fromUtf8(secfile_lookup_str_default( + file, "", "%s.tiles%d.option", sec_name, j)); + if (!option.isEmpty()) { + if (!tileset_has_option(t, option)) { + // Ignore unknown options + tileset_error( + t, QtWarningMsg, "%s: unknown option %s for sprite %s", + tileset_basename(t), qUtf8Printable(option), tags[0]); + } else if (!tileset_option_is_enabled(t, option)) { + // Skip sprites that correspond to disabled options + continue; + } + } + // there must be at least 1 because of the while(): fc_assert_action(num_tags > 0, continue); @@ -1358,7 +1387,9 @@ static void scan_specfile(struct tileset *t, struct specfile *sf, if (!duplicates_ok) { for (k = 0; k < num_tags; k++) { - if (t->sprite_hash->contains(tags[k])) { + if (t->sprite_hash->contains(tags[k]) && !option.isEmpty()) { + // Warn about duplicated sprites, except if it was enabled by + // a user option (to override the default). qCritical("warning: %s: already have a sprite for \"%s\".", t->name, tags[k]); } @@ -1395,9 +1426,25 @@ static void scan_specfile(struct tileset *t, struct specfile *sf, secfile_error()); continue; } + + // Cursor pointing coordinates hot_x = secfile_lookup_int_default(file, 0, "extra.sprites%d.hot_x", i); hot_y = secfile_lookup_int_default(file, 0, "extra.sprites%d.hot_y", i); + // User-configured options + auto option = QString::fromUtf8( + secfile_lookup_str_default(file, "", "extras.sprites%d.option", i)); + if (!option.isEmpty()) { + if (!tileset_has_option(t, option)) { + // Ignore unknown options + tileset_error(t, QtWarningMsg, "%s: unknown option %s for sprite %s", + tileset_basename(t), qUtf8Printable(option), tags[0]); + } else if (!tileset_option_is_enabled(t, option)) { + // Skip sprites that correspond to disabled options + continue; + } + } + ss = new small_sprite; ss->ref_count = 0; ss->file = fc_strdup(filename); @@ -2048,6 +2095,10 @@ static struct tileset *tileset_read_toplevel(const QString &tileset_name, section_list_destroy(sections); sections = nullptr; + if (!tileset_setup_options(t, file)) { + return nullptr; + } + t->estyle_hash = new QHash<QString, int>; for (i = 0; i < ESTYLE_COUNT; i++) { @@ -2133,6 +2184,77 @@ static struct tileset *tileset_read_toplevel(const QString &tileset_name, return t; } +/** + * Loads tileset options. + * + * This function loads options from the a '.tilespec' file and sets up all + * structures in the tileset. + */ +static bool tileset_setup_options(struct tileset *t, + const section_file *file) +{ + // First load options from the tilespec file. + auto sections = + secfile_sections_by_name_prefix(file, OPTION_SECTION_PREFIX); + if (!sections) { + return true; + } + + std::set<QString> all_names; + + section_list_iterate(sections, psection) + { + // Mandatory fields: name, description. Optional: enabled_by_default. + const auto sec_name = section_name(psection); + + tileset_option option; + + auto name = secfile_lookup_str_default(file, "", "%s.name", sec_name); + if (qstrlen(name) == 0) { + tileset_error(t, QtCriticalMsg, "Option \"%s\" has no name", sec_name); + continue; // Skip instead of erroring out: options are optional + } + + // Check for duplicates + if (all_names.count(name)) { + tileset_error(t, QtCriticalMsg, "Duplicated option name \"%s\"", name); + continue; // Skip instead of erroring out: options are optional + } + all_names.insert(name); + + auto description = + secfile_lookup_str_default(file, "", "%s.description", sec_name); + if (qstrlen(description) == 0) { + tileset_error(t, QtCriticalMsg, "Option \"%s\" has no description", + name); + continue; // Skip instead of erroring out: options are optional + } + option.description = QString::fromUtf8(description); + + option.enabled_by_default = + secfile_lookup_bool_default(file, false, "%s.default", sec_name); + option.enabled = option.enabled_by_default; + + t->options[name] = std::move(option); + } + section_list_iterate_end; + + // Then apply client options. They override any default value we may have + // set. + const auto tileset_name = tileset_basename(t); + if (gui_options->tileset_options.count(tileset_name)) { + for (const auto &[name, value] : + gui_options->tileset_options[tileset_name]) { + if (tileset_has_option(t, name)) { + t->options[name].enabled = value; + } + // Silently ignore options that do not exist. + } + } + + return true; +} + /** Returns a text name for the citizen, as used in the tileset. */ @@ -5690,35 +5812,97 @@ bool tileset_has_error(const struct tileset *t) [](auto &entry) { return entry.level == LOG_ERROR; }); } +/** + * Checks if the tileset has any user-settable options. + */ +bool tileset_has_options(const struct tileset *t) +{ + return !t->options.empty(); +} + +/** + * Checks if the tileset has supports the given user-settable option. + */ +bool tileset_has_option(const struct tileset *t, const QString &option) +{ + return t->options.count(option); +} + +/** + * Gets the user-settable options of the tileset. + */ +std::map<QString, tileset_option> +tileset_get_options(const struct tileset *t) +{ + return t->options; +} + +/** + * Checks if an user-settable tileset option is enabled. + * + * The option must exist in the tileset. + */ +bool tileset_option_is_enabled(const struct tileset *t, const QString &name) +{ + return t->options.at(name).enabled; +} + +/** + * Enable or disable a user-settable tileset option. + * + * The tileset may be reloaded as a result, invalidating \c t. + * + * Returns false if the option does not exist. The game must have been + * initialized before calling this. + */ +bool tileset_set_option(struct tileset *t, const QString &name, bool enabled) +{ + auto it = t->options.find(name); + fc_assert_ret_val(it != t->options.end(), false); + + if (it->second.enabled != enabled) { + // Change the value in the client settings + gui_options->tileset_options[tileset_basename(t)][name] = enabled; + tilespec_reread_frozen_refresh(t->name); + } + return true; +} + /** Return tileset name */ -const char *tileset_name_get(struct tileset *t) { return t->given_name; } +const char *tileset_name_get(const struct tileset *t) +{ + return t->given_name; +} /** Return tileset version */ -const char *tileset_version(struct tileset *t) { return t->version; } +const char *tileset_version(const struct tileset *t) { return t->version; } /** Return tileset description summary */ -const char *tileset_summary(struct tileset *t) { return t->summary; } +const char *tileset_summary(const struct tileset *t) { return t->summary; } /** Return tileset description body */ -const char *tileset_description(struct tileset *t) { return t->description; } +const char *tileset_description(const struct tileset *t) +{ + return t->description; +} /** Return tileset topology index */ -int tileset_topo_index(struct tileset *t) { return t->ts_topo_idx; } +int tileset_topo_index(const struct tileset *t) { return t->ts_topo_idx; } /** * Creates the help item for the given tileset */ -help_item *tileset_help(struct tileset *t) +help_item *tileset_help(const struct tileset *t) { if (t == nullptr) { return nullptr; diff --git a/client/tileset/tilespec.h b/client/tileset/tilespec.h index 55ee70e94d..b3b0814743 100644 --- a/client/tileset/tilespec.h +++ b/client/tileset/tilespec.h @@ -23,6 +23,8 @@ #include <QColor> #include <QEvent> +#include <map> + struct base_type; struct help_item; struct resource_type; @@ -97,6 +99,16 @@ struct tileset_log_entry { QString message; }; +/** + * Tileset options allow altering the behavior of a tileset. + */ +struct tileset_option { + QString + description; ///< One-line description for use in the UI (translated) + bool enabled; /// < Current status + bool enabled_by_default; ///< Default status +}; + struct tileset; extern struct tileset *tileset; @@ -119,6 +131,14 @@ bool tileset_is_fully_loaded(); std::vector<tileset_log_entry> tileset_log(const struct tileset *t); bool tileset_has_error(const struct tileset *t); +bool tileset_has_options(const struct tileset *t); +bool tileset_has_option(const struct tileset *t, const QString &name); +std::map<QString, tileset_option> +tileset_get_options(const struct tileset *t); +bool tileset_option_is_enabled(const struct tileset *t, const QString &name); +bool tileset_set_option(struct tileset *t, const QString &name, + bool enabled); + void finish_loading_sprites(struct tileset *t); bool tilespec_try_read(const QString &name, bool verbose, int topo_id); @@ -321,9 +341,9 @@ QString cardinal_index_str(const struct tileset *t, int idx); #define TS_TOPO_HEX 1 #define TS_TOPO_ISOHEX 2 -const char *tileset_name_get(struct tileset *t); -const char *tileset_version(struct tileset *t); -const char *tileset_summary(struct tileset *t); -const char *tileset_description(struct tileset *t); -int tileset_topo_index(struct tileset *t); -help_item *tileset_help(struct tileset *t); +const char *tileset_name_get(const struct tileset *t); +const char *tileset_version(const struct tileset *t); +const char *tileset_summary(const struct tileset *t); +const char *tileset_description(const struct tileset *t); +int tileset_topo_index(const struct tileset *t); +help_item *tileset_help(const struct tileset *t); diff --git a/client/tileset_options.cpp b/client/tileset_options.cpp new file mode 100644 index 0000000000..296608a131 --- /dev/null +++ b/client/tileset_options.cpp @@ -0,0 +1,71 @@ +// SPDX-FileCopyrightText: Louis Moureaux +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "tileset_options.h" + +#include "name_translation.h" +#include "tileset/tilespec.h" + +#include <QCheckBox> +#include <QDialogButtonBox> +#include <QPushButton> +#include <QVBoxLayout> + +namespace freeciv { + +/** + * Sets up the tileset options dialog. + * + * The dialog contains a series of check boxes, one for each options. They + * take effect immediately. There is also a close button and a reset button. + */ +tileset_options_dialog::tileset_options_dialog(struct tileset *t, + QWidget *parent) + : QDialog(parent) +{ + setModal(true); + setMinimumWidth(300); // For the title to be fully visible + setWindowTitle(_("Tileset Options")); + + auto layout = new QVBoxLayout; + setLayout(layout); + + for (const auto &[name_, option] : tileset_get_options(t)) { + // https://stackoverflow.com/q/46114214 (TODO C++20) + auto name = name_; + + auto check = new QCheckBox(option.description); + + // Sync check box state with the tileset + check->setChecked(tileset_option_is_enabled(t, name)); + connect(check, &QCheckBox::toggled, [name](bool checked) { + tileset_set_option(tileset, name, checked); + }); + + m_checks[name] = check; + layout->addWidget(check); + } + + layout->addSpacing(6); + + auto buttons = new QDialogButtonBox(QDialogButtonBox::Close + | QDialogButtonBox::Reset); + connect(buttons->button(QDialogButtonBox::Close), &QPushButton::clicked, + this, &QDialog::accept); + connect(buttons->button(QDialogButtonBox::Reset), &QPushButton::clicked, + this, &tileset_options_dialog::reset); + layout->addWidget(buttons); +} + +/** + * Resets all options to the tileset defaults. + */ +void tileset_options_dialog::reset() +{ + for (const auto &[name, option] : tileset_get_options(tileset)) { + // Changes are propagated though the clicked() signal. + m_checks[name]->setChecked(option.enabled_by_default); + } +} + +} // namespace freeciv diff --git a/client/tileset_options.h b/client/tileset_options.h new file mode 100644 index 0000000000..8cc4f20fb0 --- /dev/null +++ b/client/tileset_options.h @@ -0,0 +1,31 @@ +// SPDX-FileCopyrightText: 2024 Louis Moureaux +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + +#include <QDialog> +#include <QString> + +#include <map> + +class QCheckBox; +struct tileset; + +namespace freeciv { + +/** + * Lets the user toggle tileset options. + */ +class tileset_options_dialog : public QDialog { + Q_OBJECT + + std::map<QString, QCheckBox *> m_checks; + +public: + explicit tileset_options_dialog(struct tileset *t, QWidget *parent = 0); + +private slots: + void reset(); +}; + +} // namespace freeciv diff --git a/data/CMakeLists.txt b/data/CMakeLists.txt index 773f7e0cee..87209653bd 100644 --- a/data/CMakeLists.txt +++ b/data/CMakeLists.txt @@ -131,13 +131,19 @@ endif() if (FREECIV_ENABLE_CLIENT) # Tilesets add_tileset(NAME amplio2) - add_tileset(NAME cimpletoon) add_tileset(NAME hex2t) add_tileset(NAME hexemplio) add_tileset(NAME isophex) add_tileset(NAME isotrident) add_tileset(NAME trident) + # Cimpletoon option. Sprites shared by amplio2 and hexemplio + install( + DIRECTORY cimpletoon + DESTINATION "${CMAKE_INSTALL_DATADIR}/${PROJECT_NAME}" + COMPONENT freeciv21 + FILES_MATCHING PATTERN *.png PATTERN *.spec PATTERN README.*) + add_subdirectory(tilesets) # Misc diff --git a/data/amplio2.tilespec b/data/amplio2.tilespec index f5c586c85a..6419b662da 100644 --- a/data/amplio2.tilespec +++ b/data/amplio2.tilespec @@ -149,6 +149,7 @@ files = "misc/governments.spec", "misc/specialists.spec", "misc/units.spec", + "cimpletoon/orient_units.spec", "amplio2/veterancy.spec", "misc/flags-large.spec", "misc/buildings-large.spec", @@ -340,3 +341,8 @@ styles = "ts.horses", "Single1" "ts.seals", "Single1" } + +[option_cimpletoon] +name = "cimpletoon" +description = _("Use 3D Cimpletoon units") +default = FALSE diff --git a/data/cimpletoon.tilespec b/data/cimpletoon.tilespec deleted file mode 100644 index c2c6545dce..0000000000 --- a/data/cimpletoon.tilespec +++ /dev/null @@ -1,345 +0,0 @@ - -[tilespec] - -; Format and options of this tilespec file: -options = "+Freeciv-tilespec-Devel-2019-Jul-03" - -; A simple name for the tileset specified by this file: -name = "Cimpletoon" -priority = 25 - -; There`s no separate versioning in tilesets part of main freeciv distribution -;version = "" - -; Summary and full description of the tileset. -summary = _("\ -Variant of Amplio2 isometric tileset with unit sprites showing the \ -direction the unit is facing.\ -") -;description = "" - -; TODO: add more overall information fields on tiles, -; eg, authors, colors, etc. - -; Basic tile sizes: -normal_tile_width = 96 -normal_tile_height = 48 -small_tile_width = 15 -small_tile_height = 20 - -; Basic tile style. -type = "isometric" -is_hex = FALSE - -; Blended fog -fog_style = "Darkness" -darkness_style = "Corner" - -; offset the flags by this amount when drawing units -unit_flag_offset_x = 25 -unit_flag_offset_y = 16 -city_flag_offset_x = 2 -city_flag_offset_y = 9 - -; offset the city occupied sprite by this amount -occupied_offset_x = 0 -occupied_offset_y = 0 - -; offset the units by this amount -unit_offset_x = 19 -unit_offset_y = 18 - -; colors with this (HSL) hue will be replaced by the player color in city and -; unit sprites (-1 to disable) -replaced_hue = -1 - -; offset of the normal activity icons -activity_offset_x = 0 -activity_offset_y = 0 - -; offset of the selected unit sprites -select_offset_x = 0 -select_offset_y = 0 -; delay between two consecutive images -;select_step_ms = 100 - -; offset the cities by this amount -city_offset_x = 0 -city_offset_y = 0 - -; offset the city size number by this amount -; This is relative to full sprite origin. -city_size_offset_x = 0 -city_size_offset_y = 0 - -; offset the city bar text by this amount (from the city tile origin) -citybar_offset_y = 30 - -; offset the tile label text by this amount -tilelabel_offset_y = 15 - -; offset the upkeep icons by this amount from the top of the unit itself. -; The default is the normal tile height, which means that the upkeep icons -; appear below the unit icon if the unit icons are equal to tile height -; (typical in overhead tileset), or overlay lower part of the unit icon, -; if unit icon is higher than tiles (typical in iso tilesets) -;unit_upkeep_offset_y = 0 - -; Like unit_upkeep_offset_y, but to be used in case there`s only small -; space for the overall icon produced. Defaults to unit_upkeep_offset_y - -; not having alternative layout. -;unit_upkeep_small_offset_y = 0 - -; For tilesets with oriented units, the directional sprite to use to -; represent a unit type rather than a specific unit from the map -; (e.g., in worklists, editor, and online help). Does not have to be a -; valid direction for the tileset. -unit_default_orientation = "s" - -; The map is rendered in "layers", just like any decent image editor -; supports. The setting below allows to change the layer drawing order. The -; first layer in the list will be drawn below the others; the second on top -; of it, and so on. No layer can be omitted from the list, nor can new ones -; be added. -;layer_order = -; "Background", ; Background color (if enabled, the player color where there -; ; are units or cities). You probably want to leave this -; ; first. -; "Terrain1", ; The three terrain layers. See sections [layerN] below. -; "Darkness", ; Darkness (unseen tiles) -; "Terrain2", -; "Terrain3", -; "Water", ; All extras with "River" style. -; "Roads", ; All extras with style "RoadAllSeparate", -; ; "RoadParityCombined" or "RoadAllCombined". -; "Special1", ; 1st layer for extras with style "3Layers" or "Single1". -; "Grid1", ; Grid layer for isometric tilesets. -; "City1", ; City and walls. -; "Special2", ; 2nd layer for extras with "3Layers" and "Single2" styles. -; "Fog", ; Fog of war (on tiles one knows but doesn`t see). -; "Unit", ; Units except the selected one(s). -; "Special3", ; 3rd layer for extras with "3Layers" style. -; "BaseFlags", ; Base flags. -; "City2", ; City size when the city bar is disabled. -; "Grid2", ; Second grid layer (overhead tilesets only). -; "Overlays", ; Tile output sprites. -; "TileLabel", ; Tile labels ("Scorched spot"). -; "CityBar", ; The city bar with name, production, food, ... -; "FocusUnit", ; The focused unit(s). -; "Goto", ; Goto turn count and intermediate points, *not* goto lines. -; "WorkerTask", ; The unit task indicators ("G", "S", ...). -; "Editor", ; Editor stuff (selected tile and start points). -; "InfraWork" ; Icons for the extras being placed. - -; Below, the graphics spec files; must be somewhere (anywhere) in -; the data path. Order may be important for color allocation on -; low-color systems, and if there are any duplicate tags (lattermost -; tag is used). -files = - "amplio2/terrain1.spec", - "amplio2/maglev.spec", - "amplio2/terrain2.spec", - "amplio2/hills.spec", - "amplio2/mountains.spec", - "amplio2/ocean.spec", - "amplio2/water.spec", - "amplio2/tiles.spec", - "amplio2/upkeep.spec", - "amplio2/activities.spec", - "amplio2/fog.spec", - "misc/small.spec", - "misc/events.spec", - "misc/governments.spec", - "misc/specialists.spec", - "amplio2/veterancy.spec", - "cimpletoon/orient_units.spec", - "misc/flags-large.spec", - "misc/buildings-large.spec", - "misc/wonders-large.spec", - "misc/space.spec", - "misc/techs.spec", - "misc/treaty.spec", - "amplio2/nuke.spec", - "amplio2/explosions.spec", - "amplio2/cities.spec", - "amplio2/bases.spec", - "amplio2/select.spec", - "amplio2/grid.spec", - "misc/cursors.spec", - "misc/overlays.spec", - "misc/citybar.spec", - "misc/shields-large.spec", - "misc/editor.spec" - - -; Include color definitions -*include "misc/colors.tilespec" - -; Terrain info - see README.graphics - -[layer0] -match_types = "shallow", "deep", "land" - -[layer1] -match_types = "forest", "hills", "mountains", "water", "ice" - -[layer2] -match_types = "water", "ice" - -; Water graphics referenced by terrain.ruleset -; -[tile_lake] -tag = "lake" -blend_layer = 1 -num_layers = 1 -layer0_match_type = "shallow" -layer0_match_with = "land" -layer0_sprite_type = "corner" - -[tile_coast] -tag = "coast" -blend_layer = 1 -num_layers = 2 -layer0_match_type = "shallow" -layer0_match_with = "deep", "land" -layer0_sprite_type = "corner" -layer1_match_type = "water" -layer1_match_with = "ice" -layer1_sprite_type = "corner" - -[tile_floor] -tag = "floor" -blend_layer = 0 -num_layers = 2 -layer0_match_type = "deep" -layer0_match_with = "shallow", "land" -layer0_sprite_type = "corner" -layer1_match_type = "water" -layer1_match_with = "ice" -layer1_sprite_type = "corner" - -; Land graphics referenced by terrain.ruleset -; -[tile_arctic] -tag = "arctic" -; treated as water for ice cliffs -blend_layer = 0 -num_layers = 3 -layer0_match_type = "shallow" -layer1_match_type = "ice" -layer2_match_type = "ice" - -[tile_desert] -tag = "desert" -blend_layer = 1 -num_layers = 1 -layer0_match_type = "land" - -[tile_forest] -tag = "forest" -blend_layer = 1 -num_layers = 2 -layer0_match_type = "land" -layer1_match_type = "forest" -layer1_match_with = "forest" - -[tile_grassland] -tag = "grassland" -blend_layer = 1 -num_layers = 1 -layer0_match_type = "land" - -[tile_hills] -tag = "hills" -blend_layer = 1 -num_layers = 2 -layer0_match_type = "land" -layer1_match_type = "hills" -layer1_match_with = "hills" - -[tile_jungle] -tag = "jungle" -blend_layer = 1 -num_layers = 2 -layer0_match_type = "land" -layer1_match_type = "forest" -layer1_match_with = "forest" - -[tile_mountains] -tag = "mountains" -blend_layer = 1 -num_layers = 2 -layer0_match_type = "land" -layer1_match_type = "hills" -layer1_match_with = "hills" -layer1_is_tall = TRUE -layer1_offset_y = 6 - -[tile_plains] -tag = "plains" -blend_layer = 1 -num_layers = 1 -layer0_match_type = "land" - -[tile_swamp] -tag = "swamp" -blend_layer = 1 -num_layers = 1 -layer0_match_type = "land" - -[tile_tundra] -tag = "tundra" -blend_layer = 1 -num_layers = 1 -layer0_match_type = "land" - -[tile_inaccessible] -tag = "inaccessible" -blend_layer = 0 -num_layers = 1 -layer0_match_type = "land" - -[extras] -styles = - { "name", "style" - "road.road", "RoadAllSeparate" - "road.rail", "RoadAllSeparate" - "road.maglev", "RoadAllSeparate" - "road.river", "River" - "tx.irrigation", "Cardinals" - "tx.farmland", "Cardinals" - "tx.mine", "Single1" - "tx.oil_mine", "Single1" - "tx.oil_rig", "Single1" - "tx.pollution", "Single2" - "tx.fallout", "Single2" - "tx.village", "Single1" - "base.outpost", "3Layer" - "base.fortress", "3Layer" - "base.airstrip", "3Layer" - "base.airbase", "3Layer" - "base.buoy", "3Layer" - "extra.ruins", "3Layer" - "ts.gold", "Single1" - "ts.iron", "Single1" - "ts.tundra_game", "Single1" - "ts.furs", "Single1" - "ts.coal", "Single1" - "ts.fish", "Single1" - "ts.fruit", "Single1" - "ts.gems", "Single1" - "ts.buffalo", "Single1" - "ts.wheat", "Single1" - "ts.oasis", "Single1" - "ts.peat", "Single1" - "ts.pheasant", "Single1" - "ts.grassland_resources", "Single1" - "ts.arctic_ivory", "Single1" - "ts.silk", "Single1" - "ts.spice", "Single1" - "ts.whales", "Single1" - "ts.wine", "Single1" - "ts.oil", "Single1" - "ts.horses", "Single1" - "ts.seals", "Single1" - } diff --git a/data/cimpletoon/orient_units.spec b/data/cimpletoon/orient_units.spec index fc5e389c95..e1130b2719 100644 --- a/data/cimpletoon/orient_units.spec +++ b/data/cimpletoon/orient_units.spec @@ -2,7 +2,7 @@ [spec] ; Format and options of this spec file: -options = "+Freeciv-spec-Devel-2019-Jul-03" +options = "+Freeciv-spec-Devel-2019-Jul-03 options" [info] @@ -23,509 +23,509 @@ dx = 64 dy = 48 pixel_border = 1 -tiles = { "row", "column", "tag" - 0, 0, "u.settlers_sw" - 0, 1, "u.settlers_w" - 0, 2, "u.settlers_nw" - 0, 3, "u.settlers_n" - 0, 4, "u.settlers_ne" - 0, 5, "u.settlers_e" - 0, 6, "u.settlers_se" - 0, 7, "u.settlers_s" - - 1, 0, "u.warriors_sw" - 1, 1, "u.warriors_w" - 1, 2, "u.warriors_nw" - 1, 3, "u.warriors_n" - 1, 4, "u.warriors_ne" - 1, 5, "u.warriors_e" - 1, 6, "u.warriors_se" - 1, 7, "u.warriors_s" - - 2, 0, "u.explorer_sw" - 2, 1, "u.explorer_w" - 2, 2, "u.explorer_nw" - 2, 3, "u.explorer_n" - 2, 4, "u.explorer_ne" - 2, 5, "u.explorer_e" - 2, 6, "u.explorer_se" - 2, 7, "u.explorer_s" - - 3, 0, "u.worker_sw" - 3, 1, "u.worker_w" - 3, 2, "u.worker_nw" - 3, 3, "u.worker_n" - 3, 4, "u.worker_ne" - 3, 5, "u.worker_e" - 3, 6, "u.worker_se" - 3, 7, "u.worker_s" - - 4, 0, "u.horsemen_sw" - 4, 1, "u.horsemen_w" - 4, 2, "u.horsemen_nw" - 4, 3, "u.horsemen_n" - 4, 4, "u.horsemen_ne" - 4, 5, "u.horsemen_e" - 4, 6, "u.horsemen_se" - 4, 7, "u.horsemen_s" - - 5, 0, "u.archers_sw" - 5, 1, "u.archers_w" - 5, 2, "u.archers_nw" - 5, 3, "u.archers_n" - 5, 4, "u.archers_ne" - 5, 5, "u.archers_e" - 5, 6, "u.archers_se" - 5, 7, "u.archers_s" - - 6, 0, "u.phalanx_sw" - 6, 1, "u.phalanx_w" - 6, 2, "u.phalanx_nw" - 6, 3, "u.phalanx_n" - 6, 4, "u.phalanx_ne" - 6, 5, "u.phalanx_e" - 6, 6, "u.phalanx_se" - 6, 7, "u.phalanx_s" - - 7, 0, "u.trireme_sw" - 7, 1, "u.trireme_w" - 7, 2, "u.trireme_nw" - 7, 3, "u.trireme_n" - 7, 4, "u.trireme_ne" - 7, 5, "u.trireme_e" - 7, 6, "u.trireme_se" - 7, 7, "u.trireme_s" - - 8, 0, "u.chariot_sw" - 8, 1, "u.chariot_w" - 8, 2, "u.chariot_nw" - 8, 3, "u.chariot_n" - 8, 4, "u.chariot_ne" - 8, 5, "u.chariot_e" - 8, 6, "u.chariot_se" - 8, 7, "u.chariot_s" - - 9, 0, "u.catapult_sw" - 9, 1, "u.catapult_w" - 9, 2, "u.catapult_nw" - 9, 3, "u.catapult_n" - 9, 4, "u.catapult_ne" - 9, 5, "u.catapult_e" - 9, 6, "u.catapult_se" - 9, 7, "u.catapult_s" - - 10, 0, "u.legion_sw" - 10, 1, "u.legion_w" - 10, 2, "u.legion_nw" - 10, 3, "u.legion_n" - 10, 4, "u.legion_ne" - 10, 5, "u.legion_e" - 10, 6, "u.legion_se" - 10, 7, "u.legion_s" - - 11, 0, "u.diplomat_sw" - 11, 1, "u.diplomat_w" - 11, 2, "u.diplomat_nw" - 11, 3, "u.diplomat_n" - 11, 4, "u.diplomat_ne" - 11, 5, "u.diplomat_e" - 11, 6, "u.diplomat_se" - 11, 7, "u.diplomat_s" - - 12, 0, "u.caravan_sw" - 12, 1, "u.caravan_w" - 12, 2, "u.caravan_nw" - 12, 3, "u.caravan_n" - 12, 4, "u.caravan_ne" - 12, 5, "u.caravan_e" - 12, 6, "u.caravan_se" - 12, 7, "u.caravan_s" - - 13, 0, "u.pikemen_sw" - 13, 1, "u.pikemen_w" - 13, 2, "u.pikemen_nw" - 13, 3, "u.pikemen_n" - 13, 4, "u.pikemen_ne" - 13, 5, "u.pikemen_e" - 13, 6, "u.pikemen_se" - 13, 7, "u.pikemen_s" - - 14, 0, "u.knights_sw" - 14, 1, "u.knights_w" - 14, 2, "u.knights_nw" - 14, 3, "u.knights_n" - 14, 4, "u.knights_ne" - 14, 5, "u.knights_e" - 14, 6, "u.knights_se" - 14, 7, "u.knights_s" - - 15, 0, "u.caravel_sw" - 15, 1, "u.caravel_w" - 15, 2, "u.caravel_nw" - 15, 3, "u.caravel_n" - 15, 4, "u.caravel_ne" - 15, 5, "u.caravel_e" - 15, 6, "u.caravel_se" - 15, 7, "u.caravel_s" - - 16, 0, "u.galleon_sw" - 16, 1, "u.galleon_w" - 16, 2, "u.galleon_nw" - 16, 3, "u.galleon_n" - 16, 4, "u.galleon_ne" - 16, 5, "u.galleon_e" - 16, 6, "u.galleon_se" - 16, 7, "u.galleon_s" - - 17, 0, "u.frigate_sw" - 17, 1, "u.frigate_w" - 17, 2, "u.frigate_nw" - 17, 3, "u.frigate_n" - 17, 4, "u.frigate_ne" - 17, 5, "u.frigate_e" - 17, 6, "u.frigate_se" - 17, 7, "u.frigate_s" - - 18, 0, "u.ironclad_sw" - 18, 1, "u.ironclad_w" - 18, 2, "u.ironclad_nw" - 18, 3, "u.ironclad_n" - 18, 4, "u.ironclad_ne" - 18, 5, "u.ironclad_e" - 18, 6, "u.ironclad_se" - 18, 7, "u.ironclad_s" - - 19, 0, "u.musketeers_sw" - 19, 1, "u.musketeers_w" - 19, 2, "u.musketeers_nw" - 19, 3, "u.musketeers_n" - 19, 4, "u.musketeers_ne" - 19, 5, "u.musketeers_e" - 19, 6, "u.musketeers_se" - 19, 7, "u.musketeers_s" - - 20, 0, "u.dragoons_sw" - 20, 1, "u.dragoons_w" - 20, 2, "u.dragoons_nw" - 20, 3, "u.dragoons_n" - 20, 4, "u.dragoons_ne" - 20, 5, "u.dragoons_e" - 20, 6, "u.dragoons_se" - 20, 7, "u.dragoons_s" - - 21, 0, "u.cannon_sw" - 21, 1, "u.cannon_w" - 21, 2, "u.cannon_nw" - 21, 3, "u.cannon_n" - 21, 4, "u.cannon_ne" - 21, 5, "u.cannon_e" - 21, 6, "u.cannon_se" - 21, 7, "u.cannon_s" - - 22, 0, "u.engineers_sw" - 22, 1, "u.engineers_w" - 22, 2, "u.engineers_nw" - 22, 3, "u.engineers_n" - 22, 4, "u.engineers_ne" - 22, 5, "u.engineers_e" - 22, 6, "u.engineers_se" - 22, 7, "u.engineers_s" - - 23, 0, "u.transport_sw" - 23, 1, "u.transport_w" - 23, 2, "u.transport_nw" - 23, 3, "u.transport_n" - 23, 4, "u.transport_ne" - 23, 5, "u.transport_e" - 23, 6, "u.transport_se" - 23, 7, "u.transport_s" - - 24, 0, "u.destroyer_sw" - 24, 1, "u.destroyer_w" - 24, 2, "u.destroyer_nw" - 24, 3, "u.destroyer_n" - 24, 4, "u.destroyer_ne" - 24, 5, "u.destroyer_e" - 24, 6, "u.destroyer_se" - 24, 7, "u.destroyer_s" - - 25, 0, "u.riflemen_sw" - 25, 1, "u.riflemen_w" - 25, 2, "u.riflemen_nw" - 25, 3, "u.riflemen_n" - 25, 4, "u.riflemen_ne" - 25, 5, "u.riflemen_e" - 25, 6, "u.riflemen_se" - 25, 7, "u.riflemen_s" - - 26, 0, "u.cavalry_sw" - 26, 1, "u.cavalry_w" - 26, 2, "u.cavalry_nw" - 26, 3, "u.cavalry_n" - 26, 4, "u.cavalry_ne" - 26, 5, "u.cavalry_e" - 26, 6, "u.cavalry_se" - 26, 7, "u.cavalry_s" - - 27, 0, "u.alpine_troops_sw" - 27, 1, "u.alpine_troops_w" - 27, 2, "u.alpine_troops_nw" - 27, 3, "u.alpine_troops_n" - 27, 4, "u.alpine_troops_ne" - 27, 5, "u.alpine_troops_e" - 27, 6, "u.alpine_troops_se" - 27, 7, "u.alpine_troops_s" - - 28, 0, "u.freight_sw" - 28, 1, "u.freight_w" - 28, 2, "u.freight_nw" - 28, 3, "u.freight_n" - 28, 4, "u.freight_ne" - 28, 5, "u.freight_e" - 28, 6, "u.freight_se" - 28, 7, "u.freight_s" - - 29, 0, "u.spy_sw" - 29, 1, "u.spy_w" - 29, 2, "u.spy_nw" - 29, 3, "u.spy_n" - 29, 4, "u.spy_ne" - 29, 5, "u.spy_e" - 29, 6, "u.spy_se" - 29, 7, "u.spy_s" - - 30, 0, "u.cruiser_sw" - 30, 1, "u.cruiser_w" - 30, 2, "u.cruiser_nw" - 30, 3, "u.cruiser_n" - 30, 4, "u.cruiser_ne" - 30, 5, "u.cruiser_e" - 30, 6, "u.cruiser_se" - 30, 7, "u.cruiser_s" - - 31, 0, "u.battleship_sw" - 31, 1, "u.battleship_w" - 31, 2, "u.battleship_nw" - 31, 3, "u.battleship_n" - 31, 4, "u.battleship_ne" - 31, 5, "u.battleship_e" - 31, 6, "u.battleship_se" - 31, 7, "u.battleship_s" - - 32, 0, "u.submarine_sw" - 32, 1, "u.submarine_w" - 32, 2, "u.submarine_nw" - 32, 3, "u.submarine_n" - 32, 4, "u.submarine_ne" - 32, 5, "u.submarine_e" - 32, 6, "u.submarine_se" - 32, 7, "u.submarine_s" - - 33, 0, "u.marines_sw" - 33, 1, "u.marines_w" - 33, 2, "u.marines_nw" - 33, 3, "u.marines_n" - 33, 4, "u.marines_ne" - 33, 5, "u.marines_e" - 33, 6, "u.marines_se" - 33, 7, "u.marines_s" - - 34, 0, "u.partisan_sw" - 34, 1, "u.partisan_w" - 34, 2, "u.partisan_nw" - 34, 3, "u.partisan_n" - 34, 4, "u.partisan_ne" - 34, 5, "u.partisan_e" - 34, 6, "u.partisan_se" - 34, 7, "u.partisan_s" - - 35, 0, "u.artillery_sw" - 35, 1, "u.artillery_w" - 35, 2, "u.artillery_nw" - 35, 3, "u.artillery_n" - 35, 4, "u.artillery_ne" - 35, 5, "u.artillery_e" - 35, 6, "u.artillery_se" - 35, 7, "u.artillery_s" - - 36, 0, "u.fighter_sw" - 36, 1, "u.fighter_w" - 36, 2, "u.fighter_nw" - 36, 3, "u.fighter_n" - 36, 4, "u.fighter_ne" - 36, 5, "u.fighter_e" - 36, 6, "u.fighter_se" - 36, 7, "u.fighter_s" - - 37, 0, "u.aegis_cruiser_sw" - 37, 1, "u.aegis_cruiser_w" - 37, 2, "u.aegis_cruiser_nw" - 37, 3, "u.aegis_cruiser_n" - 37, 4, "u.aegis_cruiser_ne" - 37, 5, "u.aegis_cruiser_e" - 37, 6, "u.aegis_cruiser_se" - 37, 7, "u.aegis_cruiser_s" - - 38, 0, "u.carrier_sw" - 38, 1, "u.carrier_w" - 38, 2, "u.carrier_nw" - 38, 3, "u.carrier_n" - 38, 4, "u.carrier_ne" - 38, 5, "u.carrier_e" - 38, 6, "u.carrier_se" - 38, 7, "u.carrier_s" - - 39, 0, "u.armor_sw" - 39, 1, "u.armor_w" - 39, 2, "u.armor_nw" - 39, 3, "u.armor_n" - 39, 4, "u.armor_ne" - 39, 5, "u.armor_e" - 39, 6, "u.armor_se" - 39, 7, "u.armor_s" - - 40, 0, "u.mech_inf_sw" - 40, 1, "u.mech_inf_w" - 40, 2, "u.mech_inf_nw" - 40, 3, "u.mech_inf_n" - 40, 4, "u.mech_inf_ne" - 40, 5, "u.mech_inf_e" - 40, 6, "u.mech_inf_se" - 40, 7, "u.mech_inf_s" - - 41, 0, "u.howitzer_sw" - 41, 1, "u.howitzer_w" - 41, 2, "u.howitzer_nw" - 41, 3, "u.howitzer_n" - 41, 4, "u.howitzer_ne" - 41, 5, "u.howitzer_e" - 41, 6, "u.howitzer_se" - 41, 7, "u.howitzer_s" - - 42, 0, "u.paratroopers_sw" - 42, 1, "u.paratroopers_w" - 42, 2, "u.paratroopers_nw" - 42, 3, "u.paratroopers_n" - 42, 4, "u.paratroopers_ne" - 42, 5, "u.paratroopers_e" - 42, 6, "u.paratroopers_se" - 42, 7, "u.paratroopers_s" - - 43, 0, "u.helicopter_sw" - 43, 1, "u.helicopter_w" - 43, 2, "u.helicopter_nw" - 43, 3, "u.helicopter_n" - 43, 4, "u.helicopter_ne" - 43, 5, "u.helicopter_e" - 43, 6, "u.helicopter_se" - 43, 7, "u.helicopter_s" - - 44, 0, "u.bomber_sw" - 44, 1, "u.bomber_w" - 44, 2, "u.bomber_nw" - 44, 3, "u.bomber_n" - 44, 4, "u.bomber_ne" - 44, 5, "u.bomber_e" - 44, 6, "u.bomber_se" - 44, 7, "u.bomber_s" - - 45, 0, "u.awacs_sw" - 45, 1, "u.awacs_w" - 45, 2, "u.awacs_nw" - 45, 3, "u.awacs_n" - 45, 4, "u.awacs_ne" - 45, 5, "u.awacs_e" - 45, 6, "u.awacs_se" - 45, 7, "u.awacs_s" - - 46, 0, "u.nuclear_sw" - 46, 1, "u.nuclear_w" - 46, 2, "u.nuclear_nw" - 46, 3, "u.nuclear_n" - 46, 4, "u.nuclear_ne" - 46, 5, "u.nuclear_e" - 46, 6, "u.nuclear_se" - 46, 7, "u.nuclear_s" - - 47, 0, "u.cruise_missile_sw" - 47, 1, "u.cruise_missile_w" - 47, 2, "u.cruise_missile_nw" - 47, 3, "u.cruise_missile_n" - 47, 4, "u.cruise_missile_ne" - 47, 5, "u.cruise_missile_e" - 47, 6, "u.cruise_missile_se" - 47, 7, "u.cruise_missile_s" - - 48, 0, "u.stealth_bomber_sw" - 48, 1, "u.stealth_bomber_w" - 48, 2, "u.stealth_bomber_nw" - 48, 3, "u.stealth_bomber_n" - 48, 4, "u.stealth_bomber_ne" - 48, 5, "u.stealth_bomber_e" - 48, 6, "u.stealth_bomber_se" - 48, 7, "u.stealth_bomber_s" - - 49, 0, "u.stealth_fighter_sw" - 49, 1, "u.stealth_fighter_w" - 49, 2, "u.stealth_fighter_nw" - 49, 3, "u.stealth_fighter_n" - 49, 4, "u.stealth_fighter_ne" - 49, 5, "u.stealth_fighter_e" - 49, 6, "u.stealth_fighter_se" - 49, 7, "u.stealth_fighter_s" - - 50, 0, "u.leader_sw" - 50, 1, "u.leader_w" - 50, 2, "u.leader_nw" - 50, 3, "u.leader_n" - 50, 4, "u.leader_ne" - 50, 5, "u.leader_e" - 50, 6, "u.leader_se" - 50, 7, "u.leader_s" - - 51, 0, "u.barbarian_leader_sw" - 51, 1, "u.barbarian_leader_w" - 51, 2, "u.barbarian_leader_nw" - 51, 3, "u.barbarian_leader_n" - 51, 4, "u.barbarian_leader_ne" - 51, 5, "u.barbarian_leader_e" - 51, 6, "u.barbarian_leader_se" - 51, 7, "u.barbarian_leader_s" - - 52, 0, "u.fanatics_sw" - 52, 1, "u.fanatics_w" - 52, 2, "u.fanatics_nw" - 52, 3, "u.fanatics_n" - 52, 4, "u.fanatics_ne" - 52, 5, "u.fanatics_e" - 52, 6, "u.fanatics_se" - 52, 7, "u.fanatics_s" - - 53, 0, "u.crusaders_sw" - 53, 1, "u.crusaders_w" - 53, 2, "u.crusaders_nw" - 53, 3, "u.crusaders_n" - 53, 4, "u.crusaders_ne" - 53, 5, "u.crusaders_e" - 53, 6, "u.crusaders_se" - 53, 7, "u.crusaders_s" - - 54, 0, "u.elephants_sw" - 54, 1, "u.elephants_w" - 54, 2, "u.elephants_nw" - 54, 3, "u.elephants_n" - 54, 4, "u.elephants_ne" - 54, 5, "u.elephants_e" - 54, 6, "u.elephants_se" - 54, 7, "u.elephants_s" - - 55, 0, "u.migrants_sw" - 55, 1, "u.migrants_w" - 55, 2, "u.migrants_nw" - 55, 3, "u.migrants_n" - 55, 4, "u.migrants_ne" - 55, 5, "u.migrants_e" - 55, 6, "u.migrants_se" - 55, 7, "u.migrants_s" +tiles = { "row", "column", "option", "tag" + 0, 0, "cimpletoon", "u.settlers_sw" + 0, 1, "cimpletoon", "u.settlers_w" + 0, 2, "cimpletoon", "u.settlers_nw" + 0, 3, "cimpletoon", "u.settlers_n" + 0, 4, "cimpletoon", "u.settlers_ne" + 0, 5, "cimpletoon", "u.settlers_e" + 0, 6, "cimpletoon", "u.settlers_se" + 0, 7, "cimpletoon", "u.settlers_s" + + 1, 0, "cimpletoon", "u.warriors_sw" + 1, 1, "cimpletoon", "u.warriors_w" + 1, 2, "cimpletoon", "u.warriors_nw" + 1, 3, "cimpletoon", "u.warriors_n" + 1, 4, "cimpletoon", "u.warriors_ne" + 1, 5, "cimpletoon", "u.warriors_e" + 1, 6, "cimpletoon", "u.warriors_se" + 1, 7, "cimpletoon", "u.warriors_s" + + 2, 0, "cimpletoon", "u.explorer_sw" + 2, 1, "cimpletoon", "u.explorer_w" + 2, 2, "cimpletoon", "u.explorer_nw" + 2, 3, "cimpletoon", "u.explorer_n" + 2, 4, "cimpletoon", "u.explorer_ne" + 2, 5, "cimpletoon", "u.explorer_e" + 2, 6, "cimpletoon", "u.explorer_se" + 2, 7, "cimpletoon", "u.explorer_s" + + 3, 0, "cimpletoon", "u.worker_sw" + 3, 1, "cimpletoon", "u.worker_w" + 3, 2, "cimpletoon", "u.worker_nw" + 3, 3, "cimpletoon", "u.worker_n" + 3, 4, "cimpletoon", "u.worker_ne" + 3, 5, "cimpletoon", "u.worker_e" + 3, 6, "cimpletoon", "u.worker_se" + 3, 7, "cimpletoon", "u.worker_s" + + 4, 0, "cimpletoon", "u.horsemen_sw" + 4, 1, "cimpletoon", "u.horsemen_w" + 4, 2, "cimpletoon", "u.horsemen_nw" + 4, 3, "cimpletoon", "u.horsemen_n" + 4, 4, "cimpletoon", "u.horsemen_ne" + 4, 5, "cimpletoon", "u.horsemen_e" + 4, 6, "cimpletoon", "u.horsemen_se" + 4, 7, "cimpletoon", "u.horsemen_s" + + 5, 0, "cimpletoon", "u.archers_sw" + 5, 1, "cimpletoon", "u.archers_w" + 5, 2, "cimpletoon", "u.archers_nw" + 5, 3, "cimpletoon", "u.archers_n" + 5, 4, "cimpletoon", "u.archers_ne" + 5, 5, "cimpletoon", "u.archers_e" + 5, 6, "cimpletoon", "u.archers_se" + 5, 7, "cimpletoon", "u.archers_s" + + 6, 0, "cimpletoon", "u.phalanx_sw" + 6, 1, "cimpletoon", "u.phalanx_w" + 6, 2, "cimpletoon", "u.phalanx_nw" + 6, 3, "cimpletoon", "u.phalanx_n" + 6, 4, "cimpletoon", "u.phalanx_ne" + 6, 5, "cimpletoon", "u.phalanx_e" + 6, 6, "cimpletoon", "u.phalanx_se" + 6, 7, "cimpletoon", "u.phalanx_s" + + 7, 0, "cimpletoon", "u.trireme_sw" + 7, 1, "cimpletoon", "u.trireme_w" + 7, 2, "cimpletoon", "u.trireme_nw" + 7, 3, "cimpletoon", "u.trireme_n" + 7, 4, "cimpletoon", "u.trireme_ne" + 7, 5, "cimpletoon", "u.trireme_e" + 7, 6, "cimpletoon", "u.trireme_se" + 7, 7, "cimpletoon", "u.trireme_s" + + 8, 0, "cimpletoon", "u.chariot_sw" + 8, 1, "cimpletoon", "u.chariot_w" + 8, 2, "cimpletoon", "u.chariot_nw" + 8, 3, "cimpletoon", "u.chariot_n" + 8, 4, "cimpletoon", "u.chariot_ne" + 8, 5, "cimpletoon", "u.chariot_e" + 8, 6, "cimpletoon", "u.chariot_se" + 8, 7, "cimpletoon", "u.chariot_s" + + 9, 0, "cimpletoon", "u.catapult_sw" + 9, 1, "cimpletoon", "u.catapult_w" + 9, 2, "cimpletoon", "u.catapult_nw" + 9, 3, "cimpletoon", "u.catapult_n" + 9, 4, "cimpletoon", "u.catapult_ne" + 9, 5, "cimpletoon", "u.catapult_e" + 9, 6, "cimpletoon", "u.catapult_se" + 9, 7, "cimpletoon", "u.catapult_s" + + 10, 0, "cimpletoon", "u.legion_sw" + 10, 1, "cimpletoon", "u.legion_w" + 10, 2, "cimpletoon", "u.legion_nw" + 10, 3, "cimpletoon", "u.legion_n" + 10, 4, "cimpletoon", "u.legion_ne" + 10, 5, "cimpletoon", "u.legion_e" + 10, 6, "cimpletoon", "u.legion_se" + 10, 7, "cimpletoon", "u.legion_s" + + 11, 0, "cimpletoon", "u.diplomat_sw" + 11, 1, "cimpletoon", "u.diplomat_w" + 11, 2, "cimpletoon", "u.diplomat_nw" + 11, 3, "cimpletoon", "u.diplomat_n" + 11, 4, "cimpletoon", "u.diplomat_ne" + 11, 5, "cimpletoon", "u.diplomat_e" + 11, 6, "cimpletoon", "u.diplomat_se" + 11, 7, "cimpletoon", "u.diplomat_s" + + 12, 0, "cimpletoon", "u.caravan_sw" + 12, 1, "cimpletoon", "u.caravan_w" + 12, 2, "cimpletoon", "u.caravan_nw" + 12, 3, "cimpletoon", "u.caravan_n" + 12, 4, "cimpletoon", "u.caravan_ne" + 12, 5, "cimpletoon", "u.caravan_e" + 12, 6, "cimpletoon", "u.caravan_se" + 12, 7, "cimpletoon", "u.caravan_s" + + 13, 0, "cimpletoon", "u.pikemen_sw" + 13, 1, "cimpletoon", "u.pikemen_w" + 13, 2, "cimpletoon", "u.pikemen_nw" + 13, 3, "cimpletoon", "u.pikemen_n" + 13, 4, "cimpletoon", "u.pikemen_ne" + 13, 5, "cimpletoon", "u.pikemen_e" + 13, 6, "cimpletoon", "u.pikemen_se" + 13, 7, "cimpletoon", "u.pikemen_s" + + 14, 0, "cimpletoon", "u.knights_sw" + 14, 1, "cimpletoon", "u.knights_w" + 14, 2, "cimpletoon", "u.knights_nw" + 14, 3, "cimpletoon", "u.knights_n" + 14, 4, "cimpletoon", "u.knights_ne" + 14, 5, "cimpletoon", "u.knights_e" + 14, 6, "cimpletoon", "u.knights_se" + 14, 7, "cimpletoon", "u.knights_s" + + 15, 0, "cimpletoon", "u.caravel_sw" + 15, 1, "cimpletoon", "u.caravel_w" + 15, 2, "cimpletoon", "u.caravel_nw" + 15, 3, "cimpletoon", "u.caravel_n" + 15, 4, "cimpletoon", "u.caravel_ne" + 15, 5, "cimpletoon", "u.caravel_e" + 15, 6, "cimpletoon", "u.caravel_se" + 15, 7, "cimpletoon", "u.caravel_s" + + 16, 0, "cimpletoon", "u.galleon_sw" + 16, 1, "cimpletoon", "u.galleon_w" + 16, 2, "cimpletoon", "u.galleon_nw" + 16, 3, "cimpletoon", "u.galleon_n" + 16, 4, "cimpletoon", "u.galleon_ne" + 16, 5, "cimpletoon", "u.galleon_e" + 16, 6, "cimpletoon", "u.galleon_se" + 16, 7, "cimpletoon", "u.galleon_s" + + 17, 0, "cimpletoon", "u.frigate_sw" + 17, 1, "cimpletoon", "u.frigate_w" + 17, 2, "cimpletoon", "u.frigate_nw" + 17, 3, "cimpletoon", "u.frigate_n" + 17, 4, "cimpletoon", "u.frigate_ne" + 17, 5, "cimpletoon", "u.frigate_e" + 17, 6, "cimpletoon", "u.frigate_se" + 17, 7, "cimpletoon", "u.frigate_s" + + 18, 0, "cimpletoon", "u.ironclad_sw" + 18, 1, "cimpletoon", "u.ironclad_w" + 18, 2, "cimpletoon", "u.ironclad_nw" + 18, 3, "cimpletoon", "u.ironclad_n" + 18, 4, "cimpletoon", "u.ironclad_ne" + 18, 5, "cimpletoon", "u.ironclad_e" + 18, 6, "cimpletoon", "u.ironclad_se" + 18, 7, "cimpletoon", "u.ironclad_s" + + 19, 0, "cimpletoon", "u.musketeers_sw" + 19, 1, "cimpletoon", "u.musketeers_w" + 19, 2, "cimpletoon", "u.musketeers_nw" + 19, 3, "cimpletoon", "u.musketeers_n" + 19, 4, "cimpletoon", "u.musketeers_ne" + 19, 5, "cimpletoon", "u.musketeers_e" + 19, 6, "cimpletoon", "u.musketeers_se" + 19, 7, "cimpletoon", "u.musketeers_s" + + 20, 0, "cimpletoon", "u.dragoons_sw" + 20, 1, "cimpletoon", "u.dragoons_w" + 20, 2, "cimpletoon", "u.dragoons_nw" + 20, 3, "cimpletoon", "u.dragoons_n" + 20, 4, "cimpletoon", "u.dragoons_ne" + 20, 5, "cimpletoon", "u.dragoons_e" + 20, 6, "cimpletoon", "u.dragoons_se" + 20, 7, "cimpletoon", "u.dragoons_s" + + 21, 0, "cimpletoon", "u.cannon_sw" + 21, 1, "cimpletoon", "u.cannon_w" + 21, 2, "cimpletoon", "u.cannon_nw" + 21, 3, "cimpletoon", "u.cannon_n" + 21, 4, "cimpletoon", "u.cannon_ne" + 21, 5, "cimpletoon", "u.cannon_e" + 21, 6, "cimpletoon", "u.cannon_se" + 21, 7, "cimpletoon", "u.cannon_s" + + 22, 0, "cimpletoon", "u.engineers_sw" + 22, 1, "cimpletoon", "u.engineers_w" + 22, 2, "cimpletoon", "u.engineers_nw" + 22, 3, "cimpletoon", "u.engineers_n" + 22, 4, "cimpletoon", "u.engineers_ne" + 22, 5, "cimpletoon", "u.engineers_e" + 22, 6, "cimpletoon", "u.engineers_se" + 22, 7, "cimpletoon", "u.engineers_s" + + 23, 0, "cimpletoon", "u.transport_sw" + 23, 1, "cimpletoon", "u.transport_w" + 23, 2, "cimpletoon", "u.transport_nw" + 23, 3, "cimpletoon", "u.transport_n" + 23, 4, "cimpletoon", "u.transport_ne" + 23, 5, "cimpletoon", "u.transport_e" + 23, 6, "cimpletoon", "u.transport_se" + 23, 7, "cimpletoon", "u.transport_s" + + 24, 0, "cimpletoon", "u.destroyer_sw" + 24, 1, "cimpletoon", "u.destroyer_w" + 24, 2, "cimpletoon", "u.destroyer_nw" + 24, 3, "cimpletoon", "u.destroyer_n" + 24, 4, "cimpletoon", "u.destroyer_ne" + 24, 5, "cimpletoon", "u.destroyer_e" + 24, 6, "cimpletoon", "u.destroyer_se" + 24, 7, "cimpletoon", "u.destroyer_s" + + 25, 0, "cimpletoon", "u.riflemen_sw" + 25, 1, "cimpletoon", "u.riflemen_w" + 25, 2, "cimpletoon", "u.riflemen_nw" + 25, 3, "cimpletoon", "u.riflemen_n" + 25, 4, "cimpletoon", "u.riflemen_ne" + 25, 5, "cimpletoon", "u.riflemen_e" + 25, 6, "cimpletoon", "u.riflemen_se" + 25, 7, "cimpletoon", "u.riflemen_s" + + 26, 0, "cimpletoon", "u.cavalry_sw" + 26, 1, "cimpletoon", "u.cavalry_w" + 26, 2, "cimpletoon", "u.cavalry_nw" + 26, 3, "cimpletoon", "u.cavalry_n" + 26, 4, "cimpletoon", "u.cavalry_ne" + 26, 5, "cimpletoon", "u.cavalry_e" + 26, 6, "cimpletoon", "u.cavalry_se" + 26, 7, "cimpletoon", "u.cavalry_s" + + 27, 0, "cimpletoon", "u.alpine_troops_sw" + 27, 1, "cimpletoon", "u.alpine_troops_w" + 27, 2, "cimpletoon", "u.alpine_troops_nw" + 27, 3, "cimpletoon", "u.alpine_troops_n" + 27, 4, "cimpletoon", "u.alpine_troops_ne" + 27, 5, "cimpletoon", "u.alpine_troops_e" + 27, 6, "cimpletoon", "u.alpine_troops_se" + 27, 7, "cimpletoon", "u.alpine_troops_s" + + 28, 0, "cimpletoon", "u.freight_sw" + 28, 1, "cimpletoon", "u.freight_w" + 28, 2, "cimpletoon", "u.freight_nw" + 28, 3, "cimpletoon", "u.freight_n" + 28, 4, "cimpletoon", "u.freight_ne" + 28, 5, "cimpletoon", "u.freight_e" + 28, 6, "cimpletoon", "u.freight_se" + 28, 7, "cimpletoon", "u.freight_s" + + 29, 0, "cimpletoon", "u.spy_sw" + 29, 1, "cimpletoon", "u.spy_w" + 29, 2, "cimpletoon", "u.spy_nw" + 29, 3, "cimpletoon", "u.spy_n" + 29, 4, "cimpletoon", "u.spy_ne" + 29, 5, "cimpletoon", "u.spy_e" + 29, 6, "cimpletoon", "u.spy_se" + 29, 7, "cimpletoon", "u.spy_s" + + 30, 0, "cimpletoon", "u.cruiser_sw" + 30, 1, "cimpletoon", "u.cruiser_w" + 30, 2, "cimpletoon", "u.cruiser_nw" + 30, 3, "cimpletoon", "u.cruiser_n" + 30, 4, "cimpletoon", "u.cruiser_ne" + 30, 5, "cimpletoon", "u.cruiser_e" + 30, 6, "cimpletoon", "u.cruiser_se" + 30, 7, "cimpletoon", "u.cruiser_s" + + 31, 0, "cimpletoon", "u.battleship_sw" + 31, 1, "cimpletoon", "u.battleship_w" + 31, 2, "cimpletoon", "u.battleship_nw" + 31, 3, "cimpletoon", "u.battleship_n" + 31, 4, "cimpletoon", "u.battleship_ne" + 31, 5, "cimpletoon", "u.battleship_e" + 31, 6, "cimpletoon", "u.battleship_se" + 31, 7, "cimpletoon", "u.battleship_s" + + 32, 0, "cimpletoon", "u.submarine_sw" + 32, 1, "cimpletoon", "u.submarine_w" + 32, 2, "cimpletoon", "u.submarine_nw" + 32, 3, "cimpletoon", "u.submarine_n" + 32, 4, "cimpletoon", "u.submarine_ne" + 32, 5, "cimpletoon", "u.submarine_e" + 32, 6, "cimpletoon", "u.submarine_se" + 32, 7, "cimpletoon", "u.submarine_s" + + 33, 0, "cimpletoon", "u.marines_sw" + 33, 1, "cimpletoon", "u.marines_w" + 33, 2, "cimpletoon", "u.marines_nw" + 33, 3, "cimpletoon", "u.marines_n" + 33, 4, "cimpletoon", "u.marines_ne" + 33, 5, "cimpletoon", "u.marines_e" + 33, 6, "cimpletoon", "u.marines_se" + 33, 7, "cimpletoon", "u.marines_s" + + 34, 0, "cimpletoon", "u.partisan_sw" + 34, 1, "cimpletoon", "u.partisan_w" + 34, 2, "cimpletoon", "u.partisan_nw" + 34, 3, "cimpletoon", "u.partisan_n" + 34, 4, "cimpletoon", "u.partisan_ne" + 34, 5, "cimpletoon", "u.partisan_e" + 34, 6, "cimpletoon", "u.partisan_se" + 34, 7, "cimpletoon", "u.partisan_s" + + 35, 0, "cimpletoon", "u.artillery_sw" + 35, 1, "cimpletoon", "u.artillery_w" + 35, 2, "cimpletoon", "u.artillery_nw" + 35, 3, "cimpletoon", "u.artillery_n" + 35, 4, "cimpletoon", "u.artillery_ne" + 35, 5, "cimpletoon", "u.artillery_e" + 35, 6, "cimpletoon", "u.artillery_se" + 35, 7, "cimpletoon", "u.artillery_s" + + 36, 0, "cimpletoon", "u.fighter_sw" + 36, 1, "cimpletoon", "u.fighter_w" + 36, 2, "cimpletoon", "u.fighter_nw" + 36, 3, "cimpletoon", "u.fighter_n" + 36, 4, "cimpletoon", "u.fighter_ne" + 36, 5, "cimpletoon", "u.fighter_e" + 36, 6, "cimpletoon", "u.fighter_se" + 36, 7, "cimpletoon", "u.fighter_s" + + 37, 0, "cimpletoon", "u.aegis_cruiser_sw" + 37, 1, "cimpletoon", "u.aegis_cruiser_w" + 37, 2, "cimpletoon", "u.aegis_cruiser_nw" + 37, 3, "cimpletoon", "u.aegis_cruiser_n" + 37, 4, "cimpletoon", "u.aegis_cruiser_ne" + 37, 5, "cimpletoon", "u.aegis_cruiser_e" + 37, 6, "cimpletoon", "u.aegis_cruiser_se" + 37, 7, "cimpletoon", "u.aegis_cruiser_s" + + 38, 0, "cimpletoon", "u.carrier_sw" + 38, 1, "cimpletoon", "u.carrier_w" + 38, 2, "cimpletoon", "u.carrier_nw" + 38, 3, "cimpletoon", "u.carrier_n" + 38, 4, "cimpletoon", "u.carrier_ne" + 38, 5, "cimpletoon", "u.carrier_e" + 38, 6, "cimpletoon", "u.carrier_se" + 38, 7, "cimpletoon", "u.carrier_s" + + 39, 0, "cimpletoon", "u.armor_sw" + 39, 1, "cimpletoon", "u.armor_w" + 39, 2, "cimpletoon", "u.armor_nw" + 39, 3, "cimpletoon", "u.armor_n" + 39, 4, "cimpletoon", "u.armor_ne" + 39, 5, "cimpletoon", "u.armor_e" + 39, 6, "cimpletoon", "u.armor_se" + 39, 7, "cimpletoon", "u.armor_s" + + 40, 0, "cimpletoon", "u.mech_inf_sw" + 40, 1, "cimpletoon", "u.mech_inf_w" + 40, 2, "cimpletoon", "u.mech_inf_nw" + 40, 3, "cimpletoon", "u.mech_inf_n" + 40, 4, "cimpletoon", "u.mech_inf_ne" + 40, 5, "cimpletoon", "u.mech_inf_e" + 40, 6, "cimpletoon", "u.mech_inf_se" + 40, 7, "cimpletoon", "u.mech_inf_s" + + 41, 0, "cimpletoon", "u.howitzer_sw" + 41, 1, "cimpletoon", "u.howitzer_w" + 41, 2, "cimpletoon", "u.howitzer_nw" + 41, 3, "cimpletoon", "u.howitzer_n" + 41, 4, "cimpletoon", "u.howitzer_ne" + 41, 5, "cimpletoon", "u.howitzer_e" + 41, 6, "cimpletoon", "u.howitzer_se" + 41, 7, "cimpletoon", "u.howitzer_s" + + 42, 0, "cimpletoon", "u.paratroopers_sw" + 42, 1, "cimpletoon", "u.paratroopers_w" + 42, 2, "cimpletoon", "u.paratroopers_nw" + 42, 3, "cimpletoon", "u.paratroopers_n" + 42, 4, "cimpletoon", "u.paratroopers_ne" + 42, 5, "cimpletoon", "u.paratroopers_e" + 42, 6, "cimpletoon", "u.paratroopers_se" + 42, 7, "cimpletoon", "u.paratroopers_s" + + 43, 0, "cimpletoon", "u.helicopter_sw" + 43, 1, "cimpletoon", "u.helicopter_w" + 43, 2, "cimpletoon", "u.helicopter_nw" + 43, 3, "cimpletoon", "u.helicopter_n" + 43, 4, "cimpletoon", "u.helicopter_ne" + 43, 5, "cimpletoon", "u.helicopter_e" + 43, 6, "cimpletoon", "u.helicopter_se" + 43, 7, "cimpletoon", "u.helicopter_s" + + 44, 0, "cimpletoon", "u.bomber_sw" + 44, 1, "cimpletoon", "u.bomber_w" + 44, 2, "cimpletoon", "u.bomber_nw" + 44, 3, "cimpletoon", "u.bomber_n" + 44, 4, "cimpletoon", "u.bomber_ne" + 44, 5, "cimpletoon", "u.bomber_e" + 44, 6, "cimpletoon", "u.bomber_se" + 44, 7, "cimpletoon", "u.bomber_s" + + 45, 0, "cimpletoon", "u.awacs_sw" + 45, 1, "cimpletoon", "u.awacs_w" + 45, 2, "cimpletoon", "u.awacs_nw" + 45, 3, "cimpletoon", "u.awacs_n" + 45, 4, "cimpletoon", "u.awacs_ne" + 45, 5, "cimpletoon", "u.awacs_e" + 45, 6, "cimpletoon", "u.awacs_se" + 45, 7, "cimpletoon", "u.awacs_s" + + 46, 0, "cimpletoon", "u.nuclear_sw" + 46, 1, "cimpletoon", "u.nuclear_w" + 46, 2, "cimpletoon", "u.nuclear_nw" + 46, 3, "cimpletoon", "u.nuclear_n" + 46, 4, "cimpletoon", "u.nuclear_ne" + 46, 5, "cimpletoon", "u.nuclear_e" + 46, 6, "cimpletoon", "u.nuclear_se" + 46, 7, "cimpletoon", "u.nuclear_s" + + 47, 0, "cimpletoon", "u.cruise_missile_sw" + 47, 1, "cimpletoon", "u.cruise_missile_w" + 47, 2, "cimpletoon", "u.cruise_missile_nw" + 47, 3, "cimpletoon", "u.cruise_missile_n" + 47, 4, "cimpletoon", "u.cruise_missile_ne" + 47, 5, "cimpletoon", "u.cruise_missile_e" + 47, 6, "cimpletoon", "u.cruise_missile_se" + 47, 7, "cimpletoon", "u.cruise_missile_s" + + 48, 0, "cimpletoon", "u.stealth_bomber_sw" + 48, 1, "cimpletoon", "u.stealth_bomber_w" + 48, 2, "cimpletoon", "u.stealth_bomber_nw" + 48, 3, "cimpletoon", "u.stealth_bomber_n" + 48, 4, "cimpletoon", "u.stealth_bomber_ne" + 48, 5, "cimpletoon", "u.stealth_bomber_e" + 48, 6, "cimpletoon", "u.stealth_bomber_se" + 48, 7, "cimpletoon", "u.stealth_bomber_s" + + 49, 0, "cimpletoon", "u.stealth_fighter_sw" + 49, 1, "cimpletoon", "u.stealth_fighter_w" + 49, 2, "cimpletoon", "u.stealth_fighter_nw" + 49, 3, "cimpletoon", "u.stealth_fighter_n" + 49, 4, "cimpletoon", "u.stealth_fighter_ne" + 49, 5, "cimpletoon", "u.stealth_fighter_e" + 49, 6, "cimpletoon", "u.stealth_fighter_se" + 49, 7, "cimpletoon", "u.stealth_fighter_s" + + 50, 0, "cimpletoon", "u.leader_sw" + 50, 1, "cimpletoon", "u.leader_w" + 50, 2, "cimpletoon", "u.leader_nw" + 50, 3, "cimpletoon", "u.leader_n" + 50, 4, "cimpletoon", "u.leader_ne" + 50, 5, "cimpletoon", "u.leader_e" + 50, 6, "cimpletoon", "u.leader_se" + 50, 7, "cimpletoon", "u.leader_s" + + 51, 0, "cimpletoon", "u.barbarian_leader_sw" + 51, 1, "cimpletoon", "u.barbarian_leader_w" + 51, 2, "cimpletoon", "u.barbarian_leader_nw" + 51, 3, "cimpletoon", "u.barbarian_leader_n" + 51, 4, "cimpletoon", "u.barbarian_leader_ne" + 51, 5, "cimpletoon", "u.barbarian_leader_e" + 51, 6, "cimpletoon", "u.barbarian_leader_se" + 51, 7, "cimpletoon", "u.barbarian_leader_s" + + 52, 0, "cimpletoon", "u.fanatics_sw" + 52, 1, "cimpletoon", "u.fanatics_w" + 52, 2, "cimpletoon", "u.fanatics_nw" + 52, 3, "cimpletoon", "u.fanatics_n" + 52, 4, "cimpletoon", "u.fanatics_ne" + 52, 5, "cimpletoon", "u.fanatics_e" + 52, 6, "cimpletoon", "u.fanatics_se" + 52, 7, "cimpletoon", "u.fanatics_s" + + 53, 0, "cimpletoon", "u.crusaders_sw" + 53, 1, "cimpletoon", "u.crusaders_w" + 53, 2, "cimpletoon", "u.crusaders_nw" + 53, 3, "cimpletoon", "u.crusaders_n" + 53, 4, "cimpletoon", "u.crusaders_ne" + 53, 5, "cimpletoon", "u.crusaders_e" + 53, 6, "cimpletoon", "u.crusaders_se" + 53, 7, "cimpletoon", "u.crusaders_s" + + 54, 0, "cimpletoon", "u.elephants_sw" + 54, 1, "cimpletoon", "u.elephants_w" + 54, 2, "cimpletoon", "u.elephants_nw" + 54, 3, "cimpletoon", "u.elephants_n" + 54, 4, "cimpletoon", "u.elephants_ne" + 54, 5, "cimpletoon", "u.elephants_e" + 54, 6, "cimpletoon", "u.elephants_se" + 54, 7, "cimpletoon", "u.elephants_s" + + 55, 0, "cimpletoon", "u.migrants_sw" + 55, 1, "cimpletoon", "u.migrants_w" + 55, 2, "cimpletoon", "u.migrants_nw" + 55, 3, "cimpletoon", "u.migrants_n" + 55, 4, "cimpletoon", "u.migrants_ne" + 55, 5, "cimpletoon", "u.migrants_e" + 55, 6, "cimpletoon", "u.migrants_se" + 55, 7, "cimpletoon", "u.migrants_s" } diff --git a/data/hexemplio.tilespec b/data/hexemplio.tilespec index 15318b8f6f..8055a3cacd 100644 --- a/data/hexemplio.tilespec +++ b/data/hexemplio.tilespec @@ -155,6 +155,7 @@ files = "misc/treaty.spec", "misc/editor.spec", "misc/units.spec", + "cimpletoon/orient_units.spec", "amplio2/nuke.spec", "amplio2/explosions.spec", "hexemplio/activities.spec", @@ -359,3 +360,8 @@ styles = "ts.horses", "Single1" "ts.seals", "Single1" } + +[option_cimpletoon] +name = "cimpletoon" +description = _("Use 3D Cimpletoon units") +default = FALSE diff --git a/data/toonhex.tilespec b/data/toonhex.tilespec deleted file mode 100644 index 2ad1840456..0000000000 --- a/data/toonhex.tilespec +++ /dev/null @@ -1,364 +0,0 @@ - -[tilespec] - -; Format and options of this tilespec file: -options = "+Freeciv-tilespec-Devel-2019-Jul-03" - -; A simple name for the tileset specified by this file: -name = "Toonhex" -; Based on hexemplio, which in turn is based on -; amplio2hexgbig by GriffonSpade - -priority = 3 - -; There`s no separate versioning in tilesets part of main freeciv distribution -;version = "" - -; Summary and full description of the tileset. -summary = _("Large iso-hex tileset combining Hexemplio's terrains \ -and Cimpletoon's units with orientation.") -;description = "" - -; TODO: add more overall information fields on tiles, -; eg, authors, colors, etc. - -; Basic tile sizes: -normal_tile_width = 126 -normal_tile_height = 64 -small_tile_width = 15 -small_tile_height = 20 - -; Basic tile style. -hex_side = 16 -is_hex = TRUE -type = "isometric" - -; Use old iso style -fog_style = "Auto" - -; Was darkness style "IsoRect" (single-sprite) -darkness_style = "CardinalSingle" - -; offset the flags by this amount when drawing units -unit_flag_offset_x = 45 -unit_flag_offset_y = 39 -city_flag_offset_x = 41 -city_flag_offset_y = 10 - -; offset the city occupied sprite by this amount -occupied_offset_x = 0 -occupied_offset_y = 0 - -; offset the units by this amount -unit_offset_x = 34 -unit_offset_y = 38 - -; colors with this (HSL) hue will be replaced by the player color in city and -; unit sprites (-1 to disable) -replaced_hue = -1 - -; offset of the normal activity icons -activity_offset_x = 74 -activity_offset_y = 28 - -; offset of the selected unit sprites -select_offset_x = 0 -select_offset_y = 21 -; delay between two consecutive images -;select_step_ms = 100 - -; offset the cities by this amount -city_offset_x = 17 -city_offset_y = 21 - -; offset the city size number by this amount -; This is relative to full sprite origin. -city_size_offset_x = 0 -city_size_offset_y = 0 - -; offset the city bar text by this amount (from the city tile origin) -citybar_offset_y = 40 - -; offset the tile label text by this amount -tilelabel_offset_y = 20 - -; offset the upkeep icons by this amount from the top of the unit itself. -; The default is the normal tile height, which means that the upkeep icons -; appear below the unit icon if the unit icons are equal to tile height -; (typical in overhead tileset), or overlay lower part of the unit icon, -; if unit icon is higher than tiles (typical in iso tilesets) -;unit_upkeep_offset_y = 0 - -; Like unit_upkeep_offset_y, but to be used in case there`s only small -; space for the overall icon produced. Defaults to unit_upkeep_offset_y - -; not having alternative layout. -;unit_upkeep_small_offset_y = 0 - -; For tilesets with oriented units, the directional sprite to use to -; represent a unit type rather than a specific unit from the map -; (e.g., in worklists, editor, and online help). Does not have to be a -; valid direction for the tileset. -unit_default_orientation = "s" - -; The map is rendered in "layers", just like any decent image editor -; supports. The setting below allows to change the layer drawing order. The -; first layer in the list will be drawn below the others; the second on top -; of it, and so on. No layer can be omitted from the list, nor can new ones -; be added. -layer_order = - "Background", ; Background color (if enabled, the player color where there - ; are units or cities). You probably want to leave this - ; first. - "Terrain1", ; The three terrain layers. See sections [layerN] below. - "Terrain2", - "Darkness", ; Darkness (unseen tiles) - "Terrain3", - "Water", ; All extras with "River" style. - "Roads", ; All extras with style "RoadAllSeparate", - ; "RoadParityCombined" or "RoadAllCombined". - "Special1", ; 1st layer for extras with style "3Layers" or "Single1". - "Grid1", ; Grid layer for isometric tilesets. - "City1", ; City and walls. - "Special2", ; 2nd layer for extras with "3Layers" and "Single2" styles. - "Fog", ; Fog of war (on tiles one knows but doesn`t see). - "Unit", ; Units except the selected one(s). - "Special3", ; 3rd layer for extras with "3Layers" style. - "BaseFlags", ; Base flags. - "City2", ; City size when the city bar is disabled. - "Grid2", ; Second grid layer (overhead tilesets only). - "Overlays", ; Tile output sprites. - "TileLabel", ; Tile labels ("Scorched spot"). - "CityBar", ; The city bar with name, production, food, ... - "FocusUnit", ; The focused unit(s). - "Goto", ; Goto turn count and intermediate points, *not* goto lines. - "WorkerTask", ; The unit task indicators ("G", "S", ...). - "Editor", ; Editor stuff (selected tile and start points). - "InfraWork" ; Icons for the extras being placed. - -; Below, the graphics spec files; must be somewhere (anywhere) in -; the data path. Order may be important for color allocation on -; low-color systems, and if there are any duplicate tags (lattermost -; tag is used). - -files = - "misc/overlays.spec", - "misc/citybar.spec", - "misc/small.spec", - "misc/governments.spec", - "misc/specialists.spec", - "misc/events.spec", - "misc/buildings-large.spec", - "misc/wonders-large.spec", - "misc/flags-large.spec", - "misc/shields-large.spec", - "misc/cursors.spec", - "misc/space.spec", - "misc/techs.spec", - "misc/treaty.spec", - "misc/editor.spec", - "cimpletoon/orient_units.spec", - "amplio2/nuke.spec", - "amplio2/explosions.spec", - "hexemplio/activities.spec", - "hexemplio/bases.spec", - "hexemplio/cities.spec", - "hexemplio/terrain.spec", - "hexemplio/embellishments.spec", - "hexemplio/forests.spec", - "hexemplio/hills.spec", - "hexemplio/mountains.spec", - "hexemplio/tiles.spec", - "hexemplio/grid.spec", - "hexemplio/rivers.spec", - "hexemplio/roads.spec", - "hexemplio/roads-rails.spec", - "hexemplio/roads-maglevs.spec", - "hexemplio/unitextras.spec", - "hexemplio/unitcost.spec", - "hexemplio/select.spec", - "hexemplio/water1.spec", - "hexemplio/water2.spec", - "hexemplio/water3.spec" - - -; Include color definitions -*include "misc/colors.tilespec" - -; Terrain info - see README.graphics - -[layer0] -match_types = "floor", "coast", "lake" - -[layer1] -match_types = "water", "land" - -[layer2] -match_types = "hills", "foliage" - -; Water graphics referenced by terrain.ruleset -; - -[tile_lake] -tag = "lake" -blend_layer = 2 -num_layers = 2 -layer0_match_type = "lake" -layer0_match_with = "lake" -layer0_sprite_type = "corner" -layer1_match_type = "water" -layer1_match_with = "water" -layer1_sprite_type = "corner" - -[tile_coast] -tag = "coast" -blend_layer = 2 -num_layers = 2 -layer0_match_type = "coast" -layer1_match_type = "water" -layer1_match_with = "water" -layer1_sprite_type = "corner" - -[tile_floor] -tag = "floor" -blend_layer = 2 -num_layers = 2 -layer0_match_type = "floor" -layer0_match_with = "floor" -layer0_sprite_type = "corner" -layer1_match_type = "water" -layer1_match_with = "water" -layer1_sprite_type = "corner" - -[tile_inaccessible] -tag = "inaccessible" -blend_layer = 0 -num_layers = 2 -layer0_match_type = "floor" -layer1_match_type = "land" - -; Land graphics referenced by terrain.ruleset -; - -[tile_arctic] -tag = "arctic" -blend_layer = 0 -num_layers = 2 -layer0_match_type = "lake" -layer1_match_type = "water" - -[tile_desert] -tag = "desert" -blend_layer = 1 -num_layers = 2 -layer0_match_type = "lake" -layer1_match_type = "land" - -[tile_forest] -tag = "forest" -blend_layer = 1 -num_layers = 3 -layer0_match_type = "lake" -layer1_match_type = "land" -layer2_match_type = "foliage" -layer2_match_with = "foliage" - -[tile_grassland] -tag = "grassland" -blend_layer = 1 -num_layers = 2 -layer0_match_type = "lake" -layer1_match_type = "land" - -[tile_hills] -tag = "hills" -blend_layer = 1 -num_layers = 3 -layer0_match_type = "lake" -layer1_match_type = "land" -layer2_match_type = "hills" -layer2_match_with = "hills" - -[tile_jungle] -tag = "jungle" -blend_layer = 1 -num_layers = 3 -layer0_match_type = "lake" -layer1_match_type = "land" -layer2_match_type = "foliage" -layer2_match_with = "foliage" - -[tile_mountains] -tag = "mountains" -blend_layer = 1 -num_layers = 3 -layer0_match_type = "lake" -layer1_match_type = "land" -layer2_match_type = "hills" -layer2_match_with = "hills" - -[tile_plains] -tag = "plains" -blend_layer = 1 -num_layers = 2 -layer0_match_type = "lake" -layer1_match_type = "land" - -[tile_swamp] -tag = "swamp" -blend_layer = 1 -num_layers = 2 -layer0_match_type = "lake" -layer1_match_type = "land" - -[tile_tundra] -tag = "tundra" -blend_layer = 1 -num_layers = 2 -layer0_match_type = "lake" -layer1_match_type = "land" - -[extras] -styles = - { "name", "style" - "road.road", "RoadAllSeparate" - "road.rail", "RoadAllCombined" - "road.maglev", "RoadAllCombined" - "road.pave", "RoadAllSeparate" - "road.river", "River" - "tx.irrigation", "River" - "tx.farmland", "River" - "tx.mine", "Single1" - "tx.oil_mine", "Single1" - "tx.oil_rig", "Single1" - "tx.pollution", "Single2" - "tx.fallout", "Single2" - "tx.village", "Single1" - "base.outpost", "3Layer" - "base.fortress", "3Layer" - "base.airstrip", "3Layer" - "base.airbase", "3layer" - "base.buoy", "3layer" - "extra.ruins", "3layer" - "ts.gold", "Single1" - "ts.iron", "Single1" - "ts.tundra_game", "Single1" - "ts.furs", "Single1" - "ts.coal", "Single1" - "ts.fish", "Single1" - "ts.fruit", "Single1" - "ts.gems", "Single1" - "ts.buffalo", "Single1" - "ts.wheat", "Single1" - "ts.oasis", "Single1" - "ts.peat", "Single1" - "ts.pheasant", "Single1" - "ts.grassland_resources", "Single1" - "ts.arctic_ivory", "Single1" - "ts.silk", "Single1" - "ts.spice", "Single1" - "ts.whales", "Single1" - "ts.wine", "Single1" - "ts.oil", "Single1" - "ts.horses", "Single1" - "ts.seals", "Single1" - } diff --git a/docs/Manuals/Game/menu.rst b/docs/Manuals/Game/menu.rst index 5cf0f430a3..3770aaa3ff 100644 --- a/docs/Manuals/Game/menu.rst +++ b/docs/Manuals/Game/menu.rst @@ -114,6 +114,9 @@ Add Modpacks Launches the modpack installer. This utility allows the Longturn community to create third-party content and offer it for enhanced gameplay. For more information refer to :doc:`/Manuals/modpack-installer`. +Tileset Options + For tilesets supporting it, opens a dialog that lets you change the appearance of the map. + Tileset Debugger Opens the :guilabel:`Tileset Debugger` dialog. This option is documented in :doc:`/Modding/Tilesets/debugger` diff --git a/docs/Modding/Tilesets/compatibility.rst b/docs/Modding/Tilesets/compatibility.rst index 583a01fee3..1e30c88377 100644 --- a/docs/Modding/Tilesets/compatibility.rst +++ b/docs/Modding/Tilesets/compatibility.rst @@ -1,7 +1,7 @@ .. SPDX-License-Identifier: GPL-3.0-or-later .. SPDX-FileCopyrightText: Louis Moureaux <m_louis30@yahoo.com> -Tileset compatibility +Tileset Compatibility ********************* The tileset format evolves when new Freeciv21 releases are published. As a rule of thumb, we try @@ -50,3 +50,6 @@ terrain-specific-extras bases is expected to roll out soon. To use terrain-specific sprites, use the same nomenclature as before, but with the terrain time included after the type of extra. E.g. ``road.road_isolated`` becomes ``road.road_mountain_isolated``. + +options + Support for this option signals that :doc:`options` are available. diff --git a/docs/Modding/Tilesets/options.rst b/docs/Modding/Tilesets/options.rst new file mode 100644 index 0000000000..4cbe72af95 --- /dev/null +++ b/docs/Modding/Tilesets/options.rst @@ -0,0 +1,75 @@ +.. SPDX-License-Identifier: GPL-3.0-or-later +.. SPDX-FileCopyrightText: Louis Moureaux <m_louis30@yahoo.com> + +.. role:: unit + +Tileset Options +*************** + +It is often possible to introduce slight variations in a tileset. One may +have, for instance, multiple versions of unit sprites. In such cases, it may +make sense to let the user choose between the two options. This is enabled +by tileset options, which provide a list of parameters that the user can +control under :menuselection:`Game --> Tileset Options` in the +:doc:`main menu </Manuals/Game/menu>`. + +Options are always very simple yes/no questions. Tilesets can configure which +questions are asked and, most importantly, load different sprites depending +on the answer. + +:since: 3.1 + +Adding Options +============== + +Each option is added as a section in the main ``tilespec`` file of the +tileset. The section title must start with ``option_`` as this is how the +engine recognizes that it defines an option. Each option must be given a name +(which will be used when selecting sprites, see below), a one-line +description for the user, and a default value. The following example can be +used as a starting point: + +.. code-block:: ini + + [option_cimpletoon] + name = "cimpletoon" + description = _("Use 3D Cimpletoon units") + default = FALSE + +This defines an option called ``cimpletoon`` that will be shown to the user +as "Use 3D Cimpletoon units" and will be disabled when the tileset is used +for the first time. + +Sprite Selection +================ + +When specifying sprites for use in the tileset, option support is enabled by +an additional attribute called ``option``. If the attribute is not empty, it +specifies the name of an option used to control the loading of the sprite, +and the sprite is only loaded when the option is enabled. A simple example +could be as follows: + +.. code-block:: py + + tiles = { "row", "column", "option", "tag" + 0, 0, "", "u.settlers" + 0, 1, "cimpletoon", "u.settlers" + } + +Let us decompose how this works. Regardless of whether the ``cimpletoon`` +option is enabled, the sprite at row 0 and column 0 is always specified for +:unit:`Settlers` units. However, when the ``cimpletoon`` is enabled, the +second line overrides the first and the alternative sprite in column 1 is +used. The end result is that the user sees a different sprite depending on +the state of the option. + +In the example above, the "main" and "optional" sprites are located in the +same grid. This is not required and they can very well belong to different +files. Remember, however, that the alternative must come *after* the main +sprite in order to override it when the option is enabled. + +Tileset options are very flexible and the changes they control can range from +small tweaks involving a couple of sprites to complete overhauls that change +the appearance of the map completely. The main limitation is that map +geometry cannot change, as tiles have the same dimensions regardless of which +options are enabled. diff --git a/docs/Modding/index.rst b/docs/Modding/index.rst index a74d7d3395..687302f1c6 100644 --- a/docs/Modding/index.rst +++ b/docs/Modding/index.rst @@ -89,6 +89,7 @@ guides document specific aspects of tileset creation: Tilesets/tutorial.rst Tilesets/graphics.rst Tilesets/terrain.rst + Tilesets/options.rst Tilesets/debugger.rst Tilesets/compatibility.rst Tilesets/ts-breaking-changes.rst diff --git a/translations/core/POTFILES.in b/translations/core/POTFILES.in index ecd421a553..192ff95451 100644 --- a/translations/core/POTFILES.in +++ b/translations/core/POTFILES.in @@ -206,7 +206,6 @@ common/vision.cpp common/workertask.cpp common/worklist.cpp data/amplio2.tilespec -data/cimpletoon.tilespec data/civ1/buildings.ruleset data/civ1/cities.ruleset data/civ1/effects.ruleset @@ -348,7 +347,6 @@ data/sandbox/styles.ruleset data/sandbox/techs.ruleset data/sandbox/terrain.ruleset data/sandbox/units.ruleset -data/toonhex.tilespec data/trident.tilespec server/actiontools.cpp server/advisors/advbuilding.cpp