Freeciv21
Develop your civilization from humble roots to a global empire
layer_overlays.cpp
Go to the documentation of this file.
1 // SPDX-License-Identifier: GPLv3-or-later
2 // SPDX-FileCopyrightText: Freeciv authors
3 // SPDX-FileCopyrightText: Freeciv21 authors
4 // SPDX-FileCopyrightText: Louis Moureaux <m_louis30@yahoo.com>
5 
6 #include "layer_overlays.h"
7 
8 #include "citydlg_g.h"
9 #include "climap.h"
10 #include "log.h"
11 #include "sprite_g.h"
12 #include "tilespec.h"
13 #include "views/view_map_common.h"
14 
15 namespace freeciv {
16 
18  : freeciv::layer(ts, LAYER_OVERLAYS)
19 {
20 }
21 
23 {
24  // Tile output counters
25  for (int i = 0;; ++i) {
26  auto buffer = QStringLiteral("city.t_food_%1").arg(i);
27  if (auto sprite = load_sprite({buffer})) {
28  m_food.push_back(sprite);
29  } else {
30  break;
31  }
32  }
33  for (int i = 0;; ++i) {
34  auto buffer = QStringLiteral("city.t_shields_%1").arg(i);
35  if (auto sprite = load_sprite({buffer})) {
36  m_prod.push_back(sprite);
37  } else {
38  break;
39  }
40  }
41  for (int i = 0;; ++i) {
42  auto buffer = QStringLiteral("city.t_trade_%1").arg(i);
43  if (auto sprite = load_sprite({buffer})) {
44  m_trade.push_back(sprite);
45  } else {
46  break;
47  }
48  }
49 
50  // Overlay colors
51  std::vector<QPixmap *> colors;
52  for (int i = 0;; ++i) {
53  auto buffer = QStringLiteral("colors.overlay_%1").arg(i);
54  auto sprite = load_sprite({buffer});
55  if (!sprite) {
56  break;
57  }
58  colors.push_back(sprite);
59  }
60  if (colors.empty()) {
62  _("Missing overlay-color sprite colors.overlay_0."));
63  }
64 
65  auto worked_base = load_sprite({"mask.worked_tile"}, true);
66  auto unworked_base = load_sprite({"mask.unworked_tile"}, true);
67 
68  // Chop up and build the overlay graphics.
70  for (const auto &color : colors) {
71  auto color_mask = std::unique_ptr<QPixmap>(
72  crop_sprite(color, 0, 0, W, H, get_mask_sprite(tileset()), 0, 0));
73  m_worked.emplace_back(
74  crop_sprite(color_mask.get(), 0, 0, W, H, worked_base, 0, 0));
75  m_unworked.emplace_back(
76  crop_sprite(color_mask.get(), 0, 0, W, H, unworked_base, 0, 0));
77  }
78 }
79 
83 std::vector<drawn_sprite>
85  const tile_corner *pcorner,
86  const unit *punit) const
87 {
88  std::vector<drawn_sprite> sprs;
89 
90  if (!ptile || client_tile_get_known(ptile) == TILE_UNKNOWN) {
91  return {};
92  }
93 
94  unit *psettler = nullptr;
95  const auto citymode = is_any_city_dialog_open();
96  auto pcity =
97  citymode ? citymode : find_city_or_settler_near_tile(ptile, &psettler);
98 
99  // The code below does not work if pcity is invisible. Make sure it is not.
100  fc_assert_action(!pcity || pcity->tile, pcity = nullptr);
101 
102  int city_x, city_y;
103  if (pcity && city_base_to_city_map(&city_x, &city_y, pcity, ptile)) {
104  const auto pwork = tile_worked(ptile);
105  if (!citymode && pcity->client.colored) {
106  // Add citymap overlay for a city.
107  int idx = pcity->client.color_index % m_worked.size();
108  if (pwork && pwork == pcity) {
109  sprs.emplace_back(tileset(), m_worked[idx].get());
110  } else if (city_can_work_tile(pcity, ptile)) {
111  sprs.emplace_back(tileset(), m_unworked[idx].get());
112  }
113  } else if (pwork && pwork == pcity
114  && (citymode || gui_options->draw_city_output)) {
115  // Add on the tile output sprites.
116  const int ox = tileset_is_isometric(tileset())
117  ? tileset_tile_width(tileset()) / 3
118  : 0;
119  const int oy = tileset_is_isometric(tileset())
120  ? -tileset_tile_height(tileset()) / 3
121  : 0;
122 
123  if (!m_food.empty()) {
124  int food = city_tile_output_now(pcity, ptile, O_FOOD);
125  food = CLIP(0, food / game.info.granularity, m_food.size() - 1);
126  sprs.emplace_back(tileset(), m_food[food], true, ox, oy);
127  }
128  if (!m_prod.empty()) {
129  int shields = city_tile_output_now(pcity, ptile, O_SHIELD);
130  shields =
131  CLIP(0, shields / game.info.granularity, m_prod.size() - 1);
132  sprs.emplace_back(tileset(), m_prod[shields], true, ox, oy);
133  }
134  if (!m_trade.empty()) {
135  int trade = city_tile_output_now(pcity, ptile, O_TRADE);
136  trade = CLIP(0, trade / game.info.granularity, m_trade.size() - 1);
137  sprs.emplace_back(tileset(), m_trade[trade], true, ox, oy);
138  }
139  }
140  } else if (psettler && psettler->client.colored) {
141  // Add citymap overlay for a unit.
142  auto idx = psettler->client.color_index % m_unworked.size();
143  sprs.emplace_back(tileset(), m_unworked[idx].get());
144  }
145 
146  // Crosshair sprite
147  if (mapdeco_is_crosshair_set(ptile)) {
148  sprs.emplace_back(tileset(), get_attention_crosshair_sprite(tileset()));
149  }
150 
151  return sprs;
152 }
153 
154 } // namespace freeciv
QPixmap crop_sprite(const QPixmap *sprite)
Helper function to crop a sprite.
Definition: canvas.cpp:115
int city_tile_output_now(const struct city *pcity, const struct tile *ptile, Output_type_id otype)
Calculate the production output the given tile is capable of producing for the city.
Definition: city.cpp:1322
bool city_base_to_city_map(int *city_map_x, int *city_map_y, const struct city *const pcity, const struct tile *map_tile)
Finds the city map coordinate for a given map position and a city.
Definition: city.cpp:274
bool city_can_work_tile(const struct city *pcity, const struct tile *ptile)
Returns TRUE when a tile is available to be worked, or the city itself is currently working the tile ...
Definition: city.cpp:1392
struct city * is_any_city_dialog_open()
Definition: citydlg.cpp:2315
layer_overlays(struct tileset *ts)
void load_sprites() override
Loads all sprites that do not depend on the ruleset.
std::vector< QPixmap * > m_food
std::vector< std::unique_ptr< QPixmap > > m_worked
std::vector< QPixmap * > m_prod
std::vector< QPixmap * > m_trade
std::vector< drawn_sprite > fill_sprite_array(const tile *ptile, const tile_edge *pedge, const tile_corner *pcorner, const unit *punit) const override
Fill in the given sprite array with any needed overlays sprites.
std::vector< std::unique_ptr< QPixmap > > m_unworked
A layer when drawing the map.
Definition: layer.h:153
QPixmap * load_sprite(const QStringList &possible_names, bool required=false, bool verbose=true) const
Shortcut to load a sprite from the tileset.
Definition: layer.cpp:79
struct tileset * tileset() const
Definition: layer.h:241
enum known_type client_tile_get_known(const struct tile *ptile)
A tile's "known" field is used by the server to store whether each player knows the tile.
Definition: climap.cpp:29
@ O_SHIELD
Definition: fc_types.h:86
@ O_FOOD
Definition: fc_types.h:85
@ O_TRADE
Definition: fc_types.h:87
#define _(String)
Definition: fcintl.h:50
struct civ_game game
Definition: game.cpp:47
#define fc_assert_action(condition, action)
Definition: log.h:104
constexpr auto LOG_FATAL
Definition: log.h:22
Colors.
Definition: path.cpp:10
client_options * gui_options
Definition: options.cpp:74
#define CLIP(lower, current, upper)
Definition: shared.h:51
struct packet_game_info info
Definition: game.h:80
bool draw_city_output
Definition: options.h:121
Definition: tile.h:42
Definition: unit.h:134
struct unit::@76::@78 client
#define tile_worked(_tile)
Definition: tile.h:97
@ TILE_UNKNOWN
Definition: tile.h:29
const QPixmap * get_attention_crosshair_sprite(const struct tileset *t)
Returns a sprite with the "user-attention" crosshair graphic.
Definition: tilespec.cpp:3557
bool tileset_is_isometric(const struct tileset *t)
Return whether the current tileset is isometric.
Definition: tilespec.cpp:336
const QPixmap * get_mask_sprite(const struct tileset *t)
Return tile mask sprite.
Definition: tilespec.cpp:3486
int tileset_tile_height(const struct tileset *t)
Return the tile height of the current tileset.
Definition: tilespec.cpp:383
void tileset_error(struct tileset *t, QtMsgType level, const char *format,...)
Called when ever there's problem in ruleset/tileset compatibility.
Definition: tilespec.cpp:291
int tileset_tile_width(const struct tileset *t)
Return the tile width of the current tileset.
Definition: tilespec.cpp:371
struct city * find_city_or_settler_near_tile(const struct tile *ptile, struct unit **punit)
Find the "best" city/settlers to associate with the selected tile.
bool mapdeco_is_crosshair_set(const struct tile *ptile)
Returns TRUE if there is a "crosshair" decoration set at the given tile.