OpenClonk
C4ConsoleQtNewScenario.cpp
Go to the documentation of this file.
1 /*
2 * OpenClonk, http://www.openclonk.org
3 *
4 * Copyright (c) 2001-2009, RedWolf Design GmbH, http://www.clonk.de/
5 * Copyright (c) 2013, The OpenClonk Team and contributors
6 *
7 * Distributed under the terms of the ISC license; see accompanying file
8 * "COPYING" for details.
9 *
10 * "Clonk" is a registered trademark of Matthes Bender, used with permission.
11 * See accompanying file "TRADEMARK" for details.
12 *
13 * To redistribute this file separately, substitute the full license texts
14 * for the above references.
15 */
16 
17 /* "New scenario" editor dialogue */
18 
19 #include "C4Include.h"
20 #include "script/C4Value.h"
21 #include "config/C4Config.h"
23 
24 
25 /* Definition file list model for new scenario definition selection */
26 
27 C4ConsoleQtDefinitionFileListModel::DefFileInfo::DefFileInfo(C4ConsoleQtDefinitionFileListModel::DefFileInfo *parent, const char *filename, const char *root_path)
28  : parent(parent), filename(filename), root_path(root_path), was_opened(false), is_root(false), user_selected(parent->IsUserSelected()), force_selected(parent->IsForceSelected())
29 {
30  // Delay opening of groups until information is actually requested
31  // Full names into child groups in C4S always delimeted with backslashes
32  if (parent->full_filename.getLength())
33  full_filename = parent->full_filename + R"(\)" + filename;
34  else
35  full_filename = filename;
36 }
37 
38 C4ConsoleQtDefinitionFileListModel::DefFileInfo::DefFileInfo()
39 {
40  // Init as root: List definitions in root paths
41  // Objects.ocd is always there (even if not actually found) and always first
42  DefFileInfo *main_objects_def = new DefFileInfo(this, C4CFN_Objects, "");
43  children.emplace_back(main_objects_def);
44  bool has_default_objects_found = false;
45  for (auto & root_iter : ::Reloc)
46  {
47  const char *root = root_iter.strBuf.getData();
48  for (DirectoryIterator def_file_iter(root); *def_file_iter; ++def_file_iter)
49  {
50  const char *def_file = ::GetFilename(*def_file_iter);
51  if (WildcardMatch(C4CFN_DefFiles, def_file))
52  {
53  // Set path of main objects if found
54  if (!has_default_objects_found && !strcmp(C4CFN_Objects, def_file))
55  {
56  main_objects_def->root_path.Copy(root);
57  continue;
58  }
59  // Avoid duplicates on top level
60  bool dup = false;
61  for (auto & child : children)
62  if (!strcmp(child->GetName(), def_file))
63  {
64  dup = true; break;
65  }
66  if (dup) continue;
67  children.emplace_back(new DefFileInfo(this, def_file, root));
68  }
69  }
70  }
71 }
72 
73 void C4ConsoleQtDefinitionFileListModel::DefFileInfo::SetSelected(bool to_val, bool forced)
74 {
75  if (forced)
76  force_selected = to_val;
77  else
78  user_selected = to_val;
79  // Selection propagates to children
80  for (auto & child : children)
81  {
82  child->SetSelected(to_val, forced);
83  }
84 }
85 
86 bool C4ConsoleQtDefinitionFileListModel::DefFileInfo::OpenGroup()
87 {
88  children.clear();
89  was_opened = true; // mark as opened even if fails to prevent permanent re-loading of broken groups
90  if (parent->IsRoot())
91  {
92  if (!grp.Open((root_path + DirectorySeparator + filename).getData())) return false;
93  }
94  else
95  {
96  if (!grp.OpenAsChild(&parent->grp, filename.getData())) return false;
97  }
98  // Init child array (without loading full groups)
99  StdStrBuf child_filename;
100  children.reserve(grp.EntryCount(C4CFN_DefFiles));
101  grp.ResetSearch();
102  while (grp.FindNextEntry(C4CFN_DefFiles, &child_filename))
103  children.emplace_back(new DefFileInfo(this, child_filename.getData(), nullptr));
104  return true;
105 }
106 
107 int32_t C4ConsoleQtDefinitionFileListModel::DefFileInfo::GetChildCount()
108 {
109  if (!was_opened) OpenGroup();
110  return children.size();
111 }
112 
113 C4ConsoleQtDefinitionFileListModel::DefFileInfo *C4ConsoleQtDefinitionFileListModel::DefFileInfo::GetChild(int32_t index)
114 {
115  if (!was_opened) OpenGroup();
116  if (index >= children.size()) return nullptr;
117  return children[index].get();
118 }
119 
120 int32_t C4ConsoleQtDefinitionFileListModel::DefFileInfo::GetChildIndex(const DefFileInfo *child)
121 {
122  auto iter = std::find_if(children.begin(), children.end(),
123  [child](std::unique_ptr<DefFileInfo> & item)->bool { return item.get() == child; });
124  if (iter == children.end()) return -1; // not found
125  return int32_t(iter - children.begin());
126 }
127 
128 void C4ConsoleQtDefinitionFileListModel::DefFileInfo::AddUserSelectedDefinitions(std::list<const char *> *result) const
129 {
130  // Add parent-most selected
131  // Ignore any forced selection even if also selected by user.
132  // It may have been selected first and then forced by the scenario preset after the template has been switched)
133  if (!IsForceSelected())
134  {
135  if (IsUserSelected())
136  result->push_back(full_filename.getData());
137  else
138  for (auto &iter : children) iter->AddUserSelectedDefinitions(result);
139  }
140 }
141 
142 void C4ConsoleQtDefinitionFileListModel::DefFileInfo::AddSelectedDefinitions(std::list<const char *> *result) const
143 {
144  // Add parent-most selected
145  if (IsSelected())
146  result->push_back(full_filename.getData());
147  else
148  for (auto &iter : children) iter->AddSelectedDefinitions(result);
149 }
150 
151 void C4ConsoleQtDefinitionFileListModel::DefFileInfo::SetForcedSelection(const char *selected_def_filepath)
152 {
153  // Filenames are assumed to be case insensitive for the Windows client
154  if (SEqualNoCase(selected_def_filepath, full_filename.getData()))
155  {
156  // This is the def to be force-selected
157  SetSelected(true, true);
158  }
159  else if (is_root || (SEqual2NoCase(selected_def_filepath, full_filename.getData()) && selected_def_filepath[full_filename.getLength()] == '\\'))
160  {
161  // One of the child definitions should be force-selected
162  if (!was_opened) OpenGroup();
163  for (auto &iter : children) iter->SetForcedSelection(selected_def_filepath);
164  }
165 }
166 
167 void C4ConsoleQtDefinitionFileListModel::DefFileInfo::AddExtraDef(const char *def)
168 {
169  assert(is_root);
170  // Ignore if it was already added
171  // Could also avoid adding child definitions if they are already in the list.
172  // E.g. do not add both foo.ocs\bar.ocd and foo.ocs\bar.ocd\baz.ocd, but keep only the parent path.
173  // But it's overkill for a case that will probably never happen and would pose just a minor nuisance if it does.
174  for (auto &iter : children)
175  {
176  if (SEqualNoCase(iter->full_filename.getData(), def))
177  {
178  return;
179  }
180  }
181  // Add using user path as root (extra defs will always be in the user path because they are not used by our main system templates)
182  children.emplace_back(new DefFileInfo(this, def, ::Config.General.UserDataPath));
183 }
184 
185 
186 C4ConsoleQtDefinitionFileListModel::C4ConsoleQtDefinitionFileListModel() = default;
187 
188 C4ConsoleQtDefinitionFileListModel::~C4ConsoleQtDefinitionFileListModel() = default;
189 
190 void C4ConsoleQtDefinitionFileListModel::AddExtraDef(const char *def)
191 {
192  root.AddExtraDef(def);
193 }
194 
195 std::list<const char *> C4ConsoleQtDefinitionFileListModel::GetUserSelectedDefinitions() const
196 {
197  std::list<const char *> result;
198  root.AddUserSelectedDefinitions(&result);
199  return result;
200 }
201 
202 std::list<const char *> C4ConsoleQtDefinitionFileListModel::GetSelectedDefinitions() const
203 {
204  std::list<const char *> result;
205  root.AddSelectedDefinitions(&result);
206  return result;
207 }
208 
209 void C4ConsoleQtDefinitionFileListModel::SetForcedSelection(const std::list<const char *> &defs)
210 {
211  beginResetModel();
212  // Unselect previous
213  root.SetSelected(false, true);
214  // Force new selection
215  for (const char *def : defs)
216  {
217  root.SetForcedSelection(def);
218  }
219  endResetModel();
220 }
221 
222 int C4ConsoleQtDefinitionFileListModel::rowCount(const QModelIndex & parent) const
223 {
224  if (!parent.isValid()) return root.GetChildCount();
225  DefFileInfo *parent_def = static_cast<DefFileInfo *>(parent.internalPointer());
226  if (!parent_def) return 0;
227  return parent_def->GetChildCount();
228 }
229 
230 int C4ConsoleQtDefinitionFileListModel::columnCount(const QModelIndex & parent) const
231 {
232  return 1; // Name
233 }
234 
235 QVariant C4ConsoleQtDefinitionFileListModel::data(const QModelIndex & index, int role) const
236 {
237  DefFileInfo *def = static_cast<DefFileInfo *>(index.internalPointer());
238  if (!def) return QVariant();
239  // Query latest data from prop list
240  if (role == Qt::DisplayRole)
241  {
242  return QString(def->GetName());
243  }
244  else if (role == Qt::CheckStateRole)
245  {
246  return def->IsSelected() ? Qt::Checked : Qt::Unchecked;
247  }
248  // Nothing to show
249  return QVariant();
250 }
251 
252 QModelIndex C4ConsoleQtDefinitionFileListModel::index(int row, int column, const QModelIndex &parent) const
253 {
254  if (column) return QModelIndex();
255  DefFileInfo *parent_def = &root;
256  if (parent.isValid()) parent_def = static_cast<DefFileInfo *>(parent.internalPointer());
257  if (!parent_def) return QModelIndex();
258  return createIndex(row, column, parent_def->GetChild(row));
259 }
260 
261 QModelIndex C4ConsoleQtDefinitionFileListModel::parent(const QModelIndex &index) const
262 {
263  DefFileInfo *def = static_cast<DefFileInfo *>(index.internalPointer());
264  if (!def) return QModelIndex();
265  DefFileInfo *parent_def = def->GetParent();
266  if (!parent_def) return QModelIndex();
267  int32_t def_index = parent_def->GetChildIndex(def);
268  if (def_index < 0) return QModelIndex(); // can't happen
269  return createIndex(def_index, 0, parent_def);
270 }
271 
272 Qt::ItemFlags C4ConsoleQtDefinitionFileListModel::flags(const QModelIndex &index) const
273 {
274  Qt::ItemFlags flags = Qt::ItemIsSelectable | Qt::ItemIsUserCheckable;
275  DefFileInfo *def = static_cast<DefFileInfo *>(index.internalPointer());
276  if (def && !def->IsDisabled()) flags |= Qt::ItemIsEnabled;
277  return flags;
278 }
279 
280 bool C4ConsoleQtDefinitionFileListModel::setData(const QModelIndex& index, const QVariant& value, int role)
281 {
282  // Adjust check-state
283  if (role == Qt::CheckStateRole)
284  {
285  DefFileInfo *def = static_cast<DefFileInfo *>(index.internalPointer());
286  if (def && !def->IsDisabled())
287  {
288  def->SetSelected(value.toBool(), false);
289  // Update changed index and all children
290  int32_t child_count = def->GetChildCount();
291  QModelIndex end_changed = index;
292  if (child_count) end_changed = createIndex(child_count - 1, 0, def->GetChild(child_count - 1));
293  emit dataChanged(index, end_changed);
294  }
295  }
296  return true;
297 }
298 
299 
300 /* New scenario dialogue */
301 
302 C4ConsoleQtNewScenarioDlg::C4ConsoleQtNewScenarioDlg(class QMainWindow *parent_window)
303  : QDialog(parent_window, Qt::WindowSystemMenuHint | Qt::WindowTitleHint | Qt::WindowCloseButtonHint)
304  , has_custom_filename(false)
305 {
306  ui.setupUi(this);
307  adjustSize();
308  setMinimumSize(size());
309  // Create scenario at user path by default
310  ui.filenameEdit->setText(::Config.General.UserDataPath);
311  // Fill definition file model
312  QItemSelectionModel *m = ui.definitionTreeView->selectionModel();
313  ui.definitionTreeView->setModel(&def_file_model);
314  delete m;
315  // Init scenario template list
316  InitScenarioTemplateList();
317 }
318 
319 void C4ConsoleQtNewScenarioDlg::InitScenarioTemplateList()
320 {
321  // Init template scenarios from user and system folder
322  // Clear previous
323  ui.templateComboBox->clear();
324  C4Group system_templates, user_templates;
325  system_templates.OpenAsChild(&::Application.SystemGroup, C4CFN_Template);
326  user_templates.Open(Config.AtUserDataPath(C4CFN_Template));
327  for (C4Group *template_group : { &system_templates, &user_templates })
328  {
329  if (template_group->IsOpen()) // open may have failed (e.g. if it doesn't exist)
330  {
331  // All scenarios within the template group are possible scenario templates
332  template_group->ResetSearch();
333  StdStrBuf template_filename;
334  while (template_group->FindNextEntry(C4CFN_ScenarioFiles, &template_filename))
335  {
336  bool is_default = (template_group == &system_templates) && (template_filename == C4CFN_DefaultScenarioTemplate);
337  AddScenarioTemplate(*template_group, template_filename.getData(), is_default);
338  }
339  }
340  }
341  // TODO could sort elements. But should usually be sorted within the packed groups anyway.
342 }
343 
344 void C4ConsoleQtNewScenarioDlg::AddScenarioTemplate(C4Group &parent, const char *filename, bool is_default)
345 {
346  // Load scenario information from group and add as template
347  C4Group grp;
348  if (!grp.OpenAsChild(&parent, filename)) return;
349  C4Scenario template_c4s;
350  if (!template_c4s.Load(grp)) return;
351  // Title from file or scenario core
352  C4ComponentHost title_file;
353  StdCopyStrBuf title(template_c4s.Head.Title);
355  title_file.GetLanguageString(Config.General.LanguageEx, title);
356  // Add it; remember full path as user data
357  StdStrBuf template_path(grp.GetFullName());
358  ui.templateComboBox->addItem(QString(title.getData()), QString(template_path.getData()));
359  all_template_c4s.push_back(template_c4s);
360  // Add any extra definition (e.g. pointing into a scenario) to selection model
361  // "extra" definitions are those that use non-ocd-files anywhere in their path
362  auto c4s_defs = template_c4s.Definitions.GetModulesAsList();
363  for (const char *c4s_def : c4s_defs)
364  {
365  char c4s_def_component[_MAX_PATH_LEN];
366  int32_t i = 0;
367  bool is_extra_def = false;
368  while (SCopySegment(c4s_def, i++, c4s_def_component, '\\', _MAX_PATH))
369  {
370  if (!WildcardMatch(C4CFN_DefFiles, c4s_def_component))
371  {
372  is_extra_def = true;
373  break;
374  }
375  }
376  if (is_extra_def)
377  {
378  def_file_model.AddExtraDef(c4s_def);
379  }
380  }
381  // Default selection
382  if (is_default) ui.templateComboBox->setCurrentIndex(ui.templateComboBox->count()-1);
383 }
384 
385 bool C4ConsoleQtNewScenarioDlg::IsHostAsNetwork() const
386 {
387  return ui.startInNetworkCheckbox->isChecked();
388 }
389 
390 void C4ConsoleQtNewScenarioDlg::SelectedTemplateChanged(int new_selection)
391 {
392  // Update forced definition selection for template
393  if (new_selection >= 0 && new_selection < all_template_c4s.size())
394  {
395  const C4Scenario &template_c4s = all_template_c4s[new_selection];
396  def_file_model.SetForcedSelection(template_c4s.Definitions.GetModulesAsList());
397  }
398  else
399  {
400  def_file_model.SetForcedSelection(std::list<const char *>());
401  }
402 }
403 
404 bool C4ConsoleQtNewScenarioDlg::CreateScenario()
405 {
406  // Try to create scenario from template. Unpack if necessery.
407  QVariant tmpl_data = ui.templateComboBox->currentData();
408  Log(tmpl_data.toString().toUtf8());
409  StdStrBuf template_filename;
410  template_filename.Copy(tmpl_data.toString().toUtf8());
411  if (DirectoryExists(template_filename.getData()))
412  {
413  if (!CopyDirectory(template_filename.getData(), filename.getData(), true))
414  {
415  return false;
416  }
417  }
418  else
419  {
420  if (!C4Group_CopyItem(template_filename.getData(), filename.getData(), true, true))
421  {
422  return false;
423  }
424  if (!C4Group_UnpackDirectory(filename.getData()))
425  {
426  return false;
427  }
428  }
429  C4Group grp;
430  if (!grp.Open(filename.getData()))
431  {
432  return false;
433  }
434  // Remove localized title file to ensure it's loaded from the scenario core
436  // Update scenario core with settings from dialogue
437  C4Scenario c4s;
438  if (!c4s.Load(grp)) return false;
439  // Take over settings
440  c4s.Landscape.MapWdt.SetConstant(ui.mapWidthSpinBox->value());
441  c4s.Landscape.MapHgt.SetConstant(ui.mapHeightSpinBox->value());
442  c4s.Landscape.MapZoom.SetConstant(ui.mapZoomSpinBox->value());
443  c4s.Head.Title = ui.titleEdit->text().toStdString();
444  c4s.Game.Mode.Copy(ui.gameModeComboBox->currentText().toUtf8());
445  if (c4s.Game.Mode == "Undefined") c4s.Game.Mode.Clear();
446  filename.Copy(ui.filenameEdit->text().toUtf8());
447  std::list<const char *> definitions = def_file_model.GetUserSelectedDefinitions();
448  StdStrBuf forced_definitions;
449  c4s.Definitions.GetModules(&forced_definitions);
450  const char *forced_definitions_c = forced_definitions.getData();
451  std::ostringstream definitions_join(forced_definitions_c ? forced_definitions_c : nullptr, std::ostringstream::ate);
452  if (definitions.size())
453  {
454  // definitions_join = definitions.join(";")
455  if (forced_definitions.getLength())
456  {
457  // Combine both forced and user-selected definitions
458  definitions_join << ";";
459  }
460  auto iter_end = definitions.end();
461  std::copy(definitions.begin(), --iter_end, std::ostream_iterator<std::string>(definitions_join, ";"));
462  definitions_join << *iter_end;
463  }
464  c4s.Definitions.SetModules(definitions_join.str().c_str());
465  if (!c4s.Save(grp))
466  {
467  return false;
468  }
469  // Group saving not needed because it's unpacked.
470  //if (!grp.Save()) return false;
471  return true;
472 }
473 
474 void C4ConsoleQtNewScenarioDlg::CreatePressed()
475 {
476  // Check validity of settings
477  if (!ui.titleEdit->text().length())
478  {
479  DoError(::LoadResStr("IDS_ERR_ENTERTITLE"));
480  ui.titleEdit->setFocus();
481  return;
482  }
483  if (ItemExists(filename.getData()))
484  {
485  DoError(::LoadResStr("IDS_ERR_NEWSCENARIOFILEEXISTS"));
486  ui.titleEdit->setFocus();
487  return;
488  }
489  std::list<const char *> definitions = def_file_model.GetSelectedDefinitions();
490  if (definitions.size() > C4S_MaxDefinitions)
491  {
492  DoError(FormatString(::LoadResStr("IDS_ERR_TOOMANYDEFINITIONS"), (int)definitions.size(), (int)C4S_MaxDefinitions).getData());
493  ui.definitionTreeView->setFocus();
494  return;
495  }
496  if (!CreateScenario())
497  {
498  EraseItem(filename.getData());
499  DoError(::LoadResStr("IDS_ERR_CREATESCENARIO"));
500  ui.titleEdit->setFocus();
501  return;
502  }
503  // Close dialogue with OK
504  accept();
505 }
506 
507 // Filter for allowed characters in filename
508 // (Also replace space, because spaces in filenames suk)
509 static char ReplaceSpecialFilenameChars(char c)
510 {
511  const char *special_chars = R"(\/:<>|$?" )";
512  return strchr(special_chars, c) ? '_' : c;
513 }
514 
515 void C4ConsoleQtNewScenarioDlg::TitleChanged(const QString &new_title)
516 {
517  if (!has_custom_filename)
518  {
519  // Default filename by title
520  std::string filename = new_title.toStdString();
521  std::transform(filename.begin(), filename.end(), filename.begin(), ReplaceSpecialFilenameChars);
522  filename += (C4CFN_ScenarioFiles+1);
523  const char *filename_full = Config.AtUserDataPath(filename.c_str());
524  ui.filenameEdit->setText(filename_full);
525  this->filename.Copy(filename_full);
526 
527  }
528 }
529 
530 void C4ConsoleQtNewScenarioDlg::DoError(const char *msg)
531 {
532  QMessageBox::critical(this, ::LoadResStr("IDS_ERR_TITLE"), QString(msg));
533 }
534 
535 void C4ConsoleQtNewScenarioDlg::BrowsePressed()
536 {
537  // Browse for new filename to be used instead of the filename generated from the title
538  QString new_file;
539  for (;;)
540  {
541  new_file = QFileDialog::getSaveFileName(this, LoadResStr("IDS_CNS_NEWSCENARIO"), Config.General.UserDataPath, QString("%1 (%2)").arg(LoadResStr("IDS_CNS_SCENARIOFILE")).arg(C4CFN_ScenarioFiles), nullptr, QFileDialog::DontConfirmOverwrite);
542  if (!new_file.size()) return;
543  // Extension must be .ocs
544  if (!new_file.endsWith(C4CFN_ScenarioFiles + 1)) new_file += (C4CFN_ScenarioFiles + 1);
545  if (!ItemExists(new_file.toUtf8())) break;
546  // Overwriting of existing scenarios not supported
547  QMessageBox::critical(this, ::LoadResStr("IDS_ERR_TITLE"), ::LoadResStr("IDS_ERR_NEWSCENARIOFILEEXISTS"));
548  }
549  filename.Copy(new_file.toUtf8());
550  ui.filenameEdit->setText(filename.getData()); // set from converted filename just in case weird stuff happened in toUtf8
551  // After setting a new filename, it no longer changes when changing the title
552  has_custom_filename = true;
553 }
#define C4CFN_Objects
Definition: C4Components.h:40
#define C4CFN_Template
Definition: C4Components.h:33
#define C4CFN_DefaultScenarioTemplate
Definition: C4Components.h:149
#define C4CFN_Title
Definition: C4Components.h:82
#define C4CFN_ScenarioFiles
Definition: C4Components.h:175
#define C4CFN_DefFiles
Definition: C4Components.h:166
#define C4CFN_WriteTitle
Definition: C4Components.h:83
C4Config Config
Definition: C4Config.cpp:930
C4Application Application
Definition: C4Globals.cpp:44
bool C4Group_CopyItem(const char *source, const char *target, bool no_sorting, bool reset_attributes)
Definition: C4Group.cpp:115
bool C4Group_UnpackDirectory(const char *filename)
Definition: C4Group.cpp:401
const char * LoadResStr(const char *id)
Definition: C4Language.h:83
bool Log(const char *szMessage)
Definition: C4Log.cpp:204
C4Reloc Reloc
Definition: C4Reloc.cpp:21
const int32_t C4S_MaxDefinitions
Definition: C4Scenario.h:87
#define DirectorySeparator
#define _MAX_PATH
#define _MAX_PATH_LEN
bool SCopySegment(const char *szString, int iSegment, char *sTarget, char cSeparator, int iMaxL, bool fSkipWhitespace)
Definition: Standard.cpp:279
bool SEqualNoCase(const char *szStr1, const char *szStr2, int iLen)
Definition: Standard.cpp:213
bool SEqual2NoCase(const char *szStr1, const char *szStr2, int iLen)
Definition: Standard.cpp:226
StdStrBuf FormatString(const char *szFmt,...)
Definition: StdBuf.cpp:270
bool EraseItem(const char *szItemName)
Definition: StdFile.cpp:833
bool CopyDirectory(const char *szSource, const char *szTarget, bool fResetAttributes)
Definition: StdFile.cpp:737
bool DirectoryExists(const char *szFilename)
Definition: StdFile.cpp:708
bool WildcardMatch(const char *szWildcard, const char *szString)
Definition: StdFile.cpp:396
char * GetFilename(char *szPath)
Definition: StdFile.cpp:42
bool ItemExists(const char *szItemName)
Definition: StdFile.h:75
C4Group SystemGroup
Definition: C4Application.h:40
bool GetLanguageString(const char *szLanguage, StdStrBuf &rTarget)
char LanguageEx[CFG_MaxString+1]
Definition: C4Config.h:38
char UserDataPath[CFG_MaxString+1]
Definition: C4Config.h:56
C4ConfigGeneral General
Definition: C4Config.h:255
const char * AtUserDataPath(const char *filename)
Definition: C4Config.cpp:586
bool DeleteEntry(const char *filename, bool do_recycle=false)
Definition: C4Group.cpp:1695
StdStrBuf GetFullName() const
Definition: C4Group.cpp:2638
bool OpenAsChild(C4Group *mother, const char *entry_name, bool is_exclusive=false, bool do_create=false)
Definition: C4Group.cpp:1952
bool Open(const char *group_name, bool do_create=false)
Definition: C4Group.cpp:660
static bool LoadComponentHost(C4ComponentHost *host, C4Group &hGroup, const char *szFilename, const char *szLanguage)
Definition: C4Language.cpp:232
void SetModules(const char *szList, const char *szRelativeToPath=nullptr, const char *szRelativeToPath2=nullptr)
Definition: C4Scenario.cpp:464
std::list< const char * > GetModulesAsList() const
Definition: C4Scenario.cpp:446
bool GetModules(StdStrBuf *psOutModules) const
Definition: C4Scenario.cpp:422
StdCopyStrBuf Mode
Definition: C4Scenario.h:121
std::string Title
Definition: C4Scenario.h:64
C4SVal MapZoom
Definition: C4Scenario.h:178
C4SVal MapWdt
Definition: C4Scenario.h:178
C4SVal MapHgt
Definition: C4Scenario.h:178
void SetConstant(int32_t val)
Definition: C4Scenario.cpp:41
C4SGame Game
Definition: C4Scenario.h:234
bool Save(C4Group &hGroup, bool fSaveSection=false)
Definition: C4Scenario.cpp:114
C4SLandscape Landscape
Definition: C4Scenario.h:236
C4SHead Head
Definition: C4Scenario.h:232
C4SDefinitions Definitions
Definition: C4Scenario.h:233
bool Load(C4Group &hGroup, bool fLoadSection=false, bool suppress_errors=false)
Definition: C4Scenario.cpp:92
const char * getData() const
Definition: StdBuf.h:442
void Copy()
Definition: StdBuf.h:467
void Clear()
Definition: StdBuf.h:466
size_t getLength() const
Definition: StdBuf.h:445