Cytopia  0.3
A city building simulation game
BuildMenu.cxx
Go to the documentation of this file.
1 #include "BuildMenu.hxx"
2 
3 #include "imgui.h"
4 #include "imgui_impl_sdl.h"
5 #include "imgui_impl_sdlrenderer.h"
6 
7 #include <UIManager.hxx>
8 #include <Settings.hxx>
9 #include <GameStates.hxx>
10 #include <MapLayers.hxx>
11 #include <mapEdit.hxx>
12 #include <tileData.hxx>
13 #include "../engine/ResourcesManager.hxx"
14 
15 namespace ui = ImGui;
16 
18 {
19  // function create new big category button
20  auto main_button = [this](const char *tx, const char *id)
21  {
22  m_buttons.emplace_back(std::make_shared<BuildMenuButton>(tx, id));
23  return m_buttons.back();
24  };
25 
26  // special case for construction button
27  auto constrution = main_button("Button_ConstructionMenu", "Construction");
28  constrution->addActionButton("Button_ConstructionMenu_Demolish", "Demolish", "Demolish");
29  constrution->addActionButton("Button_ConstructionMenu_RaiseTerrain", "RaiseTerrain", "Raise Terrain");
30  constrution->addActionButton("Button_ConstructionMenu_LowerTerrain", "LowerTerrain", "Lower Terrain");
31  constrution->addActionButton("Button_ConstructionMenu_LevelTerrain", "LevelTerrain", "Level Terrain");
32  constrution->addActionButton("Button_ConstructionMenu_DeZone", "DeZone", "De-zone");
33  constrution->addActionButton("Button_ConstructionMenu_Water", "Water", "Water");
34 
35  // add big caterogries buttons
36  main_button("Button_NatureMenu", "Nature");
37  main_button("Button_RoadsMenu", "Roads");
38  main_button("Button_ZonesMenu", "Zones");
39  main_button("Button_RecreationMenu", "Recreation");
40  main_button("Button_PowerMenu", "Power");
41  main_button("Button_WaterMenu", "Waterworks");
42  main_button("Button_EmergencyMenu", "Emergency");
43  main_button("Button_DebugMenu", "Debug");
44 
45  // save texture size
46  ImSpan2i size;
47  SDL_QueryTexture(m_buttons.front()->m_tex, nullptr, nullptr, &size.w, &size.h);
48  m_btnSize = ImVec2(size.w, size.h);
49 
51 }
52 
53 namespace detail
54 {
55 float getItemSpan(int deep) { return deep == 0 ? 16.f : 6.f; }
56 } // namespace detail
57 
58 // recusively draw categories
59 template <class Holder> void drawSubmenu(ImVec2 pos, float categoryOffset, const Holder &holder, BuildMenu *menu, int deep)
60 {
61  if (holder.getButtons().empty())
62  return;
63 
64  const ImVec2 &frameSize = holder.getButtons().front()->getBtnSize();
65  const float frameFullWidth = frameSize.x + detail::getItemSpan(deep);
66  ImVec2 screenSize = ui::GetIO().DisplaySize;
67 
68  auto &uiManager = UIManager::instance();
69 
70  ImVec2 windowSize;
71  ImVec2 itemSpacing;
72  ImVec2 nextPos;
73  ImVec2 nextOffset{0, 0};
74  bool verticalMenu =
75  (uiManager.buildMenuLayout() == BUILDMENU_LAYOUT::LEFT || uiManager.buildMenuLayout() == BUILDMENU_LAYOUT::RIGHT);
76  itemSpacing = verticalMenu ? itemSpacing = ImVec2(0, detail::getItemSpan(deep)) : ImVec2(detail::getItemSpan(deep), 0);
77  windowSize = verticalMenu ? ImVec2(frameSize.x, frameFullWidth * (float)holder.getButtons().size())
78  : ImVec2(frameFullWidth * (float)holder.getButtons().size(), frameSize.y);
79 
80  switch (uiManager.buildMenuLayout())
81  {
83  nextOffset.y = -categoryOffset;
84  break;
86  nextOffset.y = +categoryOffset;
87  break;
89  nextOffset.x = categoryOffset;
90  break;
91  default:
92  nextOffset.x = -categoryOffset;
93  }
94 
95  const auto &layout = uiManager.getLayouts()["BuildMenuButtons"];
96 
97  ui::SetNextWindowPos(pos);
98  ui::SetNextWindowSize(windowSize);
99 
100  // Set frame style, font size, noborder, transparent
101  ui::PushFont(layout.font);
102  ui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f);
103  ui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2{0, 0});
104  ui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2{0, 0});
105  ui::PushStyleVar(ImGuiStyleVar_ItemSpacing, itemSpacing);
106 
107  // every subcaterory is different widget, it need unique id
108  bool open = true;
109  std::string wId = std::string("##BuildMenu_") + holder.getId() + std::to_string(deep);
110  // begin buttons
111  ui::Begin(wId.c_str(), &open,
112  ImGuiWindowFlags_NoBackground | ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoScrollbar |
113  ImGuiWindowFlags_NoScrollWithMouse);
114 
115  // setup screen size cliip rect that handle mouse event outside
116  ui::PushClipRect(ImVec2{0, 0}, screenSize, false);
117  BuildMenuButton::Ptr nextMenuLevel = nullptr;
118  int idx = 0;
119 
120  // draw buttons, each button need unique id
121  std::array<char, 128> id_str = {0};
122  for (auto btn : holder.getButtons())
123  {
124  snprintf(id_str.data(), 128, "%s_%d", holder.getId().c_str(), ++idx);
125 
126  ImVec2 imgPos{btn->m_destRect.x, btn->m_destRect.y};
127  ImVec2 imgSize{btn->m_destRect.z, btn->m_destRect.w};
128 
129  // draw bg | pressed state
130  ImGuiButtonFlags flags = btn->m_open ? ImGuiButtonFlags_ForcePressed : 0;
131  flags |= btn->m_background ? 0 : ImGuiButtonFlags_NoBackground;
132 
133  if (ui::ImageButtonCt(btn->m_tex, flags, frameSize, imgPos, imgSize, btn->m_uv0, btn->m_uv1, -1, ImVec4(0, 0, 0, 0)))
134  {
135  btn->m_open = !btn->m_open;
136  menu->setItemVisible(btn, btn->m_open); // close all other buttons and open only me
137  menu->onClick(btn);
138  }
139 
140  if (ui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled) && ui::GetHoveredTimer() > menu->getTooltipDelay())
141  {
142  ui::SetTooltip(btn->getId().c_str());
143  }
144 
145  // calc next subcategory position center
146  if (btn->m_open && !btn->getButtons().empty())
147  {
148  nextMenuLevel = btn;
149  const ImVec2 &nextFrameSize = btn->getButtons().front()->getBtnSize();
150  const float nextFrameFullWidth = (verticalMenu ? nextFrameSize.y : nextFrameSize.x) + detail::getItemSpan(deep + 1);
151  const float nextCategoryOffset = (nextFrameFullWidth * (float)btn->getButtons().size()) / 2;
152 
153  switch (uiManager.buildMenuLayout())
154  {
156  nextPos.x = ui::GetCursorScreenPos().x + ((float)(idx - 1) * frameFullWidth) - nextCategoryOffset + frameFullWidth / 2;
157  nextPos.y = pos.y - nextFrameFullWidth;
158  break;
160  nextPos.x = ui::GetCursorScreenPos().x + ((float)(idx - 1) * frameFullWidth) - nextCategoryOffset + frameFullWidth / 2;
161  nextPos.y = pos.y + frameFullWidth + detail::getItemSpan(1);
162  break;
164  nextPos.x = pos.x + frameFullWidth + detail::getItemSpan(1);
165  nextPos.y = ui::GetCursorScreenPos().y - nextCategoryOffset - frameFullWidth / 2;
166  break;
167  default:
168  nextPos.x = pos.x - nextFrameFullWidth;
169  nextPos.y = ui::GetCursorScreenPos().y - nextCategoryOffset - frameFullWidth / 2;
170  break;
171  }
172  }
173 
174  if (!verticalMenu)
175  {
176  ui::SameLine();
177  }
178  }
179 
180  ui::PopClipRect(); // back common clip rect
181 
182  ui::End(); // end buttons
183 
184  ui::PopStyleVar(4);
185  ui::PopFont();
186 
187  if (nextMenuLevel)
188  {
189  drawSubmenu(nextPos, frameSize.y + 10.f, *nextMenuLevel, menu, deep + 1);
190  }
191 }
192 
193 void BuildMenu::draw() const
194 {
195  ImVec2 screenSize = ui::GetIO().DisplaySize;
196  auto _self = const_cast<BuildMenu *>(this); // const_cast here because button open state can be changed
197 
198  ImVec2 pos{0, 0};
199  const auto &uiManager = UIManager::instance();
200  const float frameSize = m_btnSize.x + detail::getItemSpan(0);
201  const float buttonsSize = (float)m_buttons.size();
202 
203  switch (uiManager.buildMenuLayout())
204  {
206  pos = {(screenSize.x - buttonsSize * frameSize) / 2, screenSize.y - m_btnSize.y};
207  break;
209  pos = ImVec2{(screenSize.x - buttonsSize * frameSize) / 2, 0};
210  break;
212  pos = ImVec2{0, (screenSize.y - buttonsSize * frameSize) / 2};
213  break;
214  default:
215  pos = {screenSize.x - m_btnSize.x, (screenSize.y - buttonsSize * frameSize) / 2};
216  }
217 
218  drawSubmenu(pos, frameSize, *this, _self, 0);
219 }
220 
222 {
223  auto debugBtnIt = std::find_if(m_buttons.begin(), m_buttons.end(), [](auto &btn) { return btn->getId() == "Debug"; });
224  if (debugBtnIt == m_buttons.end())
225  {
226  return;
227  }
228 
229  std::map<std::string, BuildMenuButton::Ptr> categories;
230  for (auto btn : m_buttons)
231  {
232  categories[btn->getId()] = btn;
233  }
234 
235  for (const auto &[tx, tileData] : TileManager::instance().getAllTileData())
236  {
237  const std::string &category = tileData.category;
238  const std::string subCategory =
239  (tileData.subCategory == tileData.category) ? (tileData.category + "_" + tileData.subCategory) : tileData.subCategory;
240  const std::string &title = tileData.title;
241  const std::string &tooltip = !title.empty() ? title : subCategory.empty() ? category : subCategory;
242 
243  // Skip all items that have no button group
244  if (category == "Water" || category == "Terrain")
245  {
246  continue;
247  }
248 
249  if (!subCategory.empty())
250  {
251  auto it = categories.find(subCategory);
252  if (it == categories.end())
253  {
254  auto category_it = categories.find(category);
256  if (category_it == categories.end())
257  {
258  btn = (*debugBtnIt)->addCategoryButton(tx, tooltip, tileData);
259  categories[category] = btn;
260  }
261  else
262  {
263  btn = category_it->second;
264  }
265 
266  auto subBtn = btn->addCategoryButton(tx, tooltip, tileData);
267  categories[subCategory] = subBtn;
268 
269  subBtn->addTileButton(tx, tooltip, tileData);
270  }
271  else
272  {
273  it->second->addTileButton(tx, tooltip, tileData);
274  }
275  }
276  else
277  {
278  auto it = categories.find(category);
279  if (it == categories.end())
280  {
281  auto btn = (*debugBtnIt)->addTileButton(tx, tooltip, tileData);
282  categories[category] = btn;
283  }
284  else
285  {
286  it->second->addTileButton(tx, tooltip, tileData);
287  }
288  }
289  }
290 }
291 
293 {
294  if (!visible)
295  {
296  for (auto it : btn->getButtons())
297  {
298  it->hideItems();
299  }
300  }
301  else
302  {
303  for (auto it : m_buttons)
304  {
305  it->hideItems();
306  }
307 
308  BuildMenuButton *parent = btn.get();
309  while (parent)
310  {
311  parent->m_open = true;
312  parent = parent->m_parent;
313  }
314  }
315 }
316 
318 {
319  clearState();
320 
321  if (!btn->m_action.empty())
322  {
323  onAction(btn->m_action, btn->m_open);
324  }
325 
326  const bool hasAction = !btn->m_tiletype.empty();
327  const bool isCategoryButton = btn->getButtons().size() > 0;
328  if (hasAction && !isCategoryButton)
329  {
330  onChangeTileType(btn->m_tiletype, btn->m_open);
331  }
332 }
333 
334 void BuildMenu::onAction(const std::string &action, bool checked)
335 {
336  if (action == "Demolish")
337  {
338  demolishMode = checked;
339  highlightSelection = checked;
340 
341  if (demolishMode)
342  {
345  }
346  }
347  else if (action == "LowerTerrain")
348  {
350  highlightSelection = checked;
351  }
352  else if (action == "RaiseTerrain")
353  {
355  highlightSelection = checked;
356  }
357  else if (action == "LevelTerrain")
358  {
360  highlightSelection = checked;
361  }
362  else if (action == "DeZone")
363  {
364  demolishMode = checked;
365  highlightSelection = checked;
366  if (demolishMode)
367  {
370  }
371  }
372  else if (action == "underground_pipes")
373  {
375  }
376  else if (action == "Water")
377  {
378  tileToPlace = checked ? "water" : "";
379  highlightSelection = checked;
381  }
382  else
383  {
385  highlightSelection = false;
386  }
387 }
388 
389 void BuildMenu::onChangeTileType(const std::string &actionParameter, bool checked)
390 {
391  if (actionParameter.empty())
392  {
393  tileToPlace = "";
394  highlightSelection = false;
395  }
396 
397  tileToPlace = checked ? actionParameter : "";
398  highlightSelection = checked;
399  if (GameStates::instance().layerEditMode == LayerEditMode::BLUEPRINT)
400  {
403  }
404 
405  if (!tileToPlace.empty())
406  {
407  if (TileManager::instance().getTileData(tileToPlace))
408  {
409  switch (TileManager::instance().getTileData(tileToPlace)->tileType)
410  {
411  case +TileType::DEFAULT:
413  break;
414 
415  case +TileType::ROAD:
416  case +TileType::AUTOTILE:
417  case +TileType::POWERLINE:
419  break;
420 
421  case +TileType::GROUNDDECORATION:
422  case +TileType::WATER:
423  case +TileType::ZONE:
425  break;
426 
427  case +TileType::UNDERGROUND:
431  break;
432 
433  default:
434  break;
435  }
436  }
437  }
438 }
439 
441 {
442  clearState();
443 
444  for (auto &btn : m_buttons)
445  {
446  btn->hideItems();
447  }
448 }
449 
451 {
452  tileToPlace = "";
453  highlightSelection = false;
455 }
456 
457 BuildMenuButton::BuildMenuButton(const std::string &tx, const std::string &id) : m_texstr(tx), m_id(id)
458 {
460  SDL_QueryTexture(m_tex, nullptr, nullptr, &m_texSize.w, &m_texSize.h);
461  m_btnSize = ImVec2(m_texSize.w, m_texSize.h);
462  m_destRect = ImVec4(0, 0, (float)m_texSize.w, (float)m_texSize.h);
463 }
464 
466  : m_background(true), m_texstr(tx), m_id(id), m_tiletype(tx)
467 {
468  int bWid = Settings::instance().subMenuButtonWidth; //UI button width for sub menues
469  int bHei = Settings::instance().subMenuButtonHeight; //UI button height for sub menues
470 
471  SDL_Rect destRect;
472  scaleCenterImage(destRect, bWid, bHei, tile.tiles.clippingWidth, tile.tiles.clippingHeight);
473 
475  SDL_QueryTexture(m_tex, nullptr, nullptr, &m_texSize.w, &m_texSize.h);
476  m_uv0 = ImVec2((float)(tile.tiles.clippingWidth * tile.tiles.offset) / (float)m_texSize.w, 0.f);
477  m_uv1 = ImVec2(m_uv0.x + (float)(tile.tiles.clippingWidth) / (float)m_texSize.w,
478  m_uv0.y + ((float)tile.tiles.clippingHeight) / (float)m_texSize.h);
479  m_btnSize = ImVec2(bWid, bHei);
480  m_destRect = ImVec4((float)destRect.x, (float)destRect.y, (float)destRect.w, (float)destRect.h);
481 }
482 
484  const std::string &tooltip)
485 {
486  auto btn = std::make_shared<BuildMenuButton>(tx, action);
487  btn->m_id = tooltip;
488  btn->m_background = true;
489  btn->m_parent = this;
490  btn->m_action = action;
491  m_buttons.push_back(btn);
492  return btn;
493 }
494 
496 {
497  auto btn = std::make_shared<BuildMenuButton>(tx, id, tile);
498  btn->m_parent = this;
499  m_buttons.push_back(btn);
500  return btn;
501 }
502 
503 void BuildMenuButton::scaleCenterImage(SDL_Rect &ret, int btnW, int btnH, int imgW, int imgH) const
504 {
505  if (imgW > imgH)
506  {
507  float ratio = (float)imgH / (float)imgW;
508  ret.w = btnW;
509  ret.h = static_cast<int>(ceil((float)btnH * ratio));
510  ret.x = 0;
511  ret.y = btnH - ret.h;
512  }
513  else
514  {
515  float ratio = (float)imgW / (float)imgH;
516  ret.w = static_cast<int>(ceil((float)btnW * ratio));
517  ret.h = btnH;
518  ret.x = static_cast<int>(ceil(((float)(btnW - ret.w)) / 2));
519  ret.y = 0;
520  }
521 }
522 
524 {
525  m_open = false;
526  for (auto btn : m_buttons)
527  {
528  btn->hideItems();
529  }
530 }
BuildMenu::closeSubmenus
void closeSubmenus() override
Definition: BuildMenu.cxx:440
BuildMenuButton::m_tex
SDL_Texture * m_tex
Definition: BuildMenu.hxx:22
tileData.hxx
BUILDMENU_LAYOUT::BOTTOM
@ BOTTOM
demolishMode
bool demolishMode
Definition: mapEdit.cxx:5
BuildMenu::draw
void draw() const override
Definition: BuildMenu.cxx:193
terrainEditMode
TerrainEdit terrainEditMode
Definition: mapEdit.cxx:3
DemolishMode::DE_ZONE
@ DE_ZONE
Remove only zones.
MapLayers::setLayerEditMode
static void setLayerEditMode(LayerEditMode layerEditMode)
Definition: MapLayers.cxx:7
TerrainEdit::RAISE
@ RAISE
BuildMenu::setItemVisible
void setItemVisible(BuildMenuButton::Ptr btn, bool visible)
Definition: BuildMenu.cxx:292
detail::getItemSpan
float getItemSpan(int deep)
Definition: BuildMenu.cxx:55
WATER
@ WATER
6- Water tiles
Definition: enums.hxx:17
DEFAULT
@ DEFAULT
Definition: TileManager.hxx:18
TerrainEdit::LOWER
@ LOWER
GameStatesData::placementMode
PlacementMode placementMode
Specifies the placement mode when holding down the mouse.
Definition: GameStates.hxx:18
BuildMenuButton::addActionButton
Ptr addActionButton(const std::string &tx, const std::string &action, const std::string &tooltip)
Definition: BuildMenu.cxx:483
TerrainEdit::NONE
@ NONE
BuildMenu::onClick
void onClick(BuildMenuButton::Ptr btn)
Definition: BuildMenu.cxx:317
BuildMenu::BuildMenu
BuildMenu()
Definition: BuildMenu.cxx:17
BuildMenu::m_buttons
BuildMenuButton::Items m_buttons
Definition: BuildMenu.hxx:105
detail
Definition: BuildMenu.cxx:53
BUILDMENU_LAYOUT::TOP
@ TOP
SettingsData::subMenuButtonWidth
int subMenuButtonWidth
The width in pixels of the buttons used in the build sub menues on the UI.
Definition: Settings.hxx:154
drawSubmenu
void drawSubmenu(ImVec2 pos, float categoryOffset, const Holder &holder, BuildMenu *menu, int deep)
Definition: BuildMenu.cxx:59
BuildMenu::createSubMenus
void createSubMenus()
Definition: BuildMenu.cxx:221
BuildMenu::onChangeTileType
void onChangeTileType(const std::string &id, bool checked)
Definition: BuildMenu.cxx:389
BuildMenuButton::Ptr
std::shared_ptr< BuildMenuButton > Ptr
Definition: BuildMenu.hxx:11
BuildMenuButton::m_parent
BuildMenuButton * m_parent
Definition: BuildMenu.hxx:26
BuildMenuButton::BuildMenuButton
BuildMenuButton(const std::string &tx, const std::string &category)
Definition: BuildMenu.cxx:457
ResourcesManager::getUITexture
SDL_Texture * getUITexture(const std::string &uiElement)
retrieves texture for a tileID
Definition: ResourcesManager.cxx:44
BuildMenu::m_btnSize
ImVec2 m_btnSize
Definition: BuildMenu.hxx:107
BuildMenu::onAction
void onAction(const std::string &action, bool checked)
Definition: BuildMenu.cxx:334
BUILDMENU_LAYOUT::RIGHT
@ RIGHT
TileData::tiles
TileSetData tiles
Tile Spritesheet information.
Definition: tileData.hxx:148
BuildMenu
Definition: BuildMenu.hxx:74
GameStates.hxx
ZONE
@ ZONE
4- Optional layer, zones(Industrial/Residential/Commercial).
Definition: enums.hxx:15
BuildMenuButton::m_uv0
ImVec2 m_uv0
Definition: BuildMenu.hxx:23
PlacementMode::LINE
@ LINE
Place tiles in a line from start to end point.
BuildMenu::clearState
void clearState()
Definition: BuildMenu.cxx:450
TerrainEdit::LEVEL
@ LEVEL
BUILDMENU_LAYOUT::LEFT
@ LEFT
mapEdit.hxx
PlacementMode::SINGLE
@ SINGLE
Place tiles on a single spot.
TileManager::getTexture
SDL_Texture * getTexture(const std::string &tileID) const
Get the Texture for the tileID.
Definition: TileManager.cxx:17
BuildMenuButton::m_uv1
ImVec2 m_uv1
Definition: BuildMenu.hxx:24
GameStatesData::demolishMode
DemolishMode demolishMode
Definition: GameStates.hxx:19
SettingsData::subMenuButtonHeight
int subMenuButtonHeight
The height in pixels of the buttons used in the build sub menues on the UI.
Definition: Settings.hxx:160
Settings.hxx
highlightSelection
bool highlightSelection
Definition: mapEdit.cxx:6
tileToPlace
std::string tileToPlace
Definition: mapEdit.cxx:4
BuildMenuButton::scaleCenterImage
void scaleCenterImage(SDL_Rect &ret, int btnW, int btnH, int imgW, int imgH) const
takes an SDL_Rect, default button width and height, and image width and height and scales the image t...
Definition: BuildMenu.cxx:503
BuildMenu.hxx
DemolishMode::DEFAULT
@ DEFAULT
Demolish everything, but not.
BuildMenuButton::m_texSize
ImSpan2i m_texSize
Definition: BuildMenu.hxx:25
BuildMenuButton::m_open
bool m_open
Definition: BuildMenu.hxx:14
MapLayers.hxx
BuildMenuButton::m_destRect
ImVec4 m_destRect
Definition: BuildMenu.hxx:28
GameStatesData::layerEditMode
LayerEditMode layerEditMode
Specifies the Layer Editmode. Editing Terrain or Blueprint (water pipes, subway,.....
Definition: GameStates.hxx:16
PlacementMode::RECTANGLE
@ RECTANGLE
draw a rectangle between start and end point
BuildMenuButton::m_btnSize
ImVec2 m_btnSize
Definition: BuildMenu.hxx:29
ROAD
@ ROAD
5- Optional layer, roads.
Definition: enums.hxx:16
BuildMenuButton::hideItems
void hideItems()
Definition: BuildMenu.cxx:523
LayerEditMode::TERRAIN
@ TERRAIN
Default "overworld" edit mode.
BuildMenuButton
Definition: BuildMenu.hxx:9
UIManager.hxx
Singleton< UIManager >::instance
static UIManager & instance(void)
Get an instance of the singleton.
Definition: Singleton.hxx:15
BuildMenuButton::addButtonImpl
Ptr addButtonImpl(const std::string &tx, const std::string &id, const TileData &tile)
Definition: BuildMenu.cxx:495
LayerEditMode::BLUEPRINT
@ BLUEPRINT
Placing water pipes and underground transportation on the Blueprint layer.
BuildMenu::getTooltipDelay
float getTooltipDelay() const
Definition: BuildMenu.hxx:102
string
std::string string
Definition: AudioConfig.hxx:14
UNDERGROUND
@ UNDERGROUND
2- Optional layer - Pipes, Subway-pipes and so onn
Definition: enums.hxx:13
TileData
Holds all releavted information to this specific tile.
Definition: tileData.hxx:135
BuildMenuButton::m_buttons
Items m_buttons
Definition: BuildMenu.hxx:31